From d6abbc1054eacc4b80b1f30fbc68cfcafcd22507 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:51:21 +0200 Subject: [PATCH 1/4] feat: add caching for testkube binary --- dist/index.js | 18012 +++++++++++++++++--------------------------- dist/licenses.txt | 169 +- package-lock.json | 138 +- package.json | 2 +- src/index.ts | 189 +- 5 files changed, 6939 insertions(+), 11571 deletions(-) diff --git a/dist/index.js b/dist/index.js index f3d17ee..3a2fdc8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -994,6 +994,741 @@ exports.toCommandProperties = toCommandProperties; /***/ }), +/***/ 1514: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getExecOutput = exports.exec = void 0; +const string_decoder_1 = __nccwpck_require__(1576); +const tr = __importStar(__nccwpck_require__(8159)); +/** + * Exec a command. + * Output will be streamed to the live console. + * Returns promise with return code + * + * @param commandLine command to execute (can include additional args). Must be correctly escaped. + * @param args optional arguments for tool. Escaping is handled by the lib. + * @param options optional exec options. See ExecOptions + * @returns Promise exit code + */ +function exec(commandLine, args, options) { + return __awaiter(this, void 0, void 0, function* () { + const commandArgs = tr.argStringToArray(commandLine); + if (commandArgs.length === 0) { + throw new Error(`Parameter 'commandLine' cannot be null or empty.`); + } + // Path to tool to execute should be first arg + const toolPath = commandArgs[0]; + args = commandArgs.slice(1).concat(args || []); + const runner = new tr.ToolRunner(toolPath, args, options); + return runner.exec(); + }); +} +exports.exec = exec; +/** + * Exec a command and get the output. + * Output will be streamed to the live console. + * Returns promise with the exit code and collected stdout and stderr + * + * @param commandLine command to execute (can include additional args). Must be correctly escaped. + * @param args optional arguments for tool. Escaping is handled by the lib. + * @param options optional exec options. See ExecOptions + * @returns Promise exit code, stdout, and stderr + */ +function getExecOutput(commandLine, args, options) { + var _a, _b; + return __awaiter(this, void 0, void 0, function* () { + let stdout = ''; + let stderr = ''; + //Using string decoder covers the case where a mult-byte character is split + const stdoutDecoder = new string_decoder_1.StringDecoder('utf8'); + const stderrDecoder = new string_decoder_1.StringDecoder('utf8'); + const originalStdoutListener = (_a = options === null || options === void 0 ? void 0 : options.listeners) === null || _a === void 0 ? void 0 : _a.stdout; + const originalStdErrListener = (_b = options === null || options === void 0 ? void 0 : options.listeners) === null || _b === void 0 ? void 0 : _b.stderr; + const stdErrListener = (data) => { + stderr += stderrDecoder.write(data); + if (originalStdErrListener) { + originalStdErrListener(data); + } + }; + const stdOutListener = (data) => { + stdout += stdoutDecoder.write(data); + if (originalStdoutListener) { + originalStdoutListener(data); + } + }; + const listeners = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.listeners), { stdout: stdOutListener, stderr: stdErrListener }); + const exitCode = yield exec(commandLine, args, Object.assign(Object.assign({}, options), { listeners })); + //flush any remaining characters + stdout += stdoutDecoder.end(); + stderr += stderrDecoder.end(); + return { + exitCode, + stdout, + stderr + }; + }); +} +exports.getExecOutput = getExecOutput; +//# sourceMappingURL=exec.js.map + +/***/ }), + +/***/ 8159: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.argStringToArray = exports.ToolRunner = void 0; +const os = __importStar(__nccwpck_require__(2037)); +const events = __importStar(__nccwpck_require__(2361)); +const child = __importStar(__nccwpck_require__(2081)); +const path = __importStar(__nccwpck_require__(1017)); +const io = __importStar(__nccwpck_require__(7436)); +const ioUtil = __importStar(__nccwpck_require__(1962)); +const timers_1 = __nccwpck_require__(9512); +/* eslint-disable @typescript-eslint/unbound-method */ +const IS_WINDOWS = process.platform === 'win32'; +/* + * Class for running command line tools. Handles quoting and arg parsing in a platform agnostic way. + */ +class ToolRunner extends events.EventEmitter { + constructor(toolPath, args, options) { + super(); + if (!toolPath) { + throw new Error("Parameter 'toolPath' cannot be null or empty."); + } + this.toolPath = toolPath; + this.args = args || []; + this.options = options || {}; + } + _debug(message) { + if (this.options.listeners && this.options.listeners.debug) { + this.options.listeners.debug(message); + } + } + _getCommandString(options, noPrefix) { + const toolPath = this._getSpawnFileName(); + const args = this._getSpawnArgs(options); + let cmd = noPrefix ? '' : '[command]'; // omit prefix when piped to a second tool + if (IS_WINDOWS) { + // Windows + cmd file + if (this._isCmdFile()) { + cmd += toolPath; + for (const a of args) { + cmd += ` ${a}`; + } + } + // Windows + verbatim + else if (options.windowsVerbatimArguments) { + cmd += `"${toolPath}"`; + for (const a of args) { + cmd += ` ${a}`; + } + } + // Windows (regular) + else { + cmd += this._windowsQuoteCmdArg(toolPath); + for (const a of args) { + cmd += ` ${this._windowsQuoteCmdArg(a)}`; + } + } + } + else { + // OSX/Linux - this can likely be improved with some form of quoting. + // creating processes on Unix is fundamentally different than Windows. + // on Unix, execvp() takes an arg array. + cmd += toolPath; + for (const a of args) { + cmd += ` ${a}`; + } + } + return cmd; + } + _processLineBuffer(data, strBuffer, onLine) { + try { + let s = strBuffer + data.toString(); + let n = s.indexOf(os.EOL); + while (n > -1) { + const line = s.substring(0, n); + onLine(line); + // the rest of the string ... + s = s.substring(n + os.EOL.length); + n = s.indexOf(os.EOL); + } + return s; + } + catch (err) { + // streaming lines to console is best effort. Don't fail a build. + this._debug(`error processing line. Failed with error ${err}`); + return ''; + } + } + _getSpawnFileName() { + if (IS_WINDOWS) { + if (this._isCmdFile()) { + return process.env['COMSPEC'] || 'cmd.exe'; + } + } + return this.toolPath; + } + _getSpawnArgs(options) { + if (IS_WINDOWS) { + if (this._isCmdFile()) { + let argline = `/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`; + for (const a of this.args) { + argline += ' '; + argline += options.windowsVerbatimArguments + ? a + : this._windowsQuoteCmdArg(a); + } + argline += '"'; + return [argline]; + } + } + return this.args; + } + _endsWith(str, end) { + return str.endsWith(end); + } + _isCmdFile() { + const upperToolPath = this.toolPath.toUpperCase(); + return (this._endsWith(upperToolPath, '.CMD') || + this._endsWith(upperToolPath, '.BAT')); + } + _windowsQuoteCmdArg(arg) { + // for .exe, apply the normal quoting rules that libuv applies + if (!this._isCmdFile()) { + return this._uvQuoteCmdArg(arg); + } + // otherwise apply quoting rules specific to the cmd.exe command line parser. + // the libuv rules are generic and are not designed specifically for cmd.exe + // command line parser. + // + // for a detailed description of the cmd.exe command line parser, refer to + // http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912 + // need quotes for empty arg + if (!arg) { + return '""'; + } + // determine whether the arg needs to be quoted + const cmdSpecialChars = [ + ' ', + '\t', + '&', + '(', + ')', + '[', + ']', + '{', + '}', + '^', + '=', + ';', + '!', + "'", + '+', + ',', + '`', + '~', + '|', + '<', + '>', + '"' + ]; + let needsQuotes = false; + for (const char of arg) { + if (cmdSpecialChars.some(x => x === char)) { + needsQuotes = true; + break; + } + } + // short-circuit if quotes not needed + if (!needsQuotes) { + return arg; + } + // the following quoting rules are very similar to the rules that by libuv applies. + // + // 1) wrap the string in quotes + // + // 2) double-up quotes - i.e. " => "" + // + // this is different from the libuv quoting rules. libuv replaces " with \", which unfortunately + // doesn't work well with a cmd.exe command line. + // + // note, replacing " with "" also works well if the arg is passed to a downstream .NET console app. + // for example, the command line: + // foo.exe "myarg:""my val""" + // is parsed by a .NET console app into an arg array: + // [ "myarg:\"my val\"" ] + // which is the same end result when applying libuv quoting rules. although the actual + // command line from libuv quoting rules would look like: + // foo.exe "myarg:\"my val\"" + // + // 3) double-up slashes that precede a quote, + // e.g. hello \world => "hello \world" + // hello\"world => "hello\\""world" + // hello\\"world => "hello\\\\""world" + // hello world\ => "hello world\\" + // + // technically this is not required for a cmd.exe command line, or the batch argument parser. + // the reasons for including this as a .cmd quoting rule are: + // + // a) this is optimized for the scenario where the argument is passed from the .cmd file to an + // external program. many programs (e.g. .NET console apps) rely on the slash-doubling rule. + // + // b) it's what we've been doing previously (by deferring to node default behavior) and we + // haven't heard any complaints about that aspect. + // + // note, a weakness of the quoting rules chosen here, is that % is not escaped. in fact, % cannot be + // escaped when used on the command line directly - even though within a .cmd file % can be escaped + // by using %%. + // + // the saving grace is, on the command line, %var% is left as-is if var is not defined. this contrasts + // the line parsing rules within a .cmd file, where if var is not defined it is replaced with nothing. + // + // one option that was explored was replacing % with ^% - i.e. %var% => ^%var^%. this hack would + // often work, since it is unlikely that var^ would exist, and the ^ character is removed when the + // variable is used. the problem, however, is that ^ is not removed when %* is used to pass the args + // to an external program. + // + // an unexplored potential solution for the % escaping problem, is to create a wrapper .cmd file. + // % can be escaped within a .cmd file. + let reverse = '"'; + let quoteHit = true; + for (let i = arg.length; i > 0; i--) { + // walk the string in reverse + reverse += arg[i - 1]; + if (quoteHit && arg[i - 1] === '\\') { + reverse += '\\'; // double the slash + } + else if (arg[i - 1] === '"') { + quoteHit = true; + reverse += '"'; // double the quote + } + else { + quoteHit = false; + } + } + reverse += '"'; + return reverse + .split('') + .reverse() + .join(''); + } + _uvQuoteCmdArg(arg) { + // Tool runner wraps child_process.spawn() and needs to apply the same quoting as + // Node in certain cases where the undocumented spawn option windowsVerbatimArguments + // is used. + // + // Since this function is a port of quote_cmd_arg from Node 4.x (technically, lib UV, + // see https://github.com/nodejs/node/blob/v4.x/deps/uv/src/win/process.c for details), + // pasting copyright notice from Node within this function: + // + // Copyright Joyent, Inc. and other Node contributors. All rights reserved. + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to + // deal in the Software without restriction, including without limitation the + // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + // sell copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + // IN THE SOFTWARE. + if (!arg) { + // Need double quotation for empty argument + return '""'; + } + if (!arg.includes(' ') && !arg.includes('\t') && !arg.includes('"')) { + // No quotation needed + return arg; + } + if (!arg.includes('"') && !arg.includes('\\')) { + // No embedded double quotes or backslashes, so I can just wrap + // quote marks around the whole thing. + return `"${arg}"`; + } + // Expected input/output: + // input : hello"world + // output: "hello\"world" + // input : hello""world + // output: "hello\"\"world" + // input : hello\world + // output: hello\world + // input : hello\\world + // output: hello\\world + // input : hello\"world + // output: "hello\\\"world" + // input : hello\\"world + // output: "hello\\\\\"world" + // input : hello world\ + // output: "hello world\\" - note the comment in libuv actually reads "hello world\" + // but it appears the comment is wrong, it should be "hello world\\" + let reverse = '"'; + let quoteHit = true; + for (let i = arg.length; i > 0; i--) { + // walk the string in reverse + reverse += arg[i - 1]; + if (quoteHit && arg[i - 1] === '\\') { + reverse += '\\'; + } + else if (arg[i - 1] === '"') { + quoteHit = true; + reverse += '\\'; + } + else { + quoteHit = false; + } + } + reverse += '"'; + return reverse + .split('') + .reverse() + .join(''); + } + _cloneExecOptions(options) { + options = options || {}; + const result = { + cwd: options.cwd || process.cwd(), + env: options.env || process.env, + silent: options.silent || false, + windowsVerbatimArguments: options.windowsVerbatimArguments || false, + failOnStdErr: options.failOnStdErr || false, + ignoreReturnCode: options.ignoreReturnCode || false, + delay: options.delay || 10000 + }; + result.outStream = options.outStream || process.stdout; + result.errStream = options.errStream || process.stderr; + return result; + } + _getSpawnOptions(options, toolPath) { + options = options || {}; + const result = {}; + result.cwd = options.cwd; + result.env = options.env; + result['windowsVerbatimArguments'] = + options.windowsVerbatimArguments || this._isCmdFile(); + if (options.windowsVerbatimArguments) { + result.argv0 = `"${toolPath}"`; + } + return result; + } + /** + * Exec a tool. + * Output will be streamed to the live console. + * Returns promise with return code + * + * @param tool path to tool to exec + * @param options optional exec options. See ExecOptions + * @returns number + */ + exec() { + return __awaiter(this, void 0, void 0, function* () { + // root the tool path if it is unrooted and contains relative pathing + if (!ioUtil.isRooted(this.toolPath) && + (this.toolPath.includes('/') || + (IS_WINDOWS && this.toolPath.includes('\\')))) { + // prefer options.cwd if it is specified, however options.cwd may also need to be rooted + this.toolPath = path.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); + } + // if the tool is only a file name, then resolve it from the PATH + // otherwise verify it exists (add extension on Windows if necessary) + this.toolPath = yield io.which(this.toolPath, true); + return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { + this._debug(`exec tool: ${this.toolPath}`); + this._debug('arguments:'); + for (const arg of this.args) { + this._debug(` ${arg}`); + } + const optionsNonNull = this._cloneExecOptions(this.options); + if (!optionsNonNull.silent && optionsNonNull.outStream) { + optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL); + } + const state = new ExecState(optionsNonNull, this.toolPath); + state.on('debug', (message) => { + this._debug(message); + }); + if (this.options.cwd && !(yield ioUtil.exists(this.options.cwd))) { + return reject(new Error(`The cwd: ${this.options.cwd} does not exist!`)); + } + const fileName = this._getSpawnFileName(); + const cp = child.spawn(fileName, this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(this.options, fileName)); + let stdbuffer = ''; + if (cp.stdout) { + cp.stdout.on('data', (data) => { + if (this.options.listeners && this.options.listeners.stdout) { + this.options.listeners.stdout(data); + } + if (!optionsNonNull.silent && optionsNonNull.outStream) { + optionsNonNull.outStream.write(data); + } + stdbuffer = this._processLineBuffer(data, stdbuffer, (line) => { + if (this.options.listeners && this.options.listeners.stdline) { + this.options.listeners.stdline(line); + } + }); + }); + } + let errbuffer = ''; + if (cp.stderr) { + cp.stderr.on('data', (data) => { + state.processStderr = true; + if (this.options.listeners && this.options.listeners.stderr) { + this.options.listeners.stderr(data); + } + if (!optionsNonNull.silent && + optionsNonNull.errStream && + optionsNonNull.outStream) { + const s = optionsNonNull.failOnStdErr + ? optionsNonNull.errStream + : optionsNonNull.outStream; + s.write(data); + } + errbuffer = this._processLineBuffer(data, errbuffer, (line) => { + if (this.options.listeners && this.options.listeners.errline) { + this.options.listeners.errline(line); + } + }); + }); + } + cp.on('error', (err) => { + state.processError = err.message; + state.processExited = true; + state.processClosed = true; + state.CheckComplete(); + }); + cp.on('exit', (code) => { + state.processExitCode = code; + state.processExited = true; + this._debug(`Exit code ${code} received from tool '${this.toolPath}'`); + state.CheckComplete(); + }); + cp.on('close', (code) => { + state.processExitCode = code; + state.processExited = true; + state.processClosed = true; + this._debug(`STDIO streams have closed for tool '${this.toolPath}'`); + state.CheckComplete(); + }); + state.on('done', (error, exitCode) => { + if (stdbuffer.length > 0) { + this.emit('stdline', stdbuffer); + } + if (errbuffer.length > 0) { + this.emit('errline', errbuffer); + } + cp.removeAllListeners(); + if (error) { + reject(error); + } + else { + resolve(exitCode); + } + }); + if (this.options.input) { + if (!cp.stdin) { + throw new Error('child process missing stdin'); + } + cp.stdin.end(this.options.input); + } + })); + }); + } +} +exports.ToolRunner = ToolRunner; +/** + * Convert an arg string to an array of args. Handles escaping + * + * @param argString string of arguments + * @returns string[] array of arguments + */ +function argStringToArray(argString) { + const args = []; + let inQuotes = false; + let escaped = false; + let arg = ''; + function append(c) { + // we only escape double quotes. + if (escaped && c !== '"') { + arg += '\\'; + } + arg += c; + escaped = false; + } + for (let i = 0; i < argString.length; i++) { + const c = argString.charAt(i); + if (c === '"') { + if (!escaped) { + inQuotes = !inQuotes; + } + else { + append(c); + } + continue; + } + if (c === '\\' && escaped) { + append(c); + continue; + } + if (c === '\\' && inQuotes) { + escaped = true; + continue; + } + if (c === ' ' && !inQuotes) { + if (arg.length > 0) { + args.push(arg); + arg = ''; + } + continue; + } + append(c); + } + if (arg.length > 0) { + args.push(arg.trim()); + } + return args; +} +exports.argStringToArray = argStringToArray; +class ExecState extends events.EventEmitter { + constructor(options, toolPath) { + super(); + this.processClosed = false; // tracks whether the process has exited and stdio is closed + this.processError = ''; + this.processExitCode = 0; + this.processExited = false; // tracks whether the process has exited + this.processStderr = false; // tracks whether stderr was written to + this.delay = 10000; // 10 seconds + this.done = false; + this.timeout = null; + if (!toolPath) { + throw new Error('toolPath must not be empty'); + } + this.options = options; + this.toolPath = toolPath; + if (options.delay) { + this.delay = options.delay; + } + } + CheckComplete() { + if (this.done) { + return; + } + if (this.processClosed) { + this._setResult(); + } + else if (this.processExited) { + this.timeout = timers_1.setTimeout(ExecState.HandleTimeout, this.delay, this); + } + } + _debug(message) { + this.emit('debug', message); + } + _setResult() { + // determine whether there is an error + let error; + if (this.processExited) { + if (this.processError) { + error = new Error(`There was an error when attempting to execute the process '${this.toolPath}'. This may indicate the process failed to start. Error: ${this.processError}`); + } + else if (this.processExitCode !== 0 && !this.options.ignoreReturnCode) { + error = new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`); + } + else if (this.processStderr && this.options.failOnStdErr) { + error = new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`); + } + } + // clear the timeout + if (this.timeout) { + clearTimeout(this.timeout); + this.timeout = null; + } + this.done = true; + this.emit('done', error, this.processExitCode); + } + static HandleTimeout(state) { + if (state.done) { + return; + } + if (!state.processClosed && state.processExited) { + const message = `The STDIO streams did not close within ${state.delay / + 1000} seconds of the exit event from process '${state.toolPath}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`; + state._debug(message); + } + state._setResult(); + } +} +//# sourceMappingURL=toolrunner.js.map + +/***/ }), + /***/ 5526: /***/ (function(__unused_webpack_module, exports) { @@ -1796,11912 +2531,7079 @@ function isLoopbackAddress(host) { /***/ }), -/***/ 9051: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 1962: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; -const fs = __nccwpck_require__(7147) -const path = __nccwpck_require__(1017) - -/* istanbul ignore next */ -const LCHOWN = fs.lchown ? 'lchown' : 'chown' -/* istanbul ignore next */ -const LCHOWNSYNC = fs.lchownSync ? 'lchownSync' : 'chownSync' - -/* istanbul ignore next */ -const needEISDIRHandled = fs.lchown && - !process.version.match(/v1[1-9]+\./) && - !process.version.match(/v10\.[6-9]/) - -const lchownSync = (path, uid, gid) => { - try { - return fs[LCHOWNSYNC](path, uid, gid) - } catch (er) { - if (er.code !== 'ENOENT') - throw er - } -} - -/* istanbul ignore next */ -const chownSync = (path, uid, gid) => { - try { - return fs.chownSync(path, uid, gid) - } catch (er) { - if (er.code !== 'ENOENT') - throw er - } -} - -/* istanbul ignore next */ -const handleEISDIR = - needEISDIRHandled ? (path, uid, gid, cb) => er => { - // Node prior to v10 had a very questionable implementation of - // fs.lchown, which would always try to call fs.open on a directory - // Fall back to fs.chown in those cases. - if (!er || er.code !== 'EISDIR') - cb(er) - else - fs.chown(path, uid, gid, cb) - } - : (_, __, ___, cb) => cb - -/* istanbul ignore next */ -const handleEISDirSync = - needEISDIRHandled ? (path, uid, gid) => { - try { - return lchownSync(path, uid, gid) - } catch (er) { - if (er.code !== 'EISDIR') - throw er - chownSync(path, uid, gid) - } - } - : (path, uid, gid) => lchownSync(path, uid, gid) - -// fs.readdir could only accept an options object as of node v6 -const nodeVersion = process.version -let readdir = (path, options, cb) => fs.readdir(path, options, cb) -let readdirSync = (path, options) => fs.readdirSync(path, options) -/* istanbul ignore next */ -if (/^v4\./.test(nodeVersion)) - readdir = (path, options, cb) => fs.readdir(path, cb) - -const chown = (cpath, uid, gid, cb) => { - fs[LCHOWN](cpath, uid, gid, handleEISDIR(cpath, uid, gid, er => { - // Skip ENOENT error - cb(er && er.code !== 'ENOENT' ? er : null) - })) -} - -const chownrKid = (p, child, uid, gid, cb) => { - if (typeof child === 'string') - return fs.lstat(path.resolve(p, child), (er, stats) => { - // Skip ENOENT error - if (er) - return cb(er.code !== 'ENOENT' ? er : null) - stats.name = child - chownrKid(p, stats, uid, gid, cb) - }) - - if (child.isDirectory()) { - chownr(path.resolve(p, child.name), uid, gid, er => { - if (er) - return cb(er) - const cpath = path.resolve(p, child.name) - chown(cpath, uid, gid, cb) - }) - } else { - const cpath = path.resolve(p, child.name) - chown(cpath, uid, gid, cb) - } +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var _a; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0; +const fs = __importStar(__nccwpck_require__(7147)); +const path = __importStar(__nccwpck_require__(1017)); +_a = fs.promises +// export const {open} = 'fs' +, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; +// export const {open} = 'fs' +exports.IS_WINDOWS = process.platform === 'win32'; +// See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691 +exports.UV_FS_O_EXLOCK = 0x10000000; +exports.READONLY = fs.constants.O_RDONLY; +function exists(fsPath) { + return __awaiter(this, void 0, void 0, function* () { + try { + yield exports.stat(fsPath); + } + catch (err) { + if (err.code === 'ENOENT') { + return false; + } + throw err; + } + return true; + }); } - - -const chownr = (p, uid, gid, cb) => { - readdir(p, { withFileTypes: true }, (er, children) => { - // any error other than ENOTDIR or ENOTSUP means it's not readable, - // or doesn't exist. give up. - if (er) { - if (er.code === 'ENOENT') - return cb() - else if (er.code !== 'ENOTDIR' && er.code !== 'ENOTSUP') - return cb(er) - } - if (er || !children.length) - return chown(p, uid, gid, cb) - - let len = children.length - let errState = null - const then = er => { - if (errState) - return - if (er) - return cb(errState = er) - if (-- len === 0) - return chown(p, uid, gid, cb) - } - - children.forEach(child => chownrKid(p, child, uid, gid, then)) - }) +exports.exists = exists; +function isDirectory(fsPath, useStat = false) { + return __awaiter(this, void 0, void 0, function* () { + const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath); + return stats.isDirectory(); + }); } - -const chownrKidSync = (p, child, uid, gid) => { - if (typeof child === 'string') { - try { - const stats = fs.lstatSync(path.resolve(p, child)) - stats.name = child - child = stats - } catch (er) { - if (er.code === 'ENOENT') - return - else - throw er +exports.isDirectory = isDirectory; +/** + * On OSX/Linux, true if path starts with '/'. On Windows, true for paths like: + * \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases). + */ +function isRooted(p) { + p = normalizeSeparators(p); + if (!p) { + throw new Error('isRooted() parameter "p" cannot be empty'); } - } - - if (child.isDirectory()) - chownrSync(path.resolve(p, child.name), uid, gid) - - handleEISDirSync(path.resolve(p, child.name), uid, gid) + if (exports.IS_WINDOWS) { + return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello + ); // e.g. C: or C:\hello + } + return p.startsWith('/'); } - -const chownrSync = (p, uid, gid) => { - let children - try { - children = readdirSync(p, { withFileTypes: true }) - } catch (er) { - if (er.code === 'ENOENT') - return - else if (er.code === 'ENOTDIR' || er.code === 'ENOTSUP') - return handleEISDirSync(p, uid, gid) - else - throw er - } - - if (children && children.length) - children.forEach(child => chownrKidSync(p, child, uid, gid)) - - return handleEISDirSync(p, uid, gid) +exports.isRooted = isRooted; +/** + * Best effort attempt to determine whether a file exists and is executable. + * @param filePath file path to check + * @param extensions additional file extensions to try + * @return if file exists and is executable, returns the file path. otherwise empty string. + */ +function tryGetExecutablePath(filePath, extensions) { + return __awaiter(this, void 0, void 0, function* () { + let stats = undefined; + try { + // test file exists + stats = yield exports.stat(filePath); + } + catch (err) { + if (err.code !== 'ENOENT') { + // eslint-disable-next-line no-console + console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); + } + } + if (stats && stats.isFile()) { + if (exports.IS_WINDOWS) { + // on Windows, test for valid extension + const upperExt = path.extname(filePath).toUpperCase(); + if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) { + return filePath; + } + } + else { + if (isUnixExecutable(stats)) { + return filePath; + } + } + } + // try each extension + const originalFilePath = filePath; + for (const extension of extensions) { + filePath = originalFilePath + extension; + stats = undefined; + try { + stats = yield exports.stat(filePath); + } + catch (err) { + if (err.code !== 'ENOENT') { + // eslint-disable-next-line no-console + console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); + } + } + if (stats && stats.isFile()) { + if (exports.IS_WINDOWS) { + // preserve the case of the actual file (since an extension was appended) + try { + const directory = path.dirname(filePath); + const upperName = path.basename(filePath).toUpperCase(); + for (const actualName of yield exports.readdir(directory)) { + if (upperName === actualName.toUpperCase()) { + filePath = path.join(directory, actualName); + break; + } + } + } + catch (err) { + // eslint-disable-next-line no-console + console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`); + } + return filePath; + } + else { + if (isUnixExecutable(stats)) { + return filePath; + } + } + } + } + return ''; + }); } - -module.exports = chownr -chownr.sync = chownrSync - +exports.tryGetExecutablePath = tryGetExecutablePath; +function normalizeSeparators(p) { + p = p || ''; + if (exports.IS_WINDOWS) { + // convert slashes on Windows + p = p.replace(/\//g, '\\'); + // remove redundant slashes + return p.replace(/\\\\+/g, '\\'); + } + // remove redundant slashes + return p.replace(/\/\/+/g, '/'); +} +// on Mac/Linux, test the execute bit +// R W X R W X R W X +// 256 128 64 32 16 8 4 2 1 +function isUnixExecutable(stats) { + return ((stats.mode & 1) > 0 || + ((stats.mode & 8) > 0 && stats.gid === process.getgid()) || + ((stats.mode & 64) > 0 && stats.uid === process.getuid())); +} +// Get the path of cmd.exe in windows +function getCmdPath() { + var _a; + return (_a = process.env['COMSPEC']) !== null && _a !== void 0 ? _a : `cmd.exe`; +} +exports.getCmdPath = getCmdPath; +//# sourceMappingURL=io-util.js.map /***/ }), -/***/ 2391: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 7436: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; -const {Transform, PassThrough} = __nccwpck_require__(2781); -const zlib = __nccwpck_require__(9796); -const mimicResponse = __nccwpck_require__(3877); - -module.exports = response => { - const contentEncoding = (response.headers['content-encoding'] || '').toLowerCase(); - - if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) { - return response; - } - - // TODO: Remove this when targeting Node.js 12. - const isBrotli = contentEncoding === 'br'; - if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') { - response.destroy(new Error('Brotli is not supported on Node.js < 12')); - return response; - } +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0; +const assert_1 = __nccwpck_require__(9491); +const path = __importStar(__nccwpck_require__(1017)); +const ioUtil = __importStar(__nccwpck_require__(1962)); +/** + * Copies a file or folder. + * Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js + * + * @param source source path + * @param dest destination path + * @param options optional. See CopyOptions. + */ +function cp(source, dest, options = {}) { + return __awaiter(this, void 0, void 0, function* () { + const { force, recursive, copySourceDirectory } = readCopyOptions(options); + const destStat = (yield ioUtil.exists(dest)) ? yield ioUtil.stat(dest) : null; + // Dest is an existing file, but not forcing + if (destStat && destStat.isFile() && !force) { + return; + } + // If dest is an existing directory, should copy inside. + const newDest = destStat && destStat.isDirectory() && copySourceDirectory + ? path.join(dest, path.basename(source)) + : dest; + if (!(yield ioUtil.exists(source))) { + throw new Error(`no such file or directory: ${source}`); + } + const sourceStat = yield ioUtil.stat(source); + if (sourceStat.isDirectory()) { + if (!recursive) { + throw new Error(`Failed to copy. ${source} is a directory, but tried to copy without recursive flag.`); + } + else { + yield cpDirRecursive(source, newDest, 0, force); + } + } + else { + if (path.relative(source, newDest) === '') { + // a file cannot be copied to itself + throw new Error(`'${newDest}' and '${source}' are the same file`); + } + yield copyFile(source, newDest, force); + } + }); +} +exports.cp = cp; +/** + * Moves a path. + * + * @param source source path + * @param dest destination path + * @param options optional. See MoveOptions. + */ +function mv(source, dest, options = {}) { + return __awaiter(this, void 0, void 0, function* () { + if (yield ioUtil.exists(dest)) { + let destExists = true; + if (yield ioUtil.isDirectory(dest)) { + // If dest is directory copy src into dest + dest = path.join(dest, path.basename(source)); + destExists = yield ioUtil.exists(dest); + } + if (destExists) { + if (options.force == null || options.force) { + yield rmRF(dest); + } + else { + throw new Error('Destination already exists'); + } + } + } + yield mkdirP(path.dirname(dest)); + yield ioUtil.rename(source, dest); + }); +} +exports.mv = mv; +/** + * Remove a path recursively with force + * + * @param inputPath path to remove + */ +function rmRF(inputPath) { + return __awaiter(this, void 0, void 0, function* () { + if (ioUtil.IS_WINDOWS) { + // Check for invalid characters + // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + if (/[*"<>|]/.test(inputPath)) { + throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows'); + } + } + try { + // note if path does not exist, error is silent + yield ioUtil.rm(inputPath, { + force: true, + maxRetries: 3, + recursive: true, + retryDelay: 300 + }); + } + catch (err) { + throw new Error(`File was unable to be removed ${err}`); + } + }); +} +exports.rmRF = rmRF; +/** + * Make a directory. Creates the full path with folders in between + * Will throw if it fails + * + * @param fsPath path to create + * @returns Promise + */ +function mkdirP(fsPath) { + return __awaiter(this, void 0, void 0, function* () { + assert_1.ok(fsPath, 'a path argument must be provided'); + yield ioUtil.mkdir(fsPath, { recursive: true }); + }); +} +exports.mkdirP = mkdirP; +/** + * Returns path of a tool had the tool actually been invoked. Resolves via paths. + * If you check and the tool does not exist, it will throw. + * + * @param tool name of the tool + * @param check whether to check if tool exists + * @returns Promise path to tool + */ +function which(tool, check) { + return __awaiter(this, void 0, void 0, function* () { + if (!tool) { + throw new Error("parameter 'tool' is required"); + } + // recursive when check=true + if (check) { + const result = yield which(tool, false); + if (!result) { + if (ioUtil.IS_WINDOWS) { + throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`); + } + else { + throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`); + } + } + return result; + } + const matches = yield findInPath(tool); + if (matches && matches.length > 0) { + return matches[0]; + } + return ''; + }); +} +exports.which = which; +/** + * Returns a list of all occurrences of the given tool on the system path. + * + * @returns Promise the paths of the tool + */ +function findInPath(tool) { + return __awaiter(this, void 0, void 0, function* () { + if (!tool) { + throw new Error("parameter 'tool' is required"); + } + // build the list of extensions to try + const extensions = []; + if (ioUtil.IS_WINDOWS && process.env['PATHEXT']) { + for (const extension of process.env['PATHEXT'].split(path.delimiter)) { + if (extension) { + extensions.push(extension); + } + } + } + // if it's rooted, return it if exists. otherwise return empty. + if (ioUtil.isRooted(tool)) { + const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions); + if (filePath) { + return [filePath]; + } + return []; + } + // if any path separators, return empty + if (tool.includes(path.sep)) { + return []; + } + // build the list of directories + // + // Note, technically "where" checks the current directory on Windows. From a toolkit perspective, + // it feels like we should not do this. Checking the current directory seems like more of a use + // case of a shell, and the which() function exposed by the toolkit should strive for consistency + // across platforms. + const directories = []; + if (process.env.PATH) { + for (const p of process.env.PATH.split(path.delimiter)) { + if (p) { + directories.push(p); + } + } + } + // find all matches + const matches = []; + for (const directory of directories) { + const filePath = yield ioUtil.tryGetExecutablePath(path.join(directory, tool), extensions); + if (filePath) { + matches.push(filePath); + } + } + return matches; + }); +} +exports.findInPath = findInPath; +function readCopyOptions(options) { + const force = options.force == null ? true : options.force; + const recursive = Boolean(options.recursive); + const copySourceDirectory = options.copySourceDirectory == null + ? true + : Boolean(options.copySourceDirectory); + return { force, recursive, copySourceDirectory }; +} +function cpDirRecursive(sourceDir, destDir, currentDepth, force) { + return __awaiter(this, void 0, void 0, function* () { + // Ensure there is not a run away recursive copy + if (currentDepth >= 255) + return; + currentDepth++; + yield mkdirP(destDir); + const files = yield ioUtil.readdir(sourceDir); + for (const fileName of files) { + const srcFile = `${sourceDir}/${fileName}`; + const destFile = `${destDir}/${fileName}`; + const srcFileStat = yield ioUtil.lstat(srcFile); + if (srcFileStat.isDirectory()) { + // Recurse + yield cpDirRecursive(srcFile, destFile, currentDepth, force); + } + else { + yield copyFile(srcFile, destFile, force); + } + } + // Change the mode for the newly created directory + yield ioUtil.chmod(destDir, (yield ioUtil.stat(sourceDir)).mode); + }); +} +// Buffered file copy +function copyFile(srcFile, destFile, force) { + return __awaiter(this, void 0, void 0, function* () { + if ((yield ioUtil.lstat(srcFile)).isSymbolicLink()) { + // unlink/re-link it + try { + yield ioUtil.lstat(destFile); + yield ioUtil.unlink(destFile); + } + catch (e) { + // Try to override file permission + if (e.code === 'EPERM') { + yield ioUtil.chmod(destFile, '0666'); + yield ioUtil.unlink(destFile); + } + // other errors = it doesn't exist, no work to do + } + // Copy over symlink + const symlinkFull = yield ioUtil.readlink(srcFile); + yield ioUtil.symlink(symlinkFull, destFile, ioUtil.IS_WINDOWS ? 'junction' : null); + } + else if (!(yield ioUtil.exists(destFile)) || force) { + yield ioUtil.copyFile(srcFile, destFile); + } + }); +} +//# sourceMappingURL=io.js.map - let isEmpty = true; +/***/ }), - const checker = new Transform({ - transform(data, _encoding, callback) { - isEmpty = false; +/***/ 2473: +/***/ (function(module, exports, __nccwpck_require__) { - callback(null, data); - }, +"use strict"; - flush(callback) { - callback(); - } - }); - - const finalStream = new PassThrough({ - autoDestroy: false, - destroy(error, callback) { - response.destroy(); - - callback(error); - } - }); - - const decompressStream = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip(); - - decompressStream.once('error', error => { - if (isEmpty && !response.readable) { - finalStream.end(); - return; - } - - finalStream.destroy(error); - }); - - mimicResponse(response, finalStream); - response.pipe(checker).pipe(decompressStream).pipe(finalStream); - - return finalStream; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; }; - - -/***/ }), - -/***/ 3877: -/***/ ((module) => { - -"use strict"; - - -// We define these manually to ensure they're always copied -// even if they would move up the prototype chain -// https://nodejs.org/api/http.html#http_class_http_incomingmessage -const knownProperties = [ - 'aborted', - 'complete', - 'headers', - 'httpVersion', - 'httpVersionMinor', - 'httpVersionMajor', - 'method', - 'rawHeaders', - 'rawTrailers', - 'setTimeout', - 'socket', - 'statusCode', - 'statusMessage', - 'trailers', - 'url' -]; - -module.exports = (fromStream, toStream) => { - if (toStream._readableState.autoDestroy) { - throw new Error('The second stream must have the `autoDestroy` option set to `false`'); - } - - const fromProperties = new Set(Object.keys(fromStream).concat(knownProperties)); - - const properties = {}; - - for (const property of fromProperties) { - // Don't overwrite existing properties. - if (property in toStream) { - continue; - } - - properties[property] = { - get() { - const value = fromStream[property]; - const isFunction = typeof value === 'function'; - - return isFunction ? value.bind(fromStream) : value; - }, - set(value) { - fromStream[property] = value; - }, - enumerable: true, - configurable: false - }; - } - - Object.defineProperties(toStream, properties); - - fromStream.once('aborted', () => { - toStream.destroy(); - - toStream.emit('aborted'); - }); - - fromStream.once('close', () => { - if (fromStream.complete) { - if (toStream.readable) { - toStream.once('end', () => { - toStream.emit('close'); - }); - } else { - toStream.emit('close'); - } - } else { - toStream.emit('close'); - } - }); - - return toStream; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); }; - +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports._readLinuxVersionFile = exports._getOsVersion = exports._findMatch = void 0; +const semver = __importStar(__nccwpck_require__(5911)); +const core_1 = __nccwpck_require__(2186); +// needs to be require for core node modules to be mocked +/* eslint @typescript-eslint/no-require-imports: 0 */ +const os = __nccwpck_require__(2037); +const cp = __nccwpck_require__(2081); +const fs = __nccwpck_require__(7147); +function _findMatch(versionSpec, stable, candidates, archFilter) { + return __awaiter(this, void 0, void 0, function* () { + const platFilter = os.platform(); + let result; + let match; + let file; + for (const candidate of candidates) { + const version = candidate.version; + core_1.debug(`check ${version} satisfies ${versionSpec}`); + if (semver.satisfies(version, versionSpec) && + (!stable || candidate.stable === stable)) { + file = candidate.files.find(item => { + core_1.debug(`${item.arch}===${archFilter} && ${item.platform}===${platFilter}`); + let chk = item.arch === archFilter && item.platform === platFilter; + if (chk && item.platform_version) { + const osVersion = module.exports._getOsVersion(); + if (osVersion === item.platform_version) { + chk = true; + } + else { + chk = semver.satisfies(osVersion, item.platform_version); + } + } + return chk; + }); + if (file) { + core_1.debug(`matched ${candidate.version}`); + match = candidate; + break; + } + } + } + if (match && file) { + // clone since we're mutating the file list to be only the file that matches + result = Object.assign({}, match); + result.files = [file]; + } + return result; + }); +} +exports._findMatch = _findMatch; +function _getOsVersion() { + // TODO: add windows and other linux, arm variants + // right now filtering on version is only an ubuntu and macos scenario for tools we build for hosted (python) + const plat = os.platform(); + let version = ''; + if (plat === 'darwin') { + version = cp.execSync('sw_vers -productVersion').toString(); + } + else if (plat === 'linux') { + // lsb_release process not in some containers, readfile + // Run cat /etc/lsb-release + // DISTRIB_ID=Ubuntu + // DISTRIB_RELEASE=18.04 + // DISTRIB_CODENAME=bionic + // DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS" + const lsbContents = module.exports._readLinuxVersionFile(); + if (lsbContents) { + const lines = lsbContents.split('\n'); + for (const line of lines) { + const parts = line.split('='); + if (parts.length === 2 && + (parts[0].trim() === 'VERSION_ID' || + parts[0].trim() === 'DISTRIB_RELEASE')) { + version = parts[1] + .trim() + .replace(/^"/, '') + .replace(/"$/, ''); + break; + } + } + } + } + return version; +} +exports._getOsVersion = _getOsVersion; +function _readLinuxVersionFile() { + const lsbReleaseFile = '/etc/lsb-release'; + const osReleaseFile = '/etc/os-release'; + let contents = ''; + if (fs.existsSync(lsbReleaseFile)) { + contents = fs.readFileSync(lsbReleaseFile).toString(); + } + else if (fs.existsSync(osReleaseFile)) { + contents = fs.readFileSync(osReleaseFile).toString(); + } + return contents; +} +exports._readLinuxVersionFile = _readLinuxVersionFile; +//# sourceMappingURL=manifest.js.map /***/ }), -/***/ 6214: -/***/ ((module, exports) => { +/***/ 8279: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; Object.defineProperty(exports, "__esModule", ({ value: true })); -function isTLSSocket(socket) { - return socket.encrypted; -} -const deferToConnect = (socket, fn) => { - let listeners; - if (typeof fn === 'function') { - const connect = fn; - listeners = { connect }; - } - else { - listeners = fn; - } - const hasConnectListener = typeof listeners.connect === 'function'; - const hasSecureConnectListener = typeof listeners.secureConnect === 'function'; - const hasCloseListener = typeof listeners.close === 'function'; - const onConnect = () => { - if (hasConnectListener) { - listeners.connect(); - } - if (isTLSSocket(socket) && hasSecureConnectListener) { - if (socket.authorized) { - listeners.secureConnect(); - } - else if (!socket.authorizationError) { - socket.once('secureConnect', listeners.secureConnect); - } +exports.RetryHelper = void 0; +const core = __importStar(__nccwpck_require__(2186)); +/** + * Internal class for retries + */ +class RetryHelper { + constructor(maxAttempts, minSeconds, maxSeconds) { + if (maxAttempts < 1) { + throw new Error('max attempts should be greater than or equal to 1'); } - if (hasCloseListener) { - socket.once('close', listeners.close); + this.maxAttempts = maxAttempts; + this.minSeconds = Math.floor(minSeconds); + this.maxSeconds = Math.floor(maxSeconds); + if (this.minSeconds > this.maxSeconds) { + throw new Error('min seconds should be less than or equal to max seconds'); } - }; - if (socket.writable && !socket.connecting) { - onConnect(); } - else if (socket.connecting) { - socket.once('connect', onConnect); + execute(action, isRetryable) { + return __awaiter(this, void 0, void 0, function* () { + let attempt = 1; + while (attempt < this.maxAttempts) { + // Try + try { + return yield action(); + } + catch (err) { + if (isRetryable && !isRetryable(err)) { + throw err; + } + core.info(err.message); + } + // Sleep + const seconds = this.getSleepAmount(); + core.info(`Waiting ${seconds} seconds before trying again`); + yield this.sleep(seconds); + attempt++; + } + // Last attempt + return yield action(); + }); } - else if (socket.destroyed && hasCloseListener) { - listeners.close(socket._hadError); + getSleepAmount() { + return (Math.floor(Math.random() * (this.maxSeconds - this.minSeconds + 1)) + + this.minSeconds); } -}; -exports["default"] = deferToConnect; -// For CommonJS default export support -module.exports = deferToConnect; -module.exports["default"] = deferToConnect; - + sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } +} +exports.RetryHelper = RetryHelper; +//# sourceMappingURL=retry-helper.js.map /***/ }), -/***/ 7714: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { +/***/ 7784: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; -const MiniPass = __nccwpck_require__(2505) -const EE = (__nccwpck_require__(2361).EventEmitter) -const fs = __nccwpck_require__(7147) - -let writev = fs.writev -/* istanbul ignore next */ -if (!writev) { - // This entire block can be removed if support for earlier than Node.js - // 12.9.0 is not needed. - const binding = process.binding('fs') - const FSReqWrap = binding.FSReqWrap || binding.FSReqCallback - - writev = (fd, iovec, pos, cb) => { - const done = (er, bw) => cb(er, bw, iovec) - const req = new FSReqWrap() - req.oncomplete = done - binding.writeBuffers(fd, iovec, pos, req) - } -} - -const _autoClose = Symbol('_autoClose') -const _close = Symbol('_close') -const _ended = Symbol('_ended') -const _fd = Symbol('_fd') -const _finished = Symbol('_finished') -const _flags = Symbol('_flags') -const _flush = Symbol('_flush') -const _handleChunk = Symbol('_handleChunk') -const _makeBuf = Symbol('_makeBuf') -const _mode = Symbol('_mode') -const _needDrain = Symbol('_needDrain') -const _onerror = Symbol('_onerror') -const _onopen = Symbol('_onopen') -const _onread = Symbol('_onread') -const _onwrite = Symbol('_onwrite') -const _open = Symbol('_open') -const _path = Symbol('_path') -const _pos = Symbol('_pos') -const _queue = Symbol('_queue') -const _read = Symbol('_read') -const _readSize = Symbol('_readSize') -const _reading = Symbol('_reading') -const _remain = Symbol('_remain') -const _size = Symbol('_size') -const _write = Symbol('_write') -const _writing = Symbol('_writing') -const _defaultFlag = Symbol('_defaultFlag') -const _errored = Symbol('_errored') - -class ReadStream extends MiniPass { - constructor (path, opt) { - opt = opt || {} - super(opt) - - this.readable = true - this.writable = false - - if (typeof path !== 'string') - throw new TypeError('path must be a string') - - this[_errored] = false - this[_fd] = typeof opt.fd === 'number' ? opt.fd : null - this[_path] = path - this[_readSize] = opt.readSize || 16*1024*1024 - this[_reading] = false - this[_size] = typeof opt.size === 'number' ? opt.size : Infinity - this[_remain] = this[_size] - this[_autoClose] = typeof opt.autoClose === 'boolean' ? - opt.autoClose : true - - if (typeof this[_fd] === 'number') - this[_read]() - else - this[_open]() - } - - get fd () { return this[_fd] } - get path () { return this[_path] } - - write () { - throw new TypeError('this is a readable stream') - } - - end () { - throw new TypeError('this is a readable stream') - } - - [_open] () { - fs.open(this[_path], 'r', (er, fd) => this[_onopen](er, fd)) - } - - [_onopen] (er, fd) { - if (er) - this[_onerror](er) - else { - this[_fd] = fd - this.emit('open', fd) - this[_read]() - } - } - - [_makeBuf] () { - return Buffer.allocUnsafe(Math.min(this[_readSize], this[_remain])) - } - - [_read] () { - if (!this[_reading]) { - this[_reading] = true - const buf = this[_makeBuf]() - /* istanbul ignore if */ - if (buf.length === 0) - return process.nextTick(() => this[_onread](null, 0, buf)) - fs.read(this[_fd], buf, 0, buf.length, null, (er, br, buf) => - this[_onread](er, br, buf)) - } - } - - [_onread] (er, br, buf) { - this[_reading] = false - if (er) - this[_onerror](er) - else if (this[_handleChunk](br, buf)) - this[_read]() - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.close(fd, er => er ? this.emit('error', er) : this.emit('close')) - } - } - - [_onerror] (er) { - this[_reading] = true - this[_close]() - this.emit('error', er) - } - - [_handleChunk] (br, buf) { - let ret = false - // no effect if infinite - this[_remain] -= br - if (br > 0) - ret = super.write(br < buf.length ? buf.slice(0, br) : buf) - - if (br === 0 || this[_remain] <= 0) { - ret = false - this[_close]() - super.end() - } - - return ret - } - - emit (ev, data) { - switch (ev) { - case 'prefinish': - case 'finish': - break - - case 'drain': - if (typeof this[_fd] === 'number') - this[_read]() - break - - case 'error': - if (this[_errored]) - return - this[_errored] = true - return super.emit(ev, data) - - default: - return super.emit(ev, data) - } - } +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.evaluateVersions = exports.isExplicitVersion = exports.findFromManifest = exports.getManifestFromRepo = exports.findAllVersions = exports.find = exports.cacheFile = exports.cacheDir = exports.extractZip = exports.extractXar = exports.extractTar = exports.extract7z = exports.downloadTool = exports.HTTPError = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const io = __importStar(__nccwpck_require__(7436)); +const fs = __importStar(__nccwpck_require__(7147)); +const mm = __importStar(__nccwpck_require__(2473)); +const os = __importStar(__nccwpck_require__(2037)); +const path = __importStar(__nccwpck_require__(1017)); +const httpm = __importStar(__nccwpck_require__(6255)); +const semver = __importStar(__nccwpck_require__(5911)); +const stream = __importStar(__nccwpck_require__(2781)); +const util = __importStar(__nccwpck_require__(3837)); +const assert_1 = __nccwpck_require__(9491); +const v4_1 = __importDefault(__nccwpck_require__(7468)); +const exec_1 = __nccwpck_require__(1514); +const retry_helper_1 = __nccwpck_require__(8279); +class HTTPError extends Error { + constructor(httpStatusCode) { + super(`Unexpected HTTP response: ${httpStatusCode}`); + this.httpStatusCode = httpStatusCode; + Object.setPrototypeOf(this, new.target.prototype); + } +} +exports.HTTPError = HTTPError; +const IS_WINDOWS = process.platform === 'win32'; +const IS_MAC = process.platform === 'darwin'; +const userAgent = 'actions/tool-cache'; +/** + * Download a tool from an url and stream it into a file + * + * @param url url of tool to download + * @param dest path to download tool + * @param auth authorization header + * @param headers other headers + * @returns path to downloaded tool + */ +function downloadTool(url, dest, auth, headers) { + return __awaiter(this, void 0, void 0, function* () { + dest = dest || path.join(_getTempDirectory(), v4_1.default()); + yield io.mkdirP(path.dirname(dest)); + core.debug(`Downloading ${url}`); + core.debug(`Destination ${dest}`); + const maxAttempts = 3; + const minSeconds = _getGlobal('TEST_DOWNLOAD_TOOL_RETRY_MIN_SECONDS', 10); + const maxSeconds = _getGlobal('TEST_DOWNLOAD_TOOL_RETRY_MAX_SECONDS', 20); + const retryHelper = new retry_helper_1.RetryHelper(maxAttempts, minSeconds, maxSeconds); + return yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () { + return yield downloadToolAttempt(url, dest || '', auth, headers); + }), (err) => { + if (err instanceof HTTPError && err.httpStatusCode) { + // Don't retry anything less than 500, except 408 Request Timeout and 429 Too Many Requests + if (err.httpStatusCode < 500 && + err.httpStatusCode !== 408 && + err.httpStatusCode !== 429) { + return false; + } + } + // Otherwise retry + return true; + }); + }); } - -class ReadStreamSync extends ReadStream { - [_open] () { - let threw = true - try { - this[_onopen](null, fs.openSync(this[_path], 'r')) - threw = false - } finally { - if (threw) - this[_close]() - } - } - - [_read] () { - let threw = true - try { - if (!this[_reading]) { - this[_reading] = true - do { - const buf = this[_makeBuf]() - /* istanbul ignore next */ - const br = buf.length === 0 ? 0 - : fs.readSync(this[_fd], buf, 0, buf.length, null) - if (!this[_handleChunk](br, buf)) - break - } while (true) - this[_reading] = false - } - threw = false - } finally { - if (threw) - this[_close]() - } - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.closeSync(fd) - this.emit('close') - } - } +exports.downloadTool = downloadTool; +function downloadToolAttempt(url, dest, auth, headers) { + return __awaiter(this, void 0, void 0, function* () { + if (fs.existsSync(dest)) { + throw new Error(`Destination file path ${dest} already exists`); + } + // Get the response headers + const http = new httpm.HttpClient(userAgent, [], { + allowRetries: false + }); + if (auth) { + core.debug('set auth'); + if (headers === undefined) { + headers = {}; + } + headers.authorization = auth; + } + const response = yield http.get(url, headers); + if (response.message.statusCode !== 200) { + const err = new HTTPError(response.message.statusCode); + core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`); + throw err; + } + // Download the response body + const pipeline = util.promisify(stream.pipeline); + const responseMessageFactory = _getGlobal('TEST_DOWNLOAD_TOOL_RESPONSE_MESSAGE_FACTORY', () => response.message); + const readStream = responseMessageFactory(); + let succeeded = false; + try { + yield pipeline(readStream, fs.createWriteStream(dest)); + core.debug('download complete'); + succeeded = true; + return dest; + } + finally { + // Error, delete dest before retry + if (!succeeded) { + core.debug('download failed'); + try { + yield io.rmRF(dest); + } + catch (err) { + core.debug(`Failed to delete '${dest}'. ${err.message}`); + } + } + } + }); } - -class WriteStream extends EE { - constructor (path, opt) { - opt = opt || {} - super(opt) - this.readable = false - this.writable = true - this[_errored] = false - this[_writing] = false - this[_ended] = false - this[_needDrain] = false - this[_queue] = [] - this[_path] = path - this[_fd] = typeof opt.fd === 'number' ? opt.fd : null - this[_mode] = opt.mode === undefined ? 0o666 : opt.mode - this[_pos] = typeof opt.start === 'number' ? opt.start : null - this[_autoClose] = typeof opt.autoClose === 'boolean' ? - opt.autoClose : true - - // truncating makes no sense when writing into the middle - const defaultFlag = this[_pos] !== null ? 'r+' : 'w' - this[_defaultFlag] = opt.flags === undefined - this[_flags] = this[_defaultFlag] ? defaultFlag : opt.flags - - if (this[_fd] === null) - this[_open]() - } - - emit (ev, data) { - if (ev === 'error') { - if (this[_errored]) - return - this[_errored] = true - } - return super.emit(ev, data) - } - - - get fd () { return this[_fd] } - get path () { return this[_path] } - - [_onerror] (er) { - this[_close]() - this[_writing] = true - this.emit('error', er) - } - - [_open] () { - fs.open(this[_path], this[_flags], this[_mode], - (er, fd) => this[_onopen](er, fd)) - } - - [_onopen] (er, fd) { - if (this[_defaultFlag] && - this[_flags] === 'r+' && - er && er.code === 'ENOENT') { - this[_flags] = 'w' - this[_open]() - } else if (er) - this[_onerror](er) - else { - this[_fd] = fd - this.emit('open', fd) - this[_flush]() - } - } - - end (buf, enc) { - if (buf) - this.write(buf, enc) - - this[_ended] = true - - // synthetic after-write logic, where drain/finish live - if (!this[_writing] && !this[_queue].length && - typeof this[_fd] === 'number') - this[_onwrite](null, 0) - return this - } - - write (buf, enc) { - if (typeof buf === 'string') - buf = Buffer.from(buf, enc) - - if (this[_ended]) { - this.emit('error', new Error('write() after end()')) - return false - } - - if (this[_fd] === null || this[_writing] || this[_queue].length) { - this[_queue].push(buf) - this[_needDrain] = true - return false - } - - this[_writing] = true - this[_write](buf) - return true - } - - [_write] (buf) { - fs.write(this[_fd], buf, 0, buf.length, this[_pos], (er, bw) => - this[_onwrite](er, bw)) - } - - [_onwrite] (er, bw) { - if (er) - this[_onerror](er) - else { - if (this[_pos] !== null) - this[_pos] += bw - if (this[_queue].length) - this[_flush]() - else { - this[_writing] = false - - if (this[_ended] && !this[_finished]) { - this[_finished] = true - this[_close]() - this.emit('finish') - } else if (this[_needDrain]) { - this[_needDrain] = false - this.emit('drain') +/** + * Extract a .7z file + * + * @param file path to the .7z file + * @param dest destination directory. Optional. + * @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this + * problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will + * gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is + * bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line + * interface, it is smaller than the full command line interface, and it does support long paths. At the + * time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website. + * Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path + * to 7zr.exe can be pass to this function. + * @returns path to the destination directory + */ +function extract7z(file, dest, _7zPath) { + return __awaiter(this, void 0, void 0, function* () { + assert_1.ok(IS_WINDOWS, 'extract7z() not supported on current OS'); + assert_1.ok(file, 'parameter "file" is required'); + dest = yield _createExtractFolder(dest); + const originalCwd = process.cwd(); + process.chdir(dest); + if (_7zPath) { + try { + const logLevel = core.isDebug() ? '-bb1' : '-bb0'; + const args = [ + 'x', + logLevel, + '-bd', + '-sccUTF-8', + file + ]; + const options = { + silent: true + }; + yield exec_1.exec(`"${_7zPath}"`, args, options); + } + finally { + process.chdir(originalCwd); + } } - } - } - } - - [_flush] () { - if (this[_queue].length === 0) { - if (this[_ended]) - this[_onwrite](null, 0) - } else if (this[_queue].length === 1) - this[_write](this[_queue].pop()) - else { - const iovec = this[_queue] - this[_queue] = [] - writev(this[_fd], iovec, this[_pos], - (er, bw) => this[_onwrite](er, bw)) - } - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.close(fd, er => er ? this.emit('error', er) : this.emit('close')) - } - } + else { + const escapedScript = path + .join(__dirname, '..', 'scripts', 'Invoke-7zdec.ps1') + .replace(/'/g, "''") + .replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines + const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); + const escapedTarget = dest.replace(/'/g, "''").replace(/"|\n|\r/g, ''); + const command = `& '${escapedScript}' -Source '${escapedFile}' -Target '${escapedTarget}'`; + const args = [ + '-NoLogo', + '-Sta', + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Unrestricted', + '-Command', + command + ]; + const options = { + silent: true + }; + try { + const powershellPath = yield io.which('powershell', true); + yield exec_1.exec(`"${powershellPath}"`, args, options); + } + finally { + process.chdir(originalCwd); + } + } + return dest; + }); } - -class WriteStreamSync extends WriteStream { - [_open] () { - let fd - // only wrap in a try{} block if we know we'll retry, to avoid - // the rethrow obscuring the error's source frame in most cases. - if (this[_defaultFlag] && this[_flags] === 'r+') { - try { - fd = fs.openSync(this[_path], this[_flags], this[_mode]) - } catch (er) { - if (er.code === 'ENOENT') { - this[_flags] = 'w' - return this[_open]() - } else - throw er - } - } else - fd = fs.openSync(this[_path], this[_flags], this[_mode]) - - this[_onopen](null, fd) - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.closeSync(fd) - this.emit('close') - } - } - - [_write] (buf) { - // throw the original, but try to close if it fails - let threw = true - try { - this[_onwrite](null, - fs.writeSync(this[_fd], buf, 0, buf.length, this[_pos])) - threw = false - } finally { - if (threw) - try { this[_close]() } catch (_) {} - } - } +exports.extract7z = extract7z; +/** + * Extract a compressed tar archive + * + * @param file path to the tar + * @param dest destination directory. Optional. + * @param flags flags for the tar command to use for extraction. Defaults to 'xz' (extracting gzipped tars). Optional. + * @returns path to the destination directory + */ +function extractTar(file, dest, flags = 'xz') { + return __awaiter(this, void 0, void 0, function* () { + if (!file) { + throw new Error("parameter 'file' is required"); + } + // Create dest + dest = yield _createExtractFolder(dest); + // Determine whether GNU tar + core.debug('Checking tar --version'); + let versionOutput = ''; + yield exec_1.exec('tar --version', [], { + ignoreReturnCode: true, + silent: true, + listeners: { + stdout: (data) => (versionOutput += data.toString()), + stderr: (data) => (versionOutput += data.toString()) + } + }); + core.debug(versionOutput.trim()); + const isGnuTar = versionOutput.toUpperCase().includes('GNU TAR'); + // Initialize args + let args; + if (flags instanceof Array) { + args = flags; + } + else { + args = [flags]; + } + if (core.isDebug() && !flags.includes('v')) { + args.push('-v'); + } + let destArg = dest; + let fileArg = file; + if (IS_WINDOWS && isGnuTar) { + args.push('--force-local'); + destArg = dest.replace(/\\/g, '/'); + // Technically only the dest needs to have `/` but for aesthetic consistency + // convert slashes in the file arg too. + fileArg = file.replace(/\\/g, '/'); + } + if (isGnuTar) { + // Suppress warnings when using GNU tar to extract archives created by BSD tar + args.push('--warning=no-unknown-keyword'); + args.push('--overwrite'); + } + args.push('-C', destArg, '-f', fileArg); + yield exec_1.exec(`tar`, args); + return dest; + }); } - -exports.ReadStream = ReadStream -exports.ReadStreamSync = ReadStreamSync - -exports.WriteStream = WriteStream -exports.WriteStreamSync = WriteStreamSync - - -/***/ }), - -/***/ 2505: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const proc = typeof process === 'object' && process ? process : { - stdout: null, - stderr: null, -} -const EE = __nccwpck_require__(2361) -const Stream = __nccwpck_require__(2781) -const SD = (__nccwpck_require__(1576).StringDecoder) - -const EOF = Symbol('EOF') -const MAYBE_EMIT_END = Symbol('maybeEmitEnd') -const EMITTED_END = Symbol('emittedEnd') -const EMITTING_END = Symbol('emittingEnd') -const EMITTED_ERROR = Symbol('emittedError') -const CLOSED = Symbol('closed') -const READ = Symbol('read') -const FLUSH = Symbol('flush') -const FLUSHCHUNK = Symbol('flushChunk') -const ENCODING = Symbol('encoding') -const DECODER = Symbol('decoder') -const FLOWING = Symbol('flowing') -const PAUSED = Symbol('paused') -const RESUME = Symbol('resume') -const BUFFERLENGTH = Symbol('bufferLength') -const BUFFERPUSH = Symbol('bufferPush') -const BUFFERSHIFT = Symbol('bufferShift') -const OBJECTMODE = Symbol('objectMode') -const DESTROYED = Symbol('destroyed') -const EMITDATA = Symbol('emitData') -const EMITEND = Symbol('emitEnd') -const EMITEND2 = Symbol('emitEnd2') -const ASYNC = Symbol('async') - -const defer = fn => Promise.resolve().then(fn) - -// TODO remove when Node v8 support drops -const doIter = global._MP_NO_ITERATOR_SYMBOLS_ !== '1' -const ASYNCITERATOR = doIter && Symbol.asyncIterator - || Symbol('asyncIterator not implemented') -const ITERATOR = doIter && Symbol.iterator - || Symbol('iterator not implemented') - -// events that mean 'the stream is over' -// these are treated specially, and re-emitted -// if they are listened for after emitting. -const isEndish = ev => - ev === 'end' || - ev === 'finish' || - ev === 'prefinish' - -const isArrayBuffer = b => b instanceof ArrayBuffer || - typeof b === 'object' && - b.constructor && - b.constructor.name === 'ArrayBuffer' && - b.byteLength >= 0 - -const isArrayBufferView = b => !Buffer.isBuffer(b) && ArrayBuffer.isView(b) - -class Pipe { - constructor (src, dest, opts) { - this.src = src - this.dest = dest - this.opts = opts - this.ondrain = () => src[RESUME]() - dest.on('drain', this.ondrain) - } - unpipe () { - this.dest.removeListener('drain', this.ondrain) - } - // istanbul ignore next - only here for the prototype - proxyErrors () {} - end () { - this.unpipe() - if (this.opts.end) - this.dest.end() - } +exports.extractTar = extractTar; +/** + * Extract a xar compatible archive + * + * @param file path to the archive + * @param dest destination directory. Optional. + * @param flags flags for the xar. Optional. + * @returns path to the destination directory + */ +function extractXar(file, dest, flags = []) { + return __awaiter(this, void 0, void 0, function* () { + assert_1.ok(IS_MAC, 'extractXar() not supported on current OS'); + assert_1.ok(file, 'parameter "file" is required'); + dest = yield _createExtractFolder(dest); + let args; + if (flags instanceof Array) { + args = flags; + } + else { + args = [flags]; + } + args.push('-x', '-C', dest, '-f', file); + if (core.isDebug()) { + args.push('-v'); + } + const xarPath = yield io.which('xar', true); + yield exec_1.exec(`"${xarPath}"`, _unique(args)); + return dest; + }); } - -class PipeProxyErrors extends Pipe { - unpipe () { - this.src.removeListener('error', this.proxyErrors) - super.unpipe() - } - constructor (src, dest, opts) { - super(src, dest, opts) - this.proxyErrors = er => dest.emit('error', er) - src.on('error', this.proxyErrors) - } +exports.extractXar = extractXar; +/** + * Extract a zip + * + * @param file path to the zip + * @param dest destination directory. Optional. + * @returns path to the destination directory + */ +function extractZip(file, dest) { + return __awaiter(this, void 0, void 0, function* () { + if (!file) { + throw new Error("parameter 'file' is required"); + } + dest = yield _createExtractFolder(dest); + if (IS_WINDOWS) { + yield extractZipWin(file, dest); + } + else { + yield extractZipNix(file, dest); + } + return dest; + }); } - -module.exports = class Minipass extends Stream { - constructor (options) { - super() - this[FLOWING] = false - // whether we're explicitly paused - this[PAUSED] = false - this.pipes = [] - this.buffer = [] - this[OBJECTMODE] = options && options.objectMode || false - if (this[OBJECTMODE]) - this[ENCODING] = null - else - this[ENCODING] = options && options.encoding || null - if (this[ENCODING] === 'buffer') - this[ENCODING] = null - this[ASYNC] = options && !!options.async || false - this[DECODER] = this[ENCODING] ? new SD(this[ENCODING]) : null - this[EOF] = false - this[EMITTED_END] = false - this[EMITTING_END] = false - this[CLOSED] = false - this[EMITTED_ERROR] = null - this.writable = true - this.readable = true - this[BUFFERLENGTH] = 0 - this[DESTROYED] = false - } - - get bufferLength () { return this[BUFFERLENGTH] } - - get encoding () { return this[ENCODING] } - set encoding (enc) { - if (this[OBJECTMODE]) - throw new Error('cannot set encoding in objectMode') - - if (this[ENCODING] && enc !== this[ENCODING] && - (this[DECODER] && this[DECODER].lastNeed || this[BUFFERLENGTH])) - throw new Error('cannot change encoding') - - if (this[ENCODING] !== enc) { - this[DECODER] = enc ? new SD(enc) : null - if (this.buffer.length) - this.buffer = this.buffer.map(chunk => this[DECODER].write(chunk)) +exports.extractZip = extractZip; +function extractZipWin(file, dest) { + return __awaiter(this, void 0, void 0, function* () { + // build the powershell command + const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines + const escapedDest = dest.replace(/'/g, "''").replace(/"|\n|\r/g, ''); + const pwshPath = yield io.which('pwsh', false); + //To match the file overwrite behavior on nix systems, we use the overwrite = true flag for ExtractToDirectory + //and the -Force flag for Expand-Archive as a fallback + if (pwshPath) { + //attempt to use pwsh with ExtractToDirectory, if this fails attempt Expand-Archive + const pwshCommand = [ + `$ErrorActionPreference = 'Stop' ;`, + `try { Add-Type -AssemblyName System.IO.Compression.ZipFile } catch { } ;`, + `try { [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}', $true) }`, + `catch { if (($_.Exception.GetType().FullName -eq 'System.Management.Automation.MethodException') -or ($_.Exception.GetType().FullName -eq 'System.Management.Automation.RuntimeException') ){ Expand-Archive -LiteralPath '${escapedFile}' -DestinationPath '${escapedDest}' -Force } else { throw $_ } } ;` + ].join(' '); + const args = [ + '-NoLogo', + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Unrestricted', + '-Command', + pwshCommand + ]; + core.debug(`Using pwsh at path: ${pwshPath}`); + yield exec_1.exec(`"${pwshPath}"`, args); + } + else { + const powershellCommand = [ + `$ErrorActionPreference = 'Stop' ;`, + `try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ;`, + `if ((Get-Command -Name Expand-Archive -Module Microsoft.PowerShell.Archive -ErrorAction Ignore)) { Expand-Archive -LiteralPath '${escapedFile}' -DestinationPath '${escapedDest}' -Force }`, + `else {[System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}', $true) }` + ].join(' '); + const args = [ + '-NoLogo', + '-Sta', + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Unrestricted', + '-Command', + powershellCommand + ]; + const powershellPath = yield io.which('powershell', true); + core.debug(`Using powershell at path: ${powershellPath}`); + yield exec_1.exec(`"${powershellPath}"`, args); + } + }); +} +function extractZipNix(file, dest) { + return __awaiter(this, void 0, void 0, function* () { + const unzipPath = yield io.which('unzip', true); + const args = [file]; + if (!core.isDebug()) { + args.unshift('-q'); + } + args.unshift('-o'); //overwrite with -o, otherwise a prompt is shown which freezes the run + yield exec_1.exec(`"${unzipPath}"`, args, { cwd: dest }); + }); +} +/** + * Caches a directory and installs it into the tool cacheDir + * + * @param sourceDir the directory to cache into tools + * @param tool tool name + * @param version version of the tool. semver format + * @param arch architecture of the tool. Optional. Defaults to machine architecture + */ +function cacheDir(sourceDir, tool, version, arch) { + return __awaiter(this, void 0, void 0, function* () { + version = semver.clean(version) || version; + arch = arch || os.arch(); + core.debug(`Caching tool ${tool} ${version} ${arch}`); + core.debug(`source dir: ${sourceDir}`); + if (!fs.statSync(sourceDir).isDirectory()) { + throw new Error('sourceDir is not a directory'); + } + // Create the tool dir + const destPath = yield _createToolPath(tool, version, arch); + // copy each child item. do not move. move can fail on Windows + // due to anti-virus software having an open handle on a file. + for (const itemName of fs.readdirSync(sourceDir)) { + const s = path.join(sourceDir, itemName); + yield io.cp(s, destPath, { recursive: true }); + } + // write .complete + _completeToolPath(tool, version, arch); + return destPath; + }); +} +exports.cacheDir = cacheDir; +/** + * Caches a downloaded file (GUID) and installs it + * into the tool cache with a given targetName + * + * @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid. + * @param targetFile the name of the file name in the tools directory + * @param tool tool name + * @param version version of the tool. semver format + * @param arch architecture of the tool. Optional. Defaults to machine architecture + */ +function cacheFile(sourceFile, targetFile, tool, version, arch) { + return __awaiter(this, void 0, void 0, function* () { + version = semver.clean(version) || version; + arch = arch || os.arch(); + core.debug(`Caching tool ${tool} ${version} ${arch}`); + core.debug(`source file: ${sourceFile}`); + if (!fs.statSync(sourceFile).isFile()) { + throw new Error('sourceFile is not a file'); + } + // create the tool dir + const destFolder = yield _createToolPath(tool, version, arch); + // copy instead of move. move can fail on Windows due to + // anti-virus software having an open handle on a file. + const destPath = path.join(destFolder, targetFile); + core.debug(`destination file ${destPath}`); + yield io.cp(sourceFile, destPath); + // write .complete + _completeToolPath(tool, version, arch); + return destFolder; + }); +} +exports.cacheFile = cacheFile; +/** + * Finds the path to a tool version in the local installed tool cache + * + * @param toolName name of the tool + * @param versionSpec version of the tool + * @param arch optional arch. defaults to arch of computer + */ +function find(toolName, versionSpec, arch) { + if (!toolName) { + throw new Error('toolName parameter is required'); + } + if (!versionSpec) { + throw new Error('versionSpec parameter is required'); + } + arch = arch || os.arch(); + // attempt to resolve an explicit version + if (!isExplicitVersion(versionSpec)) { + const localVersions = findAllVersions(toolName, arch); + const match = evaluateVersions(localVersions, versionSpec); + versionSpec = match; + } + // check for the explicit version in the cache + let toolPath = ''; + if (versionSpec) { + versionSpec = semver.clean(versionSpec) || ''; + const cachePath = path.join(_getCacheDirectory(), toolName, versionSpec, arch); + core.debug(`checking cache: ${cachePath}`); + if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) { + core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`); + toolPath = cachePath; + } + else { + core.debug('not found'); + } } - - this[ENCODING] = enc - } - - setEncoding (enc) { - this.encoding = enc - } - - get objectMode () { return this[OBJECTMODE] } - set objectMode (om) { this[OBJECTMODE] = this[OBJECTMODE] || !!om } - - get ['async'] () { return this[ASYNC] } - set ['async'] (a) { this[ASYNC] = this[ASYNC] || !!a } - - write (chunk, encoding, cb) { - if (this[EOF]) - throw new Error('write after end') - - if (this[DESTROYED]) { - this.emit('error', Object.assign( - new Error('Cannot call write after a stream was destroyed'), - { code: 'ERR_STREAM_DESTROYED' } - )) - return true - } - - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - - if (!encoding) - encoding = 'utf8' - - const fn = this[ASYNC] ? defer : f => f() - - // convert array buffers and typed array views into buffers - // at some point in the future, we may want to do the opposite! - // leave strings and buffers as-is - // anything else switches us into object mode - if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) { - if (isArrayBufferView(chunk)) - chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength) - else if (isArrayBuffer(chunk)) - chunk = Buffer.from(chunk) - else if (typeof chunk !== 'string') - // use the setter so we throw if we have encoding set - this.objectMode = true - } - - // handle object mode up front, since it's simpler - // this yields better performance, fewer checks later. - if (this[OBJECTMODE]) { - /* istanbul ignore if - maybe impossible? */ - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) - - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) - - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - - if (cb) - fn(cb) - - return this.flowing - } - - // at this point the chunk is a buffer or string - // don't buffer it up or send it to the decoder - if (!chunk.length) { - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - if (cb) - fn(cb) - return this.flowing - } - - // fast-path writing strings of same encoding to a stream with - // an empty buffer, skipping the buffer/decoder dance - if (typeof chunk === 'string' && - // unless it is a string already ready for us to use - !(encoding === this[ENCODING] && !this[DECODER].lastNeed)) { - chunk = Buffer.from(chunk, encoding) - } - - if (Buffer.isBuffer(chunk) && this[ENCODING]) - chunk = this[DECODER].write(chunk) - - // Note: flushing CAN potentially switch us into not-flowing mode - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) - - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) - - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - - if (cb) - fn(cb) - - return this.flowing - } - - read (n) { - if (this[DESTROYED]) - return null - - if (this[BUFFERLENGTH] === 0 || n === 0 || n > this[BUFFERLENGTH]) { - this[MAYBE_EMIT_END]() - return null - } - - if (this[OBJECTMODE]) - n = null - - if (this.buffer.length > 1 && !this[OBJECTMODE]) { - if (this.encoding) - this.buffer = [this.buffer.join('')] - else - this.buffer = [Buffer.concat(this.buffer, this[BUFFERLENGTH])] - } - - const ret = this[READ](n || null, this.buffer[0]) - this[MAYBE_EMIT_END]() - return ret - } - - [READ] (n, chunk) { - if (n === chunk.length || n === null) - this[BUFFERSHIFT]() - else { - this.buffer[0] = chunk.slice(n) - chunk = chunk.slice(0, n) - this[BUFFERLENGTH] -= n - } - - this.emit('data', chunk) - - if (!this.buffer.length && !this[EOF]) - this.emit('drain') - - return chunk - } - - end (chunk, encoding, cb) { - if (typeof chunk === 'function') - cb = chunk, chunk = null - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - if (chunk) - this.write(chunk, encoding) - if (cb) - this.once('end', cb) - this[EOF] = true - this.writable = false - - // if we haven't written anything, then go ahead and emit, - // even if we're not reading. - // we'll re-emit if a new 'end' listener is added anyway. - // This makes MP more suitable to write-only use cases. - if (this.flowing || !this[PAUSED]) - this[MAYBE_EMIT_END]() - return this - } - - // don't let the internal resume be overwritten - [RESUME] () { - if (this[DESTROYED]) - return - - this[PAUSED] = false - this[FLOWING] = true - this.emit('resume') - if (this.buffer.length) - this[FLUSH]() - else if (this[EOF]) - this[MAYBE_EMIT_END]() - else - this.emit('drain') - } - - resume () { - return this[RESUME]() - } - - pause () { - this[FLOWING] = false - this[PAUSED] = true - } - - get destroyed () { - return this[DESTROYED] - } - - get flowing () { - return this[FLOWING] - } - - get paused () { - return this[PAUSED] - } - - [BUFFERPUSH] (chunk) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] += 1 - else - this[BUFFERLENGTH] += chunk.length - this.buffer.push(chunk) - } - - [BUFFERSHIFT] () { - if (this.buffer.length) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] -= 1 - else - this[BUFFERLENGTH] -= this.buffer[0].length - } - return this.buffer.shift() - } - - [FLUSH] (noDrain) { - do {} while (this[FLUSHCHUNK](this[BUFFERSHIFT]())) - - if (!noDrain && !this.buffer.length && !this[EOF]) - this.emit('drain') - } - - [FLUSHCHUNK] (chunk) { - return chunk ? (this.emit('data', chunk), this.flowing) : false - } - - pipe (dest, opts) { - if (this[DESTROYED]) - return - - const ended = this[EMITTED_END] - opts = opts || {} - if (dest === proc.stdout || dest === proc.stderr) - opts.end = false - else - opts.end = opts.end !== false - opts.proxyErrors = !!opts.proxyErrors - - // piping an ended stream ends immediately - if (ended) { - if (opts.end) - dest.end() - } else { - this.pipes.push(!opts.proxyErrors ? new Pipe(this, dest, opts) - : new PipeProxyErrors(this, dest, opts)) - if (this[ASYNC]) - defer(() => this[RESUME]()) - else - this[RESUME]() - } - - return dest - } - - unpipe (dest) { - const p = this.pipes.find(p => p.dest === dest) - if (p) { - this.pipes.splice(this.pipes.indexOf(p), 1) - p.unpipe() - } - } - - addListener (ev, fn) { - return this.on(ev, fn) - } - - on (ev, fn) { - const ret = super.on(ev, fn) - if (ev === 'data' && !this.pipes.length && !this.flowing) - this[RESUME]() - else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) - super.emit('readable') - else if (isEndish(ev) && this[EMITTED_END]) { - super.emit(ev) - this.removeAllListeners(ev) - } else if (ev === 'error' && this[EMITTED_ERROR]) { - if (this[ASYNC]) - defer(() => fn.call(this, this[EMITTED_ERROR])) - else - fn.call(this, this[EMITTED_ERROR]) - } - return ret - } - - get emittedEnd () { - return this[EMITTED_END] - } - - [MAYBE_EMIT_END] () { - if (!this[EMITTING_END] && - !this[EMITTED_END] && - !this[DESTROYED] && - this.buffer.length === 0 && - this[EOF]) { - this[EMITTING_END] = true - this.emit('end') - this.emit('prefinish') - this.emit('finish') - if (this[CLOSED]) - this.emit('close') - this[EMITTING_END] = false - } - } - - emit (ev, data, ...extra) { - // error and close are only events allowed after calling destroy() - if (ev !== 'error' && ev !== 'close' && ev !== DESTROYED && this[DESTROYED]) - return - else if (ev === 'data') { - return !data ? false - : this[ASYNC] ? defer(() => this[EMITDATA](data)) - : this[EMITDATA](data) - } else if (ev === 'end') { - return this[EMITEND]() - } else if (ev === 'close') { - this[CLOSED] = true - // don't emit close before 'end' and 'finish' - if (!this[EMITTED_END] && !this[DESTROYED]) - return - const ret = super.emit('close') - this.removeAllListeners('close') - return ret - } else if (ev === 'error') { - this[EMITTED_ERROR] = data - const ret = super.emit('error', data) - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'resume') { - const ret = super.emit('resume') - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'finish' || ev === 'prefinish') { - const ret = super.emit(ev) - this.removeAllListeners(ev) - return ret - } - - // Some other unknown event - const ret = super.emit(ev, data, ...extra) - this[MAYBE_EMIT_END]() - return ret - } - - [EMITDATA] (data) { - for (const p of this.pipes) { - if (p.dest.write(data) === false) - this.pause() - } - const ret = super.emit('data', data) - this[MAYBE_EMIT_END]() - return ret - } - - [EMITEND] () { - if (this[EMITTED_END]) - return - - this[EMITTED_END] = true - this.readable = false - if (this[ASYNC]) - defer(() => this[EMITEND2]()) - else - this[EMITEND2]() - } - - [EMITEND2] () { - if (this[DECODER]) { - const data = this[DECODER].end() - if (data) { - for (const p of this.pipes) { - p.dest.write(data) + return toolPath; +} +exports.find = find; +/** + * Finds the paths to all versions of a tool that are installed in the local tool cache + * + * @param toolName name of the tool + * @param arch optional arch. defaults to arch of computer + */ +function findAllVersions(toolName, arch) { + const versions = []; + arch = arch || os.arch(); + const toolPath = path.join(_getCacheDirectory(), toolName); + if (fs.existsSync(toolPath)) { + const children = fs.readdirSync(toolPath); + for (const child of children) { + if (isExplicitVersion(child)) { + const fullPath = path.join(toolPath, child, arch || ''); + if (fs.existsSync(fullPath) && fs.existsSync(`${fullPath}.complete`)) { + versions.push(child); + } + } } - super.emit('data', data) - } - } - - for (const p of this.pipes) { - p.end() - } - const ret = super.emit('end') - this.removeAllListeners('end') - return ret - } - - // const all = await stream.collect() - collect () { - const buf = [] - if (!this[OBJECTMODE]) - buf.dataLength = 0 - // set the promise first, in case an error is raised - // by triggering the flow here. - const p = this.promise() - this.on('data', c => { - buf.push(c) - if (!this[OBJECTMODE]) - buf.dataLength += c.length - }) - return p.then(() => buf) - } - - // const data = await stream.concat() - concat () { - return this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this.collect().then(buf => - this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this[ENCODING] ? buf.join('') : Buffer.concat(buf, buf.dataLength)) - } - - // stream.promise().then(() => done, er => emitted error) - promise () { - return new Promise((resolve, reject) => { - this.on(DESTROYED, () => reject(new Error('stream destroyed'))) - this.on('error', er => reject(er)) - this.on('end', () => resolve()) - }) - } - - // for await (let chunk of stream) - [ASYNCITERATOR] () { - const next = () => { - const res = this.read() - if (res !== null) - return Promise.resolve({ done: false, value: res }) - - if (this[EOF]) - return Promise.resolve({ done: true }) - - let resolve = null - let reject = null - const onerr = er => { - this.removeListener('data', ondata) - this.removeListener('end', onend) - reject(er) - } - const ondata = value => { - this.removeListener('error', onerr) - this.removeListener('end', onend) - this.pause() - resolve({ value: value, done: !!this[EOF] }) - } - const onend = () => { - this.removeListener('error', onerr) - this.removeListener('data', ondata) - resolve({ done: true }) - } - const ondestroy = () => onerr(new Error('stream destroyed')) - return new Promise((res, rej) => { - reject = rej - resolve = res - this.once(DESTROYED, ondestroy) - this.once('error', onerr) - this.once('end', onend) - this.once('data', ondata) - }) - } - - return { next } - } - - // for (let chunk of stream) - [ITERATOR] () { - const next = () => { - const value = this.read() - const done = value === null - return { value, done } - } - return { next } - } - - destroy (er) { - if (this[DESTROYED]) { - if (er) - this.emit('error', er) - else - this.emit(DESTROYED) - return this } - - this[DESTROYED] = true - - // throw away all buffered data, it's never coming out - this.buffer.length = 0 - this[BUFFERLENGTH] = 0 - - if (typeof this.close === 'function' && !this[CLOSED]) - this.close() - - if (er) - this.emit('error', er) - else // if no error to emit, still reject pending promises - this.emit(DESTROYED) - - return this - } - - static isStream (s) { - return !!s && (s instanceof Minipass || s instanceof Stream || - s instanceof EE && ( - typeof s.pipe === 'function' || // readable - (typeof s.write === 'function' && typeof s.end === 'function') // writable - )) - } -} - - -/***/ }), - -/***/ 1585: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const {PassThrough: PassThroughStream} = __nccwpck_require__(2781); - -module.exports = options => { - options = {...options}; - - const {array} = options; - let {encoding} = options; - const isBuffer = encoding === 'buffer'; - let objectMode = false; - - if (array) { - objectMode = !(encoding || isBuffer); - } else { - encoding = encoding || 'utf8'; - } - - if (isBuffer) { - encoding = null; - } - - const stream = new PassThroughStream({objectMode}); - - if (encoding) { - stream.setEncoding(encoding); - } - - let length = 0; - const chunks = []; - - stream.on('data', chunk => { - chunks.push(chunk); - - if (objectMode) { - length = chunks.length; - } else { - length += chunk.length; - } - }); - - stream.getBufferedValue = () => { - if (array) { - return chunks; - } - - return isBuffer ? Buffer.concat(chunks, length) : chunks.join(''); - }; - - stream.getBufferedLength = () => length; - - return stream; -}; - - -/***/ }), - -/***/ 1766: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const {constants: BufferConstants} = __nccwpck_require__(4300); -const stream = __nccwpck_require__(2781); -const {promisify} = __nccwpck_require__(3837); -const bufferStream = __nccwpck_require__(1585); - -const streamPipelinePromisified = promisify(stream.pipeline); - -class MaxBufferError extends Error { - constructor() { - super('maxBuffer exceeded'); - this.name = 'MaxBufferError'; - } + return versions; } - -async function getStream(inputStream, options) { - if (!inputStream) { - throw new Error('Expected a stream'); - } - - options = { - maxBuffer: Infinity, - ...options - }; - - const {maxBuffer} = options; - const stream = bufferStream(options); - - await new Promise((resolve, reject) => { - const rejectPromise = error => { - // Don't retrieve an oversized buffer. - if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) { - error.bufferedData = stream.getBufferedValue(); - } - - reject(error); - }; - - (async () => { - try { - await streamPipelinePromisified(inputStream, stream); - resolve(); - } catch (error) { - rejectPromise(error); - } - })(); - - stream.on('data', () => { - if (stream.getBufferedLength() > maxBuffer) { - rejectPromise(new MaxBufferError()); - } - }); - }); - - return stream.getBufferedValue(); -} - -module.exports = getStream; -module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'}); -module.exports.array = (stream, options) => getStream(stream, {...options, array: true}); -module.exports.MaxBufferError = MaxBufferError; - - -/***/ }), - -/***/ 1002: -/***/ ((module) => { - -"use strict"; - -// rfc7231 6.1 -const statusCodeCacheableByDefault = new Set([ - 200, - 203, - 204, - 206, - 300, - 301, - 308, - 404, - 405, - 410, - 414, - 501, -]); - -// This implementation does not understand partial responses (206) -const understoodStatuses = new Set([ - 200, - 203, - 204, - 300, - 301, - 302, - 303, - 307, - 308, - 404, - 405, - 410, - 414, - 501, -]); - -const errorStatusCodes = new Set([ - 500, - 502, - 503, - 504, -]); - -const hopByHopHeaders = { - date: true, // included, because we add Age update Date - connection: true, - 'keep-alive': true, - 'proxy-authenticate': true, - 'proxy-authorization': true, - te: true, - trailer: true, - 'transfer-encoding': true, - upgrade: true, -}; - -const excludedFromRevalidationUpdate = { - // Since the old body is reused, it doesn't make sense to change properties of the body - 'content-length': true, - 'content-encoding': true, - 'transfer-encoding': true, - 'content-range': true, -}; - -function toNumberOrZero(s) { - const n = parseInt(s, 10); - return isFinite(n) ? n : 0; -} - -// RFC 5861 -function isErrorResponse(response) { - // consider undefined response as faulty - if(!response) { - return true - } - return errorStatusCodes.has(response.status); -} - -function parseCacheControl(header) { - const cc = {}; - if (!header) return cc; - - // TODO: When there is more than one value present for a given directive (e.g., two Expires header fields, multiple Cache-Control: max-age directives), - // the directive's value is considered invalid. Caches are encouraged to consider responses that have invalid freshness information to be stale - const parts = header.trim().split(/,/); - for (const part of parts) { - const [k, v] = part.split(/=/, 2); - cc[k.trim()] = v === undefined ? true : v.trim().replace(/^"|"$/g, ''); - } - - return cc; -} - -function formatCacheControl(cc) { - let parts = []; - for (const k in cc) { - const v = cc[k]; - parts.push(v === true ? k : k + '=' + v); - } - if (!parts.length) { - return undefined; - } - return parts.join(', '); -} - -module.exports = class CachePolicy { - constructor( - req, - res, - { - shared, - cacheHeuristic, - immutableMinTimeToLive, - ignoreCargoCult, - _fromObject, - } = {} - ) { - if (_fromObject) { - this._fromObject(_fromObject); - return; - } - - if (!res || !res.headers) { - throw Error('Response headers missing'); - } - this._assertRequestHasHeaders(req); - - this._responseTime = this.now(); - this._isShared = shared !== false; - this._cacheHeuristic = - undefined !== cacheHeuristic ? cacheHeuristic : 0.1; // 10% matches IE - this._immutableMinTtl = - undefined !== immutableMinTimeToLive - ? immutableMinTimeToLive - : 24 * 3600 * 1000; - - this._status = 'status' in res ? res.status : 200; - this._resHeaders = res.headers; - this._rescc = parseCacheControl(res.headers['cache-control']); - this._method = 'method' in req ? req.method : 'GET'; - this._url = req.url; - this._host = req.headers.host; - this._noAuthorization = !req.headers.authorization; - this._reqHeaders = res.headers.vary ? req.headers : null; // Don't keep all request headers if they won't be used - this._reqcc = parseCacheControl(req.headers['cache-control']); - - // Assume that if someone uses legacy, non-standard uncecessary options they don't understand caching, - // so there's no point stricly adhering to the blindly copy&pasted directives. - if ( - ignoreCargoCult && - 'pre-check' in this._rescc && - 'post-check' in this._rescc - ) { - delete this._rescc['pre-check']; - delete this._rescc['post-check']; - delete this._rescc['no-cache']; - delete this._rescc['no-store']; - delete this._rescc['must-revalidate']; - this._resHeaders = Object.assign({}, this._resHeaders, { - 'cache-control': formatCacheControl(this._rescc), - }); - delete this._resHeaders.expires; - delete this._resHeaders.pragma; - } - - // When the Cache-Control header field is not present in a request, caches MUST consider the no-cache request pragma-directive - // as having the same effect as if "Cache-Control: no-cache" were present (see Section 5.2.1). - if ( - res.headers['cache-control'] == null && - /no-cache/.test(res.headers.pragma) - ) { - this._rescc['no-cache'] = true; - } - } - - now() { - return Date.now(); - } - - storable() { - // The "no-store" request directive indicates that a cache MUST NOT store any part of either this request or any response to it. - return !!( - !this._reqcc['no-store'] && - // A cache MUST NOT store a response to any request, unless: - // The request method is understood by the cache and defined as being cacheable, and - ('GET' === this._method || - 'HEAD' === this._method || - ('POST' === this._method && this._hasExplicitExpiration())) && - // the response status code is understood by the cache, and - understoodStatuses.has(this._status) && - // the "no-store" cache directive does not appear in request or response header fields, and - !this._rescc['no-store'] && - // the "private" response directive does not appear in the response, if the cache is shared, and - (!this._isShared || !this._rescc.private) && - // the Authorization header field does not appear in the request, if the cache is shared, - (!this._isShared || - this._noAuthorization || - this._allowsStoringAuthenticated()) && - // the response either: - // contains an Expires header field, or - (this._resHeaders.expires || - // contains a max-age response directive, or - // contains a s-maxage response directive and the cache is shared, or - // contains a public response directive. - this._rescc['max-age'] || - (this._isShared && this._rescc['s-maxage']) || - this._rescc.public || - // has a status code that is defined as cacheable by default - statusCodeCacheableByDefault.has(this._status)) - ); - } - - _hasExplicitExpiration() { - // 4.2.1 Calculating Freshness Lifetime - return ( - (this._isShared && this._rescc['s-maxage']) || - this._rescc['max-age'] || - this._resHeaders.expires - ); - } - - _assertRequestHasHeaders(req) { - if (!req || !req.headers) { - throw Error('Request headers missing'); +exports.findAllVersions = findAllVersions; +function getManifestFromRepo(owner, repo, auth, branch = 'master') { + return __awaiter(this, void 0, void 0, function* () { + let releases = []; + const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}`; + const http = new httpm.HttpClient('tool-cache'); + const headers = {}; + if (auth) { + core.debug('set auth'); + headers.authorization = auth; + } + const response = yield http.getJson(treeUrl, headers); + if (!response.result) { + return releases; + } + let manifestUrl = ''; + for (const item of response.result.tree) { + if (item.path === 'versions-manifest.json') { + manifestUrl = item.url; + break; + } } - } - - satisfiesWithoutRevalidation(req) { - this._assertRequestHasHeaders(req); - - // When presented with a request, a cache MUST NOT reuse a stored response, unless: - // the presented request does not contain the no-cache pragma (Section 5.4), nor the no-cache cache directive, - // unless the stored response is successfully validated (Section 4.3), and - const requestCC = parseCacheControl(req.headers['cache-control']); - if (requestCC['no-cache'] || /no-cache/.test(req.headers.pragma)) { - return false; - } - - if (requestCC['max-age'] && this.age() > requestCC['max-age']) { - return false; - } - - if ( - requestCC['min-fresh'] && - this.timeToLive() < 1000 * requestCC['min-fresh'] - ) { - return false; - } - - // the stored response is either: - // fresh, or allowed to be served stale - if (this.stale()) { - const allowsStale = - requestCC['max-stale'] && - !this._rescc['must-revalidate'] && - (true === requestCC['max-stale'] || - requestCC['max-stale'] > this.age() - this.maxAge()); - if (!allowsStale) { - return false; - } - } - - return this._requestMatches(req, false); - } - - _requestMatches(req, allowHeadMethod) { - // The presented effective request URI and that of the stored response match, and - return ( - (!this._url || this._url === req.url) && - this._host === req.headers.host && - // the request method associated with the stored response allows it to be used for the presented request, and - (!req.method || - this._method === req.method || - (allowHeadMethod && 'HEAD' === req.method)) && - // selecting header fields nominated by the stored response (if any) match those presented, and - this._varyMatches(req) - ); - } - - _allowsStoringAuthenticated() { - // following Cache-Control response directives (Section 5.2.2) have such an effect: must-revalidate, public, and s-maxage. - return ( - this._rescc['must-revalidate'] || - this._rescc.public || - this._rescc['s-maxage'] - ); - } - - _varyMatches(req) { - if (!this._resHeaders.vary) { - return true; - } - - // A Vary header field-value of "*" always fails to match - if (this._resHeaders.vary === '*') { - return false; - } - - const fields = this._resHeaders.vary - .trim() - .toLowerCase() - .split(/\s*,\s*/); - for (const name of fields) { - if (req.headers[name] !== this._reqHeaders[name]) return false; - } - return true; - } - - _copyWithoutHopByHopHeaders(inHeaders) { - const headers = {}; - for (const name in inHeaders) { - if (hopByHopHeaders[name]) continue; - headers[name] = inHeaders[name]; - } - // 9.1. Connection - if (inHeaders.connection) { - const tokens = inHeaders.connection.trim().split(/\s*,\s*/); - for (const name of tokens) { - delete headers[name]; - } - } - if (headers.warning) { - const warnings = headers.warning.split(/,/).filter(warning => { - return !/^\s*1[0-9][0-9]/.test(warning); - }); - if (!warnings.length) { - delete headers.warning; - } else { - headers.warning = warnings.join(',').trim(); - } - } - return headers; - } - - responseHeaders() { - const headers = this._copyWithoutHopByHopHeaders(this._resHeaders); - const age = this.age(); - - // A cache SHOULD generate 113 warning if it heuristically chose a freshness - // lifetime greater than 24 hours and the response's age is greater than 24 hours. - if ( - age > 3600 * 24 && - !this._hasExplicitExpiration() && - this.maxAge() > 3600 * 24 - ) { - headers.warning = - (headers.warning ? `${headers.warning}, ` : '') + - '113 - "rfc7234 5.5.4"'; - } - headers.age = `${Math.round(age)}`; - headers.date = new Date(this.now()).toUTCString(); - return headers; - } - - /** - * Value of the Date response header or current time if Date was invalid - * @return timestamp - */ - date() { - const serverDate = Date.parse(this._resHeaders.date); - if (isFinite(serverDate)) { - return serverDate; - } - return this._responseTime; - } - - /** - * Value of the Age header, in seconds, updated for the current time. - * May be fractional. - * - * @return Number - */ - age() { - let age = this._ageValue(); - - const residentTime = (this.now() - this._responseTime) / 1000; - return age + residentTime; - } - - _ageValue() { - return toNumberOrZero(this._resHeaders.age); - } - - /** - * Value of applicable max-age (or heuristic equivalent) in seconds. This counts since response's `Date`. - * - * For an up-to-date value, see `timeToLive()`. - * - * @return Number - */ - maxAge() { - if (!this.storable() || this._rescc['no-cache']) { - return 0; - } - - // Shared responses with cookies are cacheable according to the RFC, but IMHO it'd be unwise to do so by default - // so this implementation requires explicit opt-in via public header - if ( - this._isShared && - (this._resHeaders['set-cookie'] && - !this._rescc.public && - !this._rescc.immutable) - ) { - return 0; - } - - if (this._resHeaders.vary === '*') { - return 0; - } - - if (this._isShared) { - if (this._rescc['proxy-revalidate']) { - return 0; - } - // if a response includes the s-maxage directive, a shared cache recipient MUST ignore the Expires field. - if (this._rescc['s-maxage']) { - return toNumberOrZero(this._rescc['s-maxage']); - } - } - - // If a response includes a Cache-Control field with the max-age directive, a recipient MUST ignore the Expires field. - if (this._rescc['max-age']) { - return toNumberOrZero(this._rescc['max-age']); - } - - const defaultMinTtl = this._rescc.immutable ? this._immutableMinTtl : 0; - - const serverDate = this.date(); - if (this._resHeaders.expires) { - const expires = Date.parse(this._resHeaders.expires); - // A cache recipient MUST interpret invalid date formats, especially the value "0", as representing a time in the past (i.e., "already expired"). - if (Number.isNaN(expires) || expires < serverDate) { - return 0; - } - return Math.max(defaultMinTtl, (expires - serverDate) / 1000); - } - - if (this._resHeaders['last-modified']) { - const lastModified = Date.parse(this._resHeaders['last-modified']); - if (isFinite(lastModified) && serverDate > lastModified) { - return Math.max( - defaultMinTtl, - ((serverDate - lastModified) / 1000) * this._cacheHeuristic - ); + headers['accept'] = 'application/vnd.github.VERSION.raw'; + let versionsRaw = yield (yield http.get(manifestUrl, headers)).readBody(); + if (versionsRaw) { + // shouldn't be needed but protects against invalid json saved with BOM + versionsRaw = versionsRaw.replace(/^\uFEFF/, ''); + try { + releases = JSON.parse(versionsRaw); } - } - - return defaultMinTtl; - } - - timeToLive() { - const age = this.maxAge() - this.age(); - const staleIfErrorAge = age + toNumberOrZero(this._rescc['stale-if-error']); - const staleWhileRevalidateAge = age + toNumberOrZero(this._rescc['stale-while-revalidate']); - return Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1000; - } - - stale() { - return this.maxAge() <= this.age(); - } - - _useStaleIfError() { - return this.maxAge() + toNumberOrZero(this._rescc['stale-if-error']) > this.age(); - } - - useStaleWhileRevalidate() { - return this.maxAge() + toNumberOrZero(this._rescc['stale-while-revalidate']) > this.age(); - } - - static fromObject(obj) { - return new this(undefined, undefined, { _fromObject: obj }); - } - - _fromObject(obj) { - if (this._responseTime) throw Error('Reinitialized'); - if (!obj || obj.v !== 1) throw Error('Invalid serialization'); - - this._responseTime = obj.t; - this._isShared = obj.sh; - this._cacheHeuristic = obj.ch; - this._immutableMinTtl = - obj.imm !== undefined ? obj.imm : 24 * 3600 * 1000; - this._status = obj.st; - this._resHeaders = obj.resh; - this._rescc = obj.rescc; - this._method = obj.m; - this._url = obj.u; - this._host = obj.h; - this._noAuthorization = obj.a; - this._reqHeaders = obj.reqh; - this._reqcc = obj.reqcc; - } - - toObject() { - return { - v: 1, - t: this._responseTime, - sh: this._isShared, - ch: this._cacheHeuristic, - imm: this._immutableMinTtl, - st: this._status, - resh: this._resHeaders, - rescc: this._rescc, - m: this._method, - u: this._url, - h: this._host, - a: this._noAuthorization, - reqh: this._reqHeaders, - reqcc: this._reqcc, - }; - } - - /** - * Headers for sending to the origin server to revalidate stale response. - * Allows server to return 304 to allow reuse of the previous response. - * - * Hop by hop headers are always stripped. - * Revalidation headers may be added or removed, depending on request. - */ - revalidationHeaders(incomingReq) { - this._assertRequestHasHeaders(incomingReq); - const headers = this._copyWithoutHopByHopHeaders(incomingReq.headers); - - // This implementation does not understand range requests - delete headers['if-range']; - - if (!this._requestMatches(incomingReq, true) || !this.storable()) { - // revalidation allowed via HEAD - // not for the same resource, or wasn't allowed to be cached anyway - delete headers['if-none-match']; - delete headers['if-modified-since']; - return headers; - } - - /* MUST send that entity-tag in any cache validation request (using If-Match or If-None-Match) if an entity-tag has been provided by the origin server. */ - if (this._resHeaders.etag) { - headers['if-none-match'] = headers['if-none-match'] - ? `${headers['if-none-match']}, ${this._resHeaders.etag}` - : this._resHeaders.etag; - } - - // Clients MAY issue simple (non-subrange) GET requests with either weak validators or strong validators. Clients MUST NOT use weak validators in other forms of request. - const forbidsWeakValidators = - headers['accept-ranges'] || - headers['if-match'] || - headers['if-unmodified-since'] || - (this._method && this._method != 'GET'); - - /* SHOULD send the Last-Modified value in non-subrange cache validation requests (using If-Modified-Since) if only a Last-Modified value has been provided by the origin server. - Note: This implementation does not understand partial responses (206) */ - if (forbidsWeakValidators) { - delete headers['if-modified-since']; - - if (headers['if-none-match']) { - const etags = headers['if-none-match'] - .split(/,/) - .filter(etag => { - return !/^\s*W\//.test(etag); - }); - if (!etags.length) { - delete headers['if-none-match']; - } else { - headers['if-none-match'] = etags.join(',').trim(); - } - } - } else if ( - this._resHeaders['last-modified'] && - !headers['if-modified-since'] - ) { - headers['if-modified-since'] = this._resHeaders['last-modified']; - } - - return headers; - } - - /** - * Creates new CachePolicy with information combined from the previews response, - * and the new revalidation response. - * - * Returns {policy, modified} where modified is a boolean indicating - * whether the response body has been modified, and old cached body can't be used. - * - * @return {Object} {policy: CachePolicy, modified: Boolean} - */ - revalidatedPolicy(request, response) { - this._assertRequestHasHeaders(request); - if(this._useStaleIfError() && isErrorResponse(response)) { // I consider the revalidation request unsuccessful - return { - modified: false, - matches: false, - policy: this, - }; - } - if (!response || !response.headers) { - throw Error('Response headers missing'); - } - - // These aren't going to be supported exactly, since one CachePolicy object - // doesn't know about all the other cached objects. - let matches = false; - if (response.status !== undefined && response.status != 304) { - matches = false; - } else if ( - response.headers.etag && - !/^\s*W\//.test(response.headers.etag) - ) { - // "All of the stored responses with the same strong validator are selected. - // If none of the stored responses contain the same strong validator, - // then the cache MUST NOT use the new response to update any stored responses." - matches = - this._resHeaders.etag && - this._resHeaders.etag.replace(/^\s*W\//, '') === - response.headers.etag; - } else if (this._resHeaders.etag && response.headers.etag) { - // "If the new response contains a weak validator and that validator corresponds - // to one of the cache's stored responses, - // then the most recent of those matching stored responses is selected for update." - matches = - this._resHeaders.etag.replace(/^\s*W\//, '') === - response.headers.etag.replace(/^\s*W\//, ''); - } else if (this._resHeaders['last-modified']) { - matches = - this._resHeaders['last-modified'] === - response.headers['last-modified']; - } else { - // If the new response does not include any form of validator (such as in the case where - // a client generates an If-Modified-Since request from a source other than the Last-Modified - // response header field), and there is only one stored response, and that stored response also - // lacks a validator, then that stored response is selected for update. - if ( - !this._resHeaders.etag && - !this._resHeaders['last-modified'] && - !response.headers.etag && - !response.headers['last-modified'] - ) { - matches = true; - } - } - - if (!matches) { - return { - policy: new this.constructor(request, response), - // Client receiving 304 without body, even if it's invalid/mismatched has no option - // but to reuse a cached body. We don't have a good way to tell clients to do - // error recovery in such case. - modified: response.status != 304, - matches: false, - }; - } - - // use other header fields provided in the 304 (Not Modified) response to replace all instances - // of the corresponding header fields in the stored response. - const headers = {}; - for (const k in this._resHeaders) { - headers[k] = - k in response.headers && !excludedFromRevalidationUpdate[k] - ? response.headers[k] - : this._resHeaders[k]; - } - - const newResponse = Object.assign({}, response, { - status: this._status, - method: this._method, - headers, - }); - return { - policy: new this.constructor(request, newResponse, { - shared: this._isShared, - cacheHeuristic: this._cacheHeuristic, - immutableMinTimeToLive: this._immutableMinTtl, - }), - modified: false, - matches: true, - }; - } -}; - - -/***/ }), - -/***/ 9898: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -// See https://github.com/facebook/jest/issues/2549 -// eslint-disable-next-line node/prefer-global/url -const {URL} = __nccwpck_require__(7310); -const EventEmitter = __nccwpck_require__(2361); -const tls = __nccwpck_require__(4404); -const http2 = __nccwpck_require__(5158); -const QuickLRU = __nccwpck_require__(9273); -const delayAsyncDestroy = __nccwpck_require__(9237); - -const kCurrentStreamCount = Symbol('currentStreamCount'); -const kRequest = Symbol('request'); -const kOriginSet = Symbol('cachedOriginSet'); -const kGracefullyClosing = Symbol('gracefullyClosing'); -const kLength = Symbol('length'); - -const nameKeys = [ - // Not an Agent option actually - 'createConnection', - - // `http2.connect()` options - 'maxDeflateDynamicTableSize', - 'maxSettings', - 'maxSessionMemory', - 'maxHeaderListPairs', - 'maxOutstandingPings', - 'maxReservedRemoteStreams', - 'maxSendHeaderBlockLength', - 'paddingStrategy', - 'peerMaxConcurrentStreams', - 'settings', - - // `tls.connect()` source options - 'family', - 'localAddress', - 'rejectUnauthorized', - - // `tls.connect()` secure context options - 'pskCallback', - 'minDHSize', - - // `tls.connect()` destination options - // - `servername` is automatically validated, skip it - // - `host` and `port` just describe the destination server, - 'path', - 'socket', - - // `tls.createSecureContext()` options - 'ca', - 'cert', - 'sigalgs', - 'ciphers', - 'clientCertEngine', - 'crl', - 'dhparam', - 'ecdhCurve', - 'honorCipherOrder', - 'key', - 'privateKeyEngine', - 'privateKeyIdentifier', - 'maxVersion', - 'minVersion', - 'pfx', - 'secureOptions', - 'secureProtocol', - 'sessionIdContext', - 'ticketKeys' -]; - -const getSortedIndex = (array, value, compare) => { - let low = 0; - let high = array.length; - - while (low < high) { - const mid = (low + high) >>> 1; - - if (compare(array[mid], value)) { - low = mid + 1; - } else { - high = mid; - } - } - - return low; -}; - -const compareSessions = (a, b) => a.remoteSettings.maxConcurrentStreams > b.remoteSettings.maxConcurrentStreams; - -// See https://tools.ietf.org/html/rfc8336 -const closeCoveredSessions = (where, session) => { - // Clients SHOULD NOT emit new requests on any connection whose Origin - // Set is a proper subset of another connection's Origin Set, and they - // SHOULD close it once all outstanding requests are satisfied. - for (let index = 0; index < where.length; index++) { - const coveredSession = where[index]; - - if ( - // Unfortunately `.every()` returns true for an empty array - coveredSession[kOriginSet].length > 0 - - // The set is a proper subset when its length is less than the other set. - && coveredSession[kOriginSet].length < session[kOriginSet].length - - // And the other set includes all elements of the subset. - && coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) - - // Makes sure that the session can handle all requests from the covered session. - && (coveredSession[kCurrentStreamCount] + session[kCurrentStreamCount]) <= session.remoteSettings.maxConcurrentStreams - ) { - // This allows pending requests to finish and prevents making new requests. - gracefullyClose(coveredSession); - } - } -}; - -// This is basically inverted `closeCoveredSessions(...)`. -const closeSessionIfCovered = (where, coveredSession) => { - for (let index = 0; index < where.length; index++) { - const session = where[index]; - - if ( - coveredSession[kOriginSet].length > 0 - && coveredSession[kOriginSet].length < session[kOriginSet].length - && coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) - && (coveredSession[kCurrentStreamCount] + session[kCurrentStreamCount]) <= session.remoteSettings.maxConcurrentStreams - ) { - gracefullyClose(coveredSession); - - return true; - } - } - - return false; -}; - -const gracefullyClose = session => { - session[kGracefullyClosing] = true; - - if (session[kCurrentStreamCount] === 0) { - session.close(); - } -}; - -class Agent extends EventEmitter { - constructor({timeout = 0, maxSessions = Number.POSITIVE_INFINITY, maxEmptySessions = 10, maxCachedTlsSessions = 100} = {}) { - super(); - - // SESSIONS[NORMALIZED_OPTIONS] = []; - this.sessions = {}; - - // The queue for creating new sessions. It looks like this: - // QUEUE[NORMALIZED_OPTIONS][NORMALIZED_ORIGIN] = ENTRY_FUNCTION - // - // It's faster when there are many origins. If there's only one, then QUEUE[`${options}:${origin}`] is faster. - // I guess object creation / deletion is causing the slowdown. - // - // The entry function has `listeners`, `completed` and `destroyed` properties. - // `listeners` is an array of objects containing `resolve` and `reject` functions. - // `completed` is a boolean. It's set to true after ENTRY_FUNCTION is executed. - // `destroyed` is a boolean. If it's set to true, the session will be destroyed if hasn't connected yet. - this.queue = {}; - - // Each session will use this timeout value. - this.timeout = timeout; - - // Max sessions in total - this.maxSessions = maxSessions; - - // Max empty sessions in total - this.maxEmptySessions = maxEmptySessions; - - this._emptySessionCount = 0; - this._sessionCount = 0; - - // We don't support push streams by default. - this.settings = { - enablePush: false, - initialWindowSize: 1024 * 1024 * 32 // 32MB, see https://github.com/nodejs/node/issues/38426 - }; - - // Reusing TLS sessions increases performance. - this.tlsSessionCache = new QuickLRU({maxSize: maxCachedTlsSessions}); - } - - get protocol() { - return 'https:'; - } - - normalizeOptions(options) { - let normalized = ''; - - for (let index = 0; index < nameKeys.length; index++) { - const key = nameKeys[index]; - - normalized += ':'; - - if (options && options[key] !== undefined) { - normalized += options[key]; - } - } - - return normalized; - } - - _processQueue() { - if (this._sessionCount >= this.maxSessions) { - this.closeEmptySessions(this.maxSessions - this._sessionCount + 1); - return; - } - - // eslint-disable-next-line guard-for-in - for (const normalizedOptions in this.queue) { - // eslint-disable-next-line guard-for-in - for (const normalizedOrigin in this.queue[normalizedOptions]) { - const item = this.queue[normalizedOptions][normalizedOrigin]; - - // The entry function can be run only once. - if (!item.completed) { - item.completed = true; - - item(); - } - } - } - } - - _isBetterSession(thisStreamCount, thatStreamCount) { - return thisStreamCount > thatStreamCount; - } - - _accept(session, listeners, normalizedOrigin, options) { - let index = 0; - - while (index < listeners.length && session[kCurrentStreamCount] < session.remoteSettings.maxConcurrentStreams) { - // We assume `resolve(...)` calls `request(...)` *directly*, - // otherwise the session will get overloaded. - listeners[index].resolve(session); - - index++; - } - - listeners.splice(0, index); - - if (listeners.length > 0) { - this.getSession(normalizedOrigin, options, listeners); - listeners.length = 0; - } - } - - getSession(origin, options, listeners) { - return new Promise((resolve, reject) => { - if (Array.isArray(listeners) && listeners.length > 0) { - listeners = [...listeners]; - - // Resolve the current promise ASAP, we're just moving the listeners. - // They will be executed at a different time. - resolve(); - } else { - listeners = [{resolve, reject}]; - } - - try { - // Parse origin - if (typeof origin === 'string') { - origin = new URL(origin); - } else if (!(origin instanceof URL)) { - throw new TypeError('The `origin` argument needs to be a string or an URL object'); - } - - if (options) { - // Validate servername - const {servername} = options; - const {hostname} = origin; - if (servername && hostname !== servername) { - throw new Error(`Origin ${hostname} differs from servername ${servername}`); - } - } - } catch (error) { - for (let index = 0; index < listeners.length; index++) { - listeners[index].reject(error); - } - - return; - } - - const normalizedOptions = this.normalizeOptions(options); - const normalizedOrigin = origin.origin; - - if (normalizedOptions in this.sessions) { - const sessions = this.sessions[normalizedOptions]; - - let maxConcurrentStreams = -1; - let currentStreamsCount = -1; - let optimalSession; - - // We could just do this.sessions[normalizedOptions].find(...) but that isn't optimal. - // Additionally, we are looking for session which has biggest current pending streams count. - // - // |------------| |------------| |------------| |------------| - // | Session: A | | Session: B | | Session: C | | Session: D | - // | Pending: 5 |-| Pending: 8 |-| Pending: 9 |-| Pending: 4 | - // | Max: 10 | | Max: 10 | | Max: 9 | | Max: 5 | - // |------------| |------------| |------------| |------------| - // ^ - // | - // pick this one -- - // - for (let index = 0; index < sessions.length; index++) { - const session = sessions[index]; - - const sessionMaxConcurrentStreams = session.remoteSettings.maxConcurrentStreams; - - if (sessionMaxConcurrentStreams < maxConcurrentStreams) { - break; - } - - if (!session[kOriginSet].includes(normalizedOrigin)) { - continue; - } - - const sessionCurrentStreamsCount = session[kCurrentStreamCount]; - - if ( - sessionCurrentStreamsCount >= sessionMaxConcurrentStreams - || session[kGracefullyClosing] - // Unfortunately the `close` event isn't called immediately, - // so `session.destroyed` is `true`, but `session.closed` is `false`. - || session.destroyed - ) { - continue; - } - - // We only need set this once. - if (!optimalSession) { - maxConcurrentStreams = sessionMaxConcurrentStreams; - } - - // Either get the session which has biggest current stream count or the lowest. - if (this._isBetterSession(sessionCurrentStreamsCount, currentStreamsCount)) { - optimalSession = session; - currentStreamsCount = sessionCurrentStreamsCount; - } - } - - if (optimalSession) { - this._accept(optimalSession, listeners, normalizedOrigin, options); - return; - } - } - - if (normalizedOptions in this.queue) { - if (normalizedOrigin in this.queue[normalizedOptions]) { - // There's already an item in the queue, just attach ourselves to it. - this.queue[normalizedOptions][normalizedOrigin].listeners.push(...listeners); - return; - } - } else { - this.queue[normalizedOptions] = { - [kLength]: 0 - }; - } - - // The entry must be removed from the queue IMMEDIATELY when: - // 1. the session connects successfully, - // 2. an error occurs. - const removeFromQueue = () => { - // Our entry can be replaced. We cannot remove the new one. - if (normalizedOptions in this.queue && this.queue[normalizedOptions][normalizedOrigin] === entry) { - delete this.queue[normalizedOptions][normalizedOrigin]; - - if (--this.queue[normalizedOptions][kLength] === 0) { - delete this.queue[normalizedOptions]; - } - } - }; - - // The main logic is here - const entry = async () => { - this._sessionCount++; - - const name = `${normalizedOrigin}:${normalizedOptions}`; - let receivedSettings = false; - let socket; - - try { - const computedOptions = {...options}; - - if (computedOptions.settings === undefined) { - computedOptions.settings = this.settings; - } - - if (computedOptions.session === undefined) { - computedOptions.session = this.tlsSessionCache.get(name); - } - - const createConnection = computedOptions.createConnection || this.createConnection; - - // A hacky workaround to enable async `createConnection` - socket = await createConnection.call(this, origin, computedOptions); - computedOptions.createConnection = () => socket; - - const session = http2.connect(origin, computedOptions); - session[kCurrentStreamCount] = 0; - session[kGracefullyClosing] = false; - - // Node.js return https://false:443 instead of https://1.1.1.1:443 - const getOriginSet = () => { - const {socket} = session; - - let originSet; - if (socket.servername === false) { - socket.servername = socket.remoteAddress; - originSet = session.originSet; - socket.servername = false; - } else { - originSet = session.originSet; - } - - return originSet; - }; - - const isFree = () => session[kCurrentStreamCount] < session.remoteSettings.maxConcurrentStreams; - - session.socket.once('session', tlsSession => { - this.tlsSessionCache.set(name, tlsSession); - }); - - session.once('error', error => { - // Listeners are empty when the session successfully connected. - for (let index = 0; index < listeners.length; index++) { - listeners[index].reject(error); - } - - // The connection got broken, purge the cache. - this.tlsSessionCache.delete(name); - }); - - session.setTimeout(this.timeout, () => { - // Terminates all streams owned by this session. - session.destroy(); - }); - - session.once('close', () => { - this._sessionCount--; - - if (receivedSettings) { - // Assumes session `close` is emitted after request `close` - this._emptySessionCount--; - - // This cannot be moved to the stream logic, - // because there may be a session that hadn't made a single request. - const where = this.sessions[normalizedOptions]; - - if (where.length === 1) { - delete this.sessions[normalizedOptions]; - } else { - where.splice(where.indexOf(session), 1); - } - } else { - // Broken connection - removeFromQueue(); - - const error = new Error('Session closed without receiving a SETTINGS frame'); - error.code = 'HTTP2WRAPPER_NOSETTINGS'; - - for (let index = 0; index < listeners.length; index++) { - listeners[index].reject(error); - } - } - - // There may be another session awaiting. - this._processQueue(); - }); - - // Iterates over the queue and processes listeners. - const processListeners = () => { - const queue = this.queue[normalizedOptions]; - if (!queue) { - return; - } - - const originSet = session[kOriginSet]; - - for (let index = 0; index < originSet.length; index++) { - const origin = originSet[index]; - - if (origin in queue) { - const {listeners, completed} = queue[origin]; - - let index = 0; - - // Prevents session overloading. - while (index < listeners.length && isFree()) { - // We assume `resolve(...)` calls `request(...)` *directly*, - // otherwise the session will get overloaded. - listeners[index].resolve(session); - - index++; - } - - queue[origin].listeners.splice(0, index); - - if (queue[origin].listeners.length === 0 && !completed) { - delete queue[origin]; - - if (--queue[kLength] === 0) { - delete this.queue[normalizedOptions]; - break; - } - } - - // We're no longer free, no point in continuing. - if (!isFree()) { - break; - } - } - } - }; - - // The Origin Set cannot shrink. No need to check if it suddenly became covered by another one. - session.on('origin', () => { - session[kOriginSet] = getOriginSet() || []; - session[kGracefullyClosing] = false; - closeSessionIfCovered(this.sessions[normalizedOptions], session); - - if (session[kGracefullyClosing] || !isFree()) { - return; - } - - processListeners(); - - if (!isFree()) { - return; - } - - // Close covered sessions (if possible). - closeCoveredSessions(this.sessions[normalizedOptions], session); - }); - - session.once('remoteSettings', () => { - // The Agent could have been destroyed already. - if (entry.destroyed) { - const error = new Error('Agent has been destroyed'); - - for (let index = 0; index < listeners.length; index++) { - listeners[index].reject(error); - } - - session.destroy(); - return; - } - - // See https://github.com/nodejs/node/issues/38426 - if (session.setLocalWindowSize) { - session.setLocalWindowSize(1024 * 1024 * 4); // 4 MB - } - - session[kOriginSet] = getOriginSet() || []; - - if (session.socket.encrypted) { - const mainOrigin = session[kOriginSet][0]; - if (mainOrigin !== normalizedOrigin) { - const error = new Error(`Requested origin ${normalizedOrigin} does not match server ${mainOrigin}`); - - for (let index = 0; index < listeners.length; index++) { - listeners[index].reject(error); - } - - session.destroy(); - return; - } - } - - removeFromQueue(); - - { - const where = this.sessions; - - if (normalizedOptions in where) { - const sessions = where[normalizedOptions]; - sessions.splice(getSortedIndex(sessions, session, compareSessions), 0, session); - } else { - where[normalizedOptions] = [session]; - } - } - - receivedSettings = true; - this._emptySessionCount++; - - this.emit('session', session); - this._accept(session, listeners, normalizedOrigin, options); - - if (session[kCurrentStreamCount] === 0 && this._emptySessionCount > this.maxEmptySessions) { - this.closeEmptySessions(this._emptySessionCount - this.maxEmptySessions); - } - - // `session.remoteSettings.maxConcurrentStreams` might get increased - session.on('remoteSettings', () => { - if (!isFree()) { - return; - } - - processListeners(); - - if (!isFree()) { - return; - } - - // In case the Origin Set changes - closeCoveredSessions(this.sessions[normalizedOptions], session); - }); - }); - - // Shim `session.request()` in order to catch all streams - session[kRequest] = session.request; - session.request = (headers, streamOptions) => { - if (session[kGracefullyClosing]) { - throw new Error('The session is gracefully closing. No new streams are allowed.'); - } - - const stream = session[kRequest](headers, streamOptions); - - // The process won't exit until the session is closed or all requests are gone. - session.ref(); - - if (session[kCurrentStreamCount]++ === 0) { - this._emptySessionCount--; - } - - stream.once('close', () => { - if (--session[kCurrentStreamCount] === 0) { - this._emptySessionCount++; - session.unref(); - - if (this._emptySessionCount > this.maxEmptySessions || session[kGracefullyClosing]) { - session.close(); - return; - } - } - - if (session.destroyed || session.closed) { - return; - } - - if (isFree() && !closeSessionIfCovered(this.sessions[normalizedOptions], session)) { - closeCoveredSessions(this.sessions[normalizedOptions], session); - processListeners(); - - if (session[kCurrentStreamCount] === 0) { - this._processQueue(); - } - } - }); - - return stream; - }; - } catch (error) { - removeFromQueue(); - this._sessionCount--; - - for (let index = 0; index < listeners.length; index++) { - listeners[index].reject(error); - } - } - }; - - entry.listeners = listeners; - entry.completed = false; - entry.destroyed = false; - - this.queue[normalizedOptions][normalizedOrigin] = entry; - this.queue[normalizedOptions][kLength]++; - this._processQueue(); - }); - } - - request(origin, options, headers, streamOptions) { - return new Promise((resolve, reject) => { - this.getSession(origin, options, [{ - reject, - resolve: session => { - try { - const stream = session.request(headers, streamOptions); - - // Do not throw before `request(...)` has been awaited - delayAsyncDestroy(stream); - - resolve(stream); - } catch (error) { - reject(error); - } - } - }]); - }); - } - - async createConnection(origin, options) { - return Agent.connect(origin, options); - } - - static connect(origin, options) { - options.ALPNProtocols = ['h2']; - - const port = origin.port || 443; - const host = origin.hostname; - - if (typeof options.servername === 'undefined') { - options.servername = host; - } - - const socket = tls.connect(port, host, options); - - if (options.socket) { - socket._peername = { - family: undefined, - address: undefined, - port - }; - } - - return socket; - } - - closeEmptySessions(maxCount = Number.POSITIVE_INFINITY) { - let closedCount = 0; - - const {sessions} = this; - - // eslint-disable-next-line guard-for-in - for (const key in sessions) { - const thisSessions = sessions[key]; - - for (let index = 0; index < thisSessions.length; index++) { - const session = thisSessions[index]; - - if (session[kCurrentStreamCount] === 0) { - closedCount++; - session.close(); - - if (closedCount >= maxCount) { - return closedCount; - } - } - } - } - - return closedCount; - } - - destroy(reason) { - const {sessions, queue} = this; - - // eslint-disable-next-line guard-for-in - for (const key in sessions) { - const thisSessions = sessions[key]; - - for (let index = 0; index < thisSessions.length; index++) { - thisSessions[index].destroy(reason); - } - } - - // eslint-disable-next-line guard-for-in - for (const normalizedOptions in queue) { - const entries = queue[normalizedOptions]; - - // eslint-disable-next-line guard-for-in - for (const normalizedOrigin in entries) { - entries[normalizedOrigin].destroyed = true; - } - } - - // New requests should NOT attach to destroyed sessions - this.queue = {}; - this.tlsSessionCache.clear(); - } - - get emptySessionCount() { - return this._emptySessionCount; - } - - get pendingSessionCount() { - return this._sessionCount - this._emptySessionCount; - } - - get sessionCount() { - return this._sessionCount; - } -} - -Agent.kCurrentStreamCount = kCurrentStreamCount; -Agent.kGracefullyClosing = kGracefullyClosing; - -module.exports = { - Agent, - globalAgent: new Agent() -}; - - -/***/ }), - -/***/ 7167: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -// See https://github.com/facebook/jest/issues/2549 -// eslint-disable-next-line node/prefer-global/url -const {URL, urlToHttpOptions} = __nccwpck_require__(7310); -const http = __nccwpck_require__(3685); -const https = __nccwpck_require__(5687); -const resolveALPN = __nccwpck_require__(6624); -const QuickLRU = __nccwpck_require__(9273); -const {Agent, globalAgent} = __nccwpck_require__(9898); -const Http2ClientRequest = __nccwpck_require__(9632); -const calculateServerName = __nccwpck_require__(1982); -const delayAsyncDestroy = __nccwpck_require__(9237); - -const cache = new QuickLRU({maxSize: 100}); -const queue = new Map(); - -const installSocket = (agent, socket, options) => { - socket._httpMessage = {shouldKeepAlive: true}; - - const onFree = () => { - agent.emit('free', socket, options); - }; - - socket.on('free', onFree); - - const onClose = () => { - agent.removeSocket(socket, options); - }; - - socket.on('close', onClose); - - const onTimeout = () => { - const {freeSockets} = agent; - - for (const sockets of Object.values(freeSockets)) { - if (sockets.includes(socket)) { - socket.destroy(); - return; - } - } - }; - - socket.on('timeout', onTimeout); - - const onRemove = () => { - agent.removeSocket(socket, options); - socket.off('close', onClose); - socket.off('free', onFree); - socket.off('timeout', onTimeout); - socket.off('agentRemove', onRemove); - }; - - socket.on('agentRemove', onRemove); - - agent.emit('free', socket, options); -}; - -const createResolveProtocol = (cache, queue = new Map(), connect = undefined) => { - return async options => { - const name = `${options.host}:${options.port}:${options.ALPNProtocols.sort()}`; - - if (!cache.has(name)) { - if (queue.has(name)) { - const result = await queue.get(name); - return {alpnProtocol: result.alpnProtocol}; - } - - const {path} = options; - options.path = options.socketPath; - - const resultPromise = resolveALPN(options, connect); - queue.set(name, resultPromise); - - try { - const result = await resultPromise; - - cache.set(name, result.alpnProtocol); - queue.delete(name); - - options.path = path; - - return result; - } catch (error) { - queue.delete(name); - - options.path = path; - - throw error; - } - } - - return {alpnProtocol: cache.get(name)}; - }; -}; - -const defaultResolveProtocol = createResolveProtocol(cache, queue); - -module.exports = async (input, options, callback) => { - if (typeof input === 'string') { - input = urlToHttpOptions(new URL(input)); - } else if (input instanceof URL) { - input = urlToHttpOptions(input); - } else { - input = {...input}; - } - - if (typeof options === 'function' || options === undefined) { - // (options, callback) - callback = options; - options = input; - } else { - // (input, options, callback) - options = Object.assign(input, options); - } - - options.ALPNProtocols = options.ALPNProtocols || ['h2', 'http/1.1']; - - if (!Array.isArray(options.ALPNProtocols) || options.ALPNProtocols.length === 0) { - throw new Error('The `ALPNProtocols` option must be an Array with at least one entry'); - } - - options.protocol = options.protocol || 'https:'; - const isHttps = options.protocol === 'https:'; - - options.host = options.hostname || options.host || 'localhost'; - options.session = options.tlsSession; - options.servername = options.servername || calculateServerName((options.headers && options.headers.host) || options.host); - options.port = options.port || (isHttps ? 443 : 80); - options._defaultAgent = isHttps ? https.globalAgent : http.globalAgent; - - const resolveProtocol = options.resolveProtocol || defaultResolveProtocol; - - // Note: We don't support `h2session` here - - let {agent} = options; - if (agent !== undefined && agent !== false && agent.constructor.name !== 'Object') { - throw new Error('The `options.agent` can be only an object `http`, `https` or `http2` properties'); - } - - if (isHttps) { - options.resolveSocket = true; - - let {socket, alpnProtocol, timeout} = await resolveProtocol(options); - - if (timeout) { - if (socket) { - socket.destroy(); - } - - const error = new Error(`Timed out resolving ALPN: ${options.timeout} ms`); - error.code = 'ETIMEDOUT'; - error.ms = options.timeout; - - throw error; - } - - // We can't accept custom `createConnection` because the API is different for HTTP/2 - if (socket && options.createConnection) { - socket.destroy(); - socket = undefined; - } - - delete options.resolveSocket; - - const isHttp2 = alpnProtocol === 'h2'; - - if (agent) { - agent = isHttp2 ? agent.http2 : agent.https; - options.agent = agent; - } - - if (agent === undefined) { - agent = isHttp2 ? globalAgent : https.globalAgent; - } - - if (socket) { - if (agent === false) { - socket.destroy(); - } else { - const defaultCreateConnection = (isHttp2 ? Agent : https.Agent).prototype.createConnection; - - if (agent.createConnection === defaultCreateConnection) { - if (isHttp2) { - options._reuseSocket = socket; - } else { - installSocket(agent, socket, options); - } - } else { - socket.destroy(); - } - } - } - - if (isHttp2) { - return delayAsyncDestroy(new Http2ClientRequest(options, callback)); - } - } else if (agent) { - options.agent = agent.http; - } - - return delayAsyncDestroy(http.request(options, callback)); -}; - -module.exports.protocolCache = cache; -module.exports.resolveProtocol = defaultResolveProtocol; -module.exports.createResolveProtocol = createResolveProtocol; - - -/***/ }), - -/***/ 9632: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -// See https://github.com/facebook/jest/issues/2549 -// eslint-disable-next-line node/prefer-global/url -const {URL, urlToHttpOptions} = __nccwpck_require__(7310); -const http2 = __nccwpck_require__(5158); -const {Writable} = __nccwpck_require__(2781); -const {Agent, globalAgent} = __nccwpck_require__(9898); -const IncomingMessage = __nccwpck_require__(2575); -const proxyEvents = __nccwpck_require__(1818); -const { - ERR_INVALID_ARG_TYPE, - ERR_INVALID_PROTOCOL, - ERR_HTTP_HEADERS_SENT -} = __nccwpck_require__(7087); -const validateHeaderName = __nccwpck_require__(4592); -const validateHeaderValue = __nccwpck_require__(3549); -const proxySocketHandler = __nccwpck_require__(9404); - -const { - HTTP2_HEADER_STATUS, - HTTP2_HEADER_METHOD, - HTTP2_HEADER_PATH, - HTTP2_HEADER_AUTHORITY, - HTTP2_METHOD_CONNECT -} = http2.constants; - -const kHeaders = Symbol('headers'); -const kOrigin = Symbol('origin'); -const kSession = Symbol('session'); -const kOptions = Symbol('options'); -const kFlushedHeaders = Symbol('flushedHeaders'); -const kJobs = Symbol('jobs'); -const kPendingAgentPromise = Symbol('pendingAgentPromise'); - -class ClientRequest extends Writable { - constructor(input, options, callback) { - super({ - autoDestroy: false, - emitClose: false - }); - - if (typeof input === 'string') { - input = urlToHttpOptions(new URL(input)); - } else if (input instanceof URL) { - input = urlToHttpOptions(input); - } else { - input = {...input}; - } - - if (typeof options === 'function' || options === undefined) { - // (options, callback) - callback = options; - options = input; - } else { - // (input, options, callback) - options = Object.assign(input, options); - } - - if (options.h2session) { - this[kSession] = options.h2session; - - if (this[kSession].destroyed) { - throw new Error('The session has been closed already'); - } - - this.protocol = this[kSession].socket.encrypted ? 'https:' : 'http:'; - } else if (options.agent === false) { - this.agent = new Agent({maxEmptySessions: 0}); - } else if (typeof options.agent === 'undefined' || options.agent === null) { - this.agent = globalAgent; - } else if (typeof options.agent.request === 'function') { - this.agent = options.agent; - } else { - throw new ERR_INVALID_ARG_TYPE('options.agent', ['http2wrapper.Agent-like Object', 'undefined', 'false'], options.agent); - } - - if (this.agent) { - this.protocol = this.agent.protocol; - } - - if (options.protocol && options.protocol !== this.protocol) { - throw new ERR_INVALID_PROTOCOL(options.protocol, this.protocol); - } - - if (!options.port) { - options.port = options.defaultPort || (this.agent && this.agent.defaultPort) || 443; - } - - options.host = options.hostname || options.host || 'localhost'; - - // Unused - delete options.hostname; - - const {timeout} = options; - options.timeout = undefined; - - this[kHeaders] = Object.create(null); - this[kJobs] = []; - - this[kPendingAgentPromise] = undefined; - - this.socket = null; - this.connection = null; - - this.method = options.method || 'GET'; - - if (!(this.method === 'CONNECT' && (options.path === '/' || options.path === undefined))) { - this.path = options.path; - } - - this.res = null; - this.aborted = false; - this.reusedSocket = false; - - const {headers} = options; - if (headers) { - // eslint-disable-next-line guard-for-in - for (const header in headers) { - this.setHeader(header, headers[header]); - } - } - - if (options.auth && !('authorization' in this[kHeaders])) { - this[kHeaders].authorization = 'Basic ' + Buffer.from(options.auth).toString('base64'); - } - - options.session = options.tlsSession; - options.path = options.socketPath; - - this[kOptions] = options; - - // Clients that generate HTTP/2 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field. - this[kOrigin] = new URL(`${this.protocol}//${options.servername || options.host}:${options.port}`); - - // A socket is being reused - const reuseSocket = options._reuseSocket; - if (reuseSocket) { - options.createConnection = (...args) => { - if (reuseSocket.destroyed) { - return this.agent.createConnection(...args); - } - - return reuseSocket; - }; - - // eslint-disable-next-line promise/prefer-await-to-then - this.agent.getSession(this[kOrigin], this[kOptions]).catch(() => {}); - } - - if (timeout) { - this.setTimeout(timeout); - } - - if (callback) { - this.once('response', callback); - } - - this[kFlushedHeaders] = false; - } - - get method() { - return this[kHeaders][HTTP2_HEADER_METHOD]; - } - - set method(value) { - if (value) { - this[kHeaders][HTTP2_HEADER_METHOD] = value.toUpperCase(); - } - } - - get path() { - const header = this.method === 'CONNECT' ? HTTP2_HEADER_AUTHORITY : HTTP2_HEADER_PATH; - - return this[kHeaders][header]; - } - - set path(value) { - if (value) { - const header = this.method === 'CONNECT' ? HTTP2_HEADER_AUTHORITY : HTTP2_HEADER_PATH; - - this[kHeaders][header] = value; - } - } - - get host() { - return this[kOrigin].hostname; - } - - set host(_value) { - // Do nothing as this is read only. - } - - get _mustNotHaveABody() { - return this.method === 'GET' || this.method === 'HEAD' || this.method === 'DELETE'; - } - - _write(chunk, encoding, callback) { - // https://github.com/nodejs/node/blob/654df09ae0c5e17d1b52a900a545f0664d8c7627/lib/internal/http2/util.js#L148-L156 - if (this._mustNotHaveABody) { - callback(new Error('The GET, HEAD and DELETE methods must NOT have a body')); - /* istanbul ignore next: Node.js 12 throws directly */ - return; - } - - this.flushHeaders(); - - const callWrite = () => this._request.write(chunk, encoding, callback); - if (this._request) { - callWrite(); - } else { - this[kJobs].push(callWrite); - } - } - - _final(callback) { - this.flushHeaders(); - - const callEnd = () => { - // For GET, HEAD and DELETE and CONNECT - if (this._mustNotHaveABody || this.method === 'CONNECT') { - callback(); - return; - } - - this._request.end(callback); - }; - - if (this._request) { - callEnd(); - } else { - this[kJobs].push(callEnd); - } - } - - abort() { - if (this.res && this.res.complete) { - return; - } - - if (!this.aborted) { - process.nextTick(() => this.emit('abort')); - } - - this.aborted = true; - - this.destroy(); - } - - async _destroy(error, callback) { - if (this.res) { - this.res._dump(); - } - - if (this._request) { - this._request.destroy(); - } else { - process.nextTick(() => { - this.emit('close'); - }); - } - - try { - await this[kPendingAgentPromise]; - } catch (internalError) { - if (this.aborted) { - error = internalError; - } - } - - callback(error); - } - - async flushHeaders() { - if (this[kFlushedHeaders] || this.destroyed) { - return; - } - - this[kFlushedHeaders] = true; - - const isConnectMethod = this.method === HTTP2_METHOD_CONNECT; - - // The real magic is here - const onStream = stream => { - this._request = stream; - - if (this.destroyed) { - stream.destroy(); - return; - } - - // Forwards `timeout`, `continue`, `close` and `error` events to this instance. - if (!isConnectMethod) { - // TODO: Should we proxy `close` here? - proxyEvents(stream, this, ['timeout', 'continue']); - } - - stream.once('error', error => { - this.destroy(error); - }); - - stream.once('aborted', () => { - const {res} = this; - if (res) { - res.aborted = true; - res.emit('aborted'); - res.destroy(); - } else { - this.destroy(new Error('The server aborted the HTTP/2 stream')); - } - }); - - const onResponse = (headers, flags, rawHeaders) => { - // If we were to emit raw request stream, it would be as fast as the native approach. - // Note that wrapping the raw stream in a Proxy instance won't improve the performance (already tested it). - const response = new IncomingMessage(this.socket, stream.readableHighWaterMark); - this.res = response; - - // Undocumented, but it is used by `cacheable-request` - response.url = `${this[kOrigin].origin}${this.path}`; - - response.req = this; - response.statusCode = headers[HTTP2_HEADER_STATUS]; - response.headers = headers; - response.rawHeaders = rawHeaders; - - response.once('end', () => { - response.complete = true; - - // Has no effect, just be consistent with the Node.js behavior - response.socket = null; - response.connection = null; - }); - - if (isConnectMethod) { - response.upgrade = true; - - // The HTTP1 API says the socket is detached here, - // but we can't do that so we pass the original HTTP2 request. - if (this.emit('connect', response, stream, Buffer.alloc(0))) { - this.emit('close'); - } else { - // No listeners attached, destroy the original request. - stream.destroy(); - } - } else { - // Forwards data - stream.on('data', chunk => { - if (!response._dumped && !response.push(chunk)) { - stream.pause(); - } - }); - - stream.once('end', () => { - if (!this.aborted) { - response.push(null); - } - }); - - if (!this.emit('response', response)) { - // No listeners attached, dump the response. - response._dump(); - } - } - }; - - // This event tells we are ready to listen for the data. - stream.once('response', onResponse); - - // Emits `information` event - stream.once('headers', headers => this.emit('information', {statusCode: headers[HTTP2_HEADER_STATUS]})); - - stream.once('trailers', (trailers, flags, rawTrailers) => { - const {res} = this; - - // https://github.com/nodejs/node/issues/41251 - if (res === null) { - onResponse(trailers, flags, rawTrailers); - return; - } - - // Assigns trailers to the response object. - res.trailers = trailers; - res.rawTrailers = rawTrailers; - }); - - stream.once('close', () => { - const {aborted, res} = this; - if (res) { - if (aborted) { - res.aborted = true; - res.emit('aborted'); - res.destroy(); - } - - const finish = () => { - res.emit('close'); - - this.destroy(); - this.emit('close'); - }; - - if (res.readable) { - res.once('end', finish); - } else { - finish(); - } - - return; - } - - if (!this.destroyed) { - this.destroy(new Error('The HTTP/2 stream has been early terminated')); - this.emit('close'); - return; - } - - this.destroy(); - this.emit('close'); - }); - - this.socket = new Proxy(stream, proxySocketHandler); - - for (const job of this[kJobs]) { - job(); - } - - this[kJobs].length = 0; - - this.emit('socket', this.socket); - }; - - if (!(HTTP2_HEADER_AUTHORITY in this[kHeaders]) && !isConnectMethod) { - this[kHeaders][HTTP2_HEADER_AUTHORITY] = this[kOrigin].host; - } - - // Makes a HTTP2 request - if (this[kSession]) { - try { - onStream(this[kSession].request(this[kHeaders])); - } catch (error) { - this.destroy(error); - } - } else { - this.reusedSocket = true; - - try { - const promise = this.agent.request(this[kOrigin], this[kOptions], this[kHeaders]); - this[kPendingAgentPromise] = promise; - - onStream(await promise); - - this[kPendingAgentPromise] = false; - } catch (error) { - this[kPendingAgentPromise] = false; - - this.destroy(error); - } - } - } - - get connection() { - return this.socket; - } - - set connection(value) { - this.socket = value; - } - - getHeaderNames() { - return Object.keys(this[kHeaders]); - } - - hasHeader(name) { - if (typeof name !== 'string') { - throw new ERR_INVALID_ARG_TYPE('name', 'string', name); - } - - return Boolean(this[kHeaders][name.toLowerCase()]); - } - - getHeader(name) { - if (typeof name !== 'string') { - throw new ERR_INVALID_ARG_TYPE('name', 'string', name); - } - - return this[kHeaders][name.toLowerCase()]; - } - - get headersSent() { - return this[kFlushedHeaders]; - } - - removeHeader(name) { - if (typeof name !== 'string') { - throw new ERR_INVALID_ARG_TYPE('name', 'string', name); - } - - if (this.headersSent) { - throw new ERR_HTTP_HEADERS_SENT('remove'); - } - - delete this[kHeaders][name.toLowerCase()]; - } - - setHeader(name, value) { - if (this.headersSent) { - throw new ERR_HTTP_HEADERS_SENT('set'); - } - - validateHeaderName(name); - validateHeaderValue(name, value); - - const lowercased = name.toLowerCase(); - - if (lowercased === 'connection') { - if (value.toLowerCase() === 'keep-alive') { - return; - } - - throw new Error(`Invalid 'connection' header: ${value}`); - } - - if (lowercased === 'host' && this.method === 'CONNECT') { - this[kHeaders][HTTP2_HEADER_AUTHORITY] = value; - } else { - this[kHeaders][lowercased] = value; - } - } - - setNoDelay() { - // HTTP2 sockets cannot be malformed, do nothing. - } - - setSocketKeepAlive() { - // HTTP2 sockets cannot be malformed, do nothing. - } - - setTimeout(ms, callback) { - const applyTimeout = () => this._request.setTimeout(ms, callback); - - if (this._request) { - applyTimeout(); - } else { - this[kJobs].push(applyTimeout); - } - - return this; - } - - get maxHeadersCount() { - if (!this.destroyed && this._request) { - return this._request.session.localSettings.maxHeaderListSize; - } - - return undefined; - } - - set maxHeadersCount(_value) { - // Updating HTTP2 settings would affect all requests, do nothing. - } -} - -module.exports = ClientRequest; - - -/***/ }), - -/***/ 2575: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const {Readable} = __nccwpck_require__(2781); - -class IncomingMessage extends Readable { - constructor(socket, highWaterMark) { - super({ - emitClose: false, - autoDestroy: true, - highWaterMark - }); - - this.statusCode = null; - this.statusMessage = ''; - this.httpVersion = '2.0'; - this.httpVersionMajor = 2; - this.httpVersionMinor = 0; - this.headers = {}; - this.trailers = {}; - this.req = null; - - this.aborted = false; - this.complete = false; - this.upgrade = null; - - this.rawHeaders = []; - this.rawTrailers = []; - - this.socket = socket; - - this._dumped = false; - } - - get connection() { - return this.socket; - } - - set connection(value) { - this.socket = value; - } - - _destroy(error, callback) { - if (!this.readableEnded) { - this.aborted = true; - } - - // See https://github.com/nodejs/node/issues/35303 - callback(); - - this.req._request.destroy(error); - } - - setTimeout(ms, callback) { - this.req.setTimeout(ms, callback); - return this; - } - - _dump() { - if (!this._dumped) { - this._dumped = true; - - this.removeAllListeners('data'); - this.resume(); - } - } - - _read() { - if (this.req) { - this.req._request.resume(); - } - } -} - -module.exports = IncomingMessage; - - -/***/ }), - -/***/ 4645: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const http2 = __nccwpck_require__(5158); -const { - Agent, - globalAgent -} = __nccwpck_require__(9898); -const ClientRequest = __nccwpck_require__(9632); -const IncomingMessage = __nccwpck_require__(2575); -const auto = __nccwpck_require__(7167); -const { - HttpOverHttp2, - HttpsOverHttp2 -} = __nccwpck_require__(8795); -const Http2OverHttp2 = __nccwpck_require__(8553); -const { - Http2OverHttp, - Http2OverHttps -} = __nccwpck_require__(9794); -const validateHeaderName = __nccwpck_require__(4592); -const validateHeaderValue = __nccwpck_require__(3549); - -const request = (url, options, callback) => new ClientRequest(url, options, callback); - -const get = (url, options, callback) => { - // eslint-disable-next-line unicorn/prevent-abbreviations - const req = new ClientRequest(url, options, callback); - req.end(); - - return req; -}; - -module.exports = { - ...http2, - ClientRequest, - IncomingMessage, - Agent, - globalAgent, - request, - get, - auto, - proxies: { - HttpOverHttp2, - HttpsOverHttp2, - Http2OverHttp2, - Http2OverHttp, - Http2OverHttps - }, - validateHeaderName, - validateHeaderValue -}; - - -/***/ }), - -/***/ 7885: -/***/ ((module) => { - -"use strict"; - - -module.exports = self => { - const {username, password} = self.proxyOptions.url; - - if (username || password) { - const data = `${username}:${password}`; - const authorization = `Basic ${Buffer.from(data).toString('base64')}`; - - return { - 'proxy-authorization': authorization, - authorization - }; - } - - return {}; -}; - - -/***/ }), - -/***/ 8795: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const tls = __nccwpck_require__(4404); -const http = __nccwpck_require__(3685); -const https = __nccwpck_require__(5687); -const JSStreamSocket = __nccwpck_require__(1564); -const {globalAgent} = __nccwpck_require__(9898); -const UnexpectedStatusCodeError = __nccwpck_require__(6203); -const initialize = __nccwpck_require__(1089); -const getAuthorizationHeaders = __nccwpck_require__(7885); - -const createConnection = (self, options, callback) => { - (async () => { - try { - const {proxyOptions} = self; - const {url, headers, raw} = proxyOptions; - - const stream = await globalAgent.request(url, proxyOptions, { - ...getAuthorizationHeaders(self), - ...headers, - ':method': 'CONNECT', - ':authority': `${options.host}:${options.port}` - }); - - stream.once('error', callback); - stream.once('response', headers => { - const statusCode = headers[':status']; - - if (statusCode !== 200) { - callback(new UnexpectedStatusCodeError(statusCode, '')); - return; - } - - const encrypted = self instanceof https.Agent; - - if (raw && encrypted) { - options.socket = stream; - const secureStream = tls.connect(options); - - secureStream.once('close', () => { - stream.destroy(); - }); - - callback(null, secureStream); - return; - } - - const socket = new JSStreamSocket(stream); - socket.encrypted = false; - socket._handle.getpeername = out => { - out.family = undefined; - out.address = undefined; - out.port = undefined; - }; - - callback(null, socket); - }); - } catch (error) { - callback(error); - } - })(); -}; - -class HttpOverHttp2 extends http.Agent { - constructor(options) { - super(options); - - initialize(this, options.proxyOptions); - } - - createConnection(options, callback) { - createConnection(this, options, callback); - } -} - -class HttpsOverHttp2 extends https.Agent { - constructor(options) { - super(options); - - initialize(this, options.proxyOptions); - } - - createConnection(options, callback) { - createConnection(this, options, callback); - } -} - -module.exports = { - HttpOverHttp2, - HttpsOverHttp2 -}; - - -/***/ }), - -/***/ 9794: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const http = __nccwpck_require__(3685); -const https = __nccwpck_require__(5687); -const Http2OverHttpX = __nccwpck_require__(1857); -const getAuthorizationHeaders = __nccwpck_require__(7885); - -const getStream = request => new Promise((resolve, reject) => { - const onConnect = (response, socket, head) => { - socket.unshift(head); - - request.off('error', reject); - resolve([socket, response.statusCode, response.statusMessage]); - }; - - request.once('error', reject); - request.once('connect', onConnect); -}); - -class Http2OverHttp extends Http2OverHttpX { - async _getProxyStream(authority) { - const {proxyOptions} = this; - const {url, headers} = this.proxyOptions; - - const network = url.protocol === 'https:' ? https : http; - - // `new URL('https://localhost/httpbin.org:443')` results in - // a `/httpbin.org:443` path, which has an invalid leading slash. - const request = network.request({ - ...proxyOptions, - hostname: url.hostname, - port: url.port, - path: authority, - headers: { - ...getAuthorizationHeaders(this), - ...headers, - host: authority - }, - method: 'CONNECT' - }).end(); - - return getStream(request); - } -} - -module.exports = { - Http2OverHttp, - Http2OverHttps: Http2OverHttp -}; - - -/***/ }), - -/***/ 8553: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const {globalAgent} = __nccwpck_require__(9898); -const Http2OverHttpX = __nccwpck_require__(1857); -const getAuthorizationHeaders = __nccwpck_require__(7885); - -const getStatusCode = stream => new Promise((resolve, reject) => { - stream.once('error', reject); - stream.once('response', headers => { - stream.off('error', reject); - resolve(headers[':status']); - }); -}); - -class Http2OverHttp2 extends Http2OverHttpX { - async _getProxyStream(authority) { - const {proxyOptions} = this; - - const headers = { - ...getAuthorizationHeaders(this), - ...proxyOptions.headers, - ':method': 'CONNECT', - ':authority': authority - }; - - const stream = await globalAgent.request(proxyOptions.url, proxyOptions, headers); - const statusCode = await getStatusCode(stream); - - return [stream, statusCode, '']; - } -} - -module.exports = Http2OverHttp2; - - -/***/ }), - -/***/ 1857: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -const {Agent} = __nccwpck_require__(9898); -const JSStreamSocket = __nccwpck_require__(1564); -const UnexpectedStatusCodeError = __nccwpck_require__(6203); -const initialize = __nccwpck_require__(1089); - -class Http2OverHttpX extends Agent { - constructor(options) { - super(options); - - initialize(this, options.proxyOptions); - } - - async createConnection(origin, options) { - const authority = `${origin.hostname}:${origin.port || 443}`; - - const [stream, statusCode, statusMessage] = await this._getProxyStream(authority); - if (statusCode !== 200) { - throw new UnexpectedStatusCodeError(statusCode, statusMessage); - } - - if (this.proxyOptions.raw) { - options.socket = stream; - } else { - const socket = new JSStreamSocket(stream); - socket.encrypted = false; - socket._handle.getpeername = out => { - out.family = undefined; - out.address = undefined; - out.port = undefined; - }; - - return socket; - } - - return super.createConnection(origin, options); - } + catch (_a) { + core.debug('Invalid json'); + } + } + return releases; + }); } - -module.exports = Http2OverHttpX; - - -/***/ }), - -/***/ 1089: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -// See https://github.com/facebook/jest/issues/2549 -// eslint-disable-next-line node/prefer-global/url -const {URL} = __nccwpck_require__(7310); -const checkType = __nccwpck_require__(3453); - -module.exports = (self, proxyOptions) => { - checkType('proxyOptions', proxyOptions, ['object']); - checkType('proxyOptions.headers', proxyOptions.headers, ['object', 'undefined']); - checkType('proxyOptions.raw', proxyOptions.raw, ['boolean', 'undefined']); - checkType('proxyOptions.url', proxyOptions.url, [URL, 'string']); - - const url = new URL(proxyOptions.url); - - self.proxyOptions = { - raw: true, - ...proxyOptions, - headers: {...proxyOptions.headers}, - url - }; -}; - +exports.getManifestFromRepo = getManifestFromRepo; +function findFromManifest(versionSpec, stable, manifest, archFilter = os.arch()) { + return __awaiter(this, void 0, void 0, function* () { + // wrap the internal impl + const match = yield mm._findMatch(versionSpec, stable, manifest, archFilter); + return match; + }); +} +exports.findFromManifest = findFromManifest; +function _createExtractFolder(dest) { + return __awaiter(this, void 0, void 0, function* () { + if (!dest) { + // create a temp dir + dest = path.join(_getTempDirectory(), v4_1.default()); + } + yield io.mkdirP(dest); + return dest; + }); +} +function _createToolPath(tool, version, arch) { + return __awaiter(this, void 0, void 0, function* () { + const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || ''); + core.debug(`destination ${folderPath}`); + const markerPath = `${folderPath}.complete`; + yield io.rmRF(folderPath); + yield io.rmRF(markerPath); + yield io.mkdirP(folderPath); + return folderPath; + }); +} +function _completeToolPath(tool, version, arch) { + const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || ''); + const markerPath = `${folderPath}.complete`; + fs.writeFileSync(markerPath, ''); + core.debug('finished caching tool'); +} +/** + * Check if version string is explicit + * + * @param versionSpec version string to check + */ +function isExplicitVersion(versionSpec) { + const c = semver.clean(versionSpec) || ''; + core.debug(`isExplicit: ${c}`); + const valid = semver.valid(c) != null; + core.debug(`explicit? ${valid}`); + return valid; +} +exports.isExplicitVersion = isExplicitVersion; +/** + * Get the highest satisfiying semantic version in `versions` which satisfies `versionSpec` + * + * @param versions array of versions to evaluate + * @param versionSpec semantic version spec to satisfy + */ +function evaluateVersions(versions, versionSpec) { + let version = ''; + core.debug(`evaluating ${versions.length} versions`); + versions = versions.sort((a, b) => { + if (semver.gt(a, b)) { + return 1; + } + return -1; + }); + for (let i = versions.length - 1; i >= 0; i--) { + const potential = versions[i]; + const satisfied = semver.satisfies(potential, versionSpec); + if (satisfied) { + version = potential; + break; + } + } + if (version) { + core.debug(`matched: ${version}`); + } + else { + core.debug('match not found'); + } + return version; +} +exports.evaluateVersions = evaluateVersions; +/** + * Gets RUNNER_TOOL_CACHE + */ +function _getCacheDirectory() { + const cacheDirectory = process.env['RUNNER_TOOL_CACHE'] || ''; + assert_1.ok(cacheDirectory, 'Expected RUNNER_TOOL_CACHE to be defined'); + return cacheDirectory; +} +/** + * Gets RUNNER_TEMP + */ +function _getTempDirectory() { + const tempDirectory = process.env['RUNNER_TEMP'] || ''; + assert_1.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined'); + return tempDirectory; +} +/** + * Gets a global variable + */ +function _getGlobal(key, defaultValue) { + /* eslint-disable @typescript-eslint/no-explicit-any */ + const value = global[key]; + /* eslint-enable @typescript-eslint/no-explicit-any */ + return value !== undefined ? value : defaultValue; +} +/** + * Returns an array of unique values. + * @param values Values to make unique. + */ +function _unique(values) { + return Array.from(new Set(values)); +} +//# sourceMappingURL=tool-cache.js.map /***/ }), -/***/ 6203: +/***/ 7701: /***/ ((module) => { -"use strict"; - +/** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ +var byteToHex = []; +for (var i = 0; i < 256; ++i) { + byteToHex[i] = (i + 0x100).toString(16).substr(1); +} -class UnexpectedStatusCodeError extends Error { - constructor(statusCode, statusMessage = '') { - super(`The proxy server rejected the request with status code ${statusCode} (${statusMessage || 'empty status message'})`); - this.statusCode = statusCode; - this.statusMessage = statusMessage; - } +function bytesToUuid(buf, offset) { + var i = offset || 0; + var bth = byteToHex; + // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4 + return ([ + bth[buf[i++]], bth[buf[i++]], + bth[buf[i++]], bth[buf[i++]], '-', + bth[buf[i++]], bth[buf[i++]], '-', + bth[buf[i++]], bth[buf[i++]], '-', + bth[buf[i++]], bth[buf[i++]], '-', + bth[buf[i++]], bth[buf[i++]], + bth[buf[i++]], bth[buf[i++]], + bth[buf[i++]], bth[buf[i++]] + ]).join(''); } -module.exports = UnexpectedStatusCodeError; +module.exports = bytesToUuid; /***/ }), -/***/ 1982: +/***/ 7269: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -"use strict"; - -const {isIP} = __nccwpck_require__(1808); -const assert = __nccwpck_require__(9491); - -const getHost = host => { - if (host[0] === '[') { - const idx = host.indexOf(']'); - - assert(idx !== -1); - return host.slice(1, idx); - } - - const idx = host.indexOf(':'); - if (idx === -1) { - return host; - } - - return host.slice(0, idx); -}; - -module.exports = host => { - const servername = getHost(host); - - if (isIP(servername)) { - return ''; - } - - return servername; -}; - - -/***/ }), - -/***/ 3453: -/***/ ((module) => { - -"use strict"; - - -const checkType = (name, value, types) => { - const valid = types.some(type => { - const typeofType = typeof type; - if (typeofType === 'string') { - return typeof value === type; - } - - return value instanceof type; - }); - - if (!valid) { - const names = types.map(type => typeof type === 'string' ? type : type.name); - - throw new TypeError(`Expected '${name}' to be a type of ${names.join(' or ')}, got ${typeof value}`); - } -}; - -module.exports = checkType; - - -/***/ }), - -/***/ 9237: -/***/ ((module) => { - -"use strict"; - - -module.exports = stream => { - if (stream.listenerCount('error') !== 0) { - return stream; - } +// Unique ID creation requires a high quality random # generator. In node.js +// this is pretty straight-forward - we use the crypto API. - stream.__destroy = stream._destroy; - stream._destroy = (...args) => { - const callback = args.pop(); - - stream.__destroy(...args, async error => { - await Promise.resolve(); - callback(error); - }); - }; - - const onError = error => { - // eslint-disable-next-line promise/prefer-await-to-then - Promise.resolve().then(() => { - stream.emit('error', error); - }); - }; +var crypto = __nccwpck_require__(6113); - stream.once('error', onError); - - // eslint-disable-next-line promise/prefer-await-to-then - Promise.resolve().then(() => { - stream.off('error', onError); - }); - - return stream; +module.exports = function nodeRNG() { + return crypto.randomBytes(16); }; /***/ }), -/***/ 7087: -/***/ ((module) => { - -"use strict"; - -/* istanbul ignore file: https://github.com/nodejs/node/blob/master/lib/internal/errors.js */ - -const makeError = (Base, key, getMessage) => { - module.exports[key] = class NodeError extends Base { - constructor(...args) { - super(typeof getMessage === 'string' ? getMessage : getMessage(args)); - this.name = `${super.name} [${key}]`; - this.code = key; - } - }; -}; - -makeError(TypeError, 'ERR_INVALID_ARG_TYPE', args => { - const type = args[0].includes('.') ? 'property' : 'argument'; - - let valid = args[1]; - const isManyTypes = Array.isArray(valid); +/***/ 7468: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (isManyTypes) { - valid = `${valid.slice(0, -1).join(', ')} or ${valid.slice(-1)}`; - } +var rng = __nccwpck_require__(7269); +var bytesToUuid = __nccwpck_require__(7701); - return `The "${args[0]}" ${type} must be ${isManyTypes ? 'one of' : 'of'} type ${valid}. Received ${typeof args[2]}`; -}); +function v4(options, buf, offset) { + var i = buf && offset || 0; -makeError(TypeError, 'ERR_INVALID_PROTOCOL', args => - `Protocol "${args[0]}" not supported. Expected "${args[1]}"` -); + if (typeof(options) == 'string') { + buf = options === 'binary' ? new Array(16) : null; + options = null; + } + options = options || {}; -makeError(Error, 'ERR_HTTP_HEADERS_SENT', args => - `Cannot ${args[0]} headers after they are sent to the client` -); + var rnds = options.random || (options.rng || rng)(); -makeError(TypeError, 'ERR_INVALID_HTTP_TOKEN', args => - `${args[0]} must be a valid HTTP token [${args[1]}]` -); + // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + rnds[6] = (rnds[6] & 0x0f) | 0x40; + rnds[8] = (rnds[8] & 0x3f) | 0x80; -makeError(TypeError, 'ERR_HTTP_INVALID_HEADER_VALUE', args => - `Invalid value "${args[0]} for header "${args[1]}"` -); + // Copy bytes to buffer, if provided + if (buf) { + for (var ii = 0; ii < 16; ++ii) { + buf[i + ii] = rnds[ii]; + } + } -makeError(TypeError, 'ERR_INVALID_CHAR', args => - `Invalid character in ${args[0]} [${args[1]}]` -); + return buf || bytesToUuid(rnds); +} -makeError( - Error, - 'ERR_HTTP2_NO_SOCKET_MANIPULATION', - 'HTTP/2 sockets should not be directly manipulated (e.g. read and written)' -); +module.exports = v4; /***/ }), -/***/ 1199: -/***/ ((module) => { +/***/ 2391: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; +const {Transform, PassThrough} = __nccwpck_require__(2781); +const zlib = __nccwpck_require__(9796); +const mimicResponse = __nccwpck_require__(3877); -module.exports = header => { - switch (header) { - case ':method': - case ':scheme': - case ':authority': - case ':path': - return true; - default: - return false; - } -}; - - -/***/ }), +module.exports = response => { + const contentEncoding = (response.headers['content-encoding'] || '').toLowerCase(); -/***/ 1564: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) { + return response; + } -"use strict"; + // TODO: Remove this when targeting Node.js 12. + const isBrotli = contentEncoding === 'br'; + if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') { + response.destroy(new Error('Brotli is not supported on Node.js < 12')); + return response; + } -const stream = __nccwpck_require__(2781); -const tls = __nccwpck_require__(4404); + let isEmpty = true; -// Really awesome hack. -const JSStreamSocket = (new tls.TLSSocket(new stream.PassThrough()))._handle._parentWrap.constructor; + const checker = new Transform({ + transform(data, _encoding, callback) { + isEmpty = false; -module.exports = JSStreamSocket; + callback(null, data); + }, + + flush(callback) { + callback(); + } + }); + const finalStream = new PassThrough({ + autoDestroy: false, + destroy(error, callback) { + response.destroy(); -/***/ }), + callback(error); + } + }); -/***/ 1818: -/***/ ((module) => { + const decompressStream = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip(); -"use strict"; + decompressStream.once('error', error => { + if (isEmpty && !response.readable) { + finalStream.end(); + return; + } + finalStream.destroy(error); + }); -module.exports = (from, to, events) => { - for (const event of events) { - from.on(event, (...args) => to.emit(event, ...args)); - } + mimicResponse(response, finalStream); + response.pipe(checker).pipe(decompressStream).pipe(finalStream); + + return finalStream; }; /***/ }), -/***/ 9404: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 3877: +/***/ ((module) => { "use strict"; -const {ERR_HTTP2_NO_SOCKET_MANIPULATION} = __nccwpck_require__(7087); - -/* istanbul ignore file */ -/* https://github.com/nodejs/node/blob/6eec858f34a40ffa489c1ec54bb24da72a28c781/lib/internal/http2/compat.js#L195-L272 */ - -const proxySocketHandler = { - has(stream, property) { - // Replaced [kSocket] with .socket - const reference = stream.session === undefined ? stream : stream.session.socket; - return (property in stream) || (property in reference); - }, - get(stream, property) { - switch (property) { - case 'on': - case 'once': - case 'end': - case 'emit': - case 'destroy': - return stream[property].bind(stream); - case 'writable': - case 'destroyed': - return stream[property]; - case 'readable': - if (stream.destroyed) { - return false; - } +// We define these manually to ensure they're always copied +// even if they would move up the prototype chain +// https://nodejs.org/api/http.html#http_class_http_incomingmessage +const knownProperties = [ + 'aborted', + 'complete', + 'headers', + 'httpVersion', + 'httpVersionMinor', + 'httpVersionMajor', + 'method', + 'rawHeaders', + 'rawTrailers', + 'setTimeout', + 'socket', + 'statusCode', + 'statusMessage', + 'trailers', + 'url' +]; - return stream.readable; - case 'setTimeout': { - const {session} = stream; - if (session !== undefined) { - return session.setTimeout.bind(session); - } +module.exports = (fromStream, toStream) => { + if (toStream._readableState.autoDestroy) { + throw new Error('The second stream must have the `autoDestroy` option set to `false`'); + } - return stream.setTimeout.bind(stream); - } + const fromProperties = new Set(Object.keys(fromStream).concat(knownProperties)); - case 'write': - case 'read': - case 'pause': - case 'resume': - throw new ERR_HTTP2_NO_SOCKET_MANIPULATION(); - default: { - // Replaced [kSocket] with .socket - const reference = stream.session === undefined ? stream : stream.session.socket; - const value = reference[property]; + const properties = {}; - return typeof value === 'function' ? value.bind(reference) : value; - } + for (const property of fromProperties) { + // Don't overwrite existing properties. + if (property in toStream) { + continue; } - }, - getPrototypeOf(stream) { - if (stream.session !== undefined) { - // Replaced [kSocket] with .socket - return Reflect.getPrototypeOf(stream.session.socket); - } + properties[property] = { + get() { + const value = fromStream[property]; + const isFunction = typeof value === 'function'; - return Reflect.getPrototypeOf(stream); - }, + return isFunction ? value.bind(fromStream) : value; + }, + set(value) { + fromStream[property] = value; + }, + enumerable: true, + configurable: false + }; + } - set(stream, property, value) { - switch (property) { - case 'writable': - case 'readable': - case 'destroyed': - case 'on': - case 'once': - case 'end': - case 'emit': - case 'destroy': - stream[property] = value; - return true; - case 'setTimeout': { - const {session} = stream; - if (session === undefined) { - stream.setTimeout = value; - } else { - session.setTimeout = value; - } + Object.defineProperties(toStream, properties); - return true; - } + fromStream.once('aborted', () => { + toStream.destroy(); - case 'write': - case 'read': - case 'pause': - case 'resume': - throw new ERR_HTTP2_NO_SOCKET_MANIPULATION(); - default: { - // Replaced [kSocket] with .socket - const reference = stream.session === undefined ? stream : stream.session.socket; - reference[property] = value; - return true; + toStream.emit('aborted'); + }); + + fromStream.once('close', () => { + if (fromStream.complete) { + if (toStream.readable) { + toStream.once('end', () => { + toStream.emit('close'); + }); + } else { + toStream.emit('close'); } + } else { + toStream.emit('close'); } - } -}; + }); -module.exports = proxySocketHandler; + return toStream; +}; /***/ }), -/***/ 4592: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 6214: +/***/ ((module, exports) => { "use strict"; -const {ERR_INVALID_HTTP_TOKEN} = __nccwpck_require__(7087); -const isRequestPseudoHeader = __nccwpck_require__(1199); - -const isValidHttpToken = /^[\^`\-\w!#$%&*+.|~]+$/; - -module.exports = name => { - if (typeof name !== 'string' || (!isValidHttpToken.test(name) && !isRequestPseudoHeader(name))) { - throw new ERR_INVALID_HTTP_TOKEN('Header name', name); - } +Object.defineProperty(exports, "__esModule", ({ value: true })); +function isTLSSocket(socket) { + return socket.encrypted; +} +const deferToConnect = (socket, fn) => { + let listeners; + if (typeof fn === 'function') { + const connect = fn; + listeners = { connect }; + } + else { + listeners = fn; + } + const hasConnectListener = typeof listeners.connect === 'function'; + const hasSecureConnectListener = typeof listeners.secureConnect === 'function'; + const hasCloseListener = typeof listeners.close === 'function'; + const onConnect = () => { + if (hasConnectListener) { + listeners.connect(); + } + if (isTLSSocket(socket) && hasSecureConnectListener) { + if (socket.authorized) { + listeners.secureConnect(); + } + else if (!socket.authorizationError) { + socket.once('secureConnect', listeners.secureConnect); + } + } + if (hasCloseListener) { + socket.once('close', listeners.close); + } + }; + if (socket.writable && !socket.connecting) { + onConnect(); + } + else if (socket.connecting) { + socket.once('connect', onConnect); + } + else if (socket.destroyed && hasCloseListener) { + listeners.close(socket._hadError); + } }; +exports["default"] = deferToConnect; +// For CommonJS default export support +module.exports = deferToConnect; +module.exports["default"] = deferToConnect; /***/ }), -/***/ 3549: +/***/ 1585: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { - ERR_HTTP_INVALID_HEADER_VALUE, - ERR_INVALID_CHAR -} = __nccwpck_require__(7087); +const {PassThrough: PassThroughStream} = __nccwpck_require__(2781); -const isInvalidHeaderValue = /[^\t\u0020-\u007E\u0080-\u00FF]/; +module.exports = options => { + options = {...options}; -module.exports = (name, value) => { - if (typeof value === 'undefined') { - throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name); - } + const {array} = options; + let {encoding} = options; + const isBuffer = encoding === 'buffer'; + let objectMode = false; - if (isInvalidHeaderValue.test(value)) { - throw new ERR_INVALID_CHAR('header content', name); + if (array) { + objectMode = !(encoding || isBuffer); + } else { + encoding = encoding || 'utf8'; } -}; - - -/***/ }), -/***/ 2820: -/***/ ((__unused_webpack_module, exports) => { + if (isBuffer) { + encoding = null; + } -//TODO: handle reviver/dehydrate function like normal -//and handle indentation, like normal. -//if anyone needs this... please send pull request. + const stream = new PassThroughStream({objectMode}); -exports.stringify = function stringify (o) { - if('undefined' == typeof o) return o + if (encoding) { + stream.setEncoding(encoding); + } - if(o && Buffer.isBuffer(o)) - return JSON.stringify(':base64:' + o.toString('base64')) + let length = 0; + const chunks = []; - if(o && o.toJSON) - o = o.toJSON() + stream.on('data', chunk => { + chunks.push(chunk); - if(o && 'object' === typeof o) { - var s = '' - var array = Array.isArray(o) - s = array ? '[' : '{' - var first = true + if (objectMode) { + length = chunks.length; + } else { + length += chunk.length; + } + }); - for(var k in o) { - var ignore = 'function' == typeof o[k] || (!array && 'undefined' === typeof o[k]) - if(Object.hasOwnProperty.call(o, k) && !ignore) { - if(!first) - s += ',' - first = false - if (array) { - if(o[k] == undefined) - s += 'null' - else - s += stringify(o[k]) - } else if (o[k] !== void(0)) { - s += stringify(k) + ':' + stringify(o[k]) - } - } - } + stream.getBufferedValue = () => { + if (array) { + return chunks; + } - s += array ? ']' : '}' + return isBuffer ? Buffer.concat(chunks, length) : chunks.join(''); + }; - return s - } else if ('string' === typeof o) { - return JSON.stringify(/^:/.test(o) ? ':' + o : o) - } else if ('undefined' === typeof o) { - return 'null'; - } else - return JSON.stringify(o) -} + stream.getBufferedLength = () => length; -exports.parse = function (s) { - return JSON.parse(s, function (key, value) { - if('string' === typeof value) { - if(/^:base64:/.test(value)) - return Buffer.from(value.substring(8), 'base64') - else - return /^:/.test(value) ? value.substring(1) : value - } - return value - }) -} + return stream; +}; /***/ }), -/***/ 1531: +/***/ 1766: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; +const {constants: BufferConstants} = __nccwpck_require__(4300); +const stream = __nccwpck_require__(2781); +const {promisify} = __nccwpck_require__(3837); +const bufferStream = __nccwpck_require__(1585); + +const streamPipelinePromisified = promisify(stream.pipeline); -const EventEmitter = __nccwpck_require__(2361); -const JSONB = __nccwpck_require__(2820); +class MaxBufferError extends Error { + constructor() { + super('maxBuffer exceeded'); + this.name = 'MaxBufferError'; + } +} -const loadStore = options => { - const adapters = { - redis: '@keyv/redis', - rediss: '@keyv/redis', - mongodb: '@keyv/mongo', - mongo: '@keyv/mongo', - sqlite: '@keyv/sqlite', - postgresql: '@keyv/postgres', - postgres: '@keyv/postgres', - mysql: '@keyv/mysql', - etcd: '@keyv/etcd', - offline: '@keyv/offline', - tiered: '@keyv/tiered', - }; - if (options.adapter || options.uri) { - const adapter = options.adapter || /^[^:+]*/.exec(options.uri)[0]; - return new (require(adapters[adapter]))(options); +async function getStream(inputStream, options) { + if (!inputStream) { + throw new Error('Expected a stream'); } - return new Map(); -}; + options = { + maxBuffer: Infinity, + ...options + }; -const iterableAdapters = [ - 'sqlite', - 'postgres', - 'mysql', - 'mongo', - 'redis', - 'tiered', -]; + const {maxBuffer} = options; + const stream = bufferStream(options); -class Keyv extends EventEmitter { - constructor(uri, {emitErrors = true, ...options} = {}) { - super(); - this.opts = { - namespace: 'keyv', - serialize: JSONB.stringify, - deserialize: JSONB.parse, - ...((typeof uri === 'string') ? {uri} : uri), - ...options, + await new Promise((resolve, reject) => { + const rejectPromise = error => { + // Don't retrieve an oversized buffer. + if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) { + error.bufferedData = stream.getBufferedValue(); + } + + reject(error); }; - if (!this.opts.store) { - const adapterOptions = {...this.opts}; - this.opts.store = loadStore(adapterOptions); - } + (async () => { + try { + await streamPipelinePromisified(inputStream, stream); + resolve(); + } catch (error) { + rejectPromise(error); + } + })(); - if (this.opts.compression) { - const compression = this.opts.compression; - this.opts.serialize = compression.serialize.bind(compression); - this.opts.deserialize = compression.deserialize.bind(compression); - } + stream.on('data', () => { + if (stream.getBufferedLength() > maxBuffer) { + rejectPromise(new MaxBufferError()); + } + }); + }); - if (typeof this.opts.store.on === 'function' && emitErrors) { - this.opts.store.on('error', error => this.emit('error', error)); - } + return stream.getBufferedValue(); +} - this.opts.store.namespace = this.opts.namespace; +module.exports = getStream; +module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'}); +module.exports.array = (stream, options) => getStream(stream, {...options, array: true}); +module.exports.MaxBufferError = MaxBufferError; - const generateIterator = iterator => async function * () { - for await (const [key, raw] of typeof iterator === 'function' - ? iterator(this.opts.store.namespace) - : iterator) { - const data = await this.opts.deserialize(raw); - if (this.opts.store.namespace && !key.includes(this.opts.store.namespace)) { - continue; - } - if (typeof data.expires === 'number' && Date.now() > data.expires) { - this.delete(key); - continue; - } +/***/ }), - yield [this._getKeyUnprefix(key), data.value]; - } - }; +/***/ 1002: +/***/ ((module) => { - // Attach iterators - if (typeof this.opts.store[Symbol.iterator] === 'function' && this.opts.store instanceof Map) { - this.iterator = generateIterator(this.opts.store); - } else if (typeof this.opts.store.iterator === 'function' && this.opts.store.opts - && this._checkIterableAdaptar()) { - this.iterator = generateIterator(this.opts.store.iterator.bind(this.opts.store)); - } - } +"use strict"; + +// rfc7231 6.1 +const statusCodeCacheableByDefault = new Set([ + 200, + 203, + 204, + 206, + 300, + 301, + 308, + 404, + 405, + 410, + 414, + 501, +]); - _checkIterableAdaptar() { - return iterableAdapters.includes(this.opts.store.opts.dialect) - || iterableAdapters.findIndex(element => this.opts.store.opts.url.includes(element)) >= 0; - } +// This implementation does not understand partial responses (206) +const understoodStatuses = new Set([ + 200, + 203, + 204, + 300, + 301, + 302, + 303, + 307, + 308, + 404, + 405, + 410, + 414, + 501, +]); - _getKeyPrefix(key) { - return `${this.opts.namespace}:${key}`; - } +const errorStatusCodes = new Set([ + 500, + 502, + 503, + 504, +]); - _getKeyPrefixArray(keys) { - return keys.map(key => `${this.opts.namespace}:${key}`); - } +const hopByHopHeaders = { + date: true, // included, because we add Age update Date + connection: true, + 'keep-alive': true, + 'proxy-authenticate': true, + 'proxy-authorization': true, + te: true, + trailer: true, + 'transfer-encoding': true, + upgrade: true, +}; - _getKeyUnprefix(key) { - return key - .split(':') - .splice(1) - .join(':'); - } +const excludedFromRevalidationUpdate = { + // Since the old body is reused, it doesn't make sense to change properties of the body + 'content-length': true, + 'content-encoding': true, + 'transfer-encoding': true, + 'content-range': true, +}; - get(key, options) { - const {store} = this.opts; - const isArray = Array.isArray(key); - const keyPrefixed = isArray ? this._getKeyPrefixArray(key) : this._getKeyPrefix(key); - if (isArray && store.getMany === undefined) { - const promises = []; - for (const key of keyPrefixed) { - promises.push(Promise.resolve() - .then(() => store.get(key)) - .then(data => (typeof data === 'string') ? this.opts.deserialize(data) : (this.opts.compression ? this.opts.deserialize(data) : data)) - .then(data => { - if (data === undefined || data === null) { - return undefined; - } +function toNumberOrZero(s) { + const n = parseInt(s, 10); + return isFinite(n) ? n : 0; +} - if (typeof data.expires === 'number' && Date.now() > data.expires) { - return this.delete(key).then(() => undefined); - } +// RFC 5861 +function isErrorResponse(response) { + // consider undefined response as faulty + if(!response) { + return true + } + return errorStatusCodes.has(response.status); +} - return (options && options.raw) ? data : data.value; - }), - ); - } +function parseCacheControl(header) { + const cc = {}; + if (!header) return cc; - return Promise.allSettled(promises) - .then(values => { - const data = []; - for (const value of values) { - data.push(value.value); - } + // TODO: When there is more than one value present for a given directive (e.g., two Expires header fields, multiple Cache-Control: max-age directives), + // the directive's value is considered invalid. Caches are encouraged to consider responses that have invalid freshness information to be stale + const parts = header.trim().split(/,/); + for (const part of parts) { + const [k, v] = part.split(/=/, 2); + cc[k.trim()] = v === undefined ? true : v.trim().replace(/^"|"$/g, ''); + } - return data; - }); - } + return cc; +} - return Promise.resolve() - .then(() => isArray ? store.getMany(keyPrefixed) : store.get(keyPrefixed)) - .then(data => (typeof data === 'string') ? this.opts.deserialize(data) : (this.opts.compression ? this.opts.deserialize(data) : data)) - .then(data => { - if (data === undefined || data === null) { - return undefined; - } +function formatCacheControl(cc) { + let parts = []; + for (const k in cc) { + const v = cc[k]; + parts.push(v === true ? k : k + '=' + v); + } + if (!parts.length) { + return undefined; + } + return parts.join(', '); +} - if (isArray) { - const result = []; +module.exports = class CachePolicy { + constructor( + req, + res, + { + shared, + cacheHeuristic, + immutableMinTimeToLive, + ignoreCargoCult, + _fromObject, + } = {} + ) { + if (_fromObject) { + this._fromObject(_fromObject); + return; + } - for (let row of data) { - if ((typeof row === 'string')) { - row = this.opts.deserialize(row); - } + if (!res || !res.headers) { + throw Error('Response headers missing'); + } + this._assertRequestHasHeaders(req); - if (row === undefined || row === null) { - result.push(undefined); - continue; - } + this._responseTime = this.now(); + this._isShared = shared !== false; + this._cacheHeuristic = + undefined !== cacheHeuristic ? cacheHeuristic : 0.1; // 10% matches IE + this._immutableMinTtl = + undefined !== immutableMinTimeToLive + ? immutableMinTimeToLive + : 24 * 3600 * 1000; - if (typeof row.expires === 'number' && Date.now() > row.expires) { - this.delete(key).then(() => undefined); - result.push(undefined); - } else { - result.push((options && options.raw) ? row : row.value); - } - } + this._status = 'status' in res ? res.status : 200; + this._resHeaders = res.headers; + this._rescc = parseCacheControl(res.headers['cache-control']); + this._method = 'method' in req ? req.method : 'GET'; + this._url = req.url; + this._host = req.headers.host; + this._noAuthorization = !req.headers.authorization; + this._reqHeaders = res.headers.vary ? req.headers : null; // Don't keep all request headers if they won't be used + this._reqcc = parseCacheControl(req.headers['cache-control']); - return result; - } + // Assume that if someone uses legacy, non-standard uncecessary options they don't understand caching, + // so there's no point stricly adhering to the blindly copy&pasted directives. + if ( + ignoreCargoCult && + 'pre-check' in this._rescc && + 'post-check' in this._rescc + ) { + delete this._rescc['pre-check']; + delete this._rescc['post-check']; + delete this._rescc['no-cache']; + delete this._rescc['no-store']; + delete this._rescc['must-revalidate']; + this._resHeaders = Object.assign({}, this._resHeaders, { + 'cache-control': formatCacheControl(this._rescc), + }); + delete this._resHeaders.expires; + delete this._resHeaders.pragma; + } - if (typeof data.expires === 'number' && Date.now() > data.expires) { - return this.delete(key).then(() => undefined); - } + // When the Cache-Control header field is not present in a request, caches MUST consider the no-cache request pragma-directive + // as having the same effect as if "Cache-Control: no-cache" were present (see Section 5.2.1). + if ( + res.headers['cache-control'] == null && + /no-cache/.test(res.headers.pragma) + ) { + this._rescc['no-cache'] = true; + } + } - return (options && options.raw) ? data : data.value; - }); - } + now() { + return Date.now(); + } - set(key, value, ttl) { - const keyPrefixed = this._getKeyPrefix(key); - if (typeof ttl === 'undefined') { - ttl = this.opts.ttl; - } + storable() { + // The "no-store" request directive indicates that a cache MUST NOT store any part of either this request or any response to it. + return !!( + !this._reqcc['no-store'] && + // A cache MUST NOT store a response to any request, unless: + // The request method is understood by the cache and defined as being cacheable, and + ('GET' === this._method || + 'HEAD' === this._method || + ('POST' === this._method && this._hasExplicitExpiration())) && + // the response status code is understood by the cache, and + understoodStatuses.has(this._status) && + // the "no-store" cache directive does not appear in request or response header fields, and + !this._rescc['no-store'] && + // the "private" response directive does not appear in the response, if the cache is shared, and + (!this._isShared || !this._rescc.private) && + // the Authorization header field does not appear in the request, if the cache is shared, + (!this._isShared || + this._noAuthorization || + this._allowsStoringAuthenticated()) && + // the response either: + // contains an Expires header field, or + (this._resHeaders.expires || + // contains a max-age response directive, or + // contains a s-maxage response directive and the cache is shared, or + // contains a public response directive. + this._rescc['max-age'] || + (this._isShared && this._rescc['s-maxage']) || + this._rescc.public || + // has a status code that is defined as cacheable by default + statusCodeCacheableByDefault.has(this._status)) + ); + } - if (ttl === 0) { - ttl = undefined; - } + _hasExplicitExpiration() { + // 4.2.1 Calculating Freshness Lifetime + return ( + (this._isShared && this._rescc['s-maxage']) || + this._rescc['max-age'] || + this._resHeaders.expires + ); + } - const {store} = this.opts; + _assertRequestHasHeaders(req) { + if (!req || !req.headers) { + throw Error('Request headers missing'); + } + } - return Promise.resolve() - .then(() => { - const expires = (typeof ttl === 'number') ? (Date.now() + ttl) : null; - if (typeof value === 'symbol') { - this.emit('error', 'symbol cannot be serialized'); - } + satisfiesWithoutRevalidation(req) { + this._assertRequestHasHeaders(req); - value = {value, expires}; - return this.opts.serialize(value); - }) - .then(value => store.set(keyPrefixed, value, ttl)) - .then(() => true); - } + // When presented with a request, a cache MUST NOT reuse a stored response, unless: + // the presented request does not contain the no-cache pragma (Section 5.4), nor the no-cache cache directive, + // unless the stored response is successfully validated (Section 4.3), and + const requestCC = parseCacheControl(req.headers['cache-control']); + if (requestCC['no-cache'] || /no-cache/.test(req.headers.pragma)) { + return false; + } - delete(key) { - const {store} = this.opts; - if (Array.isArray(key)) { - const keyPrefixed = this._getKeyPrefixArray(key); - if (store.deleteMany === undefined) { - const promises = []; - for (const key of keyPrefixed) { - promises.push(store.delete(key)); - } + if (requestCC['max-age'] && this.age() > requestCC['max-age']) { + return false; + } - return Promise.allSettled(promises) - .then(values => values.every(x => x.value === true)); - } + if ( + requestCC['min-fresh'] && + this.timeToLive() < 1000 * requestCC['min-fresh'] + ) { + return false; + } - return Promise.resolve() - .then(() => store.deleteMany(keyPrefixed)); - } + // the stored response is either: + // fresh, or allowed to be served stale + if (this.stale()) { + const allowsStale = + requestCC['max-stale'] && + !this._rescc['must-revalidate'] && + (true === requestCC['max-stale'] || + requestCC['max-stale'] > this.age() - this.maxAge()); + if (!allowsStale) { + return false; + } + } - const keyPrefixed = this._getKeyPrefix(key); - return Promise.resolve() - .then(() => store.delete(keyPrefixed)); - } + return this._requestMatches(req, false); + } - clear() { - const {store} = this.opts; - return Promise.resolve() - .then(() => store.clear()); - } + _requestMatches(req, allowHeadMethod) { + // The presented effective request URI and that of the stored response match, and + return ( + (!this._url || this._url === req.url) && + this._host === req.headers.host && + // the request method associated with the stored response allows it to be used for the presented request, and + (!req.method || + this._method === req.method || + (allowHeadMethod && 'HEAD' === req.method)) && + // selecting header fields nominated by the stored response (if any) match those presented, and + this._varyMatches(req) + ); + } - has(key) { - const keyPrefixed = this._getKeyPrefix(key); - const {store} = this.opts; - return Promise.resolve() - .then(async () => { - if (typeof store.has === 'function') { - return store.has(keyPrefixed); - } + _allowsStoringAuthenticated() { + // following Cache-Control response directives (Section 5.2.2) have such an effect: must-revalidate, public, and s-maxage. + return ( + this._rescc['must-revalidate'] || + this._rescc.public || + this._rescc['s-maxage'] + ); + } - const value = await store.get(keyPrefixed); - return value !== undefined; - }); - } + _varyMatches(req) { + if (!this._resHeaders.vary) { + return true; + } - disconnect() { - const {store} = this.opts; - if (typeof store.disconnect === 'function') { - return store.disconnect(); - } - } -} + // A Vary header field-value of "*" always fails to match + if (this._resHeaders.vary === '*') { + return false; + } -module.exports = Keyv; + const fields = this._resHeaders.vary + .trim() + .toLowerCase() + .split(/\s*,\s*/); + for (const name of fields) { + if (req.headers[name] !== this._reqHeaders[name]) return false; + } + return true; + } + _copyWithoutHopByHopHeaders(inHeaders) { + const headers = {}; + for (const name in inHeaders) { + if (hopByHopHeaders[name]) continue; + headers[name] = inHeaders[name]; + } + // 9.1. Connection + if (inHeaders.connection) { + const tokens = inHeaders.connection.trim().split(/\s*,\s*/); + for (const name of tokens) { + delete headers[name]; + } + } + if (headers.warning) { + const warnings = headers.warning.split(/,/).filter(warning => { + return !/^\s*1[0-9][0-9]/.test(warning); + }); + if (!warnings.length) { + delete headers.warning; + } else { + headers.warning = warnings.join(',').trim(); + } + } + return headers; + } -/***/ }), + responseHeaders() { + const headers = this._copyWithoutHopByHopHeaders(this._resHeaders); + const age = this.age(); -/***/ 6769: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // A cache SHOULD generate 113 warning if it heuristically chose a freshness + // lifetime greater than 24 hours and the response's age is greater than 24 hours. + if ( + age > 3600 * 24 && + !this._hasExplicitExpiration() && + this.maxAge() > 3600 * 24 + ) { + headers.warning = + (headers.warning ? `${headers.warning}, ` : '') + + '113 - "rfc7234 5.5.4"'; + } + headers.age = `${Math.round(age)}`; + headers.date = new Date(this.now()).toUTCString(); + return headers; + } -// Update with any zlib constants that are added or changed in the future. -// Node v6 didn't export this, so we just hard code the version and rely -// on all the other hard-coded values from zlib v4736. When node v6 -// support drops, we can just export the realZlibConstants object. -const realZlibConstants = (__nccwpck_require__(9796).constants) || - /* istanbul ignore next */ { ZLIB_VERNUM: 4736 } - -module.exports = Object.freeze(Object.assign(Object.create(null), { - Z_NO_FLUSH: 0, - Z_PARTIAL_FLUSH: 1, - Z_SYNC_FLUSH: 2, - Z_FULL_FLUSH: 3, - Z_FINISH: 4, - Z_BLOCK: 5, - Z_OK: 0, - Z_STREAM_END: 1, - Z_NEED_DICT: 2, - Z_ERRNO: -1, - Z_STREAM_ERROR: -2, - Z_DATA_ERROR: -3, - Z_MEM_ERROR: -4, - Z_BUF_ERROR: -5, - Z_VERSION_ERROR: -6, - Z_NO_COMPRESSION: 0, - Z_BEST_SPEED: 1, - Z_BEST_COMPRESSION: 9, - Z_DEFAULT_COMPRESSION: -1, - Z_FILTERED: 1, - Z_HUFFMAN_ONLY: 2, - Z_RLE: 3, - Z_FIXED: 4, - Z_DEFAULT_STRATEGY: 0, - DEFLATE: 1, - INFLATE: 2, - GZIP: 3, - GUNZIP: 4, - DEFLATERAW: 5, - INFLATERAW: 6, - UNZIP: 7, - BROTLI_DECODE: 8, - BROTLI_ENCODE: 9, - Z_MIN_WINDOWBITS: 8, - Z_MAX_WINDOWBITS: 15, - Z_DEFAULT_WINDOWBITS: 15, - Z_MIN_CHUNK: 64, - Z_MAX_CHUNK: Infinity, - Z_DEFAULT_CHUNK: 16384, - Z_MIN_MEMLEVEL: 1, - Z_MAX_MEMLEVEL: 9, - Z_DEFAULT_MEMLEVEL: 8, - Z_MIN_LEVEL: -1, - Z_MAX_LEVEL: 9, - Z_DEFAULT_LEVEL: -1, - BROTLI_OPERATION_PROCESS: 0, - BROTLI_OPERATION_FLUSH: 1, - BROTLI_OPERATION_FINISH: 2, - BROTLI_OPERATION_EMIT_METADATA: 3, - BROTLI_MODE_GENERIC: 0, - BROTLI_MODE_TEXT: 1, - BROTLI_MODE_FONT: 2, - BROTLI_DEFAULT_MODE: 0, - BROTLI_MIN_QUALITY: 0, - BROTLI_MAX_QUALITY: 11, - BROTLI_DEFAULT_QUALITY: 11, - BROTLI_MIN_WINDOW_BITS: 10, - BROTLI_MAX_WINDOW_BITS: 24, - BROTLI_LARGE_MAX_WINDOW_BITS: 30, - BROTLI_DEFAULT_WINDOW: 22, - BROTLI_MIN_INPUT_BLOCK_BITS: 16, - BROTLI_MAX_INPUT_BLOCK_BITS: 24, - BROTLI_PARAM_MODE: 0, - BROTLI_PARAM_QUALITY: 1, - BROTLI_PARAM_LGWIN: 2, - BROTLI_PARAM_LGBLOCK: 3, - BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: 4, - BROTLI_PARAM_SIZE_HINT: 5, - BROTLI_PARAM_LARGE_WINDOW: 6, - BROTLI_PARAM_NPOSTFIX: 7, - BROTLI_PARAM_NDIRECT: 8, - BROTLI_DECODER_RESULT_ERROR: 0, - BROTLI_DECODER_RESULT_SUCCESS: 1, - BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: 2, - BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: 3, - BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION: 0, - BROTLI_DECODER_PARAM_LARGE_WINDOW: 1, - BROTLI_DECODER_NO_ERROR: 0, - BROTLI_DECODER_SUCCESS: 1, - BROTLI_DECODER_NEEDS_MORE_INPUT: 2, - BROTLI_DECODER_NEEDS_MORE_OUTPUT: 3, - BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE: -1, - BROTLI_DECODER_ERROR_FORMAT_RESERVED: -2, - BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE: -3, - BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET: -4, - BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME: -5, - BROTLI_DECODER_ERROR_FORMAT_CL_SPACE: -6, - BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE: -7, - BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT: -8, - BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1: -9, - BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2: -10, - BROTLI_DECODER_ERROR_FORMAT_TRANSFORM: -11, - BROTLI_DECODER_ERROR_FORMAT_DICTIONARY: -12, - BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS: -13, - BROTLI_DECODER_ERROR_FORMAT_PADDING_1: -14, - BROTLI_DECODER_ERROR_FORMAT_PADDING_2: -15, - BROTLI_DECODER_ERROR_FORMAT_DISTANCE: -16, - BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET: -19, - BROTLI_DECODER_ERROR_INVALID_ARGUMENTS: -20, - BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES: -21, - BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS: -22, - BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP: -25, - BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1: -26, - BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2: -27, - BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES: -30, - BROTLI_DECODER_ERROR_UNREACHABLE: -31, -}, realZlibConstants)) + /** + * Value of the Date response header or current time if Date was invalid + * @return timestamp + */ + date() { + const serverDate = Date.parse(this._resHeaders.date); + if (isFinite(serverDate)) { + return serverDate; + } + return this._responseTime; + } + /** + * Value of the Age header, in seconds, updated for the current time. + * May be fractional. + * + * @return Number + */ + age() { + let age = this._ageValue(); -/***/ }), + const residentTime = (this.now() - this._responseTime) / 1000; + return age + residentTime; + } -/***/ 3486: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + _ageValue() { + return toNumberOrZero(this._resHeaders.age); + } -"use strict"; + /** + * Value of applicable max-age (or heuristic equivalent) in seconds. This counts since response's `Date`. + * + * For an up-to-date value, see `timeToLive()`. + * + * @return Number + */ + maxAge() { + if (!this.storable() || this._rescc['no-cache']) { + return 0; + } + // Shared responses with cookies are cacheable according to the RFC, but IMHO it'd be unwise to do so by default + // so this implementation requires explicit opt-in via public header + if ( + this._isShared && + (this._resHeaders['set-cookie'] && + !this._rescc.public && + !this._rescc.immutable) + ) { + return 0; + } -const assert = __nccwpck_require__(9491) -const Buffer = (__nccwpck_require__(4300).Buffer) -const realZlib = __nccwpck_require__(9796) + if (this._resHeaders.vary === '*') { + return 0; + } -const constants = exports.constants = __nccwpck_require__(6769) -const Minipass = __nccwpck_require__(7557) + if (this._isShared) { + if (this._rescc['proxy-revalidate']) { + return 0; + } + // if a response includes the s-maxage directive, a shared cache recipient MUST ignore the Expires field. + if (this._rescc['s-maxage']) { + return toNumberOrZero(this._rescc['s-maxage']); + } + } -const OriginalBufferConcat = Buffer.concat + // If a response includes a Cache-Control field with the max-age directive, a recipient MUST ignore the Expires field. + if (this._rescc['max-age']) { + return toNumberOrZero(this._rescc['max-age']); + } -const _superWrite = Symbol('_superWrite') -class ZlibError extends Error { - constructor (err) { - super('zlib: ' + err.message) - this.code = err.code - this.errno = err.errno - /* istanbul ignore if */ - if (!this.code) - this.code = 'ZLIB_ERROR' + const defaultMinTtl = this._rescc.immutable ? this._immutableMinTtl : 0; - this.message = 'zlib: ' + err.message - Error.captureStackTrace(this, this.constructor) - } + const serverDate = this.date(); + if (this._resHeaders.expires) { + const expires = Date.parse(this._resHeaders.expires); + // A cache recipient MUST interpret invalid date formats, especially the value "0", as representing a time in the past (i.e., "already expired"). + if (Number.isNaN(expires) || expires < serverDate) { + return 0; + } + return Math.max(defaultMinTtl, (expires - serverDate) / 1000); + } - get name () { - return 'ZlibError' - } -} + if (this._resHeaders['last-modified']) { + const lastModified = Date.parse(this._resHeaders['last-modified']); + if (isFinite(lastModified) && serverDate > lastModified) { + return Math.max( + defaultMinTtl, + ((serverDate - lastModified) / 1000) * this._cacheHeuristic + ); + } + } -// the Zlib class they all inherit from -// This thing manages the queue of requests, and returns -// true or false if there is anything in the queue when -// you call the .write() method. -const _opts = Symbol('opts') -const _flushFlag = Symbol('flushFlag') -const _finishFlushFlag = Symbol('finishFlushFlag') -const _fullFlushFlag = Symbol('fullFlushFlag') -const _handle = Symbol('handle') -const _onError = Symbol('onError') -const _sawError = Symbol('sawError') -const _level = Symbol('level') -const _strategy = Symbol('strategy') -const _ended = Symbol('ended') -const _defaultFullFlush = Symbol('_defaultFullFlush') - -class ZlibBase extends Minipass { - constructor (opts, mode) { - if (!opts || typeof opts !== 'object') - throw new TypeError('invalid options for ZlibBase constructor') - - super(opts) - this[_sawError] = false - this[_ended] = false - this[_opts] = opts - - this[_flushFlag] = opts.flush - this[_finishFlushFlag] = opts.finishFlush - // this will throw if any options are invalid for the class selected - try { - this[_handle] = new realZlib[mode](opts) - } catch (er) { - // make sure that all errors get decorated properly - throw new ZlibError(er) + return defaultMinTtl; } - this[_onError] = (err) => { - // no sense raising multiple errors, since we abort on the first one. - if (this[_sawError]) - return - - this[_sawError] = true - - // there is no way to cleanly recover. - // continuing only obscures problems. - this.close() - this.emit('error', err) + timeToLive() { + const age = this.maxAge() - this.age(); + const staleIfErrorAge = age + toNumberOrZero(this._rescc['stale-if-error']); + const staleWhileRevalidateAge = age + toNumberOrZero(this._rescc['stale-while-revalidate']); + return Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1000; } - this[_handle].on('error', er => this[_onError](new ZlibError(er))) - this.once('end', () => this.close) - } - - close () { - if (this[_handle]) { - this[_handle].close() - this[_handle] = null - this.emit('close') + stale() { + return this.maxAge() <= this.age(); } - } - reset () { - if (!this[_sawError]) { - assert(this[_handle], 'zlib binding closed') - return this[_handle].reset() + _useStaleIfError() { + return this.maxAge() + toNumberOrZero(this._rescc['stale-if-error']) > this.age(); } - } - - flush (flushFlag) { - if (this.ended) - return - - if (typeof flushFlag !== 'number') - flushFlag = this[_fullFlushFlag] - this.write(Object.assign(Buffer.alloc(0), { [_flushFlag]: flushFlag })) - } - - end (chunk, encoding, cb) { - if (chunk) - this.write(chunk, encoding) - this.flush(this[_finishFlushFlag]) - this[_ended] = true - return super.end(null, null, cb) - } - - get ended () { - return this[_ended] - } - write (chunk, encoding, cb) { - // process the chunk using the sync process - // then super.write() all the outputted chunks - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - - if (typeof chunk === 'string') - chunk = Buffer.from(chunk, encoding) - - if (this[_sawError]) - return - assert(this[_handle], 'zlib binding closed') - - // _processChunk tries to .close() the native handle after it's done, so we - // intercept that by temporarily making it a no-op. - const nativeHandle = this[_handle]._handle - const originalNativeClose = nativeHandle.close - nativeHandle.close = () => {} - const originalClose = this[_handle].close - this[_handle].close = () => {} - // It also calls `Buffer.concat()` at the end, which may be convenient - // for some, but which we are not interested in as it slows us down. - Buffer.concat = (args) => args - let result - try { - const flushFlag = typeof chunk[_flushFlag] === 'number' - ? chunk[_flushFlag] : this[_flushFlag] - result = this[_handle]._processChunk(chunk, flushFlag) - // if we don't throw, reset it back how it was - Buffer.concat = OriginalBufferConcat - } catch (err) { - // or if we do, put Buffer.concat() back before we emit error - // Error events call into user code, which may call Buffer.concat() - Buffer.concat = OriginalBufferConcat - this[_onError](new ZlibError(err)) - } finally { - if (this[_handle]) { - // Core zlib resets `_handle` to null after attempting to close the - // native handle. Our no-op handler prevented actual closure, but we - // need to restore the `._handle` property. - this[_handle]._handle = nativeHandle - nativeHandle.close = originalNativeClose - this[_handle].close = originalClose - // `_processChunk()` adds an 'error' listener. If we don't remove it - // after each call, these handlers start piling up. - this[_handle].removeAllListeners('error') - // make sure OUR error listener is still attached tho - } + useStaleWhileRevalidate() { + return this.maxAge() + toNumberOrZero(this._rescc['stale-while-revalidate']) > this.age(); } - if (this[_handle]) - this[_handle].on('error', er => this[_onError](new ZlibError(er))) - - let writeReturn - if (result) { - if (Array.isArray(result) && result.length > 0) { - // The first buffer is always `handle._outBuffer`, which would be - // re-used for later invocations; so, we always have to copy that one. - writeReturn = this[_superWrite](Buffer.from(result[0])) - for (let i = 1; i < result.length; i++) { - writeReturn = this[_superWrite](result[i]) - } - } else { - writeReturn = this[_superWrite](Buffer.from(result)) - } + static fromObject(obj) { + return new this(undefined, undefined, { _fromObject: obj }); } - if (cb) - cb() - return writeReturn - } - - [_superWrite] (data) { - return super.write(data) - } -} - -class Zlib extends ZlibBase { - constructor (opts, mode) { - opts = opts || {} - - opts.flush = opts.flush || constants.Z_NO_FLUSH - opts.finishFlush = opts.finishFlush || constants.Z_FINISH - super(opts, mode) - - this[_fullFlushFlag] = constants.Z_FULL_FLUSH - this[_level] = opts.level - this[_strategy] = opts.strategy - } + _fromObject(obj) { + if (this._responseTime) throw Error('Reinitialized'); + if (!obj || obj.v !== 1) throw Error('Invalid serialization'); - params (level, strategy) { - if (this[_sawError]) - return - - if (!this[_handle]) - throw new Error('cannot switch params when binding is closed') - - // no way to test this without also not supporting params at all - /* istanbul ignore if */ - if (!this[_handle].params) - throw new Error('not supported in this implementation') - - if (this[_level] !== level || this[_strategy] !== strategy) { - this.flush(constants.Z_SYNC_FLUSH) - assert(this[_handle], 'zlib binding closed') - // .params() calls .flush(), but the latter is always async in the - // core zlib. We override .flush() temporarily to intercept that and - // flush synchronously. - const origFlush = this[_handle].flush - this[_handle].flush = (flushFlag, cb) => { - this.flush(flushFlag) - cb() - } - try { - this[_handle].params(level, strategy) - } finally { - this[_handle].flush = origFlush - } - /* istanbul ignore else */ - if (this[_handle]) { - this[_level] = level - this[_strategy] = strategy - } + this._responseTime = obj.t; + this._isShared = obj.sh; + this._cacheHeuristic = obj.ch; + this._immutableMinTtl = + obj.imm !== undefined ? obj.imm : 24 * 3600 * 1000; + this._status = obj.st; + this._resHeaders = obj.resh; + this._rescc = obj.rescc; + this._method = obj.m; + this._url = obj.u; + this._host = obj.h; + this._noAuthorization = obj.a; + this._reqHeaders = obj.reqh; + this._reqcc = obj.reqcc; } - } -} - -// minimal 2-byte header -class Deflate extends Zlib { - constructor (opts) { - super(opts, 'Deflate') - } -} -class Inflate extends Zlib { - constructor (opts) { - super(opts, 'Inflate') - } -} - -// gzip - bigger header, same deflate compression -const _portable = Symbol('_portable') -class Gzip extends Zlib { - constructor (opts) { - super(opts, 'Gzip') - this[_portable] = opts && !!opts.portable - } + toObject() { + return { + v: 1, + t: this._responseTime, + sh: this._isShared, + ch: this._cacheHeuristic, + imm: this._immutableMinTtl, + st: this._status, + resh: this._resHeaders, + rescc: this._rescc, + m: this._method, + u: this._url, + h: this._host, + a: this._noAuthorization, + reqh: this._reqHeaders, + reqcc: this._reqcc, + }; + } - [_superWrite] (data) { - if (!this[_portable]) - return super[_superWrite](data) + /** + * Headers for sending to the origin server to revalidate stale response. + * Allows server to return 304 to allow reuse of the previous response. + * + * Hop by hop headers are always stripped. + * Revalidation headers may be added or removed, depending on request. + */ + revalidationHeaders(incomingReq) { + this._assertRequestHasHeaders(incomingReq); + const headers = this._copyWithoutHopByHopHeaders(incomingReq.headers); - // we'll always get the header emitted in one first chunk - // overwrite the OS indicator byte with 0xFF - this[_portable] = false - data[9] = 255 - return super[_superWrite](data) - } -} + // This implementation does not understand range requests + delete headers['if-range']; -class Gunzip extends Zlib { - constructor (opts) { - super(opts, 'Gunzip') - } -} + if (!this._requestMatches(incomingReq, true) || !this.storable()) { + // revalidation allowed via HEAD + // not for the same resource, or wasn't allowed to be cached anyway + delete headers['if-none-match']; + delete headers['if-modified-since']; + return headers; + } -// raw - no header -class DeflateRaw extends Zlib { - constructor (opts) { - super(opts, 'DeflateRaw') - } -} + /* MUST send that entity-tag in any cache validation request (using If-Match or If-None-Match) if an entity-tag has been provided by the origin server. */ + if (this._resHeaders.etag) { + headers['if-none-match'] = headers['if-none-match'] + ? `${headers['if-none-match']}, ${this._resHeaders.etag}` + : this._resHeaders.etag; + } -class InflateRaw extends Zlib { - constructor (opts) { - super(opts, 'InflateRaw') - } -} + // Clients MAY issue simple (non-subrange) GET requests with either weak validators or strong validators. Clients MUST NOT use weak validators in other forms of request. + const forbidsWeakValidators = + headers['accept-ranges'] || + headers['if-match'] || + headers['if-unmodified-since'] || + (this._method && this._method != 'GET'); -// auto-detect header. -class Unzip extends Zlib { - constructor (opts) { - super(opts, 'Unzip') - } -} + /* SHOULD send the Last-Modified value in non-subrange cache validation requests (using If-Modified-Since) if only a Last-Modified value has been provided by the origin server. + Note: This implementation does not understand partial responses (206) */ + if (forbidsWeakValidators) { + delete headers['if-modified-since']; -class Brotli extends ZlibBase { - constructor (opts, mode) { - opts = opts || {} + if (headers['if-none-match']) { + const etags = headers['if-none-match'] + .split(/,/) + .filter(etag => { + return !/^\s*W\//.test(etag); + }); + if (!etags.length) { + delete headers['if-none-match']; + } else { + headers['if-none-match'] = etags.join(',').trim(); + } + } + } else if ( + this._resHeaders['last-modified'] && + !headers['if-modified-since'] + ) { + headers['if-modified-since'] = this._resHeaders['last-modified']; + } - opts.flush = opts.flush || constants.BROTLI_OPERATION_PROCESS - opts.finishFlush = opts.finishFlush || constants.BROTLI_OPERATION_FINISH + return headers; + } - super(opts, mode) + /** + * Creates new CachePolicy with information combined from the previews response, + * and the new revalidation response. + * + * Returns {policy, modified} where modified is a boolean indicating + * whether the response body has been modified, and old cached body can't be used. + * + * @return {Object} {policy: CachePolicy, modified: Boolean} + */ + revalidatedPolicy(request, response) { + this._assertRequestHasHeaders(request); + if(this._useStaleIfError() && isErrorResponse(response)) { // I consider the revalidation request unsuccessful + return { + modified: false, + matches: false, + policy: this, + }; + } + if (!response || !response.headers) { + throw Error('Response headers missing'); + } - this[_fullFlushFlag] = constants.BROTLI_OPERATION_FLUSH - } -} + // These aren't going to be supported exactly, since one CachePolicy object + // doesn't know about all the other cached objects. + let matches = false; + if (response.status !== undefined && response.status != 304) { + matches = false; + } else if ( + response.headers.etag && + !/^\s*W\//.test(response.headers.etag) + ) { + // "All of the stored responses with the same strong validator are selected. + // If none of the stored responses contain the same strong validator, + // then the cache MUST NOT use the new response to update any stored responses." + matches = + this._resHeaders.etag && + this._resHeaders.etag.replace(/^\s*W\//, '') === + response.headers.etag; + } else if (this._resHeaders.etag && response.headers.etag) { + // "If the new response contains a weak validator and that validator corresponds + // to one of the cache's stored responses, + // then the most recent of those matching stored responses is selected for update." + matches = + this._resHeaders.etag.replace(/^\s*W\//, '') === + response.headers.etag.replace(/^\s*W\//, ''); + } else if (this._resHeaders['last-modified']) { + matches = + this._resHeaders['last-modified'] === + response.headers['last-modified']; + } else { + // If the new response does not include any form of validator (such as in the case where + // a client generates an If-Modified-Since request from a source other than the Last-Modified + // response header field), and there is only one stored response, and that stored response also + // lacks a validator, then that stored response is selected for update. + if ( + !this._resHeaders.etag && + !this._resHeaders['last-modified'] && + !response.headers.etag && + !response.headers['last-modified'] + ) { + matches = true; + } + } -class BrotliCompress extends Brotli { - constructor (opts) { - super(opts, 'BrotliCompress') - } -} + if (!matches) { + return { + policy: new this.constructor(request, response), + // Client receiving 304 without body, even if it's invalid/mismatched has no option + // but to reuse a cached body. We don't have a good way to tell clients to do + // error recovery in such case. + modified: response.status != 304, + matches: false, + }; + } -class BrotliDecompress extends Brotli { - constructor (opts) { - super(opts, 'BrotliDecompress') - } -} + // use other header fields provided in the 304 (Not Modified) response to replace all instances + // of the corresponding header fields in the stored response. + const headers = {}; + for (const k in this._resHeaders) { + headers[k] = + k in response.headers && !excludedFromRevalidationUpdate[k] + ? response.headers[k] + : this._resHeaders[k]; + } -exports.Deflate = Deflate -exports.Inflate = Inflate -exports.Gzip = Gzip -exports.Gunzip = Gunzip -exports.DeflateRaw = DeflateRaw -exports.InflateRaw = InflateRaw -exports.Unzip = Unzip -/* istanbul ignore else */ -if (typeof realZlib.BrotliCompress === 'function') { - exports.BrotliCompress = BrotliCompress - exports.BrotliDecompress = BrotliDecompress -} else { - exports.BrotliCompress = exports.BrotliDecompress = class { - constructor () { - throw new Error('Brotli is not supported in this version of Node.js') + const newResponse = Object.assign({}, response, { + status: this._status, + method: this._method, + headers, + }); + return { + policy: new this.constructor(request, newResponse, { + shared: this._isShared, + cacheHeuristic: this._cacheHeuristic, + immutableMinTimeToLive: this._immutableMinTtl, + }), + modified: false, + matches: true, + }; } - } -} +}; /***/ }), -/***/ 7557: +/***/ 9898: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const proc = typeof process === 'object' && process ? process : { - stdout: null, - stderr: null, -} -const EE = __nccwpck_require__(2361) -const Stream = __nccwpck_require__(2781) -const SD = (__nccwpck_require__(1576).StringDecoder) - -const EOF = Symbol('EOF') -const MAYBE_EMIT_END = Symbol('maybeEmitEnd') -const EMITTED_END = Symbol('emittedEnd') -const EMITTING_END = Symbol('emittingEnd') -const EMITTED_ERROR = Symbol('emittedError') -const CLOSED = Symbol('closed') -const READ = Symbol('read') -const FLUSH = Symbol('flush') -const FLUSHCHUNK = Symbol('flushChunk') -const ENCODING = Symbol('encoding') -const DECODER = Symbol('decoder') -const FLOWING = Symbol('flowing') -const PAUSED = Symbol('paused') -const RESUME = Symbol('resume') -const BUFFERLENGTH = Symbol('bufferLength') -const BUFFERPUSH = Symbol('bufferPush') -const BUFFERSHIFT = Symbol('bufferShift') -const OBJECTMODE = Symbol('objectMode') -const DESTROYED = Symbol('destroyed') -const EMITDATA = Symbol('emitData') -const EMITEND = Symbol('emitEnd') -const EMITEND2 = Symbol('emitEnd2') -const ASYNC = Symbol('async') - -const defer = fn => Promise.resolve().then(fn) - -// TODO remove when Node v8 support drops -const doIter = global._MP_NO_ITERATOR_SYMBOLS_ !== '1' -const ASYNCITERATOR = doIter && Symbol.asyncIterator - || Symbol('asyncIterator not implemented') -const ITERATOR = doIter && Symbol.iterator - || Symbol('iterator not implemented') - -// events that mean 'the stream is over' -// these are treated specially, and re-emitted -// if they are listened for after emitting. -const isEndish = ev => - ev === 'end' || - ev === 'finish' || - ev === 'prefinish' - -const isArrayBuffer = b => b instanceof ArrayBuffer || - typeof b === 'object' && - b.constructor && - b.constructor.name === 'ArrayBuffer' && - b.byteLength >= 0 - -const isArrayBufferView = b => !Buffer.isBuffer(b) && ArrayBuffer.isView(b) - -class Pipe { - constructor (src, dest, opts) { - this.src = src - this.dest = dest - this.opts = opts - this.ondrain = () => src[RESUME]() - dest.on('drain', this.ondrain) - } - unpipe () { - this.dest.removeListener('drain', this.ondrain) - } - // istanbul ignore next - only here for the prototype - proxyErrors () {} - end () { - this.unpipe() - if (this.opts.end) - this.dest.end() - } -} +// See https://github.com/facebook/jest/issues/2549 +// eslint-disable-next-line node/prefer-global/url +const {URL} = __nccwpck_require__(7310); +const EventEmitter = __nccwpck_require__(2361); +const tls = __nccwpck_require__(4404); +const http2 = __nccwpck_require__(5158); +const QuickLRU = __nccwpck_require__(9273); +const delayAsyncDestroy = __nccwpck_require__(9237); -class PipeProxyErrors extends Pipe { - unpipe () { - this.src.removeListener('error', this.proxyErrors) - super.unpipe() - } - constructor (src, dest, opts) { - super(src, dest, opts) - this.proxyErrors = er => dest.emit('error', er) - src.on('error', this.proxyErrors) - } -} +const kCurrentStreamCount = Symbol('currentStreamCount'); +const kRequest = Symbol('request'); +const kOriginSet = Symbol('cachedOriginSet'); +const kGracefullyClosing = Symbol('gracefullyClosing'); +const kLength = Symbol('length'); -module.exports = class Minipass extends Stream { - constructor (options) { - super() - this[FLOWING] = false - // whether we're explicitly paused - this[PAUSED] = false - this.pipes = [] - this.buffer = [] - this[OBJECTMODE] = options && options.objectMode || false - if (this[OBJECTMODE]) - this[ENCODING] = null - else - this[ENCODING] = options && options.encoding || null - if (this[ENCODING] === 'buffer') - this[ENCODING] = null - this[ASYNC] = options && !!options.async || false - this[DECODER] = this[ENCODING] ? new SD(this[ENCODING]) : null - this[EOF] = false - this[EMITTED_END] = false - this[EMITTING_END] = false - this[CLOSED] = false - this[EMITTED_ERROR] = null - this.writable = true - this.readable = true - this[BUFFERLENGTH] = 0 - this[DESTROYED] = false - } +const nameKeys = [ + // Not an Agent option actually + 'createConnection', + + // `http2.connect()` options + 'maxDeflateDynamicTableSize', + 'maxSettings', + 'maxSessionMemory', + 'maxHeaderListPairs', + 'maxOutstandingPings', + 'maxReservedRemoteStreams', + 'maxSendHeaderBlockLength', + 'paddingStrategy', + 'peerMaxConcurrentStreams', + 'settings', - get bufferLength () { return this[BUFFERLENGTH] } + // `tls.connect()` source options + 'family', + 'localAddress', + 'rejectUnauthorized', - get encoding () { return this[ENCODING] } - set encoding (enc) { - if (this[OBJECTMODE]) - throw new Error('cannot set encoding in objectMode') + // `tls.connect()` secure context options + 'pskCallback', + 'minDHSize', - if (this[ENCODING] && enc !== this[ENCODING] && - (this[DECODER] && this[DECODER].lastNeed || this[BUFFERLENGTH])) - throw new Error('cannot change encoding') + // `tls.connect()` destination options + // - `servername` is automatically validated, skip it + // - `host` and `port` just describe the destination server, + 'path', + 'socket', - if (this[ENCODING] !== enc) { - this[DECODER] = enc ? new SD(enc) : null - if (this.buffer.length) - this.buffer = this.buffer.map(chunk => this[DECODER].write(chunk)) - } + // `tls.createSecureContext()` options + 'ca', + 'cert', + 'sigalgs', + 'ciphers', + 'clientCertEngine', + 'crl', + 'dhparam', + 'ecdhCurve', + 'honorCipherOrder', + 'key', + 'privateKeyEngine', + 'privateKeyIdentifier', + 'maxVersion', + 'minVersion', + 'pfx', + 'secureOptions', + 'secureProtocol', + 'sessionIdContext', + 'ticketKeys' +]; - this[ENCODING] = enc - } +const getSortedIndex = (array, value, compare) => { + let low = 0; + let high = array.length; - setEncoding (enc) { - this.encoding = enc - } + while (low < high) { + const mid = (low + high) >>> 1; - get objectMode () { return this[OBJECTMODE] } - set objectMode (om) { this[OBJECTMODE] = this[OBJECTMODE] || !!om } + if (compare(array[mid], value)) { + low = mid + 1; + } else { + high = mid; + } + } - get ['async'] () { return this[ASYNC] } - set ['async'] (a) { this[ASYNC] = this[ASYNC] || !!a } + return low; +}; - write (chunk, encoding, cb) { - if (this[EOF]) - throw new Error('write after end') +const compareSessions = (a, b) => a.remoteSettings.maxConcurrentStreams > b.remoteSettings.maxConcurrentStreams; - if (this[DESTROYED]) { - this.emit('error', Object.assign( - new Error('Cannot call write after a stream was destroyed'), - { code: 'ERR_STREAM_DESTROYED' } - )) - return true - } +// See https://tools.ietf.org/html/rfc8336 +const closeCoveredSessions = (where, session) => { + // Clients SHOULD NOT emit new requests on any connection whose Origin + // Set is a proper subset of another connection's Origin Set, and they + // SHOULD close it once all outstanding requests are satisfied. + for (let index = 0; index < where.length; index++) { + const coveredSession = where[index]; - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' + if ( + // Unfortunately `.every()` returns true for an empty array + coveredSession[kOriginSet].length > 0 - if (!encoding) - encoding = 'utf8' + // The set is a proper subset when its length is less than the other set. + && coveredSession[kOriginSet].length < session[kOriginSet].length - const fn = this[ASYNC] ? defer : f => f() + // And the other set includes all elements of the subset. + && coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) - // convert array buffers and typed array views into buffers - // at some point in the future, we may want to do the opposite! - // leave strings and buffers as-is - // anything else switches us into object mode - if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) { - if (isArrayBufferView(chunk)) - chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength) - else if (isArrayBuffer(chunk)) - chunk = Buffer.from(chunk) - else if (typeof chunk !== 'string') - // use the setter so we throw if we have encoding set - this.objectMode = true - } + // Makes sure that the session can handle all requests from the covered session. + && (coveredSession[kCurrentStreamCount] + session[kCurrentStreamCount]) <= session.remoteSettings.maxConcurrentStreams + ) { + // This allows pending requests to finish and prevents making new requests. + gracefullyClose(coveredSession); + } + } +}; - // handle object mode up front, since it's simpler - // this yields better performance, fewer checks later. - if (this[OBJECTMODE]) { - /* istanbul ignore if - maybe impossible? */ - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) +// This is basically inverted `closeCoveredSessions(...)`. +const closeSessionIfCovered = (where, coveredSession) => { + for (let index = 0; index < where.length; index++) { + const session = where[index]; - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) + if ( + coveredSession[kOriginSet].length > 0 + && coveredSession[kOriginSet].length < session[kOriginSet].length + && coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) + && (coveredSession[kCurrentStreamCount] + session[kCurrentStreamCount]) <= session.remoteSettings.maxConcurrentStreams + ) { + gracefullyClose(coveredSession); - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') + return true; + } + } - if (cb) - fn(cb) + return false; +}; - return this.flowing - } +const gracefullyClose = session => { + session[kGracefullyClosing] = true; - // at this point the chunk is a buffer or string - // don't buffer it up or send it to the decoder - if (!chunk.length) { - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - if (cb) - fn(cb) - return this.flowing - } + if (session[kCurrentStreamCount] === 0) { + session.close(); + } +}; - // fast-path writing strings of same encoding to a stream with - // an empty buffer, skipping the buffer/decoder dance - if (typeof chunk === 'string' && - // unless it is a string already ready for us to use - !(encoding === this[ENCODING] && !this[DECODER].lastNeed)) { - chunk = Buffer.from(chunk, encoding) - } +class Agent extends EventEmitter { + constructor({timeout = 0, maxSessions = Number.POSITIVE_INFINITY, maxEmptySessions = 10, maxCachedTlsSessions = 100} = {}) { + super(); + + // SESSIONS[NORMALIZED_OPTIONS] = []; + this.sessions = {}; + + // The queue for creating new sessions. It looks like this: + // QUEUE[NORMALIZED_OPTIONS][NORMALIZED_ORIGIN] = ENTRY_FUNCTION + // + // It's faster when there are many origins. If there's only one, then QUEUE[`${options}:${origin}`] is faster. + // I guess object creation / deletion is causing the slowdown. + // + // The entry function has `listeners`, `completed` and `destroyed` properties. + // `listeners` is an array of objects containing `resolve` and `reject` functions. + // `completed` is a boolean. It's set to true after ENTRY_FUNCTION is executed. + // `destroyed` is a boolean. If it's set to true, the session will be destroyed if hasn't connected yet. + this.queue = {}; - if (Buffer.isBuffer(chunk) && this[ENCODING]) - chunk = this[DECODER].write(chunk) + // Each session will use this timeout value. + this.timeout = timeout; - // Note: flushing CAN potentially switch us into not-flowing mode - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) + // Max sessions in total + this.maxSessions = maxSessions; - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) + // Max empty sessions in total + this.maxEmptySessions = maxEmptySessions; - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') + this._emptySessionCount = 0; + this._sessionCount = 0; - if (cb) - fn(cb) + // We don't support push streams by default. + this.settings = { + enablePush: false, + initialWindowSize: 1024 * 1024 * 32 // 32MB, see https://github.com/nodejs/node/issues/38426 + }; - return this.flowing - } + // Reusing TLS sessions increases performance. + this.tlsSessionCache = new QuickLRU({maxSize: maxCachedTlsSessions}); + } - read (n) { - if (this[DESTROYED]) - return null + get protocol() { + return 'https:'; + } - if (this[BUFFERLENGTH] === 0 || n === 0 || n > this[BUFFERLENGTH]) { - this[MAYBE_EMIT_END]() - return null - } + normalizeOptions(options) { + let normalized = ''; - if (this[OBJECTMODE]) - n = null + for (let index = 0; index < nameKeys.length; index++) { + const key = nameKeys[index]; - if (this.buffer.length > 1 && !this[OBJECTMODE]) { - if (this.encoding) - this.buffer = [this.buffer.join('')] - else - this.buffer = [Buffer.concat(this.buffer, this[BUFFERLENGTH])] - } + normalized += ':'; - const ret = this[READ](n || null, this.buffer[0]) - this[MAYBE_EMIT_END]() - return ret - } + if (options && options[key] !== undefined) { + normalized += options[key]; + } + } - [READ] (n, chunk) { - if (n === chunk.length || n === null) - this[BUFFERSHIFT]() - else { - this.buffer[0] = chunk.slice(n) - chunk = chunk.slice(0, n) - this[BUFFERLENGTH] -= n - } + return normalized; + } - this.emit('data', chunk) + _processQueue() { + if (this._sessionCount >= this.maxSessions) { + this.closeEmptySessions(this.maxSessions - this._sessionCount + 1); + return; + } - if (!this.buffer.length && !this[EOF]) - this.emit('drain') + // eslint-disable-next-line guard-for-in + for (const normalizedOptions in this.queue) { + // eslint-disable-next-line guard-for-in + for (const normalizedOrigin in this.queue[normalizedOptions]) { + const item = this.queue[normalizedOptions][normalizedOrigin]; - return chunk - } + // The entry function can be run only once. + if (!item.completed) { + item.completed = true; - end (chunk, encoding, cb) { - if (typeof chunk === 'function') - cb = chunk, chunk = null - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - if (chunk) - this.write(chunk, encoding) - if (cb) - this.once('end', cb) - this[EOF] = true - this.writable = false - - // if we haven't written anything, then go ahead and emit, - // even if we're not reading. - // we'll re-emit if a new 'end' listener is added anyway. - // This makes MP more suitable to write-only use cases. - if (this.flowing || !this[PAUSED]) - this[MAYBE_EMIT_END]() - return this - } + item(); + } + } + } + } - // don't let the internal resume be overwritten - [RESUME] () { - if (this[DESTROYED]) - return - - this[PAUSED] = false - this[FLOWING] = true - this.emit('resume') - if (this.buffer.length) - this[FLUSH]() - else if (this[EOF]) - this[MAYBE_EMIT_END]() - else - this.emit('drain') - } + _isBetterSession(thisStreamCount, thatStreamCount) { + return thisStreamCount > thatStreamCount; + } - resume () { - return this[RESUME]() - } + _accept(session, listeners, normalizedOrigin, options) { + let index = 0; - pause () { - this[FLOWING] = false - this[PAUSED] = true - } + while (index < listeners.length && session[kCurrentStreamCount] < session.remoteSettings.maxConcurrentStreams) { + // We assume `resolve(...)` calls `request(...)` *directly*, + // otherwise the session will get overloaded. + listeners[index].resolve(session); - get destroyed () { - return this[DESTROYED] - } + index++; + } - get flowing () { - return this[FLOWING] - } + listeners.splice(0, index); - get paused () { - return this[PAUSED] - } + if (listeners.length > 0) { + this.getSession(normalizedOrigin, options, listeners); + listeners.length = 0; + } + } - [BUFFERPUSH] (chunk) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] += 1 - else - this[BUFFERLENGTH] += chunk.length - this.buffer.push(chunk) - } + getSession(origin, options, listeners) { + return new Promise((resolve, reject) => { + if (Array.isArray(listeners) && listeners.length > 0) { + listeners = [...listeners]; - [BUFFERSHIFT] () { - if (this.buffer.length) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] -= 1 - else - this[BUFFERLENGTH] -= this.buffer[0].length - } - return this.buffer.shift() - } + // Resolve the current promise ASAP, we're just moving the listeners. + // They will be executed at a different time. + resolve(); + } else { + listeners = [{resolve, reject}]; + } - [FLUSH] (noDrain) { - do {} while (this[FLUSHCHUNK](this[BUFFERSHIFT]())) + try { + // Parse origin + if (typeof origin === 'string') { + origin = new URL(origin); + } else if (!(origin instanceof URL)) { + throw new TypeError('The `origin` argument needs to be a string or an URL object'); + } - if (!noDrain && !this.buffer.length && !this[EOF]) - this.emit('drain') - } + if (options) { + // Validate servername + const {servername} = options; + const {hostname} = origin; + if (servername && hostname !== servername) { + throw new Error(`Origin ${hostname} differs from servername ${servername}`); + } + } + } catch (error) { + for (let index = 0; index < listeners.length; index++) { + listeners[index].reject(error); + } - [FLUSHCHUNK] (chunk) { - return chunk ? (this.emit('data', chunk), this.flowing) : false - } + return; + } - pipe (dest, opts) { - if (this[DESTROYED]) - return - - const ended = this[EMITTED_END] - opts = opts || {} - if (dest === proc.stdout || dest === proc.stderr) - opts.end = false - else - opts.end = opts.end !== false - opts.proxyErrors = !!opts.proxyErrors - - // piping an ended stream ends immediately - if (ended) { - if (opts.end) - dest.end() - } else { - this.pipes.push(!opts.proxyErrors ? new Pipe(this, dest, opts) - : new PipeProxyErrors(this, dest, opts)) - if (this[ASYNC]) - defer(() => this[RESUME]()) - else - this[RESUME]() - } + const normalizedOptions = this.normalizeOptions(options); + const normalizedOrigin = origin.origin; - return dest - } + if (normalizedOptions in this.sessions) { + const sessions = this.sessions[normalizedOptions]; - unpipe (dest) { - const p = this.pipes.find(p => p.dest === dest) - if (p) { - this.pipes.splice(this.pipes.indexOf(p), 1) - p.unpipe() - } - } + let maxConcurrentStreams = -1; + let currentStreamsCount = -1; + let optimalSession; - addListener (ev, fn) { - return this.on(ev, fn) - } + // We could just do this.sessions[normalizedOptions].find(...) but that isn't optimal. + // Additionally, we are looking for session which has biggest current pending streams count. + // + // |------------| |------------| |------------| |------------| + // | Session: A | | Session: B | | Session: C | | Session: D | + // | Pending: 5 |-| Pending: 8 |-| Pending: 9 |-| Pending: 4 | + // | Max: 10 | | Max: 10 | | Max: 9 | | Max: 5 | + // |------------| |------------| |------------| |------------| + // ^ + // | + // pick this one -- + // + for (let index = 0; index < sessions.length; index++) { + const session = sessions[index]; - on (ev, fn) { - const ret = super.on(ev, fn) - if (ev === 'data' && !this.pipes.length && !this.flowing) - this[RESUME]() - else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) - super.emit('readable') - else if (isEndish(ev) && this[EMITTED_END]) { - super.emit(ev) - this.removeAllListeners(ev) - } else if (ev === 'error' && this[EMITTED_ERROR]) { - if (this[ASYNC]) - defer(() => fn.call(this, this[EMITTED_ERROR])) - else - fn.call(this, this[EMITTED_ERROR]) - } - return ret - } + const sessionMaxConcurrentStreams = session.remoteSettings.maxConcurrentStreams; - get emittedEnd () { - return this[EMITTED_END] - } + if (sessionMaxConcurrentStreams < maxConcurrentStreams) { + break; + } - [MAYBE_EMIT_END] () { - if (!this[EMITTING_END] && - !this[EMITTED_END] && - !this[DESTROYED] && - this.buffer.length === 0 && - this[EOF]) { - this[EMITTING_END] = true - this.emit('end') - this.emit('prefinish') - this.emit('finish') - if (this[CLOSED]) - this.emit('close') - this[EMITTING_END] = false - } - } + if (!session[kOriginSet].includes(normalizedOrigin)) { + continue; + } - emit (ev, data, ...extra) { - // error and close are only events allowed after calling destroy() - if (ev !== 'error' && ev !== 'close' && ev !== DESTROYED && this[DESTROYED]) - return - else if (ev === 'data') { - return !data ? false - : this[ASYNC] ? defer(() => this[EMITDATA](data)) - : this[EMITDATA](data) - } else if (ev === 'end') { - return this[EMITEND]() - } else if (ev === 'close') { - this[CLOSED] = true - // don't emit close before 'end' and 'finish' - if (!this[EMITTED_END] && !this[DESTROYED]) - return - const ret = super.emit('close') - this.removeAllListeners('close') - return ret - } else if (ev === 'error') { - this[EMITTED_ERROR] = data - const ret = super.emit('error', data) - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'resume') { - const ret = super.emit('resume') - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'finish' || ev === 'prefinish') { - const ret = super.emit(ev) - this.removeAllListeners(ev) - return ret - } - - // Some other unknown event - const ret = super.emit(ev, data, ...extra) - this[MAYBE_EMIT_END]() - return ret - } + const sessionCurrentStreamsCount = session[kCurrentStreamCount]; - [EMITDATA] (data) { - for (const p of this.pipes) { - if (p.dest.write(data) === false) - this.pause() - } - const ret = super.emit('data', data) - this[MAYBE_EMIT_END]() - return ret - } + if ( + sessionCurrentStreamsCount >= sessionMaxConcurrentStreams + || session[kGracefullyClosing] + // Unfortunately the `close` event isn't called immediately, + // so `session.destroyed` is `true`, but `session.closed` is `false`. + || session.destroyed + ) { + continue; + } - [EMITEND] () { - if (this[EMITTED_END]) - return + // We only need set this once. + if (!optimalSession) { + maxConcurrentStreams = sessionMaxConcurrentStreams; + } - this[EMITTED_END] = true - this.readable = false - if (this[ASYNC]) - defer(() => this[EMITEND2]()) - else - this[EMITEND2]() - } + // Either get the session which has biggest current stream count or the lowest. + if (this._isBetterSession(sessionCurrentStreamsCount, currentStreamsCount)) { + optimalSession = session; + currentStreamsCount = sessionCurrentStreamsCount; + } + } - [EMITEND2] () { - if (this[DECODER]) { - const data = this[DECODER].end() - if (data) { - for (const p of this.pipes) { - p.dest.write(data) - } - super.emit('data', data) - } - } + if (optimalSession) { + this._accept(optimalSession, listeners, normalizedOrigin, options); + return; + } + } - for (const p of this.pipes) { - p.end() - } - const ret = super.emit('end') - this.removeAllListeners('end') - return ret - } + if (normalizedOptions in this.queue) { + if (normalizedOrigin in this.queue[normalizedOptions]) { + // There's already an item in the queue, just attach ourselves to it. + this.queue[normalizedOptions][normalizedOrigin].listeners.push(...listeners); + return; + } + } else { + this.queue[normalizedOptions] = { + [kLength]: 0 + }; + } - // const all = await stream.collect() - collect () { - const buf = [] - if (!this[OBJECTMODE]) - buf.dataLength = 0 - // set the promise first, in case an error is raised - // by triggering the flow here. - const p = this.promise() - this.on('data', c => { - buf.push(c) - if (!this[OBJECTMODE]) - buf.dataLength += c.length - }) - return p.then(() => buf) - } + // The entry must be removed from the queue IMMEDIATELY when: + // 1. the session connects successfully, + // 2. an error occurs. + const removeFromQueue = () => { + // Our entry can be replaced. We cannot remove the new one. + if (normalizedOptions in this.queue && this.queue[normalizedOptions][normalizedOrigin] === entry) { + delete this.queue[normalizedOptions][normalizedOrigin]; - // const data = await stream.concat() - concat () { - return this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this.collect().then(buf => - this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this[ENCODING] ? buf.join('') : Buffer.concat(buf, buf.dataLength)) - } + if (--this.queue[normalizedOptions][kLength] === 0) { + delete this.queue[normalizedOptions]; + } + } + }; - // stream.promise().then(() => done, er => emitted error) - promise () { - return new Promise((resolve, reject) => { - this.on(DESTROYED, () => reject(new Error('stream destroyed'))) - this.on('error', er => reject(er)) - this.on('end', () => resolve()) - }) - } + // The main logic is here + const entry = async () => { + this._sessionCount++; - // for await (let chunk of stream) - [ASYNCITERATOR] () { - const next = () => { - const res = this.read() - if (res !== null) - return Promise.resolve({ done: false, value: res }) - - if (this[EOF]) - return Promise.resolve({ done: true }) - - let resolve = null - let reject = null - const onerr = er => { - this.removeListener('data', ondata) - this.removeListener('end', onend) - reject(er) - } - const ondata = value => { - this.removeListener('error', onerr) - this.removeListener('end', onend) - this.pause() - resolve({ value: value, done: !!this[EOF] }) - } - const onend = () => { - this.removeListener('error', onerr) - this.removeListener('data', ondata) - resolve({ done: true }) - } - const ondestroy = () => onerr(new Error('stream destroyed')) - return new Promise((res, rej) => { - reject = rej - resolve = res - this.once(DESTROYED, ondestroy) - this.once('error', onerr) - this.once('end', onend) - this.once('data', ondata) - }) - } + const name = `${normalizedOrigin}:${normalizedOptions}`; + let receivedSettings = false; + let socket; - return { next } - } + try { + const computedOptions = {...options}; - // for (let chunk of stream) - [ITERATOR] () { - const next = () => { - const value = this.read() - const done = value === null - return { value, done } - } - return { next } - } + if (computedOptions.settings === undefined) { + computedOptions.settings = this.settings; + } - destroy (er) { - if (this[DESTROYED]) { - if (er) - this.emit('error', er) - else - this.emit(DESTROYED) - return this - } + if (computedOptions.session === undefined) { + computedOptions.session = this.tlsSessionCache.get(name); + } - this[DESTROYED] = true + const createConnection = computedOptions.createConnection || this.createConnection; - // throw away all buffered data, it's never coming out - this.buffer.length = 0 - this[BUFFERLENGTH] = 0 + // A hacky workaround to enable async `createConnection` + socket = await createConnection.call(this, origin, computedOptions); + computedOptions.createConnection = () => socket; - if (typeof this.close === 'function' && !this[CLOSED]) - this.close() + const session = http2.connect(origin, computedOptions); + session[kCurrentStreamCount] = 0; + session[kGracefullyClosing] = false; - if (er) - this.emit('error', er) - else // if no error to emit, still reject pending promises - this.emit(DESTROYED) + // Node.js return https://false:443 instead of https://1.1.1.1:443 + const getOriginSet = () => { + const {socket} = session; - return this - } + let originSet; + if (socket.servername === false) { + socket.servername = socket.remoteAddress; + originSet = session.originSet; + socket.servername = false; + } else { + originSet = session.originSet; + } - static isStream (s) { - return !!s && (s instanceof Minipass || s instanceof Stream || - s instanceof EE && ( - typeof s.pipe === 'function' || // readable - (typeof s.write === 'function' && typeof s.end === 'function') // writable - )) - } -} + return originSet; + }; + const isFree = () => session[kCurrentStreamCount] < session.remoteSettings.maxConcurrentStreams; -/***/ }), + session.socket.once('session', tlsSession => { + this.tlsSessionCache.set(name, tlsSession); + }); -/***/ 6186: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + session.once('error', error => { + // Listeners are empty when the session successfully connected. + for (let index = 0; index < listeners.length; index++) { + listeners[index].reject(error); + } -const optsArg = __nccwpck_require__(2853) -const pathArg = __nccwpck_require__(2930) + // The connection got broken, purge the cache. + this.tlsSessionCache.delete(name); + }); -const {mkdirpNative, mkdirpNativeSync} = __nccwpck_require__(4983) -const {mkdirpManual, mkdirpManualSync} = __nccwpck_require__(356) -const {useNative, useNativeSync} = __nccwpck_require__(4518) + session.setTimeout(this.timeout, () => { + // Terminates all streams owned by this session. + session.destroy(); + }); + session.once('close', () => { + this._sessionCount--; -const mkdirp = (path, opts) => { - path = pathArg(path) - opts = optsArg(opts) - return useNative(opts) - ? mkdirpNative(path, opts) - : mkdirpManual(path, opts) -} + if (receivedSettings) { + // Assumes session `close` is emitted after request `close` + this._emptySessionCount--; -const mkdirpSync = (path, opts) => { - path = pathArg(path) - opts = optsArg(opts) - return useNativeSync(opts) - ? mkdirpNativeSync(path, opts) - : mkdirpManualSync(path, opts) -} + // This cannot be moved to the stream logic, + // because there may be a session that hadn't made a single request. + const where = this.sessions[normalizedOptions]; -mkdirp.sync = mkdirpSync -mkdirp.native = (path, opts) => mkdirpNative(pathArg(path), optsArg(opts)) -mkdirp.manual = (path, opts) => mkdirpManual(pathArg(path), optsArg(opts)) -mkdirp.nativeSync = (path, opts) => mkdirpNativeSync(pathArg(path), optsArg(opts)) -mkdirp.manualSync = (path, opts) => mkdirpManualSync(pathArg(path), optsArg(opts)) + if (where.length === 1) { + delete this.sessions[normalizedOptions]; + } else { + where.splice(where.indexOf(session), 1); + } + } else { + // Broken connection + removeFromQueue(); -module.exports = mkdirp + const error = new Error('Session closed without receiving a SETTINGS frame'); + error.code = 'HTTP2WRAPPER_NOSETTINGS'; + for (let index = 0; index < listeners.length; index++) { + listeners[index].reject(error); + } + } -/***/ }), + // There may be another session awaiting. + this._processQueue(); + }); -/***/ 4992: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // Iterates over the queue and processes listeners. + const processListeners = () => { + const queue = this.queue[normalizedOptions]; + if (!queue) { + return; + } -const {dirname} = __nccwpck_require__(1017) + const originSet = session[kOriginSet]; -const findMade = (opts, parent, path = undefined) => { - // we never want the 'made' return value to be a root directory - if (path === parent) - return Promise.resolve() + for (let index = 0; index < originSet.length; index++) { + const origin = originSet[index]; - return opts.statAsync(parent).then( - st => st.isDirectory() ? path : undefined, // will fail later - er => er.code === 'ENOENT' - ? findMade(opts, dirname(parent), parent) - : undefined - ) -} + if (origin in queue) { + const {listeners, completed} = queue[origin]; -const findMadeSync = (opts, parent, path = undefined) => { - if (path === parent) - return undefined + let index = 0; - try { - return opts.statSync(parent).isDirectory() ? path : undefined - } catch (er) { - return er.code === 'ENOENT' - ? findMadeSync(opts, dirname(parent), parent) - : undefined - } -} + // Prevents session overloading. + while (index < listeners.length && isFree()) { + // We assume `resolve(...)` calls `request(...)` *directly*, + // otherwise the session will get overloaded. + listeners[index].resolve(session); -module.exports = {findMade, findMadeSync} + index++; + } + queue[origin].listeners.splice(0, index); -/***/ }), + if (queue[origin].listeners.length === 0 && !completed) { + delete queue[origin]; -/***/ 356: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + if (--queue[kLength] === 0) { + delete this.queue[normalizedOptions]; + break; + } + } -const {dirname} = __nccwpck_require__(1017) - -const mkdirpManual = (path, opts, made) => { - opts.recursive = false - const parent = dirname(path) - if (parent === path) { - return opts.mkdirAsync(path, opts).catch(er => { - // swallowed by recursive implementation on posix systems - // any other error is a failure - if (er.code !== 'EISDIR') - throw er - }) - } + // We're no longer free, no point in continuing. + if (!isFree()) { + break; + } + } + } + }; - return opts.mkdirAsync(path, opts).then(() => made || path, er => { - if (er.code === 'ENOENT') - return mkdirpManual(parent, opts) - .then(made => mkdirpManual(path, opts, made)) - if (er.code !== 'EEXIST' && er.code !== 'EROFS') - throw er - return opts.statAsync(path).then(st => { - if (st.isDirectory()) - return made - else - throw er - }, () => { throw er }) - }) -} + // The Origin Set cannot shrink. No need to check if it suddenly became covered by another one. + session.on('origin', () => { + session[kOriginSet] = getOriginSet() || []; + session[kGracefullyClosing] = false; + closeSessionIfCovered(this.sessions[normalizedOptions], session); -const mkdirpManualSync = (path, opts, made) => { - const parent = dirname(path) - opts.recursive = false + if (session[kGracefullyClosing] || !isFree()) { + return; + } - if (parent === path) { - try { - return opts.mkdirSync(path, opts) - } catch (er) { - // swallowed by recursive implementation on posix systems - // any other error is a failure - if (er.code !== 'EISDIR') - throw er - else - return - } - } + processListeners(); - try { - opts.mkdirSync(path, opts) - return made || path - } catch (er) { - if (er.code === 'ENOENT') - return mkdirpManualSync(path, opts, mkdirpManualSync(parent, opts, made)) - if (er.code !== 'EEXIST' && er.code !== 'EROFS') - throw er - try { - if (!opts.statSync(path).isDirectory()) - throw er - } catch (_) { - throw er - } - } -} + if (!isFree()) { + return; + } -module.exports = {mkdirpManual, mkdirpManualSync} + // Close covered sessions (if possible). + closeCoveredSessions(this.sessions[normalizedOptions], session); + }); + session.once('remoteSettings', () => { + // The Agent could have been destroyed already. + if (entry.destroyed) { + const error = new Error('Agent has been destroyed'); -/***/ }), + for (let index = 0; index < listeners.length; index++) { + listeners[index].reject(error); + } -/***/ 4983: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + session.destroy(); + return; + } -const {dirname} = __nccwpck_require__(1017) -const {findMade, findMadeSync} = __nccwpck_require__(4992) -const {mkdirpManual, mkdirpManualSync} = __nccwpck_require__(356) - -const mkdirpNative = (path, opts) => { - opts.recursive = true - const parent = dirname(path) - if (parent === path) - return opts.mkdirAsync(path, opts) - - return findMade(opts, path).then(made => - opts.mkdirAsync(path, opts).then(() => made) - .catch(er => { - if (er.code === 'ENOENT') - return mkdirpManual(path, opts) - else - throw er - })) -} + // See https://github.com/nodejs/node/issues/38426 + if (session.setLocalWindowSize) { + session.setLocalWindowSize(1024 * 1024 * 4); // 4 MB + } -const mkdirpNativeSync = (path, opts) => { - opts.recursive = true - const parent = dirname(path) - if (parent === path) - return opts.mkdirSync(path, opts) + session[kOriginSet] = getOriginSet() || []; - const made = findMadeSync(opts, path) - try { - opts.mkdirSync(path, opts) - return made - } catch (er) { - if (er.code === 'ENOENT') - return mkdirpManualSync(path, opts) - else - throw er - } -} + if (session.socket.encrypted) { + const mainOrigin = session[kOriginSet][0]; + if (mainOrigin !== normalizedOrigin) { + const error = new Error(`Requested origin ${normalizedOrigin} does not match server ${mainOrigin}`); -module.exports = {mkdirpNative, mkdirpNativeSync} + for (let index = 0; index < listeners.length; index++) { + listeners[index].reject(error); + } + session.destroy(); + return; + } + } -/***/ }), + removeFromQueue(); -/***/ 2853: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + { + const where = this.sessions; -const { promisify } = __nccwpck_require__(3837) -const fs = __nccwpck_require__(7147) -const optsArg = opts => { - if (!opts) - opts = { mode: 0o777, fs } - else if (typeof opts === 'object') - opts = { mode: 0o777, fs, ...opts } - else if (typeof opts === 'number') - opts = { mode: opts, fs } - else if (typeof opts === 'string') - opts = { mode: parseInt(opts, 8), fs } - else - throw new TypeError('invalid options argument') - - opts.mkdir = opts.mkdir || opts.fs.mkdir || fs.mkdir - opts.mkdirAsync = promisify(opts.mkdir) - opts.stat = opts.stat || opts.fs.stat || fs.stat - opts.statAsync = promisify(opts.stat) - opts.statSync = opts.statSync || opts.fs.statSync || fs.statSync - opts.mkdirSync = opts.mkdirSync || opts.fs.mkdirSync || fs.mkdirSync - return opts -} -module.exports = optsArg + if (normalizedOptions in where) { + const sessions = where[normalizedOptions]; + sessions.splice(getSortedIndex(sessions, session, compareSessions), 0, session); + } else { + where[normalizedOptions] = [session]; + } + } + receivedSettings = true; + this._emptySessionCount++; -/***/ }), + this.emit('session', session); + this._accept(session, listeners, normalizedOrigin, options); -/***/ 2930: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + if (session[kCurrentStreamCount] === 0 && this._emptySessionCount > this.maxEmptySessions) { + this.closeEmptySessions(this._emptySessionCount - this.maxEmptySessions); + } -const platform = process.env.__TESTING_MKDIRP_PLATFORM__ || process.platform -const { resolve, parse } = __nccwpck_require__(1017) -const pathArg = path => { - if (/\0/.test(path)) { - // simulate same failure that node raises - throw Object.assign( - new TypeError('path must be a string without null bytes'), - { - path, - code: 'ERR_INVALID_ARG_VALUE', - } - ) - } + // `session.remoteSettings.maxConcurrentStreams` might get increased + session.on('remoteSettings', () => { + if (!isFree()) { + return; + } - path = resolve(path) - if (platform === 'win32') { - const badWinChars = /[*|"<>?:]/ - const {root} = parse(path) - if (badWinChars.test(path.substr(root.length))) { - throw Object.assign(new Error('Illegal characters in path.'), { - path, - code: 'EINVAL', - }) - } - } + processListeners(); - return path -} -module.exports = pathArg + if (!isFree()) { + return; + } + // In case the Origin Set changes + closeCoveredSessions(this.sessions[normalizedOptions], session); + }); + }); -/***/ }), + // Shim `session.request()` in order to catch all streams + session[kRequest] = session.request; + session.request = (headers, streamOptions) => { + if (session[kGracefullyClosing]) { + throw new Error('The session is gracefully closing. No new streams are allowed.'); + } -/***/ 4518: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + const stream = session[kRequest](headers, streamOptions); -const fs = __nccwpck_require__(7147) + // The process won't exit until the session is closed or all requests are gone. + session.ref(); -const version = process.env.__TESTING_MKDIRP_NODE_VERSION__ || process.version -const versArr = version.replace(/^v/, '').split('.') -const hasNative = +versArr[0] > 10 || +versArr[0] === 10 && +versArr[1] >= 12 + if (session[kCurrentStreamCount]++ === 0) { + this._emptySessionCount--; + } -const useNative = !hasNative ? () => false : opts => opts.mkdir === fs.mkdir -const useNativeSync = !hasNative ? () => false : opts => opts.mkdirSync === fs.mkdirSync + stream.once('close', () => { + if (--session[kCurrentStreamCount] === 0) { + this._emptySessionCount++; + session.unref(); -module.exports = {useNative, useNativeSync} + if (this._emptySessionCount > this.maxEmptySessions || session[kGracefullyClosing]) { + session.close(); + return; + } + } + if (session.destroyed || session.closed) { + return; + } -/***/ }), + if (isFree() && !closeSessionIfCovered(this.sessions[normalizedOptions], session)) { + closeCoveredSessions(this.sessions[normalizedOptions], session); + processListeners(); -/***/ 9273: -/***/ ((module) => { + if (session[kCurrentStreamCount] === 0) { + this._processQueue(); + } + } + }); -"use strict"; + return stream; + }; + } catch (error) { + removeFromQueue(); + this._sessionCount--; + for (let index = 0; index < listeners.length; index++) { + listeners[index].reject(error); + } + } + }; -class QuickLRU { - constructor(options = {}) { - if (!(options.maxSize && options.maxSize > 0)) { - throw new TypeError('`maxSize` must be a number greater than 0'); - } + entry.listeners = listeners; + entry.completed = false; + entry.destroyed = false; - this.maxSize = options.maxSize; - this.onEviction = options.onEviction; - this.cache = new Map(); - this.oldCache = new Map(); - this._size = 0; + this.queue[normalizedOptions][normalizedOrigin] = entry; + this.queue[normalizedOptions][kLength]++; + this._processQueue(); + }); } - _set(key, value) { - this.cache.set(key, value); - this._size++; + request(origin, options, headers, streamOptions) { + return new Promise((resolve, reject) => { + this.getSession(origin, options, [{ + reject, + resolve: session => { + try { + const stream = session.request(headers, streamOptions); - if (this._size >= this.maxSize) { - this._size = 0; + // Do not throw before `request(...)` has been awaited + delayAsyncDestroy(stream); - if (typeof this.onEviction === 'function') { - for (const [key, value] of this.oldCache.entries()) { - this.onEviction(key, value); + resolve(stream); + } catch (error) { + reject(error); + } } - } + }]); + }); + } - this.oldCache = this.cache; - this.cache = new Map(); - } + async createConnection(origin, options) { + return Agent.connect(origin, options); } - get(key) { - if (this.cache.has(key)) { - return this.cache.get(key); - } + static connect(origin, options) { + options.ALPNProtocols = ['h2']; - if (this.oldCache.has(key)) { - const value = this.oldCache.get(key); - this.oldCache.delete(key); - this._set(key, value); - return value; + const port = origin.port || 443; + const host = origin.hostname; + + if (typeof options.servername === 'undefined') { + options.servername = host; } - } - set(key, value) { - if (this.cache.has(key)) { - this.cache.set(key, value); - } else { - this._set(key, value); + const socket = tls.connect(port, host, options); + + if (options.socket) { + socket._peername = { + family: undefined, + address: undefined, + port + }; } - return this; + return socket; } - has(key) { - return this.cache.has(key) || this.oldCache.has(key); - } + closeEmptySessions(maxCount = Number.POSITIVE_INFINITY) { + let closedCount = 0; - peek(key) { - if (this.cache.has(key)) { - return this.cache.get(key); - } + const {sessions} = this; - if (this.oldCache.has(key)) { - return this.oldCache.get(key); - } - } + // eslint-disable-next-line guard-for-in + for (const key in sessions) { + const thisSessions = sessions[key]; - delete(key) { - const deleted = this.cache.delete(key); - if (deleted) { - this._size--; + for (let index = 0; index < thisSessions.length; index++) { + const session = thisSessions[index]; + + if (session[kCurrentStreamCount] === 0) { + closedCount++; + session.close(); + + if (closedCount >= maxCount) { + return closedCount; + } + } + } } - return this.oldCache.delete(key) || deleted; + return closedCount; } - clear() { - this.cache.clear(); - this.oldCache.clear(); - this._size = 0; - } + destroy(reason) { + const {sessions, queue} = this; - * keys() { - for (const [key] of this) { - yield key; - } - } + // eslint-disable-next-line guard-for-in + for (const key in sessions) { + const thisSessions = sessions[key]; - * values() { - for (const [, value] of this) { - yield value; + for (let index = 0; index < thisSessions.length; index++) { + thisSessions[index].destroy(reason); + } } - } - * [Symbol.iterator]() { - for (const item of this.cache) { - yield item; - } + // eslint-disable-next-line guard-for-in + for (const normalizedOptions in queue) { + const entries = queue[normalizedOptions]; - for (const item of this.oldCache) { - const [key] = item; - if (!this.cache.has(key)) { - yield item; + // eslint-disable-next-line guard-for-in + for (const normalizedOrigin in entries) { + entries[normalizedOrigin].destroyed = true; } } + + // New requests should NOT attach to destroyed sessions + this.queue = {}; + this.tlsSessionCache.clear(); } - get size() { - let oldCacheSize = 0; - for (const key of this.oldCache.keys()) { - if (!this.cache.has(key)) { - oldCacheSize++; - } - } + get emptySessionCount() { + return this._emptySessionCount; + } - return Math.min(this._size + oldCacheSize, this.maxSize); + get pendingSessionCount() { + return this._sessionCount - this._emptySessionCount; + } + + get sessionCount() { + return this._sessionCount; } } -module.exports = QuickLRU; +Agent.kCurrentStreamCount = kCurrentStreamCount; +Agent.kGracefullyClosing = kGracefullyClosing; + +module.exports = { + Agent, + globalAgent: new Agent() +}; /***/ }), -/***/ 6624: +/***/ 7167: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const tls = __nccwpck_require__(4404); +// See https://github.com/facebook/jest/issues/2549 +// eslint-disable-next-line node/prefer-global/url +const {URL, urlToHttpOptions} = __nccwpck_require__(7310); +const http = __nccwpck_require__(3685); +const https = __nccwpck_require__(5687); +const resolveALPN = __nccwpck_require__(6624); +const QuickLRU = __nccwpck_require__(9273); +const {Agent, globalAgent} = __nccwpck_require__(9898); +const Http2ClientRequest = __nccwpck_require__(9632); +const calculateServerName = __nccwpck_require__(1982); +const delayAsyncDestroy = __nccwpck_require__(9237); -module.exports = (options = {}, connect = tls.connect) => new Promise((resolve, reject) => { - let timeout = false; +const cache = new QuickLRU({maxSize: 100}); +const queue = new Map(); - let socket; +const installSocket = (agent, socket, options) => { + socket._httpMessage = {shouldKeepAlive: true}; - const callback = async () => { - await socketPromise; + const onFree = () => { + agent.emit('free', socket, options); + }; - socket.off('timeout', onTimeout); - socket.off('error', reject); + socket.on('free', onFree); - if (options.resolveSocket) { - resolve({alpnProtocol: socket.alpnProtocol, socket, timeout}); + const onClose = () => { + agent.removeSocket(socket, options); + }; - if (timeout) { - await Promise.resolve(); - socket.emit('timeout'); + socket.on('close', onClose); + + const onTimeout = () => { + const {freeSockets} = agent; + + for (const sockets of Object.values(freeSockets)) { + if (sockets.includes(socket)) { + socket.destroy(); + return; } - } else { - socket.destroy(); - resolve({alpnProtocol: socket.alpnProtocol, timeout}); } }; - const onTimeout = async () => { - timeout = true; - callback(); + socket.on('timeout', onTimeout); + + const onRemove = () => { + agent.removeSocket(socket, options); + socket.off('close', onClose); + socket.off('free', onFree); + socket.off('timeout', onTimeout); + socket.off('agentRemove', onRemove); }; - const socketPromise = (async () => { - try { - socket = await connect(options, callback); + socket.on('agentRemove', onRemove); - socket.on('error', reject); - socket.once('timeout', onTimeout); - } catch (error) { - reject(error); - } - })(); -}); + agent.emit('free', socket, options); +}; + +const createResolveProtocol = (cache, queue = new Map(), connect = undefined) => { + return async options => { + const name = `${options.host}:${options.port}:${options.ALPNProtocols.sort()}`; + if (!cache.has(name)) { + if (queue.has(name)) { + const result = await queue.get(name); + return {alpnProtocol: result.alpnProtocol}; + } -/***/ }), + const {path} = options; + options.path = options.socketPath; -/***/ 4674: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + const resultPromise = resolveALPN(options, connect); + queue.set(name, resultPromise); -"use strict"; + try { + const result = await resultPromise; + cache.set(name, result.alpnProtocol); + queue.delete(name); -// high-level commands -exports.c = exports.create = __nccwpck_require__(4016) -exports.r = exports.replace = __nccwpck_require__(5923) -exports.t = exports.list = __nccwpck_require__(1525) -exports.u = exports.update = __nccwpck_require__(407) -exports.x = exports.extract = __nccwpck_require__(5317) + options.path = path; -// classes -exports.Pack = __nccwpck_require__(7900) -exports.Unpack = __nccwpck_require__(7628) -exports.Parse = __nccwpck_require__(8917) -exports.ReadEntry = __nccwpck_require__(8116) -exports.WriteEntry = __nccwpck_require__(5450) -exports.Header = __nccwpck_require__(6043) -exports.Pax = __nccwpck_require__(7996) -exports.types = __nccwpck_require__(4173) + return result; + } catch (error) { + queue.delete(name); + options.path = path; -/***/ }), + throw error; + } + } -/***/ 4016: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + return {alpnProtocol: cache.get(name)}; + }; +}; -"use strict"; +const defaultResolveProtocol = createResolveProtocol(cache, queue); + +module.exports = async (input, options, callback) => { + if (typeof input === 'string') { + input = urlToHttpOptions(new URL(input)); + } else if (input instanceof URL) { + input = urlToHttpOptions(input); + } else { + input = {...input}; + } + + if (typeof options === 'function' || options === undefined) { + // (options, callback) + callback = options; + options = input; + } else { + // (input, options, callback) + options = Object.assign(input, options); + } + + options.ALPNProtocols = options.ALPNProtocols || ['h2', 'http/1.1']; + + if (!Array.isArray(options.ALPNProtocols) || options.ALPNProtocols.length === 0) { + throw new Error('The `ALPNProtocols` option must be an Array with at least one entry'); + } + + options.protocol = options.protocol || 'https:'; + const isHttps = options.protocol === 'https:'; + options.host = options.hostname || options.host || 'localhost'; + options.session = options.tlsSession; + options.servername = options.servername || calculateServerName((options.headers && options.headers.host) || options.host); + options.port = options.port || (isHttps ? 443 : 80); + options._defaultAgent = isHttps ? https.globalAgent : http.globalAgent; -// tar -c -const hlo = __nccwpck_require__(5213) + const resolveProtocol = options.resolveProtocol || defaultResolveProtocol; -const Pack = __nccwpck_require__(7900) -const fsm = __nccwpck_require__(7714) -const t = __nccwpck_require__(1525) -const path = __nccwpck_require__(1017) + // Note: We don't support `h2session` here -module.exports = (opt_, files, cb) => { - if (typeof files === 'function') { - cb = files - } + let {agent} = options; + if (agent !== undefined && agent !== false && agent.constructor.name !== 'Object') { + throw new Error('The `options.agent` can be only an object `http`, `https` or `http2` properties'); + } - if (Array.isArray(opt_)) { - files = opt_, opt_ = {} - } + if (isHttps) { + options.resolveSocket = true; - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } + let {socket, alpnProtocol, timeout} = await resolveProtocol(options); - files = Array.from(files) + if (timeout) { + if (socket) { + socket.destroy(); + } - const opt = hlo(opt_) + const error = new Error(`Timed out resolving ALPN: ${options.timeout} ms`); + error.code = 'ETIMEDOUT'; + error.ms = options.timeout; - if (opt.sync && typeof cb === 'function') { - throw new TypeError('callback not supported for sync tar functions') - } + throw error; + } - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } + // We can't accept custom `createConnection` because the API is different for HTTP/2 + if (socket && options.createConnection) { + socket.destroy(); + socket = undefined; + } - return opt.file && opt.sync ? createFileSync(opt, files) - : opt.file ? createFile(opt, files, cb) - : opt.sync ? createSync(opt, files) - : create(opt, files) -} + delete options.resolveSocket; -const createFileSync = (opt, files) => { - const p = new Pack.Sync(opt) - const stream = new fsm.WriteStreamSync(opt.file, { - mode: opt.mode || 0o666, - }) - p.pipe(stream) - addFilesSync(p, files) -} + const isHttp2 = alpnProtocol === 'h2'; -const createFile = (opt, files, cb) => { - const p = new Pack(opt) - const stream = new fsm.WriteStream(opt.file, { - mode: opt.mode || 0o666, - }) - p.pipe(stream) + if (agent) { + agent = isHttp2 ? agent.http2 : agent.https; + options.agent = agent; + } - const promise = new Promise((res, rej) => { - stream.on('error', rej) - stream.on('close', res) - p.on('error', rej) - }) + if (agent === undefined) { + agent = isHttp2 ? globalAgent : https.globalAgent; + } - addFilesAsync(p, files) + if (socket) { + if (agent === false) { + socket.destroy(); + } else { + const defaultCreateConnection = (isHttp2 ? Agent : https.Agent).prototype.createConnection; - return cb ? promise.then(cb, cb) : promise -} + if (agent.createConnection === defaultCreateConnection) { + if (isHttp2) { + options._reuseSocket = socket; + } else { + installSocket(agent, socket, options); + } + } else { + socket.destroy(); + } + } + } -const addFilesSync = (p, files) => { - files.forEach(file => { - if (file.charAt(0) === '@') { - t({ - file: path.resolve(p.cwd, file.slice(1)), - sync: true, - noResume: true, - onentry: entry => p.add(entry), - }) - } else { - p.add(file) - } - }) - p.end() -} - -const addFilesAsync = (p, files) => { - while (files.length) { - const file = files.shift() - if (file.charAt(0) === '@') { - return t({ - file: path.resolve(p.cwd, file.slice(1)), - noResume: true, - onentry: entry => p.add(entry), - }).then(_ => addFilesAsync(p, files)) - } else { - p.add(file) - } - } - p.end() -} + if (isHttp2) { + return delayAsyncDestroy(new Http2ClientRequest(options, callback)); + } + } else if (agent) { + options.agent = agent.http; + } -const createSync = (opt, files) => { - const p = new Pack.Sync(opt) - addFilesSync(p, files) - return p -} + return delayAsyncDestroy(http.request(options, callback)); +}; -const create = (opt, files) => { - const p = new Pack(opt) - addFilesAsync(p, files) - return p -} +module.exports.protocolCache = cache; +module.exports.resolveProtocol = defaultResolveProtocol; +module.exports.createResolveProtocol = createResolveProtocol; /***/ }), -/***/ 5317: +/***/ 9632: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; +// See https://github.com/facebook/jest/issues/2549 +// eslint-disable-next-line node/prefer-global/url +const {URL, urlToHttpOptions} = __nccwpck_require__(7310); +const http2 = __nccwpck_require__(5158); +const {Writable} = __nccwpck_require__(2781); +const {Agent, globalAgent} = __nccwpck_require__(9898); +const IncomingMessage = __nccwpck_require__(2575); +const proxyEvents = __nccwpck_require__(1818); +const { + ERR_INVALID_ARG_TYPE, + ERR_INVALID_PROTOCOL, + ERR_HTTP_HEADERS_SENT +} = __nccwpck_require__(7087); +const validateHeaderName = __nccwpck_require__(4592); +const validateHeaderValue = __nccwpck_require__(3549); +const proxySocketHandler = __nccwpck_require__(9404); -// tar -x -const hlo = __nccwpck_require__(5213) -const Unpack = __nccwpck_require__(7628) -const fs = __nccwpck_require__(7147) -const fsm = __nccwpck_require__(7714) -const path = __nccwpck_require__(1017) -const stripSlash = __nccwpck_require__(8886) +const { + HTTP2_HEADER_STATUS, + HTTP2_HEADER_METHOD, + HTTP2_HEADER_PATH, + HTTP2_HEADER_AUTHORITY, + HTTP2_METHOD_CONNECT +} = http2.constants; -module.exports = (opt_, files, cb) => { - if (typeof opt_ === 'function') { - cb = opt_, files = null, opt_ = {} - } else if (Array.isArray(opt_)) { - files = opt_, opt_ = {} - } +const kHeaders = Symbol('headers'); +const kOrigin = Symbol('origin'); +const kSession = Symbol('session'); +const kOptions = Symbol('options'); +const kFlushedHeaders = Symbol('flushedHeaders'); +const kJobs = Symbol('jobs'); +const kPendingAgentPromise = Symbol('pendingAgentPromise'); - if (typeof files === 'function') { - cb = files, files = null - } +class ClientRequest extends Writable { + constructor(input, options, callback) { + super({ + autoDestroy: false, + emitClose: false + }); - if (!files) { - files = [] - } else { - files = Array.from(files) - } + if (typeof input === 'string') { + input = urlToHttpOptions(new URL(input)); + } else if (input instanceof URL) { + input = urlToHttpOptions(input); + } else { + input = {...input}; + } - const opt = hlo(opt_) + if (typeof options === 'function' || options === undefined) { + // (options, callback) + callback = options; + options = input; + } else { + // (input, options, callback) + options = Object.assign(input, options); + } - if (opt.sync && typeof cb === 'function') { - throw new TypeError('callback not supported for sync tar functions') - } + if (options.h2session) { + this[kSession] = options.h2session; - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } + if (this[kSession].destroyed) { + throw new Error('The session has been closed already'); + } - if (files.length) { - filesFilter(opt, files) - } + this.protocol = this[kSession].socket.encrypted ? 'https:' : 'http:'; + } else if (options.agent === false) { + this.agent = new Agent({maxEmptySessions: 0}); + } else if (typeof options.agent === 'undefined' || options.agent === null) { + this.agent = globalAgent; + } else if (typeof options.agent.request === 'function') { + this.agent = options.agent; + } else { + throw new ERR_INVALID_ARG_TYPE('options.agent', ['http2wrapper.Agent-like Object', 'undefined', 'false'], options.agent); + } - return opt.file && opt.sync ? extractFileSync(opt) - : opt.file ? extractFile(opt, cb) - : opt.sync ? extractSync(opt) - : extract(opt) -} + if (this.agent) { + this.protocol = this.agent.protocol; + } + + if (options.protocol && options.protocol !== this.protocol) { + throw new ERR_INVALID_PROTOCOL(options.protocol, this.protocol); + } -// construct a filter that limits the file entries listed -// include child entries if a dir is included -const filesFilter = (opt, files) => { - const map = new Map(files.map(f => [stripSlash(f), true])) - const filter = opt.filter + if (!options.port) { + options.port = options.defaultPort || (this.agent && this.agent.defaultPort) || 443; + } - const mapHas = (file, r) => { - const root = r || path.parse(file).root || '.' - const ret = file === root ? false - : map.has(file) ? map.get(file) - : mapHas(path.dirname(file), root) + options.host = options.hostname || options.host || 'localhost'; - map.set(file, ret) - return ret - } + // Unused + delete options.hostname; - opt.filter = filter - ? (file, entry) => filter(file, entry) && mapHas(stripSlash(file)) - : file => mapHas(stripSlash(file)) -} + const {timeout} = options; + options.timeout = undefined; + + this[kHeaders] = Object.create(null); + this[kJobs] = []; -const extractFileSync = opt => { - const u = new Unpack.Sync(opt) + this[kPendingAgentPromise] = undefined; - const file = opt.file - const stat = fs.statSync(file) - // This trades a zero-byte read() syscall for a stat - // However, it will usually result in less memory allocation - const readSize = opt.maxReadSize || 16 * 1024 * 1024 - const stream = new fsm.ReadStreamSync(file, { - readSize: readSize, - size: stat.size, - }) - stream.pipe(u) -} + this.socket = null; + this.connection = null; -const extractFile = (opt, cb) => { - const u = new Unpack(opt) - const readSize = opt.maxReadSize || 16 * 1024 * 1024 + this.method = options.method || 'GET'; - const file = opt.file - const p = new Promise((resolve, reject) => { - u.on('error', reject) - u.on('close', resolve) + if (!(this.method === 'CONNECT' && (options.path === '/' || options.path === undefined))) { + this.path = options.path; + } - // This trades a zero-byte read() syscall for a stat - // However, it will usually result in less memory allocation - fs.stat(file, (er, stat) => { - if (er) { - reject(er) - } else { - const stream = new fsm.ReadStream(file, { - readSize: readSize, - size: stat.size, - }) - stream.on('error', reject) - stream.pipe(u) - } - }) - }) - return cb ? p.then(cb, cb) : p -} + this.res = null; + this.aborted = false; + this.reusedSocket = false; -const extractSync = opt => new Unpack.Sync(opt) + const {headers} = options; + if (headers) { + // eslint-disable-next-line guard-for-in + for (const header in headers) { + this.setHeader(header, headers[header]); + } + } -const extract = opt => new Unpack(opt) + if (options.auth && !('authorization' in this[kHeaders])) { + this[kHeaders].authorization = 'Basic ' + Buffer.from(options.auth).toString('base64'); + } + options.session = options.tlsSession; + options.path = options.socketPath; -/***/ }), + this[kOptions] = options; -/***/ 1172: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // Clients that generate HTTP/2 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field. + this[kOrigin] = new URL(`${this.protocol}//${options.servername || options.host}:${options.port}`); + + // A socket is being reused + const reuseSocket = options._reuseSocket; + if (reuseSocket) { + options.createConnection = (...args) => { + if (reuseSocket.destroyed) { + return this.agent.createConnection(...args); + } -// Get the appropriate flag to use for creating files -// We use fmap on Windows platforms for files less than -// 512kb. This is a fairly low limit, but avoids making -// things slower in some cases. Since most of what this -// library is used for is extracting tarballs of many -// relatively small files in npm packages and the like, -// it can be a big boost on Windows platforms. -// Only supported in Node v12.9.0 and above. -const platform = process.env.__FAKE_PLATFORM__ || process.platform -const isWindows = platform === 'win32' -const fs = global.__FAKE_TESTING_FS__ || __nccwpck_require__(7147) + return reuseSocket; + }; -/* istanbul ignore next */ -const { O_CREAT, O_TRUNC, O_WRONLY, UV_FS_O_FILEMAP = 0 } = fs.constants + // eslint-disable-next-line promise/prefer-await-to-then + this.agent.getSession(this[kOrigin], this[kOptions]).catch(() => {}); + } -const fMapEnabled = isWindows && !!UV_FS_O_FILEMAP -const fMapLimit = 512 * 1024 -const fMapFlag = UV_FS_O_FILEMAP | O_TRUNC | O_CREAT | O_WRONLY -module.exports = !fMapEnabled ? () => 'w' - : size => size < fMapLimit ? fMapFlag : 'w' + if (timeout) { + this.setTimeout(timeout); + } + if (callback) { + this.once('response', callback); + } -/***/ }), + this[kFlushedHeaders] = false; + } -/***/ 6043: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + get method() { + return this[kHeaders][HTTP2_HEADER_METHOD]; + } -"use strict"; + set method(value) { + if (value) { + this[kHeaders][HTTP2_HEADER_METHOD] = value.toUpperCase(); + } + } -// parse a 512-byte header block to a data object, or vice-versa -// encode returns `true` if a pax extended header is needed, because -// the data could not be faithfully encoded in a simple header. -// (Also, check header.needPax to see if it needs a pax header.) - -const types = __nccwpck_require__(4173) -const pathModule = (__nccwpck_require__(1017).posix) -const large = __nccwpck_require__(2370) - -const SLURP = Symbol('slurp') -const TYPE = Symbol('type') - -class Header { - constructor (data, off, ex, gex) { - this.cksumValid = false - this.needPax = false - this.nullBlock = false - - this.block = null - this.path = null - this.mode = null - this.uid = null - this.gid = null - this.size = null - this.mtime = null - this.cksum = null - this[TYPE] = '0' - this.linkpath = null - this.uname = null - this.gname = null - this.devmaj = 0 - this.devmin = 0 - this.atime = null - this.ctime = null - - if (Buffer.isBuffer(data)) { - this.decode(data, off || 0, ex, gex) - } else if (data) { - this.set(data) - } - } + get path() { + const header = this.method === 'CONNECT' ? HTTP2_HEADER_AUTHORITY : HTTP2_HEADER_PATH; - decode (buf, off, ex, gex) { - if (!off) { - off = 0 - } + return this[kHeaders][header]; + } - if (!buf || !(buf.length >= off + 512)) { - throw new Error('need 512 bytes for header') - } + set path(value) { + if (value) { + const header = this.method === 'CONNECT' ? HTTP2_HEADER_AUTHORITY : HTTP2_HEADER_PATH; - this.path = decString(buf, off, 100) - this.mode = decNumber(buf, off + 100, 8) - this.uid = decNumber(buf, off + 108, 8) - this.gid = decNumber(buf, off + 116, 8) - this.size = decNumber(buf, off + 124, 12) - this.mtime = decDate(buf, off + 136, 12) - this.cksum = decNumber(buf, off + 148, 12) + this[kHeaders][header] = value; + } + } - // if we have extended or global extended headers, apply them now - // See https://github.com/npm/node-tar/pull/187 - this[SLURP](ex) - this[SLURP](gex, true) + get host() { + return this[kOrigin].hostname; + } - // old tar versions marked dirs as a file with a trailing / - this[TYPE] = decString(buf, off + 156, 1) - if (this[TYPE] === '') { - this[TYPE] = '0' - } - if (this[TYPE] === '0' && this.path.slice(-1) === '/') { - this[TYPE] = '5' - } + set host(_value) { + // Do nothing as this is read only. + } - // tar implementations sometimes incorrectly put the stat(dir).size - // as the size in the tarball, even though Directory entries are - // not able to have any body at all. In the very rare chance that - // it actually DOES have a body, we weren't going to do anything with - // it anyway, and it'll just be a warning about an invalid header. - if (this[TYPE] === '5') { - this.size = 0 - } + get _mustNotHaveABody() { + return this.method === 'GET' || this.method === 'HEAD' || this.method === 'DELETE'; + } - this.linkpath = decString(buf, off + 157, 100) - if (buf.slice(off + 257, off + 265).toString() === 'ustar\u000000') { - this.uname = decString(buf, off + 265, 32) - this.gname = decString(buf, off + 297, 32) - this.devmaj = decNumber(buf, off + 329, 8) - this.devmin = decNumber(buf, off + 337, 8) - if (buf[off + 475] !== 0) { - // definitely a prefix, definitely >130 chars. - const prefix = decString(buf, off + 345, 155) - this.path = prefix + '/' + this.path - } else { - const prefix = decString(buf, off + 345, 130) - if (prefix) { - this.path = prefix + '/' + this.path - } - this.atime = decDate(buf, off + 476, 12) - this.ctime = decDate(buf, off + 488, 12) - } - } + _write(chunk, encoding, callback) { + // https://github.com/nodejs/node/blob/654df09ae0c5e17d1b52a900a545f0664d8c7627/lib/internal/http2/util.js#L148-L156 + if (this._mustNotHaveABody) { + callback(new Error('The GET, HEAD and DELETE methods must NOT have a body')); + /* istanbul ignore next: Node.js 12 throws directly */ + return; + } - let sum = 8 * 0x20 - for (let i = off; i < off + 148; i++) { - sum += buf[i] - } + this.flushHeaders(); - for (let i = off + 156; i < off + 512; i++) { - sum += buf[i] - } + const callWrite = () => this._request.write(chunk, encoding, callback); + if (this._request) { + callWrite(); + } else { + this[kJobs].push(callWrite); + } + } - this.cksumValid = sum === this.cksum - if (this.cksum === null && sum === 8 * 0x20) { - this.nullBlock = true - } - } + _final(callback) { + this.flushHeaders(); - [SLURP] (ex, global) { - for (const k in ex) { - // we slurp in everything except for the path attribute in - // a global extended header, because that's weird. - if (ex[k] !== null && ex[k] !== undefined && - !(global && k === 'path')) { - this[k] = ex[k] - } - } - } + const callEnd = () => { + // For GET, HEAD and DELETE and CONNECT + if (this._mustNotHaveABody || this.method === 'CONNECT') { + callback(); + return; + } - encode (buf, off) { - if (!buf) { - buf = this.block = Buffer.alloc(512) - off = 0 - } - - if (!off) { - off = 0 - } - - if (!(buf.length >= off + 512)) { - throw new Error('need 512 bytes for header') - } - - const prefixSize = this.ctime || this.atime ? 130 : 155 - const split = splitPrefix(this.path || '', prefixSize) - const path = split[0] - const prefix = split[1] - this.needPax = split[2] - - this.needPax = encString(buf, off, 100, path) || this.needPax - this.needPax = encNumber(buf, off + 100, 8, this.mode) || this.needPax - this.needPax = encNumber(buf, off + 108, 8, this.uid) || this.needPax - this.needPax = encNumber(buf, off + 116, 8, this.gid) || this.needPax - this.needPax = encNumber(buf, off + 124, 12, this.size) || this.needPax - this.needPax = encDate(buf, off + 136, 12, this.mtime) || this.needPax - buf[off + 156] = this[TYPE].charCodeAt(0) - this.needPax = encString(buf, off + 157, 100, this.linkpath) || this.needPax - buf.write('ustar\u000000', off + 257, 8) - this.needPax = encString(buf, off + 265, 32, this.uname) || this.needPax - this.needPax = encString(buf, off + 297, 32, this.gname) || this.needPax - this.needPax = encNumber(buf, off + 329, 8, this.devmaj) || this.needPax - this.needPax = encNumber(buf, off + 337, 8, this.devmin) || this.needPax - this.needPax = encString(buf, off + 345, prefixSize, prefix) || this.needPax - if (buf[off + 475] !== 0) { - this.needPax = encString(buf, off + 345, 155, prefix) || this.needPax - } else { - this.needPax = encString(buf, off + 345, 130, prefix) || this.needPax - this.needPax = encDate(buf, off + 476, 12, this.atime) || this.needPax - this.needPax = encDate(buf, off + 488, 12, this.ctime) || this.needPax - } + this._request.end(callback); + }; - let sum = 8 * 0x20 - for (let i = off; i < off + 148; i++) { - sum += buf[i] - } + if (this._request) { + callEnd(); + } else { + this[kJobs].push(callEnd); + } + } - for (let i = off + 156; i < off + 512; i++) { - sum += buf[i] - } + abort() { + if (this.res && this.res.complete) { + return; + } - this.cksum = sum - encNumber(buf, off + 148, 8, this.cksum) - this.cksumValid = true + if (!this.aborted) { + process.nextTick(() => this.emit('abort')); + } - return this.needPax - } + this.aborted = true; - set (data) { - for (const i in data) { - if (data[i] !== null && data[i] !== undefined) { - this[i] = data[i] - } - } - } + this.destroy(); + } - get type () { - return types.name.get(this[TYPE]) || this[TYPE] - } + async _destroy(error, callback) { + if (this.res) { + this.res._dump(); + } - get typeKey () { - return this[TYPE] - } + if (this._request) { + this._request.destroy(); + } else { + process.nextTick(() => { + this.emit('close'); + }); + } - set type (type) { - if (types.code.has(type)) { - this[TYPE] = types.code.get(type) - } else { - this[TYPE] = type - } - } -} + try { + await this[kPendingAgentPromise]; + } catch (internalError) { + if (this.aborted) { + error = internalError; + } + } -const splitPrefix = (p, prefixSize) => { - const pathSize = 100 - let pp = p - let prefix = '' - let ret - const root = pathModule.parse(p).root || '.' + callback(error); + } - if (Buffer.byteLength(pp) < pathSize) { - ret = [pp, prefix, false] - } else { - // first set prefix to the dir, and path to the base - prefix = pathModule.dirname(pp) - pp = pathModule.basename(pp) - - do { - if (Buffer.byteLength(pp) <= pathSize && - Buffer.byteLength(prefix) <= prefixSize) { - // both fit! - ret = [pp, prefix, false] - } else if (Buffer.byteLength(pp) > pathSize && - Buffer.byteLength(prefix) <= prefixSize) { - // prefix fits in prefix, but path doesn't fit in path - ret = [pp.slice(0, pathSize - 1), prefix, true] - } else { - // make path take a bit from prefix - pp = pathModule.join(pathModule.basename(prefix), pp) - prefix = pathModule.dirname(prefix) - } - } while (prefix !== root && !ret) + async flushHeaders() { + if (this[kFlushedHeaders] || this.destroyed) { + return; + } - // at this point, found no resolution, just truncate - if (!ret) { - ret = [p.slice(0, pathSize - 1), '', true] - } - } - return ret -} + this[kFlushedHeaders] = true; -const decString = (buf, off, size) => - buf.slice(off, off + size).toString('utf8').replace(/\0.*/, '') + const isConnectMethod = this.method === HTTP2_METHOD_CONNECT; -const decDate = (buf, off, size) => - numToDate(decNumber(buf, off, size)) + // The real magic is here + const onStream = stream => { + this._request = stream; -const numToDate = num => num === null ? null : new Date(num * 1000) + if (this.destroyed) { + stream.destroy(); + return; + } -const decNumber = (buf, off, size) => - buf[off] & 0x80 ? large.parse(buf.slice(off, off + size)) - : decSmallNumber(buf, off, size) + // Forwards `timeout`, `continue`, `close` and `error` events to this instance. + if (!isConnectMethod) { + // TODO: Should we proxy `close` here? + proxyEvents(stream, this, ['timeout', 'continue']); + } -const nanNull = value => isNaN(value) ? null : value + stream.once('error', error => { + this.destroy(error); + }); -const decSmallNumber = (buf, off, size) => - nanNull(parseInt( - buf.slice(off, off + size) - .toString('utf8').replace(/\0.*$/, '').trim(), 8)) + stream.once('aborted', () => { + const {res} = this; + if (res) { + res.aborted = true; + res.emit('aborted'); + res.destroy(); + } else { + this.destroy(new Error('The server aborted the HTTP/2 stream')); + } + }); -// the maximum encodable as a null-terminated octal, by field size -const MAXNUM = { - 12: 0o77777777777, - 8: 0o7777777, -} + const onResponse = (headers, flags, rawHeaders) => { + // If we were to emit raw request stream, it would be as fast as the native approach. + // Note that wrapping the raw stream in a Proxy instance won't improve the performance (already tested it). + const response = new IncomingMessage(this.socket, stream.readableHighWaterMark); + this.res = response; -const encNumber = (buf, off, size, number) => - number === null ? false : - number > MAXNUM[size] || number < 0 - ? (large.encode(number, buf.slice(off, off + size)), true) - : (encSmallNumber(buf, off, size, number), false) + // Undocumented, but it is used by `cacheable-request` + response.url = `${this[kOrigin].origin}${this.path}`; -const encSmallNumber = (buf, off, size, number) => - buf.write(octalString(number, size), off, size, 'ascii') + response.req = this; + response.statusCode = headers[HTTP2_HEADER_STATUS]; + response.headers = headers; + response.rawHeaders = rawHeaders; -const octalString = (number, size) => - padOctal(Math.floor(number).toString(8), size) + response.once('end', () => { + response.complete = true; -const padOctal = (string, size) => - (string.length === size - 1 ? string - : new Array(size - string.length - 1).join('0') + string + ' ') + '\0' + // Has no effect, just be consistent with the Node.js behavior + response.socket = null; + response.connection = null; + }); -const encDate = (buf, off, size, date) => - date === null ? false : - encNumber(buf, off, size, date.getTime() / 1000) + if (isConnectMethod) { + response.upgrade = true; -// enough to fill the longest string we've got -const NULLS = new Array(156).join('\0') -// pad with nulls, return true if it's longer or non-ascii -const encString = (buf, off, size, string) => - string === null ? false : - (buf.write(string + NULLS, off, size, 'utf8'), - string.length !== Buffer.byteLength(string) || string.length > size) + // The HTTP1 API says the socket is detached here, + // but we can't do that so we pass the original HTTP2 request. + if (this.emit('connect', response, stream, Buffer.alloc(0))) { + this.emit('close'); + } else { + // No listeners attached, destroy the original request. + stream.destroy(); + } + } else { + // Forwards data + stream.on('data', chunk => { + if (!response._dumped && !response.push(chunk)) { + stream.pause(); + } + }); -module.exports = Header + stream.once('end', () => { + if (!this.aborted) { + response.push(null); + } + }); + if (!this.emit('response', response)) { + // No listeners attached, dump the response. + response._dump(); + } + } + }; -/***/ }), + // This event tells we are ready to listen for the data. + stream.once('response', onResponse); -/***/ 5213: -/***/ ((module) => { + // Emits `information` event + stream.once('headers', headers => this.emit('information', {statusCode: headers[HTTP2_HEADER_STATUS]})); -"use strict"; + stream.once('trailers', (trailers, flags, rawTrailers) => { + const {res} = this; + // https://github.com/nodejs/node/issues/41251 + if (res === null) { + onResponse(trailers, flags, rawTrailers); + return; + } -// turn tar(1) style args like `C` into the more verbose things like `cwd` - -const argmap = new Map([ - ['C', 'cwd'], - ['f', 'file'], - ['z', 'gzip'], - ['P', 'preservePaths'], - ['U', 'unlink'], - ['strip-components', 'strip'], - ['stripComponents', 'strip'], - ['keep-newer', 'newer'], - ['keepNewer', 'newer'], - ['keep-newer-files', 'newer'], - ['keepNewerFiles', 'newer'], - ['k', 'keep'], - ['keep-existing', 'keep'], - ['keepExisting', 'keep'], - ['m', 'noMtime'], - ['no-mtime', 'noMtime'], - ['p', 'preserveOwner'], - ['L', 'follow'], - ['h', 'follow'], -]) - -module.exports = opt => opt ? Object.keys(opt).map(k => [ - argmap.has(k) ? argmap.get(k) : k, opt[k], -]).reduce((set, kv) => (set[kv[0]] = kv[1], set), Object.create(null)) : {} + // Assigns trailers to the response object. + res.trailers = trailers; + res.rawTrailers = rawTrailers; + }); + stream.once('close', () => { + const {aborted, res} = this; + if (res) { + if (aborted) { + res.aborted = true; + res.emit('aborted'); + res.destroy(); + } -/***/ }), + const finish = () => { + res.emit('close'); -/***/ 2370: -/***/ ((module) => { + this.destroy(); + this.emit('close'); + }; -"use strict"; + if (res.readable) { + res.once('end', finish); + } else { + finish(); + } -// Tar can encode large and negative numbers using a leading byte of -// 0xff for negative, and 0x80 for positive. + return; + } -const encode = (num, buf) => { - if (!Number.isSafeInteger(num)) { - // The number is so large that javascript cannot represent it with integer - // precision. - throw Error('cannot encode number outside of javascript safe integer range') - } else if (num < 0) { - encodeNegative(num, buf) - } else { - encodePositive(num, buf) - } - return buf -} + if (!this.destroyed) { + this.destroy(new Error('The HTTP/2 stream has been early terminated')); + this.emit('close'); + return; + } -const encodePositive = (num, buf) => { - buf[0] = 0x80 + this.destroy(); + this.emit('close'); + }); - for (var i = buf.length; i > 1; i--) { - buf[i - 1] = num & 0xff - num = Math.floor(num / 0x100) - } -} + this.socket = new Proxy(stream, proxySocketHandler); -const encodeNegative = (num, buf) => { - buf[0] = 0xff - var flipped = false - num = num * -1 - for (var i = buf.length; i > 1; i--) { - var byte = num & 0xff - num = Math.floor(num / 0x100) - if (flipped) { - buf[i - 1] = onesComp(byte) - } else if (byte === 0) { - buf[i - 1] = 0 - } else { - flipped = true - buf[i - 1] = twosComp(byte) - } - } -} + for (const job of this[kJobs]) { + job(); + } -const parse = (buf) => { - const pre = buf[0] - const value = pre === 0x80 ? pos(buf.slice(1, buf.length)) - : pre === 0xff ? twos(buf) - : null - if (value === null) { - throw Error('invalid base256 encoding') - } + this[kJobs].length = 0; - if (!Number.isSafeInteger(value)) { - // The number is so large that javascript cannot represent it with integer - // precision. - throw Error('parsed number outside of javascript safe integer range') - } + this.emit('socket', this.socket); + }; - return value -} + if (!(HTTP2_HEADER_AUTHORITY in this[kHeaders]) && !isConnectMethod) { + this[kHeaders][HTTP2_HEADER_AUTHORITY] = this[kOrigin].host; + } -const twos = (buf) => { - var len = buf.length - var sum = 0 - var flipped = false - for (var i = len - 1; i > -1; i--) { - var byte = buf[i] - var f - if (flipped) { - f = onesComp(byte) - } else if (byte === 0) { - f = byte - } else { - flipped = true - f = twosComp(byte) - } - if (f !== 0) { - sum -= f * Math.pow(256, len - i - 1) - } - } - return sum -} + // Makes a HTTP2 request + if (this[kSession]) { + try { + onStream(this[kSession].request(this[kHeaders])); + } catch (error) { + this.destroy(error); + } + } else { + this.reusedSocket = true; -const pos = (buf) => { - var len = buf.length - var sum = 0 - for (var i = len - 1; i > -1; i--) { - var byte = buf[i] - if (byte !== 0) { - sum += byte * Math.pow(256, len - i - 1) - } - } - return sum -} + try { + const promise = this.agent.request(this[kOrigin], this[kOptions], this[kHeaders]); + this[kPendingAgentPromise] = promise; -const onesComp = byte => (0xff ^ byte) & 0xff + onStream(await promise); -const twosComp = byte => ((0xff ^ byte) + 1) & 0xff + this[kPendingAgentPromise] = false; + } catch (error) { + this[kPendingAgentPromise] = false; -module.exports = { - encode, - parse, -} + this.destroy(error); + } + } + } + get connection() { + return this.socket; + } -/***/ }), + set connection(value) { + this.socket = value; + } -/***/ 1525: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + getHeaderNames() { + return Object.keys(this[kHeaders]); + } -"use strict"; + hasHeader(name) { + if (typeof name !== 'string') { + throw new ERR_INVALID_ARG_TYPE('name', 'string', name); + } + return Boolean(this[kHeaders][name.toLowerCase()]); + } -// XXX: This shares a lot in common with extract.js -// maybe some DRY opportunity here? + getHeader(name) { + if (typeof name !== 'string') { + throw new ERR_INVALID_ARG_TYPE('name', 'string', name); + } -// tar -t -const hlo = __nccwpck_require__(5213) -const Parser = __nccwpck_require__(8917) -const fs = __nccwpck_require__(7147) -const fsm = __nccwpck_require__(7714) -const path = __nccwpck_require__(1017) -const stripSlash = __nccwpck_require__(8886) + return this[kHeaders][name.toLowerCase()]; + } -module.exports = (opt_, files, cb) => { - if (typeof opt_ === 'function') { - cb = opt_, files = null, opt_ = {} - } else if (Array.isArray(opt_)) { - files = opt_, opt_ = {} - } + get headersSent() { + return this[kFlushedHeaders]; + } - if (typeof files === 'function') { - cb = files, files = null - } + removeHeader(name) { + if (typeof name !== 'string') { + throw new ERR_INVALID_ARG_TYPE('name', 'string', name); + } - if (!files) { - files = [] - } else { - files = Array.from(files) - } + if (this.headersSent) { + throw new ERR_HTTP_HEADERS_SENT('remove'); + } - const opt = hlo(opt_) + delete this[kHeaders][name.toLowerCase()]; + } - if (opt.sync && typeof cb === 'function') { - throw new TypeError('callback not supported for sync tar functions') - } + setHeader(name, value) { + if (this.headersSent) { + throw new ERR_HTTP_HEADERS_SENT('set'); + } - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } + validateHeaderName(name); + validateHeaderValue(name, value); - if (files.length) { - filesFilter(opt, files) - } + const lowercased = name.toLowerCase(); - if (!opt.noResume) { - onentryFunction(opt) - } + if (lowercased === 'connection') { + if (value.toLowerCase() === 'keep-alive') { + return; + } - return opt.file && opt.sync ? listFileSync(opt) - : opt.file ? listFile(opt, cb) - : list(opt) -} + throw new Error(`Invalid 'connection' header: ${value}`); + } -const onentryFunction = opt => { - const onentry = opt.onentry - opt.onentry = onentry ? e => { - onentry(e) - e.resume() - } : e => e.resume() -} + if (lowercased === 'host' && this.method === 'CONNECT') { + this[kHeaders][HTTP2_HEADER_AUTHORITY] = value; + } else { + this[kHeaders][lowercased] = value; + } + } -// construct a filter that limits the file entries listed -// include child entries if a dir is included -const filesFilter = (opt, files) => { - const map = new Map(files.map(f => [stripSlash(f), true])) - const filter = opt.filter + setNoDelay() { + // HTTP2 sockets cannot be malformed, do nothing. + } - const mapHas = (file, r) => { - const root = r || path.parse(file).root || '.' - const ret = file === root ? false - : map.has(file) ? map.get(file) - : mapHas(path.dirname(file), root) + setSocketKeepAlive() { + // HTTP2 sockets cannot be malformed, do nothing. + } - map.set(file, ret) - return ret - } + setTimeout(ms, callback) { + const applyTimeout = () => this._request.setTimeout(ms, callback); - opt.filter = filter - ? (file, entry) => filter(file, entry) && mapHas(stripSlash(file)) - : file => mapHas(stripSlash(file)) -} + if (this._request) { + applyTimeout(); + } else { + this[kJobs].push(applyTimeout); + } -const listFileSync = opt => { - const p = list(opt) - const file = opt.file - let threw = true - let fd - try { - const stat = fs.statSync(file) - const readSize = opt.maxReadSize || 16 * 1024 * 1024 - if (stat.size < readSize) { - p.end(fs.readFileSync(file)) - } else { - let pos = 0 - const buf = Buffer.allocUnsafe(readSize) - fd = fs.openSync(file, 'r') - while (pos < stat.size) { - const bytesRead = fs.readSync(fd, buf, 0, readSize, pos) - pos += bytesRead - p.write(buf.slice(0, bytesRead)) - } - p.end() - } - threw = false - } finally { - if (threw && fd) { - try { - fs.closeSync(fd) - } catch (er) {} - } - } -} + return this; + } -const listFile = (opt, cb) => { - const parse = new Parser(opt) - const readSize = opt.maxReadSize || 16 * 1024 * 1024 + get maxHeadersCount() { + if (!this.destroyed && this._request) { + return this._request.session.localSettings.maxHeaderListSize; + } - const file = opt.file - const p = new Promise((resolve, reject) => { - parse.on('error', reject) - parse.on('end', resolve) + return undefined; + } - fs.stat(file, (er, stat) => { - if (er) { - reject(er) - } else { - const stream = new fsm.ReadStream(file, { - readSize: readSize, - size: stat.size, - }) - stream.on('error', reject) - stream.pipe(parse) - } - }) - }) - return cb ? p.then(cb, cb) : p + set maxHeadersCount(_value) { + // Updating HTTP2 settings would affect all requests, do nothing. + } } -const list = opt => new Parser(opt) +module.exports = ClientRequest; /***/ }), -/***/ 9624: +/***/ 2575: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -// wrapper around mkdirp for tar's needs. - -// TODO: This should probably be a class, not functionally -// passing around state in a gazillion args. - -const mkdirp = __nccwpck_require__(6186) -const fs = __nccwpck_require__(7147) -const path = __nccwpck_require__(1017) -const chownr = __nccwpck_require__(9051) -const normPath = __nccwpck_require__(6843) - -class SymlinkError extends Error { - constructor (symlink, path) { - super('Cannot extract through symbolic link') - this.path = path - this.symlink = symlink - } - - get name () { - return 'SylinkError' - } -} +const {Readable} = __nccwpck_require__(2781); -class CwdError extends Error { - constructor (path, code) { - super(code + ': Cannot cd into \'' + path + '\'') - this.path = path - this.code = code - } +class IncomingMessage extends Readable { + constructor(socket, highWaterMark) { + super({ + emitClose: false, + autoDestroy: true, + highWaterMark + }); - get name () { - return 'CwdError' - } -} + this.statusCode = null; + this.statusMessage = ''; + this.httpVersion = '2.0'; + this.httpVersionMajor = 2; + this.httpVersionMinor = 0; + this.headers = {}; + this.trailers = {}; + this.req = null; -const cGet = (cache, key) => cache.get(normPath(key)) -const cSet = (cache, key, val) => cache.set(normPath(key), val) + this.aborted = false; + this.complete = false; + this.upgrade = null; -const checkCwd = (dir, cb) => { - fs.stat(dir, (er, st) => { - if (er || !st.isDirectory()) { - er = new CwdError(dir, er && er.code || 'ENOTDIR') - } - cb(er) - }) -} + this.rawHeaders = []; + this.rawTrailers = []; -module.exports = (dir, opt, cb) => { - dir = normPath(dir) + this.socket = socket; - // if there's any overlap between mask and mode, - // then we'll need an explicit chmod - const umask = opt.umask - const mode = opt.mode | 0o0700 - const needChmod = (mode & umask) !== 0 + this._dumped = false; + } - const uid = opt.uid - const gid = opt.gid - const doChown = typeof uid === 'number' && - typeof gid === 'number' && - (uid !== opt.processUid || gid !== opt.processGid) + get connection() { + return this.socket; + } - const preserve = opt.preserve - const unlink = opt.unlink - const cache = opt.cache - const cwd = normPath(opt.cwd) + set connection(value) { + this.socket = value; + } - const done = (er, created) => { - if (er) { - cb(er) - } else { - cSet(cache, dir, true) - if (created && doChown) { - chownr(created, uid, gid, er => done(er)) - } else if (needChmod) { - fs.chmod(dir, mode, cb) - } else { - cb() - } - } - } + _destroy(error, callback) { + if (!this.readableEnded) { + this.aborted = true; + } - if (cache && cGet(cache, dir) === true) { - return done() - } + // See https://github.com/nodejs/node/issues/35303 + callback(); - if (dir === cwd) { - return checkCwd(dir, done) - } + this.req._request.destroy(error); + } - if (preserve) { - return mkdirp(dir, { mode }).then(made => done(null, made), done) - } + setTimeout(ms, callback) { + this.req.setTimeout(ms, callback); + return this; + } - const sub = normPath(path.relative(cwd, dir)) - const parts = sub.split('/') - mkdir_(cwd, parts, mode, cache, unlink, cwd, null, done) -} + _dump() { + if (!this._dumped) { + this._dumped = true; -const mkdir_ = (base, parts, mode, cache, unlink, cwd, created, cb) => { - if (!parts.length) { - return cb(null, created) - } - const p = parts.shift() - const part = normPath(path.resolve(base + '/' + p)) - if (cGet(cache, part)) { - return mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) - } - fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb)) -} - -const onmkdir = (part, parts, mode, cache, unlink, cwd, created, cb) => er => { - if (er) { - fs.lstat(part, (statEr, st) => { - if (statEr) { - statEr.path = statEr.path && normPath(statEr.path) - cb(statEr) - } else if (st.isDirectory()) { - mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) - } else if (unlink) { - fs.unlink(part, er => { - if (er) { - return cb(er) - } - fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb)) - }) - } else if (st.isSymbolicLink()) { - return cb(new SymlinkError(part, part + '/' + parts.join('/'))) - } else { - cb(er) - } - }) - } else { - created = created || part - mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) - } -} + this.removeAllListeners('data'); + this.resume(); + } + } -const checkCwdSync = dir => { - let ok = false - let code = 'ENOTDIR' - try { - ok = fs.statSync(dir).isDirectory() - } catch (er) { - code = er.code - } finally { - if (!ok) { - throw new CwdError(dir, code) - } - } + _read() { + if (this.req) { + this.req._request.resume(); + } + } } -module.exports.sync = (dir, opt) => { - dir = normPath(dir) - // if there's any overlap between mask and mode, - // then we'll need an explicit chmod - const umask = opt.umask - const mode = opt.mode | 0o0700 - const needChmod = (mode & umask) !== 0 +module.exports = IncomingMessage; - const uid = opt.uid - const gid = opt.gid - const doChown = typeof uid === 'number' && - typeof gid === 'number' && - (uid !== opt.processUid || gid !== opt.processGid) - const preserve = opt.preserve - const unlink = opt.unlink - const cache = opt.cache - const cwd = normPath(opt.cwd) +/***/ }), - const done = (created) => { - cSet(cache, dir, true) - if (created && doChown) { - chownr.sync(created, uid, gid) - } - if (needChmod) { - fs.chmodSync(dir, mode) - } - } +/***/ 4645: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (cache && cGet(cache, dir) === true) { - return done() - } +"use strict"; - if (dir === cwd) { - checkCwdSync(cwd) - return done() - } +const http2 = __nccwpck_require__(5158); +const { + Agent, + globalAgent +} = __nccwpck_require__(9898); +const ClientRequest = __nccwpck_require__(9632); +const IncomingMessage = __nccwpck_require__(2575); +const auto = __nccwpck_require__(7167); +const { + HttpOverHttp2, + HttpsOverHttp2 +} = __nccwpck_require__(8795); +const Http2OverHttp2 = __nccwpck_require__(8553); +const { + Http2OverHttp, + Http2OverHttps +} = __nccwpck_require__(9794); +const validateHeaderName = __nccwpck_require__(4592); +const validateHeaderValue = __nccwpck_require__(3549); - if (preserve) { - return done(mkdirp.sync(dir, mode)) - } +const request = (url, options, callback) => new ClientRequest(url, options, callback); - const sub = normPath(path.relative(cwd, dir)) - const parts = sub.split('/') - let created = null - for (let p = parts.shift(), part = cwd; - p && (part += '/' + p); - p = parts.shift()) { - part = normPath(path.resolve(part)) - if (cGet(cache, part)) { - continue - } +const get = (url, options, callback) => { + // eslint-disable-next-line unicorn/prevent-abbreviations + const req = new ClientRequest(url, options, callback); + req.end(); - try { - fs.mkdirSync(part, mode) - created = created || part - cSet(cache, part, true) - } catch (er) { - const st = fs.lstatSync(part) - if (st.isDirectory()) { - cSet(cache, part, true) - continue - } else if (unlink) { - fs.unlinkSync(part) - fs.mkdirSync(part, mode) - created = created || part - cSet(cache, part, true) - continue - } else if (st.isSymbolicLink()) { - return new SymlinkError(part, part + '/' + parts.join('/')) - } - } - } + return req; +}; - return done(created) -} +module.exports = { + ...http2, + ClientRequest, + IncomingMessage, + Agent, + globalAgent, + request, + get, + auto, + proxies: { + HttpOverHttp2, + HttpsOverHttp2, + Http2OverHttp2, + Http2OverHttp, + Http2OverHttps + }, + validateHeaderName, + validateHeaderValue +}; /***/ }), -/***/ 8371: +/***/ 7885: /***/ ((module) => { "use strict"; -module.exports = (mode, isDir, portable) => { - mode &= 0o7777 - - // in portable mode, use the minimum reasonable umask - // if this system creates files with 0o664 by default - // (as some linux distros do), then we'll write the - // archive with 0o644 instead. Also, don't ever create - // a file that is not readable/writable by the owner. - if (portable) { - mode = (mode | 0o600) & ~0o22 - } - - // if dirs are readable, then they should be listable - if (isDir) { - if (mode & 0o400) { - mode |= 0o100 - } - if (mode & 0o40) { - mode |= 0o10 - } - if (mode & 0o4) { - mode |= 0o1 - } - } - return mode -} +module.exports = self => { + const {username, password} = self.proxyOptions.url; -/***/ }), + if (username || password) { + const data = `${username}:${password}`; + const authorization = `Basic ${Buffer.from(data).toString('base64')}`; -/***/ 7118: -/***/ ((module) => { + return { + 'proxy-authorization': authorization, + authorization + }; + } -// warning: extremely hot code path. -// This has been meticulously optimized for use -// within npm install on large package trees. -// Do not edit without careful benchmarking. -const normalizeCache = Object.create(null) -const { hasOwnProperty } = Object.prototype -module.exports = s => { - if (!hasOwnProperty.call(normalizeCache, s)) { - normalizeCache[s] = s.normalize('NFD') - } - return normalizeCache[s] -} + return {}; +}; /***/ }), -/***/ 6843: -/***/ ((module) => { +/***/ 8795: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -// on windows, either \ or / are valid directory separators. -// on unix, \ is a valid character in filenames. -// so, on windows, and only on windows, we replace all \ chars with /, -// so that we can use / as our one and only directory separator char. +"use strict"; -const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform -module.exports = platform !== 'win32' ? p => p - : p => p && p.replace(/\\/g, '/') +const tls = __nccwpck_require__(4404); +const http = __nccwpck_require__(3685); +const https = __nccwpck_require__(5687); +const JSStreamSocket = __nccwpck_require__(1564); +const {globalAgent} = __nccwpck_require__(9898); +const UnexpectedStatusCodeError = __nccwpck_require__(6203); +const initialize = __nccwpck_require__(1089); +const getAuthorizationHeaders = __nccwpck_require__(7885); +const createConnection = (self, options, callback) => { + (async () => { + try { + const {proxyOptions} = self; + const {url, headers, raw} = proxyOptions; -/***/ }), + const stream = await globalAgent.request(url, proxyOptions, { + ...getAuthorizationHeaders(self), + ...headers, + ':method': 'CONNECT', + ':authority': `${options.host}:${options.port}` + }); -/***/ 7900: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + stream.once('error', callback); + stream.once('response', headers => { + const statusCode = headers[':status']; -"use strict"; + if (statusCode !== 200) { + callback(new UnexpectedStatusCodeError(statusCode, '')); + return; + } + const encrypted = self instanceof https.Agent; -// A readable tar stream creator -// Technically, this is a transform stream that you write paths into, -// and tar format comes out of. -// The `add()` method is like `write()` but returns this, -// and end() return `this` as well, so you can -// do `new Pack(opt).add('files').add('dir').end().pipe(output) -// You could also do something like: -// streamOfPaths().pipe(new Pack()).pipe(new fs.WriteStream('out.tar')) - -class PackJob { - constructor (path, absolute) { - this.path = path || './' - this.absolute = absolute - this.entry = null - this.stat = null - this.readdir = null - this.pending = false - this.ignore = false - this.piped = false - } -} + if (raw && encrypted) { + options.socket = stream; + const secureStream = tls.connect(options); -const { Minipass } = __nccwpck_require__(6684) -const zlib = __nccwpck_require__(3486) -const ReadEntry = __nccwpck_require__(8116) -const WriteEntry = __nccwpck_require__(5450) -const WriteEntrySync = WriteEntry.Sync -const WriteEntryTar = WriteEntry.Tar -const Yallist = __nccwpck_require__(665) -const EOF = Buffer.alloc(1024) -const ONSTAT = Symbol('onStat') -const ENDED = Symbol('ended') -const QUEUE = Symbol('queue') -const CURRENT = Symbol('current') -const PROCESS = Symbol('process') -const PROCESSING = Symbol('processing') -const PROCESSJOB = Symbol('processJob') -const JOBS = Symbol('jobs') -const JOBDONE = Symbol('jobDone') -const ADDFSENTRY = Symbol('addFSEntry') -const ADDTARENTRY = Symbol('addTarEntry') -const STAT = Symbol('stat') -const READDIR = Symbol('readdir') -const ONREADDIR = Symbol('onreaddir') -const PIPE = Symbol('pipe') -const ENTRY = Symbol('entry') -const ENTRYOPT = Symbol('entryOpt') -const WRITEENTRYCLASS = Symbol('writeEntryClass') -const WRITE = Symbol('write') -const ONDRAIN = Symbol('ondrain') - -const fs = __nccwpck_require__(7147) -const path = __nccwpck_require__(1017) -const warner = __nccwpck_require__(5899) -const normPath = __nccwpck_require__(6843) - -const Pack = warner(class Pack extends Minipass { - constructor (opt) { - super(opt) - opt = opt || Object.create(null) - this.opt = opt - this.file = opt.file || '' - this.cwd = opt.cwd || process.cwd() - this.maxReadSize = opt.maxReadSize - this.preservePaths = !!opt.preservePaths - this.strict = !!opt.strict - this.noPax = !!opt.noPax - this.prefix = normPath(opt.prefix || '') - this.linkCache = opt.linkCache || new Map() - this.statCache = opt.statCache || new Map() - this.readdirCache = opt.readdirCache || new Map() - - this[WRITEENTRYCLASS] = WriteEntry - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - - this.portable = !!opt.portable - this.zip = null - - if (opt.gzip || opt.brotli) { - if (opt.gzip && opt.brotli) { - throw new TypeError('gzip and brotli are mutually exclusive') - } - if (opt.gzip) { - if (typeof opt.gzip !== 'object') { - opt.gzip = {} - } - if (this.portable) { - opt.gzip.portable = true - } - this.zip = new zlib.Gzip(opt.gzip) - } - if (opt.brotli) { - if (typeof opt.brotli !== 'object') { - opt.brotli = {} - } - this.zip = new zlib.BrotliCompress(opt.brotli) - } - this.zip.on('data', chunk => super.write(chunk)) - this.zip.on('end', _ => super.end()) - this.zip.on('drain', _ => this[ONDRAIN]()) - this.on('resume', _ => this.zip.resume()) - } else { - this.on('drain', this[ONDRAIN]) - } + secureStream.once('close', () => { + stream.destroy(); + }); - this.noDirRecurse = !!opt.noDirRecurse - this.follow = !!opt.follow - this.noMtime = !!opt.noMtime - this.mtime = opt.mtime || null + callback(null, secureStream); + return; + } - this.filter = typeof opt.filter === 'function' ? opt.filter : _ => true + const socket = new JSStreamSocket(stream); + socket.encrypted = false; + socket._handle.getpeername = out => { + out.family = undefined; + out.address = undefined; + out.port = undefined; + }; - this[QUEUE] = new Yallist() - this[JOBS] = 0 - this.jobs = +opt.jobs || 4 - this[PROCESSING] = false - this[ENDED] = false - } + callback(null, socket); + }); + } catch (error) { + callback(error); + } + })(); +}; - [WRITE] (chunk) { - return super.write(chunk) - } +class HttpOverHttp2 extends http.Agent { + constructor(options) { + super(options); - add (path) { - this.write(path) - return this - } + initialize(this, options.proxyOptions); + } - end (path) { - if (path) { - this.write(path) - } - this[ENDED] = true - this[PROCESS]() - return this - } + createConnection(options, callback) { + createConnection(this, options, callback); + } +} - write (path) { - if (this[ENDED]) { - throw new Error('write after end') - } +class HttpsOverHttp2 extends https.Agent { + constructor(options) { + super(options); - if (path instanceof ReadEntry) { - this[ADDTARENTRY](path) - } else { - this[ADDFSENTRY](path) - } - return this.flowing - } + initialize(this, options.proxyOptions); + } - [ADDTARENTRY] (p) { - const absolute = normPath(path.resolve(this.cwd, p.path)) - // in this case, we don't have to wait for the stat - if (!this.filter(p.path, p)) { - p.resume() - } else { - const job = new PackJob(p.path, absolute, false) - job.entry = new WriteEntryTar(p, this[ENTRYOPT](job)) - job.entry.on('end', _ => this[JOBDONE](job)) - this[JOBS] += 1 - this[QUEUE].push(job) - } + createConnection(options, callback) { + createConnection(this, options, callback); + } +} - this[PROCESS]() - } +module.exports = { + HttpOverHttp2, + HttpsOverHttp2 +}; - [ADDFSENTRY] (p) { - const absolute = normPath(path.resolve(this.cwd, p)) - this[QUEUE].push(new PackJob(p, absolute)) - this[PROCESS]() - } - [STAT] (job) { - job.pending = true - this[JOBS] += 1 - const stat = this.follow ? 'stat' : 'lstat' - fs[stat](job.absolute, (er, stat) => { - job.pending = false - this[JOBS] -= 1 - if (er) { - this.emit('error', er) - } else { - this[ONSTAT](job, stat) - } - }) - } +/***/ }), - [ONSTAT] (job, stat) { - this.statCache.set(job.absolute, stat) - job.stat = stat +/***/ 9794: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // now we have the stat, we can filter it. - if (!this.filter(job.path, stat)) { - job.ignore = true - } +"use strict"; - this[PROCESS]() - } +const http = __nccwpck_require__(3685); +const https = __nccwpck_require__(5687); +const Http2OverHttpX = __nccwpck_require__(1857); +const getAuthorizationHeaders = __nccwpck_require__(7885); - [READDIR] (job) { - job.pending = true - this[JOBS] += 1 - fs.readdir(job.absolute, (er, entries) => { - job.pending = false - this[JOBS] -= 1 - if (er) { - return this.emit('error', er) - } - this[ONREADDIR](job, entries) - }) - } +const getStream = request => new Promise((resolve, reject) => { + const onConnect = (response, socket, head) => { + socket.unshift(head); - [ONREADDIR] (job, entries) { - this.readdirCache.set(job.absolute, entries) - job.readdir = entries - this[PROCESS]() - } + request.off('error', reject); + resolve([socket, response.statusCode, response.statusMessage]); + }; - [PROCESS] () { - if (this[PROCESSING]) { - return - } + request.once('error', reject); + request.once('connect', onConnect); +}); - this[PROCESSING] = true - for (let w = this[QUEUE].head; - w !== null && this[JOBS] < this.jobs; - w = w.next) { - this[PROCESSJOB](w.value) - if (w.value.ignore) { - const p = w.next - this[QUEUE].removeNode(w) - w.next = p - } - } +class Http2OverHttp extends Http2OverHttpX { + async _getProxyStream(authority) { + const {proxyOptions} = this; + const {url, headers} = this.proxyOptions; - this[PROCESSING] = false + const network = url.protocol === 'https:' ? https : http; - if (this[ENDED] && !this[QUEUE].length && this[JOBS] === 0) { - if (this.zip) { - this.zip.end(EOF) - } else { - super.write(EOF) - super.end() - } - } - } + // `new URL('https://localhost/httpbin.org:443')` results in + // a `/httpbin.org:443` path, which has an invalid leading slash. + const request = network.request({ + ...proxyOptions, + hostname: url.hostname, + port: url.port, + path: authority, + headers: { + ...getAuthorizationHeaders(this), + ...headers, + host: authority + }, + method: 'CONNECT' + }).end(); - get [CURRENT] () { - return this[QUEUE] && this[QUEUE].head && this[QUEUE].head.value - } + return getStream(request); + } +} - [JOBDONE] (job) { - this[QUEUE].shift() - this[JOBS] -= 1 - this[PROCESS]() - } +module.exports = { + Http2OverHttp, + Http2OverHttps: Http2OverHttp +}; - [PROCESSJOB] (job) { - if (job.pending) { - return - } - if (job.entry) { - if (job === this[CURRENT] && !job.piped) { - this[PIPE](job) - } - return - } +/***/ }), - if (!job.stat) { - if (this.statCache.has(job.absolute)) { - this[ONSTAT](job, this.statCache.get(job.absolute)) - } else { - this[STAT](job) - } - } - if (!job.stat) { - return - } +/***/ 8553: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // filtered out! - if (job.ignore) { - return - } +"use strict"; - if (!this.noDirRecurse && job.stat.isDirectory() && !job.readdir) { - if (this.readdirCache.has(job.absolute)) { - this[ONREADDIR](job, this.readdirCache.get(job.absolute)) - } else { - this[READDIR](job) - } - if (!job.readdir) { - return - } - } +const {globalAgent} = __nccwpck_require__(9898); +const Http2OverHttpX = __nccwpck_require__(1857); +const getAuthorizationHeaders = __nccwpck_require__(7885); - // we know it doesn't have an entry, because that got checked above - job.entry = this[ENTRY](job) - if (!job.entry) { - job.ignore = true - return - } +const getStatusCode = stream => new Promise((resolve, reject) => { + stream.once('error', reject); + stream.once('response', headers => { + stream.off('error', reject); + resolve(headers[':status']); + }); +}); + +class Http2OverHttp2 extends Http2OverHttpX { + async _getProxyStream(authority) { + const {proxyOptions} = this; - if (job === this[CURRENT] && !job.piped) { - this[PIPE](job) - } - } + const headers = { + ...getAuthorizationHeaders(this), + ...proxyOptions.headers, + ':method': 'CONNECT', + ':authority': authority + }; - [ENTRYOPT] (job) { - return { - onwarn: (code, msg, data) => this.warn(code, msg, data), - noPax: this.noPax, - cwd: this.cwd, - absolute: job.absolute, - preservePaths: this.preservePaths, - maxReadSize: this.maxReadSize, - strict: this.strict, - portable: this.portable, - linkCache: this.linkCache, - statCache: this.statCache, - noMtime: this.noMtime, - mtime: this.mtime, - prefix: this.prefix, - } - } + const stream = await globalAgent.request(proxyOptions.url, proxyOptions, headers); + const statusCode = await getStatusCode(stream); - [ENTRY] (job) { - this[JOBS] += 1 - try { - return new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job)) - .on('end', () => this[JOBDONE](job)) - .on('error', er => this.emit('error', er)) - } catch (er) { - this.emit('error', er) - } - } + return [stream, statusCode, '']; + } +} - [ONDRAIN] () { - if (this[CURRENT] && this[CURRENT].entry) { - this[CURRENT].entry.resume() - } - } +module.exports = Http2OverHttp2; - // like .pipe() but using super, because our write() is special - [PIPE] (job) { - job.piped = true - if (job.readdir) { - job.readdir.forEach(entry => { - const p = job.path - const base = p === './' ? '' : p.replace(/\/*$/, '/') - this[ADDFSENTRY](base + entry) - }) - } +/***/ }), - const source = job.entry - const zip = this.zip +/***/ 1857: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (zip) { - source.on('data', chunk => { - if (!zip.write(chunk)) { - source.pause() - } - }) - } else { - source.on('data', chunk => { - if (!super.write(chunk)) { - source.pause() - } - }) - } - } +"use strict"; - pause () { - if (this.zip) { - this.zip.pause() - } - return super.pause() - } -}) +const {Agent} = __nccwpck_require__(9898); +const JSStreamSocket = __nccwpck_require__(1564); +const UnexpectedStatusCodeError = __nccwpck_require__(6203); +const initialize = __nccwpck_require__(1089); -class PackSync extends Pack { - constructor (opt) { - super(opt) - this[WRITEENTRYCLASS] = WriteEntrySync - } +class Http2OverHttpX extends Agent { + constructor(options) { + super(options); - // pause/resume are no-ops in sync streams. - pause () {} - resume () {} + initialize(this, options.proxyOptions); + } - [STAT] (job) { - const stat = this.follow ? 'statSync' : 'lstatSync' - this[ONSTAT](job, fs[stat](job.absolute)) - } + async createConnection(origin, options) { + const authority = `${origin.hostname}:${origin.port || 443}`; - [READDIR] (job, stat) { - this[ONREADDIR](job, fs.readdirSync(job.absolute)) - } + const [stream, statusCode, statusMessage] = await this._getProxyStream(authority); + if (statusCode !== 200) { + throw new UnexpectedStatusCodeError(statusCode, statusMessage); + } - // gotta get it all in this tick - [PIPE] (job) { - const source = job.entry - const zip = this.zip + if (this.proxyOptions.raw) { + options.socket = stream; + } else { + const socket = new JSStreamSocket(stream); + socket.encrypted = false; + socket._handle.getpeername = out => { + out.family = undefined; + out.address = undefined; + out.port = undefined; + }; - if (job.readdir) { - job.readdir.forEach(entry => { - const p = job.path - const base = p === './' ? '' : p.replace(/\/*$/, '/') - this[ADDFSENTRY](base + entry) - }) - } + return socket; + } - if (zip) { - source.on('data', chunk => { - zip.write(chunk) - }) - } else { - source.on('data', chunk => { - super[WRITE](chunk) - }) - } - } + return super.createConnection(origin, options); + } } -Pack.Sync = PackSync - -module.exports = Pack +module.exports = Http2OverHttpX; /***/ }), -/***/ 8917: +/***/ 1089: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; +// See https://github.com/facebook/jest/issues/2549 +// eslint-disable-next-line node/prefer-global/url +const {URL} = __nccwpck_require__(7310); +const checkType = __nccwpck_require__(3453); -// this[BUFFER] is the remainder of a chunk if we're waiting for -// the full 512 bytes of a header to come in. We will Buffer.concat() -// it to the next write(), which is a mem copy, but a small one. -// -// this[QUEUE] is a Yallist of entries that haven't been emitted -// yet this can only get filled up if the user keeps write()ing after -// a write() returns false, or does a write() with more than one entry -// -// We don't buffer chunks, we always parse them and either create an -// entry, or push it into the active entry. The ReadEntry class knows -// to throw data away if .ignore=true -// -// Shift entry off the buffer when it emits 'end', and emit 'entry' for -// the next one in the list. -// -// At any time, we're pushing body chunks into the entry at WRITEENTRY, -// and waiting for 'end' on the entry at READENTRY -// -// ignored entries get .resume() called on them straight away - -const warner = __nccwpck_require__(5899) -const Header = __nccwpck_require__(6043) -const EE = __nccwpck_require__(2361) -const Yallist = __nccwpck_require__(665) -const maxMetaEntrySize = 1024 * 1024 -const Entry = __nccwpck_require__(8116) -const Pax = __nccwpck_require__(7996) -const zlib = __nccwpck_require__(3486) -const { nextTick } = __nccwpck_require__(7282) - -const gzipHeader = Buffer.from([0x1f, 0x8b]) -const STATE = Symbol('state') -const WRITEENTRY = Symbol('writeEntry') -const READENTRY = Symbol('readEntry') -const NEXTENTRY = Symbol('nextEntry') -const PROCESSENTRY = Symbol('processEntry') -const EX = Symbol('extendedHeader') -const GEX = Symbol('globalExtendedHeader') -const META = Symbol('meta') -const EMITMETA = Symbol('emitMeta') -const BUFFER = Symbol('buffer') -const QUEUE = Symbol('queue') -const ENDED = Symbol('ended') -const EMITTEDEND = Symbol('emittedEnd') -const EMIT = Symbol('emit') -const UNZIP = Symbol('unzip') -const CONSUMECHUNK = Symbol('consumeChunk') -const CONSUMECHUNKSUB = Symbol('consumeChunkSub') -const CONSUMEBODY = Symbol('consumeBody') -const CONSUMEMETA = Symbol('consumeMeta') -const CONSUMEHEADER = Symbol('consumeHeader') -const CONSUMING = Symbol('consuming') -const BUFFERCONCAT = Symbol('bufferConcat') -const MAYBEEND = Symbol('maybeEnd') -const WRITING = Symbol('writing') -const ABORTED = Symbol('aborted') -const DONE = Symbol('onDone') -const SAW_VALID_ENTRY = Symbol('sawValidEntry') -const SAW_NULL_BLOCK = Symbol('sawNullBlock') -const SAW_EOF = Symbol('sawEOF') -const CLOSESTREAM = Symbol('closeStream') - -const noop = _ => true - -module.exports = warner(class Parser extends EE { - constructor (opt) { - opt = opt || {} - super(opt) - - this.file = opt.file || '' - - // set to boolean false when an entry starts. 1024 bytes of \0 - // is technically a valid tarball, albeit a boring one. - this[SAW_VALID_ENTRY] = null - - // these BADARCHIVE errors can't be detected early. listen on DONE. - this.on(DONE, _ => { - if (this[STATE] === 'begin' || this[SAW_VALID_ENTRY] === false) { - // either less than 1 block of data, or all entries were invalid. - // Either way, probably not even a tarball. - this.warn('TAR_BAD_ARCHIVE', 'Unrecognized archive format') - } - }) +module.exports = (self, proxyOptions) => { + checkType('proxyOptions', proxyOptions, ['object']); + checkType('proxyOptions.headers', proxyOptions.headers, ['object', 'undefined']); + checkType('proxyOptions.raw', proxyOptions.raw, ['boolean', 'undefined']); + checkType('proxyOptions.url', proxyOptions.url, [URL, 'string']); - if (opt.ondone) { - this.on(DONE, opt.ondone) - } else { - this.on(DONE, _ => { - this.emit('prefinish') - this.emit('finish') - this.emit('end') - }) - } + const url = new URL(proxyOptions.url); - this.strict = !!opt.strict - this.maxMetaEntrySize = opt.maxMetaEntrySize || maxMetaEntrySize - this.filter = typeof opt.filter === 'function' ? opt.filter : noop - // Unlike gzip, brotli doesn't have any magic bytes to identify it - // Users need to explicitly tell us they're extracting a brotli file - // Or we infer from the file extension - const isTBR = (opt.file && ( - opt.file.endsWith('.tar.br') || opt.file.endsWith('.tbr'))) - // if it's a tbr file it MIGHT be brotli, but we don't know until - // we look at it and verify it's not a valid tar file. - this.brotli = !opt.gzip && opt.brotli !== undefined ? opt.brotli - : isTBR ? undefined - : false - - // have to set this so that streams are ok piping into it - this.writable = true - this.readable = false - - this[QUEUE] = new Yallist() - this[BUFFER] = null - this[READENTRY] = null - this[WRITEENTRY] = null - this[STATE] = 'begin' - this[META] = '' - this[EX] = null - this[GEX] = null - this[ENDED] = false - this[UNZIP] = null - this[ABORTED] = false - this[SAW_NULL_BLOCK] = false - this[SAW_EOF] = false - - this.on('end', () => this[CLOSESTREAM]()) - - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - if (typeof opt.onentry === 'function') { - this.on('entry', opt.onentry) - } - } + self.proxyOptions = { + raw: true, + ...proxyOptions, + headers: {...proxyOptions.headers}, + url + }; +}; - [CONSUMEHEADER] (chunk, position) { - if (this[SAW_VALID_ENTRY] === null) { - this[SAW_VALID_ENTRY] = false - } - let header - try { - header = new Header(chunk, position, this[EX], this[GEX]) - } catch (er) { - return this.warn('TAR_ENTRY_INVALID', er) - } - if (header.nullBlock) { - if (this[SAW_NULL_BLOCK]) { - this[SAW_EOF] = true - // ending an archive with no entries. pointless, but legal. - if (this[STATE] === 'begin') { - this[STATE] = 'header' - } - this[EMIT]('eof') - } else { - this[SAW_NULL_BLOCK] = true - this[EMIT]('nullBlock') - } - } else { - this[SAW_NULL_BLOCK] = false - if (!header.cksumValid) { - this.warn('TAR_ENTRY_INVALID', 'checksum failure', { header }) - } else if (!header.path) { - this.warn('TAR_ENTRY_INVALID', 'path is required', { header }) - } else { - const type = header.type - if (/^(Symbolic)?Link$/.test(type) && !header.linkpath) { - this.warn('TAR_ENTRY_INVALID', 'linkpath required', { header }) - } else if (!/^(Symbolic)?Link$/.test(type) && header.linkpath) { - this.warn('TAR_ENTRY_INVALID', 'linkpath forbidden', { header }) - } else { - const entry = this[WRITEENTRY] = new Entry(header, this[EX], this[GEX]) - - // we do this for meta & ignored entries as well, because they - // are still valid tar, or else we wouldn't know to ignore them - if (!this[SAW_VALID_ENTRY]) { - if (entry.remain) { - // this might be the one! - const onend = () => { - if (!entry.invalid) { - this[SAW_VALID_ENTRY] = true - } - } - entry.on('end', onend) - } else { - this[SAW_VALID_ENTRY] = true - } - } +/***/ }), - if (entry.meta) { - if (entry.size > this.maxMetaEntrySize) { - entry.ignore = true - this[EMIT]('ignoredEntry', entry) - this[STATE] = 'ignore' - entry.resume() - } else if (entry.size > 0) { - this[META] = '' - entry.on('data', c => this[META] += c) - this[STATE] = 'meta' - } - } else { - this[EX] = null - entry.ignore = entry.ignore || !this.filter(entry.path, entry) - - if (entry.ignore) { - // probably valid, just not something we care about - this[EMIT]('ignoredEntry', entry) - this[STATE] = entry.remain ? 'ignore' : 'header' - entry.resume() - } else { - if (entry.remain) { - this[STATE] = 'body' - } else { - this[STATE] = 'header' - entry.end() - } - - if (!this[READENTRY]) { - this[QUEUE].push(entry) - this[NEXTENTRY]() - } else { - this[QUEUE].push(entry) - } - } - } - } - } - } - } +/***/ 6203: +/***/ ((module) => { - [CLOSESTREAM] () { - nextTick(() => this.emit('close')) - } +"use strict"; - [PROCESSENTRY] (entry) { - let go = true - if (!entry) { - this[READENTRY] = null - go = false - } else if (Array.isArray(entry)) { - this.emit.apply(this, entry) - } else { - this[READENTRY] = entry - this.emit('entry', entry) - if (!entry.emittedEnd) { - entry.on('end', _ => this[NEXTENTRY]()) - go = false - } - } +class UnexpectedStatusCodeError extends Error { + constructor(statusCode, statusMessage = '') { + super(`The proxy server rejected the request with status code ${statusCode} (${statusMessage || 'empty status message'})`); + this.statusCode = statusCode; + this.statusMessage = statusMessage; + } +} - return go - } +module.exports = UnexpectedStatusCodeError; - [NEXTENTRY] () { - do {} while (this[PROCESSENTRY](this[QUEUE].shift())) - - if (!this[QUEUE].length) { - // At this point, there's nothing in the queue, but we may have an - // entry which is being consumed (readEntry). - // If we don't, then we definitely can handle more data. - // If we do, and either it's flowing, or it has never had any data - // written to it, then it needs more. - // The only other possibility is that it has returned false from a - // write() call, so we wait for the next drain to continue. - const re = this[READENTRY] - const drainNow = !re || re.flowing || re.size === re.remain - if (drainNow) { - if (!this[WRITING]) { - this.emit('drain') - } - } else { - re.once('drain', _ => this.emit('drain')) - } - } - } - [CONSUMEBODY] (chunk, position) { - // write up to but no more than writeEntry.blockRemain - const entry = this[WRITEENTRY] - const br = entry.blockRemain - const c = (br >= chunk.length && position === 0) ? chunk - : chunk.slice(position, position + br) +/***/ }), - entry.write(c) +/***/ 1982: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (!entry.blockRemain) { - this[STATE] = 'header' - this[WRITEENTRY] = null - entry.end() - } +"use strict"; - return c.length - } +const {isIP} = __nccwpck_require__(1808); +const assert = __nccwpck_require__(9491); - [CONSUMEMETA] (chunk, position) { - const entry = this[WRITEENTRY] - const ret = this[CONSUMEBODY](chunk, position) +const getHost = host => { + if (host[0] === '[') { + const idx = host.indexOf(']'); - // if we finished, then the entry is reset - if (!this[WRITEENTRY]) { - this[EMITMETA](entry) - } + assert(idx !== -1); + return host.slice(1, idx); + } - return ret - } + const idx = host.indexOf(':'); + if (idx === -1) { + return host; + } - [EMIT] (ev, data, extra) { - if (!this[QUEUE].length && !this[READENTRY]) { - this.emit(ev, data, extra) - } else { - this[QUEUE].push([ev, data, extra]) - } - } + return host.slice(0, idx); +}; - [EMITMETA] (entry) { - this[EMIT]('meta', this[META]) - switch (entry.type) { - case 'ExtendedHeader': - case 'OldExtendedHeader': - this[EX] = Pax.parse(this[META], this[EX], false) - break +module.exports = host => { + const servername = getHost(host); - case 'GlobalExtendedHeader': - this[GEX] = Pax.parse(this[META], this[GEX], true) - break + if (isIP(servername)) { + return ''; + } - case 'NextFileHasLongPath': - case 'OldGnuLongPath': - this[EX] = this[EX] || Object.create(null) - this[EX].path = this[META].replace(/\0.*/, '') - break + return servername; +}; - case 'NextFileHasLongLinkpath': - this[EX] = this[EX] || Object.create(null) - this[EX].linkpath = this[META].replace(/\0.*/, '') - break - /* istanbul ignore next */ - default: throw new Error('unknown meta: ' + entry.type) - } - } +/***/ }), - abort (error) { - this[ABORTED] = true - this.emit('abort', error) - // always throws, even in non-strict mode - this.warn('TAR_ABORT', error, { recoverable: false }) - } +/***/ 3453: +/***/ ((module) => { - write (chunk) { - if (this[ABORTED]) { - return - } +"use strict"; - // first write, might be gzipped - const needSniff = this[UNZIP] === null || - this.brotli === undefined && this[UNZIP] === false - if (needSniff && chunk) { - if (this[BUFFER]) { - chunk = Buffer.concat([this[BUFFER], chunk]) - this[BUFFER] = null - } - if (chunk.length < gzipHeader.length) { - this[BUFFER] = chunk - return true - } - // look for gzip header - for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) { - if (chunk[i] !== gzipHeader[i]) { - this[UNZIP] = false - } - } +const checkType = (name, value, types) => { + const valid = types.some(type => { + const typeofType = typeof type; + if (typeofType === 'string') { + return typeof value === type; + } - const maybeBrotli = this.brotli === undefined - if (this[UNZIP] === false && maybeBrotli) { - // read the first header to see if it's a valid tar file. If so, - // we can safely assume that it's not actually brotli, despite the - // .tbr or .tar.br file extension. - // if we ended before getting a full chunk, yes, def brotli - if (chunk.length < 512) { - if (this[ENDED]) { - this.brotli = true - } else { - this[BUFFER] = chunk - return true - } - } else { - // if it's tar, it's pretty reliably not brotli, chances of - // that happening are astronomical. - try { - new Header(chunk.slice(0, 512)) - this.brotli = false - } catch (_) { - this.brotli = true - } - } - } + return value instanceof type; + }); - if (this[UNZIP] === null || (this[UNZIP] === false && this.brotli)) { - const ended = this[ENDED] - this[ENDED] = false - this[UNZIP] = this[UNZIP] === null - ? new zlib.Unzip() - : new zlib.BrotliDecompress() - this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) - this[UNZIP].on('error', er => this.abort(er)) - this[UNZIP].on('end', _ => { - this[ENDED] = true - this[CONSUMECHUNK]() - }) - this[WRITING] = true - const ret = this[UNZIP][ended ? 'end' : 'write'](chunk) - this[WRITING] = false - return ret - } - } + if (!valid) { + const names = types.map(type => typeof type === 'string' ? type : type.name); - this[WRITING] = true - if (this[UNZIP]) { - this[UNZIP].write(chunk) - } else { - this[CONSUMECHUNK](chunk) - } - this[WRITING] = false + throw new TypeError(`Expected '${name}' to be a type of ${names.join(' or ')}, got ${typeof value}`); + } +}; - // return false if there's a queue, or if the current entry isn't flowing - const ret = - this[QUEUE].length ? false : - this[READENTRY] ? this[READENTRY].flowing : - true +module.exports = checkType; - // if we have no queue, then that means a clogged READENTRY - if (!ret && !this[QUEUE].length) { - this[READENTRY].once('drain', _ => this.emit('drain')) - } - return ret - } +/***/ }), - [BUFFERCONCAT] (c) { - if (c && !this[ABORTED]) { - this[BUFFER] = this[BUFFER] ? Buffer.concat([this[BUFFER], c]) : c - } - } +/***/ 9237: +/***/ ((module) => { - [MAYBEEND] () { - if (this[ENDED] && - !this[EMITTEDEND] && - !this[ABORTED] && - !this[CONSUMING]) { - this[EMITTEDEND] = true - const entry = this[WRITEENTRY] - if (entry && entry.blockRemain) { - // truncated, likely a damaged file - const have = this[BUFFER] ? this[BUFFER].length : 0 - this.warn('TAR_BAD_ARCHIVE', `Truncated input (needed ${ - entry.blockRemain} more bytes, only ${have} available)`, { entry }) - if (this[BUFFER]) { - entry.write(this[BUFFER]) - } - entry.end() - } - this[EMIT](DONE) - } - } +"use strict"; - [CONSUMECHUNK] (chunk) { - if (this[CONSUMING]) { - this[BUFFERCONCAT](chunk) - } else if (!chunk && !this[BUFFER]) { - this[MAYBEEND]() - } else { - this[CONSUMING] = true - if (this[BUFFER]) { - this[BUFFERCONCAT](chunk) - const c = this[BUFFER] - this[BUFFER] = null - this[CONSUMECHUNKSUB](c) - } else { - this[CONSUMECHUNKSUB](chunk) - } - while (this[BUFFER] && - this[BUFFER].length >= 512 && - !this[ABORTED] && - !this[SAW_EOF]) { - const c = this[BUFFER] - this[BUFFER] = null - this[CONSUMECHUNKSUB](c) - } - this[CONSUMING] = false - } +module.exports = stream => { + if (stream.listenerCount('error') !== 0) { + return stream; + } + + stream.__destroy = stream._destroy; + stream._destroy = (...args) => { + const callback = args.pop(); + + stream.__destroy(...args, async error => { + await Promise.resolve(); + callback(error); + }); + }; + + const onError = error => { + // eslint-disable-next-line promise/prefer-await-to-then + Promise.resolve().then(() => { + stream.emit('error', error); + }); + }; - if (!this[BUFFER] || this[ENDED]) { - this[MAYBEEND]() - } - } + stream.once('error', onError); - [CONSUMECHUNKSUB] (chunk) { - // we know that we are in CONSUMING mode, so anything written goes into - // the buffer. Advance the position and put any remainder in the buffer. - let position = 0 - const length = chunk.length - while (position + 512 <= length && !this[ABORTED] && !this[SAW_EOF]) { - switch (this[STATE]) { - case 'begin': - case 'header': - this[CONSUMEHEADER](chunk, position) - position += 512 - break + // eslint-disable-next-line promise/prefer-await-to-then + Promise.resolve().then(() => { + stream.off('error', onError); + }); - case 'ignore': - case 'body': - position += this[CONSUMEBODY](chunk, position) - break + return stream; +}; - case 'meta': - position += this[CONSUMEMETA](chunk, position) - break - /* istanbul ignore next */ - default: - throw new Error('invalid state: ' + this[STATE]) - } - } +/***/ }), - if (position < length) { - if (this[BUFFER]) { - this[BUFFER] = Buffer.concat([chunk.slice(position), this[BUFFER]]) - } else { - this[BUFFER] = chunk.slice(position) - } - } - } +/***/ 7087: +/***/ ((module) => { - end (chunk) { - if (!this[ABORTED]) { - if (this[UNZIP]) { - this[UNZIP].end(chunk) - } else { - this[ENDED] = true - if (this.brotli === undefined) chunk = chunk || Buffer.alloc(0) - this.write(chunk) - } - } - } -}) +"use strict"; +/* istanbul ignore file: https://github.com/nodejs/node/blob/master/lib/internal/errors.js */ -/***/ }), +const makeError = (Base, key, getMessage) => { + module.exports[key] = class NodeError extends Base { + constructor(...args) { + super(typeof getMessage === 'string' ? getMessage : getMessage(args)); + this.name = `${super.name} [${key}]`; + this.code = key; + } + }; +}; -/***/ 9587: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +makeError(TypeError, 'ERR_INVALID_ARG_TYPE', args => { + const type = args[0].includes('.') ? 'property' : 'argument'; -// A path exclusive reservation system -// reserve([list, of, paths], fn) -// When the fn is first in line for all its paths, it -// is called with a cb that clears the reservation. -// -// Used by async unpack to avoid clobbering paths in use, -// while still allowing maximal safe parallelization. - -const assert = __nccwpck_require__(9491) -const normalize = __nccwpck_require__(7118) -const stripSlashes = __nccwpck_require__(8886) -const { join } = __nccwpck_require__(1017) - -const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform -const isWindows = platform === 'win32' - -module.exports = () => { - // path => [function or Set] - // A Set object means a directory reservation - // A fn is a direct reservation on that path - const queues = new Map() - - // fn => {paths:[path,...], dirs:[path, ...]} - const reservations = new Map() - - // return a set of parent dirs for a given path - // '/a/b/c/d' -> ['/', '/a', '/a/b', '/a/b/c', '/a/b/c/d'] - const getDirs = path => { - const dirs = path.split('/').slice(0, -1).reduce((set, path) => { - if (set.length) { - path = join(set[set.length - 1], path) - } - set.push(path || '/') - return set - }, []) - return dirs - } + let valid = args[1]; + const isManyTypes = Array.isArray(valid); - // functions currently running - const running = new Set() + if (isManyTypes) { + valid = `${valid.slice(0, -1).join(', ')} or ${valid.slice(-1)}`; + } - // return the queues for each path the function cares about - // fn => {paths, dirs} - const getQueues = fn => { - const res = reservations.get(fn) - /* istanbul ignore if - unpossible */ - if (!res) { - throw new Error('function does not have any path reservations') - } - return { - paths: res.paths.map(path => queues.get(path)), - dirs: [...res.dirs].map(path => queues.get(path)), - } - } + return `The "${args[0]}" ${type} must be ${isManyTypes ? 'one of' : 'of'} type ${valid}. Received ${typeof args[2]}`; +}); - // check if fn is first in line for all its paths, and is - // included in the first set for all its dir queues - const check = fn => { - const { paths, dirs } = getQueues(fn) - return paths.every(q => q[0] === fn) && - dirs.every(q => q[0] instanceof Set && q[0].has(fn)) - } +makeError(TypeError, 'ERR_INVALID_PROTOCOL', args => + `Protocol "${args[0]}" not supported. Expected "${args[1]}"` +); - // run the function if it's first in line and not already running - const run = fn => { - if (running.has(fn) || !check(fn)) { - return false - } - running.add(fn) - fn(() => clear(fn)) - return true - } +makeError(Error, 'ERR_HTTP_HEADERS_SENT', args => + `Cannot ${args[0]} headers after they are sent to the client` +); - const clear = fn => { - if (!running.has(fn)) { - return false - } +makeError(TypeError, 'ERR_INVALID_HTTP_TOKEN', args => + `${args[0]} must be a valid HTTP token [${args[1]}]` +); - const { paths, dirs } = reservations.get(fn) - const next = new Set() +makeError(TypeError, 'ERR_HTTP_INVALID_HEADER_VALUE', args => + `Invalid value "${args[0]} for header "${args[1]}"` +); - paths.forEach(path => { - const q = queues.get(path) - assert.equal(q[0], fn) - if (q.length === 1) { - queues.delete(path) - } else { - q.shift() - if (typeof q[0] === 'function') { - next.add(q[0]) - } else { - q[0].forEach(fn => next.add(fn)) - } - } - }) +makeError(TypeError, 'ERR_INVALID_CHAR', args => + `Invalid character in ${args[0]} [${args[1]}]` +); - dirs.forEach(dir => { - const q = queues.get(dir) - assert(q[0] instanceof Set) - if (q[0].size === 1 && q.length === 1) { - queues.delete(dir) - } else if (q[0].size === 1) { - q.shift() +makeError( + Error, + 'ERR_HTTP2_NO_SOCKET_MANIPULATION', + 'HTTP/2 sockets should not be directly manipulated (e.g. read and written)' +); - // must be a function or else the Set would've been reused - next.add(q[0]) - } else { - q[0].delete(fn) - } - }) - running.delete(fn) - next.forEach(fn => run(fn)) - return true - } +/***/ }), - const reserve = (paths, fn) => { - // collide on matches across case and unicode normalization - // On windows, thanks to the magic of 8.3 shortnames, it is fundamentally - // impossible to determine whether two paths refer to the same thing on - // disk, without asking the kernel for a shortname. - // So, we just pretend that every path matches every other path here, - // effectively removing all parallelization on windows. - paths = isWindows ? ['win32 parallelization disabled'] : paths.map(p => { - // don't need normPath, because we skip this entirely for windows - return stripSlashes(join(normalize(p))).toLowerCase() - }) +/***/ 1199: +/***/ ((module) => { - const dirs = new Set( - paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b)) - ) - reservations.set(fn, { dirs, paths }) - paths.forEach(path => { - const q = queues.get(path) - if (!q) { - queues.set(path, [fn]) - } else { - q.push(fn) - } - }) - dirs.forEach(dir => { - const q = queues.get(dir) - if (!q) { - queues.set(dir, [new Set([fn])]) - } else if (q[q.length - 1] instanceof Set) { - q[q.length - 1].add(fn) - } else { - q.push(new Set([fn])) - } - }) +"use strict"; - return run(fn) - } - return { check, reserve } -} +module.exports = header => { + switch (header) { + case ':method': + case ':scheme': + case ':authority': + case ':path': + return true; + default: + return false; + } +}; /***/ }), -/***/ 7996: +/***/ 1564: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const Header = __nccwpck_require__(6043) -const path = __nccwpck_require__(1017) - -class Pax { - constructor (obj, global) { - this.atime = obj.atime || null - this.charset = obj.charset || null - this.comment = obj.comment || null - this.ctime = obj.ctime || null - this.gid = obj.gid || null - this.gname = obj.gname || null - this.linkpath = obj.linkpath || null - this.mtime = obj.mtime || null - this.path = obj.path || null - this.size = obj.size || null - this.uid = obj.uid || null - this.uname = obj.uname || null - this.dev = obj.dev || null - this.ino = obj.ino || null - this.nlink = obj.nlink || null - this.global = global || false - } - - encode () { - const body = this.encodeBody() - if (body === '') { - return null - } - - const bodyLen = Buffer.byteLength(body) - // round up to 512 bytes - // add 512 for header - const bufLen = 512 * Math.ceil(1 + bodyLen / 512) - const buf = Buffer.allocUnsafe(bufLen) - - // 0-fill the header section, it might not hit every field - for (let i = 0; i < 512; i++) { - buf[i] = 0 - } - - new Header({ - // XXX split the path - // then the path should be PaxHeader + basename, but less than 99, - // prepend with the dirname - path: ('PaxHeader/' + path.basename(this.path)).slice(0, 99), - mode: this.mode || 0o644, - uid: this.uid || null, - gid: this.gid || null, - size: bodyLen, - mtime: this.mtime || null, - type: this.global ? 'GlobalExtendedHeader' : 'ExtendedHeader', - linkpath: '', - uname: this.uname || '', - gname: this.gname || '', - devmaj: 0, - devmin: 0, - atime: this.atime || null, - ctime: this.ctime || null, - }).encode(buf) - - buf.write(body, 512, bodyLen, 'utf8') - - // null pad after the body - for (let i = bodyLen + 512; i < buf.length; i++) { - buf[i] = 0 - } - - return buf - } - - encodeBody () { - return ( - this.encodeField('path') + - this.encodeField('ctime') + - this.encodeField('atime') + - this.encodeField('dev') + - this.encodeField('ino') + - this.encodeField('nlink') + - this.encodeField('charset') + - this.encodeField('comment') + - this.encodeField('gid') + - this.encodeField('gname') + - this.encodeField('linkpath') + - this.encodeField('mtime') + - this.encodeField('size') + - this.encodeField('uid') + - this.encodeField('uname') - ) - } - - encodeField (field) { - if (this[field] === null || this[field] === undefined) { - return '' - } - const v = this[field] instanceof Date ? this[field].getTime() / 1000 - : this[field] - const s = ' ' + - (field === 'dev' || field === 'ino' || field === 'nlink' - ? 'SCHILY.' : '') + - field + '=' + v + '\n' - const byteLen = Buffer.byteLength(s) - // the digits includes the length of the digits in ascii base-10 - // so if it's 9 characters, then adding 1 for the 9 makes it 10 - // which makes it 11 chars. - let digits = Math.floor(Math.log(byteLen) / Math.log(10)) + 1 - if (byteLen + digits >= Math.pow(10, digits)) { - digits += 1 - } - const len = digits + byteLen - return len + s - } -} +const stream = __nccwpck_require__(2781); +const tls = __nccwpck_require__(4404); -Pax.parse = (string, ex, g) => new Pax(merge(parseKV(string), ex), g) +// Really awesome hack. +const JSStreamSocket = (new tls.TLSSocket(new stream.PassThrough()))._handle._parentWrap.constructor; -const merge = (a, b) => - b ? Object.keys(a).reduce((s, k) => (s[k] = a[k], s), b) : a +module.exports = JSStreamSocket; -const parseKV = string => - string - .replace(/\n$/, '') - .split('\n') - .reduce(parseKVLine, Object.create(null)) -const parseKVLine = (set, line) => { - const n = parseInt(line, 10) +/***/ }), - // XXX Values with \n in them will fail this. - // Refactor to not be a naive line-by-line parse. - if (n !== Buffer.byteLength(line) + 1) { - return set - } +/***/ 1818: +/***/ ((module) => { - line = line.slice((n + ' ').length) - const kv = line.split('=') - const k = kv.shift().replace(/^SCHILY\.(dev|ino|nlink)/, '$1') - if (!k) { - return set - } +"use strict"; - const v = kv.join('=') - set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) - ? new Date(v * 1000) - : /^[0-9]+$/.test(v) ? +v - : v - return set -} -module.exports = Pax +module.exports = (from, to, events) => { + for (const event of events) { + from.on(event, (...args) => to.emit(event, ...args)); + } +}; /***/ }), -/***/ 8116: +/***/ 9404: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { Minipass } = __nccwpck_require__(6684) -const normPath = __nccwpck_require__(6843) - -const SLURP = Symbol('slurp') -module.exports = class ReadEntry extends Minipass { - constructor (header, ex, gex) { - super() - // read entries always start life paused. this is to avoid the - // situation where Minipass's auto-ending empty streams results - // in an entry ending before we're ready for it. - this.pause() - this.extended = ex - this.globalExtended = gex - this.header = header - this.startBlockSize = 512 * Math.ceil(header.size / 512) - this.blockRemain = this.startBlockSize - this.remain = header.size - this.type = header.type - this.meta = false - this.ignore = false - switch (this.type) { - case 'File': - case 'OldFile': - case 'Link': - case 'SymbolicLink': - case 'CharacterDevice': - case 'BlockDevice': - case 'Directory': - case 'FIFO': - case 'ContiguousFile': - case 'GNUDumpDir': - break - - case 'NextFileHasLongLinkpath': - case 'NextFileHasLongPath': - case 'OldGnuLongPath': - case 'GlobalExtendedHeader': - case 'ExtendedHeader': - case 'OldExtendedHeader': - this.meta = true - break - - // NOTE: gnutar and bsdtar treat unrecognized types as 'File' - // it may be worth doing the same, but with a warning. - default: - this.ignore = true - } - - this.path = normPath(header.path) - this.mode = header.mode - if (this.mode) { - this.mode = this.mode & 0o7777 - } - this.uid = header.uid - this.gid = header.gid - this.uname = header.uname - this.gname = header.gname - this.size = header.size - this.mtime = header.mtime - this.atime = header.atime - this.ctime = header.ctime - this.linkpath = normPath(header.linkpath) - this.uname = header.uname - this.gname = header.gname - - if (ex) { - this[SLURP](ex) - } - if (gex) { - this[SLURP](gex, true) - } - } - - write (data) { - const writeLen = data.length - if (writeLen > this.blockRemain) { - throw new Error('writing more to entry than is appropriate') - } - - const r = this.remain - const br = this.blockRemain - this.remain = Math.max(0, r - writeLen) - this.blockRemain = Math.max(0, br - writeLen) - if (this.ignore) { - return true - } +const {ERR_HTTP2_NO_SOCKET_MANIPULATION} = __nccwpck_require__(7087); - if (r >= writeLen) { - return super.write(data) - } +/* istanbul ignore file */ +/* https://github.com/nodejs/node/blob/6eec858f34a40ffa489c1ec54bb24da72a28c781/lib/internal/http2/compat.js#L195-L272 */ - // r < writeLen - return super.write(data.slice(0, r)) - } +const proxySocketHandler = { + has(stream, property) { + // Replaced [kSocket] with .socket + const reference = stream.session === undefined ? stream : stream.session.socket; + return (property in stream) || (property in reference); + }, - [SLURP] (ex, global) { - for (const k in ex) { - // we slurp in everything except for the path attribute in - // a global extended header, because that's weird. - if (ex[k] !== null && ex[k] !== undefined && - !(global && k === 'path')) { - this[k] = k === 'path' || k === 'linkpath' ? normPath(ex[k]) : ex[k] - } - } - } -} + get(stream, property) { + switch (property) { + case 'on': + case 'once': + case 'end': + case 'emit': + case 'destroy': + return stream[property].bind(stream); + case 'writable': + case 'destroyed': + return stream[property]; + case 'readable': + if (stream.destroyed) { + return false; + } + return stream.readable; + case 'setTimeout': { + const {session} = stream; + if (session !== undefined) { + return session.setTimeout.bind(session); + } -/***/ }), + return stream.setTimeout.bind(stream); + } -/***/ 5923: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + case 'write': + case 'read': + case 'pause': + case 'resume': + throw new ERR_HTTP2_NO_SOCKET_MANIPULATION(); + default: { + // Replaced [kSocket] with .socket + const reference = stream.session === undefined ? stream : stream.session.socket; + const value = reference[property]; -"use strict"; + return typeof value === 'function' ? value.bind(reference) : value; + } + } + }, + getPrototypeOf(stream) { + if (stream.session !== undefined) { + // Replaced [kSocket] with .socket + return Reflect.getPrototypeOf(stream.session.socket); + } -// tar -r -const hlo = __nccwpck_require__(5213) -const Pack = __nccwpck_require__(7900) -const fs = __nccwpck_require__(7147) -const fsm = __nccwpck_require__(7714) -const t = __nccwpck_require__(1525) -const path = __nccwpck_require__(1017) + return Reflect.getPrototypeOf(stream); + }, -// starting at the head of the file, read a Header -// If the checksum is invalid, that's our position to start writing -// If it is, jump forward by the specified size (round up to 512) -// and try again. -// Write the new Pack stream starting there. + set(stream, property, value) { + switch (property) { + case 'writable': + case 'readable': + case 'destroyed': + case 'on': + case 'once': + case 'end': + case 'emit': + case 'destroy': + stream[property] = value; + return true; + case 'setTimeout': { + const {session} = stream; + if (session === undefined) { + stream.setTimeout = value; + } else { + session.setTimeout = value; + } -const Header = __nccwpck_require__(6043) + return true; + } -module.exports = (opt_, files, cb) => { - const opt = hlo(opt_) + case 'write': + case 'read': + case 'pause': + case 'resume': + throw new ERR_HTTP2_NO_SOCKET_MANIPULATION(); + default: { + // Replaced [kSocket] with .socket + const reference = stream.session === undefined ? stream : stream.session.socket; + reference[property] = value; + return true; + } + } + } +}; - if (!opt.file) { - throw new TypeError('file is required') - } +module.exports = proxySocketHandler; - if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { - throw new TypeError('cannot append to compressed archives') - } - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } +/***/ }), - files = Array.from(files) +/***/ 4592: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - return opt.sync ? replaceSync(opt, files) - : replace(opt, files, cb) -} +"use strict"; -const replaceSync = (opt, files) => { - const p = new Pack.Sync(opt) +const {ERR_INVALID_HTTP_TOKEN} = __nccwpck_require__(7087); +const isRequestPseudoHeader = __nccwpck_require__(1199); - let threw = true - let fd - let position +const isValidHttpToken = /^[\^`\-\w!#$%&*+.|~]+$/; - try { - try { - fd = fs.openSync(opt.file, 'r+') - } catch (er) { - if (er.code === 'ENOENT') { - fd = fs.openSync(opt.file, 'w+') - } else { - throw er - } - } +module.exports = name => { + if (typeof name !== 'string' || (!isValidHttpToken.test(name) && !isRequestPseudoHeader(name))) { + throw new ERR_INVALID_HTTP_TOKEN('Header name', name); + } +}; - const st = fs.fstatSync(fd) - const headBuf = Buffer.alloc(512) - POSITION: for (position = 0; position < st.size; position += 512) { - for (let bufPos = 0, bytes = 0; bufPos < 512; bufPos += bytes) { - bytes = fs.readSync( - fd, headBuf, bufPos, headBuf.length - bufPos, position + bufPos - ) +/***/ }), - if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) { - throw new Error('cannot append to compressed archives') - } +/***/ 3549: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (!bytes) { - break POSITION - } - } +"use strict"; - const h = new Header(headBuf) - if (!h.cksumValid) { - break - } - const entryBlockSize = 512 * Math.ceil(h.size / 512) - if (position + entryBlockSize + 512 > st.size) { - break - } - // the 512 for the header we just parsed will be added as well - // also jump ahead all the blocks for the body - position += entryBlockSize - if (opt.mtimeCache) { - opt.mtimeCache.set(h.path, h.mtime) - } - } - threw = false +const { + ERR_HTTP_INVALID_HEADER_VALUE, + ERR_INVALID_CHAR +} = __nccwpck_require__(7087); - streamSync(opt, p, position, fd, files) - } finally { - if (threw) { - try { - fs.closeSync(fd) - } catch (er) {} - } - } -} +const isInvalidHeaderValue = /[^\t\u0020-\u007E\u0080-\u00FF]/; -const streamSync = (opt, p, position, fd, files) => { - const stream = new fsm.WriteStreamSync(opt.file, { - fd: fd, - start: position, - }) - p.pipe(stream) - addFilesSync(p, files) -} +module.exports = (name, value) => { + if (typeof value === 'undefined') { + throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name); + } -const replace = (opt, files, cb) => { - files = Array.from(files) - const p = new Pack(opt) + if (isInvalidHeaderValue.test(value)) { + throw new ERR_INVALID_CHAR('header content', name); + } +}; - const getPos = (fd, size, cb_) => { - const cb = (er, pos) => { - if (er) { - fs.close(fd, _ => cb_(er)) - } else { - cb_(null, pos) - } - } - let position = 0 - if (size === 0) { - return cb(null, 0) - } +/***/ }), - let bufPos = 0 - const headBuf = Buffer.alloc(512) - const onread = (er, bytes) => { - if (er) { - return cb(er) - } - bufPos += bytes - if (bufPos < 512 && bytes) { - return fs.read( - fd, headBuf, bufPos, headBuf.length - bufPos, - position + bufPos, onread - ) - } +/***/ 2820: +/***/ ((__unused_webpack_module, exports) => { - if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) { - return cb(new Error('cannot append to compressed archives')) - } +//TODO: handle reviver/dehydrate function like normal +//and handle indentation, like normal. +//if anyone needs this... please send pull request. - // truncated header - if (bufPos < 512) { - return cb(null, position) - } +exports.stringify = function stringify (o) { + if('undefined' == typeof o) return o - const h = new Header(headBuf) - if (!h.cksumValid) { - return cb(null, position) - } + if(o && Buffer.isBuffer(o)) + return JSON.stringify(':base64:' + o.toString('base64')) - const entryBlockSize = 512 * Math.ceil(h.size / 512) - if (position + entryBlockSize + 512 > size) { - return cb(null, position) - } + if(o && o.toJSON) + o = o.toJSON() - position += entryBlockSize + 512 - if (position >= size) { - return cb(null, position) - } + if(o && 'object' === typeof o) { + var s = '' + var array = Array.isArray(o) + s = array ? '[' : '{' + var first = true - if (opt.mtimeCache) { - opt.mtimeCache.set(h.path, h.mtime) + for(var k in o) { + var ignore = 'function' == typeof o[k] || (!array && 'undefined' === typeof o[k]) + if(Object.hasOwnProperty.call(o, k) && !ignore) { + if(!first) + s += ',' + first = false + if (array) { + if(o[k] == undefined) + s += 'null' + else + s += stringify(o[k]) + } else if (o[k] !== void(0)) { + s += stringify(k) + ':' + stringify(o[k]) + } } - bufPos = 0 - fs.read(fd, headBuf, 0, 512, position, onread) } - fs.read(fd, headBuf, 0, 512, position, onread) - } - - const promise = new Promise((resolve, reject) => { - p.on('error', reject) - let flag = 'r+' - const onopen = (er, fd) => { - if (er && er.code === 'ENOENT' && flag === 'r+') { - flag = 'w+' - return fs.open(opt.file, flag, onopen) - } - - if (er) { - return reject(er) - } - fs.fstat(fd, (er, st) => { - if (er) { - return fs.close(fd, () => reject(er)) - } - - getPos(fd, st.size, (er, position) => { - if (er) { - return reject(er) - } - const stream = new fsm.WriteStream(opt.file, { - fd: fd, - start: position, - }) - p.pipe(stream) - stream.on('error', reject) - stream.on('close', resolve) - addFilesAsync(p, files) - }) - }) - } - fs.open(opt.file, flag, onopen) - }) + s += array ? ']' : '}' - return cb ? promise.then(cb, cb) : promise + return s + } else if ('string' === typeof o) { + return JSON.stringify(/^:/.test(o) ? ':' + o : o) + } else if ('undefined' === typeof o) { + return 'null'; + } else + return JSON.stringify(o) } -const addFilesSync = (p, files) => { - files.forEach(file => { - if (file.charAt(0) === '@') { - t({ - file: path.resolve(p.cwd, file.slice(1)), - sync: true, - noResume: true, - onentry: entry => p.add(entry), - }) - } else { - p.add(file) +exports.parse = function (s) { + return JSON.parse(s, function (key, value) { + if('string' === typeof value) { + if(/^:base64:/.test(value)) + return Buffer.from(value.substring(8), 'base64') + else + return /^:/.test(value) ? value.substring(1) : value } + return value }) - p.end() -} - -const addFilesAsync = (p, files) => { - while (files.length) { - const file = files.shift() - if (file.charAt(0) === '@') { - return t({ - file: path.resolve(p.cwd, file.slice(1)), - noResume: true, - onentry: entry => p.add(entry), - }).then(_ => addFilesAsync(p, files)) - } else { - p.add(file) - } - } - p.end() -} - - -/***/ }), - -/***/ 7111: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -// unix absolute paths are also absolute on win32, so we use this for both -const { isAbsolute, parse } = (__nccwpck_require__(1017).win32) - -// returns [root, stripped] -// Note that windows will think that //x/y/z/a has a "root" of //x/y, and in -// those cases, we want to sanitize it to x/y/z/a, not z/a, so we strip / -// explicitly if it's the first character. -// drive-specific relative paths on Windows get their root stripped off even -// though they are not absolute, so `c:../foo` becomes ['c:', '../foo'] -module.exports = path => { - let r = '' - - let parsed = parse(path) - while (isAbsolute(path) || parsed.root) { - // windows will think that //x/y/z has a "root" of //x/y/ - // but strip the //?/C:/ off of //?/C:/path - const root = path.charAt(0) === '/' && path.slice(0, 4) !== '//?/' ? '/' - : parsed.root - path = path.slice(root.length) - r += root - parsed = parse(path) - } - return [r, path] -} - - -/***/ }), - -/***/ 8886: -/***/ ((module) => { - -// warning: extremely hot code path. -// This has been meticulously optimized for use -// within npm install on large package trees. -// Do not edit without careful benchmarking. -module.exports = str => { - let i = str.length - 1 - let slashesStart = -1 - while (i > -1 && str.charAt(i) === '/') { - slashesStart = i - i-- - } - return slashesStart === -1 ? str : str.slice(0, slashesStart) } /***/ }), -/***/ 4173: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - -// map types from key to human-friendly name -exports.name = new Map([ - ['0', 'File'], - // same as File - ['', 'OldFile'], - ['1', 'Link'], - ['2', 'SymbolicLink'], - // Devices and FIFOs aren't fully supported - // they are parsed, but skipped when unpacking - ['3', 'CharacterDevice'], - ['4', 'BlockDevice'], - ['5', 'Directory'], - ['6', 'FIFO'], - // same as File - ['7', 'ContiguousFile'], - // pax headers - ['g', 'GlobalExtendedHeader'], - ['x', 'ExtendedHeader'], - // vendor-specific stuff - // skip - ['A', 'SolarisACL'], - // like 5, but with data, which should be skipped - ['D', 'GNUDumpDir'], - // metadata only, skip - ['I', 'Inode'], - // data = link path of next file - ['K', 'NextFileHasLongLinkpath'], - // data = path of next file - ['L', 'NextFileHasLongPath'], - // skip - ['M', 'ContinuationFile'], - // like L - ['N', 'OldGnuLongPath'], - // skip - ['S', 'SparseFile'], - // skip - ['V', 'TapeVolumeHeader'], - // like x - ['X', 'OldExtendedHeader'], -]) - -// map the other direction -exports.code = new Map(Array.from(exports.name).map(kv => [kv[1], kv[0]])) - - -/***/ }), - -/***/ 7628: +/***/ 1531: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -// the PEND/UNPEND stuff tracks whether we're ready to emit end/close yet. -// but the path reservations are required to avoid race conditions where -// parallelized unpack ops may mess with one another, due to dependencies -// (like a Link depending on its target) or destructive operations (like -// clobbering an fs object to create one of a different type.) - -const assert = __nccwpck_require__(9491) -const Parser = __nccwpck_require__(8917) -const fs = __nccwpck_require__(7147) -const fsm = __nccwpck_require__(7714) -const path = __nccwpck_require__(1017) -const mkdir = __nccwpck_require__(9624) -const wc = __nccwpck_require__(4808) -const pathReservations = __nccwpck_require__(9587) -const stripAbsolutePath = __nccwpck_require__(7111) -const normPath = __nccwpck_require__(6843) -const stripSlash = __nccwpck_require__(8886) -const normalize = __nccwpck_require__(7118) - -const ONENTRY = Symbol('onEntry') -const CHECKFS = Symbol('checkFs') -const CHECKFS2 = Symbol('checkFs2') -const PRUNECACHE = Symbol('pruneCache') -const ISREUSABLE = Symbol('isReusable') -const MAKEFS = Symbol('makeFs') -const FILE = Symbol('file') -const DIRECTORY = Symbol('directory') -const LINK = Symbol('link') -const SYMLINK = Symbol('symlink') -const HARDLINK = Symbol('hardlink') -const UNSUPPORTED = Symbol('unsupported') -const CHECKPATH = Symbol('checkPath') -const MKDIR = Symbol('mkdir') -const ONERROR = Symbol('onError') -const PENDING = Symbol('pending') -const PEND = Symbol('pend') -const UNPEND = Symbol('unpend') -const ENDED = Symbol('ended') -const MAYBECLOSE = Symbol('maybeClose') -const SKIP = Symbol('skip') -const DOCHOWN = Symbol('doChown') -const UID = Symbol('uid') -const GID = Symbol('gid') -const CHECKED_CWD = Symbol('checkedCwd') -const crypto = __nccwpck_require__(6113) -const getFlag = __nccwpck_require__(1172) -const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform -const isWindows = platform === 'win32' - -// Unlinks on Windows are not atomic. -// -// This means that if you have a file entry, followed by another -// file entry with an identical name, and you cannot re-use the file -// (because it's a hardlink, or because unlink:true is set, or it's -// Windows, which does not have useful nlink values), then the unlink -// will be committed to the disk AFTER the new file has been written -// over the old one, deleting the new file. -// -// To work around this, on Windows systems, we rename the file and then -// delete the renamed file. It's a sloppy kludge, but frankly, I do not -// know of a better way to do this, given windows' non-atomic unlink -// semantics. -// -// See: https://github.com/npm/node-tar/issues/183 -/* istanbul ignore next */ -const unlinkFile = (path, cb) => { - if (!isWindows) { - return fs.unlink(path, cb) - } - - const name = path + '.DELETE.' + crypto.randomBytes(16).toString('hex') - fs.rename(path, name, er => { - if (er) { - return cb(er) - } - fs.unlink(name, cb) - }) -} - -/* istanbul ignore next */ -const unlinkFileSync = path => { - if (!isWindows) { - return fs.unlinkSync(path) - } +const EventEmitter = __nccwpck_require__(2361); +const JSONB = __nccwpck_require__(2820); - const name = path + '.DELETE.' + crypto.randomBytes(16).toString('hex') - fs.renameSync(path, name) - fs.unlinkSync(name) -} - -// this.gid, entry.gid, this.processUid -const uint32 = (a, b, c) => - a === a >>> 0 ? a - : b === b >>> 0 ? b - : c - -// clear the cache if it's a case-insensitive unicode-squashing match. -// we can't know if the current file system is case-sensitive or supports -// unicode fully, so we check for similarity on the maximally compatible -// representation. Err on the side of pruning, since all it's doing is -// preventing lstats, and it's not the end of the world if we get a false -// positive. -// Note that on windows, we always drop the entire cache whenever a -// symbolic link is encountered, because 8.3 filenames are impossible -// to reason about, and collisions are hazards rather than just failures. -const cacheKeyNormalize = path => stripSlash(normPath(normalize(path))) - .toLowerCase() - -const pruneCache = (cache, abs) => { - abs = cacheKeyNormalize(abs) - for (const path of cache.keys()) { - const pnorm = cacheKeyNormalize(path) - if (pnorm === abs || pnorm.indexOf(abs + '/') === 0) { - cache.delete(path) - } - } -} +const loadStore = options => { + const adapters = { + redis: '@keyv/redis', + rediss: '@keyv/redis', + mongodb: '@keyv/mongo', + mongo: '@keyv/mongo', + sqlite: '@keyv/sqlite', + postgresql: '@keyv/postgres', + postgres: '@keyv/postgres', + mysql: '@keyv/mysql', + etcd: '@keyv/etcd', + offline: '@keyv/offline', + tiered: '@keyv/tiered', + }; + if (options.adapter || options.uri) { + const adapter = options.adapter || /^[^:+]*/.exec(options.uri)[0]; + return new (require(adapters[adapter]))(options); + } -const dropCache = cache => { - for (const key of cache.keys()) { - cache.delete(key) - } -} + return new Map(); +}; -class Unpack extends Parser { - constructor (opt) { - if (!opt) { - opt = {} - } +const iterableAdapters = [ + 'sqlite', + 'postgres', + 'mysql', + 'mongo', + 'redis', + 'tiered', +]; - opt.ondone = _ => { - this[ENDED] = true - this[MAYBECLOSE]() - } +class Keyv extends EventEmitter { + constructor(uri, {emitErrors = true, ...options} = {}) { + super(); + this.opts = { + namespace: 'keyv', + serialize: JSONB.stringify, + deserialize: JSONB.parse, + ...((typeof uri === 'string') ? {uri} : uri), + ...options, + }; - super(opt) + if (!this.opts.store) { + const adapterOptions = {...this.opts}; + this.opts.store = loadStore(adapterOptions); + } - this[CHECKED_CWD] = false + if (this.opts.compression) { + const compression = this.opts.compression; + this.opts.serialize = compression.serialize.bind(compression); + this.opts.deserialize = compression.deserialize.bind(compression); + } - this.reservations = pathReservations() + if (typeof this.opts.store.on === 'function' && emitErrors) { + this.opts.store.on('error', error => this.emit('error', error)); + } - this.transform = typeof opt.transform === 'function' ? opt.transform : null + this.opts.store.namespace = this.opts.namespace; - this.writable = true - this.readable = false + const generateIterator = iterator => async function * () { + for await (const [key, raw] of typeof iterator === 'function' + ? iterator(this.opts.store.namespace) + : iterator) { + const data = await this.opts.deserialize(raw); + if (this.opts.store.namespace && !key.includes(this.opts.store.namespace)) { + continue; + } - this[PENDING] = 0 - this[ENDED] = false + if (typeof data.expires === 'number' && Date.now() > data.expires) { + this.delete(key); + continue; + } - this.dirCache = opt.dirCache || new Map() + yield [this._getKeyUnprefix(key), data.value]; + } + }; - if (typeof opt.uid === 'number' || typeof opt.gid === 'number') { - // need both or neither - if (typeof opt.uid !== 'number' || typeof opt.gid !== 'number') { - throw new TypeError('cannot set owner without number uid and gid') - } - if (opt.preserveOwner) { - throw new TypeError( - 'cannot preserve owner in archive and also set owner explicitly') - } - this.uid = opt.uid - this.gid = opt.gid - this.setOwner = true - } else { - this.uid = null - this.gid = null - this.setOwner = false - } + // Attach iterators + if (typeof this.opts.store[Symbol.iterator] === 'function' && this.opts.store instanceof Map) { + this.iterator = generateIterator(this.opts.store); + } else if (typeof this.opts.store.iterator === 'function' && this.opts.store.opts + && this._checkIterableAdaptar()) { + this.iterator = generateIterator(this.opts.store.iterator.bind(this.opts.store)); + } + } - // default true for root - if (opt.preserveOwner === undefined && typeof opt.uid !== 'number') { - this.preserveOwner = process.getuid && process.getuid() === 0 - } else { - this.preserveOwner = !!opt.preserveOwner - } + _checkIterableAdaptar() { + return iterableAdapters.includes(this.opts.store.opts.dialect) + || iterableAdapters.findIndex(element => this.opts.store.opts.url.includes(element)) >= 0; + } - this.processUid = (this.preserveOwner || this.setOwner) && process.getuid ? - process.getuid() : null - this.processGid = (this.preserveOwner || this.setOwner) && process.getgid ? - process.getgid() : null + _getKeyPrefix(key) { + return `${this.opts.namespace}:${key}`; + } - // mostly just for testing, but useful in some cases. - // Forcibly trigger a chown on every entry, no matter what - this.forceChown = opt.forceChown === true + _getKeyPrefixArray(keys) { + return keys.map(key => `${this.opts.namespace}:${key}`); + } - // turn > store.get(key)) + .then(data => (typeof data === 'string') ? this.opts.deserialize(data) : (this.opts.compression ? this.opts.deserialize(data) : data)) + .then(data => { + if (data === undefined || data === null) { + return undefined; + } - // do not unpack over ANY files - this.keep = !!opt.keep + if (typeof data.expires === 'number' && Date.now() > data.expires) { + return this.delete(key).then(() => undefined); + } - // do not set mtime/atime of extracted entries - this.noMtime = !!opt.noMtime + return (options && options.raw) ? data : data.value; + }), + ); + } - // allow .., absolute path entries, and unpacking through symlinks - // without this, warn and skip .., relativize absolutes, and error - // on symlinks in extraction path - this.preservePaths = !!opt.preservePaths + return Promise.allSettled(promises) + .then(values => { + const data = []; + for (const value of values) { + data.push(value.value); + } - // unlink files and links before writing. This breaks existing hard - // links, and removes symlink directories rather than erroring - this.unlink = !!opt.unlink + return data; + }); + } - this.cwd = normPath(path.resolve(opt.cwd || process.cwd())) - this.strip = +opt.strip || 0 - // if we're not chmodding, then we don't need the process umask - this.processUmask = opt.noChmod ? 0 : process.umask() - this.umask = typeof opt.umask === 'number' ? opt.umask : this.processUmask + return Promise.resolve() + .then(() => isArray ? store.getMany(keyPrefixed) : store.get(keyPrefixed)) + .then(data => (typeof data === 'string') ? this.opts.deserialize(data) : (this.opts.compression ? this.opts.deserialize(data) : data)) + .then(data => { + if (data === undefined || data === null) { + return undefined; + } - // default mode for dirs created as parents - this.dmode = opt.dmode || (0o0777 & (~this.umask)) - this.fmode = opt.fmode || (0o0666 & (~this.umask)) + if (isArray) { + const result = []; - this.on('entry', entry => this[ONENTRY](entry)) - } + for (let row of data) { + if ((typeof row === 'string')) { + row = this.opts.deserialize(row); + } - // a bad or damaged archive is a warning for Parser, but an error - // when extracting. Mark those errors as unrecoverable, because - // the Unpack contract cannot be met. - warn (code, msg, data = {}) { - if (code === 'TAR_BAD_ARCHIVE' || code === 'TAR_ABORT') { - data.recoverable = false - } - return super.warn(code, msg, data) - } + if (row === undefined || row === null) { + result.push(undefined); + continue; + } - [MAYBECLOSE] () { - if (this[ENDED] && this[PENDING] === 0) { - this.emit('prefinish') - this.emit('finish') - this.emit('end') - } - } + if (typeof row.expires === 'number' && Date.now() > row.expires) { + this.delete(key).then(() => undefined); + result.push(undefined); + } else { + result.push((options && options.raw) ? row : row.value); + } + } - [CHECKPATH] (entry) { - if (this.strip) { - const parts = normPath(entry.path).split('/') - if (parts.length < this.strip) { - return false - } - entry.path = parts.slice(this.strip).join('/') + return result; + } - if (entry.type === 'Link') { - const linkparts = normPath(entry.linkpath).split('/') - if (linkparts.length >= this.strip) { - entry.linkpath = linkparts.slice(this.strip).join('/') - } else { - return false - } - } - } + if (typeof data.expires === 'number' && Date.now() > data.expires) { + return this.delete(key).then(() => undefined); + } - if (!this.preservePaths) { - const p = normPath(entry.path) - const parts = p.split('/') - if (parts.includes('..') || isWindows && /^[a-z]:\.\.$/i.test(parts[0])) { - this.warn('TAR_ENTRY_ERROR', `path contains '..'`, { - entry, - path: p, - }) - return false - } + return (options && options.raw) ? data : data.value; + }); + } - // strip off the root - const [root, stripped] = stripAbsolutePath(p) - if (root) { - entry.path = stripped - this.warn('TAR_ENTRY_INFO', `stripping ${root} from absolute path`, { - entry, - path: p, - }) - } - } + set(key, value, ttl) { + const keyPrefixed = this._getKeyPrefix(key); + if (typeof ttl === 'undefined') { + ttl = this.opts.ttl; + } - if (path.isAbsolute(entry.path)) { - entry.absolute = normPath(path.resolve(entry.path)) - } else { - entry.absolute = normPath(path.resolve(this.cwd, entry.path)) - } - - // if we somehow ended up with a path that escapes the cwd, and we are - // not in preservePaths mode, then something is fishy! This should have - // been prevented above, so ignore this for coverage. - /* istanbul ignore if - defense in depth */ - if (!this.preservePaths && - entry.absolute.indexOf(this.cwd + '/') !== 0 && - entry.absolute !== this.cwd) { - this.warn('TAR_ENTRY_ERROR', 'path escaped extraction target', { - entry, - path: normPath(entry.path), - resolvedPath: entry.absolute, - cwd: this.cwd, - }) - return false - } + if (ttl === 0) { + ttl = undefined; + } - // an archive can set properties on the extraction directory, but it - // may not replace the cwd with a different kind of thing entirely. - if (entry.absolute === this.cwd && - entry.type !== 'Directory' && - entry.type !== 'GNUDumpDir') { - return false - } + const {store} = this.opts; - // only encode : chars that aren't drive letter indicators - if (this.win32) { - const { root: aRoot } = path.win32.parse(entry.absolute) - entry.absolute = aRoot + wc.encode(entry.absolute.slice(aRoot.length)) - const { root: pRoot } = path.win32.parse(entry.path) - entry.path = pRoot + wc.encode(entry.path.slice(pRoot.length)) - } + return Promise.resolve() + .then(() => { + const expires = (typeof ttl === 'number') ? (Date.now() + ttl) : null; + if (typeof value === 'symbol') { + this.emit('error', 'symbol cannot be serialized'); + } - return true - } + value = {value, expires}; + return this.opts.serialize(value); + }) + .then(value => store.set(keyPrefixed, value, ttl)) + .then(() => true); + } - [ONENTRY] (entry) { - if (!this[CHECKPATH](entry)) { - return entry.resume() - } + delete(key) { + const {store} = this.opts; + if (Array.isArray(key)) { + const keyPrefixed = this._getKeyPrefixArray(key); + if (store.deleteMany === undefined) { + const promises = []; + for (const key of keyPrefixed) { + promises.push(store.delete(key)); + } - assert.equal(typeof entry.absolute, 'string') + return Promise.allSettled(promises) + .then(values => values.every(x => x.value === true)); + } - switch (entry.type) { - case 'Directory': - case 'GNUDumpDir': - if (entry.mode) { - entry.mode = entry.mode | 0o700 - } + return Promise.resolve() + .then(() => store.deleteMany(keyPrefixed)); + } - // eslint-disable-next-line no-fallthrough - case 'File': - case 'OldFile': - case 'ContiguousFile': - case 'Link': - case 'SymbolicLink': - return this[CHECKFS](entry) + const keyPrefixed = this._getKeyPrefix(key); + return Promise.resolve() + .then(() => store.delete(keyPrefixed)); + } - case 'CharacterDevice': - case 'BlockDevice': - case 'FIFO': - default: - return this[UNSUPPORTED](entry) - } - } + clear() { + const {store} = this.opts; + return Promise.resolve() + .then(() => store.clear()); + } - [ONERROR] (er, entry) { - // Cwd has to exist, or else nothing works. That's serious. - // Other errors are warnings, which raise the error in strict - // mode, but otherwise continue on. - if (er.name === 'CwdError') { - this.emit('error', er) - } else { - this.warn('TAR_ENTRY_ERROR', er, { entry }) - this[UNPEND]() - entry.resume() - } - } + has(key) { + const keyPrefixed = this._getKeyPrefix(key); + const {store} = this.opts; + return Promise.resolve() + .then(async () => { + if (typeof store.has === 'function') { + return store.has(keyPrefixed); + } - [MKDIR] (dir, mode, cb) { - mkdir(normPath(dir), { - uid: this.uid, - gid: this.gid, - processUid: this.processUid, - processGid: this.processGid, - umask: this.processUmask, - preserve: this.preservePaths, - unlink: this.unlink, - cache: this.dirCache, - cwd: this.cwd, - mode: mode, - noChmod: this.noChmod, - }, cb) - } + const value = await store.get(keyPrefixed); + return value !== undefined; + }); + } - [DOCHOWN] (entry) { - // in preserve owner mode, chown if the entry doesn't match process - // in set owner mode, chown if setting doesn't match process - return this.forceChown || - this.preserveOwner && - (typeof entry.uid === 'number' && entry.uid !== this.processUid || - typeof entry.gid === 'number' && entry.gid !== this.processGid) - || - (typeof this.uid === 'number' && this.uid !== this.processUid || - typeof this.gid === 'number' && this.gid !== this.processGid) - } + disconnect() { + const {store} = this.opts; + if (typeof store.disconnect === 'function') { + return store.disconnect(); + } + } +} - [UID] (entry) { - return uint32(this.uid, entry.uid, this.processUid) - } +module.exports = Keyv; - [GID] (entry) { - return uint32(this.gid, entry.gid, this.processGid) - } - [FILE] (entry, fullyDone) { - const mode = entry.mode & 0o7777 || this.fmode - const stream = new fsm.WriteStream(entry.absolute, { - flags: getFlag(entry.size), - mode: mode, - autoClose: false, - }) - stream.on('error', er => { - if (stream.fd) { - fs.close(stream.fd, () => {}) - } +/***/ }), - // flush all the data out so that we aren't left hanging - // if the error wasn't actually fatal. otherwise the parse - // is blocked, and we never proceed. - stream.write = () => true - this[ONERROR](er, entry) - fullyDone() - }) +/***/ 9273: +/***/ ((module) => { - let actions = 1 - const done = er => { - if (er) { - /* istanbul ignore else - we should always have a fd by now */ - if (stream.fd) { - fs.close(stream.fd, () => {}) - } +"use strict"; - this[ONERROR](er, entry) - fullyDone() - return - } - if (--actions === 0) { - fs.close(stream.fd, er => { - if (er) { - this[ONERROR](er, entry) - } else { - this[UNPEND]() - } - fullyDone() - }) - } - } +class QuickLRU { + constructor(options = {}) { + if (!(options.maxSize && options.maxSize > 0)) { + throw new TypeError('`maxSize` must be a number greater than 0'); + } - stream.on('finish', _ => { - // if futimes fails, try utimes - // if utimes fails, fail with the original error - // same for fchown/chown - const abs = entry.absolute - const fd = stream.fd - - if (entry.mtime && !this.noMtime) { - actions++ - const atime = entry.atime || new Date() - const mtime = entry.mtime - fs.futimes(fd, atime, mtime, er => - er ? fs.utimes(abs, atime, mtime, er2 => done(er2 && er)) - : done()) - } + this.maxSize = options.maxSize; + this.onEviction = options.onEviction; + this.cache = new Map(); + this.oldCache = new Map(); + this._size = 0; + } - if (this[DOCHOWN](entry)) { - actions++ - const uid = this[UID](entry) - const gid = this[GID](entry) - fs.fchown(fd, uid, gid, er => - er ? fs.chown(abs, uid, gid, er2 => done(er2 && er)) - : done()) - } + _set(key, value) { + this.cache.set(key, value); + this._size++; - done() - }) + if (this._size >= this.maxSize) { + this._size = 0; - const tx = this.transform ? this.transform(entry) || entry : entry - if (tx !== entry) { - tx.on('error', er => { - this[ONERROR](er, entry) - fullyDone() - }) - entry.pipe(tx) - } - tx.pipe(stream) - } + if (typeof this.onEviction === 'function') { + for (const [key, value] of this.oldCache.entries()) { + this.onEviction(key, value); + } + } - [DIRECTORY] (entry, fullyDone) { - const mode = entry.mode & 0o7777 || this.dmode - this[MKDIR](entry.absolute, mode, er => { - if (er) { - this[ONERROR](er, entry) - fullyDone() - return - } + this.oldCache = this.cache; + this.cache = new Map(); + } + } - let actions = 1 - const done = _ => { - if (--actions === 0) { - fullyDone() - this[UNPEND]() - entry.resume() - } - } + get(key) { + if (this.cache.has(key)) { + return this.cache.get(key); + } - if (entry.mtime && !this.noMtime) { - actions++ - fs.utimes(entry.absolute, entry.atime || new Date(), entry.mtime, done) - } + if (this.oldCache.has(key)) { + const value = this.oldCache.get(key); + this.oldCache.delete(key); + this._set(key, value); + return value; + } + } - if (this[DOCHOWN](entry)) { - actions++ - fs.chown(entry.absolute, this[UID](entry), this[GID](entry), done) - } + set(key, value) { + if (this.cache.has(key)) { + this.cache.set(key, value); + } else { + this._set(key, value); + } - done() - }) - } + return this; + } - [UNSUPPORTED] (entry) { - entry.unsupported = true - this.warn('TAR_ENTRY_UNSUPPORTED', - `unsupported entry type: ${entry.type}`, { entry }) - entry.resume() - } + has(key) { + return this.cache.has(key) || this.oldCache.has(key); + } - [SYMLINK] (entry, done) { - this[LINK](entry, entry.linkpath, 'symlink', done) - } + peek(key) { + if (this.cache.has(key)) { + return this.cache.get(key); + } - [HARDLINK] (entry, done) { - const linkpath = normPath(path.resolve(this.cwd, entry.linkpath)) - this[LINK](entry, linkpath, 'link', done) - } + if (this.oldCache.has(key)) { + return this.oldCache.get(key); + } + } - [PEND] () { - this[PENDING]++ - } + delete(key) { + const deleted = this.cache.delete(key); + if (deleted) { + this._size--; + } - [UNPEND] () { - this[PENDING]-- - this[MAYBECLOSE]() - } + return this.oldCache.delete(key) || deleted; + } - [SKIP] (entry) { - this[UNPEND]() - entry.resume() - } + clear() { + this.cache.clear(); + this.oldCache.clear(); + this._size = 0; + } - // Check if we can reuse an existing filesystem entry safely and - // overwrite it, rather than unlinking and recreating - // Windows doesn't report a useful nlink, so we just never reuse entries - [ISREUSABLE] (entry, st) { - return entry.type === 'File' && - !this.unlink && - st.isFile() && - st.nlink <= 1 && - !isWindows - } + * keys() { + for (const [key] of this) { + yield key; + } + } - // check if a thing is there, and if so, try to clobber it - [CHECKFS] (entry) { - this[PEND]() - const paths = [entry.path] - if (entry.linkpath) { - paths.push(entry.linkpath) - } - this.reservations.reserve(paths, done => this[CHECKFS2](entry, done)) - } + * values() { + for (const [, value] of this) { + yield value; + } + } - [PRUNECACHE] (entry) { - // if we are not creating a directory, and the path is in the dirCache, - // then that means we are about to delete the directory we created - // previously, and it is no longer going to be a directory, and neither - // is any of its children. - // If a symbolic link is encountered, all bets are off. There is no - // reasonable way to sanitize the cache in such a way we will be able to - // avoid having filesystem collisions. If this happens with a non-symlink - // entry, it'll just fail to unpack, but a symlink to a directory, using an - // 8.3 shortname or certain unicode attacks, can evade detection and lead - // to arbitrary writes to anywhere on the system. - if (entry.type === 'SymbolicLink') { - dropCache(this.dirCache) - } else if (entry.type !== 'Directory') { - pruneCache(this.dirCache, entry.absolute) - } - } + * [Symbol.iterator]() { + for (const item of this.cache) { + yield item; + } - [CHECKFS2] (entry, fullyDone) { - this[PRUNECACHE](entry) + for (const item of this.oldCache) { + const [key] = item; + if (!this.cache.has(key)) { + yield item; + } + } + } - const done = er => { - this[PRUNECACHE](entry) - fullyDone(er) - } + get size() { + let oldCacheSize = 0; + for (const key of this.oldCache.keys()) { + if (!this.cache.has(key)) { + oldCacheSize++; + } + } - const checkCwd = () => { - this[MKDIR](this.cwd, this.dmode, er => { - if (er) { - this[ONERROR](er, entry) - done() - return - } - this[CHECKED_CWD] = true - start() - }) - } + return Math.min(this._size + oldCacheSize, this.maxSize); + } +} - const start = () => { - if (entry.absolute !== this.cwd) { - const parent = normPath(path.dirname(entry.absolute)) - if (parent !== this.cwd) { - return this[MKDIR](parent, this.dmode, er => { - if (er) { - this[ONERROR](er, entry) - done() - return - } - afterMakeParent() - }) - } - } - afterMakeParent() - } +module.exports = QuickLRU; - const afterMakeParent = () => { - fs.lstat(entry.absolute, (lstatEr, st) => { - if (st && (this.keep || this.newer && st.mtime > entry.mtime)) { - this[SKIP](entry) - done() - return - } - if (lstatEr || this[ISREUSABLE](entry, st)) { - return this[MAKEFS](null, entry, done) - } - if (st.isDirectory()) { - if (entry.type === 'Directory') { - const needChmod = !this.noChmod && - entry.mode && - (st.mode & 0o7777) !== entry.mode - const afterChmod = er => this[MAKEFS](er, entry, done) - if (!needChmod) { - return afterChmod() - } - return fs.chmod(entry.absolute, entry.mode, afterChmod) - } - // Not a dir entry, have to remove it. - // NB: the only way to end up with an entry that is the cwd - // itself, in such a way that == does not detect, is a - // tricky windows absolute path with UNC or 8.3 parts (and - // preservePaths:true, or else it will have been stripped). - // In that case, the user has opted out of path protections - // explicitly, so if they blow away the cwd, c'est la vie. - if (entry.absolute !== this.cwd) { - return fs.rmdir(entry.absolute, er => - this[MAKEFS](er, entry, done)) - } - } +/***/ }), - // not a dir, and not reusable - // don't remove if the cwd, we want that error - if (entry.absolute === this.cwd) { - return this[MAKEFS](null, entry, done) - } +/***/ 6624: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - unlinkFile(entry.absolute, er => - this[MAKEFS](er, entry, done)) - }) - } +"use strict"; - if (this[CHECKED_CWD]) { - start() - } else { - checkCwd() - } - } +const tls = __nccwpck_require__(4404); - [MAKEFS] (er, entry, done) { - if (er) { - this[ONERROR](er, entry) - done() - return - } +module.exports = (options = {}, connect = tls.connect) => new Promise((resolve, reject) => { + let timeout = false; - switch (entry.type) { - case 'File': - case 'OldFile': - case 'ContiguousFile': - return this[FILE](entry, done) + let socket; - case 'Link': - return this[HARDLINK](entry, done) + const callback = async () => { + await socketPromise; - case 'SymbolicLink': - return this[SYMLINK](entry, done) + socket.off('timeout', onTimeout); + socket.off('error', reject); - case 'Directory': - case 'GNUDumpDir': - return this[DIRECTORY](entry, done) - } - } + if (options.resolveSocket) { + resolve({alpnProtocol: socket.alpnProtocol, socket, timeout}); - [LINK] (entry, linkpath, link, done) { - // XXX: get the type ('symlink' or 'junction') for windows - fs[link](linkpath, entry.absolute, er => { - if (er) { - this[ONERROR](er, entry) - } else { - this[UNPEND]() - entry.resume() - } - done() - }) - } -} + if (timeout) { + await Promise.resolve(); + socket.emit('timeout'); + } + } else { + socket.destroy(); + resolve({alpnProtocol: socket.alpnProtocol, timeout}); + } + }; -const callSync = fn => { - try { - return [null, fn()] - } catch (er) { - return [er, null] - } -} -class UnpackSync extends Unpack { - [MAKEFS] (er, entry) { - return super[MAKEFS](er, entry, () => {}) - } + const onTimeout = async () => { + timeout = true; + callback(); + }; - [CHECKFS] (entry) { - this[PRUNECACHE](entry) + const socketPromise = (async () => { + try { + socket = await connect(options, callback); - if (!this[CHECKED_CWD]) { - const er = this[MKDIR](this.cwd, this.dmode) - if (er) { - return this[ONERROR](er, entry) - } - this[CHECKED_CWD] = true - } + socket.on('error', reject); + socket.once('timeout', onTimeout); + } catch (error) { + reject(error); + } + })(); +}); - // don't bother to make the parent if the current entry is the cwd, - // we've already checked it. - if (entry.absolute !== this.cwd) { - const parent = normPath(path.dirname(entry.absolute)) - if (parent !== this.cwd) { - const mkParent = this[MKDIR](parent, this.dmode) - if (mkParent) { - return this[ONERROR](mkParent, entry) - } - } - } - const [lstatEr, st] = callSync(() => fs.lstatSync(entry.absolute)) - if (st && (this.keep || this.newer && st.mtime > entry.mtime)) { - return this[SKIP](entry) - } +/***/ }), - if (lstatEr || this[ISREUSABLE](entry, st)) { - return this[MAKEFS](null, entry) - } +/***/ 5911: +/***/ ((module, exports) => { - if (st.isDirectory()) { - if (entry.type === 'Directory') { - const needChmod = !this.noChmod && - entry.mode && - (st.mode & 0o7777) !== entry.mode - const [er] = needChmod ? callSync(() => { - fs.chmodSync(entry.absolute, entry.mode) - }) : [] - return this[MAKEFS](er, entry) - } - // not a dir entry, have to remove it - const [er] = callSync(() => fs.rmdirSync(entry.absolute)) - this[MAKEFS](er, entry) - } +exports = module.exports = SemVer - // not a dir, and not reusable. - // don't remove if it's the cwd, since we want that error. - const [er] = entry.absolute === this.cwd ? [] - : callSync(() => unlinkFileSync(entry.absolute)) - this[MAKEFS](er, entry) +var debug +/* istanbul ignore next */ +if (typeof process === 'object' && + process.env && + process.env.NODE_DEBUG && + /\bsemver\b/i.test(process.env.NODE_DEBUG)) { + debug = function () { + var args = Array.prototype.slice.call(arguments, 0) + args.unshift('SEMVER') + console.log.apply(console, args) } +} else { + debug = function () {} +} - [FILE] (entry, done) { - const mode = entry.mode & 0o7777 || this.fmode - - const oner = er => { - let closeError - try { - fs.closeSync(fd) - } catch (e) { - closeError = e - } - if (er || closeError) { - this[ONERROR](er || closeError, entry) - } - done() - } - - let fd - try { - fd = fs.openSync(entry.absolute, getFlag(entry.size), mode) - } catch (er) { - return oner(er) - } - const tx = this.transform ? this.transform(entry) || entry : entry - if (tx !== entry) { - tx.on('error', er => this[ONERROR](er, entry)) - entry.pipe(tx) - } +// Note: this is the semver.org version of the spec that it implements +// Not necessarily the package version of this code. +exports.SEMVER_SPEC_VERSION = '2.0.0' - tx.on('data', chunk => { - try { - fs.writeSync(fd, chunk, 0, chunk.length) - } catch (er) { - oner(er) - } - }) +var MAX_LENGTH = 256 +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || + /* istanbul ignore next */ 9007199254740991 - tx.on('end', _ => { - let er = null - // try both, falling futimes back to utimes - // if either fails, handle the first error - if (entry.mtime && !this.noMtime) { - const atime = entry.atime || new Date() - const mtime = entry.mtime - try { - fs.futimesSync(fd, atime, mtime) - } catch (futimeser) { - try { - fs.utimesSync(entry.absolute, atime, mtime) - } catch (utimeser) { - er = futimeser - } - } - } +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16 - if (this[DOCHOWN](entry)) { - const uid = this[UID](entry) - const gid = this[GID](entry) +var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6 - try { - fs.fchownSync(fd, uid, gid) - } catch (fchowner) { - try { - fs.chownSync(entry.absolute, uid, gid) - } catch (chowner) { - er = er || fchowner - } - } - } +// The actual regexps go on exports.re +var re = exports.re = [] +var safeRe = exports.safeRe = [] +var src = exports.src = [] +var t = exports.tokens = {} +var R = 0 - oner(er) - }) - } +function tok (n) { + t[n] = R++ +} - [DIRECTORY] (entry, done) { - const mode = entry.mode & 0o7777 || this.dmode - const er = this[MKDIR](entry.absolute, mode) - if (er) { - this[ONERROR](er, entry) - done() - return - } - if (entry.mtime && !this.noMtime) { - try { - fs.utimesSync(entry.absolute, entry.atime || new Date(), entry.mtime) - } catch (er) {} - } - if (this[DOCHOWN](entry)) { - try { - fs.chownSync(entry.absolute, this[UID](entry), this[GID](entry)) - } catch (er) {} - } - done() - entry.resume() - } +var LETTERDASHNUMBER = '[a-zA-Z0-9-]' - [MKDIR] (dir, mode) { - try { - return mkdir.sync(normPath(dir), { - uid: this.uid, - gid: this.gid, - processUid: this.processUid, - processGid: this.processGid, - umask: this.processUmask, - preserve: this.preservePaths, - unlink: this.unlink, - cache: this.dirCache, - cwd: this.cwd, - mode: mode, - }) - } catch (er) { - return er - } - } +// Replace some greedy regex tokens to prevent regex dos issues. These regex are +// used internally via the safeRe object since all inputs in this library get +// normalized first to trim and collapse all extra whitespace. The original +// regexes are exported for userland consumption and lower level usage. A +// future breaking change could export the safer regex only with a note that +// all input should have extra whitespace removed. +var safeRegexReplacements = [ + ['\\s', 1], + ['\\d', MAX_LENGTH], + [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], +] - [LINK] (entry, linkpath, link, done) { - try { - fs[link + 'Sync'](linkpath, entry.absolute) - done() - entry.resume() - } catch (er) { - return this[ONERROR](er, entry) - } +function makeSafeRe (value) { + for (var i = 0; i < safeRegexReplacements.length; i++) { + var token = safeRegexReplacements[i][0] + var max = safeRegexReplacements[i][1] + value = value + .split(token + '*').join(token + '{0,' + max + '}') + .split(token + '+').join(token + '{1,' + max + '}') } + return value } -Unpack.Sync = UnpackSync -module.exports = Unpack - - -/***/ }), - -/***/ 407: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - +// The following Regular Expressions can be used for tokenizing, +// validating, and parsing SemVer version strings. -// tar -u +// ## Numeric Identifier +// A single `0`, or a non-zero digit followed by zero or more digits. -const hlo = __nccwpck_require__(5213) -const r = __nccwpck_require__(5923) -// just call tar.r with the filter and mtimeCache +tok('NUMERICIDENTIFIER') +src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*' +tok('NUMERICIDENTIFIERLOOSE') +src[t.NUMERICIDENTIFIERLOOSE] = '\\d+' -module.exports = (opt_, files, cb) => { - const opt = hlo(opt_) +// ## Non-numeric Identifier +// Zero or more digits, followed by a letter or hyphen, and then zero or +// more letters, digits, or hyphens. - if (!opt.file) { - throw new TypeError('file is required') +tok('NONNUMERICIDENTIFIER') +src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-]' + LETTERDASHNUMBER + '*' + +// ## Main Version +// Three dot-separated numeric identifiers. + +tok('MAINVERSION') +src[t.MAINVERSION] = '(' + src[t.NUMERICIDENTIFIER] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIER] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIER] + ')' + +tok('MAINVERSIONLOOSE') +src[t.MAINVERSIONLOOSE] = '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')' + +// ## Pre-release Version Identifier +// A numeric identifier, or a non-numeric identifier. + +tok('PRERELEASEIDENTIFIER') +src[t.PRERELEASEIDENTIFIER] = '(?:' + src[t.NUMERICIDENTIFIER] + + '|' + src[t.NONNUMERICIDENTIFIER] + ')' + +tok('PRERELEASEIDENTIFIERLOOSE') +src[t.PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[t.NUMERICIDENTIFIERLOOSE] + + '|' + src[t.NONNUMERICIDENTIFIER] + ')' + +// ## Pre-release Version +// Hyphen, followed by one or more dot-separated pre-release version +// identifiers. + +tok('PRERELEASE') +src[t.PRERELEASE] = '(?:-(' + src[t.PRERELEASEIDENTIFIER] + + '(?:\\.' + src[t.PRERELEASEIDENTIFIER] + ')*))' + +tok('PRERELEASELOOSE') +src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[t.PRERELEASEIDENTIFIERLOOSE] + ')*))' + +// ## Build Metadata Identifier +// Any combination of digits, letters, or hyphens. + +tok('BUILDIDENTIFIER') +src[t.BUILDIDENTIFIER] = LETTERDASHNUMBER + '+' + +// ## Build Metadata +// Plus sign, followed by one or more period-separated build metadata +// identifiers. + +tok('BUILD') +src[t.BUILD] = '(?:\\+(' + src[t.BUILDIDENTIFIER] + + '(?:\\.' + src[t.BUILDIDENTIFIER] + ')*))' + +// ## Full Version String +// A main version, followed optionally by a pre-release version and +// build metadata. + +// Note that the only major, minor, patch, and pre-release sections of +// the version string are capturing groups. The build metadata is not a +// capturing group, because it should not ever be used in version +// comparison. + +tok('FULL') +tok('FULLPLAIN') +src[t.FULLPLAIN] = 'v?' + src[t.MAINVERSION] + + src[t.PRERELEASE] + '?' + + src[t.BUILD] + '?' + +src[t.FULL] = '^' + src[t.FULLPLAIN] + '$' + +// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. +// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty +// common in the npm registry. +tok('LOOSEPLAIN') +src[t.LOOSEPLAIN] = '[v=\\s]*' + src[t.MAINVERSIONLOOSE] + + src[t.PRERELEASELOOSE] + '?' + + src[t.BUILD] + '?' + +tok('LOOSE') +src[t.LOOSE] = '^' + src[t.LOOSEPLAIN] + '$' + +tok('GTLT') +src[t.GTLT] = '((?:<|>)?=?)' + +// Something like "2.*" or "1.2.x". +// Note that "x.x" is a valid xRange identifer, meaning "any version" +// Only the first item is strictly required. +tok('XRANGEIDENTIFIERLOOSE') +src[t.XRANGEIDENTIFIERLOOSE] = src[t.NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' +tok('XRANGEIDENTIFIER') +src[t.XRANGEIDENTIFIER] = src[t.NUMERICIDENTIFIER] + '|x|X|\\*' + +tok('XRANGEPLAIN') +src[t.XRANGEPLAIN] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' + + '(?:' + src[t.PRERELEASE] + ')?' + + src[t.BUILD] + '?' + + ')?)?' + +tok('XRANGEPLAINLOOSE') +src[t.XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[t.PRERELEASELOOSE] + ')?' + + src[t.BUILD] + '?' + + ')?)?' + +tok('XRANGE') +src[t.XRANGE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAIN] + '$' +tok('XRANGELOOSE') +src[t.XRANGELOOSE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAINLOOSE] + '$' + +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +tok('COERCE') +src[t.COERCE] = '(^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])' +tok('COERCERTL') +re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g') +safeRe[t.COERCERTL] = new RegExp(makeSafeRe(src[t.COERCE]), 'g') + +// Tilde ranges. +// Meaning is "reasonably at or greater than" +tok('LONETILDE') +src[t.LONETILDE] = '(?:~>?)' + +tok('TILDETRIM') +src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+' +re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g') +safeRe[t.TILDETRIM] = new RegExp(makeSafeRe(src[t.TILDETRIM]), 'g') +var tildeTrimReplace = '$1~' + +tok('TILDE') +src[t.TILDE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAIN] + '$' +tok('TILDELOOSE') +src[t.TILDELOOSE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAINLOOSE] + '$' + +// Caret ranges. +// Meaning is "at least and backwards compatible with" +tok('LONECARET') +src[t.LONECARET] = '(?:\\^)' + +tok('CARETTRIM') +src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+' +re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g') +safeRe[t.CARETTRIM] = new RegExp(makeSafeRe(src[t.CARETTRIM]), 'g') +var caretTrimReplace = '$1^' + +tok('CARET') +src[t.CARET] = '^' + src[t.LONECARET] + src[t.XRANGEPLAIN] + '$' +tok('CARETLOOSE') +src[t.CARETLOOSE] = '^' + src[t.LONECARET] + src[t.XRANGEPLAINLOOSE] + '$' + +// A simple gt/lt/eq thing, or just "" to indicate "any version" +tok('COMPARATORLOOSE') +src[t.COMPARATORLOOSE] = '^' + src[t.GTLT] + '\\s*(' + src[t.LOOSEPLAIN] + ')$|^$' +tok('COMPARATOR') +src[t.COMPARATOR] = '^' + src[t.GTLT] + '\\s*(' + src[t.FULLPLAIN] + ')$|^$' + +// An expression to strip any whitespace between the gtlt and the thing +// it modifies, so that `> 1.2.3` ==> `>1.2.3` +tok('COMPARATORTRIM') +src[t.COMPARATORTRIM] = '(\\s*)' + src[t.GTLT] + + '\\s*(' + src[t.LOOSEPLAIN] + '|' + src[t.XRANGEPLAIN] + ')' + +// this one has to use the /g flag +re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g') +safeRe[t.COMPARATORTRIM] = new RegExp(makeSafeRe(src[t.COMPARATORTRIM]), 'g') +var comparatorTrimReplace = '$1$2$3' + +// Something like `1.2.3 - 1.2.4` +// Note that these all use the loose form, because they'll be +// checked against either the strict or loose comparator form +// later. +tok('HYPHENRANGE') +src[t.HYPHENRANGE] = '^\\s*(' + src[t.XRANGEPLAIN] + ')' + + '\\s+-\\s+' + + '(' + src[t.XRANGEPLAIN] + ')' + + '\\s*$' + +tok('HYPHENRANGELOOSE') +src[t.HYPHENRANGELOOSE] = '^\\s*(' + src[t.XRANGEPLAINLOOSE] + ')' + + '\\s+-\\s+' + + '(' + src[t.XRANGEPLAINLOOSE] + ')' + + '\\s*$' + +// Star ranges basically just allow anything at all. +tok('STAR') +src[t.STAR] = '(<|>)?=?\\s*\\*' + +// Compile to actual regexp objects. +// All are flag-free, unless they were created above with a flag. +for (var i = 0; i < R; i++) { + debug(i, src[i]) + if (!re[i]) { + re[i] = new RegExp(src[i]) + + // Replace all greedy whitespace to prevent regex dos issues. These regex are + // used internally via the safeRe object since all inputs in this library get + // normalized first to trim and collapse all extra whitespace. The original + // regexes are exported for userland consumption and lower level usage. A + // future breaking change could export the safer regex only with a note that + // all input should have extra whitespace removed. + safeRe[i] = new RegExp(makeSafeRe(src[i])) + } +} + +exports.parse = parse +function parse (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + if (version instanceof SemVer) { + return version + } + + if (typeof version !== 'string') { + return null } - if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { - throw new TypeError('cannot append to compressed archives') + if (version.length > MAX_LENGTH) { + return null } - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') + var r = options.loose ? safeRe[t.LOOSE] : safeRe[t.FULL] + if (!r.test(version)) { + return null } - files = Array.from(files) - - mtimeFilter(opt) - return r(opt, files, cb) -} - -const mtimeFilter = opt => { - const filter = opt.filter - - if (!opt.mtimeCache) { - opt.mtimeCache = new Map() + try { + return new SemVer(version, options) + } catch (er) { + return null } - - opt.filter = filter ? (path, stat) => - filter(path, stat) && !(opt.mtimeCache.get(path) > stat.mtime) - : (path, stat) => !(opt.mtimeCache.get(path) > stat.mtime) } +exports.valid = valid +function valid (version, options) { + var v = parse(version, options) + return v ? v.version : null +} -/***/ }), - -/***/ 5899: -/***/ ((module) => { +exports.clean = clean +function clean (version, options) { + var s = parse(version.trim().replace(/^[=v]+/, ''), options) + return s ? s.version : null +} -"use strict"; +exports.SemVer = SemVer -module.exports = Base => class extends Base { - warn (code, message, data = {}) { - if (this.file) { - data.file = this.file - } - if (this.cwd) { - data.cwd = this.cwd +function SemVer (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false } - data.code = message instanceof Error && message.code || code - data.tarCode = code - if (!this.strict && data.recoverable !== false) { - if (message instanceof Error) { - data = Object.assign(message, data) - message = message.message - } - this.emit('warn', data.tarCode, message, data) - } else if (message instanceof Error) { - this.emit('error', Object.assign(message, data)) + } + if (version instanceof SemVer) { + if (version.loose === options.loose) { + return version } else { - this.emit('error', Object.assign(new Error(`${code}: ${message}`), data)) + version = version.version } + } else if (typeof version !== 'string') { + throw new TypeError('Invalid Version: ' + version) } -} - - -/***/ }), - -/***/ 4808: -/***/ ((module) => { - -"use strict"; - - -// When writing files on Windows, translate the characters to their -// 0xf000 higher-encoded versions. - -const raw = [ - '|', - '<', - '>', - '?', - ':', -] - -const win = raw.map(char => - String.fromCharCode(0xf000 + char.charCodeAt(0))) - -const toWin = new Map(raw.map((char, i) => [char, win[i]])) -const toRaw = new Map(win.map((char, i) => [char, raw[i]])) - -module.exports = { - encode: s => raw.reduce((s, c) => s.split(c).join(toWin.get(c)), s), - decode: s => win.reduce((s, c) => s.split(c).join(toRaw.get(c)), s), -} + if (version.length > MAX_LENGTH) { + throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + } -/***/ }), + if (!(this instanceof SemVer)) { + return new SemVer(version, options) + } -/***/ 5450: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + debug('SemVer', version, options) + this.options = options + this.loose = !!options.loose -"use strict"; + var m = version.trim().match(options.loose ? safeRe[t.LOOSE] : safeRe[t.FULL]) -const { Minipass } = __nccwpck_require__(6684) -const Pax = __nccwpck_require__(7996) -const Header = __nccwpck_require__(6043) -const fs = __nccwpck_require__(7147) -const path = __nccwpck_require__(1017) -const normPath = __nccwpck_require__(6843) -const stripSlash = __nccwpck_require__(8886) - -const prefixPath = (path, prefix) => { - if (!prefix) { - return normPath(path) + if (!m) { + throw new TypeError('Invalid Version: ' + version) } - path = normPath(path).replace(/^\.(\/|$)/, '') - return stripSlash(prefix) + '/' + path -} - -const maxReadSize = 16 * 1024 * 1024 -const PROCESS = Symbol('process') -const FILE = Symbol('file') -const DIRECTORY = Symbol('directory') -const SYMLINK = Symbol('symlink') -const HARDLINK = Symbol('hardlink') -const HEADER = Symbol('header') -const READ = Symbol('read') -const LSTAT = Symbol('lstat') -const ONLSTAT = Symbol('onlstat') -const ONREAD = Symbol('onread') -const ONREADLINK = Symbol('onreadlink') -const OPENFILE = Symbol('openfile') -const ONOPENFILE = Symbol('onopenfile') -const CLOSE = Symbol('close') -const MODE = Symbol('mode') -const AWAITDRAIN = Symbol('awaitDrain') -const ONDRAIN = Symbol('ondrain') -const PREFIX = Symbol('prefix') -const HAD_ERROR = Symbol('hadError') -const warner = __nccwpck_require__(5899) -const winchars = __nccwpck_require__(4808) -const stripAbsolutePath = __nccwpck_require__(7111) - -const modeFix = __nccwpck_require__(8371) - -const WriteEntry = warner(class WriteEntry extends Minipass { - constructor (p, opt) { - opt = opt || {} - super(opt) - if (typeof p !== 'string') { - throw new TypeError('path is required') - } - this.path = normPath(p) - // suppress atime, ctime, uid, gid, uname, gname - this.portable = !!opt.portable - // until node has builtin pwnam functions, this'll have to do - this.myuid = process.getuid && process.getuid() || 0 - this.myuser = process.env.USER || '' - this.maxReadSize = opt.maxReadSize || maxReadSize - this.linkCache = opt.linkCache || new Map() - this.statCache = opt.statCache || new Map() - this.preservePaths = !!opt.preservePaths - this.cwd = normPath(opt.cwd || process.cwd()) - this.strict = !!opt.strict - this.noPax = !!opt.noPax - this.noMtime = !!opt.noMtime - this.mtime = opt.mtime || null - this.prefix = opt.prefix ? normPath(opt.prefix) : null - - this.fd = null - this.blockLen = null - this.blockRemain = null - this.buf = null - this.offset = null - this.length = null - this.pos = null - this.remain = null - - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - - let pathWarn = false - if (!this.preservePaths) { - const [root, stripped] = stripAbsolutePath(this.path) - if (root) { - this.path = stripped - pathWarn = root - } - } - this.win32 = !!opt.win32 || process.platform === 'win32' - if (this.win32) { - // force the \ to / normalization, since we might not *actually* - // be on windows, but want \ to be considered a path separator. - this.path = winchars.decode(this.path.replace(/\\/g, '/')) - p = p.replace(/\\/g, '/') - } - - this.absolute = normPath(opt.absolute || path.resolve(this.cwd, p)) + this.raw = version - if (this.path === '') { - this.path = './' - } + // these are actually numbers + this.major = +m[1] + this.minor = +m[2] + this.patch = +m[3] - if (pathWarn) { - this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, { - entry: this, - path: pathWarn + this.path, - }) - } + if (this.major > MAX_SAFE_INTEGER || this.major < 0) { + throw new TypeError('Invalid major version') + } - if (this.statCache.has(this.absolute)) { - this[ONLSTAT](this.statCache.get(this.absolute)) - } else { - this[LSTAT]() - } + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { + throw new TypeError('Invalid minor version') } - emit (ev, ...data) { - if (ev === 'error') { - this[HAD_ERROR] = true - } - return super.emit(ev, ...data) + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { + throw new TypeError('Invalid patch version') } - [LSTAT] () { - fs.lstat(this.absolute, (er, stat) => { - if (er) { - return this.emit('error', er) + // numberify any prerelease numeric ids + if (!m[4]) { + this.prerelease = [] + } else { + this.prerelease = m[4].split('.').map(function (id) { + if (/^[0-9]+$/.test(id)) { + var num = +id + if (num >= 0 && num < MAX_SAFE_INTEGER) { + return num + } } - this[ONLSTAT](stat) + return id }) } - [ONLSTAT] (stat) { - this.statCache.set(this.absolute, stat) - this.stat = stat - if (!stat.isFile()) { - stat.size = 0 - } - this.type = getType(stat) - this.emit('stat', stat) - this[PROCESS]() - } + this.build = m[5] ? m[5].split('.') : [] + this.format() +} - [PROCESS] () { - switch (this.type) { - case 'File': return this[FILE]() - case 'Directory': return this[DIRECTORY]() - case 'SymbolicLink': return this[SYMLINK]() - // unsupported types are ignored. - default: return this.end() - } +SemVer.prototype.format = function () { + this.version = this.major + '.' + this.minor + '.' + this.patch + if (this.prerelease.length) { + this.version += '-' + this.prerelease.join('.') } + return this.version +} - [MODE] (mode) { - return modeFix(mode, this.type === 'Directory', this.portable) +SemVer.prototype.toString = function () { + return this.version +} + +SemVer.prototype.compare = function (other) { + debug('SemVer.compare', this.version, this.options, other) + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) } - [PREFIX] (path) { - return prefixPath(path, this.prefix) + return this.compareMain(other) || this.comparePre(other) +} + +SemVer.prototype.compareMain = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) } - [HEADER] () { - if (this.type === 'Directory' && this.portable) { - this.noMtime = true - } - - this.header = new Header({ - path: this[PREFIX](this.path), - // only apply the prefix to hard links. - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - // only the permissions and setuid/setgid/sticky bitflags - // not the higher-order bits that specify file type - mode: this[MODE](this.stat.mode), - uid: this.portable ? null : this.stat.uid, - gid: this.portable ? null : this.stat.gid, - size: this.stat.size, - mtime: this.noMtime ? null : this.mtime || this.stat.mtime, - type: this.type, - uname: this.portable ? null : - this.stat.uid === this.myuid ? this.myuser : '', - atime: this.portable ? null : this.stat.atime, - ctime: this.portable ? null : this.stat.ctime, - }) + return compareIdentifiers(this.major, other.major) || + compareIdentifiers(this.minor, other.minor) || + compareIdentifiers(this.patch, other.patch) +} + +SemVer.prototype.comparePre = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } - if (this.header.encode() && !this.noPax) { - super.write(new Pax({ - atime: this.portable ? null : this.header.atime, - ctime: this.portable ? null : this.header.ctime, - gid: this.portable ? null : this.header.gid, - mtime: this.noMtime ? null : this.mtime || this.header.mtime, - path: this[PREFIX](this.path), - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - size: this.header.size, - uid: this.portable ? null : this.header.uid, - uname: this.portable ? null : this.header.uname, - dev: this.portable ? null : this.stat.dev, - ino: this.portable ? null : this.stat.ino, - nlink: this.portable ? null : this.stat.nlink, - }).encode()) - } - super.write(this.header.block) + // NOT having a prerelease is > having one + if (this.prerelease.length && !other.prerelease.length) { + return -1 + } else if (!this.prerelease.length && other.prerelease.length) { + return 1 + } else if (!this.prerelease.length && !other.prerelease.length) { + return 0 } - [DIRECTORY] () { - if (this.path.slice(-1) !== '/') { - this.path += '/' + var i = 0 + do { + var a = this.prerelease[i] + var b = other.prerelease[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) } - this.stat.size = 0 - this[HEADER]() - this.end() + } while (++i) +} + +SemVer.prototype.compareBuild = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) } - [SYMLINK] () { - fs.readlink(this.absolute, (er, linkpath) => { - if (er) { - return this.emit('error', er) + var i = 0 + do { + var a = this.build[i] + var b = other.build[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) + } + } while (++i) +} + +// preminor will bump the version up to the next minor release, and immediately +// down to pre-release. premajor and prepatch work the same way. +SemVer.prototype.inc = function (release, identifier) { + switch (release) { + case 'premajor': + this.prerelease.length = 0 + this.patch = 0 + this.minor = 0 + this.major++ + this.inc('pre', identifier) + break + case 'preminor': + this.prerelease.length = 0 + this.patch = 0 + this.minor++ + this.inc('pre', identifier) + break + case 'prepatch': + // If this is already a prerelease, it will bump to the next version + // drop any prereleases that might already exist, since they are not + // relevant at this point. + this.prerelease.length = 0 + this.inc('patch', identifier) + this.inc('pre', identifier) + break + // If the input is a non-prerelease version, this acts the same as + // prepatch. + case 'prerelease': + if (this.prerelease.length === 0) { + this.inc('patch', identifier) } - this[ONREADLINK](linkpath) - }) + this.inc('pre', identifier) + break + + case 'major': + // If this is a pre-major version, bump up to the same major version. + // Otherwise increment major. + // 1.0.0-5 bumps to 1.0.0 + // 1.1.0 bumps to 2.0.0 + if (this.minor !== 0 || + this.patch !== 0 || + this.prerelease.length === 0) { + this.major++ + } + this.minor = 0 + this.patch = 0 + this.prerelease = [] + break + case 'minor': + // If this is a pre-minor version, bump up to the same minor version. + // Otherwise increment minor. + // 1.2.0-5 bumps to 1.2.0 + // 1.2.1 bumps to 1.3.0 + if (this.patch !== 0 || this.prerelease.length === 0) { + this.minor++ + } + this.patch = 0 + this.prerelease = [] + break + case 'patch': + // If this is not a pre-release version, it will increment the patch. + // If it is a pre-release it will bump up to the same patch version. + // 1.2.0-5 patches to 1.2.0 + // 1.2.0 patches to 1.2.1 + if (this.prerelease.length === 0) { + this.patch++ + } + this.prerelease = [] + break + // This probably shouldn't be used publicly. + // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. + case 'pre': + if (this.prerelease.length === 0) { + this.prerelease = [0] + } else { + var i = this.prerelease.length + while (--i >= 0) { + if (typeof this.prerelease[i] === 'number') { + this.prerelease[i]++ + i = -2 + } + } + if (i === -1) { + // didn't increment anything + this.prerelease.push(0) + } + } + if (identifier) { + // 1.2.0-beta.1 bumps to 1.2.0-beta.2, + // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 + if (this.prerelease[0] === identifier) { + if (isNaN(this.prerelease[1])) { + this.prerelease = [identifier, 0] + } + } else { + this.prerelease = [identifier, 0] + } + } + break + + default: + throw new Error('invalid increment argument: ' + release) } + this.format() + this.raw = this.version + return this +} - [ONREADLINK] (linkpath) { - this.linkpath = normPath(linkpath) - this[HEADER]() - this.end() +exports.inc = inc +function inc (version, release, loose, identifier) { + if (typeof (loose) === 'string') { + identifier = loose + loose = undefined } - [HARDLINK] (linkpath) { - this.type = 'Link' - this.linkpath = normPath(path.relative(this.cwd, linkpath)) - this.stat.size = 0 - this[HEADER]() - this.end() + try { + return new SemVer(version, loose).inc(release, identifier).version + } catch (er) { + return null } +} - [FILE] () { - if (this.stat.nlink > 1) { - const linkKey = this.stat.dev + ':' + this.stat.ino - if (this.linkCache.has(linkKey)) { - const linkpath = this.linkCache.get(linkKey) - if (linkpath.indexOf(this.cwd) === 0) { - return this[HARDLINK](linkpath) +exports.diff = diff +function diff (version1, version2) { + if (eq(version1, version2)) { + return null + } else { + var v1 = parse(version1) + var v2 = parse(version2) + var prefix = '' + if (v1.prerelease.length || v2.prerelease.length) { + prefix = 'pre' + var defaultResult = 'prerelease' + } + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return prefix + key } } - this.linkCache.set(linkKey, this.absolute) } + return defaultResult // may be undefined + } +} - this[HEADER]() - if (this.stat.size === 0) { - return this.end() - } +exports.compareIdentifiers = compareIdentifiers - this[OPENFILE]() - } +var numeric = /^[0-9]+$/ +function compareIdentifiers (a, b) { + var anum = numeric.test(a) + var bnum = numeric.test(b) - [OPENFILE] () { - fs.open(this.absolute, 'r', (er, fd) => { - if (er) { - return this.emit('error', er) - } - this[ONOPENFILE](fd) - }) + if (anum && bnum) { + a = +a + b = +b } - [ONOPENFILE] (fd) { - this.fd = fd - if (this[HAD_ERROR]) { - return this[CLOSE]() - } - - this.blockLen = 512 * Math.ceil(this.stat.size / 512) - this.blockRemain = this.blockLen - const bufLen = Math.min(this.blockLen, this.maxReadSize) - this.buf = Buffer.allocUnsafe(bufLen) - this.offset = 0 - this.pos = 0 - this.remain = this.stat.size - this.length = this.buf.length - this[READ]() - } + return a === b ? 0 + : (anum && !bnum) ? -1 + : (bnum && !anum) ? 1 + : a < b ? -1 + : 1 +} - [READ] () { - const { fd, buf, offset, length, pos } = this - fs.read(fd, buf, offset, length, pos, (er, bytesRead) => { - if (er) { - // ignoring the error from close(2) is a bad practice, but at - // this point we already have an error, don't need another one - return this[CLOSE](() => this.emit('error', er)) - } - this[ONREAD](bytesRead) - }) - } +exports.rcompareIdentifiers = rcompareIdentifiers +function rcompareIdentifiers (a, b) { + return compareIdentifiers(b, a) +} - [CLOSE] (cb) { - fs.close(this.fd, cb) - } +exports.major = major +function major (a, loose) { + return new SemVer(a, loose).major +} - [ONREAD] (bytesRead) { - if (bytesRead <= 0 && this.remain > 0) { - const er = new Error('encountered unexpected EOF') - er.path = this.absolute - er.syscall = 'read' - er.code = 'EOF' - return this[CLOSE](() => this.emit('error', er)) - } - - if (bytesRead > this.remain) { - const er = new Error('did not encounter expected EOF') - er.path = this.absolute - er.syscall = 'read' - er.code = 'EOF' - return this[CLOSE](() => this.emit('error', er)) - } - - // null out the rest of the buffer, if we could fit the block padding - // at the end of this loop, we've incremented bytesRead and this.remain - // to be incremented up to the blockRemain level, as if we had expected - // to get a null-padded file, and read it until the end. then we will - // decrement both remain and blockRemain by bytesRead, and know that we - // reached the expected EOF, without any null buffer to append. - if (bytesRead === this.remain) { - for (let i = bytesRead; i < this.length && bytesRead < this.blockRemain; i++) { - this.buf[i + this.offset] = 0 - bytesRead++ - this.remain++ - } - } +exports.minor = minor +function minor (a, loose) { + return new SemVer(a, loose).minor +} - const writeBuf = this.offset === 0 && bytesRead === this.buf.length ? - this.buf : this.buf.slice(this.offset, this.offset + bytesRead) +exports.patch = patch +function patch (a, loose) { + return new SemVer(a, loose).patch +} - const flushed = this.write(writeBuf) - if (!flushed) { - this[AWAITDRAIN](() => this[ONDRAIN]()) - } else { - this[ONDRAIN]() - } - } +exports.compare = compare +function compare (a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)) +} - [AWAITDRAIN] (cb) { - this.once('drain', cb) - } +exports.compareLoose = compareLoose +function compareLoose (a, b) { + return compare(a, b, true) +} - write (writeBuf) { - if (this.blockRemain < writeBuf.length) { - const er = new Error('writing more data than expected') - er.path = this.absolute - return this.emit('error', er) - } - this.remain -= writeBuf.length - this.blockRemain -= writeBuf.length - this.pos += writeBuf.length - this.offset += writeBuf.length - return super.write(writeBuf) - } +exports.compareBuild = compareBuild +function compareBuild (a, b, loose) { + var versionA = new SemVer(a, loose) + var versionB = new SemVer(b, loose) + return versionA.compare(versionB) || versionA.compareBuild(versionB) +} - [ONDRAIN] () { - if (!this.remain) { - if (this.blockRemain) { - super.write(Buffer.alloc(this.blockRemain)) - } - return this[CLOSE](er => er ? this.emit('error', er) : this.end()) - } +exports.rcompare = rcompare +function rcompare (a, b, loose) { + return compare(b, a, loose) +} - if (this.offset >= this.length) { - // if we only have a smaller bit left to read, alloc a smaller buffer - // otherwise, keep it the same length it was before. - this.buf = Buffer.allocUnsafe(Math.min(this.blockRemain, this.buf.length)) - this.offset = 0 - } - this.length = this.buf.length - this.offset - this[READ]() - } -}) +exports.sort = sort +function sort (list, loose) { + return list.sort(function (a, b) { + return exports.compareBuild(a, b, loose) + }) +} -class WriteEntrySync extends WriteEntry { - [LSTAT] () { - this[ONLSTAT](fs.lstatSync(this.absolute)) - } +exports.rsort = rsort +function rsort (list, loose) { + return list.sort(function (a, b) { + return exports.compareBuild(b, a, loose) + }) +} - [SYMLINK] () { - this[ONREADLINK](fs.readlinkSync(this.absolute)) - } +exports.gt = gt +function gt (a, b, loose) { + return compare(a, b, loose) > 0 +} - [OPENFILE] () { - this[ONOPENFILE](fs.openSync(this.absolute, 'r')) - } +exports.lt = lt +function lt (a, b, loose) { + return compare(a, b, loose) < 0 +} - [READ] () { - let threw = true - try { - const { fd, buf, offset, length, pos } = this - const bytesRead = fs.readSync(fd, buf, offset, length, pos) - this[ONREAD](bytesRead) - threw = false - } finally { - // ignoring the error from close(2) is a bad practice, but at - // this point we already have an error, don't need another one - if (threw) { - try { - this[CLOSE](() => {}) - } catch (er) {} - } - } - } +exports.eq = eq +function eq (a, b, loose) { + return compare(a, b, loose) === 0 +} - [AWAITDRAIN] (cb) { - cb() - } +exports.neq = neq +function neq (a, b, loose) { + return compare(a, b, loose) !== 0 +} - [CLOSE] (cb) { - fs.closeSync(this.fd) - cb() - } +exports.gte = gte +function gte (a, b, loose) { + return compare(a, b, loose) >= 0 } -const WriteEntryTar = warner(class WriteEntryTar extends Minipass { - constructor (readEntry, opt) { - opt = opt || {} - super(opt) - this.preservePaths = !!opt.preservePaths - this.portable = !!opt.portable - this.strict = !!opt.strict - this.noPax = !!opt.noPax - this.noMtime = !!opt.noMtime - - this.readEntry = readEntry - this.type = readEntry.type - if (this.type === 'Directory' && this.portable) { - this.noMtime = true - } - - this.prefix = opt.prefix || null - - this.path = normPath(readEntry.path) - this.mode = this[MODE](readEntry.mode) - this.uid = this.portable ? null : readEntry.uid - this.gid = this.portable ? null : readEntry.gid - this.uname = this.portable ? null : readEntry.uname - this.gname = this.portable ? null : readEntry.gname - this.size = readEntry.size - this.mtime = this.noMtime ? null : opt.mtime || readEntry.mtime - this.atime = this.portable ? null : readEntry.atime - this.ctime = this.portable ? null : readEntry.ctime - this.linkpath = normPath(readEntry.linkpath) - - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - - let pathWarn = false - if (!this.preservePaths) { - const [root, stripped] = stripAbsolutePath(this.path) - if (root) { - this.path = stripped - pathWarn = root - } - } +exports.lte = lte +function lte (a, b, loose) { + return compare(a, b, loose) <= 0 +} - this.remain = readEntry.size - this.blockRemain = readEntry.startBlockSize - - this.header = new Header({ - path: this[PREFIX](this.path), - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - // only the permissions and setuid/setgid/sticky bitflags - // not the higher-order bits that specify file type - mode: this.mode, - uid: this.portable ? null : this.uid, - gid: this.portable ? null : this.gid, - size: this.size, - mtime: this.noMtime ? null : this.mtime, - type: this.type, - uname: this.portable ? null : this.uname, - atime: this.portable ? null : this.atime, - ctime: this.portable ? null : this.ctime, - }) +exports.cmp = cmp +function cmp (a, op, b, loose) { + switch (op) { + case '===': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a === b - if (pathWarn) { - this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, { - entry: this, - path: pathWarn + this.path, - }) - } + case '!==': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a !== b - if (this.header.encode() && !this.noPax) { - super.write(new Pax({ - atime: this.portable ? null : this.atime, - ctime: this.portable ? null : this.ctime, - gid: this.portable ? null : this.gid, - mtime: this.noMtime ? null : this.mtime, - path: this[PREFIX](this.path), - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - size: this.size, - uid: this.portable ? null : this.uid, - uname: this.portable ? null : this.uname, - dev: this.portable ? null : this.readEntry.dev, - ino: this.portable ? null : this.readEntry.ino, - nlink: this.portable ? null : this.readEntry.nlink, - }).encode()) - } - - super.write(this.header.block) - readEntry.pipe(this) - } + case '': + case '=': + case '==': + return eq(a, b, loose) - [PREFIX] (path) { - return prefixPath(path, this.prefix) - } + case '!=': + return neq(a, b, loose) + + case '>': + return gt(a, b, loose) + + case '>=': + return gte(a, b, loose) + + case '<': + return lt(a, b, loose) - [MODE] (mode) { - return modeFix(mode, this.type === 'Directory', this.portable) + case '<=': + return lte(a, b, loose) + + default: + throw new TypeError('Invalid operator: ' + op) } +} - write (data) { - const writeLen = data.length - if (writeLen > this.blockRemain) { - throw new Error('writing more to entry than is appropriate') +exports.Comparator = Comparator +function Comparator (comp, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false } - this.blockRemain -= writeLen - return super.write(data) } - end () { - if (this.blockRemain) { - super.write(Buffer.alloc(this.blockRemain)) + if (comp instanceof Comparator) { + if (comp.loose === !!options.loose) { + return comp + } else { + comp = comp.value } - return super.end() } -}) - -WriteEntry.Sync = WriteEntrySync -WriteEntry.Tar = WriteEntryTar -const getType = stat => - stat.isFile() ? 'File' - : stat.isDirectory() ? 'Directory' - : stat.isSymbolicLink() ? 'SymbolicLink' - : 'Unsupported' - -module.exports = WriteEntry + if (!(this instanceof Comparator)) { + return new Comparator(comp, options) + } + comp = comp.trim().split(/\s+/).join(' ') + debug('comparator', comp, options) + this.options = options + this.loose = !!options.loose + this.parse(comp) -/***/ }), + if (this.semver === ANY) { + this.value = '' + } else { + this.value = this.operator + this.semver.version + } -/***/ 6684: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + debug('comp', this) +} -"use strict"; +var ANY = {} +Comparator.prototype.parse = function (comp) { + var r = this.options.loose ? safeRe[t.COMPARATORLOOSE] : safeRe[t.COMPARATOR] + var m = comp.match(r) -const proc = - typeof process === 'object' && process - ? process - : { - stdout: null, - stderr: null, - } -const EE = __nccwpck_require__(2361) -const Stream = __nccwpck_require__(2781) -const stringdecoder = __nccwpck_require__(1576) -const SD = stringdecoder.StringDecoder - -const EOF = Symbol('EOF') -const MAYBE_EMIT_END = Symbol('maybeEmitEnd') -const EMITTED_END = Symbol('emittedEnd') -const EMITTING_END = Symbol('emittingEnd') -const EMITTED_ERROR = Symbol('emittedError') -const CLOSED = Symbol('closed') -const READ = Symbol('read') -const FLUSH = Symbol('flush') -const FLUSHCHUNK = Symbol('flushChunk') -const ENCODING = Symbol('encoding') -const DECODER = Symbol('decoder') -const FLOWING = Symbol('flowing') -const PAUSED = Symbol('paused') -const RESUME = Symbol('resume') -const BUFFER = Symbol('buffer') -const PIPES = Symbol('pipes') -const BUFFERLENGTH = Symbol('bufferLength') -const BUFFERPUSH = Symbol('bufferPush') -const BUFFERSHIFT = Symbol('bufferShift') -const OBJECTMODE = Symbol('objectMode') -// internal event when stream is destroyed -const DESTROYED = Symbol('destroyed') -// internal event when stream has an error -const ERROR = Symbol('error') -const EMITDATA = Symbol('emitData') -const EMITEND = Symbol('emitEnd') -const EMITEND2 = Symbol('emitEnd2') -const ASYNC = Symbol('async') -const ABORT = Symbol('abort') -const ABORTED = Symbol('aborted') -const SIGNAL = Symbol('signal') - -const defer = fn => Promise.resolve().then(fn) - -// TODO remove when Node v8 support drops -const doIter = global._MP_NO_ITERATOR_SYMBOLS_ !== '1' -const ASYNCITERATOR = - (doIter && Symbol.asyncIterator) || Symbol('asyncIterator not implemented') -const ITERATOR = - (doIter && Symbol.iterator) || Symbol('iterator not implemented') - -// events that mean 'the stream is over' -// these are treated specially, and re-emitted -// if they are listened for after emitting. -const isEndish = ev => ev === 'end' || ev === 'finish' || ev === 'prefinish' - -const isArrayBuffer = b => - b instanceof ArrayBuffer || - (typeof b === 'object' && - b.constructor && - b.constructor.name === 'ArrayBuffer' && - b.byteLength >= 0) - -const isArrayBufferView = b => !Buffer.isBuffer(b) && ArrayBuffer.isView(b) - -class Pipe { - constructor(src, dest, opts) { - this.src = src - this.dest = dest - this.opts = opts - this.ondrain = () => src[RESUME]() - dest.on('drain', this.ondrain) + if (!m) { + throw new TypeError('Invalid comparator: ' + comp) } - unpipe() { - this.dest.removeListener('drain', this.ondrain) + + this.operator = m[1] !== undefined ? m[1] : '' + if (this.operator === '=') { + this.operator = '' } - // istanbul ignore next - only here for the prototype - proxyErrors() {} - end() { - this.unpipe() - if (this.opts.end) this.dest.end() + + // if it literally is just '>' or '' then allow anything. + if (!m[2]) { + this.semver = ANY + } else { + this.semver = new SemVer(m[2], this.options.loose) } } -class PipeProxyErrors extends Pipe { - unpipe() { - this.src.removeListener('error', this.proxyErrors) - super.unpipe() - } - constructor(src, dest, opts) { - super(src, dest, opts) - this.proxyErrors = er => dest.emit('error', er) - src.on('error', this.proxyErrors) - } +Comparator.prototype.toString = function () { + return this.value } -class Minipass extends Stream { - constructor(options) { - super() - this[FLOWING] = false - // whether we're explicitly paused - this[PAUSED] = false - this[PIPES] = [] - this[BUFFER] = [] - this[OBJECTMODE] = (options && options.objectMode) || false - if (this[OBJECTMODE]) this[ENCODING] = null - else this[ENCODING] = (options && options.encoding) || null - if (this[ENCODING] === 'buffer') this[ENCODING] = null - this[ASYNC] = (options && !!options.async) || false - this[DECODER] = this[ENCODING] ? new SD(this[ENCODING]) : null - this[EOF] = false - this[EMITTED_END] = false - this[EMITTING_END] = false - this[CLOSED] = false - this[EMITTED_ERROR] = null - this.writable = true - this.readable = true - this[BUFFERLENGTH] = 0 - this[DESTROYED] = false - if (options && options.debugExposeBuffer === true) { - Object.defineProperty(this, 'buffer', { get: () => this[BUFFER] }) - } - if (options && options.debugExposePipes === true) { - Object.defineProperty(this, 'pipes', { get: () => this[PIPES] }) - } - this[SIGNAL] = options && options.signal - this[ABORTED] = false - if (this[SIGNAL]) { - this[SIGNAL].addEventListener('abort', () => this[ABORT]()) - if (this[SIGNAL].aborted) { - this[ABORT]() - } - } - } +Comparator.prototype.test = function (version) { + debug('Comparator.test', version, this.options.loose) - get bufferLength() { - return this[BUFFERLENGTH] + if (this.semver === ANY || version === ANY) { + return true } - get encoding() { - return this[ENCODING] + if (typeof version === 'string') { + try { + version = new SemVer(version, this.options) + } catch (er) { + return false + } } - set encoding(enc) { - if (this[OBJECTMODE]) throw new Error('cannot set encoding in objectMode') - - if ( - this[ENCODING] && - enc !== this[ENCODING] && - ((this[DECODER] && this[DECODER].lastNeed) || this[BUFFERLENGTH]) - ) - throw new Error('cannot change encoding') - if (this[ENCODING] !== enc) { - this[DECODER] = enc ? new SD(enc) : null - if (this[BUFFER].length) - this[BUFFER] = this[BUFFER].map(chunk => this[DECODER].write(chunk)) - } + return cmp(version, this.operator, this.semver, this.options) +} - this[ENCODING] = enc +Comparator.prototype.intersects = function (comp, options) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required') } - setEncoding(enc) { - this.encoding = enc + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } } - get objectMode() { - return this[OBJECTMODE] - } - set objectMode(om) { - this[OBJECTMODE] = this[OBJECTMODE] || !!om - } + var rangeTmp - get ['async']() { - return this[ASYNC] - } - set ['async'](a) { - this[ASYNC] = this[ASYNC] || !!a + if (this.operator === '') { + if (this.value === '') { + return true + } + rangeTmp = new Range(comp.value, options) + return satisfies(this.value, rangeTmp, options) + } else if (comp.operator === '') { + if (comp.value === '') { + return true + } + rangeTmp = new Range(this.value, options) + return satisfies(comp.semver, rangeTmp, options) + } + + var sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>') + var sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<') + var sameSemVer = this.semver.version === comp.semver.version + var differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<=') + var oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, options) && + ((this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<')) + var oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, options) && + ((this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>')) + + return sameDirectionIncreasing || sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan +} + +exports.Range = Range +function Range (range, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + if (range instanceof Range) { + if (range.loose === !!options.loose && + range.includePrerelease === !!options.includePrerelease) { + return range + } else { + return new Range(range.raw, options) + } } - // drop everything and get out of the flow completely - [ABORT]() { - this[ABORTED] = true - this.emit('abort', this[SIGNAL].reason) - this.destroy(this[SIGNAL].reason) + if (range instanceof Comparator) { + return new Range(range.value, options) } - get aborted() { - return this[ABORTED] + if (!(this instanceof Range)) { + return new Range(range, options) } - set aborted(_) {} - - write(chunk, encoding, cb) { - if (this[ABORTED]) return false - if (this[EOF]) throw new Error('write after end') - - if (this[DESTROYED]) { - this.emit( - 'error', - Object.assign( - new Error('Cannot call write after a stream was destroyed'), - { code: 'ERR_STREAM_DESTROYED' } - ) - ) - return true - } - if (typeof encoding === 'function') (cb = encoding), (encoding = 'utf8') + this.options = options + this.loose = !!options.loose + this.includePrerelease = !!options.includePrerelease + + // First reduce all whitespace as much as possible so we do not have to rely + // on potentially slow regexes like \s*. This is then stored and used for + // future error messages as well. + this.raw = range + .trim() + .split(/\s+/) + .join(' ') - if (!encoding) encoding = 'utf8' + // First, split based on boolean or || + this.set = this.raw.split('||').map(function (range) { + return this.parseRange(range.trim()) + }, this).filter(function (c) { + // throw out any that are not relevant for whatever reason + return c.length + }) - const fn = this[ASYNC] ? defer : f => f() + if (!this.set.length) { + throw new TypeError('Invalid SemVer Range: ' + this.raw) + } - // convert array buffers and typed array views into buffers - // at some point in the future, we may want to do the opposite! - // leave strings and buffers as-is - // anything else switches us into object mode - if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) { - if (isArrayBufferView(chunk)) - chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength) - else if (isArrayBuffer(chunk)) chunk = Buffer.from(chunk) - else if (typeof chunk !== 'string') - // use the setter so we throw if we have encoding set - this.objectMode = true - } + this.format() +} - // handle object mode up front, since it's simpler - // this yields better performance, fewer checks later. - if (this[OBJECTMODE]) { - /* istanbul ignore if - maybe impossible? */ - if (this.flowing && this[BUFFERLENGTH] !== 0) this[FLUSH](true) +Range.prototype.format = function () { + this.range = this.set.map(function (comps) { + return comps.join(' ').trim() + }).join('||').trim() + return this.range +} - if (this.flowing) this.emit('data', chunk) - else this[BUFFERPUSH](chunk) +Range.prototype.toString = function () { + return this.range +} - if (this[BUFFERLENGTH] !== 0) this.emit('readable') +Range.prototype.parseRange = function (range) { + var loose = this.options.loose + // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` + var hr = loose ? safeRe[t.HYPHENRANGELOOSE] : safeRe[t.HYPHENRANGE] + range = range.replace(hr, hyphenReplace) + debug('hyphen replace', range) + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` + range = range.replace(safeRe[t.COMPARATORTRIM], comparatorTrimReplace) + debug('comparator trim', range, safeRe[t.COMPARATORTRIM]) - if (cb) fn(cb) + // `~ 1.2.3` => `~1.2.3` + range = range.replace(safeRe[t.TILDETRIM], tildeTrimReplace) - return this.flowing - } + // `^ 1.2.3` => `^1.2.3` + range = range.replace(safeRe[t.CARETTRIM], caretTrimReplace) - // at this point the chunk is a buffer or string - // don't buffer it up or send it to the decoder - if (!chunk.length) { - if (this[BUFFERLENGTH] !== 0) this.emit('readable') - if (cb) fn(cb) - return this.flowing - } + // normalize spaces + range = range.split(/\s+/).join(' ') - // fast-path writing strings of same encoding to a stream with - // an empty buffer, skipping the buffer/decoder dance - if ( - typeof chunk === 'string' && - // unless it is a string already ready for us to use - !(encoding === this[ENCODING] && !this[DECODER].lastNeed) - ) { - chunk = Buffer.from(chunk, encoding) - } + // At this point, the range is completely trimmed and + // ready to be split into comparators. + + var compRe = loose ? safeRe[t.COMPARATORLOOSE] : safeRe[t.COMPARATOR] + var set = range.split(' ').map(function (comp) { + return parseComparator(comp, this.options) + }, this).join(' ').split(/\s+/) + if (this.options.loose) { + // in loose mode, throw out any that are not valid comparators + set = set.filter(function (comp) { + return !!comp.match(compRe) + }) + } + set = set.map(function (comp) { + return new Comparator(comp, this.options) + }, this) - if (Buffer.isBuffer(chunk) && this[ENCODING]) - chunk = this[DECODER].write(chunk) + return set +} - // Note: flushing CAN potentially switch us into not-flowing mode - if (this.flowing && this[BUFFERLENGTH] !== 0) this[FLUSH](true) +Range.prototype.intersects = function (range, options) { + if (!(range instanceof Range)) { + throw new TypeError('a Range is required') + } - if (this.flowing) this.emit('data', chunk) - else this[BUFFERPUSH](chunk) + return this.set.some(function (thisComparators) { + return ( + isSatisfiable(thisComparators, options) && + range.set.some(function (rangeComparators) { + return ( + isSatisfiable(rangeComparators, options) && + thisComparators.every(function (thisComparator) { + return rangeComparators.every(function (rangeComparator) { + return thisComparator.intersects(rangeComparator, options) + }) + }) + ) + }) + ) + }) +} - if (this[BUFFERLENGTH] !== 0) this.emit('readable') +// take a set of comparators and determine whether there +// exists a version which can satisfy it +function isSatisfiable (comparators, options) { + var result = true + var remainingComparators = comparators.slice() + var testComparator = remainingComparators.pop() - if (cb) fn(cb) + while (result && remainingComparators.length) { + result = remainingComparators.every(function (otherComparator) { + return testComparator.intersects(otherComparator, options) + }) - return this.flowing + testComparator = remainingComparators.pop() } - read(n) { - if (this[DESTROYED]) return null + return result +} + +// Mostly just for testing and legacy API reasons +exports.toComparators = toComparators +function toComparators (range, options) { + return new Range(range, options).set.map(function (comp) { + return comp.map(function (c) { + return c.value + }).join(' ').trim().split(' ') + }) +} - if (this[BUFFERLENGTH] === 0 || n === 0 || n > this[BUFFERLENGTH]) { - this[MAYBE_EMIT_END]() - return null +// comprised of xranges, tildes, stars, and gtlt's at this point. +// already replaced the hyphen ranges +// turn into a set of JUST comparators. +function parseComparator (comp, options) { + debug('comp', comp, options) + comp = replaceCarets(comp, options) + debug('caret', comp) + comp = replaceTildes(comp, options) + debug('tildes', comp) + comp = replaceXRanges(comp, options) + debug('xrange', comp) + comp = replaceStars(comp, options) + debug('stars', comp) + return comp +} + +function isX (id) { + return !id || id.toLowerCase() === 'x' || id === '*' +} + +// ~, ~> --> * (any, kinda silly) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 +function replaceTildes (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceTilde(comp, options) + }).join(' ') +} + +function replaceTilde (comp, options) { + var r = options.loose ? safeRe[t.TILDELOOSE] : safeRe[t.TILDE] + return comp.replace(r, function (_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr) + var ret + + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + // ~1.2 == >=1.2.0 <1.3.0 + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else if (pr) { + debug('replaceTilde pr', pr) + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } else { + // ~1.2.3 == >=1.2.3 <1.3.0 + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' } - if (this[OBJECTMODE]) n = null + debug('tilde return', ret) + return ret + }) +} - if (this[BUFFER].length > 1 && !this[OBJECTMODE]) { - if (this.encoding) this[BUFFER] = [this[BUFFER].join('')] - else this[BUFFER] = [Buffer.concat(this[BUFFER], this[BUFFERLENGTH])] +// ^ --> * (any, kinda silly) +// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 +// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 +// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2.0 --> >=1.2.0 <2.0.0 +function replaceCarets (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceCaret(comp, options) + }).join(' ') +} + +function replaceCaret (comp, options) { + debug('caret', comp, options) + var r = options.loose ? safeRe[t.CARETLOOSE] : safeRe[t.CARET] + return comp.replace(r, function (_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr) + var ret + + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + if (M === '0') { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else { + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0' + } + } else if (pr) { + debug('replaceCaret pr', pr) + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + (+M + 1) + '.0.0' + } + } else { + debug('no pr') + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + (+M + 1) + '.0.0' + } } - const ret = this[READ](n || null, this[BUFFER][0]) - this[MAYBE_EMIT_END]() + debug('caret return', ret) return ret - } + }) +} - [READ](n, chunk) { - if (n === chunk.length || n === null) this[BUFFERSHIFT]() - else { - this[BUFFER][0] = chunk.slice(n) - chunk = chunk.slice(0, n) - this[BUFFERLENGTH] -= n - } +function replaceXRanges (comp, options) { + debug('replaceXRanges', comp, options) + return comp.split(/\s+/).map(function (comp) { + return replaceXRange(comp, options) + }).join(' ') +} - this.emit('data', chunk) +function replaceXRange (comp, options) { + comp = comp.trim() + var r = options.loose ? safeRe[t.XRANGELOOSE] : safeRe[t.XRANGE] + return comp.replace(r, function (ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr) + var xM = isX(M) + var xm = xM || isX(m) + var xp = xm || isX(p) + var anyX = xp - if (!this[BUFFER].length && !this[EOF]) this.emit('drain') + if (gtlt === '=' && anyX) { + gtlt = '' + } - return chunk - } + // if we're including prereleases in the match, then we need + // to fix this to -0, the lowest possible prerelease value + pr = options.includePrerelease ? '-0' : '' - end(chunk, encoding, cb) { - if (typeof chunk === 'function') (cb = chunk), (chunk = null) - if (typeof encoding === 'function') (cb = encoding), (encoding = 'utf8') - if (chunk) this.write(chunk, encoding) - if (cb) this.once('end', cb) - this[EOF] = true - this.writable = false - - // if we haven't written anything, then go ahead and emit, - // even if we're not reading. - // we'll re-emit if a new 'end' listener is added anyway. - // This makes MP more suitable to write-only use cases. - if (this.flowing || !this[PAUSED]) this[MAYBE_EMIT_END]() - return this - } + if (xM) { + if (gtlt === '>' || gtlt === '<') { + // nothing is allowed + ret = '<0.0.0-0' + } else { + // nothing is forbidden + ret = '*' + } + } else if (gtlt && anyX) { + // we know patch is an x, because we have any x at all. + // replace X with 0 + if (xm) { + m = 0 + } + p = 0 + + if (gtlt === '>') { + // >1 => >=2.0.0 + // >1.2 => >=1.3.0 + // >1.2.3 => >= 1.2.4 + gtlt = '>=' + if (xm) { + M = +M + 1 + m = 0 + p = 0 + } else { + m = +m + 1 + p = 0 + } + } else if (gtlt === '<=') { + // <=0.7.x is actually <0.8.0, since any 0.7.x should + // pass. Similarly, <=7.x is actually <8.0.0, etc. + gtlt = '<' + if (xm) { + M = +M + 1 + } else { + m = +m + 1 + } + } - // don't let the internal resume be overwritten - [RESUME]() { - if (this[DESTROYED]) return + ret = gtlt + M + '.' + m + '.' + p + pr + } else if (xm) { + ret = '>=' + M + '.0.0' + pr + ' <' + (+M + 1) + '.0.0' + pr + } else if (xp) { + ret = '>=' + M + '.' + m + '.0' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + pr + } - this[PAUSED] = false - this[FLOWING] = true - this.emit('resume') - if (this[BUFFER].length) this[FLUSH]() - else if (this[EOF]) this[MAYBE_EMIT_END]() - else this.emit('drain') - } + debug('xRange return', ret) - resume() { - return this[RESUME]() - } + return ret + }) +} - pause() { - this[FLOWING] = false - this[PAUSED] = true +// Because * is AND-ed with everything else in the comparator, +// and '' means "any version", just remove the *s entirely. +function replaceStars (comp, options) { + debug('replaceStars', comp, options) + // Looseness is ignored here. star is always as loose as it gets! + return comp.trim().replace(safeRe[t.STAR], '') +} + +// This function is passed to string.replace(re[t.HYPHENRANGE]) +// M, m, patch, prerelease, build +// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 +// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do +// 1.2 - 3.4 => >=1.2.0 <3.5.0 +function hyphenReplace ($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + if (isX(fM)) { + from = '' + } else if (isX(fm)) { + from = '>=' + fM + '.0.0' + } else if (isX(fp)) { + from = '>=' + fM + '.' + fm + '.0' + } else { + from = '>=' + from } - get destroyed() { - return this[DESTROYED] + if (isX(tM)) { + to = '' + } else if (isX(tm)) { + to = '<' + (+tM + 1) + '.0.0' + } else if (isX(tp)) { + to = '<' + tM + '.' + (+tm + 1) + '.0' + } else if (tpr) { + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr + } else { + to = '<=' + to } - get flowing() { - return this[FLOWING] + return (from + ' ' + to).trim() +} + +// if ANY of the sets match ALL of its comparators, then pass +Range.prototype.test = function (version) { + if (!version) { + return false } - get paused() { - return this[PAUSED] + if (typeof version === 'string') { + try { + version = new SemVer(version, this.options) + } catch (er) { + return false + } } - [BUFFERPUSH](chunk) { - if (this[OBJECTMODE]) this[BUFFERLENGTH] += 1 - else this[BUFFERLENGTH] += chunk.length - this[BUFFER].push(chunk) + for (var i = 0; i < this.set.length; i++) { + if (testSet(this.set[i], version, this.options)) { + return true + } } + return false +} - [BUFFERSHIFT]() { - if (this[OBJECTMODE]) this[BUFFERLENGTH] -= 1 - else this[BUFFERLENGTH] -= this[BUFFER][0].length - return this[BUFFER].shift() +function testSet (set, version, options) { + for (var i = 0; i < set.length; i++) { + if (!set[i].test(version)) { + return false + } } - [FLUSH](noDrain) { - do {} while (this[FLUSHCHUNK](this[BUFFERSHIFT]()) && this[BUFFER].length) + if (version.prerelease.length && !options.includePrerelease) { + // Find the set of versions that are allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (i = 0; i < set.length; i++) { + debug(set[i].semver) + if (set[i].semver === ANY) { + continue + } - if (!noDrain && !this[BUFFER].length && !this[EOF]) this.emit('drain') - } + if (set[i].semver.prerelease.length > 0) { + var allowed = set[i].semver + if (allowed.major === version.major && + allowed.minor === version.minor && + allowed.patch === version.patch) { + return true + } + } + } - [FLUSHCHUNK](chunk) { - this.emit('data', chunk) - return this.flowing + // Version has a -pre, but it's not one of the ones we like. + return false } - pipe(dest, opts) { - if (this[DESTROYED]) return + return true +} - const ended = this[EMITTED_END] - opts = opts || {} - if (dest === proc.stdout || dest === proc.stderr) opts.end = false - else opts.end = opts.end !== false - opts.proxyErrors = !!opts.proxyErrors +exports.satisfies = satisfies +function satisfies (version, range, options) { + try { + range = new Range(range, options) + } catch (er) { + return false + } + return range.test(version) +} - // piping an ended stream ends immediately - if (ended) { - if (opts.end) dest.end() - } else { - this[PIPES].push( - !opts.proxyErrors - ? new Pipe(this, dest, opts) - : new PipeProxyErrors(this, dest, opts) - ) - if (this[ASYNC]) defer(() => this[RESUME]()) - else this[RESUME]() +exports.maxSatisfying = maxSatisfying +function maxSatisfying (versions, range, options) { + var max = null + var maxSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!max || maxSV.compare(v) === -1) { + // compare(max, v, true) + max = v + maxSV = new SemVer(max, options) + } } + }) + return max +} - return dest +exports.minSatisfying = minSatisfying +function minSatisfying (versions, range, options) { + var min = null + var minSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null } - - unpipe(dest) { - const p = this[PIPES].find(p => p.dest === dest) - if (p) { - this[PIPES].splice(this[PIPES].indexOf(p), 1) - p.unpipe() + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!min || minSV.compare(v) === 1) { + // compare(min, v, true) + min = v + minSV = new SemVer(min, options) + } } - } + }) + return min +} - addListener(ev, fn) { - return this.on(ev, fn) - } +exports.minVersion = minVersion +function minVersion (range, loose) { + range = new Range(range, loose) - on(ev, fn) { - const ret = super.on(ev, fn) - if (ev === 'data' && !this[PIPES].length && !this.flowing) this[RESUME]() - else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) - super.emit('readable') - else if (isEndish(ev) && this[EMITTED_END]) { - super.emit(ev) - this.removeAllListeners(ev) - } else if (ev === 'error' && this[EMITTED_ERROR]) { - if (this[ASYNC]) defer(() => fn.call(this, this[EMITTED_ERROR])) - else fn.call(this, this[EMITTED_ERROR]) - } - return ret + var minver = new SemVer('0.0.0') + if (range.test(minver)) { + return minver } - get emittedEnd() { - return this[EMITTED_END] + minver = new SemVer('0.0.0-0') + if (range.test(minver)) { + return minver } - [MAYBE_EMIT_END]() { - if ( - !this[EMITTING_END] && - !this[EMITTED_END] && - !this[DESTROYED] && - this[BUFFER].length === 0 && - this[EOF] - ) { - this[EMITTING_END] = true - this.emit('end') - this.emit('prefinish') - this.emit('finish') - if (this[CLOSED]) this.emit('close') - this[EMITTING_END] = false - } - } + minver = null + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] - emit(ev, data, ...extra) { - // error and close are only events allowed after calling destroy() - if (ev !== 'error' && ev !== 'close' && ev !== DESTROYED && this[DESTROYED]) - return - else if (ev === 'data') { - return !this[OBJECTMODE] && !data - ? false - : this[ASYNC] - ? defer(() => this[EMITDATA](data)) - : this[EMITDATA](data) - } else if (ev === 'end') { - return this[EMITEND]() - } else if (ev === 'close') { - this[CLOSED] = true - // don't emit close before 'end' and 'finish' - if (!this[EMITTED_END] && !this[DESTROYED]) return - const ret = super.emit('close') - this.removeAllListeners('close') - return ret - } else if (ev === 'error') { - this[EMITTED_ERROR] = data - super.emit(ERROR, data) - const ret = - !this[SIGNAL] || this.listeners('error').length - ? super.emit('error', data) - : false - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'resume') { - const ret = super.emit('resume') - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'finish' || ev === 'prefinish') { - const ret = super.emit(ev) - this.removeAllListeners(ev) - return ret - } - - // Some other unknown event - const ret = super.emit(ev, data, ...extra) - this[MAYBE_EMIT_END]() - return ret + comparators.forEach(function (comparator) { + // Clone to avoid manipulating the comparator's semver object. + var compver = new SemVer(comparator.semver.version) + switch (comparator.operator) { + case '>': + if (compver.prerelease.length === 0) { + compver.patch++ + } else { + compver.prerelease.push(0) + } + compver.raw = compver.format() + /* fallthrough */ + case '': + case '>=': + if (!minver || gt(minver, compver)) { + minver = compver + } + break + case '<': + case '<=': + /* Ignore maximum versions */ + break + /* istanbul ignore next */ + default: + throw new Error('Unexpected operation: ' + comparator.operator) + } + }) } - [EMITDATA](data) { - for (const p of this[PIPES]) { - if (p.dest.write(data) === false) this.pause() - } - const ret = super.emit('data', data) - this[MAYBE_EMIT_END]() - return ret + if (minver && range.test(minver)) { + return minver } - [EMITEND]() { - if (this[EMITTED_END]) return + return null +} - this[EMITTED_END] = true - this.readable = false - if (this[ASYNC]) defer(() => this[EMITEND2]()) - else this[EMITEND2]() +exports.validRange = validRange +function validRange (range, options) { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, options).range || '*' + } catch (er) { + return null } +} - [EMITEND2]() { - if (this[DECODER]) { - const data = this[DECODER].end() - if (data) { - for (const p of this[PIPES]) { - p.dest.write(data) - } - super.emit('data', data) - } - } +// Determine if version is less than all the versions possible in the range +exports.ltr = ltr +function ltr (version, range, options) { + return outside(version, range, '<', options) +} - for (const p of this[PIPES]) { - p.end() - } - const ret = super.emit('end') - this.removeAllListeners('end') - return ret - } +// Determine if version is greater than all the versions possible in the range. +exports.gtr = gtr +function gtr (version, range, options) { + return outside(version, range, '>', options) +} - // const all = await stream.collect() - collect() { - const buf = [] - if (!this[OBJECTMODE]) buf.dataLength = 0 - // set the promise first, in case an error is raised - // by triggering the flow here. - const p = this.promise() - this.on('data', c => { - buf.push(c) - if (!this[OBJECTMODE]) buf.dataLength += c.length - }) - return p.then(() => buf) - } +exports.outside = outside +function outside (version, range, hilo, options) { + version = new SemVer(version, options) + range = new Range(range, options) - // const data = await stream.concat() - concat() { - return this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this.collect().then(buf => - this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this[ENCODING] - ? buf.join('') - : Buffer.concat(buf, buf.dataLength) - ) + var gtfn, ltefn, ltfn, comp, ecomp + switch (hilo) { + case '>': + gtfn = gt + ltefn = lte + ltfn = lt + comp = '>' + ecomp = '>=' + break + case '<': + gtfn = lt + ltefn = gte + ltfn = gt + comp = '<' + ecomp = '<=' + break + default: + throw new TypeError('Must provide a hilo val of "<" or ">"') } - // stream.promise().then(() => done, er => emitted error) - promise() { - return new Promise((resolve, reject) => { - this.on(DESTROYED, () => reject(new Error('stream destroyed'))) - this.on('error', er => reject(er)) - this.on('end', () => resolve()) - }) + // If it satisifes the range it is not outside + if (satisfies(version, range, options)) { + return false } - // for await (let chunk of stream) - [ASYNCITERATOR]() { - let stopped = false - const stop = () => { - this.pause() - stopped = true - return Promise.resolve({ done: true }) - } - const next = () => { - if (stopped) return stop() - const res = this.read() - if (res !== null) return Promise.resolve({ done: false, value: res }) - - if (this[EOF]) return stop() - - let resolve = null - let reject = null - const onerr = er => { - this.removeListener('data', ondata) - this.removeListener('end', onend) - this.removeListener(DESTROYED, ondestroy) - stop() - reject(er) - } - const ondata = value => { - this.removeListener('error', onerr) - this.removeListener('end', onend) - this.removeListener(DESTROYED, ondestroy) - this.pause() - resolve({ value: value, done: !!this[EOF] }) + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. + + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] + + var high = null + var low = null + + comparators.forEach(function (comparator) { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') } - const onend = () => { - this.removeListener('error', onerr) - this.removeListener('data', ondata) - this.removeListener(DESTROYED, ondestroy) - stop() - resolve({ done: true }) + high = high || comparator + low = low || comparator + if (gtfn(comparator.semver, high.semver, options)) { + high = comparator + } else if (ltfn(comparator.semver, low.semver, options)) { + low = comparator } - const ondestroy = () => onerr(new Error('stream destroyed')) - return new Promise((res, rej) => { - reject = rej - resolve = res - this.once(DESTROYED, ondestroy) - this.once('error', onerr) - this.once('end', onend) - this.once('data', ondata) - }) + }) + + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false } - return { - next, - throw: stop, - return: stop, - [ASYNCITERATOR]() { - return this - }, + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false } } + return true +} - // for (let chunk of stream) - [ITERATOR]() { - let stopped = false - const stop = () => { - this.pause() - this.removeListener(ERROR, stop) - this.removeListener(DESTROYED, stop) - this.removeListener('end', stop) - stopped = true - return { done: true } - } +exports.prerelease = prerelease +function prerelease (version, options) { + var parsed = parse(version, options) + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null +} - const next = () => { - if (stopped) return stop() - const value = this.read() - return value === null ? stop() : { value } - } - this.once('end', stop) - this.once(ERROR, stop) - this.once(DESTROYED, stop) +exports.intersects = intersects +function intersects (r1, r2, options) { + r1 = new Range(r1, options) + r2 = new Range(r2, options) + return r1.intersects(r2) +} - return { - next, - throw: stop, - return: stop, - [ITERATOR]() { - return this - }, - } +exports.coerce = coerce +function coerce (version, options) { + if (version instanceof SemVer) { + return version } - destroy(er) { - if (this[DESTROYED]) { - if (er) this.emit('error', er) - else this.emit(DESTROYED) - return this - } - - this[DESTROYED] = true - - // throw away all buffered data, it's never coming out - this[BUFFER].length = 0 - this[BUFFERLENGTH] = 0 + if (typeof version === 'number') { + version = String(version) + } - if (typeof this.close === 'function' && !this[CLOSED]) this.close() + if (typeof version !== 'string') { + return null + } - if (er) this.emit('error', er) - // if no error to emit, still reject pending promises - else this.emit(DESTROYED) + options = options || {} - return this + var match = null + if (!options.rtl) { + match = version.match(safeRe[t.COERCE]) + } else { + // Find the right-most coercible string that does not share + // a terminus with a more left-ward coercible string. + // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' + // + // Walk through the string checking with a /g regexp + // Manually set the index so as to pick up overlapping matches. + // Stop when we get a match that ends at the string end, since no + // coercible string can be more right-ward without the same terminus. + var next + while ((next = safeRe[t.COERCERTL].exec(version)) && + (!match || match.index + match[0].length !== version.length) + ) { + if (!match || + next.index + next[0].length !== match.index + match[0].length) { + match = next + } + safeRe[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length + } + // leave it in a clean state + safeRe[t.COERCERTL].lastIndex = -1 } - static isStream(s) { - return ( - !!s && - (s instanceof Minipass || - s instanceof Stream || - (s instanceof EE && - // readable - (typeof s.pipe === 'function' || - // writable - (typeof s.write === 'function' && typeof s.end === 'function')))) - ) + if (match === null) { + return null } -} -exports.Minipass = Minipass + return parse(match[2] + + '.' + (match[3] || '0') + + '.' + (match[4] || '0'), options) +} /***/ }), @@ -14748,456 +10650,6 @@ module.exports = which which.sync = whichSync -/***/ }), - -/***/ 4091: -/***/ ((module) => { - -"use strict"; - -module.exports = function (Yallist) { - Yallist.prototype[Symbol.iterator] = function* () { - for (let walker = this.head; walker; walker = walker.next) { - yield walker.value - } - } -} - - -/***/ }), - -/***/ 665: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -module.exports = Yallist - -Yallist.Node = Node -Yallist.create = Yallist - -function Yallist (list) { - var self = this - if (!(self instanceof Yallist)) { - self = new Yallist() - } - - self.tail = null - self.head = null - self.length = 0 - - if (list && typeof list.forEach === 'function') { - list.forEach(function (item) { - self.push(item) - }) - } else if (arguments.length > 0) { - for (var i = 0, l = arguments.length; i < l; i++) { - self.push(arguments[i]) - } - } - - return self -} - -Yallist.prototype.removeNode = function (node) { - if (node.list !== this) { - throw new Error('removing node which does not belong to this list') - } - - var next = node.next - var prev = node.prev - - if (next) { - next.prev = prev - } - - if (prev) { - prev.next = next - } - - if (node === this.head) { - this.head = next - } - if (node === this.tail) { - this.tail = prev - } - - node.list.length-- - node.next = null - node.prev = null - node.list = null - - return next -} - -Yallist.prototype.unshiftNode = function (node) { - if (node === this.head) { - return - } - - if (node.list) { - node.list.removeNode(node) - } - - var head = this.head - node.list = this - node.next = head - if (head) { - head.prev = node - } - - this.head = node - if (!this.tail) { - this.tail = node - } - this.length++ -} - -Yallist.prototype.pushNode = function (node) { - if (node === this.tail) { - return - } - - if (node.list) { - node.list.removeNode(node) - } - - var tail = this.tail - node.list = this - node.prev = tail - if (tail) { - tail.next = node - } - - this.tail = node - if (!this.head) { - this.head = node - } - this.length++ -} - -Yallist.prototype.push = function () { - for (var i = 0, l = arguments.length; i < l; i++) { - push(this, arguments[i]) - } - return this.length -} - -Yallist.prototype.unshift = function () { - for (var i = 0, l = arguments.length; i < l; i++) { - unshift(this, arguments[i]) - } - return this.length -} - -Yallist.prototype.pop = function () { - if (!this.tail) { - return undefined - } - - var res = this.tail.value - this.tail = this.tail.prev - if (this.tail) { - this.tail.next = null - } else { - this.head = null - } - this.length-- - return res -} - -Yallist.prototype.shift = function () { - if (!this.head) { - return undefined - } - - var res = this.head.value - this.head = this.head.next - if (this.head) { - this.head.prev = null - } else { - this.tail = null - } - this.length-- - return res -} - -Yallist.prototype.forEach = function (fn, thisp) { - thisp = thisp || this - for (var walker = this.head, i = 0; walker !== null; i++) { - fn.call(thisp, walker.value, i, this) - walker = walker.next - } -} - -Yallist.prototype.forEachReverse = function (fn, thisp) { - thisp = thisp || this - for (var walker = this.tail, i = this.length - 1; walker !== null; i--) { - fn.call(thisp, walker.value, i, this) - walker = walker.prev - } -} - -Yallist.prototype.get = function (n) { - for (var i = 0, walker = this.head; walker !== null && i < n; i++) { - // abort out of the list early if we hit a cycle - walker = walker.next - } - if (i === n && walker !== null) { - return walker.value - } -} - -Yallist.prototype.getReverse = function (n) { - for (var i = 0, walker = this.tail; walker !== null && i < n; i++) { - // abort out of the list early if we hit a cycle - walker = walker.prev - } - if (i === n && walker !== null) { - return walker.value - } -} - -Yallist.prototype.map = function (fn, thisp) { - thisp = thisp || this - var res = new Yallist() - for (var walker = this.head; walker !== null;) { - res.push(fn.call(thisp, walker.value, this)) - walker = walker.next - } - return res -} - -Yallist.prototype.mapReverse = function (fn, thisp) { - thisp = thisp || this - var res = new Yallist() - for (var walker = this.tail; walker !== null;) { - res.push(fn.call(thisp, walker.value, this)) - walker = walker.prev - } - return res -} - -Yallist.prototype.reduce = function (fn, initial) { - var acc - var walker = this.head - if (arguments.length > 1) { - acc = initial - } else if (this.head) { - walker = this.head.next - acc = this.head.value - } else { - throw new TypeError('Reduce of empty list with no initial value') - } - - for (var i = 0; walker !== null; i++) { - acc = fn(acc, walker.value, i) - walker = walker.next - } - - return acc -} - -Yallist.prototype.reduceReverse = function (fn, initial) { - var acc - var walker = this.tail - if (arguments.length > 1) { - acc = initial - } else if (this.tail) { - walker = this.tail.prev - acc = this.tail.value - } else { - throw new TypeError('Reduce of empty list with no initial value') - } - - for (var i = this.length - 1; walker !== null; i--) { - acc = fn(acc, walker.value, i) - walker = walker.prev - } - - return acc -} - -Yallist.prototype.toArray = function () { - var arr = new Array(this.length) - for (var i = 0, walker = this.head; walker !== null; i++) { - arr[i] = walker.value - walker = walker.next - } - return arr -} - -Yallist.prototype.toArrayReverse = function () { - var arr = new Array(this.length) - for (var i = 0, walker = this.tail; walker !== null; i++) { - arr[i] = walker.value - walker = walker.prev - } - return arr -} - -Yallist.prototype.slice = function (from, to) { - to = to || this.length - if (to < 0) { - to += this.length - } - from = from || 0 - if (from < 0) { - from += this.length - } - var ret = new Yallist() - if (to < from || to < 0) { - return ret - } - if (from < 0) { - from = 0 - } - if (to > this.length) { - to = this.length - } - for (var i = 0, walker = this.head; walker !== null && i < from; i++) { - walker = walker.next - } - for (; walker !== null && i < to; i++, walker = walker.next) { - ret.push(walker.value) - } - return ret -} - -Yallist.prototype.sliceReverse = function (from, to) { - to = to || this.length - if (to < 0) { - to += this.length - } - from = from || 0 - if (from < 0) { - from += this.length - } - var ret = new Yallist() - if (to < from || to < 0) { - return ret - } - if (from < 0) { - from = 0 - } - if (to > this.length) { - to = this.length - } - for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) { - walker = walker.prev - } - for (; walker !== null && i > from; i--, walker = walker.prev) { - ret.push(walker.value) - } - return ret -} - -Yallist.prototype.splice = function (start, deleteCount, ...nodes) { - if (start > this.length) { - start = this.length - 1 - } - if (start < 0) { - start = this.length + start; - } - - for (var i = 0, walker = this.head; walker !== null && i < start; i++) { - walker = walker.next - } - - var ret = [] - for (var i = 0; walker && i < deleteCount; i++) { - ret.push(walker.value) - walker = this.removeNode(walker) - } - if (walker === null) { - walker = this.tail - } - - if (walker !== this.head && walker !== this.tail) { - walker = walker.prev - } - - for (var i = 0; i < nodes.length; i++) { - walker = insert(this, walker, nodes[i]) - } - return ret; -} - -Yallist.prototype.reverse = function () { - var head = this.head - var tail = this.tail - for (var walker = head; walker !== null; walker = walker.prev) { - var p = walker.prev - walker.prev = walker.next - walker.next = p - } - this.head = tail - this.tail = head - return this -} - -function insert (self, node, value) { - var inserted = node === self.head ? - new Node(value, null, node, self) : - new Node(value, node, node.next, self) - - if (inserted.next === null) { - self.tail = inserted - } - if (inserted.prev === null) { - self.head = inserted - } - - self.length++ - - return inserted -} - -function push (self, item) { - self.tail = new Node(item, self.tail, null, self) - if (!self.head) { - self.head = self.tail - } - self.length++ -} - -function unshift (self, item) { - self.head = new Node(item, null, self.head, self) - if (!self.tail) { - self.tail = self.head - } - self.length++ -} - -function Node (value, prev, next, list) { - if (!(this instanceof Node)) { - return new Node(value, prev, next, list) - } - - this.list = list - this.value = value - - if (prev) { - prev.next = this - this.prev = prev - } else { - this.prev = null - } - - if (next) { - next.prev = this - this.next = next - } else { - this.next = null - } -} - -try { - // add if support for Symbol.iterator is present - __nccwpck_require__(4091)(Yallist) -} catch (er) {} - - /***/ }), /***/ 6144: @@ -15210,17 +10662,15 @@ __nccwpck_require__.r(__webpack_exports__); /* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__nccwpck_require__.n(node_child_process__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(7561); /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__nccwpck_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var node_stream__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(4492); -/* harmony import */ var node_stream__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__nccwpck_require__.n(node_stream__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(612); -/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__nccwpck_require__.n(node_os__WEBPACK_IMPORTED_MODULE_3__); +/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(612); +/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__nccwpck_require__.n(node_os__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(7784); +/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__nccwpck_require__.n(_actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(2186); /* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__nccwpck_require__.n(_actions_core__WEBPACK_IMPORTED_MODULE_4__); -/* harmony import */ var got__WEBPACK_IMPORTED_MODULE_7__ = __nccwpck_require__(4256); -/* harmony import */ var tar__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(4674); -/* harmony import */ var which__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(6143); -/* harmony import */ var which__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__nccwpck_require__.n(which__WEBPACK_IMPORTED_MODULE_6__); - +/* harmony import */ var got__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(6493); +/* harmony import */ var which__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(6143); +/* harmony import */ var which__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__nccwpck_require__.n(which__WEBPACK_IMPORTED_MODULE_5__); @@ -15229,128 +10679,154 @@ __nccwpck_require__.r(__webpack_exports__); const params = { - version: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)('version'), - channel: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)('channel') || 'stable', - namespace: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)('namespace') || 'testkube', - url: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)('url') || 'testkube.io', - organization: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)('organization'), - environment: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)('environment'), - token: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)('token'), + version: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)("version"), + channel: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)("channel") || "stable", + namespace: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)("namespace") || "testkube", + url: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)("url") || "testkube.io", + organization: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)("organization"), + environment: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)("environment"), + token: (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.getInput)("token"), }; -const mode = (params.organization || params.environment || params.token) ? 'cloud' : 'kubectl'; -if (mode === 'cloud') { +const mode = params.organization || params.environment || params.token ? "cloud" : "kubectl"; +if (mode === "cloud") { process.stdout.write(`Detected mode: cloud connection.\n`); } else { process.stdout.write(`Detected mode: kubectl connection. To use Cloud connection instead, provide your 'organization', 'environment' and 'token'.\n`); } // Check params -if (mode === 'cloud') { +if (mode === "cloud") { if (!params.organization || !params.environment || !params.token) { - throw new Error('You need to pass `organization`, `environment` and `token` for Cloud connection.'); + throw new Error("You need to pass `organization`, `environment` and `token` for Cloud connection."); } } // Detect architecture const architectureMapping = { - x86_64: 'x86_64', - x64: 'x86_64', - amd64: 'x86_64', - arm64: 'arm64', - aarch64: 'arm64', - i386: 'i386', + x86_64: "x86_64", + x64: "x86_64", + amd64: "x86_64", + arm64: "arm64", + aarch64: "arm64", + i386: "i386", }; -const architecture = architectureMapping[node_os__WEBPACK_IMPORTED_MODULE_3__.machine()]; -process.stdout.write(`Architecture: ${node_os__WEBPACK_IMPORTED_MODULE_3__.machine()} (${architecture || 'unsupported'})\n`); +const architecture = architectureMapping[node_os__WEBPACK_IMPORTED_MODULE_2__.machine()]; +process.stdout.write(`Architecture: ${node_os__WEBPACK_IMPORTED_MODULE_2__.machine()} (${architecture || "unsupported"})\n`); if (!architecture) { - throw new Error('We do not support this architecture yet.'); + throw new Error("We do not support this architecture yet."); } // Detect OS const systemMapping = { - Linux: 'Linux', - Darwin: 'Darwin', - Windows: 'Windows', - Windows_NT: 'Windows', + Linux: "Linux", + Darwin: "Darwin", + Windows: "Windows", + Windows_NT: "Windows", }; -const system = systemMapping[node_os__WEBPACK_IMPORTED_MODULE_3__.type()]; -process.stdout.write(`System: ${node_os__WEBPACK_IMPORTED_MODULE_3__.type()} (${system || 'unsupported'})\n`); +const system = systemMapping[node_os__WEBPACK_IMPORTED_MODULE_2__.type()]; +process.stdout.write(`System: ${node_os__WEBPACK_IMPORTED_MODULE_2__.type()} (${system || "unsupported"})\n`); if (!system) { - throw new Error('We do not support this OS yet.'); + throw new Error("We do not support this OS yet."); } // Detect binaries path // TODO: Consider installing Testkube in some random place, and add it to PATH environment variable -const detectedPaths = (process.env.PATH || '').split(':').filter(Boolean).sort((a, b) => a.length - b.length); -const writablePaths = (await Promise.all(detectedPaths.map(async (dirPath) => ({ path: dirPath, writable: await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.access(dirPath, node_fs__WEBPACK_IMPORTED_MODULE_1__.constants.W_OK).then(() => true).catch(() => false) })))).filter(x => x.writable).map(x => x.path); -const preferredPaths = ['/usr/local/bin', '/usr/bin']; -const binaryDirPath = preferredPaths.find(x => writablePaths.includes(x)) || writablePaths[0]; -process.stdout.write(`Binary path: ${binaryDirPath || ''}\n`); +const detectedPaths = (process.env.PATH || "") + .split(":") + .filter(Boolean) + .sort((a, b) => a.length - b.length); +const writablePaths = (await Promise.all(detectedPaths.map(async (dirPath) => ({ + path: dirPath, + writable: await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.access(dirPath, node_fs__WEBPACK_IMPORTED_MODULE_1__.constants.W_OK) + .then(() => true) + .catch(() => false), +})))) + .filter((x) => x.writable) + .map((x) => x.path); +const preferredPaths = ["/usr/local/bin", "/usr/bin"]; +const binaryDirPath = preferredPaths.find((x) => writablePaths.includes(x)) || writablePaths[0]; +process.stdout.write(`Binary path: ${binaryDirPath || ""}\n`); if (!binaryDirPath) { - throw new Error('Could not find a writable path that is exposed in PATH to put the binary.'); + throw new Error("Could not find a writable path that is exposed in PATH to put the binary."); } // Detect if there is kubectl installed -if (mode === 'kubectl') { - const hasKubectl = await which__WEBPACK_IMPORTED_MODULE_6___default()('kubectl', { nothrow: true }); - process.stdout.write(`kubectl: ${hasKubectl ? 'detected' : 'not available'}.\n`); +if (mode === "kubectl") { + const hasKubectl = await which__WEBPACK_IMPORTED_MODULE_5___default()("kubectl", { nothrow: true }); + process.stdout.write(`kubectl: ${hasKubectl ? "detected" : "not available"}.\n`); if (!hasKubectl) { - throw new Error('You do not have kubectl installed. Most likely you need to configure your workflow to initialize connection with Kubernetes cluster.'); + throw new Error("You do not have kubectl installed. Most likely you need to configure your workflow to initialize connection with Kubernetes cluster."); } } else { - process.stdout.write('kubectl: ignored for Cloud integration\n'); + process.stdout.write("kubectl: ignored for Cloud integration\n"); } // Detect if there is Testkube CLI already installed -if (await which__WEBPACK_IMPORTED_MODULE_6___default()('kubectl-testkube', { nothrow: true })) { - process.stdout.write('Looks like you already have the Testkube CLI installed. Skipping...\n'); +if (await which__WEBPACK_IMPORTED_MODULE_5___default()("kubectl-testkube", { nothrow: true })) { + process.stdout.write("Looks like you already have the Testkube CLI installed. Skipping...\n"); } else { // Detect the latest version if (params.version) { - params.version = params.version.replace(/^v/, ''); + params.version = params.version.replace(/^v/, ""); process.stdout.write(`Forcing "${params.version} version...\n`); } else { process.stdout.write(`Detecting the latest version for minimum of "${params.channel}" channel...\n`); - if (params.channel === 'stable') { - const release = await (0,got__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .ZP)('https://api.github.com/repos/kubeshop/testkube/releases/latest').json(); + if (params.channel === "stable") { + const release = await (0,got__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .ZP)("https://api.github.com/repos/kubeshop/testkube/releases/latest").json(); params.version = release?.tag_name; } else { - const channels = ['stable', params.channel]; + const channels = ["stable", params.channel]; process.stdout.write(`Detecting the latest version for minimum of "${params.channel}" channel...\n`); - const releases = await (0,got__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .ZP)('https://api.github.com/repos/kubeshop/testkube/releases').json(); - const versions = releases.map(release => ({ + const releases = await (0,got__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .ZP)("https://api.github.com/repos/kubeshop/testkube/releases").json(); + const versions = releases.map((release) => ({ tag: release.tag_name, - channel: release.tag_name.match(/-([^0-9]+)/)?.[1] || 'stable', + channel: release.tag_name.match(/-([^0-9]+)/)?.[1] || "stable", })); params.version = versions.find(({ channel }) => channels.includes(channel))?.tag; } if (!params.version) { - throw new Error('Not found any version matching criteria.'); + throw new Error("Not found any version matching criteria."); } - params.version = params.version.replace(/^v/, ''); + params.version = params.version.replace(/^v/, ""); process.stdout.write(` Latest version: ${params.version}\n`); } - const artifactUrl = `https://github.com/kubeshop/testkube/releases/download/v${encodeURIComponent(params.version)}/testkube_${encodeURIComponent(params.version)}_${encodeURIComponent(system)}_${encodeURIComponent(architecture)}.tar.gz`; - process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); - const artifactStream = got__WEBPACK_IMPORTED_MODULE_7__/* ["default"].stream */ .ZP.stream(artifactUrl).pipe(tar__WEBPACK_IMPORTED_MODULE_5__.x({ C: binaryDirPath }, ['kubectl-testkube'])); - await node_stream__WEBPACK_IMPORTED_MODULE_2__.promises.finished(artifactStream); - process.stdout.write(`Extracted CLI to ${binaryDirPath}/kubectl-testkube.\n`); - await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${binaryDirPath}/kubectl-testkube`, `${binaryDirPath}/testkube`); + const encodedVersion = encodeURIComponent(params.version); + const encodedVerSysArch = `${encodeURIComponent(params.version)}_${encodeURIComponent(system)}_${encodeURIComponent(architecture)}`; + const artifactUrl = `https://github.com/kubeshop/testkube/releases/download/v${encodedVersion}/testkube_${encodedVerSysArch}.tar.gz`; + const existingTestkubePath = _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.find("kubectl-testkube", params.version); + if (!existingTestkubePath || existingTestkubePath.length === 0) { + process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); + const artifactPath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.downloadTool(artifactUrl); + const artifactExtractedPath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.extractTar(artifactPath, binaryDirPath); + process.stdout.write(`Extracted CLI to ${binaryDirPath}/kubectl-testkube.\n`); + const cachedDir = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.cacheDir(artifactExtractedPath, "kubectl-testkube", params.version); + (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.addPath)(cachedDir); + } + else { + (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.addPath)(existingTestkubePath); + process.stdout.write(`Found existing Testkube CLI at "${existingTestkubePath}".\n`); + } + const testkubePath = existingTestkubePath + ? `${existingTestkubePath}/kubectl-testkube}` + : `${binaryDirPath}/kubectl-testkube`; + await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${testkubePath}`, `${binaryDirPath}/testkube`); process.stdout.write(`Linked CLI as ${binaryDirPath}/testkube.\n`); - await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${binaryDirPath}/kubectl-testkube`, `${binaryDirPath}/tk`); + await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${testkubePath}`, `${binaryDirPath}/tk`); process.stdout.write(`Linked CLI as ${binaryDirPath}/tk.\n`); } // Configure the Testkube context -const contextArgs = mode === 'kubectl' - ? [ - '--kubeconfig', - '--namespace', params.namespace, - ] : [ - '--api-key', params.token, - '--cloud-root-domain', params.url, - '--org', params.organization, - '--env', params.environment, -]; -process.exit((0,node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync)('testkube', ['set', 'context', ...contextArgs], { stdio: 'inherit' }).status || 0); +const contextArgs = mode === "kubectl" + ? ["--kubeconfig", "--namespace", params.namespace] + : [ + "--api-key", + params.token, + "--cloud-root-domain", + params.url, + "--org", + params.organization, + "--env", + params.environment, + ]; +process.exit((0,node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync)("testkube", ["set", "context", ...contextArgs], { stdio: "inherit" }).status || 0); __webpack_async_result__(); } catch(e) { __webpack_async_result__(e); } }, 1); @@ -15373,6 +10849,14 @@ module.exports = require("buffer"); /***/ }), +/***/ 2081: +/***/ ((module) => { + +"use strict"; +module.exports = require("child_process"); + +/***/ }), + /***/ 6113: /***/ ((module) => { @@ -15461,14 +10945,6 @@ module.exports = require("node:os"); /***/ }), -/***/ 4492: -/***/ ((module) => { - -"use strict"; -module.exports = require("node:stream"); - -/***/ }), - /***/ 2037: /***/ ((module) => { @@ -15485,27 +10961,27 @@ module.exports = require("path"); /***/ }), -/***/ 7282: +/***/ 2781: /***/ ((module) => { "use strict"; -module.exports = require("process"); +module.exports = require("stream"); /***/ }), -/***/ 2781: +/***/ 1576: /***/ ((module) => { "use strict"; -module.exports = require("stream"); +module.exports = require("string_decoder"); /***/ }), -/***/ 1576: +/***/ 9512: /***/ ((module) => { "use strict"; -module.exports = require("string_decoder"); +module.exports = require("timers"); /***/ }), @@ -15747,7 +11223,7 @@ const checkStat = (stat, path, options) => stat.isFile() && checkPathExt(path, o /***/ }), -/***/ 4256: +/***/ 6493: /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => { "use strict"; @@ -16513,8 +11989,8 @@ class AbortError extends RequestError { const external_node_process_namespaceObject = require("node:process"); ;// CONCATENATED MODULE: external "node:buffer" const external_node_buffer_namespaceObject = require("node:buffer"); -// EXTERNAL MODULE: external "node:stream" -var external_node_stream_ = __nccwpck_require__(4492); +;// CONCATENATED MODULE: external "node:stream" +const external_node_stream_namespaceObject = require("node:stream"); ;// CONCATENATED MODULE: external "node:url" const external_node_url_namespaceObject = require("node:url"); ;// CONCATENATED MODULE: external "node:http" @@ -16932,7 +12408,7 @@ function lowercaseKeys(object) { -class Response extends external_node_stream_.Readable { +class Response extends external_node_stream_namespaceObject.Readable { statusCode; headers; body; @@ -17121,7 +12597,7 @@ class CacheableRequest { // cache-control headers. As a result, the body of the request should be // added to the cache key in order to avoid collisions. if (options.body && options.method !== undefined && ['POST', 'PATCH', 'PUT'].includes(options.method)) { - if (options.body instanceof external_node_stream_.Readable) { + if (options.body instanceof external_node_stream_namespaceObject.Readable) { // Streamed bodies should completely skip the cache because they may // or may not be hashable and in either case the stream would need to // close before the cache key could be generated. @@ -17306,7 +12782,7 @@ class CacheableRequest { } const entries = Object.entries; const cloneResponse = (response) => { - const clone = new external_node_stream_.PassThrough({ autoDestroy: false }); + const clone = new external_node_stream_namespaceObject.PassThrough({ autoDestroy: false }); mimicResponse(response, clone); return response.pipe(clone); }; @@ -20131,7 +15607,7 @@ const proxiedRequestEvents = [ 'upgrade', ]; const core_noop = () => { }; -class Request extends external_node_stream_.Duplex { +class Request extends external_node_stream_namespaceObject.Duplex { constructor(url, options, defaults) { super({ // Don't destroy immediately, as the error may be emitted on unsuccessful retry diff --git a/dist/licenses.txt b/dist/licenses.txt index a3958a1..d0a8ee7 100644 --- a/dist/licenses.txt +++ b/dist/licenses.txt @@ -10,6 +10,18 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +@actions/exec +MIT +The MIT License (MIT) + +Copyright 2019 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + @actions/http-client MIT Actions Http Client for Node.js @@ -35,6 +47,30 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +@actions/io +MIT +The MIT License (MIT) + +Copyright 2019 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@actions/tool-cache +MIT +The MIT License (MIT) + +Copyright 2019 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + @sindresorhus/is MIT MIT License @@ -101,25 +137,6 @@ SOFTWARE. cacheable-request MIT -chownr -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - decompress-response MIT MIT License @@ -183,25 +200,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -fs-minipass -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - get-stream MIT MIT License @@ -340,80 +338,6 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -minipass -ISC -The ISC License - -Copyright (c) 2017-2023 npm, Inc., Isaac Z. Schlueter, and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -minizlib -MIT -Minizlib was created by Isaac Z. Schlueter. -It is a derivative work of the Node.js project. - -""" -Copyright Isaac Z. Schlueter and Contributors -Copyright Node.js contributors. All rights reserved. -Copyright Joyent, Inc. and other Node contributors. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -""" - - -mkdirp -MIT -Copyright James Halliday (mail@substack.net) and Isaac Z. Schlueter (i@izs.me) - -This project is free software released under the MIT license: - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - normalize-url MIT MIT License @@ -493,7 +417,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -tar +semver ISC The ISC License @@ -567,22 +491,3 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -yallist -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/package-lock.json b/package-lock.json index 8645ef7..3a3d75f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,8 @@ "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^5.1.1", + "@actions/tool-cache": "^2.0.1", "got": "^12.6.0", - "tar": "^6.2.0", "which": "^4.0.0" }, "devDependencies": { @@ -36,6 +36,14 @@ "uuid": "^8.3.2" } }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, "node_modules/@actions/github": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", @@ -55,6 +63,33 @@ "tunnel": "^0.0.6" } }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==" + }, + "node_modules/@actions/tool-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz", + "integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==", + "dependencies": { + "@actions/core": "^1.2.6", + "@actions/exec": "^1.0.0", + "@actions/http-client": "^2.0.1", + "@actions/io": "^1.1.1", + "semver": "^6.1.0", + "uuid": "^3.3.2" + } + }, + "node_modules/@actions/tool-cache/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -319,14 +354,6 @@ "node": ">=14.16" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -454,28 +481,6 @@ "node": ">= 14.17" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -661,40 +666,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -814,6 +785,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -943,30 +922,6 @@ "node": ">=8" } }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -1129,11 +1084,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index c51b3a5..5fd5102 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^5.1.1", + "@actions/tool-cache": "^2.0.1", "got": "^12.6.0", - "tar": "^6.2.0", "which": "^4.0.0" }, "devDependencies": { diff --git a/src/index.ts b/src/index.ts index 1b6bc49..8cb1108 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,10 @@ -import {spawnSync} from 'node:child_process'; -import * as fs from 'node:fs'; -import * as stream from 'node:stream'; -import * as os from 'node:os'; -import {getInput} from '@actions/core'; -import got from 'got'; -import tar from 'tar'; -import which from 'which'; +import { spawnSync } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as toolCache from "@actions/tool-cache"; +import { getInput, addPath } from "@actions/core"; +import got from "got"; +import which from "which"; interface Params { version?: string | null; @@ -18,136 +17,174 @@ interface Params { } const params: Params = { - version: getInput('version'), - channel: getInput('channel') || 'stable', - namespace: getInput('namespace') || 'testkube', - url: getInput('url') || 'testkube.io', - organization: getInput('organization'), - environment: getInput('environment'), - token: getInput('token'), + version: getInput("version"), + channel: getInput("channel") || "stable", + namespace: getInput("namespace") || "testkube", + url: getInput("url") || "testkube.io", + organization: getInput("organization"), + environment: getInput("environment"), + token: getInput("token"), }; -const mode = (params.organization || params.environment || params.token) ? 'cloud' : 'kubectl'; -if (mode === 'cloud') { +const mode = params.organization || params.environment || params.token ? "cloud" : "kubectl"; +if (mode === "cloud") { process.stdout.write(`Detected mode: cloud connection.\n`); } else { - process.stdout.write(`Detected mode: kubectl connection. To use Cloud connection instead, provide your 'organization', 'environment' and 'token'.\n`); + process.stdout.write( + `Detected mode: kubectl connection. To use Cloud connection instead, provide your 'organization', 'environment' and 'token'.\n` + ); } // Check params -if (mode === 'cloud') { +if (mode === "cloud") { if (!params.organization || !params.environment || !params.token) { - throw new Error('You need to pass `organization`, `environment` and `token` for Cloud connection.'); + throw new Error("You need to pass `organization`, `environment` and `token` for Cloud connection."); } } // Detect architecture const architectureMapping: Record = { - x86_64: 'x86_64', - x64: 'x86_64', - amd64: 'x86_64', - arm64: 'arm64', - aarch64: 'arm64', - i386: 'i386', + x86_64: "x86_64", + x64: "x86_64", + amd64: "x86_64", + arm64: "arm64", + aarch64: "arm64", + i386: "i386", }; const architecture = architectureMapping[os.machine()]; -process.stdout.write(`Architecture: ${os.machine()} (${architecture || 'unsupported'})\n`); +process.stdout.write(`Architecture: ${os.machine()} (${architecture || "unsupported"})\n`); if (!architecture) { - throw new Error('We do not support this architecture yet.'); + throw new Error("We do not support this architecture yet."); } // Detect OS const systemMapping: Record = { - Linux: 'Linux', - Darwin: 'Darwin', - Windows: 'Windows', - Windows_NT: 'Windows', + Linux: "Linux", + Darwin: "Darwin", + Windows: "Windows", + Windows_NT: "Windows", }; const system = systemMapping[os.type()]; -process.stdout.write(`System: ${os.type()} (${system || 'unsupported'})\n`); +process.stdout.write(`System: ${os.type()} (${system || "unsupported"})\n`); if (!system) { - throw new Error('We do not support this OS yet.'); + throw new Error("We do not support this OS yet."); } // Detect binaries path // TODO: Consider installing Testkube in some random place, and add it to PATH environment variable -const detectedPaths = (process.env.PATH || '').split(':').filter(Boolean).sort((a, b) => a.length - b.length); -const writablePaths = (await Promise.all(detectedPaths.map(async dirPath => ({path: dirPath, writable: await fs.promises.access(dirPath, fs.constants.W_OK).then(() => true).catch(() => false)})))).filter(x => x.writable).map(x => x.path); -const preferredPaths = ['/usr/local/bin', '/usr/bin']; -const binaryDirPath = preferredPaths.find(x => writablePaths.includes(x)) || writablePaths[0]; -process.stdout.write(`Binary path: ${binaryDirPath || ''}\n`); +const detectedPaths = (process.env.PATH || "") + .split(":") + .filter(Boolean) + .sort((a, b) => a.length - b.length); +const writablePaths = ( + await Promise.all( + detectedPaths.map(async (dirPath) => ({ + path: dirPath, + writable: await fs.promises + .access(dirPath, fs.constants.W_OK) + .then(() => true) + .catch(() => false), + })) + ) +) + .filter((x) => x.writable) + .map((x) => x.path); +const preferredPaths = ["/usr/local/bin", "/usr/bin"]; +const binaryDirPath = preferredPaths.find((x) => writablePaths.includes(x)) || writablePaths[0]; +process.stdout.write(`Binary path: ${binaryDirPath || ""}\n`); if (!binaryDirPath) { - throw new Error('Could not find a writable path that is exposed in PATH to put the binary.'); + throw new Error("Could not find a writable path that is exposed in PATH to put the binary."); } // Detect if there is kubectl installed -if (mode === 'kubectl') { - const hasKubectl = await which('kubectl', {nothrow: true}); - process.stdout.write(`kubectl: ${hasKubectl ? 'detected' : 'not available'}.\n`); +if (mode === "kubectl") { + const hasKubectl = await which("kubectl", { nothrow: true }); + process.stdout.write(`kubectl: ${hasKubectl ? "detected" : "not available"}.\n`); if (!hasKubectl) { - throw new Error('You do not have kubectl installed. Most likely you need to configure your workflow to initialize connection with Kubernetes cluster.'); + throw new Error( + "You do not have kubectl installed. Most likely you need to configure your workflow to initialize connection with Kubernetes cluster." + ); } } else { - process.stdout.write('kubectl: ignored for Cloud integration\n'); + process.stdout.write("kubectl: ignored for Cloud integration\n"); } // Detect if there is Testkube CLI already installed -if (await which('kubectl-testkube', {nothrow: true})) { - process.stdout.write('Looks like you already have the Testkube CLI installed. Skipping...\n'); +if (await which("kubectl-testkube", { nothrow: true })) { + process.stdout.write("Looks like you already have the Testkube CLI installed. Skipping...\n"); } else { // Detect the latest version if (params.version) { - params.version = params.version.replace(/^v/, ''); + params.version = params.version.replace(/^v/, ""); process.stdout.write(`Forcing "${params.version} version...\n`); } else { process.stdout.write(`Detecting the latest version for minimum of "${params.channel}" channel...\n`); - if (params.channel === 'stable') { - const release: any = await got('https://api.github.com/repos/kubeshop/testkube/releases/latest').json(); + if (params.channel === "stable") { + const release: any = await got("https://api.github.com/repos/kubeshop/testkube/releases/latest").json(); params.version = release?.tag_name; } else { - const channels = ['stable', params.channel]; + const channels = ["stable", params.channel]; process.stdout.write(`Detecting the latest version for minimum of "${params.channel}" channel...\n`); - const releases: any[] = await got('https://api.github.com/repos/kubeshop/testkube/releases').json(); - const versions = releases.map(release => ({ + const releases: any[] = await got("https://api.github.com/repos/kubeshop/testkube/releases").json(); + const versions = releases.map((release) => ({ tag: release.tag_name, - channel: release.tag_name.match(/-([^0-9]+)/)?.[1] || 'stable', + channel: release.tag_name.match(/-([^0-9]+)/)?.[1] || "stable", })); - params.version = versions.find(({channel}) => channels.includes(channel))?.tag; + params.version = versions.find(({ channel }) => channels.includes(channel))?.tag; } if (!params.version) { - throw new Error('Not found any version matching criteria.'); + throw new Error("Not found any version matching criteria."); } - params.version = params.version.replace(/^v/, ''); + params.version = params.version.replace(/^v/, ""); process.stdout.write(` Latest version: ${params.version}\n`); } - const artifactUrl = `https://github.com/kubeshop/testkube/releases/download/v${encodeURIComponent(params.version)}/testkube_${encodeURIComponent(params.version)}_${encodeURIComponent(system)}_${encodeURIComponent(architecture)}.tar.gz`; - process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); + const encodedVersion = encodeURIComponent(params.version); + const encodedVerSysArch = `${encodeURIComponent(params.version)}_${encodeURIComponent(system)}_${encodeURIComponent( + architecture + )}`; - const artifactStream = got.stream(artifactUrl).pipe(tar.x({C: binaryDirPath}, ['kubectl-testkube'])); + const artifactUrl = `https://github.com/kubeshop/testkube/releases/download/v${encodedVersion}/testkube_${encodedVerSysArch}.tar.gz`; - await stream.promises.finished(artifactStream); + const existingTestkubePath = toolCache.find("kubectl-testkube", params.version); - process.stdout.write(`Extracted CLI to ${binaryDirPath}/kubectl-testkube.\n`); + if (!existingTestkubePath || existingTestkubePath.length === 0) { + process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); + const artifactPath = await toolCache.downloadTool(artifactUrl); + const artifactExtractedPath = await toolCache.extractTar(artifactPath, binaryDirPath); + process.stdout.write(`Extracted CLI to ${binaryDirPath}/kubectl-testkube.\n`); + const cachedDir = await toolCache.cacheDir(artifactExtractedPath, "kubectl-testkube", params.version); + addPath(cachedDir); + } else { + addPath(existingTestkubePath); + process.stdout.write(`Found existing Testkube CLI at "${existingTestkubePath}".\n`); + } + + const testkubePath = existingTestkubePath + ? `${existingTestkubePath}/kubectl-testkube}` + : `${binaryDirPath}/kubectl-testkube`; - await fs.promises.symlink(`${binaryDirPath}/kubectl-testkube`, `${binaryDirPath}/testkube`); + await fs.promises.symlink(`${testkubePath}`, `${binaryDirPath}/testkube`); process.stdout.write(`Linked CLI as ${binaryDirPath}/testkube.\n`); - await fs.promises.symlink(`${binaryDirPath}/kubectl-testkube`, `${binaryDirPath}/tk`); + await fs.promises.symlink(`${testkubePath}`, `${binaryDirPath}/tk`); process.stdout.write(`Linked CLI as ${binaryDirPath}/tk.\n`); } // Configure the Testkube context -const contextArgs = mode === 'kubectl' - ? [ - '--kubeconfig', - '--namespace', params.namespace!, - ] : [ - '--api-key', params.token!, - '--cloud-root-domain', params.url!, - '--org', params.organization!, - '--env', params.environment!, - ]; - -process.exit(spawnSync('testkube', ['set', 'context', ...contextArgs], {stdio: 'inherit'}).status || 0); +const contextArgs = + mode === "kubectl" + ? ["--kubeconfig", "--namespace", params.namespace!] + : [ + "--api-key", + params.token!, + "--cloud-root-domain", + params.url!, + "--org", + params.organization!, + "--env", + params.environment!, + ]; + +process.exit(spawnSync("testkube", ["set", "context", ...contextArgs], { stdio: "inherit" }).status || 0); From a6372464c280e97327cadc13d882adb4d01de8c2 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:23:21 +0200 Subject: [PATCH 2/4] fix: checking if testkube is installed --- src/index.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/index.ts b/src/index.ts index 8cb1108..e95ec4b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -109,8 +109,12 @@ if (mode === "kubectl") { process.stdout.write("kubectl: ignored for Cloud integration\n"); } -// Detect if there is Testkube CLI already installed -if (await which("kubectl-testkube", { nothrow: true })) { +const existingTestkubePath = params.version ? toolCache.find("kubectl-testkube", params.version) : ""; +const isTestkubeInstalled = + existingTestkubePath.length > 0 || Boolean(await which("kubectl-testkube", { nothrow: true })); + +if (isTestkubeInstalled) { + if (existingTestkubePath) addPath(existingTestkubePath); process.stdout.write("Looks like you already have the Testkube CLI installed. Skipping...\n"); } else { // Detect the latest version @@ -147,23 +151,17 @@ if (await which("kubectl-testkube", { nothrow: true })) { const artifactUrl = `https://github.com/kubeshop/testkube/releases/download/v${encodedVersion}/testkube_${encodedVerSysArch}.tar.gz`; - const existingTestkubePath = toolCache.find("kubectl-testkube", params.version); - - if (!existingTestkubePath || existingTestkubePath.length === 0) { + if (!isTestkubeInstalled) { process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); const artifactPath = await toolCache.downloadTool(artifactUrl); const artifactExtractedPath = await toolCache.extractTar(artifactPath, binaryDirPath); process.stdout.write(`Extracted CLI to ${binaryDirPath}/kubectl-testkube.\n`); const cachedDir = await toolCache.cacheDir(artifactExtractedPath, "kubectl-testkube", params.version); addPath(cachedDir); - } else { - addPath(existingTestkubePath); - process.stdout.write(`Found existing Testkube CLI at "${existingTestkubePath}".\n`); } - const testkubePath = existingTestkubePath - ? `${existingTestkubePath}/kubectl-testkube}` - : `${binaryDirPath}/kubectl-testkube`; + const testkubePath = + existingTestkubePath.length > 0 ? `${existingTestkubePath}/kubectl-testkube}` : `${binaryDirPath}/kubectl-testkube`; await fs.promises.symlink(`${testkubePath}`, `${binaryDirPath}/testkube`); process.stdout.write(`Linked CLI as ${binaryDirPath}/testkube.\n`); From 5c8231186a18e241bb5f930a850a77e4a9a3c3f7 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:28:48 +0200 Subject: [PATCH 3/4] chore: update build --- dist/index.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/dist/index.js b/dist/index.js index 3a2fdc8..d4351f0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -10757,8 +10757,11 @@ if (mode === "kubectl") { else { process.stdout.write("kubectl: ignored for Cloud integration\n"); } -// Detect if there is Testkube CLI already installed -if (await which__WEBPACK_IMPORTED_MODULE_5___default()("kubectl-testkube", { nothrow: true })) { +const existingTestkubePath = params.version ? _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.find("kubectl-testkube", params.version) : ""; +const isTestkubeInstalled = existingTestkubePath.length > 0 || Boolean(await which__WEBPACK_IMPORTED_MODULE_5___default()("kubectl-testkube", { nothrow: true })); +if (isTestkubeInstalled) { + if (existingTestkubePath) + (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.addPath)(existingTestkubePath); process.stdout.write("Looks like you already have the Testkube CLI installed. Skipping...\n"); } else { @@ -10792,8 +10795,7 @@ else { const encodedVersion = encodeURIComponent(params.version); const encodedVerSysArch = `${encodeURIComponent(params.version)}_${encodeURIComponent(system)}_${encodeURIComponent(architecture)}`; const artifactUrl = `https://github.com/kubeshop/testkube/releases/download/v${encodedVersion}/testkube_${encodedVerSysArch}.tar.gz`; - const existingTestkubePath = _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.find("kubectl-testkube", params.version); - if (!existingTestkubePath || existingTestkubePath.length === 0) { + if (!isTestkubeInstalled) { process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); const artifactPath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.downloadTool(artifactUrl); const artifactExtractedPath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.extractTar(artifactPath, binaryDirPath); @@ -10801,13 +10803,7 @@ else { const cachedDir = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.cacheDir(artifactExtractedPath, "kubectl-testkube", params.version); (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.addPath)(cachedDir); } - else { - (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.addPath)(existingTestkubePath); - process.stdout.write(`Found existing Testkube CLI at "${existingTestkubePath}".\n`); - } - const testkubePath = existingTestkubePath - ? `${existingTestkubePath}/kubectl-testkube}` - : `${binaryDirPath}/kubectl-testkube`; + const testkubePath = existingTestkubePath.length > 0 ? `${existingTestkubePath}/kubectl-testkube}` : `${binaryDirPath}/kubectl-testkube`; await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${testkubePath}`, `${binaryDirPath}/testkube`); process.stdout.write(`Linked CLI as ${binaryDirPath}/testkube.\n`); await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${testkubePath}`, `${binaryDirPath}/tk`); From a0e4a0f7900745a30bd38cf0a93678e7c380b108 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Fri, 26 Jan 2024 11:32:32 +0200 Subject: [PATCH 4/4] fix: errors when forcing version & detect unknown version --- dist/index.js | 13 ++++++++++++- src/index.ts | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/dist/index.js b/dist/index.js index d4351f0..1c60d74 100644 --- a/dist/index.js +++ b/dist/index.js @@ -10758,7 +10758,9 @@ else { process.stdout.write("kubectl: ignored for Cloud integration\n"); } const existingTestkubePath = params.version ? _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.find("kubectl-testkube", params.version) : ""; -const isTestkubeInstalled = existingTestkubePath.length > 0 || Boolean(await which__WEBPACK_IMPORTED_MODULE_5___default()("kubectl-testkube", { nothrow: true })); +// if params.version is not specified, we will try to detect if there is any version installed +const isUnknowmTestkubeInstalled = !params.version && Boolean(await which__WEBPACK_IMPORTED_MODULE_5___default()("kubectl-testkube", { nothrow: true })); +const isTestkubeInstalled = existingTestkubePath.length > 0 || isUnknowmTestkubeInstalled; if (isTestkubeInstalled) { if (existingTestkubePath) (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.addPath)(existingTestkubePath); @@ -10798,14 +10800,23 @@ else { if (!isTestkubeInstalled) { process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); const artifactPath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.downloadTool(artifactUrl); + if (node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(`${binaryDirPath}/kubectl-testkube`)) { + node_fs__WEBPACK_IMPORTED_MODULE_1__.rmSync(`${binaryDirPath}/kubectl-testkube`); + } const artifactExtractedPath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.extractTar(artifactPath, binaryDirPath); process.stdout.write(`Extracted CLI to ${binaryDirPath}/kubectl-testkube.\n`); const cachedDir = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_3__.cacheDir(artifactExtractedPath, "kubectl-testkube", params.version); (0,_actions_core__WEBPACK_IMPORTED_MODULE_4__.addPath)(cachedDir); } const testkubePath = existingTestkubePath.length > 0 ? `${existingTestkubePath}/kubectl-testkube}` : `${binaryDirPath}/kubectl-testkube`; + if (node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(`${binaryDirPath}/testkube`)) { + node_fs__WEBPACK_IMPORTED_MODULE_1__.rmSync(`${binaryDirPath}/testkube`); + } await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${testkubePath}`, `${binaryDirPath}/testkube`); process.stdout.write(`Linked CLI as ${binaryDirPath}/testkube.\n`); + if (node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(`${binaryDirPath}/tk`)) { + node_fs__WEBPACK_IMPORTED_MODULE_1__.rmSync(`${binaryDirPath}/tk`); + } await node_fs__WEBPACK_IMPORTED_MODULE_1__.promises.symlink(`${testkubePath}`, `${binaryDirPath}/tk`); process.stdout.write(`Linked CLI as ${binaryDirPath}/tk.\n`); } diff --git a/src/index.ts b/src/index.ts index e95ec4b..eeab35b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -110,8 +110,9 @@ if (mode === "kubectl") { } const existingTestkubePath = params.version ? toolCache.find("kubectl-testkube", params.version) : ""; -const isTestkubeInstalled = - existingTestkubePath.length > 0 || Boolean(await which("kubectl-testkube", { nothrow: true })); +// if params.version is not specified, we will try to detect if there is any version installed +const isUnknowmTestkubeInstalled = !params.version && Boolean(await which("kubectl-testkube", { nothrow: true })); +const isTestkubeInstalled = existingTestkubePath.length > 0 || isUnknowmTestkubeInstalled; if (isTestkubeInstalled) { if (existingTestkubePath) addPath(existingTestkubePath); @@ -154,6 +155,9 @@ if (isTestkubeInstalled) { if (!isTestkubeInstalled) { process.stdout.write(`Downloading the artifact from "${artifactUrl}"...\n`); const artifactPath = await toolCache.downloadTool(artifactUrl); + if (fs.existsSync(`${binaryDirPath}/kubectl-testkube`)) { + fs.rmSync(`${binaryDirPath}/kubectl-testkube`); + } const artifactExtractedPath = await toolCache.extractTar(artifactPath, binaryDirPath); process.stdout.write(`Extracted CLI to ${binaryDirPath}/kubectl-testkube.\n`); const cachedDir = await toolCache.cacheDir(artifactExtractedPath, "kubectl-testkube", params.version); @@ -163,9 +167,15 @@ if (isTestkubeInstalled) { const testkubePath = existingTestkubePath.length > 0 ? `${existingTestkubePath}/kubectl-testkube}` : `${binaryDirPath}/kubectl-testkube`; + if (fs.existsSync(`${binaryDirPath}/testkube`)) { + fs.rmSync(`${binaryDirPath}/testkube`); + } await fs.promises.symlink(`${testkubePath}`, `${binaryDirPath}/testkube`); process.stdout.write(`Linked CLI as ${binaryDirPath}/testkube.\n`); + if (fs.existsSync(`${binaryDirPath}/tk`)) { + fs.rmSync(`${binaryDirPath}/tk`); + } await fs.promises.symlink(`${testkubePath}`, `${binaryDirPath}/tk`); process.stdout.write(`Linked CLI as ${binaryDirPath}/tk.\n`); }