diff --git a/.licenses/npm/@actions/cache.dep.yml b/.licenses/npm/@actions/cache.dep.yml index 59bff06..b37997f 100644 Binary files a/.licenses/npm/@actions/cache.dep.yml and b/.licenses/npm/@actions/cache.dep.yml differ diff --git a/.licenses/npm/@actions/http-client.dep.yml b/.licenses/npm/@actions/http-client.dep.yml index 216d36c..cdccff4 100644 Binary files a/.licenses/npm/@actions/http-client.dep.yml and b/.licenses/npm/@actions/http-client.dep.yml differ diff --git a/.licenses/npm/@types/node.dep.yml b/.licenses/npm/@types/node.dep.yml index 77c8dc8..4773dad 100644 Binary files a/.licenses/npm/@types/node.dep.yml and b/.licenses/npm/@types/node.dep.yml differ diff --git a/.licenses/npm/semver-7.5.4.dep.yml b/.licenses/npm/semver-7.6.0.dep.yml similarity index 97% rename from .licenses/npm/semver-7.5.4.dep.yml rename to .licenses/npm/semver-7.6.0.dep.yml index 5de7b63..bd631be 100644 Binary files a/.licenses/npm/semver-7.5.4.dep.yml and b/.licenses/npm/semver-7.6.0.dep.yml differ diff --git a/.licenses/npm/undici-types.dep.yml b/.licenses/npm/undici-types.dep.yml index 5950b57..a65b8af 100644 Binary files a/.licenses/npm/undici-types.dep.yml and b/.licenses/npm/undici-types.dep.yml differ diff --git a/.licenses/npm/undici.dep.yml b/.licenses/npm/undici.dep.yml index 83897d7..58844ed 100644 Binary files a/.licenses/npm/undici.dep.yml and b/.licenses/npm/undici.dep.yml differ diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index 3ced1ad..270721c 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -319,7 +319,8 @@ function createHttpClient() { return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions()); } function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) { - const components = paths; + // don't pass changes upstream + const components = paths.slice(); // Add compression method to cache version to restore // compressed cache as per compression method if (compressionMethod) { @@ -608,26 +609,21 @@ function resolvePaths(patterns) { implicitDescendants: false }); try { - for (var _e = true, _f = __asyncValues(globber.globGenerator()), _g; _g = yield _f.next(), _a = _g.done, !_a;) { + for (var _e = true, _f = __asyncValues(globber.globGenerator()), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) { _c = _g.value; _e = false; - try { - const file = _c; - const relativeFile = path - .relative(workspace, file) - .replace(new RegExp(`\\${path.sep}`, 'g'), '/'); - core.debug(`Matched: ${relativeFile}`); - // Paths are made relative so the tar entries are all relative to the root of the workspace. - if (relativeFile === '') { - // path.relative returns empty string if workspace and file are equal - paths.push('.'); - } - else { - paths.push(`${relativeFile}`); - } + const file = _c; + const relativeFile = path + .relative(workspace, file) + .replace(new RegExp(`\\${path.sep}`, 'g'), '/'); + core.debug(`Matched: ${relativeFile}`); + // Paths are made relative so the tar entries are all relative to the root of the workspace. + if (relativeFile === '') { + // path.relative returns empty string if workspace and file are equal + paths.push('.'); } - finally { - _e = true; + else { + paths.push(`${relativeFile}`); } } } @@ -711,7 +707,10 @@ function assertDefined(name, value) { exports.assertDefined = assertDefined; function isGhes() { const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); - return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; + const hostname = ghUrl.hostname.trimEnd().toUpperCase(); + const isGitHubHost = hostname === 'GITHUB.COM'; + const isGheHost = hostname.endsWith('.GHE.COM') || hostname.endsWith('.GHE.LOCALHOST'); + return !isGitHubHost && !isGheHost; } exports.isGhes = isGhes; //# sourceMappingURL=cacheUtils.js.map @@ -729,7 +728,7 @@ var CacheFilename; (function (CacheFilename) { CacheFilename["Gzip"] = "cache.tgz"; CacheFilename["Zstd"] = "cache.tzst"; -})(CacheFilename = exports.CacheFilename || (exports.CacheFilename = {})); +})(CacheFilename || (exports.CacheFilename = CacheFilename = {})); var CompressionMethod; (function (CompressionMethod) { CompressionMethod["Gzip"] = "gzip"; @@ -737,12 +736,12 @@ var CompressionMethod; // This enum is for earlier version of zstd that does not have --long support CompressionMethod["ZstdWithoutLong"] = "zstd-without-long"; CompressionMethod["Zstd"] = "zstd"; -})(CompressionMethod = exports.CompressionMethod || (exports.CompressionMethod = {})); +})(CompressionMethod || (exports.CompressionMethod = CompressionMethod = {})); var ArchiveToolType; (function (ArchiveToolType) { ArchiveToolType["GNU"] = "gnu"; ArchiveToolType["BSD"] = "bsd"; -})(ArchiveToolType = exports.ArchiveToolType || (exports.ArchiveToolType = {})); +})(ArchiveToolType || (exports.ArchiveToolType = ArchiveToolType = {})); // The default number of retry attempts. exports.DefaultRetryAttempts = 2; // The default delay in milliseconds between retry attempts. @@ -8766,7 +8765,7 @@ class HttpClient { if (this._keepAlive && useProxy) { agent = this._proxyAgent; } - if (this._keepAlive && !useProxy) { + if (!useProxy) { agent = this._agent; } // if agent is already assigned use that agent. @@ -8798,16 +8797,12 @@ class HttpClient { agent = tunnelAgent(agentOptions); this._proxyAgent = agent; } - // if reusing agent across request and tunneling agent isn't assigned create a new agent - if (this._keepAlive && !agent) { + // if tunneling agent isn't assigned create a new agent + if (!agent) { const options = { keepAlive: this._keepAlive, maxSockets }; agent = usingSsl ? new https.Agent(options) : new http.Agent(options); this._agent = agent; } - // if not using private agent and tunnel agent isn't setup then use global agent - if (!agent) { - agent = usingSsl ? https.globalAgent : http.globalAgent; - } if (usingSsl && this._ignoreSslError) { // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options @@ -54532,6 +54527,7 @@ const MockAgent = __nccwpck_require__(6771) const MockPool = __nccwpck_require__(6193) const mockErrors = __nccwpck_require__(888) const ProxyAgent = __nccwpck_require__(7858) +const RetryHandler = __nccwpck_require__(2286) const { getGlobalDispatcher, setGlobalDispatcher } = __nccwpck_require__(1892) const DecoratorHandler = __nccwpck_require__(6930) const RedirectHandler = __nccwpck_require__(2860) @@ -54553,6 +54549,7 @@ module.exports.Pool = Pool module.exports.BalancedPool = BalancedPool module.exports.Agent = Agent module.exports.ProxyAgent = ProxyAgent +module.exports.RetryHandler = RetryHandler module.exports.DecoratorHandler = DecoratorHandler module.exports.RedirectHandler = RedirectHandler @@ -55453,6 +55450,7 @@ function request (opts, callback) { } module.exports = request +module.exports.RequestHandler = RequestHandler /***/ }), @@ -55835,6 +55833,8 @@ const kBody = Symbol('kBody') const kAbort = Symbol('abort') const kContentType = Symbol('kContentType') +const noop = () => {} + module.exports = class BodyReadable extends Readable { constructor ({ resume, @@ -55968,37 +55968,50 @@ module.exports = class BodyReadable extends Readable { return this[kBody] } - async dump (opts) { + dump (opts) { let limit = opts && Number.isFinite(opts.limit) ? opts.limit : 262144 const signal = opts && opts.signal - const abortFn = () => { - this.destroy() - } - let signalListenerCleanup + if (signal) { - if (typeof signal !== 'object' || !('aborted' in signal)) { - throw new InvalidArgumentError('signal must be an AbortSignal') - } - util.throwIfAborted(signal) - signalListenerCleanup = util.addAbortListener(signal, abortFn) - } - try { - for await (const chunk of this) { - util.throwIfAborted(signal) - limit -= Buffer.byteLength(chunk) - if (limit < 0) { - return + try { + if (typeof signal !== 'object' || !('aborted' in signal)) { + throw new InvalidArgumentError('signal must be an AbortSignal') } - } - } catch { - util.throwIfAborted(signal) - } finally { - if (typeof signalListenerCleanup === 'function') { - signalListenerCleanup() - } else if (signalListenerCleanup) { - signalListenerCleanup[Symbol.dispose]() + util.throwIfAborted(signal) + } catch (err) { + return Promise.reject(err) } } + + if (this.closed) { + return Promise.resolve(null) + } + + return new Promise((resolve, reject) => { + const signalListenerCleanup = signal + ? util.addAbortListener(signal, () => { + this.destroy() + }) + : noop + + this + .on('close', function () { + signalListenerCleanup() + if (signal && signal.aborted) { + reject(signal.reason || Object.assign(new Error('The operation was aborted'), { name: 'AbortError' })) + } else { + resolve(null) + } + }) + .on('error', noop) + .on('data', function (chunk) { + limit -= chunk.length + if (limit <= 0) { + this.destroy() + } + }) + .resume() + }) } } @@ -57378,13 +57391,13 @@ module.exports = { /***/ }), /***/ 9174: -/***/ ((module) => { +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; module.exports = { - kConstruct: Symbol('constructable') + kConstruct: (__nccwpck_require__(2785).kConstruct) } @@ -58370,11 +58383,9 @@ class Parser { socket[kReset] = true } - let pause - try { - pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false - } catch (err) { - util.destroy(socket, err) + const pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false + + if (request.aborted) { return -1 } @@ -58421,13 +58432,8 @@ class Parser { this.bytesRead += buf.length - try { - if (request.onData(buf) === false) { - return constants.ERROR.PAUSED - } - } catch (err) { - util.destroy(socket, err) - return -1 + if (request.onData(buf) === false) { + return constants.ERROR.PAUSED } } @@ -58468,11 +58474,7 @@ class Parser { return -1 } - try { - request.onComplete(headers) - } catch (err) { - errorRequest(client, request, err) - } + request.onComplete(headers) client[kQueue][client[kRunningIdx]++] = null @@ -58636,7 +58638,7 @@ async function connect (client) { const idx = hostname.indexOf(']') assert(idx !== -1) - const ip = hostname.substr(1, idx - 1) + const ip = hostname.substring(1, idx) assert(net.isIP(ip)) hostname = ip @@ -58915,23 +58917,7 @@ function _resume (client, sync) { return } - if (util.isStream(request.body) && util.bodyLength(request.body) === 0) { - request.body - .on('data', /* istanbul ignore next */ function () { - /* istanbul ignore next */ - assert(false) - }) - .on('error', function (err) { - errorRequest(client, request, err) - }) - .on('end', function () { - util.destroy(this) - }) - - request.body = null - } - - if (client[kRunning] > 0 && + if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 && (util.isStream(request.body) || util.isAsyncIterable(request.body))) { // Request with stream or iterator body can error while other requests // are inflight and indirectly error those as well. @@ -58952,6 +58938,11 @@ function _resume (client, sync) { } } +// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 +function shouldSendContentLength (method) { + return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT' +} + function write (client, request) { if (client[kHTTPConnVersion] === 'h2') { writeH2(client, client[kHTTP2Session], request) @@ -58980,7 +58971,9 @@ function write (client, request) { body.read(0) } - let contentLength = util.bodyLength(body) + const bodyLength = util.bodyLength(body) + + let contentLength = bodyLength if (contentLength === null) { contentLength = request.contentLength @@ -58995,7 +58988,9 @@ function write (client, request) { contentLength = null } - if (request.contentLength !== null && request.contentLength !== contentLength) { + // https://github.com/nodejs/undici/issues/2046 + // A user agent may send a Content-Length header with 0 value, this should be allowed. + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) { if (client[kStrictContentLength]) { errorRequest(client, request, new RequestContentLengthMismatchError()) return false @@ -59076,7 +59071,7 @@ function write (client, request) { } /* istanbul ignore else: assertion */ - if (!body) { + if (!body || bodyLength === 0) { if (contentLength === 0) { socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1') } else { @@ -59142,6 +59137,7 @@ function writeH2 (client, session, request) { return false } + /** @type {import('node:http2').ClientHttp2Stream} */ let stream const h2State = client[kHTTP2SessionState] @@ -59216,7 +59212,9 @@ function writeH2 (client, session, request) { contentLength = null } - if (request.contentLength != null && request.contentLength !== contentLength) { + // https://github.com/nodejs/undici/issues/2046 + // A user agent may send a Content-Length header with 0 value, this should be allowed. + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) { if (client[kStrictContentLength]) { errorRequest(client, request, new RequestContentLengthMismatchError()) return false @@ -59235,14 +59233,10 @@ function writeH2 (client, session, request) { const shouldEndStream = method === 'GET' || method === 'HEAD' if (expectContinue) { headers[HTTP2_HEADER_EXPECT] = '100-continue' - /** - * @type {import('node:http2').ClientHttp2Stream} - */ stream = session.request(headers, { endStream: shouldEndStream, signal }) stream.once('continue', writeBodyH2) } else { - /** @type {import('node:http2').ClientHttp2Stream} */ stream = session.request(headers, { endStream: shouldEndStream, signal @@ -59254,7 +59248,9 @@ function writeH2 (client, session, request) { ++h2State.openStreams stream.once('response', headers => { - if (request.onHeaders(Number(headers[HTTP2_HEADER_STATUS]), headers, stream.resume.bind(stream), '') === false) { + const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers + + if (request.onHeaders(Number(statusCode), realHeaders, stream.resume.bind(stream), '') === false) { stream.pause() } }) @@ -59264,13 +59260,17 @@ function writeH2 (client, session, request) { }) stream.on('data', (chunk) => { - if (request.onData(chunk) === false) stream.pause() + if (request.onData(chunk) === false) { + stream.pause() + } }) stream.once('close', () => { h2State.openStreams -= 1 // TODO(HTTP/2): unref only if current streams count is 0 - if (h2State.openStreams === 0) session.unref() + if (h2State.openStreams === 0) { + session.unref() + } }) stream.once('error', function (err) { @@ -59430,7 +59430,11 @@ function writeStream ({ h2stream, body, client, request, socket, contentLength, } } const onAbort = function () { - onFinished(new RequestAbortedError()) + if (finished) { + return + } + const err = new RequestAbortedError() + queueMicrotask(() => onFinished(err)) } const onFinished = function (err) { if (finished) { @@ -61035,6 +61039,19 @@ class ResponseExceededMaxSizeError extends UndiciError { } } +class RequestRetryError extends UndiciError { + constructor (message, code, { headers, data }) { + super(message) + Error.captureStackTrace(this, RequestRetryError) + this.name = 'RequestRetryError' + this.message = message || 'Request retry error' + this.code = 'UND_ERR_REQ_RETRY' + this.statusCode = code + this.data = data + this.headers = headers + } +} + module.exports = { HTTPParserError, UndiciError, @@ -61054,7 +61071,8 @@ module.exports = { NotSupportedError, ResponseContentLengthMismatchError, BalancedPoolMissingUpstreamError, - ResponseExceededMaxSizeError + ResponseExceededMaxSizeError, + RequestRetryError } @@ -61178,10 +61196,29 @@ class Request { this.method = method + this.abort = null + if (body == null) { this.body = null } else if (util.isStream(body)) { this.body = body + + const rState = this.body._readableState + if (!rState || !rState.autoDestroy) { + this.endHandler = function autoDestroy () { + util.destroy(this) + } + this.body.on('end', this.endHandler) + } + + this.errorHandler = err => { + if (this.abort) { + this.abort(err) + } else { + this.error = err + } + } + this.body.on('error', this.errorHandler) } else if (util.isBuffer(body)) { this.body = body.byteLength ? body : null } else if (ArrayBuffer.isView(body)) { @@ -61277,9 +61314,9 @@ class Request { onBodySent (chunk) { if (this[kHandler].onBodySent) { try { - this[kHandler].onBodySent(chunk) + return this[kHandler].onBodySent(chunk) } catch (err) { - this.onError(err) + this.abort(err) } } } @@ -61288,13 +61325,26 @@ class Request { if (channels.bodySent.hasSubscribers) { channels.bodySent.publish({ request: this }) } + + if (this[kHandler].onRequestSent) { + try { + return this[kHandler].onRequestSent() + } catch (err) { + this.abort(err) + } + } } onConnect (abort) { assert(!this.aborted) assert(!this.completed) - return this[kHandler].onConnect(abort) + if (this.error) { + abort(this.error) + } else { + this.abort = abort + return this[kHandler].onConnect(abort) + } } onHeaders (statusCode, headers, resume, statusText) { @@ -61305,14 +61355,23 @@ class Request { channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }) } - return this[kHandler].onHeaders(statusCode, headers, resume, statusText) + try { + return this[kHandler].onHeaders(statusCode, headers, resume, statusText) + } catch (err) { + this.abort(err) + } } onData (chunk) { assert(!this.aborted) assert(!this.completed) - return this[kHandler].onData(chunk) + try { + return this[kHandler].onData(chunk) + } catch (err) { + this.abort(err) + return false + } } onUpgrade (statusCode, headers, socket) { @@ -61323,16 +61382,26 @@ class Request { } onComplete (trailers) { + this.onFinally() + assert(!this.aborted) this.completed = true if (channels.trailers.hasSubscribers) { channels.trailers.publish({ request: this, trailers }) } - return this[kHandler].onComplete(trailers) + + try { + return this[kHandler].onComplete(trailers) + } catch (err) { + // TODO (fix): This might be a bad idea? + this.onError(err) + } } onError (error) { + this.onFinally() + if (channels.error.hasSubscribers) { channels.error.publish({ request: this, error }) } @@ -61341,9 +61410,22 @@ class Request { return } this.aborted = true + return this[kHandler].onError(error) } + onFinally () { + if (this.errorHandler) { + this.body.off('error', this.errorHandler) + this.errorHandler = null + } + + if (this.endHandler) { + this.body.off('end', this.endHandler) + this.endHandler = null + } + } + // TODO: adjust to support H2 addHeader (key, value) { processHeader(this, key, value) @@ -61565,7 +61647,9 @@ module.exports = { kHTTP2BuildRequest: Symbol('http2 build request'), kHTTP1BuildRequest: Symbol('http1 build request'), kHTTP2CopyHeaders: Symbol('http2 copy headers'), - kHTTPConnVersion: Symbol('http connection version') + kHTTPConnVersion: Symbol('http connection version'), + kRetryHandlerDefaultRetry: Symbol('retry agent default retry'), + kConstruct: Symbol('constructable') } @@ -61702,13 +61786,13 @@ function getHostname (host) { const idx = host.indexOf(']') assert(idx !== -1) - return host.substr(1, idx - 1) + return host.substring(1, idx) } const idx = host.indexOf(':') if (idx === -1) return host - return host.substr(0, idx) + return host.substring(0, idx) } // IP addresses are not valid server names per RFC6066 @@ -61767,7 +61851,7 @@ function isReadableAborted (stream) { } function destroy (stream, err) { - if (!isStream(stream) || isDestroyed(stream)) { + if (stream == null || !isStream(stream) || isDestroyed(stream)) { return } @@ -61805,7 +61889,7 @@ function parseHeaders (headers, obj = {}) { if (!val) { if (Array.isArray(headers[i + 1])) { - obj[key] = headers[i + 1] + obj[key] = headers[i + 1].map(x => x.toString('utf8')) } else { obj[key] = headers[i + 1].toString('utf8') } @@ -62008,16 +62092,7 @@ function throwIfAborted (signal) { } } -let events function addAbortListener (signal, listener) { - if (typeof Symbol.dispose === 'symbol') { - if (!events) { - events = __nccwpck_require__(2361) - } - if (typeof events.addAbortListener === 'function' && 'aborted' in signal) { - return events.addAbortListener(signal, listener) - } - } if ('addEventListener' in signal) { signal.addEventListener('abort', listener, { once: true }) return () => signal.removeEventListener('abort', listener) @@ -62041,6 +62116,21 @@ function toUSVString (val) { return `${val}` } +// Parsed accordingly to RFC 9110 +// https://www.rfc-editor.org/rfc/rfc9110#field.content-range +function parseRangeHeader (range) { + if (range == null || range === '') return { start: 0, end: null, size: null } + + const m = range ? range.match(/^bytes (\d+)-(\d+)\/(\d+)?$/) : null + return m + ? { + start: parseInt(m[1]), + end: m[2] ? parseInt(m[2]) : null, + size: m[3] ? parseInt(m[3]) : null + } + : null +} + const kEnumerableProperty = Object.create(null) kEnumerableProperty.enumerable = true @@ -62074,9 +62164,11 @@ module.exports = { buildURL, throwIfAborted, addAbortListener, + parseRangeHeader, nodeMajor, nodeMinor, - nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13) + nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13), + safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'] } @@ -62341,6 +62433,8 @@ let ReadableStream = globalThis.ReadableStream /** @type {globalThis['File']} */ const File = NativeFile ?? UndiciFile +const textEncoder = new TextEncoder() +const textDecoder = new TextDecoder() // https://fetch.spec.whatwg.org/#concept-bodyinit-extract function extractBody (object, keepalive = false) { @@ -62364,7 +62458,7 @@ function extractBody (object, keepalive = false) { stream = new ReadableStream({ async pull (controller) { controller.enqueue( - typeof source === 'string' ? new TextEncoder().encode(source) : source + typeof source === 'string' ? textEncoder.encode(source) : source ) queueMicrotask(() => readableStreamClose(controller)) }, @@ -62434,7 +62528,6 @@ function extractBody (object, keepalive = false) { // - That the content-length is calculated in advance. // - And that all parts are pre-encoded and ready to be sent. - const enc = new TextEncoder() const blobParts = [] const rn = new Uint8Array([13, 10]) // '\r\n' length = 0 @@ -62442,13 +62535,13 @@ function extractBody (object, keepalive = false) { for (const [name, value] of object) { if (typeof value === 'string') { - const chunk = enc.encode(prefix + + const chunk = textEncoder.encode(prefix + `; name="${escape(normalizeLinefeeds(name))}"` + `\r\n\r\n${normalizeLinefeeds(value)}\r\n`) blobParts.push(chunk) length += chunk.byteLength } else { - const chunk = enc.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` + + const chunk = textEncoder.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` + (value.name ? `; filename="${escape(value.name)}"` : '') + '\r\n' + `Content-Type: ${ value.type || 'application/octet-stream' @@ -62462,7 +62555,7 @@ function extractBody (object, keepalive = false) { } } - const chunk = enc.encode(`--${boundary}--`) + const chunk = textEncoder.encode(`--${boundary}--`) blobParts.push(chunk) length += chunk.byteLength if (hasUnknownSizeValue) { @@ -62758,14 +62851,16 @@ function bodyMixinMethods (instance) { let text = '' // application/x-www-form-urlencoded parser will keep the BOM. // https://url.spec.whatwg.org/#concept-urlencoded-parser - const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }) + // Note that streaming decoder is stateful and cannot be reused + const streamingDecoder = new TextDecoder('utf-8', { ignoreBOM: true }) + for await (const chunk of consumeBody(this[kState].body)) { if (!isUint8Array(chunk)) { throw new TypeError('Expected Uint8Array chunk') } - text += textDecoder.decode(chunk, { stream: true }) + text += streamingDecoder.decode(chunk, { stream: true }) } - text += textDecoder.decode() + text += streamingDecoder.decode() entries = new URLSearchParams(text) } catch (err) { // istanbul ignore next: Unclear when new URLSearchParams can fail on a string. @@ -62880,7 +62975,7 @@ function utf8DecodeBytes (buffer) { // 3. Process a queue with an instance of UTF-8’s // decoder, ioQueue, output, and "replacement". - const output = new TextDecoder().decode(buffer) + const output = textDecoder.decode(buffer) // 4. Return output. return output @@ -62928,10 +63023,12 @@ module.exports = { const { MessageChannel, receiveMessageOnPort } = __nccwpck_require__(1267) const corsSafeListedMethods = ['GET', 'HEAD', 'POST'] +const corsSafeListedMethodsSet = new Set(corsSafeListedMethods) const nullBodyStatus = [101, 204, 205, 304] const redirectStatus = [301, 302, 303, 307, 308] +const redirectStatusSet = new Set(redirectStatus) // https://fetch.spec.whatwg.org/#block-bad-port const badPorts = [ @@ -62943,6 +63040,8 @@ const badPorts = [ '10080' ] +const badPortsSet = new Set(badPorts) + // https://w3c.github.io/webappsec-referrer-policy/#referrer-policies const referrerPolicy = [ '', @@ -62955,10 +63054,12 @@ const referrerPolicy = [ 'strict-origin-when-cross-origin', 'unsafe-url' ] +const referrerPolicySet = new Set(referrerPolicy) const requestRedirect = ['follow', 'manual', 'error'] const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE'] +const safeMethodsSet = new Set(safeMethods) const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors'] @@ -62993,6 +63094,7 @@ const requestDuplex = [ // http://fetch.spec.whatwg.org/#forbidden-method const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK'] +const forbiddenMethodsSet = new Set(forbiddenMethods) const subresource = [ 'audio', @@ -63008,6 +63110,7 @@ const subresource = [ 'xslt', '' ] +const subresourceSet = new Set(subresource) /** @type {globalThis['DOMException']} */ const DOMException = globalThis.DOMException ?? (() => { @@ -63057,7 +63160,14 @@ module.exports = { nullBodyStatus, safeMethods, badPorts, - requestDuplex + requestDuplex, + subresourceSet, + badPortsSet, + redirectStatusSet, + corsSafeListedMethodsSet, + safeMethodsSet, + forbiddenMethodsSet, + referrerPolicySet } @@ -63187,17 +63297,14 @@ function dataURLProcessor (dataURL) { * @param {boolean} excludeFragment */ function URLSerializer (url, excludeFragment = false) { - const href = url.href - if (!excludeFragment) { - return href + return url.href } - const hash = href.lastIndexOf('#') - if (hash === -1) { - return href - } - return href.slice(0, hash) + const href = url.href + const hashLength = url.hash.length + + return hashLength === 0 ? href : href.substring(0, href.length - hashLength) } // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points @@ -63713,6 +63820,7 @@ const { isBlobLike } = __nccwpck_require__(2538) const { webidl } = __nccwpck_require__(1744) const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(685) const { kEnumerableProperty } = __nccwpck_require__(3983) +const encoder = new TextEncoder() class File extends Blob { constructor (fileBits, fileName, options = {}) { @@ -63986,7 +64094,7 @@ function processBlobParts (parts, options) { } // 3. Append the result of UTF-8 encoding s to bytes. - bytes.push(new TextEncoder().encode(s)) + bytes.push(encoder.encode(s)) } else if ( types.isAnyArrayBuffer(element) || types.isTypedArray(element) @@ -64380,7 +64488,7 @@ module.exports = { -const { kHeadersList } = __nccwpck_require__(2785) +const { kHeadersList, kConstruct } = __nccwpck_require__(2785) const { kGuard } = __nccwpck_require__(5861) const { kEnumerableProperty } = __nccwpck_require__(3983) const { @@ -64394,6 +64502,13 @@ const assert = __nccwpck_require__(9491) const kHeadersMap = Symbol('headers map') const kHeadersSortedMap = Symbol('headers map sorted') +/** + * @param {number} code + */ +function isHTTPWhiteSpaceCharCode (code) { + return code === 0x00a || code === 0x00d || code === 0x009 || code === 0x020 +} + /** * @see https://fetch.spec.whatwg.org/#concept-header-value-normalize * @param {string} potentialValue @@ -64402,12 +64517,12 @@ function headerValueNormalize (potentialValue) { // To normalize a byte sequence potentialValue, remove // any leading and trailing HTTP whitespace bytes from // potentialValue. + let i = 0; let j = potentialValue.length - // Trimming the end with `.replace()` and a RegExp is typically subject to - // ReDoS. This is safer and faster. - let i = potentialValue.length - while (/[\r\n\t ]/.test(potentialValue.charAt(--i))); - return potentialValue.slice(0, i + 1).replace(/^[\r\n\t ]+/, '') + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(j - 1))) --j + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(i))) ++i + + return i === 0 && j === potentialValue.length ? potentialValue : potentialValue.substring(i, j) } function fill (headers, object) { @@ -64416,7 +64531,8 @@ function fill (headers, object) { // 1. If object is a sequence, then for each header in object: // Note: webidl conversion to array has already been done. if (Array.isArray(object)) { - for (const header of object) { + for (let i = 0; i < object.length; ++i) { + const header = object[i] // 1. If header does not contain exactly two items, then throw a TypeError. if (header.length !== 2) { throw webidl.errors.exception({ @@ -64426,15 +64542,16 @@ function fill (headers, object) { } // 2. Append (header’s first item, header’s second item) to headers. - headers.append(header[0], header[1]) + appendHeader(headers, header[0], header[1]) } } else if (typeof object === 'object' && object !== null) { // Note: null should throw // 2. Otherwise, object is a record, then for each key → value in object, // append (key, value) to headers - for (const [key, value] of Object.entries(object)) { - headers.append(key, value) + const keys = Object.keys(object) + for (let i = 0; i < keys.length; ++i) { + appendHeader(headers, keys[i], object[keys[i]]) } } else { throw webidl.errors.conversionFailed({ @@ -64445,6 +64562,50 @@ function fill (headers, object) { } } +/** + * @see https://fetch.spec.whatwg.org/#concept-headers-append + */ +function appendHeader (headers, name, value) { + // 1. Normalize value. + value = headerValueNormalize(value) + + // 2. If name is not a header name or value is not a + // header value, then throw a TypeError. + if (!isValidHeaderName(name)) { + throw webidl.errors.invalidArgument({ + prefix: 'Headers.append', + value: name, + type: 'header name' + }) + } else if (!isValidHeaderValue(value)) { + throw webidl.errors.invalidArgument({ + prefix: 'Headers.append', + value, + type: 'header value' + }) + } + + // 3. If headers’s guard is "immutable", then throw a TypeError. + // 4. Otherwise, if headers’s guard is "request" and name is a + // forbidden header name, return. + // Note: undici does not implement forbidden header names + if (headers[kGuard] === 'immutable') { + throw new TypeError('immutable') + } else if (headers[kGuard] === 'request-no-cors') { + // 5. Otherwise, if headers’s guard is "request-no-cors": + // TODO + } + + // 6. Otherwise, if headers’s guard is "response" and name is a + // forbidden response-header name, return. + + // 7. Append (name, value) to headers’s header list. + return headers[kHeadersList].append(name, value) + + // 8. If headers’s guard is "request-no-cors", then remove + // privileged no-CORS request headers from headers +} + class HeadersList { /** @type {[string, string][]|null} */ cookies = null @@ -64453,7 +64614,7 @@ class HeadersList { if (init instanceof HeadersList) { this[kHeadersMap] = new Map(init[kHeadersMap]) this[kHeadersSortedMap] = init[kHeadersSortedMap] - this.cookies = init.cookies + this.cookies = init.cookies === null ? null : [...init.cookies] } else { this[kHeadersMap] = new Map(init) this[kHeadersSortedMap] = null @@ -64515,7 +64676,7 @@ class HeadersList { // the first such header to value and remove the // others. // 2. Otherwise, append header (name, value) to list. - return this[kHeadersMap].set(lowercaseName, { name, value }) + this[kHeadersMap].set(lowercaseName, { name, value }) } // https://fetch.spec.whatwg.org/#concept-header-list-delete @@ -64528,20 +64689,18 @@ class HeadersList { this.cookies = null } - return this[kHeadersMap].delete(name) + this[kHeadersMap].delete(name) } // https://fetch.spec.whatwg.org/#concept-header-list-get get (name) { - // 1. If list does not contain name, then return null. - if (!this.contains(name)) { - return null - } + const value = this[kHeadersMap].get(name.toLowerCase()) + // 1. If list does not contain name, then return null. // 2. Return the values of all headers in list whose name // is a byte-case-insensitive match for name, // separated from each other by 0x2C 0x20, in order. - return this[kHeadersMap].get(name.toLowerCase())?.value ?? null + return value === undefined ? null : value.value } * [Symbol.iterator] () { @@ -64567,6 +64726,9 @@ class HeadersList { // https://fetch.spec.whatwg.org/#headers-class class Headers { constructor (init = undefined) { + if (init === kConstruct) { + return + } this[kHeadersList] = new HeadersList() // The new Headers(init) constructor steps are: @@ -64590,43 +64752,7 @@ class Headers { name = webidl.converters.ByteString(name) value = webidl.converters.ByteString(value) - // 1. Normalize value. - value = headerValueNormalize(value) - - // 2. If name is not a header name or value is not a - // header value, then throw a TypeError. - if (!isValidHeaderName(name)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.append', - value: name, - type: 'header name' - }) - } else if (!isValidHeaderValue(value)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.append', - value, - type: 'header value' - }) - } - - // 3. If headers’s guard is "immutable", then throw a TypeError. - // 4. Otherwise, if headers’s guard is "request" and name is a - // forbidden header name, return. - // Note: undici does not implement forbidden header names - if (this[kGuard] === 'immutable') { - throw new TypeError('immutable') - } else if (this[kGuard] === 'request-no-cors') { - // 5. Otherwise, if headers’s guard is "request-no-cors": - // TODO - } - - // 6. Otherwise, if headers’s guard is "response" and name is a - // forbidden response-header name, return. - - // 7. Append (name, value) to headers’s header list. - // 8. If headers’s guard is "request-no-cors", then remove - // privileged no-CORS request headers from headers - return this[kHeadersList].append(name, value) + return appendHeader(this, name, value) } // https://fetch.spec.whatwg.org/#dom-headers-delete @@ -64671,7 +64797,7 @@ class Headers { // 7. Delete name from this’s header list. // 8. If this’s guard is "request-no-cors", then remove // privileged no-CORS request headers from this. - return this[kHeadersList].delete(name) + this[kHeadersList].delete(name) } // https://fetch.spec.whatwg.org/#dom-headers-get @@ -64764,7 +64890,7 @@ class Headers { // 7. Set (name, value) in this’s header list. // 8. If this’s guard is "request-no-cors", then remove // privileged no-CORS request headers from this - return this[kHeadersList].set(name, value) + this[kHeadersList].set(name, value) } // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie @@ -64800,7 +64926,8 @@ class Headers { const cookies = this[kHeadersList].cookies // 3. For each name of names: - for (const [name, value] of names) { + for (let i = 0; i < names.length; ++i) { + const [name, value] = names[i] // 1. If name is `set-cookie`, then: if (name === 'set-cookie') { // 1. Let values be a list of all values of headers in list whose name @@ -64808,8 +64935,8 @@ class Headers { // 2. For each value of values: // 1. Append (name, value) to headers. - for (const value of cookies) { - headers.push([name, value]) + for (let j = 0; j < cookies.length; ++j) { + headers.push([name, cookies[j]]) } } else { // 2. Otherwise: @@ -64833,6 +64960,12 @@ class Headers { keys () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'key') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -64843,6 +64976,12 @@ class Headers { values () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'value') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -64853,6 +64992,12 @@ class Headers { entries () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'key+value') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -64984,11 +65129,11 @@ const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(5861) const assert = __nccwpck_require__(9491) const { safelyExtractBody } = __nccwpck_require__(9990) const { - redirectStatus, + redirectStatusSet, nullBodyStatus, - safeMethods, + safeMethodsSet, requestBodyHeader, - subresource, + subresourceSet, DOMException } = __nccwpck_require__(1037) const { kHeadersList } = __nccwpck_require__(2785) @@ -65000,6 +65145,7 @@ const { TransformStream } = __nccwpck_require__(5356) const { getGlobalDispatcher } = __nccwpck_require__(1892) const { webidl } = __nccwpck_require__(1744) const { STATUS_CODES } = __nccwpck_require__(3685) +const GET_OR_HEAD = ['GET', 'HEAD'] /** @type {import('buffer').resolveObjectURL} */ let resolveObjectURL @@ -65223,7 +65369,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') { } // 8. If response’s timing allow passed flag is not set, then: - if (!timingInfo.timingAllowPassed) { + if (!response.timingAllowPassed) { // 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo. timingInfo = createOpaqueTimingInfo({ startTime: timingInfo.startTime @@ -65447,7 +65593,7 @@ function fetching ({ } // 15. If request is a subresource request, then: - if (subresource.includes(request.destination)) { + if (subresourceSet.has(request.destination)) { // TODO } @@ -66001,7 +66147,7 @@ async function httpFetch (fetchParams) { } // 8. If actualResponse’s status is a redirect status, then: - if (redirectStatus.includes(actualResponse.status)) { + if (redirectStatusSet.has(actualResponse.status)) { // 1. If actualResponse’s status is not 303, request’s body is not null, // and the connection uses HTTP/2, then user agents may, and are even // encouraged to, transmit an RST_STREAM frame. @@ -66119,7 +66265,7 @@ function httpRedirectFetch (fetchParams, response) { if ( ([301, 302].includes(actualResponse.status) && request.method === 'POST') || (actualResponse.status === 303 && - !['GET', 'HEAD'].includes(request.method)) + !GET_OR_HEAD.includes(request.method)) ) { // then: // 1. Set request’s method to `GET` and request’s body to null. @@ -66140,6 +66286,9 @@ function httpRedirectFetch (fetchParams, response) { // https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name request.headersList.delete('authorization') + // https://fetch.spec.whatwg.org/#authentication-entries + request.headersList.delete('proxy-authorization', true) + // "Cookie" and "Host" are forbidden request-headers, which undici doesn't implement. request.headersList.delete('cookie') request.headersList.delete('host') @@ -66403,7 +66552,7 @@ async function httpNetworkOrCacheFetch ( // responses in httpCache, as per the "Invalidation" chapter of HTTP // Caching, and set storedResponse to null. [HTTP-CACHING] if ( - !safeMethods.includes(httpRequest.method) && + !safeMethodsSet.has(httpRequest.method) && forwardResponse.status >= 200 && forwardResponse.status <= 399 ) { @@ -66894,7 +67043,7 @@ async function httpNetworkFetch ( path: url.pathname + url.search, origin: url.origin, method: request.method, - body: fetchParams.controller.dispatcher.isMockActive ? request.body && request.body.source : body, + body: fetchParams.controller.dispatcher.isMockActive ? request.body && (request.body.source || request.body.stream) : body, headers: request.headersList.entries, maxRedirections: 0, upgrade: request.mode === 'websocket' ? 'websocket' : undefined @@ -66939,7 +67088,7 @@ async function httpNetworkFetch ( location = val } - headers.append(key, val) + headers[kHeadersList].append(key, val) } } else { const keys = Object.keys(headersList) @@ -66953,7 +67102,7 @@ async function httpNetworkFetch ( location = val } - headers.append(key, val) + headers[kHeadersList].append(key, val) } } @@ -66963,7 +67112,7 @@ async function httpNetworkFetch ( const willFollow = request.redirect === 'follow' && location && - redirectStatus.includes(status) + redirectStatusSet.has(status) // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) { @@ -67057,7 +67206,7 @@ async function httpNetworkFetch ( const key = headersList[n + 0].toString('latin1') const val = headersList[n + 1].toString('latin1') - headers.append(key, val) + headers[kHeadersList].append(key, val) } resolve({ @@ -67100,11 +67249,12 @@ const { isValidHTTPToken, sameOrigin, normalizeMethod, - makePolicyContainer + makePolicyContainer, + normalizeMethodRecord } = __nccwpck_require__(2538) const { - forbiddenMethods, - corsSafeListedMethods, + forbiddenMethodsSet, + corsSafeListedMethodsSet, referrerPolicy, requestRedirect, requestMode, @@ -67117,13 +67267,12 @@ const { kHeaders, kSignal, kState, kGuard, kRealm } = __nccwpck_require__(5861) const { webidl } = __nccwpck_require__(1744) const { getGlobalOrigin } = __nccwpck_require__(1246) const { URLSerializer } = __nccwpck_require__(685) -const { kHeadersList } = __nccwpck_require__(2785) +const { kHeadersList, kConstruct } = __nccwpck_require__(2785) const assert = __nccwpck_require__(9491) const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = __nccwpck_require__(2361) let TransformStream = globalThis.TransformStream -const kInit = Symbol('init') const kAbortController = Symbol('abortController') const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => { @@ -67134,7 +67283,7 @@ const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => { class Request { // https://fetch.spec.whatwg.org/#dom-request constructor (input, init = {}) { - if (input === kInit) { + if (input === kConstruct) { return } @@ -67273,8 +67422,10 @@ class Request { urlList: [...request.urlList] }) + const initHasKey = Object.keys(init).length !== 0 + // 13. If init is not empty, then: - if (Object.keys(init).length > 0) { + if (initHasKey) { // 1. If request’s mode is "navigate", then set it to "same-origin". if (request.mode === 'navigate') { request.mode = 'same-origin' @@ -67389,7 +67540,7 @@ class Request { } // 23. If init["integrity"] exists, then set request’s integrity metadata to it. - if (init.integrity !== undefined && init.integrity != null) { + if (init.integrity != null) { request.integrity = String(init.integrity) } @@ -67405,16 +67556,16 @@ class Request { // 2. If method is not a method or method is a forbidden method, then // throw a TypeError. - if (!isValidHTTPToken(init.method)) { - throw TypeError(`'${init.method}' is not a valid HTTP method.`) + if (!isValidHTTPToken(method)) { + throw new TypeError(`'${method}' is not a valid HTTP method.`) } - if (forbiddenMethods.indexOf(method.toUpperCase()) !== -1) { - throw TypeError(`'${init.method}' HTTP method is unsupported.`) + if (forbiddenMethodsSet.has(method.toUpperCase())) { + throw new TypeError(`'${method}' HTTP method is unsupported.`) } // 3. Normalize method. - method = normalizeMethod(init.method) + method = normalizeMethodRecord[method] ?? normalizeMethod(method) // 4. Set request’s method to method. request.method = method @@ -67485,7 +67636,7 @@ class Request { // 30. Set this’s headers to a new Headers object with this’s relevant // Realm, whose header list is request’s header list and guard is // "request". - this[kHeaders] = new Headers() + this[kHeaders] = new Headers(kConstruct) this[kHeaders][kHeadersList] = request.headersList this[kHeaders][kGuard] = 'request' this[kHeaders][kRealm] = this[kRealm] @@ -67494,7 +67645,7 @@ class Request { if (mode === 'no-cors') { // 1. If this’s request’s method is not a CORS-safelisted method, // then throw a TypeError. - if (!corsSafeListedMethods.includes(request.method)) { + if (!corsSafeListedMethodsSet.has(request.method)) { throw new TypeError( `'${request.method} is unsupported in no-cors mode.` ) @@ -67505,25 +67656,25 @@ class Request { } // 32. If init is not empty, then: - if (Object.keys(init).length !== 0) { + if (initHasKey) { + /** @type {HeadersList} */ + const headersList = this[kHeaders][kHeadersList] // 1. Let headers be a copy of this’s headers and its associated header // list. - let headers = new Headers(this[kHeaders]) - // 2. If init["headers"] exists, then set headers to init["headers"]. - if (init.headers !== undefined) { - headers = init.headers - } + const headers = init.headers !== undefined ? init.headers : new HeadersList(headersList) // 3. Empty this’s headers’s header list. - this[kHeaders][kHeadersList].clear() + headersList.clear() // 4. If headers is a Headers object, then for each header in its header // list, append header’s name/header’s value to this’s headers. - if (headers.constructor.name === 'Headers') { + if (headers instanceof HeadersList) { for (const [key, val] of headers) { - this[kHeaders].append(key, val) + headersList.append(key, val) } + // Note: Copy the `set-cookie` meta-data. + headersList.cookies = headers.cookies } else { // 5. Otherwise, fill this’s headers with headers. fillHeaders(this[kHeaders], headers) @@ -67812,10 +67963,10 @@ class Request { // 3. Let clonedRequestObject be the result of creating a Request object, // given clonedRequest, this’s headers’s guard, and this’s relevant Realm. - const clonedRequestObject = new Request(kInit) + const clonedRequestObject = new Request(kConstruct) clonedRequestObject[kState] = clonedRequest clonedRequestObject[kRealm] = this[kRealm] - clonedRequestObject[kHeaders] = new Headers() + clonedRequestObject[kHeaders] = new Headers(kConstruct) clonedRequestObject[kHeaders][kHeadersList] = clonedRequest.headersList clonedRequestObject[kHeaders][kGuard] = this[kHeaders][kGuard] clonedRequestObject[kHeaders][kRealm] = this[kHeaders][kRealm] @@ -68056,7 +68207,7 @@ const { isomorphicEncode } = __nccwpck_require__(2538) const { - redirectStatus, + redirectStatusSet, nullBodyStatus, DOMException } = __nccwpck_require__(1037) @@ -68065,11 +68216,12 @@ const { webidl } = __nccwpck_require__(1744) const { FormData } = __nccwpck_require__(2015) const { getGlobalOrigin } = __nccwpck_require__(1246) const { URLSerializer } = __nccwpck_require__(685) -const { kHeadersList } = __nccwpck_require__(2785) +const { kHeadersList, kConstruct } = __nccwpck_require__(2785) const assert = __nccwpck_require__(9491) const { types } = __nccwpck_require__(3837) const ReadableStream = globalThis.ReadableStream || (__nccwpck_require__(5356).ReadableStream) +const textEncoder = new TextEncoder('utf-8') // https://fetch.spec.whatwg.org/#response-class class Response { @@ -68099,7 +68251,7 @@ class Response { } // 1. Let bytes the result of running serialize a JavaScript value to JSON bytes on data. - const bytes = new TextEncoder('utf-8').encode( + const bytes = textEncoder.encode( serializeJavascriptValueToJSONString(data) ) @@ -68144,7 +68296,7 @@ class Response { } // 3. If status is not a redirect status, then throw a RangeError. - if (!redirectStatus.includes(status)) { + if (!redirectStatusSet.has(status)) { throw new RangeError('Invalid status code ' + status) } @@ -68185,7 +68337,7 @@ class Response { // 2. Set this’s headers to a new Headers object with this’s relevant // Realm, whose header list is this’s response’s header list and guard // is "response". - this[kHeaders] = new Headers() + this[kHeaders] = new Headers(kConstruct) this[kHeaders][kGuard] = 'response' this[kHeaders][kHeadersList] = this[kState].headersList this[kHeaders][kRealm] = this[kRealm] @@ -68555,11 +68707,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { return webidl.converters.Blob(V, { strict: false }) } - if ( - types.isAnyArrayBuffer(V) || - types.isTypedArray(V) || - types.isDataView(V) - ) { + if (types.isArrayBuffer(V) || types.isTypedArray(V) || types.isDataView(V)) { return webidl.converters.BufferSource(V) } @@ -68642,7 +68790,7 @@ module.exports = { "use strict"; -const { redirectStatus, badPorts, referrerPolicy: referrerPolicyTokens } = __nccwpck_require__(1037) +const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = __nccwpck_require__(1037) const { getGlobalOrigin } = __nccwpck_require__(1246) const { performance } = __nccwpck_require__(4074) const { isBlobLike, toUSVString, ReadableStreamFrom } = __nccwpck_require__(3983) @@ -68671,7 +68819,7 @@ function responseURL (response) { // https://fetch.spec.whatwg.org/#concept-response-location-url function responseLocationURL (response, requestFragment) { // 1. If response’s status is not a redirect status, then return null. - if (!redirectStatus.includes(response.status)) { + if (!redirectStatusSet.has(response.status)) { return null } @@ -68706,7 +68854,7 @@ function requestBadPort (request) { // 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port, // then return blocked. - if (urlIsHttpHttpsScheme(url) && badPorts.includes(url.port)) { + if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) { return 'blocked' } @@ -68745,52 +68893,57 @@ function isValidReasonPhrase (statusText) { return true } -function isTokenChar (c) { - return !( - c >= 0x7f || - c <= 0x20 || - c === '(' || - c === ')' || - c === '<' || - c === '>' || - c === '@' || - c === ',' || - c === ';' || - c === ':' || - c === '\\' || - c === '"' || - c === '/' || - c === '[' || - c === ']' || - c === '?' || - c === '=' || - c === '{' || - c === '}' - ) +/** + * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 + * @param {number} c + */ +function isTokenCharCode (c) { + switch (c) { + case 0x22: + case 0x28: + case 0x29: + case 0x2c: + case 0x2f: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x40: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x7b: + case 0x7d: + // DQUOTE and "(),/:;<=>?@[\]{}" + return false + default: + // VCHAR %x21-7E + return c >= 0x21 && c <= 0x7e + } } -// See RFC 7230, Section 3.2.6. -// https://github.com/chromium/chromium/blob/d7da0240cae77824d1eda25745c4022757499131/third_party/blink/renderer/platform/network/http_parsers.cc#L321 +/** + * @param {string} characters + */ function isValidHTTPToken (characters) { - if (!characters || typeof characters !== 'string') { + if (characters.length === 0) { return false } for (let i = 0; i < characters.length; ++i) { - const c = characters.charCodeAt(i) - if (c > 0x7f || !isTokenChar(c)) { + if (!isTokenCharCode(characters.charCodeAt(i))) { return false } } return true } -// https://fetch.spec.whatwg.org/#header-name -// https://github.com/chromium/chromium/blob/b3d37e6f94f87d59e44662d6078f6a12de845d17/net/http/http_util.cc#L342 +/** + * @see https://fetch.spec.whatwg.org/#header-name + * @param {string} potentialValue + */ function isValidHeaderName (potentialValue) { - if (potentialValue.length === 0) { - return false - } - return isValidHTTPToken(potentialValue) } @@ -68848,7 +69001,7 @@ function setRequestReferrerPolicyOnRedirect (request, actualResponse) { // The left-most policy is the fallback. for (let i = policyHeader.length; i !== 0; i--) { const token = policyHeader[i - 1].trim() - if (referrerPolicyTokens.includes(token)) { + if (referrerPolicyTokens.has(token)) { policy = token break } @@ -69335,11 +69488,30 @@ function isCancelled (fetchParams) { fetchParams.controller.state === 'terminated' } -// https://fetch.spec.whatwg.org/#concept-method-normalize +const normalizeMethodRecord = { + delete: 'DELETE', + DELETE: 'DELETE', + get: 'GET', + GET: 'GET', + head: 'HEAD', + HEAD: 'HEAD', + options: 'OPTIONS', + OPTIONS: 'OPTIONS', + post: 'POST', + POST: 'POST', + put: 'PUT', + PUT: 'PUT' +} + +// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`. +Object.setPrototypeOf(normalizeMethodRecord, null) + +/** + * @see https://fetch.spec.whatwg.org/#concept-method-normalize + * @param {string} method + */ function normalizeMethod (method) { - return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method) - ? method.toUpperCase() - : method + return normalizeMethodRecord[method.toLowerCase()] ?? method } // https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string @@ -69684,7 +69856,8 @@ module.exports = { urlIsLocal, urlHasHttpsScheme, urlIsHttpHttpsScheme, - readAllBytes + readAllBytes, + normalizeMethodRecord } @@ -70123,12 +70296,10 @@ webidl.converters.ByteString = function (V) { // 2. If the value of any element of x is greater than // 255, then throw a TypeError. for (let index = 0; index < x.length; index++) { - const charCode = x.charCodeAt(index) - - if (charCode > 255) { + if (x.charCodeAt(index) > 255) { throw new TypeError( 'Cannot convert argument to a ByteString because the character at ' + - `index ${index} has a value of ${charCode} which is greater than 255.` + `index ${index} has a value of ${x.charCodeAt(index)} which is greater than 255.` ) } } @@ -71805,6 +71976,349 @@ function cleanRequestHeaders (headers, removeContent, unknownOrigin) { module.exports = RedirectHandler +/***/ }), + +/***/ 2286: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const assert = __nccwpck_require__(9491) + +const { kRetryHandlerDefaultRetry } = __nccwpck_require__(2785) +const { RequestRetryError } = __nccwpck_require__(8045) +const { isDisturbed, parseHeaders, parseRangeHeader } = __nccwpck_require__(3983) + +function calculateRetryAfterHeader (retryAfter) { + const current = Date.now() + const diff = new Date(retryAfter).getTime() - current + + return diff +} + +class RetryHandler { + constructor (opts, handlers) { + const { retryOptions, ...dispatchOpts } = opts + const { + // Retry scoped + retry: retryFn, + maxRetries, + maxTimeout, + minTimeout, + timeoutFactor, + // Response scoped + methods, + errorCodes, + retryAfter, + statusCodes + } = retryOptions ?? {} + + this.dispatch = handlers.dispatch + this.handler = handlers.handler + this.opts = dispatchOpts + this.abort = null + this.aborted = false + this.retryOpts = { + retry: retryFn ?? RetryHandler[kRetryHandlerDefaultRetry], + retryAfter: retryAfter ?? true, + maxTimeout: maxTimeout ?? 30 * 1000, // 30s, + timeout: minTimeout ?? 500, // .5s + timeoutFactor: timeoutFactor ?? 2, + maxRetries: maxRetries ?? 5, + // What errors we should retry + methods: methods ?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'], + // Indicates which errors to retry + statusCodes: statusCodes ?? [500, 502, 503, 504, 429], + // List of errors to retry + errorCodes: errorCodes ?? [ + 'ECONNRESET', + 'ECONNREFUSED', + 'ENOTFOUND', + 'ENETDOWN', + 'ENETUNREACH', + 'EHOSTDOWN', + 'EHOSTUNREACH', + 'EPIPE' + ] + } + + this.retryCount = 0 + this.start = 0 + this.end = null + this.etag = null + this.resume = null + + // Handle possible onConnect duplication + this.handler.onConnect(reason => { + this.aborted = true + if (this.abort) { + this.abort(reason) + } else { + this.reason = reason + } + }) + } + + onRequestSent () { + if (this.handler.onRequestSent) { + this.handler.onRequestSent() + } + } + + onUpgrade (statusCode, headers, socket) { + if (this.handler.onUpgrade) { + this.handler.onUpgrade(statusCode, headers, socket) + } + } + + onConnect (abort) { + if (this.aborted) { + abort(this.reason) + } else { + this.abort = abort + } + } + + onBodySent (chunk) { + if (this.handler.onBodySent) return this.handler.onBodySent(chunk) + } + + static [kRetryHandlerDefaultRetry] (err, { state, opts }, cb) { + const { statusCode, code, headers } = err + const { method, retryOptions } = opts + const { + maxRetries, + timeout, + maxTimeout, + timeoutFactor, + statusCodes, + errorCodes, + methods + } = retryOptions + let { counter, currentTimeout } = state + + currentTimeout = + currentTimeout != null && currentTimeout > 0 ? currentTimeout : timeout + + // Any code that is not a Undici's originated and allowed to retry + if ( + code && + code !== 'UND_ERR_REQ_RETRY' && + code !== 'UND_ERR_SOCKET' && + !errorCodes.includes(code) + ) { + cb(err) + return + } + + // If a set of method are provided and the current method is not in the list + if (Array.isArray(methods) && !methods.includes(method)) { + cb(err) + return + } + + // If a set of status code are provided and the current status code is not in the list + if ( + statusCode != null && + Array.isArray(statusCodes) && + !statusCodes.includes(statusCode) + ) { + cb(err) + return + } + + // If we reached the max number of retries + if (counter > maxRetries) { + cb(err) + return + } + + let retryAfterHeader = headers != null && headers['retry-after'] + if (retryAfterHeader) { + retryAfterHeader = Number(retryAfterHeader) + retryAfterHeader = isNaN(retryAfterHeader) + ? calculateRetryAfterHeader(retryAfterHeader) + : retryAfterHeader * 1e3 // Retry-After is in seconds + } + + const retryTimeout = + retryAfterHeader > 0 + ? Math.min(retryAfterHeader, maxTimeout) + : Math.min(currentTimeout * timeoutFactor ** counter, maxTimeout) + + state.currentTimeout = retryTimeout + + setTimeout(() => cb(null), retryTimeout) + } + + onHeaders (statusCode, rawHeaders, resume, statusMessage) { + const headers = parseHeaders(rawHeaders) + + this.retryCount += 1 + + if (statusCode >= 300) { + this.abort( + new RequestRetryError('Request failed', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + // Checkpoint for resume from where we left it + if (this.resume != null) { + this.resume = null + + if (statusCode !== 206) { + return true + } + + const contentRange = parseRangeHeader(headers['content-range']) + // If no content range + if (!contentRange) { + this.abort( + new RequestRetryError('Content-Range mismatch', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + // Let's start with a weak etag check + if (this.etag != null && this.etag !== headers.etag) { + this.abort( + new RequestRetryError('ETag mismatch', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + const { start, size, end = size } = contentRange + + assert(this.start === start, 'content-range mismatch') + assert(this.end == null || this.end === end, 'content-range mismatch') + + this.resume = resume + return true + } + + if (this.end == null) { + if (statusCode === 206) { + // First time we receive 206 + const range = parseRangeHeader(headers['content-range']) + + if (range == null) { + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } + + const { start, size, end = size } = range + + assert( + start != null && Number.isFinite(start) && this.start !== start, + 'content-range mismatch' + ) + assert(Number.isFinite(start)) + assert( + end != null && Number.isFinite(end) && this.end !== end, + 'invalid content-length' + ) + + this.start = start + this.end = end + } + + // We make our best to checkpoint the body for further range headers + if (this.end == null) { + const contentLength = headers['content-length'] + this.end = contentLength != null ? Number(contentLength) : null + } + + assert(Number.isFinite(this.start)) + assert( + this.end == null || Number.isFinite(this.end), + 'invalid content-length' + ) + + this.resume = resume + this.etag = headers.etag != null ? headers.etag : null + + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } + + const err = new RequestRetryError('Request failed', statusCode, { + headers, + count: this.retryCount + }) + + this.abort(err) + + return false + } + + onData (chunk) { + this.start += chunk.length + + return this.handler.onData(chunk) + } + + onComplete (rawTrailers) { + this.retryCount = 0 + return this.handler.onComplete(rawTrailers) + } + + onError (err) { + if (this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) + } + + this.retryOpts.retry( + err, + { + state: { counter: this.retryCount++, currentTimeout: this.retryAfter }, + opts: { retryOptions: this.retryOpts, ...this.opts } + }, + onRetry.bind(this) + ) + + function onRetry (err) { + if (err != null || this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) + } + + if (this.start !== 0) { + this.opts = { + ...this.opts, + headers: { + ...this.opts.headers, + range: `bytes=${this.start}-${this.end ?? ''}` + } + } + } + + try { + this.dispatch(this.opts, this) + } catch (err) { + this.handler.onError(err) + } + } + } +} + +module.exports = RetryHandler + + /***/ }), /***/ 8861: @@ -73617,7 +74131,7 @@ class Pool extends PoolBase { maxCachedSessions, allowH2, socketPath, - timeout: connectTimeout == null ? 10e3 : connectTimeout, + timeout: connectTimeout, ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), ...connect }) @@ -73727,6 +74241,9 @@ class ProxyAgent extends DispatcherBase { this[kProxyTls] = opts.proxyTls this[kProxyHeaders] = opts.headers || {} + const resolvedUrl = new URL(opts.uri) + const { origin, port, host, username, password } = resolvedUrl + if (opts.auth && opts.token) { throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token') } else if (opts.auth) { @@ -73734,11 +74251,10 @@ class ProxyAgent extends DispatcherBase { this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}` } else if (opts.token) { this[kProxyHeaders]['proxy-authorization'] = opts.token + } else if (username && password) { + this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString('base64')}` } - const resolvedUrl = new URL(opts.uri) - const { origin, port, host } = resolvedUrl - const connect = buildConnector({ ...opts.proxyTls }) this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }) this[kClient] = clientFactory(resolvedUrl, { connect }) @@ -73762,7 +74278,7 @@ class ProxyAgent extends DispatcherBase { }) if (statusCode !== 200) { socket.on('error', () => {}).destroy() - callback(new RequestAbortedError('Proxy response !== 200 when HTTP Tunneling')) + callback(new RequestAbortedError(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`)) } if (opts.protocol !== 'https:') { callback(null, socket) diff --git a/dist/setup/index.js b/dist/setup/index.js index 90558a8..1f4334d 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -319,7 +319,8 @@ function createHttpClient() { return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions()); } function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) { - const components = paths; + // don't pass changes upstream + const components = paths.slice(); // Add compression method to cache version to restore // compressed cache as per compression method if (compressionMethod) { @@ -608,26 +609,21 @@ function resolvePaths(patterns) { implicitDescendants: false }); try { - for (var _e = true, _f = __asyncValues(globber.globGenerator()), _g; _g = yield _f.next(), _a = _g.done, !_a;) { + for (var _e = true, _f = __asyncValues(globber.globGenerator()), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) { _c = _g.value; _e = false; - try { - const file = _c; - const relativeFile = path - .relative(workspace, file) - .replace(new RegExp(`\\${path.sep}`, 'g'), '/'); - core.debug(`Matched: ${relativeFile}`); - // Paths are made relative so the tar entries are all relative to the root of the workspace. - if (relativeFile === '') { - // path.relative returns empty string if workspace and file are equal - paths.push('.'); - } - else { - paths.push(`${relativeFile}`); - } + const file = _c; + const relativeFile = path + .relative(workspace, file) + .replace(new RegExp(`\\${path.sep}`, 'g'), '/'); + core.debug(`Matched: ${relativeFile}`); + // Paths are made relative so the tar entries are all relative to the root of the workspace. + if (relativeFile === '') { + // path.relative returns empty string if workspace and file are equal + paths.push('.'); } - finally { - _e = true; + else { + paths.push(`${relativeFile}`); } } } @@ -711,7 +707,10 @@ function assertDefined(name, value) { exports.assertDefined = assertDefined; function isGhes() { const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); - return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; + const hostname = ghUrl.hostname.trimEnd().toUpperCase(); + const isGitHubHost = hostname === 'GITHUB.COM'; + const isGheHost = hostname.endsWith('.GHE.COM') || hostname.endsWith('.GHE.LOCALHOST'); + return !isGitHubHost && !isGheHost; } exports.isGhes = isGhes; //# sourceMappingURL=cacheUtils.js.map @@ -729,7 +728,7 @@ var CacheFilename; (function (CacheFilename) { CacheFilename["Gzip"] = "cache.tgz"; CacheFilename["Zstd"] = "cache.tzst"; -})(CacheFilename = exports.CacheFilename || (exports.CacheFilename = {})); +})(CacheFilename || (exports.CacheFilename = CacheFilename = {})); var CompressionMethod; (function (CompressionMethod) { CompressionMethod["Gzip"] = "gzip"; @@ -737,12 +736,12 @@ var CompressionMethod; // This enum is for earlier version of zstd that does not have --long support CompressionMethod["ZstdWithoutLong"] = "zstd-without-long"; CompressionMethod["Zstd"] = "zstd"; -})(CompressionMethod = exports.CompressionMethod || (exports.CompressionMethod = {})); +})(CompressionMethod || (exports.CompressionMethod = CompressionMethod = {})); var ArchiveToolType; (function (ArchiveToolType) { ArchiveToolType["GNU"] = "gnu"; ArchiveToolType["BSD"] = "bsd"; -})(ArchiveToolType = exports.ArchiveToolType || (exports.ArchiveToolType = {})); +})(ArchiveToolType || (exports.ArchiveToolType = ArchiveToolType = {})); // The default number of retry attempts. exports.DefaultRetryAttempts = 2; // The default delay in milliseconds between retry attempts. @@ -8982,7 +8981,7 @@ class HttpClient { if (this._keepAlive && useProxy) { agent = this._proxyAgent; } - if (this._keepAlive && !useProxy) { + if (!useProxy) { agent = this._agent; } // if agent is already assigned use that agent. @@ -9014,16 +9013,12 @@ class HttpClient { agent = tunnelAgent(agentOptions); this._proxyAgent = agent; } - // if reusing agent across request and tunneling agent isn't assigned create a new agent - if (this._keepAlive && !agent) { + // if tunneling agent isn't assigned create a new agent + if (!agent) { const options = { keepAlive: this._keepAlive, maxSockets }; agent = usingSsl ? new https.Agent(options) : new http.Agent(options); this._agent = agent; } - // if not using private agent and tunnel agent isn't setup then use global agent - if (!agent) { - agent = usingSsl ? https.globalAgent : http.globalAgent; - } if (usingSsl && this._ignoreSslError) { // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options @@ -60218,35 +60213,43 @@ const coerce = (version, options) => { let match = null if (!options.rtl) { - match = version.match(re[t.COERCE]) + match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[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' + // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.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. + const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL] let next - while ((next = re[t.COERCERTL].exec(version)) && + while ((next = coerceRtlRegex.exec(version)) && (!match || match.index + match[0].length !== version.length) ) { if (!match || next.index + next[0].length !== match.index + match[0].length) { match = next } - re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length + coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length } // leave it in a clean state - re[t.COERCERTL].lastIndex = -1 + coerceRtlRegex.lastIndex = -1 } if (match === null) { return null } - return parse(`${match[2]}.${match[3] || '0'}.${match[4] || '0'}`, options) + const major = match[2] + const minor = match[3] || '0' + const patch = match[4] || '0' + const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : '' + const build = options.includePrerelease && match[6] ? `+${match[6]}` : '' + + return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options) } module.exports = coerce @@ -60938,12 +60941,17 @@ createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) // Coercion. // Extract anything that could conceivably be a part of a valid semver -createToken('COERCE', `${'(^|[^\\d])' + +createToken('COERCEPLAIN', `${'(^|[^\\d])' + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) +createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`) +createToken('COERCEFULL', src[t.COERCEPLAIN] + + `(?:${src[t.PRERELEASE]})?` + + `(?:${src[t.BUILD]})?` + `(?:$|[^\\d])`) createToken('COERCERTL', src[t.COERCE], true) +createToken('COERCERTLFULL', src[t.COERCEFULL], true) // Tilde ranges. // Meaning is "reasonably at or greater than" @@ -63315,6 +63323,7 @@ const MockAgent = __nccwpck_require__(6771) const MockPool = __nccwpck_require__(6193) const mockErrors = __nccwpck_require__(888) const ProxyAgent = __nccwpck_require__(7858) +const RetryHandler = __nccwpck_require__(2286) const { getGlobalDispatcher, setGlobalDispatcher } = __nccwpck_require__(1892) const DecoratorHandler = __nccwpck_require__(6930) const RedirectHandler = __nccwpck_require__(2860) @@ -63336,6 +63345,7 @@ module.exports.Pool = Pool module.exports.BalancedPool = BalancedPool module.exports.Agent = Agent module.exports.ProxyAgent = ProxyAgent +module.exports.RetryHandler = RetryHandler module.exports.DecoratorHandler = DecoratorHandler module.exports.RedirectHandler = RedirectHandler @@ -64236,6 +64246,7 @@ function request (opts, callback) { } module.exports = request +module.exports.RequestHandler = RequestHandler /***/ }), @@ -64618,6 +64629,8 @@ const kBody = Symbol('kBody') const kAbort = Symbol('abort') const kContentType = Symbol('kContentType') +const noop = () => {} + module.exports = class BodyReadable extends Readable { constructor ({ resume, @@ -64751,37 +64764,50 @@ module.exports = class BodyReadable extends Readable { return this[kBody] } - async dump (opts) { + dump (opts) { let limit = opts && Number.isFinite(opts.limit) ? opts.limit : 262144 const signal = opts && opts.signal - const abortFn = () => { - this.destroy() - } - let signalListenerCleanup + if (signal) { - if (typeof signal !== 'object' || !('aborted' in signal)) { - throw new InvalidArgumentError('signal must be an AbortSignal') - } - util.throwIfAborted(signal) - signalListenerCleanup = util.addAbortListener(signal, abortFn) - } - try { - for await (const chunk of this) { - util.throwIfAborted(signal) - limit -= Buffer.byteLength(chunk) - if (limit < 0) { - return + try { + if (typeof signal !== 'object' || !('aborted' in signal)) { + throw new InvalidArgumentError('signal must be an AbortSignal') } - } - } catch { - util.throwIfAborted(signal) - } finally { - if (typeof signalListenerCleanup === 'function') { - signalListenerCleanup() - } else if (signalListenerCleanup) { - signalListenerCleanup[Symbol.dispose]() + util.throwIfAborted(signal) + } catch (err) { + return Promise.reject(err) } } + + if (this.closed) { + return Promise.resolve(null) + } + + return new Promise((resolve, reject) => { + const signalListenerCleanup = signal + ? util.addAbortListener(signal, () => { + this.destroy() + }) + : noop + + this + .on('close', function () { + signalListenerCleanup() + if (signal && signal.aborted) { + reject(signal.reason || Object.assign(new Error('The operation was aborted'), { name: 'AbortError' })) + } else { + resolve(null) + } + }) + .on('error', noop) + .on('data', function (chunk) { + limit -= chunk.length + if (limit <= 0) { + this.destroy() + } + }) + .resume() + }) } } @@ -66161,13 +66187,13 @@ module.exports = { /***/ }), /***/ 9174: -/***/ ((module) => { +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; module.exports = { - kConstruct: Symbol('constructable') + kConstruct: (__nccwpck_require__(2785).kConstruct) } @@ -67153,11 +67179,9 @@ class Parser { socket[kReset] = true } - let pause - try { - pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false - } catch (err) { - util.destroy(socket, err) + const pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false + + if (request.aborted) { return -1 } @@ -67204,13 +67228,8 @@ class Parser { this.bytesRead += buf.length - try { - if (request.onData(buf) === false) { - return constants.ERROR.PAUSED - } - } catch (err) { - util.destroy(socket, err) - return -1 + if (request.onData(buf) === false) { + return constants.ERROR.PAUSED } } @@ -67251,11 +67270,7 @@ class Parser { return -1 } - try { - request.onComplete(headers) - } catch (err) { - errorRequest(client, request, err) - } + request.onComplete(headers) client[kQueue][client[kRunningIdx]++] = null @@ -67419,7 +67434,7 @@ async function connect (client) { const idx = hostname.indexOf(']') assert(idx !== -1) - const ip = hostname.substr(1, idx - 1) + const ip = hostname.substring(1, idx) assert(net.isIP(ip)) hostname = ip @@ -67698,23 +67713,7 @@ function _resume (client, sync) { return } - if (util.isStream(request.body) && util.bodyLength(request.body) === 0) { - request.body - .on('data', /* istanbul ignore next */ function () { - /* istanbul ignore next */ - assert(false) - }) - .on('error', function (err) { - errorRequest(client, request, err) - }) - .on('end', function () { - util.destroy(this) - }) - - request.body = null - } - - if (client[kRunning] > 0 && + if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 && (util.isStream(request.body) || util.isAsyncIterable(request.body))) { // Request with stream or iterator body can error while other requests // are inflight and indirectly error those as well. @@ -67735,6 +67734,11 @@ function _resume (client, sync) { } } +// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 +function shouldSendContentLength (method) { + return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT' +} + function write (client, request) { if (client[kHTTPConnVersion] === 'h2') { writeH2(client, client[kHTTP2Session], request) @@ -67763,7 +67767,9 @@ function write (client, request) { body.read(0) } - let contentLength = util.bodyLength(body) + const bodyLength = util.bodyLength(body) + + let contentLength = bodyLength if (contentLength === null) { contentLength = request.contentLength @@ -67778,7 +67784,9 @@ function write (client, request) { contentLength = null } - if (request.contentLength !== null && request.contentLength !== contentLength) { + // https://github.com/nodejs/undici/issues/2046 + // A user agent may send a Content-Length header with 0 value, this should be allowed. + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) { if (client[kStrictContentLength]) { errorRequest(client, request, new RequestContentLengthMismatchError()) return false @@ -67859,7 +67867,7 @@ function write (client, request) { } /* istanbul ignore else: assertion */ - if (!body) { + if (!body || bodyLength === 0) { if (contentLength === 0) { socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1') } else { @@ -67925,6 +67933,7 @@ function writeH2 (client, session, request) { return false } + /** @type {import('node:http2').ClientHttp2Stream} */ let stream const h2State = client[kHTTP2SessionState] @@ -67999,7 +68008,9 @@ function writeH2 (client, session, request) { contentLength = null } - if (request.contentLength != null && request.contentLength !== contentLength) { + // https://github.com/nodejs/undici/issues/2046 + // A user agent may send a Content-Length header with 0 value, this should be allowed. + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) { if (client[kStrictContentLength]) { errorRequest(client, request, new RequestContentLengthMismatchError()) return false @@ -68018,14 +68029,10 @@ function writeH2 (client, session, request) { const shouldEndStream = method === 'GET' || method === 'HEAD' if (expectContinue) { headers[HTTP2_HEADER_EXPECT] = '100-continue' - /** - * @type {import('node:http2').ClientHttp2Stream} - */ stream = session.request(headers, { endStream: shouldEndStream, signal }) stream.once('continue', writeBodyH2) } else { - /** @type {import('node:http2').ClientHttp2Stream} */ stream = session.request(headers, { endStream: shouldEndStream, signal @@ -68037,7 +68044,9 @@ function writeH2 (client, session, request) { ++h2State.openStreams stream.once('response', headers => { - if (request.onHeaders(Number(headers[HTTP2_HEADER_STATUS]), headers, stream.resume.bind(stream), '') === false) { + const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers + + if (request.onHeaders(Number(statusCode), realHeaders, stream.resume.bind(stream), '') === false) { stream.pause() } }) @@ -68047,13 +68056,17 @@ function writeH2 (client, session, request) { }) stream.on('data', (chunk) => { - if (request.onData(chunk) === false) stream.pause() + if (request.onData(chunk) === false) { + stream.pause() + } }) stream.once('close', () => { h2State.openStreams -= 1 // TODO(HTTP/2): unref only if current streams count is 0 - if (h2State.openStreams === 0) session.unref() + if (h2State.openStreams === 0) { + session.unref() + } }) stream.once('error', function (err) { @@ -68213,7 +68226,11 @@ function writeStream ({ h2stream, body, client, request, socket, contentLength, } } const onAbort = function () { - onFinished(new RequestAbortedError()) + if (finished) { + return + } + const err = new RequestAbortedError() + queueMicrotask(() => onFinished(err)) } const onFinished = function (err) { if (finished) { @@ -69818,6 +69835,19 @@ class ResponseExceededMaxSizeError extends UndiciError { } } +class RequestRetryError extends UndiciError { + constructor (message, code, { headers, data }) { + super(message) + Error.captureStackTrace(this, RequestRetryError) + this.name = 'RequestRetryError' + this.message = message || 'Request retry error' + this.code = 'UND_ERR_REQ_RETRY' + this.statusCode = code + this.data = data + this.headers = headers + } +} + module.exports = { HTTPParserError, UndiciError, @@ -69837,7 +69867,8 @@ module.exports = { NotSupportedError, ResponseContentLengthMismatchError, BalancedPoolMissingUpstreamError, - ResponseExceededMaxSizeError + ResponseExceededMaxSizeError, + RequestRetryError } @@ -69961,10 +69992,29 @@ class Request { this.method = method + this.abort = null + if (body == null) { this.body = null } else if (util.isStream(body)) { this.body = body + + const rState = this.body._readableState + if (!rState || !rState.autoDestroy) { + this.endHandler = function autoDestroy () { + util.destroy(this) + } + this.body.on('end', this.endHandler) + } + + this.errorHandler = err => { + if (this.abort) { + this.abort(err) + } else { + this.error = err + } + } + this.body.on('error', this.errorHandler) } else if (util.isBuffer(body)) { this.body = body.byteLength ? body : null } else if (ArrayBuffer.isView(body)) { @@ -70060,9 +70110,9 @@ class Request { onBodySent (chunk) { if (this[kHandler].onBodySent) { try { - this[kHandler].onBodySent(chunk) + return this[kHandler].onBodySent(chunk) } catch (err) { - this.onError(err) + this.abort(err) } } } @@ -70071,13 +70121,26 @@ class Request { if (channels.bodySent.hasSubscribers) { channels.bodySent.publish({ request: this }) } + + if (this[kHandler].onRequestSent) { + try { + return this[kHandler].onRequestSent() + } catch (err) { + this.abort(err) + } + } } onConnect (abort) { assert(!this.aborted) assert(!this.completed) - return this[kHandler].onConnect(abort) + if (this.error) { + abort(this.error) + } else { + this.abort = abort + return this[kHandler].onConnect(abort) + } } onHeaders (statusCode, headers, resume, statusText) { @@ -70088,14 +70151,23 @@ class Request { channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }) } - return this[kHandler].onHeaders(statusCode, headers, resume, statusText) + try { + return this[kHandler].onHeaders(statusCode, headers, resume, statusText) + } catch (err) { + this.abort(err) + } } onData (chunk) { assert(!this.aborted) assert(!this.completed) - return this[kHandler].onData(chunk) + try { + return this[kHandler].onData(chunk) + } catch (err) { + this.abort(err) + return false + } } onUpgrade (statusCode, headers, socket) { @@ -70106,16 +70178,26 @@ class Request { } onComplete (trailers) { + this.onFinally() + assert(!this.aborted) this.completed = true if (channels.trailers.hasSubscribers) { channels.trailers.publish({ request: this, trailers }) } - return this[kHandler].onComplete(trailers) + + try { + return this[kHandler].onComplete(trailers) + } catch (err) { + // TODO (fix): This might be a bad idea? + this.onError(err) + } } onError (error) { + this.onFinally() + if (channels.error.hasSubscribers) { channels.error.publish({ request: this, error }) } @@ -70124,9 +70206,22 @@ class Request { return } this.aborted = true + return this[kHandler].onError(error) } + onFinally () { + if (this.errorHandler) { + this.body.off('error', this.errorHandler) + this.errorHandler = null + } + + if (this.endHandler) { + this.body.off('end', this.endHandler) + this.endHandler = null + } + } + // TODO: adjust to support H2 addHeader (key, value) { processHeader(this, key, value) @@ -70348,7 +70443,9 @@ module.exports = { kHTTP2BuildRequest: Symbol('http2 build request'), kHTTP1BuildRequest: Symbol('http1 build request'), kHTTP2CopyHeaders: Symbol('http2 copy headers'), - kHTTPConnVersion: Symbol('http connection version') + kHTTPConnVersion: Symbol('http connection version'), + kRetryHandlerDefaultRetry: Symbol('retry agent default retry'), + kConstruct: Symbol('constructable') } @@ -70485,13 +70582,13 @@ function getHostname (host) { const idx = host.indexOf(']') assert(idx !== -1) - return host.substr(1, idx - 1) + return host.substring(1, idx) } const idx = host.indexOf(':') if (idx === -1) return host - return host.substr(0, idx) + return host.substring(0, idx) } // IP addresses are not valid server names per RFC6066 @@ -70550,7 +70647,7 @@ function isReadableAborted (stream) { } function destroy (stream, err) { - if (!isStream(stream) || isDestroyed(stream)) { + if (stream == null || !isStream(stream) || isDestroyed(stream)) { return } @@ -70588,7 +70685,7 @@ function parseHeaders (headers, obj = {}) { if (!val) { if (Array.isArray(headers[i + 1])) { - obj[key] = headers[i + 1] + obj[key] = headers[i + 1].map(x => x.toString('utf8')) } else { obj[key] = headers[i + 1].toString('utf8') } @@ -70791,16 +70888,7 @@ function throwIfAborted (signal) { } } -let events function addAbortListener (signal, listener) { - if (typeof Symbol.dispose === 'symbol') { - if (!events) { - events = __nccwpck_require__(2361) - } - if (typeof events.addAbortListener === 'function' && 'aborted' in signal) { - return events.addAbortListener(signal, listener) - } - } if ('addEventListener' in signal) { signal.addEventListener('abort', listener, { once: true }) return () => signal.removeEventListener('abort', listener) @@ -70824,6 +70912,21 @@ function toUSVString (val) { return `${val}` } +// Parsed accordingly to RFC 9110 +// https://www.rfc-editor.org/rfc/rfc9110#field.content-range +function parseRangeHeader (range) { + if (range == null || range === '') return { start: 0, end: null, size: null } + + const m = range ? range.match(/^bytes (\d+)-(\d+)\/(\d+)?$/) : null + return m + ? { + start: parseInt(m[1]), + end: m[2] ? parseInt(m[2]) : null, + size: m[3] ? parseInt(m[3]) : null + } + : null +} + const kEnumerableProperty = Object.create(null) kEnumerableProperty.enumerable = true @@ -70857,9 +70960,11 @@ module.exports = { buildURL, throwIfAborted, addAbortListener, + parseRangeHeader, nodeMajor, nodeMinor, - nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13) + nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13), + safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'] } @@ -71124,6 +71229,8 @@ let ReadableStream = globalThis.ReadableStream /** @type {globalThis['File']} */ const File = NativeFile ?? UndiciFile +const textEncoder = new TextEncoder() +const textDecoder = new TextDecoder() // https://fetch.spec.whatwg.org/#concept-bodyinit-extract function extractBody (object, keepalive = false) { @@ -71147,7 +71254,7 @@ function extractBody (object, keepalive = false) { stream = new ReadableStream({ async pull (controller) { controller.enqueue( - typeof source === 'string' ? new TextEncoder().encode(source) : source + typeof source === 'string' ? textEncoder.encode(source) : source ) queueMicrotask(() => readableStreamClose(controller)) }, @@ -71217,7 +71324,6 @@ function extractBody (object, keepalive = false) { // - That the content-length is calculated in advance. // - And that all parts are pre-encoded and ready to be sent. - const enc = new TextEncoder() const blobParts = [] const rn = new Uint8Array([13, 10]) // '\r\n' length = 0 @@ -71225,13 +71331,13 @@ function extractBody (object, keepalive = false) { for (const [name, value] of object) { if (typeof value === 'string') { - const chunk = enc.encode(prefix + + const chunk = textEncoder.encode(prefix + `; name="${escape(normalizeLinefeeds(name))}"` + `\r\n\r\n${normalizeLinefeeds(value)}\r\n`) blobParts.push(chunk) length += chunk.byteLength } else { - const chunk = enc.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` + + const chunk = textEncoder.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` + (value.name ? `; filename="${escape(value.name)}"` : '') + '\r\n' + `Content-Type: ${ value.type || 'application/octet-stream' @@ -71245,7 +71351,7 @@ function extractBody (object, keepalive = false) { } } - const chunk = enc.encode(`--${boundary}--`) + const chunk = textEncoder.encode(`--${boundary}--`) blobParts.push(chunk) length += chunk.byteLength if (hasUnknownSizeValue) { @@ -71541,14 +71647,16 @@ function bodyMixinMethods (instance) { let text = '' // application/x-www-form-urlencoded parser will keep the BOM. // https://url.spec.whatwg.org/#concept-urlencoded-parser - const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }) + // Note that streaming decoder is stateful and cannot be reused + const streamingDecoder = new TextDecoder('utf-8', { ignoreBOM: true }) + for await (const chunk of consumeBody(this[kState].body)) { if (!isUint8Array(chunk)) { throw new TypeError('Expected Uint8Array chunk') } - text += textDecoder.decode(chunk, { stream: true }) + text += streamingDecoder.decode(chunk, { stream: true }) } - text += textDecoder.decode() + text += streamingDecoder.decode() entries = new URLSearchParams(text) } catch (err) { // istanbul ignore next: Unclear when new URLSearchParams can fail on a string. @@ -71663,7 +71771,7 @@ function utf8DecodeBytes (buffer) { // 3. Process a queue with an instance of UTF-8’s // decoder, ioQueue, output, and "replacement". - const output = new TextDecoder().decode(buffer) + const output = textDecoder.decode(buffer) // 4. Return output. return output @@ -71711,10 +71819,12 @@ module.exports = { const { MessageChannel, receiveMessageOnPort } = __nccwpck_require__(1267) const corsSafeListedMethods = ['GET', 'HEAD', 'POST'] +const corsSafeListedMethodsSet = new Set(corsSafeListedMethods) const nullBodyStatus = [101, 204, 205, 304] const redirectStatus = [301, 302, 303, 307, 308] +const redirectStatusSet = new Set(redirectStatus) // https://fetch.spec.whatwg.org/#block-bad-port const badPorts = [ @@ -71726,6 +71836,8 @@ const badPorts = [ '10080' ] +const badPortsSet = new Set(badPorts) + // https://w3c.github.io/webappsec-referrer-policy/#referrer-policies const referrerPolicy = [ '', @@ -71738,10 +71850,12 @@ const referrerPolicy = [ 'strict-origin-when-cross-origin', 'unsafe-url' ] +const referrerPolicySet = new Set(referrerPolicy) const requestRedirect = ['follow', 'manual', 'error'] const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE'] +const safeMethodsSet = new Set(safeMethods) const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors'] @@ -71776,6 +71890,7 @@ const requestDuplex = [ // http://fetch.spec.whatwg.org/#forbidden-method const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK'] +const forbiddenMethodsSet = new Set(forbiddenMethods) const subresource = [ 'audio', @@ -71791,6 +71906,7 @@ const subresource = [ 'xslt', '' ] +const subresourceSet = new Set(subresource) /** @type {globalThis['DOMException']} */ const DOMException = globalThis.DOMException ?? (() => { @@ -71840,7 +71956,14 @@ module.exports = { nullBodyStatus, safeMethods, badPorts, - requestDuplex + requestDuplex, + subresourceSet, + badPortsSet, + redirectStatusSet, + corsSafeListedMethodsSet, + safeMethodsSet, + forbiddenMethodsSet, + referrerPolicySet } @@ -71970,17 +72093,14 @@ function dataURLProcessor (dataURL) { * @param {boolean} excludeFragment */ function URLSerializer (url, excludeFragment = false) { - const href = url.href - if (!excludeFragment) { - return href + return url.href } - const hash = href.lastIndexOf('#') - if (hash === -1) { - return href - } - return href.slice(0, hash) + const href = url.href + const hashLength = url.hash.length + + return hashLength === 0 ? href : href.substring(0, href.length - hashLength) } // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points @@ -72496,6 +72616,7 @@ const { isBlobLike } = __nccwpck_require__(2538) const { webidl } = __nccwpck_require__(1744) const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(685) const { kEnumerableProperty } = __nccwpck_require__(3983) +const encoder = new TextEncoder() class File extends Blob { constructor (fileBits, fileName, options = {}) { @@ -72769,7 +72890,7 @@ function processBlobParts (parts, options) { } // 3. Append the result of UTF-8 encoding s to bytes. - bytes.push(new TextEncoder().encode(s)) + bytes.push(encoder.encode(s)) } else if ( types.isAnyArrayBuffer(element) || types.isTypedArray(element) @@ -73163,7 +73284,7 @@ module.exports = { -const { kHeadersList } = __nccwpck_require__(2785) +const { kHeadersList, kConstruct } = __nccwpck_require__(2785) const { kGuard } = __nccwpck_require__(5861) const { kEnumerableProperty } = __nccwpck_require__(3983) const { @@ -73177,6 +73298,13 @@ const assert = __nccwpck_require__(9491) const kHeadersMap = Symbol('headers map') const kHeadersSortedMap = Symbol('headers map sorted') +/** + * @param {number} code + */ +function isHTTPWhiteSpaceCharCode (code) { + return code === 0x00a || code === 0x00d || code === 0x009 || code === 0x020 +} + /** * @see https://fetch.spec.whatwg.org/#concept-header-value-normalize * @param {string} potentialValue @@ -73185,12 +73313,12 @@ function headerValueNormalize (potentialValue) { // To normalize a byte sequence potentialValue, remove // any leading and trailing HTTP whitespace bytes from // potentialValue. + let i = 0; let j = potentialValue.length - // Trimming the end with `.replace()` and a RegExp is typically subject to - // ReDoS. This is safer and faster. - let i = potentialValue.length - while (/[\r\n\t ]/.test(potentialValue.charAt(--i))); - return potentialValue.slice(0, i + 1).replace(/^[\r\n\t ]+/, '') + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(j - 1))) --j + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(i))) ++i + + return i === 0 && j === potentialValue.length ? potentialValue : potentialValue.substring(i, j) } function fill (headers, object) { @@ -73199,7 +73327,8 @@ function fill (headers, object) { // 1. If object is a sequence, then for each header in object: // Note: webidl conversion to array has already been done. if (Array.isArray(object)) { - for (const header of object) { + for (let i = 0; i < object.length; ++i) { + const header = object[i] // 1. If header does not contain exactly two items, then throw a TypeError. if (header.length !== 2) { throw webidl.errors.exception({ @@ -73209,15 +73338,16 @@ function fill (headers, object) { } // 2. Append (header’s first item, header’s second item) to headers. - headers.append(header[0], header[1]) + appendHeader(headers, header[0], header[1]) } } else if (typeof object === 'object' && object !== null) { // Note: null should throw // 2. Otherwise, object is a record, then for each key → value in object, // append (key, value) to headers - for (const [key, value] of Object.entries(object)) { - headers.append(key, value) + const keys = Object.keys(object) + for (let i = 0; i < keys.length; ++i) { + appendHeader(headers, keys[i], object[keys[i]]) } } else { throw webidl.errors.conversionFailed({ @@ -73228,6 +73358,50 @@ function fill (headers, object) { } } +/** + * @see https://fetch.spec.whatwg.org/#concept-headers-append + */ +function appendHeader (headers, name, value) { + // 1. Normalize value. + value = headerValueNormalize(value) + + // 2. If name is not a header name or value is not a + // header value, then throw a TypeError. + if (!isValidHeaderName(name)) { + throw webidl.errors.invalidArgument({ + prefix: 'Headers.append', + value: name, + type: 'header name' + }) + } else if (!isValidHeaderValue(value)) { + throw webidl.errors.invalidArgument({ + prefix: 'Headers.append', + value, + type: 'header value' + }) + } + + // 3. If headers’s guard is "immutable", then throw a TypeError. + // 4. Otherwise, if headers’s guard is "request" and name is a + // forbidden header name, return. + // Note: undici does not implement forbidden header names + if (headers[kGuard] === 'immutable') { + throw new TypeError('immutable') + } else if (headers[kGuard] === 'request-no-cors') { + // 5. Otherwise, if headers’s guard is "request-no-cors": + // TODO + } + + // 6. Otherwise, if headers’s guard is "response" and name is a + // forbidden response-header name, return. + + // 7. Append (name, value) to headers’s header list. + return headers[kHeadersList].append(name, value) + + // 8. If headers’s guard is "request-no-cors", then remove + // privileged no-CORS request headers from headers +} + class HeadersList { /** @type {[string, string][]|null} */ cookies = null @@ -73236,7 +73410,7 @@ class HeadersList { if (init instanceof HeadersList) { this[kHeadersMap] = new Map(init[kHeadersMap]) this[kHeadersSortedMap] = init[kHeadersSortedMap] - this.cookies = init.cookies + this.cookies = init.cookies === null ? null : [...init.cookies] } else { this[kHeadersMap] = new Map(init) this[kHeadersSortedMap] = null @@ -73298,7 +73472,7 @@ class HeadersList { // the first such header to value and remove the // others. // 2. Otherwise, append header (name, value) to list. - return this[kHeadersMap].set(lowercaseName, { name, value }) + this[kHeadersMap].set(lowercaseName, { name, value }) } // https://fetch.spec.whatwg.org/#concept-header-list-delete @@ -73311,20 +73485,18 @@ class HeadersList { this.cookies = null } - return this[kHeadersMap].delete(name) + this[kHeadersMap].delete(name) } // https://fetch.spec.whatwg.org/#concept-header-list-get get (name) { - // 1. If list does not contain name, then return null. - if (!this.contains(name)) { - return null - } + const value = this[kHeadersMap].get(name.toLowerCase()) + // 1. If list does not contain name, then return null. // 2. Return the values of all headers in list whose name // is a byte-case-insensitive match for name, // separated from each other by 0x2C 0x20, in order. - return this[kHeadersMap].get(name.toLowerCase())?.value ?? null + return value === undefined ? null : value.value } * [Symbol.iterator] () { @@ -73350,6 +73522,9 @@ class HeadersList { // https://fetch.spec.whatwg.org/#headers-class class Headers { constructor (init = undefined) { + if (init === kConstruct) { + return + } this[kHeadersList] = new HeadersList() // The new Headers(init) constructor steps are: @@ -73373,43 +73548,7 @@ class Headers { name = webidl.converters.ByteString(name) value = webidl.converters.ByteString(value) - // 1. Normalize value. - value = headerValueNormalize(value) - - // 2. If name is not a header name or value is not a - // header value, then throw a TypeError. - if (!isValidHeaderName(name)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.append', - value: name, - type: 'header name' - }) - } else if (!isValidHeaderValue(value)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.append', - value, - type: 'header value' - }) - } - - // 3. If headers’s guard is "immutable", then throw a TypeError. - // 4. Otherwise, if headers’s guard is "request" and name is a - // forbidden header name, return. - // Note: undici does not implement forbidden header names - if (this[kGuard] === 'immutable') { - throw new TypeError('immutable') - } else if (this[kGuard] === 'request-no-cors') { - // 5. Otherwise, if headers’s guard is "request-no-cors": - // TODO - } - - // 6. Otherwise, if headers’s guard is "response" and name is a - // forbidden response-header name, return. - - // 7. Append (name, value) to headers’s header list. - // 8. If headers’s guard is "request-no-cors", then remove - // privileged no-CORS request headers from headers - return this[kHeadersList].append(name, value) + return appendHeader(this, name, value) } // https://fetch.spec.whatwg.org/#dom-headers-delete @@ -73454,7 +73593,7 @@ class Headers { // 7. Delete name from this’s header list. // 8. If this’s guard is "request-no-cors", then remove // privileged no-CORS request headers from this. - return this[kHeadersList].delete(name) + this[kHeadersList].delete(name) } // https://fetch.spec.whatwg.org/#dom-headers-get @@ -73547,7 +73686,7 @@ class Headers { // 7. Set (name, value) in this’s header list. // 8. If this’s guard is "request-no-cors", then remove // privileged no-CORS request headers from this - return this[kHeadersList].set(name, value) + this[kHeadersList].set(name, value) } // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie @@ -73583,7 +73722,8 @@ class Headers { const cookies = this[kHeadersList].cookies // 3. For each name of names: - for (const [name, value] of names) { + for (let i = 0; i < names.length; ++i) { + const [name, value] = names[i] // 1. If name is `set-cookie`, then: if (name === 'set-cookie') { // 1. Let values be a list of all values of headers in list whose name @@ -73591,8 +73731,8 @@ class Headers { // 2. For each value of values: // 1. Append (name, value) to headers. - for (const value of cookies) { - headers.push([name, value]) + for (let j = 0; j < cookies.length; ++j) { + headers.push([name, cookies[j]]) } } else { // 2. Otherwise: @@ -73616,6 +73756,12 @@ class Headers { keys () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'key') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -73626,6 +73772,12 @@ class Headers { values () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'value') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -73636,6 +73788,12 @@ class Headers { entries () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'key+value') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -73767,11 +73925,11 @@ const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(5861) const assert = __nccwpck_require__(9491) const { safelyExtractBody } = __nccwpck_require__(9990) const { - redirectStatus, + redirectStatusSet, nullBodyStatus, - safeMethods, + safeMethodsSet, requestBodyHeader, - subresource, + subresourceSet, DOMException } = __nccwpck_require__(1037) const { kHeadersList } = __nccwpck_require__(2785) @@ -73783,6 +73941,7 @@ const { TransformStream } = __nccwpck_require__(5356) const { getGlobalDispatcher } = __nccwpck_require__(1892) const { webidl } = __nccwpck_require__(1744) const { STATUS_CODES } = __nccwpck_require__(3685) +const GET_OR_HEAD = ['GET', 'HEAD'] /** @type {import('buffer').resolveObjectURL} */ let resolveObjectURL @@ -74006,7 +74165,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') { } // 8. If response’s timing allow passed flag is not set, then: - if (!timingInfo.timingAllowPassed) { + if (!response.timingAllowPassed) { // 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo. timingInfo = createOpaqueTimingInfo({ startTime: timingInfo.startTime @@ -74230,7 +74389,7 @@ function fetching ({ } // 15. If request is a subresource request, then: - if (subresource.includes(request.destination)) { + if (subresourceSet.has(request.destination)) { // TODO } @@ -74784,7 +74943,7 @@ async function httpFetch (fetchParams) { } // 8. If actualResponse’s status is a redirect status, then: - if (redirectStatus.includes(actualResponse.status)) { + if (redirectStatusSet.has(actualResponse.status)) { // 1. If actualResponse’s status is not 303, request’s body is not null, // and the connection uses HTTP/2, then user agents may, and are even // encouraged to, transmit an RST_STREAM frame. @@ -74902,7 +75061,7 @@ function httpRedirectFetch (fetchParams, response) { if ( ([301, 302].includes(actualResponse.status) && request.method === 'POST') || (actualResponse.status === 303 && - !['GET', 'HEAD'].includes(request.method)) + !GET_OR_HEAD.includes(request.method)) ) { // then: // 1. Set request’s method to `GET` and request’s body to null. @@ -74923,6 +75082,9 @@ function httpRedirectFetch (fetchParams, response) { // https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name request.headersList.delete('authorization') + // https://fetch.spec.whatwg.org/#authentication-entries + request.headersList.delete('proxy-authorization', true) + // "Cookie" and "Host" are forbidden request-headers, which undici doesn't implement. request.headersList.delete('cookie') request.headersList.delete('host') @@ -75186,7 +75348,7 @@ async function httpNetworkOrCacheFetch ( // responses in httpCache, as per the "Invalidation" chapter of HTTP // Caching, and set storedResponse to null. [HTTP-CACHING] if ( - !safeMethods.includes(httpRequest.method) && + !safeMethodsSet.has(httpRequest.method) && forwardResponse.status >= 200 && forwardResponse.status <= 399 ) { @@ -75677,7 +75839,7 @@ async function httpNetworkFetch ( path: url.pathname + url.search, origin: url.origin, method: request.method, - body: fetchParams.controller.dispatcher.isMockActive ? request.body && request.body.source : body, + body: fetchParams.controller.dispatcher.isMockActive ? request.body && (request.body.source || request.body.stream) : body, headers: request.headersList.entries, maxRedirections: 0, upgrade: request.mode === 'websocket' ? 'websocket' : undefined @@ -75722,7 +75884,7 @@ async function httpNetworkFetch ( location = val } - headers.append(key, val) + headers[kHeadersList].append(key, val) } } else { const keys = Object.keys(headersList) @@ -75736,7 +75898,7 @@ async function httpNetworkFetch ( location = val } - headers.append(key, val) + headers[kHeadersList].append(key, val) } } @@ -75746,7 +75908,7 @@ async function httpNetworkFetch ( const willFollow = request.redirect === 'follow' && location && - redirectStatus.includes(status) + redirectStatusSet.has(status) // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) { @@ -75840,7 +76002,7 @@ async function httpNetworkFetch ( const key = headersList[n + 0].toString('latin1') const val = headersList[n + 1].toString('latin1') - headers.append(key, val) + headers[kHeadersList].append(key, val) } resolve({ @@ -75883,11 +76045,12 @@ const { isValidHTTPToken, sameOrigin, normalizeMethod, - makePolicyContainer + makePolicyContainer, + normalizeMethodRecord } = __nccwpck_require__(2538) const { - forbiddenMethods, - corsSafeListedMethods, + forbiddenMethodsSet, + corsSafeListedMethodsSet, referrerPolicy, requestRedirect, requestMode, @@ -75900,13 +76063,12 @@ const { kHeaders, kSignal, kState, kGuard, kRealm } = __nccwpck_require__(5861) const { webidl } = __nccwpck_require__(1744) const { getGlobalOrigin } = __nccwpck_require__(1246) const { URLSerializer } = __nccwpck_require__(685) -const { kHeadersList } = __nccwpck_require__(2785) +const { kHeadersList, kConstruct } = __nccwpck_require__(2785) const assert = __nccwpck_require__(9491) const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = __nccwpck_require__(2361) let TransformStream = globalThis.TransformStream -const kInit = Symbol('init') const kAbortController = Symbol('abortController') const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => { @@ -75917,7 +76079,7 @@ const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => { class Request { // https://fetch.spec.whatwg.org/#dom-request constructor (input, init = {}) { - if (input === kInit) { + if (input === kConstruct) { return } @@ -76056,8 +76218,10 @@ class Request { urlList: [...request.urlList] }) + const initHasKey = Object.keys(init).length !== 0 + // 13. If init is not empty, then: - if (Object.keys(init).length > 0) { + if (initHasKey) { // 1. If request’s mode is "navigate", then set it to "same-origin". if (request.mode === 'navigate') { request.mode = 'same-origin' @@ -76172,7 +76336,7 @@ class Request { } // 23. If init["integrity"] exists, then set request’s integrity metadata to it. - if (init.integrity !== undefined && init.integrity != null) { + if (init.integrity != null) { request.integrity = String(init.integrity) } @@ -76188,16 +76352,16 @@ class Request { // 2. If method is not a method or method is a forbidden method, then // throw a TypeError. - if (!isValidHTTPToken(init.method)) { - throw TypeError(`'${init.method}' is not a valid HTTP method.`) + if (!isValidHTTPToken(method)) { + throw new TypeError(`'${method}' is not a valid HTTP method.`) } - if (forbiddenMethods.indexOf(method.toUpperCase()) !== -1) { - throw TypeError(`'${init.method}' HTTP method is unsupported.`) + if (forbiddenMethodsSet.has(method.toUpperCase())) { + throw new TypeError(`'${method}' HTTP method is unsupported.`) } // 3. Normalize method. - method = normalizeMethod(init.method) + method = normalizeMethodRecord[method] ?? normalizeMethod(method) // 4. Set request’s method to method. request.method = method @@ -76268,7 +76432,7 @@ class Request { // 30. Set this’s headers to a new Headers object with this’s relevant // Realm, whose header list is request’s header list and guard is // "request". - this[kHeaders] = new Headers() + this[kHeaders] = new Headers(kConstruct) this[kHeaders][kHeadersList] = request.headersList this[kHeaders][kGuard] = 'request' this[kHeaders][kRealm] = this[kRealm] @@ -76277,7 +76441,7 @@ class Request { if (mode === 'no-cors') { // 1. If this’s request’s method is not a CORS-safelisted method, // then throw a TypeError. - if (!corsSafeListedMethods.includes(request.method)) { + if (!corsSafeListedMethodsSet.has(request.method)) { throw new TypeError( `'${request.method} is unsupported in no-cors mode.` ) @@ -76288,25 +76452,25 @@ class Request { } // 32. If init is not empty, then: - if (Object.keys(init).length !== 0) { + if (initHasKey) { + /** @type {HeadersList} */ + const headersList = this[kHeaders][kHeadersList] // 1. Let headers be a copy of this’s headers and its associated header // list. - let headers = new Headers(this[kHeaders]) - // 2. If init["headers"] exists, then set headers to init["headers"]. - if (init.headers !== undefined) { - headers = init.headers - } + const headers = init.headers !== undefined ? init.headers : new HeadersList(headersList) // 3. Empty this’s headers’s header list. - this[kHeaders][kHeadersList].clear() + headersList.clear() // 4. If headers is a Headers object, then for each header in its header // list, append header’s name/header’s value to this’s headers. - if (headers.constructor.name === 'Headers') { + if (headers instanceof HeadersList) { for (const [key, val] of headers) { - this[kHeaders].append(key, val) + headersList.append(key, val) } + // Note: Copy the `set-cookie` meta-data. + headersList.cookies = headers.cookies } else { // 5. Otherwise, fill this’s headers with headers. fillHeaders(this[kHeaders], headers) @@ -76595,10 +76759,10 @@ class Request { // 3. Let clonedRequestObject be the result of creating a Request object, // given clonedRequest, this’s headers’s guard, and this’s relevant Realm. - const clonedRequestObject = new Request(kInit) + const clonedRequestObject = new Request(kConstruct) clonedRequestObject[kState] = clonedRequest clonedRequestObject[kRealm] = this[kRealm] - clonedRequestObject[kHeaders] = new Headers() + clonedRequestObject[kHeaders] = new Headers(kConstruct) clonedRequestObject[kHeaders][kHeadersList] = clonedRequest.headersList clonedRequestObject[kHeaders][kGuard] = this[kHeaders][kGuard] clonedRequestObject[kHeaders][kRealm] = this[kHeaders][kRealm] @@ -76839,7 +77003,7 @@ const { isomorphicEncode } = __nccwpck_require__(2538) const { - redirectStatus, + redirectStatusSet, nullBodyStatus, DOMException } = __nccwpck_require__(1037) @@ -76848,11 +77012,12 @@ const { webidl } = __nccwpck_require__(1744) const { FormData } = __nccwpck_require__(2015) const { getGlobalOrigin } = __nccwpck_require__(1246) const { URLSerializer } = __nccwpck_require__(685) -const { kHeadersList } = __nccwpck_require__(2785) +const { kHeadersList, kConstruct } = __nccwpck_require__(2785) const assert = __nccwpck_require__(9491) const { types } = __nccwpck_require__(3837) const ReadableStream = globalThis.ReadableStream || (__nccwpck_require__(5356).ReadableStream) +const textEncoder = new TextEncoder('utf-8') // https://fetch.spec.whatwg.org/#response-class class Response { @@ -76882,7 +77047,7 @@ class Response { } // 1. Let bytes the result of running serialize a JavaScript value to JSON bytes on data. - const bytes = new TextEncoder('utf-8').encode( + const bytes = textEncoder.encode( serializeJavascriptValueToJSONString(data) ) @@ -76927,7 +77092,7 @@ class Response { } // 3. If status is not a redirect status, then throw a RangeError. - if (!redirectStatus.includes(status)) { + if (!redirectStatusSet.has(status)) { throw new RangeError('Invalid status code ' + status) } @@ -76968,7 +77133,7 @@ class Response { // 2. Set this’s headers to a new Headers object with this’s relevant // Realm, whose header list is this’s response’s header list and guard // is "response". - this[kHeaders] = new Headers() + this[kHeaders] = new Headers(kConstruct) this[kHeaders][kGuard] = 'response' this[kHeaders][kHeadersList] = this[kState].headersList this[kHeaders][kRealm] = this[kRealm] @@ -77338,11 +77503,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { return webidl.converters.Blob(V, { strict: false }) } - if ( - types.isAnyArrayBuffer(V) || - types.isTypedArray(V) || - types.isDataView(V) - ) { + if (types.isArrayBuffer(V) || types.isTypedArray(V) || types.isDataView(V)) { return webidl.converters.BufferSource(V) } @@ -77425,7 +77586,7 @@ module.exports = { "use strict"; -const { redirectStatus, badPorts, referrerPolicy: referrerPolicyTokens } = __nccwpck_require__(1037) +const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = __nccwpck_require__(1037) const { getGlobalOrigin } = __nccwpck_require__(1246) const { performance } = __nccwpck_require__(4074) const { isBlobLike, toUSVString, ReadableStreamFrom } = __nccwpck_require__(3983) @@ -77454,7 +77615,7 @@ function responseURL (response) { // https://fetch.spec.whatwg.org/#concept-response-location-url function responseLocationURL (response, requestFragment) { // 1. If response’s status is not a redirect status, then return null. - if (!redirectStatus.includes(response.status)) { + if (!redirectStatusSet.has(response.status)) { return null } @@ -77489,7 +77650,7 @@ function requestBadPort (request) { // 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port, // then return blocked. - if (urlIsHttpHttpsScheme(url) && badPorts.includes(url.port)) { + if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) { return 'blocked' } @@ -77528,52 +77689,57 @@ function isValidReasonPhrase (statusText) { return true } -function isTokenChar (c) { - return !( - c >= 0x7f || - c <= 0x20 || - c === '(' || - c === ')' || - c === '<' || - c === '>' || - c === '@' || - c === ',' || - c === ';' || - c === ':' || - c === '\\' || - c === '"' || - c === '/' || - c === '[' || - c === ']' || - c === '?' || - c === '=' || - c === '{' || - c === '}' - ) +/** + * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 + * @param {number} c + */ +function isTokenCharCode (c) { + switch (c) { + case 0x22: + case 0x28: + case 0x29: + case 0x2c: + case 0x2f: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x40: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x7b: + case 0x7d: + // DQUOTE and "(),/:;<=>?@[\]{}" + return false + default: + // VCHAR %x21-7E + return c >= 0x21 && c <= 0x7e + } } -// See RFC 7230, Section 3.2.6. -// https://github.com/chromium/chromium/blob/d7da0240cae77824d1eda25745c4022757499131/third_party/blink/renderer/platform/network/http_parsers.cc#L321 +/** + * @param {string} characters + */ function isValidHTTPToken (characters) { - if (!characters || typeof characters !== 'string') { + if (characters.length === 0) { return false } for (let i = 0; i < characters.length; ++i) { - const c = characters.charCodeAt(i) - if (c > 0x7f || !isTokenChar(c)) { + if (!isTokenCharCode(characters.charCodeAt(i))) { return false } } return true } -// https://fetch.spec.whatwg.org/#header-name -// https://github.com/chromium/chromium/blob/b3d37e6f94f87d59e44662d6078f6a12de845d17/net/http/http_util.cc#L342 +/** + * @see https://fetch.spec.whatwg.org/#header-name + * @param {string} potentialValue + */ function isValidHeaderName (potentialValue) { - if (potentialValue.length === 0) { - return false - } - return isValidHTTPToken(potentialValue) } @@ -77631,7 +77797,7 @@ function setRequestReferrerPolicyOnRedirect (request, actualResponse) { // The left-most policy is the fallback. for (let i = policyHeader.length; i !== 0; i--) { const token = policyHeader[i - 1].trim() - if (referrerPolicyTokens.includes(token)) { + if (referrerPolicyTokens.has(token)) { policy = token break } @@ -78118,11 +78284,30 @@ function isCancelled (fetchParams) { fetchParams.controller.state === 'terminated' } -// https://fetch.spec.whatwg.org/#concept-method-normalize +const normalizeMethodRecord = { + delete: 'DELETE', + DELETE: 'DELETE', + get: 'GET', + GET: 'GET', + head: 'HEAD', + HEAD: 'HEAD', + options: 'OPTIONS', + OPTIONS: 'OPTIONS', + post: 'POST', + POST: 'POST', + put: 'PUT', + PUT: 'PUT' +} + +// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`. +Object.setPrototypeOf(normalizeMethodRecord, null) + +/** + * @see https://fetch.spec.whatwg.org/#concept-method-normalize + * @param {string} method + */ function normalizeMethod (method) { - return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method) - ? method.toUpperCase() - : method + return normalizeMethodRecord[method.toLowerCase()] ?? method } // https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string @@ -78467,7 +78652,8 @@ module.exports = { urlIsLocal, urlHasHttpsScheme, urlIsHttpHttpsScheme, - readAllBytes + readAllBytes, + normalizeMethodRecord } @@ -78906,12 +79092,10 @@ webidl.converters.ByteString = function (V) { // 2. If the value of any element of x is greater than // 255, then throw a TypeError. for (let index = 0; index < x.length; index++) { - const charCode = x.charCodeAt(index) - - if (charCode > 255) { + if (x.charCodeAt(index) > 255) { throw new TypeError( 'Cannot convert argument to a ByteString because the character at ' + - `index ${index} has a value of ${charCode} which is greater than 255.` + `index ${index} has a value of ${x.charCodeAt(index)} which is greater than 255.` ) } } @@ -80588,6 +80772,349 @@ function cleanRequestHeaders (headers, removeContent, unknownOrigin) { module.exports = RedirectHandler +/***/ }), + +/***/ 2286: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const assert = __nccwpck_require__(9491) + +const { kRetryHandlerDefaultRetry } = __nccwpck_require__(2785) +const { RequestRetryError } = __nccwpck_require__(8045) +const { isDisturbed, parseHeaders, parseRangeHeader } = __nccwpck_require__(3983) + +function calculateRetryAfterHeader (retryAfter) { + const current = Date.now() + const diff = new Date(retryAfter).getTime() - current + + return diff +} + +class RetryHandler { + constructor (opts, handlers) { + const { retryOptions, ...dispatchOpts } = opts + const { + // Retry scoped + retry: retryFn, + maxRetries, + maxTimeout, + minTimeout, + timeoutFactor, + // Response scoped + methods, + errorCodes, + retryAfter, + statusCodes + } = retryOptions ?? {} + + this.dispatch = handlers.dispatch + this.handler = handlers.handler + this.opts = dispatchOpts + this.abort = null + this.aborted = false + this.retryOpts = { + retry: retryFn ?? RetryHandler[kRetryHandlerDefaultRetry], + retryAfter: retryAfter ?? true, + maxTimeout: maxTimeout ?? 30 * 1000, // 30s, + timeout: minTimeout ?? 500, // .5s + timeoutFactor: timeoutFactor ?? 2, + maxRetries: maxRetries ?? 5, + // What errors we should retry + methods: methods ?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'], + // Indicates which errors to retry + statusCodes: statusCodes ?? [500, 502, 503, 504, 429], + // List of errors to retry + errorCodes: errorCodes ?? [ + 'ECONNRESET', + 'ECONNREFUSED', + 'ENOTFOUND', + 'ENETDOWN', + 'ENETUNREACH', + 'EHOSTDOWN', + 'EHOSTUNREACH', + 'EPIPE' + ] + } + + this.retryCount = 0 + this.start = 0 + this.end = null + this.etag = null + this.resume = null + + // Handle possible onConnect duplication + this.handler.onConnect(reason => { + this.aborted = true + if (this.abort) { + this.abort(reason) + } else { + this.reason = reason + } + }) + } + + onRequestSent () { + if (this.handler.onRequestSent) { + this.handler.onRequestSent() + } + } + + onUpgrade (statusCode, headers, socket) { + if (this.handler.onUpgrade) { + this.handler.onUpgrade(statusCode, headers, socket) + } + } + + onConnect (abort) { + if (this.aborted) { + abort(this.reason) + } else { + this.abort = abort + } + } + + onBodySent (chunk) { + if (this.handler.onBodySent) return this.handler.onBodySent(chunk) + } + + static [kRetryHandlerDefaultRetry] (err, { state, opts }, cb) { + const { statusCode, code, headers } = err + const { method, retryOptions } = opts + const { + maxRetries, + timeout, + maxTimeout, + timeoutFactor, + statusCodes, + errorCodes, + methods + } = retryOptions + let { counter, currentTimeout } = state + + currentTimeout = + currentTimeout != null && currentTimeout > 0 ? currentTimeout : timeout + + // Any code that is not a Undici's originated and allowed to retry + if ( + code && + code !== 'UND_ERR_REQ_RETRY' && + code !== 'UND_ERR_SOCKET' && + !errorCodes.includes(code) + ) { + cb(err) + return + } + + // If a set of method are provided and the current method is not in the list + if (Array.isArray(methods) && !methods.includes(method)) { + cb(err) + return + } + + // If a set of status code are provided and the current status code is not in the list + if ( + statusCode != null && + Array.isArray(statusCodes) && + !statusCodes.includes(statusCode) + ) { + cb(err) + return + } + + // If we reached the max number of retries + if (counter > maxRetries) { + cb(err) + return + } + + let retryAfterHeader = headers != null && headers['retry-after'] + if (retryAfterHeader) { + retryAfterHeader = Number(retryAfterHeader) + retryAfterHeader = isNaN(retryAfterHeader) + ? calculateRetryAfterHeader(retryAfterHeader) + : retryAfterHeader * 1e3 // Retry-After is in seconds + } + + const retryTimeout = + retryAfterHeader > 0 + ? Math.min(retryAfterHeader, maxTimeout) + : Math.min(currentTimeout * timeoutFactor ** counter, maxTimeout) + + state.currentTimeout = retryTimeout + + setTimeout(() => cb(null), retryTimeout) + } + + onHeaders (statusCode, rawHeaders, resume, statusMessage) { + const headers = parseHeaders(rawHeaders) + + this.retryCount += 1 + + if (statusCode >= 300) { + this.abort( + new RequestRetryError('Request failed', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + // Checkpoint for resume from where we left it + if (this.resume != null) { + this.resume = null + + if (statusCode !== 206) { + return true + } + + const contentRange = parseRangeHeader(headers['content-range']) + // If no content range + if (!contentRange) { + this.abort( + new RequestRetryError('Content-Range mismatch', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + // Let's start with a weak etag check + if (this.etag != null && this.etag !== headers.etag) { + this.abort( + new RequestRetryError('ETag mismatch', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + const { start, size, end = size } = contentRange + + assert(this.start === start, 'content-range mismatch') + assert(this.end == null || this.end === end, 'content-range mismatch') + + this.resume = resume + return true + } + + if (this.end == null) { + if (statusCode === 206) { + // First time we receive 206 + const range = parseRangeHeader(headers['content-range']) + + if (range == null) { + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } + + const { start, size, end = size } = range + + assert( + start != null && Number.isFinite(start) && this.start !== start, + 'content-range mismatch' + ) + assert(Number.isFinite(start)) + assert( + end != null && Number.isFinite(end) && this.end !== end, + 'invalid content-length' + ) + + this.start = start + this.end = end + } + + // We make our best to checkpoint the body for further range headers + if (this.end == null) { + const contentLength = headers['content-length'] + this.end = contentLength != null ? Number(contentLength) : null + } + + assert(Number.isFinite(this.start)) + assert( + this.end == null || Number.isFinite(this.end), + 'invalid content-length' + ) + + this.resume = resume + this.etag = headers.etag != null ? headers.etag : null + + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } + + const err = new RequestRetryError('Request failed', statusCode, { + headers, + count: this.retryCount + }) + + this.abort(err) + + return false + } + + onData (chunk) { + this.start += chunk.length + + return this.handler.onData(chunk) + } + + onComplete (rawTrailers) { + this.retryCount = 0 + return this.handler.onComplete(rawTrailers) + } + + onError (err) { + if (this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) + } + + this.retryOpts.retry( + err, + { + state: { counter: this.retryCount++, currentTimeout: this.retryAfter }, + opts: { retryOptions: this.retryOpts, ...this.opts } + }, + onRetry.bind(this) + ) + + function onRetry (err) { + if (err != null || this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) + } + + if (this.start !== 0) { + this.opts = { + ...this.opts, + headers: { + ...this.opts.headers, + range: `bytes=${this.start}-${this.end ?? ''}` + } + } + } + + try { + this.dispatch(this.opts, this) + } catch (err) { + this.handler.onError(err) + } + } + } +} + +module.exports = RetryHandler + + /***/ }), /***/ 8861: @@ -82400,7 +82927,7 @@ class Pool extends PoolBase { maxCachedSessions, allowH2, socketPath, - timeout: connectTimeout == null ? 10e3 : connectTimeout, + timeout: connectTimeout, ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), ...connect }) @@ -82510,6 +83037,9 @@ class ProxyAgent extends DispatcherBase { this[kProxyTls] = opts.proxyTls this[kProxyHeaders] = opts.headers || {} + const resolvedUrl = new URL(opts.uri) + const { origin, port, host, username, password } = resolvedUrl + if (opts.auth && opts.token) { throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token') } else if (opts.auth) { @@ -82517,11 +83047,10 @@ class ProxyAgent extends DispatcherBase { this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}` } else if (opts.token) { this[kProxyHeaders]['proxy-authorization'] = opts.token + } else if (username && password) { + this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString('base64')}` } - const resolvedUrl = new URL(opts.uri) - const { origin, port, host } = resolvedUrl - const connect = buildConnector({ ...opts.proxyTls }) this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }) this[kClient] = clientFactory(resolvedUrl, { connect }) @@ -82545,7 +83074,7 @@ class ProxyAgent extends DispatcherBase { }) if (statusCode !== 200) { socket.on('error', () => {}).destroy() - callback(new RequestAbortedError('Proxy response !== 200 when HTTP Tunneling')) + callback(new RequestAbortedError(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`)) } if (opts.protocol !== 'https:') { callback(null, socket) @@ -93151,8 +93680,8 @@ class BaseDistribution { const valid = (_a = semver_1.default.valid(c)) !== null && _a !== void 0 ? _a : versionSpec; return { range: valid, options }; } - acquireWindowsNodeFromFallbackLocation(version, arch = os_1.default.arch()) { - return __awaiter(this, void 0, void 0, function* () { + acquireWindowsNodeFromFallbackLocation(version_1) { + return __awaiter(this, arguments, void 0, function* (version, arch = os_1.default.arch()) { const initialUrl = this.getDistributionUrl(); const osArch = this.translateArchToDistUrl(arch); // Create temporary folder to download to @@ -93400,8 +93929,8 @@ class OfficialBuilds extends base_distribution_1.default { super(nodeInfo); } setupNodeJs() { - var _a; return __awaiter(this, void 0, void 0, function* () { + var _a; let manifest; let nodeJsVersions; const osArch = this.translateArchToDistUrl(this.nodeInfo.arch); diff --git a/package-lock.json b/package-lock.json index 391585a..bb65ad9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,34 +9,34 @@ "version": "4.0.0", "license": "MIT", "dependencies": { - "@actions/cache": "^3.0.4", + "@actions/cache": "^3.2.4", "@actions/core": "^1.10.0", "@actions/exec": "^1.1.0", "@actions/github": "^5.1.1", "@actions/glob": "^0.4.0", - "@actions/http-client": "^2.1.1", + "@actions/http-client": "^2.2.1", "@actions/io": "^1.0.2", "@actions/tool-cache": "^2.0.1", - "semver": "^7.5.4", + "semver": "^7.6.0", "uuid": "^9.0.1" }, "devDependencies": { - "@types/jest": "^29.5.5", - "@types/node": "^20.8.2", - "@types/semver": "^7.5.3", + "@types/jest": "^29.5.12", + "@types/node": "^20.11.25", + "@types/semver": "^7.5.8", "@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/parser": "^5.54.0", "@vercel/ncc": "^0.38.0", - "eslint": "^8.35.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^8.6.0", - "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jest": "^27.9.0", "eslint-plugin-node": "^11.1.0", "jest": "^29.7.0", "jest-circus": "^29.7.0", "jest-each": "^29.7.0", "prettier": "^2.8.4", - "ts-jest": "^29.1.1", - "typescript": "^5.2.2" + "ts-jest": "^29.1.2", + "typescript": "^5.4.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -49,9 +49,9 @@ } }, "node_modules/@actions/cache": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.2.2.tgz", - "integrity": "sha512-6D0Jq5JrLZRQ3VApeQwQkkV20ZZXjXsHNYXd9VjNUdi9E0h93wESpxfMJ2JWLCUCgHNLcfY0v3GjNM+2FdRMlg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.2.4.tgz", + "integrity": "sha512-RuHnwfcDagtX+37s0ZWy7clbOfnZ7AlDJQ7k/9rzt2W4Gnwde3fa/qjSjVuz4vLcLIpc7fUob27CMrqiWZytYA==", "dependencies": { "@actions/core": "^1.10.0", "@actions/exec": "^1.0.1", @@ -61,7 +61,7 @@ "@azure/abort-controller": "^1.1.0", "@azure/ms-rest-js": "^2.6.0", "@azure/storage-blob": "^12.13.0", - "semver": "^6.1.0", + "semver": "^6.3.1", "uuid": "^3.3.3" } }, @@ -137,9 +137,9 @@ } }, "node_modules/@actions/http-client": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz", - "integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.1.tgz", + "integrity": "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==", "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" @@ -1042,9 +1042,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1065,9 +1065,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1082,13 +1082,13 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -1109,9 +1109,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -1791,9 +1791,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.6", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.6.tgz", - "integrity": "sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==", + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1807,11 +1807,11 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", - "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "dependencies": { - "undici-types": "~5.25.1" + "undici-types": "~5.26.4" } }, "node_modules/@types/node-fetch": { @@ -1837,9 +1837,9 @@ } }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/stack-utils": { @@ -2086,9 +2086,9 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2757,16 +2757,16 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -2843,9 +2843,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.4.3.tgz", - "integrity": "sha512-7S6SmmsHsgIm06BAGCAxL+ABd9/IB3MWkz2pudj6Qqor2y1qQpWPfuFU4SG9pWj4xDjF0e+D7Llh5useuSzAZw==", + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -2854,7 +2854,7 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0", + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", "eslint": "^7.0.0 || ^8.0.0", "jest": "*" }, @@ -3362,9 +3362,9 @@ } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4864,9 +4864,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -5045,9 +5045,9 @@ "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5308,9 +5308,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", + "integrity": "sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -5326,7 +5326,7 @@ "ts-jest": "cli.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^16.10.0 || ^18.0.0 || >=20.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", @@ -5418,9 +5418,9 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5431,9 +5431,9 @@ } }, "node_modules/undici": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", - "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -5442,9 +5442,9 @@ } }, "node_modules/undici-types": { - "version": "5.25.3", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", - "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==" + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/universal-user-agent": { "version": "6.0.0", diff --git a/package.json b/package.json index af75008..cbfb2ef 100644 --- a/package.json +++ b/package.json @@ -25,33 +25,33 @@ "author": "GitHub", "license": "MIT", "dependencies": { - "@actions/cache": "^3.0.4", + "@actions/cache": "^3.2.4", "@actions/core": "^1.10.0", "@actions/exec": "^1.1.0", "@actions/github": "^5.1.1", "@actions/glob": "^0.4.0", - "@actions/http-client": "^2.1.1", + "@actions/http-client": "^2.2.1", "@actions/io": "^1.0.2", "@actions/tool-cache": "^2.0.1", - "semver": "^7.5.4", + "semver": "^7.6.0", "uuid": "^9.0.1" }, "devDependencies": { - "@types/jest": "^29.5.5", - "@types/node": "^20.8.2", - "@types/semver": "^7.5.3", + "@types/jest": "^29.5.12", + "@types/node": "^20.11.25", + "@types/semver": "^7.5.8", "@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/parser": "^5.54.0", "@vercel/ncc": "^0.38.0", - "eslint": "^8.35.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^8.6.0", - "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jest": "^27.9.0", "eslint-plugin-node": "^11.1.0", "jest": "^29.7.0", "jest-circus": "^29.7.0", "jest-each": "^29.7.0", "prettier": "^2.8.4", - "ts-jest": "^29.1.1", - "typescript": "^5.2.2" + "ts-jest": "^29.1.2", + "typescript": "^5.4.2" } }