From 8d6402c9b71205b2d8d0b82de531d8fed8430182 Mon Sep 17 00:00:00 2001 From: Kevin Stillhammer Date: Tue, 11 Aug 2026 15:08:35 +0200 Subject: [PATCH] chore(deps): roll up Dependabot updates (#1004) ## Summary Roll up the remaining dependency changes from Dependabot PRs #997, #998, #999, #1000, #1001, #1002, and #1003: - update `github/codeql-action` to 4.37.6 - update `zizmorcore/zizmor-action` to 0.6.2 - update `undici` to 8.10.0 - update `smol-toml` to 1.7.1 - update `@biomejs/biome` and its schema to 2.5.6 - regenerate the published bundles PRs #905 and #907 were excluded because their requested Jest and pep440 versions are already present on `main`. ## Validation - `npm run all` - `actionlint .github/workflows/codeql-analysis.yml .github/workflows/test.yml` - `uvx zizmor .github/workflows/codeql-analysis.yml .github/workflows/test.yml` - `git diff --check` Refs: pi-session 019ff0c9-8e00-72d3-99ad-d4383a4c57d4 --- .github/workflows/codeql-analysis.yml | 6 +- .github/workflows/test.yml | 2 +- biome.json | 2 +- dist/save-cache/index.cjs | 2 + dist/setup/index.cjs | 1634 ++++++++++++++++++++----- dist/update-known-checksums/index.cjs | 1632 +++++++++++++++++++----- package-lock.json | 170 +-- package.json | 6 +- 8 files changed, 2709 insertions(+), 745 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0f94267..be8443e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: languages: ${{ matrix.language }} source-root: src @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/autobuild@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fd02974..f1b1628 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - name: Actionlint uses: eifinger/actionlint-action@1fc89649be682d16ec5cf65ea16e269eb88d3982 # v1.10.2 - name: Run zizmor - uses: zizmorcore/zizmor-action@6fc4b006235f201fdab3722e17240ab420d580e5 # v0.6.1 + uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2 - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: .nvmrc diff --git a/biome.json b/biome.json index f5dd9b6..6cbe33c 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.5.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.5.6/schema.json", "assist": { "actions": { "source": { diff --git a/dist/save-cache/index.cjs b/dist/save-cache/index.cjs index 65cdbfe..a1dbbda 100644 --- a/dist/save-cache/index.cjs +++ b/dist/save-cache/index.cjs @@ -62228,6 +62228,8 @@ function skipUntil(str, ptr, sep7, end, banNewLines = false) { let c = str[i]; if (c === "#") { i = indexOfNewline(str, i); + if (i < 0) + break; } else if (c === sep7) { return i + 1; } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) { diff --git a/dist/setup/index.cjs b/dist/setup/index.cjs index 056aad4..f8d33d2 100644 --- a/dist/setup/index.cjs +++ b/dist/setup/index.cjs @@ -28981,6 +28981,7 @@ var require_symbols6 = __commonJS({ kCounter: /* @__PURE__ */ Symbol("socket request counter"), kMaxResponseSize: /* @__PURE__ */ Symbol("max response size"), kHTTP2Session: /* @__PURE__ */ Symbol("http2Session"), + kHTTP2Options: /* @__PURE__ */ Symbol("http2 options"), kHTTP2SessionState: /* @__PURE__ */ Symbol("http2Session state"), kRetryHandlerDefaultRetry: /* @__PURE__ */ Symbol("retry agent default retry"), kConstruct: /* @__PURE__ */ Symbol("constructable"), @@ -30107,7 +30108,10 @@ var require_util9 = __commonJS({ if (Object.getPrototypeOf(stream5).constructor === IncomingMessage) { stream5.socket = null; } - stream5.destroy(err); + try { + stream5.destroy(err); + } catch { + } } else if (err) { queueMicrotask(() => { stream5.emit("error", err); @@ -31168,7 +31172,7 @@ var require_request3 = __commonJS({ this.headersTimeout = headersTimeout; this.bodyTimeout = bodyTimeout; this.method = method; - this.typeOfService = typeOfService ?? 0; + this.typeOfService = typeOfService; this.abort = null; if (body2 == null) { this.body = null; @@ -31402,7 +31406,11 @@ var require_request3 = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - arr.push(`${val[i]}`); + const str = `${val[i]}`; + if (!isValidHeaderValue(str)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } + arr.push(str); } } val = arr; @@ -31414,6 +31422,9 @@ var require_request3 = __commonJS({ val = ""; } else { val = `${val}`; + if (!isValidHeaderValue(val)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } } if (headerName === "host") { if (request.host !== null) { @@ -31739,14 +31750,26 @@ var require_connect2 = __commonJS({ } else { assert4(!httpSocket, "httpSocket can only be sent on TLS update"); port = port || 80; - socket = net.connect({ + const connectOptions = { highWaterMark: 64 * 1024, // Same as nodejs fs streams. ...options, localAddress, port, host: hostname - }); + }; + const family = net.isIP(hostname); + if (family !== 0 && servername && servername !== hostname) { + connectOptions.host = servername; + connectOptions.lookup = (_hostname, lookupOptions, cb) => { + if (lookupOptions.all) { + cb(null, [{ address: hostname, family }]); + } else { + cb(null, hostname, family); + } + }; + } + socket = net.connect(connectOptions); if (useH2c === true) { socket.alpnProtocol = "h2"; } @@ -35103,6 +35126,7 @@ var require_body2 = __commonJS({ var { multipartFormDataParser } = require_formdata_parser2(); var { parseJSONFromBytes } = require_infra(); var { utf8DecodeBytes } = require_encoding2(); + var { ReadableStreamTee } = require("node:stream/web"); var textEncoder = new TextEncoder(); function noop() { } @@ -35245,7 +35269,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r return extractBody(object, keepalive); } function cloneBody(body2) { - const { 0: out1, 1: out2 } = body2.stream.tee(); + const { 0: out1, 1: out2 } = ReadableStreamTee?.(body2.stream, true) ?? body2.stream.tee(); body2.stream = out1; return { stream: out2, @@ -35398,6 +35422,7 @@ var require_client_h12 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, + InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -35447,6 +35472,7 @@ var require_client_h12 = __commonJS({ var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); + var kTypeOfService = /* @__PURE__ */ Symbol("kTypeOfService"); var extractBody; function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm2() : void 0; @@ -36250,6 +36276,24 @@ var require_client_h12 = __commonJS({ function shouldSendContentLength(method) { return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; } + function setTypeOfService(socket, request) { + if (typeof socket.setTypeOfService !== "function") { + return; + } + const typeOfService = request.typeOfService; + if (typeOfService === void 0) { + return; + } + const currentTypeOfService = socket[kTypeOfService]; + if (currentTypeOfService === typeOfService) { + return; + } + try { + socket.setTypeOfService(typeOfService); + socket[kTypeOfService] = typeOfService; + } catch { + } + } function writeH1(client, request) { const { method, path: path17, host, upgrade, blocking, reset } = request; let { body: body2, headers, contentLength: contentLength2 } = request; @@ -36264,8 +36308,16 @@ var require_client_h12 = __commonJS({ } body2 = bodyStream.stream; contentLength2 = bodyStream.length; - } else if (util7.isBlobLike(body2) && request.contentType == null && body2.type) { - headers.push("content-type", body2.type); + } else if (util7.isBlobLike(body2) && request.contentType == null) { + const contentType2 = body2.type; + if (contentType2) { + const contentTypeValue = `${contentType2}`; + if (!util7.isValidHeaderValue(contentTypeValue)) { + util7.errorRequest(client, request, new InvalidArgumentError("invalid content-type header")); + return false; + } + headers.push("content-type", contentTypeValue); + } } if (body2 && typeof body2.read === "function") { body2.read(0); @@ -36318,9 +36370,7 @@ var require_client_h12 = __commonJS({ if (blocking) { socket[kBlocking] = true; } - if (socket.setTypeOfService) { - socket.setTypeOfService(request.typeOfService); - } + setTypeOfService(socket, request); let header = `${method} ${path17} HTTP/1.1\r `; if (typeof host === "string") { @@ -36696,10 +36746,7 @@ var require_client_h22 = __commonJS({ kStrictContentLength, kOnError, kMaxConcurrentStreams, - kPingInterval, kHTTP2Session, - kHTTP2InitialWindowSize, - kHTTP2ConnectionWindowSize, kHostAuthority, kResume, kSize, @@ -36711,7 +36758,8 @@ var require_client_h22 = __commonJS({ kEnableConnectProtocol, kRemoteSettings, kHTTP2Stream, - kHTTP2SessionState + kHTTP2SessionState, + kHTTP2Options } = require_symbols6(); var { channels } = require_diagnostics2(); var kOpenStreams = /* @__PURE__ */ Symbol("open streams"); @@ -36720,6 +36768,9 @@ var require_client_h22 = __commonJS({ var kRequestStreamCleanup = /* @__PURE__ */ Symbol("request stream cleanup"); var kRequestStreamState = /* @__PURE__ */ Symbol("request stream state"); var kReceivedGoAway = /* @__PURE__ */ Symbol("received goaway"); + var kGoAwayReplayAttempts = /* @__PURE__ */ Symbol("goaway replay attempts"); + var kRefusedStreamRetry = /* @__PURE__ */ Symbol("refused stream retry"); + var MAX_GOAWAY_REPLAY_ATTEMPTS = 1; var extractBody; var http22; try { @@ -36803,6 +36854,7 @@ var require_client_h22 = __commonJS({ const queue = client[kQueue]; const runningIdx = client[kRunningIdx]; if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request) { + queue[runningIdx] = null; client[kRunningIdx] = runningIdx + 1; return; } @@ -36816,10 +36868,15 @@ var require_client_h22 = __commonJS({ client[kPendingIdx] = client[kRunningIdx]; } } - function canRetryRequestAfterGoAway(request) { + function canReplayRequest(request) { const { body: body2 } = request; return body2 == null || util7.isBuffer(body2) || util7.isBlobLike(body2); } + function registerGoAwayRefusal(request) { + const attempts = (request[kGoAwayReplayAttempts] ?? 0) + 1; + request[kGoAwayReplayAttempts] = attempts; + return attempts <= MAX_GOAWAY_REPLAY_ATTEMPTS; + } function closeStream(stream4, code = NGHTTP2_REFUSED_STREAM) { if (stream4 != null && !stream4.destroyed && !stream4.closed) { try { @@ -36831,15 +36888,30 @@ var require_client_h22 = __commonJS({ function detachRequestStreamForClose(request) { const stream4 = request[kRequestStream]; clearRequestStream(request); + severRequestStream(stream4); return stream4; } + function severRequestStream(stream4) { + if (stream4 == null || stream4[kRequestStreamState] == null) { + return; + } + stream4[kRequestStreamState] = null; + stream4.off("close", completeRequestStream); + stream4.off("close", onUpgradeStreamClose); + if (stream4[kHTTP2Session] != null) { + closeStreamSession(stream4); + } + if (!stream4.destroyed && !stream4.closed) { + stream4.once("error", noop); + } + } function connectH2(client, socket) { client[kSocket] = socket; - const http2InitialWindowSize = client[kHTTP2InitialWindowSize]; - const http2ConnectionWindowSize = client[kHTTP2ConnectionWindowSize]; + const http2InitialWindowSize = client[kHTTP2Options].sessionOptions?.initialWindowSize; + const http2ConnectionWindowSize = client[kHTTP2Options].connectionWindowSize; const session = http22.connect(client[kUrl], { createConnection: () => socket, - peerMaxConcurrentStreams: client[kMaxConcurrentStreams], + peerMaxConcurrentStreams: client[kHTTP2Options].maxConcurrentStreams, settings: { // TODO(metcoder95): add support for PUSH enablePush: false, @@ -36852,13 +36924,16 @@ var require_client_h22 = __commonJS({ session[kSocket] = socket; session[kHTTP2SessionState] = { idleTimeout: null, + // Armed while the peer advertises MAX_CONCURRENT_STREAMS = 0 and we have + // work that cannot start. See setNoStreamsTimeout. + noStreamsTimeout: null, // Sockets start out ref'd. Session ref/unref proxies to the socket, so a // single cached flag lets us skip redundant uv ref/unref calls, provided // every ref/unref of the session or its socket goes through // refH2Session/unrefH2Session. refed: true, ping: { - interval: client[kPingInterval] === 0 ? null : setInterval(onHttp2SendPing, client[kPingInterval], session).unref() + interval: client[kHTTP2Options].pingInterval === 0 ? null : setInterval(onHttp2SendPing, client[kHTTP2Options].pingInterval, session).unref() } }; session[kReceivedGoAway] = false; @@ -36869,7 +36944,6 @@ var require_client_h22 = __commonJS({ } util7.addListener(session, "error", onHttp2SessionError); util7.addListener(session, "frameError", onHttp2FrameError); - util7.addListener(session, "end", onHttp2SessionEnd); util7.addListener(session, "goaway", onHttp2SessionGoAway); util7.addListener(session, "close", onHttp2SessionClose); util7.addListener(session, "remoteSettings", onHttp2RemoteSettings); @@ -36928,7 +37002,6 @@ var require_client_h22 = __commonJS({ if (request != null) { if (client[kRunning] > 0) { if ((request.upgrade === "websocket" || request.method === "CONNECT") && session[kRemoteSettings] === false) return true; - if (util7.bodyLength(request.body) !== 0 && (util7.isStream(request.body) || util7.isAsyncIterable(request.body) || util7.isFormDataLike(request.body))) return true; } else { return (request.upgrade === "websocket" || request.method === "CONNECT") && session[kRemoteSettings] === false; } @@ -36965,8 +37038,48 @@ var require_client_h22 = __commonJS({ } else { clearHttp2IdleTimeout(session); } + if (client[kMaxConcurrentStreams] === 0 && client[kRunning] === 0 && client[kPending] > 0) { + setNoStreamsTimeout(session); + } else { + clearNoStreamsTimeout(session); + } } } + function clearNoStreamsTimeout(session) { + const state3 = session[kHTTP2SessionState]; + if (state3?.noStreamsTimeout != null) { + clearTimeout(state3.noStreamsTimeout); + state3.noStreamsTimeout = null; + } + } + function setNoStreamsTimeout(session) { + const client = session[kClient]; + const state3 = session[kHTTP2SessionState]; + const timeout = client[kHeadersTimeout]; + if (!timeout || state3.noStreamsTimeout != null) { + return; + } + state3.noStreamsTimeout = setTimeout(onNoStreamsTimeout, timeout, session).unref(); + } + function onNoStreamsTimeout(session) { + const client = session[kClient]; + const state3 = session[kHTTP2SessionState]; + state3.noStreamsTimeout = null; + if (client[kHTTP2Session] !== session || client[kMaxConcurrentStreams] !== 0 || client[kRunning] !== 0 || client[kPending] === 0) { + return; + } + const err = new HeadersTimeoutError( + `HTTP/2: server did not accept a new stream within ${client[kHeadersTimeout]}` + ); + const requests = client[kQueue].splice(client[kPendingIdx]); + for (let i = 0; i < requests.length; i++) { + if (requests[i] != null) { + util7.errorRequest(client, requests[i], err); + } + } + session[kError] = err; + resetHttp2Session(session, err); + } function clearHttp2IdleTimeout(session) { const state3 = session[kHTTP2SessionState]; if (state3?.idleTimeout != null) { @@ -37058,11 +37171,6 @@ var require_client_h22 = __commonJS({ this[kClient][kOnError](err); } } - function onHttp2SessionEnd() { - const err = new SocketError("other side closed", util7.getSocketInfo(this[kSocket])); - this.destroy(err); - util7.destroy(this[kSocket], err); - } function onHttp2SessionGoAway(errorCode, lastStreamID) { if (this[kReceivedGoAway]) { return; @@ -37078,7 +37186,7 @@ var require_client_h22 = __commonJS({ const request = client[kQueue][i]; if (request != null) { streamsToClose.push(detachRequestStreamForClose(request)); - if (canRetryRequestAfterGoAway(request)) { + if (canReplayRequest(request) && registerGoAwayRefusal(request)) { retriableRequests.push(request); } else { util7.errorRequest(client, request, err); @@ -37099,6 +37207,7 @@ var require_client_h22 = __commonJS({ client[kHTTP2Session] = null; } clearHttp2IdleTimeout(this); + clearNoStreamsTimeout(this); if (!this.closed && !this.destroyed) { this.close(); } @@ -37115,6 +37224,7 @@ var require_client_h22 = __commonJS({ client[kHTTP2Session] = null; } clearHttp2IdleTimeout(this); + clearNoStreamsTimeout(this); if (state3.ping.interval != null) { clearInterval(state3.ping.interval); state3.ping.interval = null; @@ -37156,7 +37266,7 @@ var require_client_h22 = __commonJS({ if (this[kHTTP2Session]?.[kReceivedGoAway]) { return; } - this[kClient][kOnError](err); + this[kHTTP2Session]?.[kClient]?.[kOnError](err); } function onHttp2SocketEnd() { util7.destroy(this, new SocketError("other side closed", util7.getSocketInfo(this))); @@ -37182,15 +37292,22 @@ var require_client_h22 = __commonJS({ failUpgradeStream(state3, new InformationalError("HTTP/2: stream closed before response headers")); closeStreamSession(this); } - function onRequestStreamClose() { + function completeRequestStream() { const state3 = this[kRequestStreamState]; - if (state3) { - releaseRequestStream(this); - if (state3.pendingEnd && !state3.request.aborted && !state3.request.completed) { - state3.request.onResponseEnd(state3.trailers || {}); - finalizeRequest(state3); - } + if (state3 == null) { + return; } + releaseRequestStream(this); + if (state3.pendingEnd && !state3.request.aborted && !state3.request.completed) { + state3.request.onResponseEnd(state3.trailers || {}); + } else if (!state3.request.aborted && !state3.request.completed) { + util7.errorRequest( + state3.client, + state3.request, + new InformationalError("HTTP/2: stream closed before the response was complete") + ); + } + finalizeRequest(state3); closeStreamSession(this); this[kRequestStreamState] = null; } @@ -37370,11 +37487,9 @@ var require_client_h22 = __commonJS({ clearRequestStream(request); const stream5 = state3.stream; stream5.close(); - setImmediate(() => { - if (!stream5.destroyed) { - util7.destroy(stream5); - } - }); + if (!stream5.destroyed) { + util7.destroy(stream5); + } client[kOnError](err); finalizeRequest(state3, resetPendingIdx); } @@ -37483,7 +37598,7 @@ var require_client_h22 = __commonJS({ stream4.setTimeout(headersTimeout); } stream4[kHTTP2Session] = session; - stream4.on("close", onRequestStreamClose); + stream4.on("close", completeRequestStream); bindRequestToStream(request, stream4, releaseRequestStream); if (expectContinue) { stream4.once("continue", writeBodyH2); @@ -37584,11 +37699,26 @@ var require_client_h22 = __commonJS({ if (state3.responseReceived) { if (!request.aborted && !request.completed) { state3.pendingEnd = true; + completeRequestStream.call(stream4); } } else { state3.abort(new InformationalError("HTTP/2: stream half-closed (remote)"), true); } } + function retryRefusedStream(stream4, state3) { + const { client, request } = state3; + if (state3.responseReceived || request.aborted || request.completed || request[kRefusedStreamRetry] || !canReplayRequest(request)) { + return false; + } + request[kRefusedStreamRetry] = true; + detachRequestStreamForClose(request); + state3.stream = null; + state3.requestFinalized = true; + completeRequest(client, request); + client[kQueue].splice(client[kPendingIdx], 0, request); + client[kResume](); + return true; + } function onError(err) { const stream4 = this; const state3 = stream4[kRequestStreamState]; @@ -37596,6 +37726,12 @@ var require_client_h22 = __commonJS({ return; } stream4.off("error", onError); + if (typeof stream4.rstCode === "number" && stream4.rstCode !== NGHTTP2_NO_ERROR) { + err.http2ErrorCode = stream4.rstCode; + } + if (stream4.rstCode === NGHTTP2_REFUSED_STREAM && retryRefusedStream(stream4, state3)) { + return; + } state3.abort(err); } function onFrameError(type, code) { @@ -37877,10 +38013,8 @@ var require_client2 = __commonJS({ kHTTPContext, kMaxConcurrentStreams, kHostAuthority, - kHTTP2InitialWindowSize, - kHTTP2ConnectionWindowSize, kResume, - kPingInterval + kHTTP2Options } = require_symbols6(); var connectH1 = require_client_h12(); var connectH2 = require_client_h22(); @@ -37893,6 +38027,14 @@ var require_client2 = __commonJS({ function getPipelining(client) { return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1; } + var h2NamespaceOptsWarning = false; + function emitH2OptionsNamespaceWarning(optName) { + if (h2NamespaceOptsWarning === true) return; + process.emitWarning(`Use h2Options.${optName} instead. ${optName} for H2 will be deprecated in future major.`, { + code: "UNDICI-H2-OPTIONS" + }); + h2NamespaceOptsWarning = true; + } function getMaxConcurrent(client) { if (client[kHTTPContext]?.version === "h2") { return client[kMaxConcurrentStreams]; @@ -37936,7 +38078,8 @@ var require_client2 = __commonJS({ initialWindowSize, connectionWindowSize, pingInterval, - webSocket + webSocket, + h2Options } = {}) { if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); @@ -37999,20 +38142,45 @@ var require_client2 = __commonJS({ if (allowH2 != null && typeof allowH2 !== "boolean") { throw new InvalidArgumentError("allowH2 must be a valid boolean value"); } - if (maxConcurrentStreams != null && (typeof maxConcurrentStreams !== "number" || maxConcurrentStreams < 1)) { - throw new InvalidArgumentError("maxConcurrentStreams must be a positive integer, greater than 0"); - } - if (useH2c != null && typeof useH2c !== "boolean") { - throw new InvalidArgumentError("useH2c must be a valid boolean value"); - } - if (initialWindowSize != null && (!Number.isInteger(initialWindowSize) || initialWindowSize < 1)) { - throw new InvalidArgumentError("initialWindowSize must be a positive integer, greater than 0"); - } - if (connectionWindowSize != null && (!Number.isInteger(connectionWindowSize) || connectionWindowSize < 1)) { - throw new InvalidArgumentError("connectionWindowSize must be a positive integer, greater than 0"); - } - if (pingInterval != null && (typeof pingInterval !== "number" || !Number.isInteger(pingInterval) || pingInterval < 0)) { - throw new InvalidArgumentError("pingInterval must be a positive integer, greater or equal to 0"); + if (allowH2 !== false) { + if (h2Options != null) { + if (h2Options.useH2c != null && typeof h2Options.useH2c !== "boolean") { + throw new InvalidArgumentError("h2Options.useH2c must be a valid boolean value"); + } + if (h2Options.settings?.initialWindowSize != null && (!Number.isInteger(h2Options.settings.initialWindowSize) || h2Options.settings.initialWindowSize < 1)) { + throw new InvalidArgumentError("h2Options.settings.initialWindowSize must be a positive integer, greater than 0"); + } + if (h2Options.maxConcurrentStreams != null && (!Number.isInteger(h2Options.connectionWindowSize) || h2Options.maxConcurrentStreams < 1)) { + throw new InvalidArgumentError("h2Options.maxConcurrentStreams must be a positive integer, greater than 0"); + } + if (h2Options.connectionWindowSize != null && (!Number.isInteger(h2Options.connectionWindowSize) || h2Options.connectionWindowSize < 1)) { + throw new InvalidArgumentError("h2Options.connectionWindowSize must be a positive integer, greater than 0"); + } + if (h2Options.pingInterval != null && (typeof h2Options.pingInterval !== "number" || !Number.isInteger(h2Options.pingInterval) || h2Options.pingInterval < 0)) { + throw new InvalidArgumentError("h2Options.pingInterval must be a positive integer, greater or equal to 0"); + } + } else { + if (useH2c != null && typeof useH2c !== "boolean") { + emitH2OptionsNamespaceWarning("useH2c"); + throw new InvalidArgumentError("useH2c must be a valid boolean value"); + } + if (maxConcurrentStreams != null && (typeof maxConcurrentStreams !== "number" || maxConcurrentStreams < 1)) { + emitH2OptionsNamespaceWarning("maxConcurrentStreams"); + throw new InvalidArgumentError("maxConcurrentStreams must be a positive integer, greater than 0"); + } + if (initialWindowSize != null && (!Number.isInteger(initialWindowSize) || initialWindowSize < 1)) { + emitH2OptionsNamespaceWarning("initialWindowSize"); + throw new InvalidArgumentError("initialWindowSize must be a positive integer, greater than 0"); + } + if (connectionWindowSize != null && (!Number.isInteger(connectionWindowSize) || connectionWindowSize < 1)) { + emitH2OptionsNamespaceWarning("connectionWindowSize"); + throw new InvalidArgumentError("connectionWindowSize must be a positive integer, greater than 0"); + } + if (pingInterval != null && (typeof pingInterval !== "number" || !Number.isInteger(pingInterval) || pingInterval < 0)) { + emitH2OptionsNamespaceWarning("pingInterval"); + throw new InvalidArgumentError("pingInterval must be a positive integer, greater or equal to 0"); + } + } } super({ webSocket }); if (typeof connect2 !== "function") { @@ -38020,8 +38188,8 @@ var require_client2 = __commonJS({ ...tls, maxCachedSessions, allowH2, - useH2c, socketPath, + useH2c: h2Options?.useH2c ?? useH2c, timeout: connectTimeout, ...typeof autoSelectFamily === "boolean" ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : void 0, ...connect2 @@ -38056,10 +38224,21 @@ var require_client2 = __commonJS({ this[kClosedResolve] = null; this[kMaxResponseSize] = maxResponseSize > -1 ? maxResponseSize : -1; this[kHTTPContext] = null; - this[kMaxConcurrentStreams] = maxConcurrentStreams != null ? maxConcurrentStreams : 100; - this[kHTTP2InitialWindowSize] = initialWindowSize != null ? initialWindowSize : 262144; - this[kHTTP2ConnectionWindowSize] = connectionWindowSize != null ? connectionWindowSize : 524288; - this[kPingInterval] = pingInterval != null ? pingInterval : 6e4; + this[kHTTP2Options] = { + pingInterval: h2Options?.pingInterval ?? pingInterval ?? 6e4, + connectionWindowSize: h2Options?.connectionWindowSize ?? connectionWindowSize ?? 524288, + maxConcurrentStreams: h2Options?.maxConcurrentStreams ?? maxConcurrentStreams ?? 100, + // Max peerConcurrentStreams for a Node h2 server + sessionOptions: { + // HTTP/2 window sizes are set to higher defaults than Node.js core for better performance: + // - initialWindowSize: 262144 (256KB) vs Node.js default 65535 (64KB - 1) + // Allows more data to be sent before requiring acknowledgment, improving throughput + // especially on high-latency networks. This matches common production HTTP/2 servers. + // - connectionWindowSize: 524288 (512KB) vs Node.js default (none set) + // Provides better flow control for the entire connection across multiple streams. + initialWindowSize: h2Options?.initialWindowSize ?? initialWindowSize ?? 262144 + } + }; this[kQueue] = []; this[kRunningIdx] = 0; this[kPendingIdx] = 0; @@ -38344,6 +38523,7 @@ var require_client2 = __commonJS({ return; } if (!client[kHTTPContext]) { + client[kServerName] = request.servername; connect(client); return; } @@ -39114,14 +39294,14 @@ var require_agent2 = __commonJS({ dispatcher.close(); } let hasOrigin = false; - for (const client of this[kClients].values()) { - if (client[kUrl].origin === dispatcher[kUrl].origin) { + for (const k of this[kClients].keys()) { + if (k === origin || k === `${origin}#http1-only`) { hasOrigin = true; break; } } if (!hasOrigin) { - this[kOrigins].delete(dispatcher[kUrl].origin); + this[kOrigins].delete(origin); } }; dispatcher.on("drain", this[kOnDrain]).on("connect", this[kOnConnect]).on("disconnect", (origin2, targets, err) => { @@ -39754,7 +39934,7 @@ var require_socks5_proxy_agent = __commonJS({ var DispatcherBase = require_dispatcher_base2(); var { InvalidArgumentError } = require_errors2(); var { Socks5Client, STATES } = require_socks5_client(); - var { kDispatch, kClose, kDestroy } = require_symbols6(); + var { kBusy, kConnected, kDispatch, kClose, kDestroy } = require_symbols6(); var Pool = require_pool2(); var buildConnector = require_connect2(); var { debuglog } = require("node:util"); @@ -39912,6 +40092,17 @@ var require_socks5_proxy_agent = __commonJS({ } }); this[kPools].set(originKey, pool); + const closePoolIfUnused = () => { + if (this[kPools].get(originKey) !== pool || pool[kConnected] > 0 || pool[kBusy]) { + return; + } + this[kPools].delete(originKey); + if (!pool.destroyed) { + pool.close(); + } + }; + pool.on("disconnect", closePoolIfUnused); + pool.on("connectionError", closePoolIfUnused); } return pool[kDispatch](opts, handler); } catch (err) { @@ -40296,7 +40487,7 @@ var require_env_http_proxy_agent2 = __commonJS({ } #getProxyAgentForUrl(url2) { let { protocol, host: hostname, port } = url2; - hostname = hostname.replace(/:\d*$/, "").toLowerCase(); + hostname = hostname.replace(/:\d*$/, "").replace(/^\[(.+)\]$/, "$1").toLowerCase(); port = Number.parseInt(port, 10) || DEFAULT_PORTS[protocol] || 0; if (!this.#shouldProxy(hostname, port)) { return this[kNoProxyAgent]; @@ -40339,11 +40530,22 @@ var require_env_http_proxy_agent2 = __commonJS({ if (!entry) { continue; } - const parsed = entry.match(/^(.+):(\d+)$/); + let hostname, port; + const ipv6WithPort = entry.match(/^\[(.+)\]:(\d+)$/); + if (ipv6WithPort) { + hostname = ipv6WithPort[1]; + port = Number.parseInt(ipv6WithPort[2], 10); + } else { + const unbracketed = entry.replace(/^\[(.+)\]$/, "$1"); + const colonCount = (unbracketed.match(/:/g) || []).length; + const parsed = colonCount === 1 && unbracketed.match(/^(.+):(\d+)$/); + hostname = parsed ? parsed[1] : unbracketed; + port = parsed ? Number.parseInt(parsed[2], 10) : 0; + } noProxyEntries.push({ // strip leading dot or asterisk with dot - hostname: (parsed ? parsed[1] : entry).replace(/^\*?\./, "").toLowerCase(), - port: parsed ? Number.parseInt(parsed[2], 10) : 0 + hostname: hostname.replace(/^\*?\./, "").toLowerCase(), + port }); } this.#noProxyValue = noProxyValue; @@ -40377,7 +40579,24 @@ var require_retry_handler2 = __commonJS({ } = require_util9(); function calculateRetryAfterHeader(retryAfter) { const retryTime = new Date(retryAfter).getTime(); - return isNaN(retryTime) ? 0 : retryTime - Date.now(); + return isNaN(retryTime) ? null : retryTime - Date.now(); + } + function validatePartialResponseContentLength(headers, range2, statusCode, retryCount) { + const contentLength2 = headers["content-length"]; + if (contentLength2 == null) { + return; + } + if (!Number.isFinite(range2.start) || !Number.isFinite(range2.end)) { + return; + } + const length = Number(contentLength2); + const expectedLength = range2.end - range2.start + 1; + if (!Number.isFinite(length) || length !== expectedLength) { + throw new RequestRetryError("Content-Length mismatch", statusCode, { + headers, + data: { count: retryCount } + }); + } } var RetryController = class { constructor() { @@ -40544,10 +40763,14 @@ var require_retry_handler2 = __commonJS({ retryAfterHeader = Number(retryAfterHeader); retryAfterHeader = Number.isNaN(retryAfterHeader) ? calculateRetryAfterHeader(headers["retry-after"]) : retryAfterHeader * 1e3; } - const retryTimeout = retryAfterHeader > 0 ? Math.min(retryAfterHeader, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout); + const retryTimeout = retryAfterHeader === 0 ? 0 : retryAfterHeader > 0 ? Math.min(retryAfterHeader, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout); setTimeout(() => cb(null), retryTimeout); } onResponseStart(controller, statusCode, headers, statusMessage) { + if (statusCode < 200) { + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + return; + } this.error = null; this.retryCount += 1; this.statusCode = statusCode; @@ -40582,6 +40805,7 @@ var require_retry_handler2 = __commonJS({ data: { count: this.retryCount } }); } + validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); const { start, size, end = size ? size - 1 : null } = contentRange; assert4(this.start === start, "content-range mismatch"); assert4(this.end == null || this.end === end, "content-range mismatch"); @@ -40590,7 +40814,7 @@ var require_retry_handler2 = __commonJS({ if (this.end == null) { if (statusCode === 206) { const range2 = parseRangeHeader(headers["content-range"]); - if (range2 == null) { + if (range2 == null || range2.end == null) { this.headersSent = true; this.handler.onResponseStart?.( this.controllerProxy, @@ -40600,6 +40824,7 @@ var require_retry_handler2 = __commonJS({ ); return; } + validatePartialResponseContentLength(headers, range2, statusCode, this.retryCount); const { start, size, end = size ? size - 1 : null } = range2; assert4( start != null && Number.isFinite(start), @@ -40609,7 +40834,7 @@ var require_retry_handler2 = __commonJS({ this.start = start; this.end = end; } - if (this.end == null) { + if (this.end == null && this.opts.method !== "HEAD") { const contentLength2 = headers["content-length"]; this.end = contentLength2 != null ? Number(contentLength2) - 1 : null; } @@ -40810,7 +41035,6 @@ var require_readable2 = __commonJS({ var kContentLength = /* @__PURE__ */ Symbol("kContentLength"); var kUsed = /* @__PURE__ */ Symbol("kUsed"); var kBytesRead = /* @__PURE__ */ Symbol("kBytesRead"); - var kPreservedBuffer = /* @__PURE__ */ Symbol("kPreservedBuffer"); var noop = () => { }; var BodyReadable = class extends Readable6 { @@ -41049,21 +41273,6 @@ var require_readable2 = __commonJS({ */ setEncoding(encoding) { if (Buffer.isEncoding(encoding)) { - const state3 = this._readableState; - const buffer3 = state3.buffer; - if (buffer3 && state3.length > 0) { - const bufferIndex = state3.bufferIndex ?? 0; - const preserved = []; - const source = typeof buffer3.slice === "function" ? buffer3.slice(bufferIndex) : buffer3; - for (const data of source) { - if (Buffer.isBuffer(data)) { - preserved.push(data); - } - } - if (preserved.length > 0) { - this[kPreservedBuffer] = (this[kPreservedBuffer] || []).concat(preserved); - } - } super.setEncoding(encoding); } return this; @@ -41114,13 +41323,7 @@ var require_readable2 = __commonJS({ return; } const { _readableState: state3 } = consume2.stream; - const preserved = consume2.stream[kPreservedBuffer]; - if (preserved && preserved.length > 0) { - for (const chunk of preserved) { - consumePush(consume2, chunk); - } - consume2.stream[kPreservedBuffer] = null; - } else if (state3.bufferIndex) { + if (state3.bufferIndex) { const start = state3.bufferIndex; const end = state3.buffer.length; for (let n = start; n < end; n++) { @@ -41131,13 +41334,17 @@ var require_readable2 = __commonJS({ consumePush(consume2, chunk); } } - if (state3.endEmitted) { - consumeEnd(this[kConsume], this._readableState.encoding); - } else { - consume2.stream.on("end", function() { - consumeEnd(this[kConsume], this._readableState.encoding); - }); + const decoder = state3.decoder; + if (decoder != null && decoder.lastNeed > 0) { + consumePush(consume2, Buffer.from(decoder.lastChar.subarray(0, decoder.lastTotal - decoder.lastNeed))); } + if (state3.endEmitted) { + consumeEnd(consume2, state3.encoding); + return; + } + consume2.stream.on("end", function() { + consumeEnd(this[kConsume], this._readableState.encoding); + }); consume2.stream.resume(); while (consume2.stream.read() != null) { } @@ -41194,6 +41401,9 @@ var require_readable2 = __commonJS({ if (consume2.body === null) { return; } + if (typeof chunk === "string") { + chunk = Buffer.from(chunk, consume2.stream._readableState.encoding); + } consume2.length += chunk.length; consume2.body.push(chunk); } @@ -42178,6 +42388,7 @@ var require_mock_utils2 = __commonJS({ } } = require("node:util"); var { InvalidArgumentError } = require_errors2(); + var requestAborted = /* @__PURE__ */ Symbol("request aborted"); function matchValue(match2, value) { if (typeof match2 === "string") { return match2 === value; @@ -42290,6 +42501,8 @@ var require_mock_utils2 = __commonJS({ return data; } else if (data instanceof ArrayBuffer) { return data; + } else if (ArrayBuffer.isView(data)) { + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); } else if (typeof data === "object") { return JSON.stringify(data); } else if (data) { @@ -42343,6 +42556,9 @@ var require_mock_utils2 = __commonJS({ } } function removeTrailingSlash(path17) { + if (typeof path17 !== "string") { + return path17; + } while (path17.endsWith("/")) { path17 = path17.slice(0, -1); } @@ -42391,17 +42607,43 @@ var require_mock_utils2 = __commonJS({ function mockDispatch(opts, handler) { const key = buildKey(opts); const mockDispatch2 = getMockDispatch(this[kDispatches], key); + const mockDispatches = this[kDispatches]; mockDispatch2.timesInvoked++; - if (mockDispatch2.data.callback) { - mockDispatch2.data = { ...mockDispatch2.data, ...mockDispatch2.data.callback(opts) }; - } - const { data: { statusCode, data, headers, trailers, error: error2 }, delay: delay4, persist } = mockDispatch2; const { timesInvoked, times } = mockDispatch2; - mockDispatch2.consumed = !persist && timesInvoked >= times; + mockDispatch2.consumed = !mockDispatch2.persist && timesInvoked >= times; mockDispatch2.pending = timesInvoked < times; - if (error2 !== null) { - deleteMockDispatch(this[kDispatches], key); - handler.onResponseError(null, error2); + const hasBodyHooks = typeof handler.onBodySent === "function" || typeof handler.onRequestSent === "function"; + if (mockDispatch2.data.callback && (!hasBodyHooks || opts.body == null)) { + const { callback, ...responseDefaults } = mockDispatch2.data; + const callbackResult = callback(opts); + if (isPromise(callbackResult)) { + callbackResult.then( + (resolvedData) => { + if (resolvedData == null || typeof resolvedData !== "object") { + handler.onResponseError(null, new InvalidArgumentError("reply options callback must return an object")); + return; + } + mockDispatch2.data = { ...responseDefaults, ...resolvedData }; + dispatchMockReply(mockDispatches, mockDispatch2, key, opts, handler); + }, + (error2) => { + handler.onResponseError(null, error2); + } + ); + return true; + } + if (callbackResult == null || typeof callbackResult !== "object") { + throw new InvalidArgumentError("reply options callback must return an object"); + } + mockDispatch2.data = { ...responseDefaults, ...callbackResult }; + } + return dispatchMockReply(mockDispatches, mockDispatch2, key, opts, handler); + } + function dispatchMockReply(mockDispatches, mockDispatch2, key, opts, handler) { + const { data: response, delay: delay4 } = mockDispatch2; + if (response.error !== null) { + deleteMockDispatch(mockDispatches, key); + handler.onResponseError(null, response.error); return true; } let aborted = false; @@ -42428,39 +42670,172 @@ var require_mock_utils2 = __commonJS({ handler.onResponseError?.(controller, reason); } }; + let replyOpts = opts; + const dispatches = mockDispatches; handler.onRequestStart?.(controller, null); - if (typeof delay4 === "number" && delay4 > 0) { - timer = setTimeout(() => { - timer = null; - handleReply(this[kDispatches]); - }, delay4); - } else { - handleReply(this[kDispatches]); + if (aborted) { + return true; } - function handleReply(mockDispatches, _data = data) { + const requestBody = dispatchRequestBody(opts.body, handler, controller, () => aborted); + if (isPromise(requestBody)) { + requestBody.then((body2) => { + if (body2 === requestAborted) { + return; + } + if (body2 !== opts.body) { + replyOpts = { ...opts, body: body2 }; + } + sendReply(); + }, (error2) => controller.abort(error2)); + return true; + } + if (requestBody === requestAborted) { + return true; + } + if (requestBody !== opts.body) { + replyOpts = { ...opts, body: requestBody }; + } + sendReply(); + function sendReply() { + if (response.callback) { + const { callback, ...responseDefaults } = response; + let callbackResult; + try { + callbackResult = callback(replyOpts); + } catch (err) { + deleteMockDispatch(mockDispatches, key); + handler.onResponseError(null, err); + return; + } + if (isPromise(callbackResult)) { + callbackResult.then( + (resolvedData) => { + if (resolvedData == null || typeof resolvedData !== "object") { + handler.onResponseError(null, new InvalidArgumentError("reply options callback must return an object")); + return; + } + mockDispatch2.data = { ...responseDefaults, ...resolvedData }; + handleReply(dispatches, mockDispatch2.data); + }, + (err) => { + handler.onResponseError(null, err); + } + ); + return; + } + if (callbackResult == null || typeof callbackResult !== "object") { + throw new InvalidArgumentError("reply options callback must return an object"); + } + mockDispatch2.data = { ...responseDefaults, ...callbackResult }; + handleReply(dispatches, mockDispatch2.data); + return; + } + if (typeof delay4 === "number" && delay4 > 0) { + timer = setTimeout(() => { + timer = null; + handleReply(dispatches); + }, delay4); + } else { + handleReply(dispatches); + } + } + function handleReply(mockDispatches2, _response = response) { if (aborted) { return; } + const { statusCode, data, headers, trailers } = _response; const optsHeaders = Array.isArray(opts.headers) ? buildHeadersFromArray(opts.headers) : opts.headers; - const body2 = typeof _data === "function" ? _data({ ...opts, headers: optsHeaders }) : _data; + const body2 = typeof data === "function" ? data({ ...replyOpts, headers: optsHeaders }) : data; if (isPromise(body2)) { - return body2.then((newData) => handleReply(mockDispatches, newData)); + return body2.then((newData) => handleReply(mockDispatches2, { ..._response, data: newData })); } if (aborted) { return; } const responseData = getResponseData(body2); - const responseHeaders = generateKeyValues(headers); - const responseTrailers = generateKeyValues(trailers); + const responseHeaders = generateKeyValues(headers ?? {}); + const responseTrailers = generateKeyValues(trailers ?? {}); controller.rawHeaders = responseHeaders; controller.rawTrailers = responseTrailers; handler.onResponseStart?.(controller, statusCode, parseHeaders(responseHeaders), getStatusText(statusCode)); handler.onResponseData?.(controller, Buffer.from(responseData)); handler.onResponseEnd?.(controller, parseHeaders(responseTrailers)); - deleteMockDispatch(mockDispatches, key); + deleteMockDispatch(mockDispatches2, key); } return true; } + function dispatchRequestBody(body2, handler, controller, isAborted) { + if (typeof handler.onBodySent !== "function" && typeof handler.onRequestSent !== "function") { + return body2; + } + if (body2 == null) { + return callOnRequestSent(handler, controller, isAborted) ? body2 : requestAborted; + } + if (body2 && typeof body2[Symbol.asyncIterator] === "function") { + return dispatchAsyncIterableBody(body2, handler, controller, isAborted); + } + if (isIterableBody(body2)) { + const chunks = []; + for (const chunk of body2) { + if (isAborted()) { + return requestAborted; + } + chunks.push(chunk); + if (!callOnBodySent(handler, controller, chunk) || isAborted()) { + return requestAborted; + } + } + return callOnRequestSent(handler, controller, isAborted) ? chunks : requestAborted; + } + if (isAborted()) { + return requestAborted; + } + if (!callOnBodySent(handler, controller, body2)) { + return requestAborted; + } + return callOnRequestSent(handler, controller, isAborted) ? body2 : requestAborted; + } + async function dispatchAsyncIterableBody(body2, handler, controller, isAborted) { + const chunks = []; + for await (const chunk of body2) { + if (isAborted()) { + return requestAborted; + } + chunks.push(chunk); + if (!callOnBodySent(handler, controller, chunk) || isAborted()) { + return requestAborted; + } + } + if (!callOnRequestSent(handler, controller, isAborted)) { + return requestAborted; + } + return { + async *[Symbol.asyncIterator]() { + yield* chunks; + } + }; + } + function callOnBodySent(handler, controller, chunk) { + try { + handler.onBodySent?.(chunk); + return true; + } catch (error2) { + controller.abort(error2); + return false; + } + } + function callOnRequestSent(handler, controller, isAborted) { + try { + handler.onRequestSent?.(); + return !isAborted(); + } catch (error2) { + controller.abort(error2); + return false; + } + } + function isIterableBody(body2) { + return typeof body2 !== "string" && !Buffer.isBuffer(body2) && !ArrayBuffer.isView(body2) && typeof body2[Symbol.iterator] === "function"; + } function buildMockDispatch() { const agent = this[kMockAgent]; const origin = this[kOrigin]; @@ -42561,6 +42936,11 @@ var require_mock_interceptor2 = __commonJS({ } = require_mock_symbols2(); var { InvalidArgumentError } = require_errors2(); var { serializePathWithQuery } = require_util9(); + var { + types: { + isPromise + } + } = require("node:util"); var MockScope = class { constructor(mockDispatch) { this[kMockDispatch] = mockDispatch; @@ -42642,8 +43022,7 @@ var require_mock_interceptor2 = __commonJS({ */ reply(replyOptionsCallbackOrStatusCode) { if (typeof replyOptionsCallbackOrStatusCode === "function") { - const wrappedDefaultsCallback = (opts) => { - const resolvedData = replyOptionsCallbackOrStatusCode(opts); + const resolveReplyCallbackData = (resolvedData) => { if (typeof resolvedData !== "object" || resolvedData === null) { throw new InvalidArgumentError("reply options callback must return an object"); } @@ -42653,6 +43032,13 @@ var require_mock_interceptor2 = __commonJS({ ...this.createMockScopeDispatchData(replyParameters2) }; }; + const wrappedDefaultsCallback = (opts) => { + const resolvedData = replyOptionsCallbackOrStatusCode(opts); + if (isPromise(resolvedData)) { + return resolvedData.then(resolveReplyCallbackData); + } + return resolveReplyCallbackData(resolvedData); + }; const newMockDispatch2 = addMockDispatch(this[kDispatches], this[kDispatchKey], wrappedDefaultsCallback, { ignoreTrailingSlash: this[kIgnoreTrailingSlash] }); return new MockScope(newMockDispatch2); } @@ -44041,6 +44427,7 @@ var require_global4 = __commonJS({ var { InvalidArgumentError } = require_errors2(); var Agent3 = require_agent2(); var Dispatcher1Wrapper = require_dispatcher1_wrapper(); + var fallbackDispatcher; if (getGlobalDispatcher() === void 0) { setGlobalDispatcher(new Agent3()); } @@ -44048,22 +44435,36 @@ var require_global4 = __commonJS({ if (!agent || typeof agent.dispatch !== "function") { throw new InvalidArgumentError("Argument agent must implement Agent"); } - Object.defineProperty(globalThis, globalDispatcher, { - value: agent, - writable: true, - enumerable: false, - configurable: false - }); - const legacyAgent = agent instanceof Dispatcher1Wrapper ? agent : new Dispatcher1Wrapper(agent); - Object.defineProperty(globalThis, legacyGlobalDispatcher, { - value: legacyAgent, - writable: true, - enumerable: false, - configurable: false - }); + try { + Object.defineProperty(globalThis, globalDispatcher, { + value: agent, + writable: true, + enumerable: false, + configurable: false + }); + } catch (err) { + if (err instanceof TypeError) { + fallbackDispatcher = agent; + return; + } + throw err; + } + try { + const legacyAgent = agent instanceof Dispatcher1Wrapper ? agent : new Dispatcher1Wrapper(agent); + Object.defineProperty(globalThis, legacyGlobalDispatcher, { + value: legacyAgent, + writable: true, + enumerable: false, + configurable: false + }); + } catch (err) { + if (!(err instanceof TypeError)) { + throw err; + } + } } function getGlobalDispatcher() { - return globalThis[globalDispatcher]; + return globalThis[globalDispatcher] ?? fallbackDispatcher; } var installedExports = ( /** @type {const} */ @@ -44189,12 +44590,14 @@ var require_redirect_handler2 = __commonJS({ if (this.opts.throwOnMaxRedirect && this.history.length >= this.maxRedirections) { throw new Error("max redirects"); } + let removeContentHeaders = statusCode === 303; if ((statusCode === 301 || statusCode === 302) && this.opts.method === "POST") { this.opts.method = "GET"; if (util7.isStream(this.opts.body)) { util7.destroy(this.opts.body.on("error", noop)); } this.opts.body = null; + removeContentHeaders = true; } if (statusCode === 303 && this.opts.method !== "HEAD") { this.opts.method = "GET"; @@ -44219,7 +44622,7 @@ var require_redirect_handler2 = __commonJS({ throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`); } } - this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect); + this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect); this.opts.path = path17; this.opts.origin = origin; this.opts.query = null; @@ -44960,24 +45363,146 @@ var require_cache2 = __commonJS({ var { safeHTTPMethods, pathHasQueryOrFragment, - hasSafeIterator + hasSafeIterator, + isValidHTTPToken } = require_util9(); var { serializePathWithQuery } = require_util9(); - function makeCacheKey(opts) { - if (!opts.origin) { - throw new Error("opts.origin is undefined"); + var MAX_DELTA_SECONDS = 2147483647; + var RESTRICTIVE_DIRECTIVE_NAMES = ["no-store", "private", "no-cache"]; + var kInvalidCacheControlDirectives = /* @__PURE__ */ Symbol("invalid cache-control directives"); + function trimOWS(value) { + return value.replace(/^[\t ]+|[\t ]+$/g, ""); + } + function arrayIncludes(array, value) { + for (let i = 0; i < array.length; i++) { + if (array[i] === value) { + return true; + } } + return false; + } + function trimOWSStart(value) { + return value.replace(/^[\t ]+/, ""); + } + function trimOWSEnd(value) { + return value.replace(/[\t ]+$/, ""); + } + function findUnescapedQuote(value, start) { + let escaped = false; + for (let i = start; i < value.length; i++) { + if (escaped) { + escaped = false; + } else if (value[i] === "\\") { + escaped = true; + } else if (value[i] === '"') { + return i; + } + } + return -1; + } + function splitCacheControlHeaderValue(value) { + const directives = []; + let start = 0; + let quoteStart = -1; + let inQuote = false; + let escaped = false; + for (let i = 0; i < value.length; i++) { + if (inQuote) { + if (escaped) { + escaped = false; + } else if (value[i] === "\\") { + escaped = true; + } else if (value[i] === '"') { + inQuote = false; + quoteStart = -1; + } + } else if (value[i] === '"') { + inQuote = true; + quoteStart = i; + } else if (value[i] === ",") { + directives.push({ value: value.substring(start, i), fromMalformedQuote: false }); + start = i + 1; + } + } + if (!inQuote) { + directives.push({ value: value.substring(start), fromMalformedQuote: false }); + return directives; + } + const tail = value.substring(start); + const quoteOffset = quoteStart - start; + let tailStart = 0; + for (let i = 0; i < tail.length; i++) { + if (tail[i] === ",") { + directives.push({ + value: tail.substring(tailStart, i), + fromMalformedQuote: tailStart > quoteOffset + }); + tailStart = i + 1; + } + } + directives.push({ + value: tail.substring(tailStart), + fromMalformedQuote: tailStart > quoteOffset + }); + return directives; + } + function markInvalidCacheControlDirective(directives, key) { + let invalidDirectives = directives[kInvalidCacheControlDirectives]; + if (invalidDirectives === void 0) { + invalidDirectives = /* @__PURE__ */ new Set(); + Object.defineProperty(directives, kInvalidCacheControlDirectives, { + value: invalidDirectives + }); + } + invalidDirectives.add(key); + } + function hasInvalidCacheControlDirective(directives, key) { + return directives[kInvalidCacheControlDirectives]?.has(key) === true; + } + function getMalformedRestrictiveDirectiveName(key) { + for (const directiveName of RESTRICTIVE_DIRECTIVE_NAMES) { + if (key.startsWith(directiveName) && key.length > directiveName.length && !isValidHTTPToken(key[directiveName.length])) { + return directiveName; + } + } + let tokenOnlyKey = ""; + let hasInvalidTokenChar = false; + for (let i = 0; i < key.length; i++) { + if (isValidHTTPToken(key[i])) { + tokenOnlyKey += key[i]; + } else { + hasInvalidTokenChar = true; + } + } + if (hasInvalidTokenChar && arrayIncludes(RESTRICTIVE_DIRECTIVE_NAMES, tokenOnlyKey)) { + return tokenOnlyKey; + } + } + function makeCacheKey(opts) { + const origin = opts.origin ? opts.origin.toString() : ""; let fullPath = opts.path || "/"; if (opts.query && !pathHasQueryOrFragment(fullPath)) { fullPath = serializePathWithQuery(fullPath, opts.query); } return { - origin: opts.origin.toString(), + origin, method: opts.method, path: fullPath, headers: opts.headers }; } + function appendHeader(headers, key, val) { + const headerName = key.toLowerCase(); + const current = headers[headerName]; + const values = Array.isArray(val) ? val : [val]; + if (current === void 0) { + headers[headerName] = Array.isArray(val) ? val.slice() : val; + } else if (Array.isArray(current)) { + current.push(...values); + } else { + headers[headerName] = [current, ...values]; + } + } function normalizeHeaders(opts) { let headers; if (opts.headers == null) { @@ -44985,19 +45510,57 @@ var require_cache2 = __commonJS({ } else if (typeof opts.headers === "object") { headers = {}; if (hasSafeIterator(opts.headers)) { - for (const x of opts.headers) { - if (!Array.isArray(x)) { - throw new Error("opts.headers is not a valid header map"); + if (Array.isArray(opts.headers)) { + const first = opts.headers[0]; + if (Array.isArray(first)) { + for (const x of opts.headers) { + if (!Array.isArray(x)) { + throw new Error("opts.headers is not a valid header map"); + } + const [key, val] = x; + if (typeof key !== "string" || typeof val !== "string") { + throw new Error("opts.headers is not a valid header map"); + } + appendHeader(headers, key, val); + } + } else { + const len = opts.headers.length; + if (len % 2 !== 0) { + throw new Error("opts.headers is not a valid header map"); + } + for (let i = 0; i < len; i += 2) { + const key = opts.headers[i]; + const val = opts.headers[i + 1]; + if (typeof key !== "string" || typeof val !== "string" && !Array.isArray(val)) { + throw new Error("opts.headers is not a valid header map"); + } + if (typeof val === "string") { + appendHeader(headers, key, val); + } else { + const mapped = []; + for (let j = 0; j < val.length; j++) { + const v = val[j]; + mapped.push(typeof v === "string" ? v : v.toString("latin1")); + } + appendHeader(headers, key, mapped); + } + } } - const [key, val] = x; - if (typeof key !== "string" || typeof val !== "string") { - throw new Error("opts.headers is not a valid header map"); + } else { + for (const x of opts.headers) { + if (!Array.isArray(x)) { + throw new Error("opts.headers is not a valid header map"); + } + const [key, val] = x; + if (typeof key !== "string" || typeof val !== "string") { + throw new Error("opts.headers is not a valid header map"); + } + appendHeader(headers, key, val); } - headers[key.toLowerCase()] = val; } } else { for (const key of Object.keys(opts.headers)) { - headers[key.toLowerCase()] = opts.headers[key]; + appendHeader(headers, key, opts.headers[key]); } } } else { @@ -45042,25 +45605,32 @@ var require_cache2 = __commonJS({ } function parseCacheControlHeader(header) { const output = {}; - let directives; - if (Array.isArray(header)) { - directives = []; - for (const directive of header) { - directives.push(...directive.split(",")); - } - } else { - directives = header.split(","); - } + const invalidNumericDirectives = /* @__PURE__ */ new Set(); + const invalidNoArgumentDirectives = /* @__PURE__ */ new Set(); + const directives = splitCacheControlHeaderValue(Array.isArray(header) ? header.join(",") : header); for (let i = 0; i < directives.length; i++) { - const directive = directives[i].toLowerCase(); + const directiveRecord = directives[i]; + const directive = directiveRecord.value.toLowerCase(); + const fromMalformedQuote = directiveRecord.fromMalformedQuote; const keyValueDelimiter = directive.indexOf("="); let key; let value; + let keyHasTrailingWhitespace = false; + let valueHasLeadingWhitespace = false; if (keyValueDelimiter !== -1) { - key = directive.substring(0, keyValueDelimiter).trimStart(); - value = directive.substring(keyValueDelimiter + 1); + const rawKey = directive.substring(0, keyValueDelimiter); + const rawValue = directive.substring(keyValueDelimiter + 1); + keyHasTrailingWhitespace = trimOWSEnd(rawKey) !== rawKey; + valueHasLeadingWhitespace = trimOWSStart(rawValue) !== rawValue; + key = trimOWS(rawKey); + value = trimOWSStart(rawValue); } else { - key = directive.trim(); + key = trimOWS(directive); + } + const malformedRestrictiveDirectiveName = getMalformedRestrictiveDirectiveName(key); + if (malformedRestrictiveDirectiveName !== void 0) { + output[malformedRestrictiveDirectiveName] = true; + continue; } switch (key) { case "min-fresh": @@ -45069,48 +45639,85 @@ var require_cache2 = __commonJS({ case "s-maxage": case "stale-while-revalidate": case "stale-if-error": { - if (value === void 0 || value[0] === " ") { + if (fromMalformedQuote || invalidNumericDirectives.has(key)) { + continue; + } + if (value === void 0 || keyHasTrailingWhitespace || valueHasLeadingWhitespace) { + delete output[key]; + invalidNumericDirectives.add(key); + markInvalidCacheControlDirective(output, key); continue; } if (value.length >= 2 && value[0] === '"' && value[value.length - 1] === '"') { value = value.substring(1, value.length - 1); } - const parsedValue = parseInt(value, 10); - if (parsedValue !== parsedValue) { + if (!/^[0-9]+$/.test(value)) { + delete output[key]; + invalidNumericDirectives.add(key); + markInvalidCacheControlDirective(output, key); continue; } - if (key === "max-age" && key in output && output[key] >= parsedValue) { - continue; + const parsedValue = Math.min(parseInt(value, 10), MAX_DELTA_SECONDS); + if (key === "min-fresh") { + if (!(key in output) || output[key] < parsedValue) { + output[key] = parsedValue; + } + } else if (!(key in output) || output[key] > parsedValue) { + output[key] = parsedValue; } - output[key] = parsedValue; break; } case "private": case "no-cache": { + if (fromMalformedQuote) { + output[key] = true; + break; + } + if (value !== void 0 && value.length === 0) { + output[key] = true; + break; + } if (value) { if (value[0] === '"') { - const headers = [value.substring(1)]; - let foundEndingQuote = value[value.length - 1] === '"'; - if (!foundEndingQuote) { + value = trimOWSEnd(value); + let fieldList = ""; + let lastQuotedPart = i; + let foundEndingQuote = false; + const closingQuote = findUnescapedQuote(value, 1); + if (closingQuote !== -1) { + fieldList = value.substring(1, closingQuote); + foundEndingQuote = true; + } else { + const fieldListParts = [value.substring(1)]; for (let j = i + 1; j < directives.length; j++) { - const nextPart = directives[j]; - const nextPartLength = nextPart.length; - headers.push(nextPart.trim()); - if (nextPartLength !== 0 && nextPart[nextPartLength - 1] === '"') { + const nextPart = trimOWS(directives[j].value); + const closingQuote2 = findUnescapedQuote(nextPart, 0); + lastQuotedPart = j; + if (closingQuote2 !== -1) { + fieldListParts.push(nextPart.substring(0, closingQuote2)); foundEndingQuote = true; break; } + fieldListParts.push(nextPart); + } + fieldList = fieldListParts.join(","); + } + if (!foundEndingQuote) { + output[key] = true; + break; + } + i = lastQuotedPart; + const headers = fieldList.split(","); + let validFieldNames = true; + for (let j = 0; j < headers.length; j++) { + headers[j] = trimOWS(headers[j]); + if (!isValidHTTPToken(headers[j])) { + validFieldNames = false; } } - if (foundEndingQuote) { - let lastHeader = headers[headers.length - 1]; - if (lastHeader[lastHeader.length - 1] === '"') { - lastHeader = lastHeader.substring(0, lastHeader.length - 1); - headers[headers.length - 1] = lastHeader; - } - for (let j = 0; j < headers.length; j++) { - headers[j] = headers[j].trim(); - } + if (!validFieldNames) { + output[key] = true; + } else if (output[key] !== true) { if (key in output) { output[key] = output[key].concat(headers); } else { @@ -45118,11 +45725,15 @@ var require_cache2 = __commonJS({ } } } else { - const fieldName = value.trim(); - if (key in output) { - output[key] = output[key].concat(fieldName); - } else { - output[key] = [fieldName]; + const fieldName = trimOWS(value); + if (!isValidHTTPToken(fieldName)) { + output[key] = true; + } else if (output[key] !== true) { + if (key in output) { + output[key] = output[key].concat(fieldName); + } else { + output[key] = [fieldName]; + } } } break; @@ -45130,16 +45741,23 @@ var require_cache2 = __commonJS({ } // eslint-disable-next-line no-fallthrough case "public": - case "no-store": case "must-revalidate": case "proxy-revalidate": case "immutable": case "no-transform": case "must-understand": case "only-if-cached": - if (value) { + if (fromMalformedQuote || invalidNoArgumentDirectives.has(key)) { continue; } + if (value !== void 0) { + delete output[key]; + invalidNoArgumentDirectives.add(key); + continue; + } + output[key] = true; + break; + case "no-store": output[key] = true; break; default: @@ -45148,21 +45766,51 @@ var require_cache2 = __commonJS({ } return output; } + function splitVaryHeader(varyHeader) { + const values = Array.isArray(varyHeader) ? varyHeader : [varyHeader]; + const output = []; + for (let i = 0; i < values.length; i++) { + const parts = values[i].split(","); + for (let j = 0; j < parts.length; j++) { + output.push(parts[j]); + } + } + return output; + } + function hasVaryStar(varyHeader) { + const values = splitVaryHeader(varyHeader); + for (let i = 0; i < values.length; i++) { + if (trimOWS(values[i]).indexOf("*") !== -1) { + return true; + } + } + return false; + } function parseVaryHeader(varyHeader, headers) { - if (typeof varyHeader === "string" && varyHeader.includes("*")) { + if (hasVaryStar(varyHeader)) { return headers; } const output = ( /** @type {Record} */ {} ); - const varyingHeaders = typeof varyHeader === "string" ? varyHeader.split(",") : varyHeader; + const varyingHeaders = splitVaryHeader(varyHeader); for (const header of varyingHeaders) { - const trimmedHeader = header.trim().toLowerCase(); - output[trimmedHeader] = headers[trimmedHeader] ?? null; + const trimmedHeader = trimOWS(header).toLowerCase(); + if (trimmedHeader.length === 0) { + continue; + } + if (!isValidHTTPToken(trimmedHeader)) { + return void 0; + } + const headerValue = headers[trimmedHeader]; + output[trimmedHeader] = Array.isArray(headerValue) ? headerValue.slice() : headerValue ?? null; } return output; } + function isInvalidOrWildcardVaryHeader(varyHeader) { + return hasVaryStar(varyHeader) || parseVaryHeader(varyHeader, {}) === void 0; + } function isEtagUsable(etag) { if (etag.length <= 2) { return false; @@ -45193,7 +45841,7 @@ var require_cache2 = __commonJS({ throw new TypeError(`${name} needs to have at least one method`); } for (const method of methods) { - if (!safeHTTPMethods.includes(method)) { + if (!arrayIncludes(safeHTTPMethods, method)) { throw new TypeError(`element of ${name}-array needs to be one of following values: ${safeHTTPMethods.join(", ")}, got ${method}`); } } @@ -45217,7 +45865,10 @@ var require_cache2 = __commonJS({ assertCacheKey, assertCacheValue, parseCacheControlHeader, + hasInvalidCacheControlDirective, parseVaryHeader, + hasVaryStar, + isInvalidOrWildcardVaryHeader, isEtagUsable, assertCacheMethods, assertCacheStore, @@ -45240,6 +45891,13 @@ var require_date = __commonJS({ return parseRfc850Date(date); } } + function makeDate(year, monthIdx, day, hour, minute, second, weekday) { + const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); + if (year >= 0 && year <= 99) { + result.setUTCFullYear(year); + } + return result.getUTCFullYear() === year && result.getUTCMonth() === monthIdx && result.getUTCDate() === day && result.getUTCHours() === hour && result.getUTCMinutes() === minute && result.getUTCSeconds() === second && result.getUTCDay() === weekday ? result : void 0; + } function parseImfDate(date) { if (date.length !== 29 || date[4] !== " " || date[7] !== " " || date[11] !== " " || date[16] !== " " || date[19] !== ":" || date[22] !== ":" || date[25] !== " " || date[26] !== "G" || date[27] !== "M" || date[28] !== "T") { return void 0; @@ -45400,8 +46058,7 @@ var require_date = __commonJS({ } second = (code1 - 48) * 10 + (code2 - 48); } - const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); - return result.getUTCDay() === weekday ? result : void 0; + return makeDate(year, monthIdx, day, hour, minute, second, weekday); } function parseAscTimeDate(date) { if (date.length !== 24 || date[7] !== " " || date[10] !== " " || date[19] !== " ") { @@ -45563,8 +46220,7 @@ var require_date = __commonJS({ return void 0; } const year = (yearDigit1 - 48) * 1e3 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48); - const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); - return result.getUTCDay() === weekday ? result : void 0; + return makeDate(year, monthIdx, day, hour, minute, second, weekday); } function parseRfc850Date(date) { let commaIndex = -1; @@ -45713,8 +46369,7 @@ var require_date = __commonJS({ } second = (code1 - 48) * 10 + (code2 - 48); } - const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); - return result.getUTCDay() === weekday ? result : void 0; + return makeDate(year, monthIdx, day, hour, minute, second, weekday); } module2.exports = { parseHttpDate @@ -45729,7 +46384,10 @@ var require_cache_handler = __commonJS({ var util7 = require_util9(); var { parseCacheControlHeader, + hasInvalidCacheControlDirective, parseVaryHeader, + hasVaryStar, + isInvalidOrWildcardVaryHeader, isEtagUsable } = require_cache2(); var { parseHttpDate } = require_date(); @@ -45753,6 +46411,79 @@ var require_cache_handler = __commonJS({ 206 ]; var MAX_RESPONSE_AGE = 2147483647e3; + var REVALIDATION_ONLY_RETENTION = 864e5; + function trimOWS(value) { + return value.replace(/^[\t ]+|[\t ]+$/g, ""); + } + function arrayIncludes(array, value) { + for (let i = 0; i < array.length; i++) { + if (array[i] === value) { + return true; + } + } + return false; + } + function appendConnectionHeaderTokens(headersToRemove, connectionHeader) { + const values = Array.isArray(connectionHeader) ? connectionHeader : [connectionHeader]; + for (let i = 0; i < values.length; i++) { + const tokens = values[i].split(","); + for (let j = 0; j < tokens.length; j++) { + headersToRemove.push(trimOWS(tokens[j]).toLowerCase()); + } + } + } + function getSameOriginPath(cacheKey, location) { + if (typeof location !== "string") { + return void 0; + } + let originUrl; + let requestUrl; + let locationUrl; + try { + originUrl = new URL(cacheKey.origin); + requestUrl = new URL(cacheKey.path, originUrl); + locationUrl = new URL(location, requestUrl); + } catch { + return void 0; + } + if (locationUrl.origin !== originUrl.origin) { + return void 0; + } + return locationUrl.pathname + locationUrl.search; + } + function deleteCachedUri(store, cacheKey, path17) { + deleteCachedValue(store, { + ...cacheKey, + path: path17 + }); + for (let i = 0; i < util7.safeHTTPMethods.length; i++) { + const method = util7.safeHTTPMethods[i]; + if (method !== cacheKey.method) { + deleteCachedValue(store, { + ...cacheKey, + method, + path: path17 + }); + } + } + } + function deleteLocationTargets(store, cacheKey, headerValue) { + if (headerValue === void 0) { + return; + } + const values = Array.isArray(headerValue) ? headerValue : [headerValue]; + for (let i = 0; i < values.length; i++) { + const path17 = getSameOriginPath(cacheKey, values[i]); + if (path17 !== void 0) { + deleteCachedUri(store, cacheKey, path17); + } + } + } + function invalidateUnsafeRequest(store, cacheKey, resHeaders) { + deleteCachedUri(store, cacheKey, cacheKey.path); + deleteLocationTargets(store, cacheKey, resHeaders.location); + deleteLocationTargets(store, cacheKey, resHeaders["content-location"]); + } var CacheHandler = class { /** * @type {import('../../types/cache-interceptor.d.ts').default.CacheKey} @@ -45812,35 +46543,51 @@ var require_cache_handler = __commonJS({ statusMessage ); const handler = this; - if (!util7.safeHTTPMethods.includes(this.#cacheKey.method) && statusCode >= 200 && statusCode <= 399) { - try { - this.#store.delete(this.#cacheKey)?.catch?.(noop); - } catch { - } + if (!arrayIncludes(util7.safeHTTPMethods, this.#cacheKey.method) && statusCode >= 200 && statusCode <= 399) { + invalidateUnsafeRequest(this.#store, this.#cacheKey, resHeaders); return downstreamOnHeaders(); } const cacheControlHeader = resHeaders["cache-control"]; - const heuristicallyCacheable = resHeaders["last-modified"] && HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode); + const heuristicallyCacheable = resHeaders["last-modified"] && arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode); if (!cacheControlHeader && !resHeaders["expires"] && !heuristicallyCacheable && !this.#cacheByDefault) { + if (statusCode === 304 && resHeaders.vary && isInvalidOrWildcardVaryHeader(resHeaders.vary)) { + deleteCachedValue(this.#store, this.#cacheKey); + } return downstreamOnHeaders(); } const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { + if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) { + deleteCachedValue(this.#store, this.#cacheKey); + } return downstreamOnHeaders(); } const now = Date.now(); - const resAge = resHeaders.age ? getAge(resHeaders.age) : void 0; - if (resAge && resAge >= MAX_RESPONSE_AGE) { + const resAge = Object.hasOwn(resHeaders, "age") ? getAge(resHeaders.age) : void 0; + if (resAge !== void 0 && resAge >= MAX_RESPONSE_AGE) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); return downstreamOnHeaders(); } - const resDate = typeof resHeaders.date === "string" ? parseHttpDate(resHeaders.date) : void 0; - const staleAt = determineStaleAt(this.#cacheType, now, resAge, resHeaders, resDate, cacheControlDirectives) ?? this.#cacheByDefault; - if (staleAt === void 0 || resAge && resAge > staleAt) { + const resDate = Object.hasOwn(resHeaders, "date") ? getDate(resHeaders.date) : void 0; + if (resDate === null) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); return downstreamOnHeaders(); } - const baseTime = resDate ? resDate.getTime() : now; + const apparentAge = resDate ? Math.max(0, now - resDate.getTime()) : 0; + const currentAge = Math.max(apparentAge, resAge ?? 0); + const hasValidator = typeof resHeaders.etag === "string" && isEtagUsable(resHeaders.etag) || typeof resHeaders["last-modified"] === "string"; + const staleAt = determineStaleAt(this.#cacheType, now, resAge, resHeaders, resDate, cacheControlDirectives, hasValidator) ?? this.#cacheByDefault; + const revalidationOnly = staleAt === 0 && hasValidator; + if (staleAt === void 0 || currentAge >= staleAt && !revalidationOnly) { + if (cacheControlHeader || staleAt !== void 0) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); + } + return downstreamOnHeaders(); + } + const baseTime = now - currentAge; const absoluteStaleAt = staleAt + baseTime; - if (now >= absoluteStaleAt) { + if (now >= absoluteStaleAt && !revalidationOnly) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); return downstreamOnHeaders(); } let varyDirectives; @@ -45850,8 +46597,8 @@ var require_cache_handler = __commonJS({ return downstreamOnHeaders(); } } - const cachedAt = resAge ? now - resAge : now; - const deleteAt = determineDeleteAt(baseTime, cachedAt, cacheControlDirectives, absoluteStaleAt); + const cachedAt = baseTime; + const deleteAt = determineDeleteAt(baseTime, now, cacheControlDirectives, absoluteStaleAt); const strippedHeaders = stripNecessaryHeaders(resHeaders, cacheControlDirectives); const value = { statusCode, @@ -45871,6 +46618,7 @@ var require_cache_handler = __commonJS({ value.statusCode = cachedValue.statusCode; value.statusMessage = cachedValue.statusMessage; value.etag = cachedValue.etag; + value.vary = varyDirectives ?? cachedValue.vary; value.headers = { ...cachedValue.headers, ...strippedHeaders }; downstreamOnHeaders(); this.#writeStream = this.#store.createWriteStream(this.#cacheKey, value); @@ -45961,11 +46709,25 @@ var require_cache_handler = __commonJS({ this.#handler.onResponseError?.(controller, err); } }; + function deleteCachedValue(store, cacheKey) { + try { + store.delete(cacheKey)?.catch?.(noop); + } catch { + } + } + function deleteCachedValueIfNotModified(statusCode, store, cacheKey) { + if (statusCode === 304) { + deleteCachedValue(store, cacheKey); + } + } + function revalidationResponseDisallowsCachedReuse(cacheType, resHeaders, cacheControlDirectives) { + return cacheControlDirectives["no-store"] === true || cacheType === "shared" && cacheControlDirectives.private === true || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); + } function canCacheResponse(cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { - if (statusCode < 200 || NOT_UNDERSTOOD_STATUS_CODES.includes(statusCode)) { + if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) { return false; } - if (!HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode) && !resHeaders["expires"] && !cacheControlDirectives.public && cacheControlDirectives["max-age"] === void 0 && // RFC 9111: a private response directive, if the cache is not shared + if (!arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode) && !resHeaders["expires"] && !cacheControlDirectives.public && cacheControlDirectives["max-age"] === void 0 && // RFC 9111: a private response directive, if the cache is not shared !(cacheControlDirectives.private && cacheType === "private") && !(cacheControlDirectives["s-maxage"] !== void 0 && cacheType === "shared")) { return false; } @@ -45975,60 +46737,104 @@ var require_cache_handler = __commonJS({ if (cacheType === "shared" && cacheControlDirectives.private === true) { return false; } - if (resHeaders.vary?.includes("*")) { + if (resHeaders.vary && hasVaryStar(resHeaders.vary)) { return false; } - if (reqHeaders?.authorization) { + if (reqHeaders != null && Object.hasOwn(reqHeaders, "authorization")) { if (!cacheControlDirectives.public && !cacheControlDirectives["s-maxage"] && !cacheControlDirectives["must-revalidate"]) { return false; } if (typeof reqHeaders.authorization !== "string") { return false; } - if (Array.isArray(cacheControlDirectives["no-cache"]) && cacheControlDirectives["no-cache"].includes("authorization")) { + if (Array.isArray(cacheControlDirectives["no-cache"]) && arrayIncludes(cacheControlDirectives["no-cache"], "authorization")) { return false; } - if (Array.isArray(cacheControlDirectives["private"]) && cacheControlDirectives["private"].includes("authorization")) { + if (Array.isArray(cacheControlDirectives["private"]) && arrayIncludes(cacheControlDirectives["private"], "authorization")) { return false; } } return true; } - function getAge(ageHeader) { - const age = parseInt(Array.isArray(ageHeader) ? ageHeader[0] : ageHeader); - return isNaN(age) ? void 0 : age * 1e3; + function getDate(dateHeader) { + let dateValue = dateHeader; + if (Array.isArray(dateValue)) { + if (dateValue.length !== 1) { + return null; + } + dateValue = dateValue[0]; + } + if (typeof dateValue !== "string") { + return null; + } + return parseHttpDate(dateValue); } - function determineStaleAt(cacheType, now, age, resHeaders, responseDate, cacheControlDirectives) { + function getAge(ageHeader) { + let ageValue = ageHeader; + if (Array.isArray(ageValue)) { + if (ageValue.length !== 1) { + return MAX_RESPONSE_AGE; + } + ageValue = ageValue[0]; + } + if (typeof ageValue !== "string" || !/^[\t ]*[0-9]+[\t ]*$/.test(ageValue)) { + return MAX_RESPONSE_AGE; + } + const age = BigInt(ageValue.replace(/^[\t ]+|[\t ]+$/g, "")); + if (age >= BigInt(MAX_RESPONSE_AGE / 1e3)) { + return MAX_RESPONSE_AGE; + } + return Number(age) * 1e3; + } + function determineStaleAt(cacheType, now, age, resHeaders, responseDate, cacheControlDirectives, hasValidator) { if (cacheType === "shared") { + if (hasInvalidCacheControlDirective(cacheControlDirectives, "s-maxage")) { + return 0; + } const sMaxAge = cacheControlDirectives["s-maxage"]; if (sMaxAge !== void 0) { - return sMaxAge > 0 ? sMaxAge * 1e3 : void 0; + if (sMaxAge > 0) { + return sMaxAge * 1e3; + } + return 0; } } + if (hasInvalidCacheControlDirective(cacheControlDirectives, "max-age")) { + return 0; + } const maxAge = cacheControlDirectives["max-age"]; if (maxAge !== void 0) { - return maxAge > 0 ? maxAge * 1e3 : void 0; - } - if (typeof resHeaders.expires === "string") { - const expiresDate = parseHttpDate(resHeaders.expires); - if (expiresDate) { - if (now >= expiresDate.getTime()) { - return void 0; - } - if (responseDate) { - if (responseDate >= expiresDate) { - return void 0; - } - if (age !== void 0 && age > expiresDate - responseDate) { - return void 0; - } - } - return expiresDate.getTime() - now; + if (maxAge > 0) { + return maxAge * 1e3; } + return 0; + } + if (Object.hasOwn(resHeaders, "expires")) { + if (typeof resHeaders.expires !== "string") { + return 0; + } + const expiresDate = parseHttpDate(resHeaders.expires); + if (!expiresDate) { + return 0; + } + if (now >= expiresDate.getTime()) { + return 0; + } + if (responseDate) { + if (responseDate >= expiresDate) { + return 0; + } + const freshnessLifetime = expiresDate.getTime() - responseDate.getTime(); + if (age !== void 0 && age >= freshnessLifetime) { + return 0; + } + return freshnessLifetime; + } + return expiresDate.getTime() - now; } if (typeof resHeaders["last-modified"] === "string") { - const lastModified = new Date(resHeaders["last-modified"]); - if (isValidDate(lastModified)) { + const lastModified = parseHttpDate(resHeaders["last-modified"]); + if (lastModified) { if (lastModified.getTime() >= now) { return void 0; } @@ -46039,6 +46845,9 @@ var require_cache_handler = __commonJS({ if (cacheControlDirectives.immutable) { return 31536e6; } + if (cacheControlDirectives["no-cache"] === true && hasValidator) { + return 0; + } return void 0; } function determineDeleteAt(baseTime, cachedAt, cacheControlDirectives, staleAt) { @@ -46056,6 +46865,9 @@ var require_cache_handler = __commonJS({ } if (staleWhileRevalidate === -Infinity && staleIfError === -Infinity && immutable === -Infinity) { const freshnessLifetime = staleAt - baseTime; + if (freshnessLifetime <= 0) { + return cachedAt + REVALIDATION_ONLY_RETENTION; + } const datePrecisionPadding = Math.min(Math.max(cachedAt - baseTime, 0), 1e3); return staleAt + freshnessLifetime + datePrecisionPadding; } @@ -46075,11 +46887,7 @@ var require_cache_handler = __commonJS({ "age" ]; if (resHeaders["connection"]) { - if (Array.isArray(resHeaders["connection"])) { - headersToRemove.push(...resHeaders["connection"].map((header) => header.trim())); - } else { - headersToRemove.push(...resHeaders["connection"].split(",").map((header) => header.trim())); - } + appendConnectionHeaderTokens(headersToRemove, resHeaders["connection"]); } if (Array.isArray(cacheControlDirectives["no-cache"])) { headersToRemove.push(...cacheControlDirectives["no-cache"]); @@ -46089,16 +46897,13 @@ var require_cache_handler = __commonJS({ } let strippedHeaders; for (const headerName of headersToRemove) { - if (resHeaders[headerName]) { + if (Object.hasOwn(resHeaders, headerName)) { strippedHeaders ??= { ...resHeaders }; delete strippedHeaders[headerName]; } } return strippedHeaders ?? resHeaders; } - function isValidDate(date) { - return date instanceof Date && Number.isFinite(date.valueOf()); - } module2.exports = CacheHandler; } }); @@ -46269,12 +47074,43 @@ var require_memory_cache_store = __commonJS({ } }; function findEntry(key, entries, now) { - return entries.find((entry) => entry.deleteAt > now && entry.method === key.method && (entry.vary == null || Object.keys(entry.vary).every((headerName) => { - if (entry.vary[headerName] === null) { - return key.headers[headerName] === void 0; + for (let i = 0; i < entries.length; i++) { + const entry = entries[i]; + if (entry.deleteAt > now && entry.method === key.method && varyMatches(key, entry)) { + return entry; } - return entry.vary[headerName] === key.headers[headerName]; - }))); + } + } + function varyMatches(key, entry) { + if (entry.vary == null) { + return true; + } + for (const headerName in entry.vary) { + if (Object.hasOwn(entry.vary, headerName) && !headerValueEquals(key.headers?.[headerName], entry.vary[headerName])) { + return false; + } + } + return true; + } + function headerValueEquals(lhs, rhs) { + if (lhs == null && rhs == null) { + return true; + } + if (lhs == null && rhs != null || lhs != null && rhs == null) { + return false; + } + if (Array.isArray(lhs) && Array.isArray(rhs)) { + if (lhs.length !== rhs.length) { + return false; + } + for (let i = 0; i < lhs.length; i++) { + if (lhs[i] !== rhs[i]) { + return false; + } + } + return true; + } + return lhs === rhs; } module2.exports = MemoryCacheStore; } @@ -46288,7 +47124,7 @@ var require_cache_revalidation_handler = __commonJS({ var CacheRevalidationHandler = class { #successful = false; /** - * @type {((boolean, any) => void) | null} + * @type {((success: boolean, context?: any, statusCode?: number, headers?: import('../../types/header.d.ts').IncomingHttpHeaders) => void) | null} */ #callback; /** @@ -46301,7 +47137,7 @@ var require_cache_revalidation_handler = __commonJS({ */ #allowErrorStatusCodes; /** - * @param {(boolean) => void} callback Function to call if the cached value is valid + * @param {(success: boolean, context?: any, statusCode?: number, headers?: import('../../types/header.d.ts').IncomingHttpHeaders) => void} callback Function to call if the cached value is valid * @param {import('../../types/dispatcher.d.ts').default.DispatchHandlers} handler * @param {boolean} allowErrorStatusCodes */ @@ -46323,7 +47159,7 @@ var require_cache_revalidation_handler = __commonJS({ onResponseStart(controller, statusCode, headers, statusMessage) { assert4(this.#callback != null); this.#successful = statusCode === 304 || this.#allowErrorStatusCodes && statusCode >= 500 && statusCode <= 504; - this.#callback(this.#successful, this.#context); + this.#callback(this.#successful, this.#context, statusCode, headers); this.#callback = null; if (this.#successful) { return true; @@ -46353,6 +47189,12 @@ var require_cache_revalidation_handler = __commonJS({ return; } if (this.#callback) { + if (this.#allowErrorStatusCodes) { + this.#successful = true; + this.#callback(true, this.#context); + this.#callback = null; + return; + } this.#callback(false); this.#callback = null; } @@ -46377,8 +47219,9 @@ var require_cache3 = __commonJS({ var CacheHandler = require_cache_handler(); var MemoryCacheStore = require_memory_cache_store(); var CacheRevalidationHandler = require_cache_revalidation_handler(); - var { assertCacheStore, assertCacheMethods, makeCacheKey, normalizeHeaders, parseCacheControlHeader } = require_cache2(); + var { assertCacheStore, assertCacheMethods, makeCacheKey, normalizeHeaders, parseCacheControlHeader, isInvalidOrWildcardVaryHeader } = require_cache2(); var { AbortError: AbortError3 } = require_errors2(); + var { parseHttpDate } = require_date(); function assertCacheOrigins(origins, name) { if (origins === void 0) return; if (!Array.isArray(origins)) { @@ -46393,6 +47236,37 @@ var require_cache3 = __commonJS({ } var nop = () => { }; + function trimOWS(value) { + return value.replace(/^[\t ]+|[\t ]+$/g, ""); + } + function arrayIncludes(array, value) { + for (let i = 0; i < array.length; i++) { + if (array[i] === value) { + return true; + } + } + return false; + } + function hasPragmaNoCache(headers) { + const pragma = headers?.pragma; + if (!pragma) { + return false; + } + const values = Array.isArray(pragma) ? pragma : [pragma]; + for (let i = 0; i < values.length; i++) { + const value = values[i]; + if (typeof value !== "string") { + continue; + } + const directives = value.split(","); + for (let j = 0; j < directives.length; j++) { + if (trimOWS(directives[j]).toLowerCase() === "no-cache") { + return true; + } + } + } + return false; + } function needsRevalidation(result, cacheControlDirectives, { headers = {} }) { if (cacheControlDirectives?.["no-cache"]) { return true; @@ -46405,10 +47279,58 @@ var require_cache3 = __commonJS({ } return false; } - function isStale(result, cacheControlDirectives) { + function staleResponseRequiresRevalidation(result, cacheType) { + return result.cacheControlDirectives?.["must-revalidate"] === true || cacheType === "shared" && (result.cacheControlDirectives?.["proxy-revalidate"] === true || // https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.2.10 + // s-maxage implies proxy-revalidate for shared caches. + result.cacheControlDirectives?.["s-maxage"] !== void 0); + } + function revalidationResponseDisallowsCachedReuse(cacheType, headers) { + if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) { + return true; + } + const cacheControl = headers["cache-control"]; + if (!cacheControl) { + return false; + } + const cacheControlDirectives = parseCacheControlHeader(cacheControl); + return cacheControlDirectives["no-store"] === true || cacheType === "shared" && cacheControlDirectives.private === true; + } + function revalidationResponseUpdatesCacheControl(headers) { + return headers["cache-control"] !== void 0; + } + function deleteCachedValue(store, cacheKey) { + try { + store.delete(cacheKey)?.catch?.(nop); + } catch { + } + } + function getUsableLastModified(headers) { + const lastModified = headers?.["last-modified"]; + if (typeof lastModified === "string" && parseHttpDate(lastModified)) { + return lastModified; + } + } + function makeRevalidationHeaders(opts, result) { + const headers = { + ...opts.headers, + "if-modified-since": getUsableLastModified(result.headers) ?? new Date(result.cachedAt).toUTCString() + }; + if (result.etag) { + headers["if-none-match"] = result.etag; + } + if (result.vary) { + for (const key in result.vary) { + if (result.vary[key] != null) { + headers[key] = result.vary[key]; + } + } + } + return headers; + } + function isStale(result, cacheControlDirectives, cacheType) { const now = Date.now(); if (now > result.staleAt) { - if (cacheControlDirectives?.["max-stale"]) { + if (!staleResponseRequiresRevalidation(result, cacheType) && cacheControlDirectives?.["max-stale"]) { const gracePeriod = result.staleAt + cacheControlDirectives["max-stale"] * 1e3; return now > gracePeriod; } @@ -46421,9 +47343,9 @@ var require_cache3 = __commonJS({ } return false; } - function withinStaleWhileRevalidateWindow(result) { + function withinStaleWhileRevalidateWindow(result, cacheType) { const staleWhileRevalidate = result.cacheControlDirectives?.["stale-while-revalidate"]; - if (!staleWhileRevalidate) { + if (!staleWhileRevalidate || staleResponseRequiresRevalidation(result, cacheType)) { return false; } const now = Date.now(); @@ -46533,32 +47455,17 @@ var require_cache3 = __commonJS({ return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)); } const age = Math.round((now - result.cachedAt) / 1e3); - if (reqCacheControl?.["max-age"] && age >= reqCacheControl["max-age"]) { - return dispatch(opts, handler); - } - const stale = isStale(result, reqCacheControl); - const revalidate = needsRevalidation(result, reqCacheControl, opts); + const requestMaxAgeExpired = reqCacheControl?.["max-age"] !== void 0 && age >= reqCacheControl["max-age"]; + const stale = requestMaxAgeExpired || isStale(result, reqCacheControl, globalOpts.type); + const revalidate = requestMaxAgeExpired || needsRevalidation(result, reqCacheControl, opts); if (stale || revalidate) { if (util7.isStream(opts.body) && util7.bodyLength(opts.body) !== 0) { return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)); } - if (!revalidate && withinStaleWhileRevalidateWindow(result)) { + if (!revalidate && withinStaleWhileRevalidateWindow(result, globalOpts.type)) { sendCachedValue(handler, opts, result, age, null, true); queueMicrotask(() => { - const headers2 = { - ...opts.headers, - "if-modified-since": new Date(result.cachedAt).toUTCString() - }; - if (result.etag) { - headers2["if-none-match"] = result.etag; - } - if (result.vary) { - for (const key in result.vary) { - if (result.vary[key] != null) { - headers2[key] = result.vary[key]; - } - } - } + const headers2 = makeRevalidationHeaders(opts, result); dispatch( { ...opts, @@ -46584,32 +47491,33 @@ var require_cache3 = __commonJS({ return true; } let withinStaleIfErrorThreshold = false; - const staleIfErrorExpiry = result.cacheControlDirectives["stale-if-error"] ?? reqCacheControl?.["stale-if-error"]; - if (staleIfErrorExpiry) { - withinStaleIfErrorThreshold = now < result.staleAt + staleIfErrorExpiry * 1e3; - } - const headers = { - ...opts.headers, - "if-modified-since": new Date(result.cachedAt).toUTCString() - }; - if (result.etag) { - headers["if-none-match"] = result.etag; - } - if (result.vary) { - for (const key in result.vary) { - if (result.vary[key] != null) { - headers[key] = result.vary[key]; - } + if (!staleResponseRequiresRevalidation(result, globalOpts.type)) { + const staleIfErrorExpiry = result.cacheControlDirectives["stale-if-error"] ?? reqCacheControl?.["stale-if-error"]; + if (staleIfErrorExpiry) { + withinStaleIfErrorThreshold = now < result.staleAt + staleIfErrorExpiry * 1e3; } } + const headers = makeRevalidationHeaders(opts, result); return dispatch( { ...opts, headers }, new CacheRevalidationHandler( - (success, context3) => { + (success, context3, statusCode, headers2) => { if (success) { + if (statusCode === 304) { + if (revalidationResponseDisallowsCachedReuse(globalOpts.type, headers2)) { + if (util7.isStream(result.body)) { + result.body.on("error", nop).destroy(); + } + deleteCachedValue(globalOpts.store, cacheKey); + return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)); + } + if (revalidationResponseUpdatesCacheControl(headers2)) { + deleteCachedValue(globalOpts.store, cacheKey); + } + } sendCachedValue(handler, opts, result, age, context3, stale); } else if (util7.isStream(result.body)) { result.body.on("error", nop).destroy(); @@ -46651,13 +47559,22 @@ var require_cache3 = __commonJS({ cacheByDefault, type }; - const safeMethodsToNotCache = util7.safeHTTPMethods.filter((method) => methods.includes(method) === false); + const safeMethodsToNotCache = []; + for (let i = 0; i < util7.safeHTTPMethods.length; i++) { + const method = util7.safeHTTPMethods[i]; + if (!arrayIncludes(methods, method)) { + safeMethodsToNotCache.push(method); + } + } return (dispatch) => { return (opts2, handler) => { - if (!opts2.origin || safeMethodsToNotCache.includes(opts2.method)) { + if (arrayIncludes(safeMethodsToNotCache, opts2.method)) { return dispatch(opts2, handler); } if (origins !== void 0) { + if (!opts2.origin) { + return dispatch(opts2, handler); + } const requestOrigin = opts2.origin.toString().toLowerCase(); let isAllowed = false; for (let i = 0; i < origins.length; i++) { @@ -46680,7 +47597,7 @@ var require_cache3 = __commonJS({ ...opts2, headers: normalizeHeaders(opts2) }; - const reqCacheControl = opts2.headers?.["cache-control"] ? parseCacheControlHeader(opts2.headers["cache-control"]) : void 0; + const reqCacheControl = opts2.headers?.["cache-control"] ? parseCacheControlHeader(opts2.headers["cache-control"]) : hasPragmaNoCache(opts2.headers) ? { "no-cache": true } : void 0; if (reqCacheControl?.["no-store"]) { return dispatch(opts2, handler); } @@ -46740,6 +47657,8 @@ var require_decompress = __commonJS({ var DecompressHandler = class extends DecoratorHandler { /** @type {Transform[]} */ #decompressors = []; + /** @type {Record | undefined} */ + #trailers; /** @type {Readonly} */ #skipStatusCodes; /** @type {boolean} */ @@ -46815,7 +47734,7 @@ var require_decompress = __commonJS({ const decompressor = this.#decompressors[0]; this.#setupDecompressorEvents(decompressor, controller); decompressor.on("end", () => { - super.onResponseEnd(controller, {}); + super.onResponseEnd(controller, this.#trailers); }); } /** @@ -46831,7 +47750,7 @@ var require_decompress = __commonJS({ super.onResponseError(controller, err); return; } - super.onResponseEnd(controller, {}); + super.onResponseEnd(controller, this.#trailers); }); } /** @@ -46909,6 +47828,7 @@ var require_decompress = __commonJS({ */ onResponseEnd(controller, trailers) { if (this.#decompressors.length > 0) { + this.#trailers = trailers; this.#decompressors[0].end(); this.#cleanupDecompressors(); return; @@ -46940,6 +47860,9 @@ var require_decompress = __commonJS({ } return (dispatch) => { return (opts, handler) => { + if (opts.method === "HEAD") { + return dispatch(opts, handler); + } const decompressHandler = new DecompressHandler(handler, options); return dispatch(opts, decompressHandler); }; @@ -47349,7 +48272,7 @@ var require_deduplicate = __commonJS({ const pendingRequests = /* @__PURE__ */ new Map(); return (dispatch) => { return (opts2, handler) => { - if (!opts2.origin || methods.includes(opts2.method) === false) { + if (opts2.upgrade || methods.includes(opts2.method) === false) { return dispatch(opts2, handler); } opts2 = { @@ -47747,7 +48670,12 @@ var require_sqlite_cache_store = __commonJS({ if (lhs.length !== rhs.length) { return false; } - return lhs.every((x, i) => x === rhs[i]); + for (let i = 0; i < lhs.length; i++) { + if (lhs[i] !== rhs[i]) { + return false; + } + } + return true; } return lhs === rhs; } @@ -48253,9 +49181,7 @@ var require_response2 = __commonJS({ // https://fetch.spec.whatwg.org/#dom-response-json static json(data, init = void 0) { webidl.argumentLengthCheck(arguments, 1, "Response.json"); - if (init !== null) { - init = webidl.converters.ResponseInit(init); - } + init = webidl.converters.ResponseInit(init); const bytes = textEncoder.encode( serializeJavascriptValueToJSONString(data) ); @@ -51474,8 +52400,42 @@ var require_util12 = __commonJS({ } } } + function isLetterOrDigit(code) { + return code >= 48 && code <= 57 || // 0-9 + code >= 65 && code <= 90 || // A-Z + code >= 97 && code <= 122; + } function validateCookieDomain(domain) { - if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { + if (domain === " ") { + return; + } + if (domain.length > 255) { + throw new Error("Invalid cookie domain"); + } + let labelLength = 0; + for (let i = 0; i < domain.length; ++i) { + const code = domain.charCodeAt(i); + if (code === 46) { + if (labelLength === 0) { + throw new Error("Invalid cookie domain"); + } + if (domain.charCodeAt(i - 1) === 45) { + throw new Error("Invalid cookie domain"); + } + labelLength = 0; + continue; + } + if (labelLength === 0 && !isLetterOrDigit(code)) { + throw new Error("Invalid cookie domain"); + } + if (!isLetterOrDigit(code) && code !== 45) { + throw new Error("Invalid cookie domain"); + } + if (++labelLength > 63) { + throw new Error("Invalid cookie domain"); + } + } + if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { throw new Error("Invalid cookie domain"); } } @@ -51558,7 +52518,11 @@ var require_util12 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - out.push(`${key.trim()}=${value.join("=")}`); + const trimmedKey = key.trim(); + const joinedValue = value.join("="); + validateCookieName(trimmedKey); + validateCookieValue(joinedValue); + out.push(`${trimmedKey}=${joinedValue}`); } return out.join("; "); } @@ -53158,6 +54122,8 @@ var require_websocket2 = __commonJS({ var { SendQueue } = require_sender2(); var { WebsocketFrameSend } = require_frame2(); var { channels } = require_diagnostics2(); + var kRef = /* @__PURE__ */ Symbol.for("nodejs.ref"); + var kUnref = /* @__PURE__ */ Symbol.for("nodejs.unref"); function getSocketAddress(socket) { if (typeof socket?.address === "function") { return socket.address(); @@ -53177,6 +54143,7 @@ var require_websocket2 = __commonJS({ #bufferedAmount = 0; #protocol = ""; #extensions = ""; + #refed = true; /** @type {SendQueue} */ #sendQueue; /** @type {Handler} */ @@ -53259,6 +54226,16 @@ var require_websocket2 = __commonJS({ this.#handler.readyState = _WebSocket.CONNECTING; this.#binaryType = "blob"; } + [kRef]() { + webidl.brandCheck(this, _WebSocket); + this.#refed = true; + this.#handler.socket?.ref?.(); + } + [kUnref]() { + webidl.brandCheck(this, _WebSocket); + this.#refed = false; + this.#handler.socket?.unref?.(); + } /** * @see https://websockets.spec.whatwg.org/#dom-websocket-close * @param {number|undefined} code @@ -53420,6 +54397,9 @@ var require_websocket2 = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { this.#handler.socket = response.socket; + if (!this.#refed) { + this.#handler.socket.unref?.(); + } const maxFragments = this.#handler.controller.dispatcher?.webSocketOptions?.maxFragments; const maxPayloadSize = this.#handler.controller.dispatcher?.webSocketOptions?.maxPayloadSize; const parser = new ByteParser(this.#handler, parsedExtensions, { @@ -97862,6 +98842,8 @@ function skipUntil(str, ptr, sep8, end, banNewLines = false) { let c = str[i]; if (c === "#") { i = indexOfNewline(str, i); + if (i < 0) + break; } else if (c === sep8) { return i + 1; } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) { diff --git a/dist/update-known-checksums/index.cjs b/dist/update-known-checksums/index.cjs index 30d8db2..1deaa1a 100644 --- a/dist/update-known-checksums/index.cjs +++ b/dist/update-known-checksums/index.cjs @@ -19803,6 +19803,7 @@ var require_symbols6 = __commonJS({ kCounter: /* @__PURE__ */ Symbol("socket request counter"), kMaxResponseSize: /* @__PURE__ */ Symbol("max response size"), kHTTP2Session: /* @__PURE__ */ Symbol("http2Session"), + kHTTP2Options: /* @__PURE__ */ Symbol("http2 options"), kHTTP2SessionState: /* @__PURE__ */ Symbol("http2Session state"), kRetryHandlerDefaultRetry: /* @__PURE__ */ Symbol("retry agent default retry"), kConstruct: /* @__PURE__ */ Symbol("constructable"), @@ -20929,7 +20930,10 @@ var require_util9 = __commonJS({ if (Object.getPrototypeOf(stream2).constructor === IncomingMessage) { stream2.socket = null; } - stream2.destroy(err); + try { + stream2.destroy(err); + } catch { + } } else if (err) { queueMicrotask(() => { stream2.emit("error", err); @@ -21990,7 +21994,7 @@ var require_request3 = __commonJS({ this.headersTimeout = headersTimeout; this.bodyTimeout = bodyTimeout; this.method = method; - this.typeOfService = typeOfService ?? 0; + this.typeOfService = typeOfService; this.abort = null; if (body == null) { this.body = null; @@ -22224,7 +22228,11 @@ var require_request3 = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - arr.push(`${val[i]}`); + const str = `${val[i]}`; + if (!isValidHeaderValue(str)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } + arr.push(str); } } val = arr; @@ -22236,6 +22244,9 @@ var require_request3 = __commonJS({ val = ""; } else { val = `${val}`; + if (!isValidHeaderValue(val)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } } if (headerName === "host") { if (request.host !== null) { @@ -22561,14 +22572,26 @@ var require_connect2 = __commonJS({ } else { assert(!httpSocket, "httpSocket can only be sent on TLS update"); port = port || 80; - socket = net.connect({ + const connectOptions = { highWaterMark: 64 * 1024, // Same as nodejs fs streams. ...options, localAddress, port, host: hostname - }); + }; + const family = net.isIP(hostname); + if (family !== 0 && servername && servername !== hostname) { + connectOptions.host = servername; + connectOptions.lookup = (_hostname, lookupOptions, cb) => { + if (lookupOptions.all) { + cb(null, [{ address: hostname, family }]); + } else { + cb(null, hostname, family); + } + }; + } + socket = net.connect(connectOptions); if (useH2c === true) { socket.alpnProtocol = "h2"; } @@ -25925,6 +25948,7 @@ var require_body2 = __commonJS({ var { multipartFormDataParser } = require_formdata_parser2(); var { parseJSONFromBytes } = require_infra(); var { utf8DecodeBytes } = require_encoding2(); + var { ReadableStreamTee } = require("node:stream/web"); var textEncoder = new TextEncoder(); function noop() { } @@ -26067,7 +26091,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r return extractBody(object, keepalive); } function cloneBody(body) { - const { 0: out1, 1: out2 } = body.stream.tee(); + const { 0: out1, 1: out2 } = ReadableStreamTee?.(body.stream, true) ?? body.stream.tee(); body.stream = out1; return { stream: out2, @@ -26220,6 +26244,7 @@ var require_client_h12 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, + InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -26269,6 +26294,7 @@ var require_client_h12 = __commonJS({ var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); + var kTypeOfService = /* @__PURE__ */ Symbol("kTypeOfService"); var extractBody; function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm2() : void 0; @@ -27072,6 +27098,24 @@ var require_client_h12 = __commonJS({ function shouldSendContentLength(method) { return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; } + function setTypeOfService(socket, request) { + if (typeof socket.setTypeOfService !== "function") { + return; + } + const typeOfService = request.typeOfService; + if (typeOfService === void 0) { + return; + } + const currentTypeOfService = socket[kTypeOfService]; + if (currentTypeOfService === typeOfService) { + return; + } + try { + socket.setTypeOfService(typeOfService); + socket[kTypeOfService] = typeOfService; + } catch { + } + } function writeH1(client, request) { const { method, path, host, upgrade, blocking, reset } = request; let { body, headers, contentLength } = request; @@ -27086,8 +27130,16 @@ var require_client_h12 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request.contentType == null && body.type) { - headers.push("content-type", body.type); + } else if (util.isBlobLike(body) && request.contentType == null) { + const contentType = body.type; + if (contentType) { + const contentTypeValue = `${contentType}`; + if (!util.isValidHeaderValue(contentTypeValue)) { + util.errorRequest(client, request, new InvalidArgumentError("invalid content-type header")); + return false; + } + headers.push("content-type", contentTypeValue); + } } if (body && typeof body.read === "function") { body.read(0); @@ -27140,9 +27192,7 @@ var require_client_h12 = __commonJS({ if (blocking) { socket[kBlocking] = true; } - if (socket.setTypeOfService) { - socket.setTypeOfService(request.typeOfService); - } + setTypeOfService(socket, request); let header = `${method} ${path} HTTP/1.1\r `; if (typeof host === "string") { @@ -27518,10 +27568,7 @@ var require_client_h22 = __commonJS({ kStrictContentLength, kOnError, kMaxConcurrentStreams, - kPingInterval, kHTTP2Session, - kHTTP2InitialWindowSize, - kHTTP2ConnectionWindowSize, kHostAuthority, kResume, kSize, @@ -27533,7 +27580,8 @@ var require_client_h22 = __commonJS({ kEnableConnectProtocol, kRemoteSettings, kHTTP2Stream, - kHTTP2SessionState + kHTTP2SessionState, + kHTTP2Options } = require_symbols6(); var { channels } = require_diagnostics2(); var kOpenStreams = /* @__PURE__ */ Symbol("open streams"); @@ -27542,6 +27590,9 @@ var require_client_h22 = __commonJS({ var kRequestStreamCleanup = /* @__PURE__ */ Symbol("request stream cleanup"); var kRequestStreamState = /* @__PURE__ */ Symbol("request stream state"); var kReceivedGoAway = /* @__PURE__ */ Symbol("received goaway"); + var kGoAwayReplayAttempts = /* @__PURE__ */ Symbol("goaway replay attempts"); + var kRefusedStreamRetry = /* @__PURE__ */ Symbol("refused stream retry"); + var MAX_GOAWAY_REPLAY_ATTEMPTS = 1; var extractBody; var http2; try { @@ -27625,6 +27676,7 @@ var require_client_h22 = __commonJS({ const queue = client[kQueue]; const runningIdx = client[kRunningIdx]; if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request) { + queue[runningIdx] = null; client[kRunningIdx] = runningIdx + 1; return; } @@ -27638,10 +27690,15 @@ var require_client_h22 = __commonJS({ client[kPendingIdx] = client[kRunningIdx]; } } - function canRetryRequestAfterGoAway(request) { + function canReplayRequest(request) { const { body } = request; return body == null || util.isBuffer(body) || util.isBlobLike(body); } + function registerGoAwayRefusal(request) { + const attempts = (request[kGoAwayReplayAttempts] ?? 0) + 1; + request[kGoAwayReplayAttempts] = attempts; + return attempts <= MAX_GOAWAY_REPLAY_ATTEMPTS; + } function closeStream(stream, code = NGHTTP2_REFUSED_STREAM) { if (stream != null && !stream.destroyed && !stream.closed) { try { @@ -27653,15 +27710,30 @@ var require_client_h22 = __commonJS({ function detachRequestStreamForClose(request) { const stream = request[kRequestStream]; clearRequestStream(request); + severRequestStream(stream); return stream; } + function severRequestStream(stream) { + if (stream == null || stream[kRequestStreamState] == null) { + return; + } + stream[kRequestStreamState] = null; + stream.off("close", completeRequestStream); + stream.off("close", onUpgradeStreamClose); + if (stream[kHTTP2Session] != null) { + closeStreamSession(stream); + } + if (!stream.destroyed && !stream.closed) { + stream.once("error", noop); + } + } function connectH2(client, socket) { client[kSocket] = socket; - const http2InitialWindowSize = client[kHTTP2InitialWindowSize]; - const http2ConnectionWindowSize = client[kHTTP2ConnectionWindowSize]; + const http2InitialWindowSize = client[kHTTP2Options].sessionOptions?.initialWindowSize; + const http2ConnectionWindowSize = client[kHTTP2Options].connectionWindowSize; const session = http2.connect(client[kUrl], { createConnection: () => socket, - peerMaxConcurrentStreams: client[kMaxConcurrentStreams], + peerMaxConcurrentStreams: client[kHTTP2Options].maxConcurrentStreams, settings: { // TODO(metcoder95): add support for PUSH enablePush: false, @@ -27674,13 +27746,16 @@ var require_client_h22 = __commonJS({ session[kSocket] = socket; session[kHTTP2SessionState] = { idleTimeout: null, + // Armed while the peer advertises MAX_CONCURRENT_STREAMS = 0 and we have + // work that cannot start. See setNoStreamsTimeout. + noStreamsTimeout: null, // Sockets start out ref'd. Session ref/unref proxies to the socket, so a // single cached flag lets us skip redundant uv ref/unref calls, provided // every ref/unref of the session or its socket goes through // refH2Session/unrefH2Session. refed: true, ping: { - interval: client[kPingInterval] === 0 ? null : setInterval(onHttp2SendPing, client[kPingInterval], session).unref() + interval: client[kHTTP2Options].pingInterval === 0 ? null : setInterval(onHttp2SendPing, client[kHTTP2Options].pingInterval, session).unref() } }; session[kReceivedGoAway] = false; @@ -27691,7 +27766,6 @@ var require_client_h22 = __commonJS({ } util.addListener(session, "error", onHttp2SessionError); util.addListener(session, "frameError", onHttp2FrameError); - util.addListener(session, "end", onHttp2SessionEnd); util.addListener(session, "goaway", onHttp2SessionGoAway); util.addListener(session, "close", onHttp2SessionClose); util.addListener(session, "remoteSettings", onHttp2RemoteSettings); @@ -27750,7 +27824,6 @@ var require_client_h22 = __commonJS({ if (request != null) { if (client[kRunning] > 0) { if ((request.upgrade === "websocket" || request.method === "CONNECT") && session[kRemoteSettings] === false) return true; - if (util.bodyLength(request.body) !== 0 && (util.isStream(request.body) || util.isAsyncIterable(request.body) || util.isFormDataLike(request.body))) return true; } else { return (request.upgrade === "websocket" || request.method === "CONNECT") && session[kRemoteSettings] === false; } @@ -27787,8 +27860,48 @@ var require_client_h22 = __commonJS({ } else { clearHttp2IdleTimeout(session); } + if (client[kMaxConcurrentStreams] === 0 && client[kRunning] === 0 && client[kPending] > 0) { + setNoStreamsTimeout(session); + } else { + clearNoStreamsTimeout(session); + } } } + function clearNoStreamsTimeout(session) { + const state = session[kHTTP2SessionState]; + if (state?.noStreamsTimeout != null) { + clearTimeout(state.noStreamsTimeout); + state.noStreamsTimeout = null; + } + } + function setNoStreamsTimeout(session) { + const client = session[kClient]; + const state = session[kHTTP2SessionState]; + const timeout = client[kHeadersTimeout]; + if (!timeout || state.noStreamsTimeout != null) { + return; + } + state.noStreamsTimeout = setTimeout(onNoStreamsTimeout, timeout, session).unref(); + } + function onNoStreamsTimeout(session) { + const client = session[kClient]; + const state = session[kHTTP2SessionState]; + state.noStreamsTimeout = null; + if (client[kHTTP2Session] !== session || client[kMaxConcurrentStreams] !== 0 || client[kRunning] !== 0 || client[kPending] === 0) { + return; + } + const err = new HeadersTimeoutError( + `HTTP/2: server did not accept a new stream within ${client[kHeadersTimeout]}` + ); + const requests = client[kQueue].splice(client[kPendingIdx]); + for (let i = 0; i < requests.length; i++) { + if (requests[i] != null) { + util.errorRequest(client, requests[i], err); + } + } + session[kError] = err; + resetHttp2Session(session, err); + } function clearHttp2IdleTimeout(session) { const state = session[kHTTP2SessionState]; if (state?.idleTimeout != null) { @@ -27880,11 +27993,6 @@ var require_client_h22 = __commonJS({ this[kClient][kOnError](err); } } - function onHttp2SessionEnd() { - const err = new SocketError("other side closed", util.getSocketInfo(this[kSocket])); - this.destroy(err); - util.destroy(this[kSocket], err); - } function onHttp2SessionGoAway(errorCode, lastStreamID) { if (this[kReceivedGoAway]) { return; @@ -27900,7 +28008,7 @@ var require_client_h22 = __commonJS({ const request = client[kQueue][i]; if (request != null) { streamsToClose.push(detachRequestStreamForClose(request)); - if (canRetryRequestAfterGoAway(request)) { + if (canReplayRequest(request) && registerGoAwayRefusal(request)) { retriableRequests.push(request); } else { util.errorRequest(client, request, err); @@ -27921,6 +28029,7 @@ var require_client_h22 = __commonJS({ client[kHTTP2Session] = null; } clearHttp2IdleTimeout(this); + clearNoStreamsTimeout(this); if (!this.closed && !this.destroyed) { this.close(); } @@ -27937,6 +28046,7 @@ var require_client_h22 = __commonJS({ client[kHTTP2Session] = null; } clearHttp2IdleTimeout(this); + clearNoStreamsTimeout(this); if (state.ping.interval != null) { clearInterval(state.ping.interval); state.ping.interval = null; @@ -27978,7 +28088,7 @@ var require_client_h22 = __commonJS({ if (this[kHTTP2Session]?.[kReceivedGoAway]) { return; } - this[kClient][kOnError](err); + this[kHTTP2Session]?.[kClient]?.[kOnError](err); } function onHttp2SocketEnd() { util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -28004,15 +28114,22 @@ var require_client_h22 = __commonJS({ failUpgradeStream(state, new InformationalError("HTTP/2: stream closed before response headers")); closeStreamSession(this); } - function onRequestStreamClose() { + function completeRequestStream() { const state = this[kRequestStreamState]; - if (state) { - releaseRequestStream(this); - if (state.pendingEnd && !state.request.aborted && !state.request.completed) { - state.request.onResponseEnd(state.trailers || {}); - finalizeRequest(state); - } + if (state == null) { + return; } + releaseRequestStream(this); + if (state.pendingEnd && !state.request.aborted && !state.request.completed) { + state.request.onResponseEnd(state.trailers || {}); + } else if (!state.request.aborted && !state.request.completed) { + util.errorRequest( + state.client, + state.request, + new InformationalError("HTTP/2: stream closed before the response was complete") + ); + } + finalizeRequest(state); closeStreamSession(this); this[kRequestStreamState] = null; } @@ -28192,11 +28309,9 @@ var require_client_h22 = __commonJS({ clearRequestStream(request); const stream2 = state.stream; stream2.close(); - setImmediate(() => { - if (!stream2.destroyed) { - util.destroy(stream2); - } - }); + if (!stream2.destroyed) { + util.destroy(stream2); + } client[kOnError](err); finalizeRequest(state, resetPendingIdx); } @@ -28305,7 +28420,7 @@ var require_client_h22 = __commonJS({ stream.setTimeout(headersTimeout); } stream[kHTTP2Session] = session; - stream.on("close", onRequestStreamClose); + stream.on("close", completeRequestStream); bindRequestToStream(request, stream, releaseRequestStream); if (expectContinue) { stream.once("continue", writeBodyH2); @@ -28406,11 +28521,26 @@ var require_client_h22 = __commonJS({ if (state.responseReceived) { if (!request.aborted && !request.completed) { state.pendingEnd = true; + completeRequestStream.call(stream); } } else { state.abort(new InformationalError("HTTP/2: stream half-closed (remote)"), true); } } + function retryRefusedStream(stream, state) { + const { client, request } = state; + if (state.responseReceived || request.aborted || request.completed || request[kRefusedStreamRetry] || !canReplayRequest(request)) { + return false; + } + request[kRefusedStreamRetry] = true; + detachRequestStreamForClose(request); + state.stream = null; + state.requestFinalized = true; + completeRequest(client, request); + client[kQueue].splice(client[kPendingIdx], 0, request); + client[kResume](); + return true; + } function onError(err) { const stream = this; const state = stream[kRequestStreamState]; @@ -28418,6 +28548,12 @@ var require_client_h22 = __commonJS({ return; } stream.off("error", onError); + if (typeof stream.rstCode === "number" && stream.rstCode !== NGHTTP2_NO_ERROR) { + err.http2ErrorCode = stream.rstCode; + } + if (stream.rstCode === NGHTTP2_REFUSED_STREAM && retryRefusedStream(stream, state)) { + return; + } state.abort(err); } function onFrameError(type, code) { @@ -28699,10 +28835,8 @@ var require_client2 = __commonJS({ kHTTPContext, kMaxConcurrentStreams, kHostAuthority, - kHTTP2InitialWindowSize, - kHTTP2ConnectionWindowSize, kResume, - kPingInterval + kHTTP2Options } = require_symbols6(); var connectH1 = require_client_h12(); var connectH2 = require_client_h22(); @@ -28715,6 +28849,14 @@ var require_client2 = __commonJS({ function getPipelining(client) { return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1; } + var h2NamespaceOptsWarning = false; + function emitH2OptionsNamespaceWarning(optName) { + if (h2NamespaceOptsWarning === true) return; + process.emitWarning(`Use h2Options.${optName} instead. ${optName} for H2 will be deprecated in future major.`, { + code: "UNDICI-H2-OPTIONS" + }); + h2NamespaceOptsWarning = true; + } function getMaxConcurrent(client) { if (client[kHTTPContext]?.version === "h2") { return client[kMaxConcurrentStreams]; @@ -28758,7 +28900,8 @@ var require_client2 = __commonJS({ initialWindowSize, connectionWindowSize, pingInterval, - webSocket + webSocket, + h2Options } = {}) { if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); @@ -28821,20 +28964,45 @@ var require_client2 = __commonJS({ if (allowH2 != null && typeof allowH2 !== "boolean") { throw new InvalidArgumentError("allowH2 must be a valid boolean value"); } - if (maxConcurrentStreams != null && (typeof maxConcurrentStreams !== "number" || maxConcurrentStreams < 1)) { - throw new InvalidArgumentError("maxConcurrentStreams must be a positive integer, greater than 0"); - } - if (useH2c != null && typeof useH2c !== "boolean") { - throw new InvalidArgumentError("useH2c must be a valid boolean value"); - } - if (initialWindowSize != null && (!Number.isInteger(initialWindowSize) || initialWindowSize < 1)) { - throw new InvalidArgumentError("initialWindowSize must be a positive integer, greater than 0"); - } - if (connectionWindowSize != null && (!Number.isInteger(connectionWindowSize) || connectionWindowSize < 1)) { - throw new InvalidArgumentError("connectionWindowSize must be a positive integer, greater than 0"); - } - if (pingInterval != null && (typeof pingInterval !== "number" || !Number.isInteger(pingInterval) || pingInterval < 0)) { - throw new InvalidArgumentError("pingInterval must be a positive integer, greater or equal to 0"); + if (allowH2 !== false) { + if (h2Options != null) { + if (h2Options.useH2c != null && typeof h2Options.useH2c !== "boolean") { + throw new InvalidArgumentError("h2Options.useH2c must be a valid boolean value"); + } + if (h2Options.settings?.initialWindowSize != null && (!Number.isInteger(h2Options.settings.initialWindowSize) || h2Options.settings.initialWindowSize < 1)) { + throw new InvalidArgumentError("h2Options.settings.initialWindowSize must be a positive integer, greater than 0"); + } + if (h2Options.maxConcurrentStreams != null && (!Number.isInteger(h2Options.connectionWindowSize) || h2Options.maxConcurrentStreams < 1)) { + throw new InvalidArgumentError("h2Options.maxConcurrentStreams must be a positive integer, greater than 0"); + } + if (h2Options.connectionWindowSize != null && (!Number.isInteger(h2Options.connectionWindowSize) || h2Options.connectionWindowSize < 1)) { + throw new InvalidArgumentError("h2Options.connectionWindowSize must be a positive integer, greater than 0"); + } + if (h2Options.pingInterval != null && (typeof h2Options.pingInterval !== "number" || !Number.isInteger(h2Options.pingInterval) || h2Options.pingInterval < 0)) { + throw new InvalidArgumentError("h2Options.pingInterval must be a positive integer, greater or equal to 0"); + } + } else { + if (useH2c != null && typeof useH2c !== "boolean") { + emitH2OptionsNamespaceWarning("useH2c"); + throw new InvalidArgumentError("useH2c must be a valid boolean value"); + } + if (maxConcurrentStreams != null && (typeof maxConcurrentStreams !== "number" || maxConcurrentStreams < 1)) { + emitH2OptionsNamespaceWarning("maxConcurrentStreams"); + throw new InvalidArgumentError("maxConcurrentStreams must be a positive integer, greater than 0"); + } + if (initialWindowSize != null && (!Number.isInteger(initialWindowSize) || initialWindowSize < 1)) { + emitH2OptionsNamespaceWarning("initialWindowSize"); + throw new InvalidArgumentError("initialWindowSize must be a positive integer, greater than 0"); + } + if (connectionWindowSize != null && (!Number.isInteger(connectionWindowSize) || connectionWindowSize < 1)) { + emitH2OptionsNamespaceWarning("connectionWindowSize"); + throw new InvalidArgumentError("connectionWindowSize must be a positive integer, greater than 0"); + } + if (pingInterval != null && (typeof pingInterval !== "number" || !Number.isInteger(pingInterval) || pingInterval < 0)) { + emitH2OptionsNamespaceWarning("pingInterval"); + throw new InvalidArgumentError("pingInterval must be a positive integer, greater or equal to 0"); + } + } } super({ webSocket }); if (typeof connect2 !== "function") { @@ -28842,8 +29010,8 @@ var require_client2 = __commonJS({ ...tls, maxCachedSessions, allowH2, - useH2c, socketPath, + useH2c: h2Options?.useH2c ?? useH2c, timeout: connectTimeout, ...typeof autoSelectFamily === "boolean" ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : void 0, ...connect2 @@ -28878,10 +29046,21 @@ var require_client2 = __commonJS({ this[kClosedResolve] = null; this[kMaxResponseSize] = maxResponseSize > -1 ? maxResponseSize : -1; this[kHTTPContext] = null; - this[kMaxConcurrentStreams] = maxConcurrentStreams != null ? maxConcurrentStreams : 100; - this[kHTTP2InitialWindowSize] = initialWindowSize != null ? initialWindowSize : 262144; - this[kHTTP2ConnectionWindowSize] = connectionWindowSize != null ? connectionWindowSize : 524288; - this[kPingInterval] = pingInterval != null ? pingInterval : 6e4; + this[kHTTP2Options] = { + pingInterval: h2Options?.pingInterval ?? pingInterval ?? 6e4, + connectionWindowSize: h2Options?.connectionWindowSize ?? connectionWindowSize ?? 524288, + maxConcurrentStreams: h2Options?.maxConcurrentStreams ?? maxConcurrentStreams ?? 100, + // Max peerConcurrentStreams for a Node h2 server + sessionOptions: { + // HTTP/2 window sizes are set to higher defaults than Node.js core for better performance: + // - initialWindowSize: 262144 (256KB) vs Node.js default 65535 (64KB - 1) + // Allows more data to be sent before requiring acknowledgment, improving throughput + // especially on high-latency networks. This matches common production HTTP/2 servers. + // - connectionWindowSize: 524288 (512KB) vs Node.js default (none set) + // Provides better flow control for the entire connection across multiple streams. + initialWindowSize: h2Options?.initialWindowSize ?? initialWindowSize ?? 262144 + } + }; this[kQueue] = []; this[kRunningIdx] = 0; this[kPendingIdx] = 0; @@ -29166,6 +29345,7 @@ var require_client2 = __commonJS({ return; } if (!client[kHTTPContext]) { + client[kServerName] = request.servername; connect(client); return; } @@ -29936,14 +30116,14 @@ var require_agent2 = __commonJS({ dispatcher.close(); } let hasOrigin = false; - for (const client of this[kClients].values()) { - if (client[kUrl].origin === dispatcher[kUrl].origin) { + for (const k of this[kClients].keys()) { + if (k === origin || k === `${origin}#http1-only`) { hasOrigin = true; break; } } if (!hasOrigin) { - this[kOrigins].delete(dispatcher[kUrl].origin); + this[kOrigins].delete(origin); } }; dispatcher.on("drain", this[kOnDrain]).on("connect", this[kOnConnect]).on("disconnect", (origin2, targets, err) => { @@ -30576,7 +30756,7 @@ var require_socks5_proxy_agent = __commonJS({ var DispatcherBase = require_dispatcher_base2(); var { InvalidArgumentError } = require_errors2(); var { Socks5Client, STATES } = require_socks5_client(); - var { kDispatch, kClose, kDestroy } = require_symbols6(); + var { kBusy, kConnected, kDispatch, kClose, kDestroy } = require_symbols6(); var Pool = require_pool2(); var buildConnector = require_connect2(); var { debuglog } = require("node:util"); @@ -30734,6 +30914,17 @@ var require_socks5_proxy_agent = __commonJS({ } }); this[kPools].set(originKey, pool); + const closePoolIfUnused = () => { + if (this[kPools].get(originKey) !== pool || pool[kConnected] > 0 || pool[kBusy]) { + return; + } + this[kPools].delete(originKey); + if (!pool.destroyed) { + pool.close(); + } + }; + pool.on("disconnect", closePoolIfUnused); + pool.on("connectionError", closePoolIfUnused); } return pool[kDispatch](opts, handler); } catch (err) { @@ -31118,7 +31309,7 @@ var require_env_http_proxy_agent2 = __commonJS({ } #getProxyAgentForUrl(url) { let { protocol, host: hostname, port } = url; - hostname = hostname.replace(/:\d*$/, "").toLowerCase(); + hostname = hostname.replace(/:\d*$/, "").replace(/^\[(.+)\]$/, "$1").toLowerCase(); port = Number.parseInt(port, 10) || DEFAULT_PORTS[protocol] || 0; if (!this.#shouldProxy(hostname, port)) { return this[kNoProxyAgent]; @@ -31161,11 +31352,22 @@ var require_env_http_proxy_agent2 = __commonJS({ if (!entry) { continue; } - const parsed = entry.match(/^(.+):(\d+)$/); + let hostname, port; + const ipv6WithPort = entry.match(/^\[(.+)\]:(\d+)$/); + if (ipv6WithPort) { + hostname = ipv6WithPort[1]; + port = Number.parseInt(ipv6WithPort[2], 10); + } else { + const unbracketed = entry.replace(/^\[(.+)\]$/, "$1"); + const colonCount = (unbracketed.match(/:/g) || []).length; + const parsed = colonCount === 1 && unbracketed.match(/^(.+):(\d+)$/); + hostname = parsed ? parsed[1] : unbracketed; + port = parsed ? Number.parseInt(parsed[2], 10) : 0; + } noProxyEntries.push({ // strip leading dot or asterisk with dot - hostname: (parsed ? parsed[1] : entry).replace(/^\*?\./, "").toLowerCase(), - port: parsed ? Number.parseInt(parsed[2], 10) : 0 + hostname: hostname.replace(/^\*?\./, "").toLowerCase(), + port }); } this.#noProxyValue = noProxyValue; @@ -31199,7 +31401,24 @@ var require_retry_handler2 = __commonJS({ } = require_util9(); function calculateRetryAfterHeader(retryAfter) { const retryTime = new Date(retryAfter).getTime(); - return isNaN(retryTime) ? 0 : retryTime - Date.now(); + return isNaN(retryTime) ? null : retryTime - Date.now(); + } + function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { + const contentLength = headers["content-length"]; + if (contentLength == null) { + return; + } + if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { + return; + } + const length = Number(contentLength); + const expectedLength = range.end - range.start + 1; + if (!Number.isFinite(length) || length !== expectedLength) { + throw new RequestRetryError("Content-Length mismatch", statusCode, { + headers, + data: { count: retryCount } + }); + } } var RetryController = class { constructor() { @@ -31366,10 +31585,14 @@ var require_retry_handler2 = __commonJS({ retryAfterHeader = Number(retryAfterHeader); retryAfterHeader = Number.isNaN(retryAfterHeader) ? calculateRetryAfterHeader(headers["retry-after"]) : retryAfterHeader * 1e3; } - const retryTimeout = retryAfterHeader > 0 ? Math.min(retryAfterHeader, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout); + const retryTimeout = retryAfterHeader === 0 ? 0 : retryAfterHeader > 0 ? Math.min(retryAfterHeader, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout); setTimeout(() => cb(null), retryTimeout); } onResponseStart(controller, statusCode, headers, statusMessage) { + if (statusCode < 200) { + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + return; + } this.error = null; this.retryCount += 1; this.statusCode = statusCode; @@ -31404,6 +31627,7 @@ var require_retry_handler2 = __commonJS({ data: { count: this.retryCount } }); } + validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); const { start, size, end = size ? size - 1 : null } = contentRange; assert(this.start === start, "content-range mismatch"); assert(this.end == null || this.end === end, "content-range mismatch"); @@ -31412,7 +31636,7 @@ var require_retry_handler2 = __commonJS({ if (this.end == null) { if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); - if (range == null) { + if (range == null || range.end == null) { this.headersSent = true; this.handler.onResponseStart?.( this.controllerProxy, @@ -31422,6 +31646,7 @@ var require_retry_handler2 = __commonJS({ ); return; } + validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); const { start, size, end = size ? size - 1 : null } = range; assert( start != null && Number.isFinite(start), @@ -31431,7 +31656,7 @@ var require_retry_handler2 = __commonJS({ this.start = start; this.end = end; } - if (this.end == null) { + if (this.end == null && this.opts.method !== "HEAD") { const contentLength = headers["content-length"]; this.end = contentLength != null ? Number(contentLength) - 1 : null; } @@ -31632,7 +31857,6 @@ var require_readable2 = __commonJS({ var kContentLength = /* @__PURE__ */ Symbol("kContentLength"); var kUsed = /* @__PURE__ */ Symbol("kUsed"); var kBytesRead = /* @__PURE__ */ Symbol("kBytesRead"); - var kPreservedBuffer = /* @__PURE__ */ Symbol("kPreservedBuffer"); var noop = () => { }; var BodyReadable = class extends Readable2 { @@ -31871,21 +32095,6 @@ var require_readable2 = __commonJS({ */ setEncoding(encoding) { if (Buffer.isEncoding(encoding)) { - const state = this._readableState; - const buffer = state.buffer; - if (buffer && state.length > 0) { - const bufferIndex = state.bufferIndex ?? 0; - const preserved = []; - const source = typeof buffer.slice === "function" ? buffer.slice(bufferIndex) : buffer; - for (const data of source) { - if (Buffer.isBuffer(data)) { - preserved.push(data); - } - } - if (preserved.length > 0) { - this[kPreservedBuffer] = (this[kPreservedBuffer] || []).concat(preserved); - } - } super.setEncoding(encoding); } return this; @@ -31936,13 +32145,7 @@ var require_readable2 = __commonJS({ return; } const { _readableState: state } = consume2.stream; - const preserved = consume2.stream[kPreservedBuffer]; - if (preserved && preserved.length > 0) { - for (const chunk of preserved) { - consumePush(consume2, chunk); - } - consume2.stream[kPreservedBuffer] = null; - } else if (state.bufferIndex) { + if (state.bufferIndex) { const start = state.bufferIndex; const end = state.buffer.length; for (let n = start; n < end; n++) { @@ -31953,13 +32156,17 @@ var require_readable2 = __commonJS({ consumePush(consume2, chunk); } } - if (state.endEmitted) { - consumeEnd(this[kConsume], this._readableState.encoding); - } else { - consume2.stream.on("end", function() { - consumeEnd(this[kConsume], this._readableState.encoding); - }); + const decoder = state.decoder; + if (decoder != null && decoder.lastNeed > 0) { + consumePush(consume2, Buffer.from(decoder.lastChar.subarray(0, decoder.lastTotal - decoder.lastNeed))); } + if (state.endEmitted) { + consumeEnd(consume2, state.encoding); + return; + } + consume2.stream.on("end", function() { + consumeEnd(this[kConsume], this._readableState.encoding); + }); consume2.stream.resume(); while (consume2.stream.read() != null) { } @@ -32016,6 +32223,9 @@ var require_readable2 = __commonJS({ if (consume2.body === null) { return; } + if (typeof chunk === "string") { + chunk = Buffer.from(chunk, consume2.stream._readableState.encoding); + } consume2.length += chunk.length; consume2.body.push(chunk); } @@ -33000,6 +33210,7 @@ var require_mock_utils2 = __commonJS({ } } = require("node:util"); var { InvalidArgumentError } = require_errors2(); + var requestAborted = /* @__PURE__ */ Symbol("request aborted"); function matchValue(match, value) { if (typeof match === "string") { return match === value; @@ -33112,6 +33323,8 @@ var require_mock_utils2 = __commonJS({ return data; } else if (data instanceof ArrayBuffer) { return data; + } else if (ArrayBuffer.isView(data)) { + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); } else if (typeof data === "object") { return JSON.stringify(data); } else if (data) { @@ -33165,6 +33378,9 @@ var require_mock_utils2 = __commonJS({ } } function removeTrailingSlash(path) { + if (typeof path !== "string") { + return path; + } while (path.endsWith("/")) { path = path.slice(0, -1); } @@ -33213,17 +33429,43 @@ var require_mock_utils2 = __commonJS({ function mockDispatch(opts, handler) { const key = buildKey(opts); const mockDispatch2 = getMockDispatch(this[kDispatches], key); + const mockDispatches = this[kDispatches]; mockDispatch2.timesInvoked++; - if (mockDispatch2.data.callback) { - mockDispatch2.data = { ...mockDispatch2.data, ...mockDispatch2.data.callback(opts) }; - } - const { data: { statusCode, data, headers, trailers, error: error2 }, delay, persist } = mockDispatch2; const { timesInvoked, times } = mockDispatch2; - mockDispatch2.consumed = !persist && timesInvoked >= times; + mockDispatch2.consumed = !mockDispatch2.persist && timesInvoked >= times; mockDispatch2.pending = timesInvoked < times; - if (error2 !== null) { - deleteMockDispatch(this[kDispatches], key); - handler.onResponseError(null, error2); + const hasBodyHooks = typeof handler.onBodySent === "function" || typeof handler.onRequestSent === "function"; + if (mockDispatch2.data.callback && (!hasBodyHooks || opts.body == null)) { + const { callback, ...responseDefaults } = mockDispatch2.data; + const callbackResult = callback(opts); + if (isPromise(callbackResult)) { + callbackResult.then( + (resolvedData) => { + if (resolvedData == null || typeof resolvedData !== "object") { + handler.onResponseError(null, new InvalidArgumentError("reply options callback must return an object")); + return; + } + mockDispatch2.data = { ...responseDefaults, ...resolvedData }; + dispatchMockReply(mockDispatches, mockDispatch2, key, opts, handler); + }, + (error2) => { + handler.onResponseError(null, error2); + } + ); + return true; + } + if (callbackResult == null || typeof callbackResult !== "object") { + throw new InvalidArgumentError("reply options callback must return an object"); + } + mockDispatch2.data = { ...responseDefaults, ...callbackResult }; + } + return dispatchMockReply(mockDispatches, mockDispatch2, key, opts, handler); + } + function dispatchMockReply(mockDispatches, mockDispatch2, key, opts, handler) { + const { data: response, delay } = mockDispatch2; + if (response.error !== null) { + deleteMockDispatch(mockDispatches, key); + handler.onResponseError(null, response.error); return true; } let aborted = false; @@ -33250,39 +33492,172 @@ var require_mock_utils2 = __commonJS({ handler.onResponseError?.(controller, reason); } }; + let replyOpts = opts; + const dispatches = mockDispatches; handler.onRequestStart?.(controller, null); - if (typeof delay === "number" && delay > 0) { - timer = setTimeout(() => { - timer = null; - handleReply(this[kDispatches]); - }, delay); - } else { - handleReply(this[kDispatches]); + if (aborted) { + return true; } - function handleReply(mockDispatches, _data = data) { + const requestBody = dispatchRequestBody(opts.body, handler, controller, () => aborted); + if (isPromise(requestBody)) { + requestBody.then((body) => { + if (body === requestAborted) { + return; + } + if (body !== opts.body) { + replyOpts = { ...opts, body }; + } + sendReply(); + }, (error2) => controller.abort(error2)); + return true; + } + if (requestBody === requestAborted) { + return true; + } + if (requestBody !== opts.body) { + replyOpts = { ...opts, body: requestBody }; + } + sendReply(); + function sendReply() { + if (response.callback) { + const { callback, ...responseDefaults } = response; + let callbackResult; + try { + callbackResult = callback(replyOpts); + } catch (err) { + deleteMockDispatch(mockDispatches, key); + handler.onResponseError(null, err); + return; + } + if (isPromise(callbackResult)) { + callbackResult.then( + (resolvedData) => { + if (resolvedData == null || typeof resolvedData !== "object") { + handler.onResponseError(null, new InvalidArgumentError("reply options callback must return an object")); + return; + } + mockDispatch2.data = { ...responseDefaults, ...resolvedData }; + handleReply(dispatches, mockDispatch2.data); + }, + (err) => { + handler.onResponseError(null, err); + } + ); + return; + } + if (callbackResult == null || typeof callbackResult !== "object") { + throw new InvalidArgumentError("reply options callback must return an object"); + } + mockDispatch2.data = { ...responseDefaults, ...callbackResult }; + handleReply(dispatches, mockDispatch2.data); + return; + } + if (typeof delay === "number" && delay > 0) { + timer = setTimeout(() => { + timer = null; + handleReply(dispatches); + }, delay); + } else { + handleReply(dispatches); + } + } + function handleReply(mockDispatches2, _response = response) { if (aborted) { return; } + const { statusCode, data, headers, trailers } = _response; const optsHeaders = Array.isArray(opts.headers) ? buildHeadersFromArray(opts.headers) : opts.headers; - const body = typeof _data === "function" ? _data({ ...opts, headers: optsHeaders }) : _data; + const body = typeof data === "function" ? data({ ...replyOpts, headers: optsHeaders }) : data; if (isPromise(body)) { - return body.then((newData) => handleReply(mockDispatches, newData)); + return body.then((newData) => handleReply(mockDispatches2, { ..._response, data: newData })); } if (aborted) { return; } const responseData = getResponseData(body); - const responseHeaders = generateKeyValues(headers); - const responseTrailers = generateKeyValues(trailers); + const responseHeaders = generateKeyValues(headers ?? {}); + const responseTrailers = generateKeyValues(trailers ?? {}); controller.rawHeaders = responseHeaders; controller.rawTrailers = responseTrailers; handler.onResponseStart?.(controller, statusCode, parseHeaders(responseHeaders), getStatusText(statusCode)); handler.onResponseData?.(controller, Buffer.from(responseData)); handler.onResponseEnd?.(controller, parseHeaders(responseTrailers)); - deleteMockDispatch(mockDispatches, key); + deleteMockDispatch(mockDispatches2, key); } return true; } + function dispatchRequestBody(body, handler, controller, isAborted) { + if (typeof handler.onBodySent !== "function" && typeof handler.onRequestSent !== "function") { + return body; + } + if (body == null) { + return callOnRequestSent(handler, controller, isAborted) ? body : requestAborted; + } + if (body && typeof body[Symbol.asyncIterator] === "function") { + return dispatchAsyncIterableBody(body, handler, controller, isAborted); + } + if (isIterableBody(body)) { + const chunks = []; + for (const chunk of body) { + if (isAborted()) { + return requestAborted; + } + chunks.push(chunk); + if (!callOnBodySent(handler, controller, chunk) || isAborted()) { + return requestAborted; + } + } + return callOnRequestSent(handler, controller, isAborted) ? chunks : requestAborted; + } + if (isAborted()) { + return requestAborted; + } + if (!callOnBodySent(handler, controller, body)) { + return requestAborted; + } + return callOnRequestSent(handler, controller, isAborted) ? body : requestAborted; + } + async function dispatchAsyncIterableBody(body, handler, controller, isAborted) { + const chunks = []; + for await (const chunk of body) { + if (isAborted()) { + return requestAborted; + } + chunks.push(chunk); + if (!callOnBodySent(handler, controller, chunk) || isAborted()) { + return requestAborted; + } + } + if (!callOnRequestSent(handler, controller, isAborted)) { + return requestAborted; + } + return { + async *[Symbol.asyncIterator]() { + yield* chunks; + } + }; + } + function callOnBodySent(handler, controller, chunk) { + try { + handler.onBodySent?.(chunk); + return true; + } catch (error2) { + controller.abort(error2); + return false; + } + } + function callOnRequestSent(handler, controller, isAborted) { + try { + handler.onRequestSent?.(); + return !isAborted(); + } catch (error2) { + controller.abort(error2); + return false; + } + } + function isIterableBody(body) { + return typeof body !== "string" && !Buffer.isBuffer(body) && !ArrayBuffer.isView(body) && typeof body[Symbol.iterator] === "function"; + } function buildMockDispatch() { const agent = this[kMockAgent]; const origin = this[kOrigin]; @@ -33383,6 +33758,11 @@ var require_mock_interceptor2 = __commonJS({ } = require_mock_symbols2(); var { InvalidArgumentError } = require_errors2(); var { serializePathWithQuery } = require_util9(); + var { + types: { + isPromise + } + } = require("node:util"); var MockScope = class { constructor(mockDispatch) { this[kMockDispatch] = mockDispatch; @@ -33464,8 +33844,7 @@ var require_mock_interceptor2 = __commonJS({ */ reply(replyOptionsCallbackOrStatusCode) { if (typeof replyOptionsCallbackOrStatusCode === "function") { - const wrappedDefaultsCallback = (opts) => { - const resolvedData = replyOptionsCallbackOrStatusCode(opts); + const resolveReplyCallbackData = (resolvedData) => { if (typeof resolvedData !== "object" || resolvedData === null) { throw new InvalidArgumentError("reply options callback must return an object"); } @@ -33475,6 +33854,13 @@ var require_mock_interceptor2 = __commonJS({ ...this.createMockScopeDispatchData(replyParameters2) }; }; + const wrappedDefaultsCallback = (opts) => { + const resolvedData = replyOptionsCallbackOrStatusCode(opts); + if (isPromise(resolvedData)) { + return resolvedData.then(resolveReplyCallbackData); + } + return resolveReplyCallbackData(resolvedData); + }; const newMockDispatch2 = addMockDispatch(this[kDispatches], this[kDispatchKey], wrappedDefaultsCallback, { ignoreTrailingSlash: this[kIgnoreTrailingSlash] }); return new MockScope(newMockDispatch2); } @@ -34863,6 +35249,7 @@ var require_global4 = __commonJS({ var { InvalidArgumentError } = require_errors2(); var Agent = require_agent2(); var Dispatcher1Wrapper = require_dispatcher1_wrapper(); + var fallbackDispatcher; if (getGlobalDispatcher() === void 0) { setGlobalDispatcher(new Agent()); } @@ -34870,22 +35257,36 @@ var require_global4 = __commonJS({ if (!agent || typeof agent.dispatch !== "function") { throw new InvalidArgumentError("Argument agent must implement Agent"); } - Object.defineProperty(globalThis, globalDispatcher, { - value: agent, - writable: true, - enumerable: false, - configurable: false - }); - const legacyAgent = agent instanceof Dispatcher1Wrapper ? agent : new Dispatcher1Wrapper(agent); - Object.defineProperty(globalThis, legacyGlobalDispatcher, { - value: legacyAgent, - writable: true, - enumerable: false, - configurable: false - }); + try { + Object.defineProperty(globalThis, globalDispatcher, { + value: agent, + writable: true, + enumerable: false, + configurable: false + }); + } catch (err) { + if (err instanceof TypeError) { + fallbackDispatcher = agent; + return; + } + throw err; + } + try { + const legacyAgent = agent instanceof Dispatcher1Wrapper ? agent : new Dispatcher1Wrapper(agent); + Object.defineProperty(globalThis, legacyGlobalDispatcher, { + value: legacyAgent, + writable: true, + enumerable: false, + configurable: false + }); + } catch (err) { + if (!(err instanceof TypeError)) { + throw err; + } + } } function getGlobalDispatcher() { - return globalThis[globalDispatcher]; + return globalThis[globalDispatcher] ?? fallbackDispatcher; } var installedExports = ( /** @type {const} */ @@ -35011,12 +35412,14 @@ var require_redirect_handler2 = __commonJS({ if (this.opts.throwOnMaxRedirect && this.history.length >= this.maxRedirections) { throw new Error("max redirects"); } + let removeContentHeaders = statusCode === 303; if ((statusCode === 301 || statusCode === 302) && this.opts.method === "POST") { this.opts.method = "GET"; if (util.isStream(this.opts.body)) { util.destroy(this.opts.body.on("error", noop)); } this.opts.body = null; + removeContentHeaders = true; } if (statusCode === 303 && this.opts.method !== "HEAD") { this.opts.method = "GET"; @@ -35041,7 +35444,7 @@ var require_redirect_handler2 = __commonJS({ throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`); } } - this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect); + this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect); this.opts.path = path; this.opts.origin = origin; this.opts.query = null; @@ -35782,24 +36185,146 @@ var require_cache2 = __commonJS({ var { safeHTTPMethods, pathHasQueryOrFragment, - hasSafeIterator + hasSafeIterator, + isValidHTTPToken } = require_util9(); var { serializePathWithQuery } = require_util9(); - function makeCacheKey(opts) { - if (!opts.origin) { - throw new Error("opts.origin is undefined"); + var MAX_DELTA_SECONDS = 2147483647; + var RESTRICTIVE_DIRECTIVE_NAMES = ["no-store", "private", "no-cache"]; + var kInvalidCacheControlDirectives = /* @__PURE__ */ Symbol("invalid cache-control directives"); + function trimOWS(value) { + return value.replace(/^[\t ]+|[\t ]+$/g, ""); + } + function arrayIncludes(array, value) { + for (let i = 0; i < array.length; i++) { + if (array[i] === value) { + return true; + } } + return false; + } + function trimOWSStart(value) { + return value.replace(/^[\t ]+/, ""); + } + function trimOWSEnd(value) { + return value.replace(/[\t ]+$/, ""); + } + function findUnescapedQuote(value, start) { + let escaped = false; + for (let i = start; i < value.length; i++) { + if (escaped) { + escaped = false; + } else if (value[i] === "\\") { + escaped = true; + } else if (value[i] === '"') { + return i; + } + } + return -1; + } + function splitCacheControlHeaderValue(value) { + const directives = []; + let start = 0; + let quoteStart = -1; + let inQuote = false; + let escaped = false; + for (let i = 0; i < value.length; i++) { + if (inQuote) { + if (escaped) { + escaped = false; + } else if (value[i] === "\\") { + escaped = true; + } else if (value[i] === '"') { + inQuote = false; + quoteStart = -1; + } + } else if (value[i] === '"') { + inQuote = true; + quoteStart = i; + } else if (value[i] === ",") { + directives.push({ value: value.substring(start, i), fromMalformedQuote: false }); + start = i + 1; + } + } + if (!inQuote) { + directives.push({ value: value.substring(start), fromMalformedQuote: false }); + return directives; + } + const tail = value.substring(start); + const quoteOffset = quoteStart - start; + let tailStart = 0; + for (let i = 0; i < tail.length; i++) { + if (tail[i] === ",") { + directives.push({ + value: tail.substring(tailStart, i), + fromMalformedQuote: tailStart > quoteOffset + }); + tailStart = i + 1; + } + } + directives.push({ + value: tail.substring(tailStart), + fromMalformedQuote: tailStart > quoteOffset + }); + return directives; + } + function markInvalidCacheControlDirective(directives, key) { + let invalidDirectives = directives[kInvalidCacheControlDirectives]; + if (invalidDirectives === void 0) { + invalidDirectives = /* @__PURE__ */ new Set(); + Object.defineProperty(directives, kInvalidCacheControlDirectives, { + value: invalidDirectives + }); + } + invalidDirectives.add(key); + } + function hasInvalidCacheControlDirective(directives, key) { + return directives[kInvalidCacheControlDirectives]?.has(key) === true; + } + function getMalformedRestrictiveDirectiveName(key) { + for (const directiveName of RESTRICTIVE_DIRECTIVE_NAMES) { + if (key.startsWith(directiveName) && key.length > directiveName.length && !isValidHTTPToken(key[directiveName.length])) { + return directiveName; + } + } + let tokenOnlyKey = ""; + let hasInvalidTokenChar = false; + for (let i = 0; i < key.length; i++) { + if (isValidHTTPToken(key[i])) { + tokenOnlyKey += key[i]; + } else { + hasInvalidTokenChar = true; + } + } + if (hasInvalidTokenChar && arrayIncludes(RESTRICTIVE_DIRECTIVE_NAMES, tokenOnlyKey)) { + return tokenOnlyKey; + } + } + function makeCacheKey(opts) { + const origin = opts.origin ? opts.origin.toString() : ""; let fullPath = opts.path || "/"; if (opts.query && !pathHasQueryOrFragment(fullPath)) { fullPath = serializePathWithQuery(fullPath, opts.query); } return { - origin: opts.origin.toString(), + origin, method: opts.method, path: fullPath, headers: opts.headers }; } + function appendHeader(headers, key, val) { + const headerName = key.toLowerCase(); + const current = headers[headerName]; + const values = Array.isArray(val) ? val : [val]; + if (current === void 0) { + headers[headerName] = Array.isArray(val) ? val.slice() : val; + } else if (Array.isArray(current)) { + current.push(...values); + } else { + headers[headerName] = [current, ...values]; + } + } function normalizeHeaders(opts) { let headers; if (opts.headers == null) { @@ -35807,19 +36332,57 @@ var require_cache2 = __commonJS({ } else if (typeof opts.headers === "object") { headers = {}; if (hasSafeIterator(opts.headers)) { - for (const x of opts.headers) { - if (!Array.isArray(x)) { - throw new Error("opts.headers is not a valid header map"); + if (Array.isArray(opts.headers)) { + const first = opts.headers[0]; + if (Array.isArray(first)) { + for (const x of opts.headers) { + if (!Array.isArray(x)) { + throw new Error("opts.headers is not a valid header map"); + } + const [key, val] = x; + if (typeof key !== "string" || typeof val !== "string") { + throw new Error("opts.headers is not a valid header map"); + } + appendHeader(headers, key, val); + } + } else { + const len = opts.headers.length; + if (len % 2 !== 0) { + throw new Error("opts.headers is not a valid header map"); + } + for (let i = 0; i < len; i += 2) { + const key = opts.headers[i]; + const val = opts.headers[i + 1]; + if (typeof key !== "string" || typeof val !== "string" && !Array.isArray(val)) { + throw new Error("opts.headers is not a valid header map"); + } + if (typeof val === "string") { + appendHeader(headers, key, val); + } else { + const mapped = []; + for (let j = 0; j < val.length; j++) { + const v = val[j]; + mapped.push(typeof v === "string" ? v : v.toString("latin1")); + } + appendHeader(headers, key, mapped); + } + } } - const [key, val] = x; - if (typeof key !== "string" || typeof val !== "string") { - throw new Error("opts.headers is not a valid header map"); + } else { + for (const x of opts.headers) { + if (!Array.isArray(x)) { + throw new Error("opts.headers is not a valid header map"); + } + const [key, val] = x; + if (typeof key !== "string" || typeof val !== "string") { + throw new Error("opts.headers is not a valid header map"); + } + appendHeader(headers, key, val); } - headers[key.toLowerCase()] = val; } } else { for (const key of Object.keys(opts.headers)) { - headers[key.toLowerCase()] = opts.headers[key]; + appendHeader(headers, key, opts.headers[key]); } } } else { @@ -35864,25 +36427,32 @@ var require_cache2 = __commonJS({ } function parseCacheControlHeader(header) { const output = {}; - let directives; - if (Array.isArray(header)) { - directives = []; - for (const directive of header) { - directives.push(...directive.split(",")); - } - } else { - directives = header.split(","); - } + const invalidNumericDirectives = /* @__PURE__ */ new Set(); + const invalidNoArgumentDirectives = /* @__PURE__ */ new Set(); + const directives = splitCacheControlHeaderValue(Array.isArray(header) ? header.join(",") : header); for (let i = 0; i < directives.length; i++) { - const directive = directives[i].toLowerCase(); + const directiveRecord = directives[i]; + const directive = directiveRecord.value.toLowerCase(); + const fromMalformedQuote = directiveRecord.fromMalformedQuote; const keyValueDelimiter = directive.indexOf("="); let key; let value; + let keyHasTrailingWhitespace = false; + let valueHasLeadingWhitespace = false; if (keyValueDelimiter !== -1) { - key = directive.substring(0, keyValueDelimiter).trimStart(); - value = directive.substring(keyValueDelimiter + 1); + const rawKey = directive.substring(0, keyValueDelimiter); + const rawValue = directive.substring(keyValueDelimiter + 1); + keyHasTrailingWhitespace = trimOWSEnd(rawKey) !== rawKey; + valueHasLeadingWhitespace = trimOWSStart(rawValue) !== rawValue; + key = trimOWS(rawKey); + value = trimOWSStart(rawValue); } else { - key = directive.trim(); + key = trimOWS(directive); + } + const malformedRestrictiveDirectiveName = getMalformedRestrictiveDirectiveName(key); + if (malformedRestrictiveDirectiveName !== void 0) { + output[malformedRestrictiveDirectiveName] = true; + continue; } switch (key) { case "min-fresh": @@ -35891,48 +36461,85 @@ var require_cache2 = __commonJS({ case "s-maxage": case "stale-while-revalidate": case "stale-if-error": { - if (value === void 0 || value[0] === " ") { + if (fromMalformedQuote || invalidNumericDirectives.has(key)) { + continue; + } + if (value === void 0 || keyHasTrailingWhitespace || valueHasLeadingWhitespace) { + delete output[key]; + invalidNumericDirectives.add(key); + markInvalidCacheControlDirective(output, key); continue; } if (value.length >= 2 && value[0] === '"' && value[value.length - 1] === '"') { value = value.substring(1, value.length - 1); } - const parsedValue = parseInt(value, 10); - if (parsedValue !== parsedValue) { + if (!/^[0-9]+$/.test(value)) { + delete output[key]; + invalidNumericDirectives.add(key); + markInvalidCacheControlDirective(output, key); continue; } - if (key === "max-age" && key in output && output[key] >= parsedValue) { - continue; + const parsedValue = Math.min(parseInt(value, 10), MAX_DELTA_SECONDS); + if (key === "min-fresh") { + if (!(key in output) || output[key] < parsedValue) { + output[key] = parsedValue; + } + } else if (!(key in output) || output[key] > parsedValue) { + output[key] = parsedValue; } - output[key] = parsedValue; break; } case "private": case "no-cache": { + if (fromMalformedQuote) { + output[key] = true; + break; + } + if (value !== void 0 && value.length === 0) { + output[key] = true; + break; + } if (value) { if (value[0] === '"') { - const headers = [value.substring(1)]; - let foundEndingQuote = value[value.length - 1] === '"'; - if (!foundEndingQuote) { + value = trimOWSEnd(value); + let fieldList = ""; + let lastQuotedPart = i; + let foundEndingQuote = false; + const closingQuote = findUnescapedQuote(value, 1); + if (closingQuote !== -1) { + fieldList = value.substring(1, closingQuote); + foundEndingQuote = true; + } else { + const fieldListParts = [value.substring(1)]; for (let j = i + 1; j < directives.length; j++) { - const nextPart = directives[j]; - const nextPartLength = nextPart.length; - headers.push(nextPart.trim()); - if (nextPartLength !== 0 && nextPart[nextPartLength - 1] === '"') { + const nextPart = trimOWS(directives[j].value); + const closingQuote2 = findUnescapedQuote(nextPart, 0); + lastQuotedPart = j; + if (closingQuote2 !== -1) { + fieldListParts.push(nextPart.substring(0, closingQuote2)); foundEndingQuote = true; break; } + fieldListParts.push(nextPart); + } + fieldList = fieldListParts.join(","); + } + if (!foundEndingQuote) { + output[key] = true; + break; + } + i = lastQuotedPart; + const headers = fieldList.split(","); + let validFieldNames = true; + for (let j = 0; j < headers.length; j++) { + headers[j] = trimOWS(headers[j]); + if (!isValidHTTPToken(headers[j])) { + validFieldNames = false; } } - if (foundEndingQuote) { - let lastHeader = headers[headers.length - 1]; - if (lastHeader[lastHeader.length - 1] === '"') { - lastHeader = lastHeader.substring(0, lastHeader.length - 1); - headers[headers.length - 1] = lastHeader; - } - for (let j = 0; j < headers.length; j++) { - headers[j] = headers[j].trim(); - } + if (!validFieldNames) { + output[key] = true; + } else if (output[key] !== true) { if (key in output) { output[key] = output[key].concat(headers); } else { @@ -35940,11 +36547,15 @@ var require_cache2 = __commonJS({ } } } else { - const fieldName = value.trim(); - if (key in output) { - output[key] = output[key].concat(fieldName); - } else { - output[key] = [fieldName]; + const fieldName = trimOWS(value); + if (!isValidHTTPToken(fieldName)) { + output[key] = true; + } else if (output[key] !== true) { + if (key in output) { + output[key] = output[key].concat(fieldName); + } else { + output[key] = [fieldName]; + } } } break; @@ -35952,16 +36563,23 @@ var require_cache2 = __commonJS({ } // eslint-disable-next-line no-fallthrough case "public": - case "no-store": case "must-revalidate": case "proxy-revalidate": case "immutable": case "no-transform": case "must-understand": case "only-if-cached": - if (value) { + if (fromMalformedQuote || invalidNoArgumentDirectives.has(key)) { continue; } + if (value !== void 0) { + delete output[key]; + invalidNoArgumentDirectives.add(key); + continue; + } + output[key] = true; + break; + case "no-store": output[key] = true; break; default: @@ -35970,21 +36588,51 @@ var require_cache2 = __commonJS({ } return output; } + function splitVaryHeader(varyHeader) { + const values = Array.isArray(varyHeader) ? varyHeader : [varyHeader]; + const output = []; + for (let i = 0; i < values.length; i++) { + const parts = values[i].split(","); + for (let j = 0; j < parts.length; j++) { + output.push(parts[j]); + } + } + return output; + } + function hasVaryStar(varyHeader) { + const values = splitVaryHeader(varyHeader); + for (let i = 0; i < values.length; i++) { + if (trimOWS(values[i]).indexOf("*") !== -1) { + return true; + } + } + return false; + } function parseVaryHeader(varyHeader, headers) { - if (typeof varyHeader === "string" && varyHeader.includes("*")) { + if (hasVaryStar(varyHeader)) { return headers; } const output = ( /** @type {Record} */ {} ); - const varyingHeaders = typeof varyHeader === "string" ? varyHeader.split(",") : varyHeader; + const varyingHeaders = splitVaryHeader(varyHeader); for (const header of varyingHeaders) { - const trimmedHeader = header.trim().toLowerCase(); - output[trimmedHeader] = headers[trimmedHeader] ?? null; + const trimmedHeader = trimOWS(header).toLowerCase(); + if (trimmedHeader.length === 0) { + continue; + } + if (!isValidHTTPToken(trimmedHeader)) { + return void 0; + } + const headerValue = headers[trimmedHeader]; + output[trimmedHeader] = Array.isArray(headerValue) ? headerValue.slice() : headerValue ?? null; } return output; } + function isInvalidOrWildcardVaryHeader(varyHeader) { + return hasVaryStar(varyHeader) || parseVaryHeader(varyHeader, {}) === void 0; + } function isEtagUsable(etag) { if (etag.length <= 2) { return false; @@ -36015,7 +36663,7 @@ var require_cache2 = __commonJS({ throw new TypeError(`${name} needs to have at least one method`); } for (const method of methods) { - if (!safeHTTPMethods.includes(method)) { + if (!arrayIncludes(safeHTTPMethods, method)) { throw new TypeError(`element of ${name}-array needs to be one of following values: ${safeHTTPMethods.join(", ")}, got ${method}`); } } @@ -36039,7 +36687,10 @@ var require_cache2 = __commonJS({ assertCacheKey, assertCacheValue, parseCacheControlHeader, + hasInvalidCacheControlDirective, parseVaryHeader, + hasVaryStar, + isInvalidOrWildcardVaryHeader, isEtagUsable, assertCacheMethods, assertCacheStore, @@ -36062,6 +36713,13 @@ var require_date = __commonJS({ return parseRfc850Date(date); } } + function makeDate(year, monthIdx, day, hour, minute, second, weekday) { + const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); + if (year >= 0 && year <= 99) { + result.setUTCFullYear(year); + } + return result.getUTCFullYear() === year && result.getUTCMonth() === monthIdx && result.getUTCDate() === day && result.getUTCHours() === hour && result.getUTCMinutes() === minute && result.getUTCSeconds() === second && result.getUTCDay() === weekday ? result : void 0; + } function parseImfDate(date) { if (date.length !== 29 || date[4] !== " " || date[7] !== " " || date[11] !== " " || date[16] !== " " || date[19] !== ":" || date[22] !== ":" || date[25] !== " " || date[26] !== "G" || date[27] !== "M" || date[28] !== "T") { return void 0; @@ -36222,8 +36880,7 @@ var require_date = __commonJS({ } second = (code1 - 48) * 10 + (code2 - 48); } - const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); - return result.getUTCDay() === weekday ? result : void 0; + return makeDate(year, monthIdx, day, hour, minute, second, weekday); } function parseAscTimeDate(date) { if (date.length !== 24 || date[7] !== " " || date[10] !== " " || date[19] !== " ") { @@ -36385,8 +37042,7 @@ var require_date = __commonJS({ return void 0; } const year = (yearDigit1 - 48) * 1e3 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48); - const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); - return result.getUTCDay() === weekday ? result : void 0; + return makeDate(year, monthIdx, day, hour, minute, second, weekday); } function parseRfc850Date(date) { let commaIndex = -1; @@ -36535,8 +37191,7 @@ var require_date = __commonJS({ } second = (code1 - 48) * 10 + (code2 - 48); } - const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second)); - return result.getUTCDay() === weekday ? result : void 0; + return makeDate(year, monthIdx, day, hour, minute, second, weekday); } module2.exports = { parseHttpDate @@ -36551,7 +37206,10 @@ var require_cache_handler = __commonJS({ var util = require_util9(); var { parseCacheControlHeader, + hasInvalidCacheControlDirective, parseVaryHeader, + hasVaryStar, + isInvalidOrWildcardVaryHeader, isEtagUsable } = require_cache2(); var { parseHttpDate } = require_date(); @@ -36575,6 +37233,79 @@ var require_cache_handler = __commonJS({ 206 ]; var MAX_RESPONSE_AGE = 2147483647e3; + var REVALIDATION_ONLY_RETENTION = 864e5; + function trimOWS(value) { + return value.replace(/^[\t ]+|[\t ]+$/g, ""); + } + function arrayIncludes(array, value) { + for (let i = 0; i < array.length; i++) { + if (array[i] === value) { + return true; + } + } + return false; + } + function appendConnectionHeaderTokens(headersToRemove, connectionHeader) { + const values = Array.isArray(connectionHeader) ? connectionHeader : [connectionHeader]; + for (let i = 0; i < values.length; i++) { + const tokens = values[i].split(","); + for (let j = 0; j < tokens.length; j++) { + headersToRemove.push(trimOWS(tokens[j]).toLowerCase()); + } + } + } + function getSameOriginPath(cacheKey, location) { + if (typeof location !== "string") { + return void 0; + } + let originUrl; + let requestUrl; + let locationUrl; + try { + originUrl = new URL(cacheKey.origin); + requestUrl = new URL(cacheKey.path, originUrl); + locationUrl = new URL(location, requestUrl); + } catch { + return void 0; + } + if (locationUrl.origin !== originUrl.origin) { + return void 0; + } + return locationUrl.pathname + locationUrl.search; + } + function deleteCachedUri(store, cacheKey, path) { + deleteCachedValue(store, { + ...cacheKey, + path + }); + for (let i = 0; i < util.safeHTTPMethods.length; i++) { + const method = util.safeHTTPMethods[i]; + if (method !== cacheKey.method) { + deleteCachedValue(store, { + ...cacheKey, + method, + path + }); + } + } + } + function deleteLocationTargets(store, cacheKey, headerValue) { + if (headerValue === void 0) { + return; + } + const values = Array.isArray(headerValue) ? headerValue : [headerValue]; + for (let i = 0; i < values.length; i++) { + const path = getSameOriginPath(cacheKey, values[i]); + if (path !== void 0) { + deleteCachedUri(store, cacheKey, path); + } + } + } + function invalidateUnsafeRequest(store, cacheKey, resHeaders) { + deleteCachedUri(store, cacheKey, cacheKey.path); + deleteLocationTargets(store, cacheKey, resHeaders.location); + deleteLocationTargets(store, cacheKey, resHeaders["content-location"]); + } var CacheHandler = class { /** * @type {import('../../types/cache-interceptor.d.ts').default.CacheKey} @@ -36634,35 +37365,51 @@ var require_cache_handler = __commonJS({ statusMessage ); const handler = this; - if (!util.safeHTTPMethods.includes(this.#cacheKey.method) && statusCode >= 200 && statusCode <= 399) { - try { - this.#store.delete(this.#cacheKey)?.catch?.(noop); - } catch { - } + if (!arrayIncludes(util.safeHTTPMethods, this.#cacheKey.method) && statusCode >= 200 && statusCode <= 399) { + invalidateUnsafeRequest(this.#store, this.#cacheKey, resHeaders); return downstreamOnHeaders(); } const cacheControlHeader = resHeaders["cache-control"]; - const heuristicallyCacheable = resHeaders["last-modified"] && HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode); + const heuristicallyCacheable = resHeaders["last-modified"] && arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode); if (!cacheControlHeader && !resHeaders["expires"] && !heuristicallyCacheable && !this.#cacheByDefault) { + if (statusCode === 304 && resHeaders.vary && isInvalidOrWildcardVaryHeader(resHeaders.vary)) { + deleteCachedValue(this.#store, this.#cacheKey); + } return downstreamOnHeaders(); } const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { + if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) { + deleteCachedValue(this.#store, this.#cacheKey); + } return downstreamOnHeaders(); } const now = Date.now(); - const resAge = resHeaders.age ? getAge(resHeaders.age) : void 0; - if (resAge && resAge >= MAX_RESPONSE_AGE) { + const resAge = Object.hasOwn(resHeaders, "age") ? getAge(resHeaders.age) : void 0; + if (resAge !== void 0 && resAge >= MAX_RESPONSE_AGE) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); return downstreamOnHeaders(); } - const resDate = typeof resHeaders.date === "string" ? parseHttpDate(resHeaders.date) : void 0; - const staleAt = determineStaleAt(this.#cacheType, now, resAge, resHeaders, resDate, cacheControlDirectives) ?? this.#cacheByDefault; - if (staleAt === void 0 || resAge && resAge > staleAt) { + const resDate = Object.hasOwn(resHeaders, "date") ? getDate(resHeaders.date) : void 0; + if (resDate === null) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); return downstreamOnHeaders(); } - const baseTime = resDate ? resDate.getTime() : now; + const apparentAge = resDate ? Math.max(0, now - resDate.getTime()) : 0; + const currentAge = Math.max(apparentAge, resAge ?? 0); + const hasValidator = typeof resHeaders.etag === "string" && isEtagUsable(resHeaders.etag) || typeof resHeaders["last-modified"] === "string"; + const staleAt = determineStaleAt(this.#cacheType, now, resAge, resHeaders, resDate, cacheControlDirectives, hasValidator) ?? this.#cacheByDefault; + const revalidationOnly = staleAt === 0 && hasValidator; + if (staleAt === void 0 || currentAge >= staleAt && !revalidationOnly) { + if (cacheControlHeader || staleAt !== void 0) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); + } + return downstreamOnHeaders(); + } + const baseTime = now - currentAge; const absoluteStaleAt = staleAt + baseTime; - if (now >= absoluteStaleAt) { + if (now >= absoluteStaleAt && !revalidationOnly) { + deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey); return downstreamOnHeaders(); } let varyDirectives; @@ -36672,8 +37419,8 @@ var require_cache_handler = __commonJS({ return downstreamOnHeaders(); } } - const cachedAt = resAge ? now - resAge : now; - const deleteAt = determineDeleteAt(baseTime, cachedAt, cacheControlDirectives, absoluteStaleAt); + const cachedAt = baseTime; + const deleteAt = determineDeleteAt(baseTime, now, cacheControlDirectives, absoluteStaleAt); const strippedHeaders = stripNecessaryHeaders(resHeaders, cacheControlDirectives); const value = { statusCode, @@ -36693,6 +37440,7 @@ var require_cache_handler = __commonJS({ value.statusCode = cachedValue.statusCode; value.statusMessage = cachedValue.statusMessage; value.etag = cachedValue.etag; + value.vary = varyDirectives ?? cachedValue.vary; value.headers = { ...cachedValue.headers, ...strippedHeaders }; downstreamOnHeaders(); this.#writeStream = this.#store.createWriteStream(this.#cacheKey, value); @@ -36783,11 +37531,25 @@ var require_cache_handler = __commonJS({ this.#handler.onResponseError?.(controller, err); } }; + function deleteCachedValue(store, cacheKey) { + try { + store.delete(cacheKey)?.catch?.(noop); + } catch { + } + } + function deleteCachedValueIfNotModified(statusCode, store, cacheKey) { + if (statusCode === 304) { + deleteCachedValue(store, cacheKey); + } + } + function revalidationResponseDisallowsCachedReuse(cacheType, resHeaders, cacheControlDirectives) { + return cacheControlDirectives["no-store"] === true || cacheType === "shared" && cacheControlDirectives.private === true || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); + } function canCacheResponse(cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { - if (statusCode < 200 || NOT_UNDERSTOOD_STATUS_CODES.includes(statusCode)) { + if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) { return false; } - if (!HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode) && !resHeaders["expires"] && !cacheControlDirectives.public && cacheControlDirectives["max-age"] === void 0 && // RFC 9111: a private response directive, if the cache is not shared + if (!arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode) && !resHeaders["expires"] && !cacheControlDirectives.public && cacheControlDirectives["max-age"] === void 0 && // RFC 9111: a private response directive, if the cache is not shared !(cacheControlDirectives.private && cacheType === "private") && !(cacheControlDirectives["s-maxage"] !== void 0 && cacheType === "shared")) { return false; } @@ -36797,60 +37559,104 @@ var require_cache_handler = __commonJS({ if (cacheType === "shared" && cacheControlDirectives.private === true) { return false; } - if (resHeaders.vary?.includes("*")) { + if (resHeaders.vary && hasVaryStar(resHeaders.vary)) { return false; } - if (reqHeaders?.authorization) { + if (reqHeaders != null && Object.hasOwn(reqHeaders, "authorization")) { if (!cacheControlDirectives.public && !cacheControlDirectives["s-maxage"] && !cacheControlDirectives["must-revalidate"]) { return false; } if (typeof reqHeaders.authorization !== "string") { return false; } - if (Array.isArray(cacheControlDirectives["no-cache"]) && cacheControlDirectives["no-cache"].includes("authorization")) { + if (Array.isArray(cacheControlDirectives["no-cache"]) && arrayIncludes(cacheControlDirectives["no-cache"], "authorization")) { return false; } - if (Array.isArray(cacheControlDirectives["private"]) && cacheControlDirectives["private"].includes("authorization")) { + if (Array.isArray(cacheControlDirectives["private"]) && arrayIncludes(cacheControlDirectives["private"], "authorization")) { return false; } } return true; } - function getAge(ageHeader) { - const age = parseInt(Array.isArray(ageHeader) ? ageHeader[0] : ageHeader); - return isNaN(age) ? void 0 : age * 1e3; + function getDate(dateHeader) { + let dateValue = dateHeader; + if (Array.isArray(dateValue)) { + if (dateValue.length !== 1) { + return null; + } + dateValue = dateValue[0]; + } + if (typeof dateValue !== "string") { + return null; + } + return parseHttpDate(dateValue); } - function determineStaleAt(cacheType, now, age, resHeaders, responseDate, cacheControlDirectives) { + function getAge(ageHeader) { + let ageValue = ageHeader; + if (Array.isArray(ageValue)) { + if (ageValue.length !== 1) { + return MAX_RESPONSE_AGE; + } + ageValue = ageValue[0]; + } + if (typeof ageValue !== "string" || !/^[\t ]*[0-9]+[\t ]*$/.test(ageValue)) { + return MAX_RESPONSE_AGE; + } + const age = BigInt(ageValue.replace(/^[\t ]+|[\t ]+$/g, "")); + if (age >= BigInt(MAX_RESPONSE_AGE / 1e3)) { + return MAX_RESPONSE_AGE; + } + return Number(age) * 1e3; + } + function determineStaleAt(cacheType, now, age, resHeaders, responseDate, cacheControlDirectives, hasValidator) { if (cacheType === "shared") { + if (hasInvalidCacheControlDirective(cacheControlDirectives, "s-maxage")) { + return 0; + } const sMaxAge = cacheControlDirectives["s-maxage"]; if (sMaxAge !== void 0) { - return sMaxAge > 0 ? sMaxAge * 1e3 : void 0; + if (sMaxAge > 0) { + return sMaxAge * 1e3; + } + return 0; } } + if (hasInvalidCacheControlDirective(cacheControlDirectives, "max-age")) { + return 0; + } const maxAge = cacheControlDirectives["max-age"]; if (maxAge !== void 0) { - return maxAge > 0 ? maxAge * 1e3 : void 0; - } - if (typeof resHeaders.expires === "string") { - const expiresDate = parseHttpDate(resHeaders.expires); - if (expiresDate) { - if (now >= expiresDate.getTime()) { - return void 0; - } - if (responseDate) { - if (responseDate >= expiresDate) { - return void 0; - } - if (age !== void 0 && age > expiresDate - responseDate) { - return void 0; - } - } - return expiresDate.getTime() - now; + if (maxAge > 0) { + return maxAge * 1e3; } + return 0; + } + if (Object.hasOwn(resHeaders, "expires")) { + if (typeof resHeaders.expires !== "string") { + return 0; + } + const expiresDate = parseHttpDate(resHeaders.expires); + if (!expiresDate) { + return 0; + } + if (now >= expiresDate.getTime()) { + return 0; + } + if (responseDate) { + if (responseDate >= expiresDate) { + return 0; + } + const freshnessLifetime = expiresDate.getTime() - responseDate.getTime(); + if (age !== void 0 && age >= freshnessLifetime) { + return 0; + } + return freshnessLifetime; + } + return expiresDate.getTime() - now; } if (typeof resHeaders["last-modified"] === "string") { - const lastModified = new Date(resHeaders["last-modified"]); - if (isValidDate(lastModified)) { + const lastModified = parseHttpDate(resHeaders["last-modified"]); + if (lastModified) { if (lastModified.getTime() >= now) { return void 0; } @@ -36861,6 +37667,9 @@ var require_cache_handler = __commonJS({ if (cacheControlDirectives.immutable) { return 31536e6; } + if (cacheControlDirectives["no-cache"] === true && hasValidator) { + return 0; + } return void 0; } function determineDeleteAt(baseTime, cachedAt, cacheControlDirectives, staleAt) { @@ -36878,6 +37687,9 @@ var require_cache_handler = __commonJS({ } if (staleWhileRevalidate === -Infinity && staleIfError === -Infinity && immutable === -Infinity) { const freshnessLifetime = staleAt - baseTime; + if (freshnessLifetime <= 0) { + return cachedAt + REVALIDATION_ONLY_RETENTION; + } const datePrecisionPadding = Math.min(Math.max(cachedAt - baseTime, 0), 1e3); return staleAt + freshnessLifetime + datePrecisionPadding; } @@ -36897,11 +37709,7 @@ var require_cache_handler = __commonJS({ "age" ]; if (resHeaders["connection"]) { - if (Array.isArray(resHeaders["connection"])) { - headersToRemove.push(...resHeaders["connection"].map((header) => header.trim())); - } else { - headersToRemove.push(...resHeaders["connection"].split(",").map((header) => header.trim())); - } + appendConnectionHeaderTokens(headersToRemove, resHeaders["connection"]); } if (Array.isArray(cacheControlDirectives["no-cache"])) { headersToRemove.push(...cacheControlDirectives["no-cache"]); @@ -36911,16 +37719,13 @@ var require_cache_handler = __commonJS({ } let strippedHeaders; for (const headerName of headersToRemove) { - if (resHeaders[headerName]) { + if (Object.hasOwn(resHeaders, headerName)) { strippedHeaders ??= { ...resHeaders }; delete strippedHeaders[headerName]; } } return strippedHeaders ?? resHeaders; } - function isValidDate(date) { - return date instanceof Date && Number.isFinite(date.valueOf()); - } module2.exports = CacheHandler; } }); @@ -37091,12 +37896,43 @@ var require_memory_cache_store = __commonJS({ } }; function findEntry(key, entries, now) { - return entries.find((entry) => entry.deleteAt > now && entry.method === key.method && (entry.vary == null || Object.keys(entry.vary).every((headerName) => { - if (entry.vary[headerName] === null) { - return key.headers[headerName] === void 0; + for (let i = 0; i < entries.length; i++) { + const entry = entries[i]; + if (entry.deleteAt > now && entry.method === key.method && varyMatches(key, entry)) { + return entry; } - return entry.vary[headerName] === key.headers[headerName]; - }))); + } + } + function varyMatches(key, entry) { + if (entry.vary == null) { + return true; + } + for (const headerName in entry.vary) { + if (Object.hasOwn(entry.vary, headerName) && !headerValueEquals(key.headers?.[headerName], entry.vary[headerName])) { + return false; + } + } + return true; + } + function headerValueEquals(lhs, rhs) { + if (lhs == null && rhs == null) { + return true; + } + if (lhs == null && rhs != null || lhs != null && rhs == null) { + return false; + } + if (Array.isArray(lhs) && Array.isArray(rhs)) { + if (lhs.length !== rhs.length) { + return false; + } + for (let i = 0; i < lhs.length; i++) { + if (lhs[i] !== rhs[i]) { + return false; + } + } + return true; + } + return lhs === rhs; } module2.exports = MemoryCacheStore; } @@ -37110,7 +37946,7 @@ var require_cache_revalidation_handler = __commonJS({ var CacheRevalidationHandler = class { #successful = false; /** - * @type {((boolean, any) => void) | null} + * @type {((success: boolean, context?: any, statusCode?: number, headers?: import('../../types/header.d.ts').IncomingHttpHeaders) => void) | null} */ #callback; /** @@ -37123,7 +37959,7 @@ var require_cache_revalidation_handler = __commonJS({ */ #allowErrorStatusCodes; /** - * @param {(boolean) => void} callback Function to call if the cached value is valid + * @param {(success: boolean, context?: any, statusCode?: number, headers?: import('../../types/header.d.ts').IncomingHttpHeaders) => void} callback Function to call if the cached value is valid * @param {import('../../types/dispatcher.d.ts').default.DispatchHandlers} handler * @param {boolean} allowErrorStatusCodes */ @@ -37145,7 +37981,7 @@ var require_cache_revalidation_handler = __commonJS({ onResponseStart(controller, statusCode, headers, statusMessage) { assert(this.#callback != null); this.#successful = statusCode === 304 || this.#allowErrorStatusCodes && statusCode >= 500 && statusCode <= 504; - this.#callback(this.#successful, this.#context); + this.#callback(this.#successful, this.#context, statusCode, headers); this.#callback = null; if (this.#successful) { return true; @@ -37175,6 +38011,12 @@ var require_cache_revalidation_handler = __commonJS({ return; } if (this.#callback) { + if (this.#allowErrorStatusCodes) { + this.#successful = true; + this.#callback(true, this.#context); + this.#callback = null; + return; + } this.#callback(false); this.#callback = null; } @@ -37199,8 +38041,9 @@ var require_cache3 = __commonJS({ var CacheHandler = require_cache_handler(); var MemoryCacheStore = require_memory_cache_store(); var CacheRevalidationHandler = require_cache_revalidation_handler(); - var { assertCacheStore, assertCacheMethods, makeCacheKey, normalizeHeaders, parseCacheControlHeader } = require_cache2(); + var { assertCacheStore, assertCacheMethods, makeCacheKey, normalizeHeaders, parseCacheControlHeader, isInvalidOrWildcardVaryHeader } = require_cache2(); var { AbortError } = require_errors2(); + var { parseHttpDate } = require_date(); function assertCacheOrigins(origins, name) { if (origins === void 0) return; if (!Array.isArray(origins)) { @@ -37215,6 +38058,37 @@ var require_cache3 = __commonJS({ } var nop = () => { }; + function trimOWS(value) { + return value.replace(/^[\t ]+|[\t ]+$/g, ""); + } + function arrayIncludes(array, value) { + for (let i = 0; i < array.length; i++) { + if (array[i] === value) { + return true; + } + } + return false; + } + function hasPragmaNoCache(headers) { + const pragma = headers?.pragma; + if (!pragma) { + return false; + } + const values = Array.isArray(pragma) ? pragma : [pragma]; + for (let i = 0; i < values.length; i++) { + const value = values[i]; + if (typeof value !== "string") { + continue; + } + const directives = value.split(","); + for (let j = 0; j < directives.length; j++) { + if (trimOWS(directives[j]).toLowerCase() === "no-cache") { + return true; + } + } + } + return false; + } function needsRevalidation(result, cacheControlDirectives, { headers = {} }) { if (cacheControlDirectives?.["no-cache"]) { return true; @@ -37227,10 +38101,58 @@ var require_cache3 = __commonJS({ } return false; } - function isStale(result, cacheControlDirectives) { + function staleResponseRequiresRevalidation(result, cacheType) { + return result.cacheControlDirectives?.["must-revalidate"] === true || cacheType === "shared" && (result.cacheControlDirectives?.["proxy-revalidate"] === true || // https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.2.10 + // s-maxage implies proxy-revalidate for shared caches. + result.cacheControlDirectives?.["s-maxage"] !== void 0); + } + function revalidationResponseDisallowsCachedReuse(cacheType, headers) { + if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) { + return true; + } + const cacheControl = headers["cache-control"]; + if (!cacheControl) { + return false; + } + const cacheControlDirectives = parseCacheControlHeader(cacheControl); + return cacheControlDirectives["no-store"] === true || cacheType === "shared" && cacheControlDirectives.private === true; + } + function revalidationResponseUpdatesCacheControl(headers) { + return headers["cache-control"] !== void 0; + } + function deleteCachedValue(store, cacheKey) { + try { + store.delete(cacheKey)?.catch?.(nop); + } catch { + } + } + function getUsableLastModified(headers) { + const lastModified = headers?.["last-modified"]; + if (typeof lastModified === "string" && parseHttpDate(lastModified)) { + return lastModified; + } + } + function makeRevalidationHeaders(opts, result) { + const headers = { + ...opts.headers, + "if-modified-since": getUsableLastModified(result.headers) ?? new Date(result.cachedAt).toUTCString() + }; + if (result.etag) { + headers["if-none-match"] = result.etag; + } + if (result.vary) { + for (const key in result.vary) { + if (result.vary[key] != null) { + headers[key] = result.vary[key]; + } + } + } + return headers; + } + function isStale(result, cacheControlDirectives, cacheType) { const now = Date.now(); if (now > result.staleAt) { - if (cacheControlDirectives?.["max-stale"]) { + if (!staleResponseRequiresRevalidation(result, cacheType) && cacheControlDirectives?.["max-stale"]) { const gracePeriod = result.staleAt + cacheControlDirectives["max-stale"] * 1e3; return now > gracePeriod; } @@ -37243,9 +38165,9 @@ var require_cache3 = __commonJS({ } return false; } - function withinStaleWhileRevalidateWindow(result) { + function withinStaleWhileRevalidateWindow(result, cacheType) { const staleWhileRevalidate = result.cacheControlDirectives?.["stale-while-revalidate"]; - if (!staleWhileRevalidate) { + if (!staleWhileRevalidate || staleResponseRequiresRevalidation(result, cacheType)) { return false; } const now = Date.now(); @@ -37355,32 +38277,17 @@ var require_cache3 = __commonJS({ return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)); } const age = Math.round((now - result.cachedAt) / 1e3); - if (reqCacheControl?.["max-age"] && age >= reqCacheControl["max-age"]) { - return dispatch(opts, handler); - } - const stale = isStale(result, reqCacheControl); - const revalidate = needsRevalidation(result, reqCacheControl, opts); + const requestMaxAgeExpired = reqCacheControl?.["max-age"] !== void 0 && age >= reqCacheControl["max-age"]; + const stale = requestMaxAgeExpired || isStale(result, reqCacheControl, globalOpts.type); + const revalidate = requestMaxAgeExpired || needsRevalidation(result, reqCacheControl, opts); if (stale || revalidate) { if (util.isStream(opts.body) && util.bodyLength(opts.body) !== 0) { return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)); } - if (!revalidate && withinStaleWhileRevalidateWindow(result)) { + if (!revalidate && withinStaleWhileRevalidateWindow(result, globalOpts.type)) { sendCachedValue(handler, opts, result, age, null, true); queueMicrotask(() => { - const headers2 = { - ...opts.headers, - "if-modified-since": new Date(result.cachedAt).toUTCString() - }; - if (result.etag) { - headers2["if-none-match"] = result.etag; - } - if (result.vary) { - for (const key in result.vary) { - if (result.vary[key] != null) { - headers2[key] = result.vary[key]; - } - } - } + const headers2 = makeRevalidationHeaders(opts, result); dispatch( { ...opts, @@ -37406,32 +38313,33 @@ var require_cache3 = __commonJS({ return true; } let withinStaleIfErrorThreshold = false; - const staleIfErrorExpiry = result.cacheControlDirectives["stale-if-error"] ?? reqCacheControl?.["stale-if-error"]; - if (staleIfErrorExpiry) { - withinStaleIfErrorThreshold = now < result.staleAt + staleIfErrorExpiry * 1e3; - } - const headers = { - ...opts.headers, - "if-modified-since": new Date(result.cachedAt).toUTCString() - }; - if (result.etag) { - headers["if-none-match"] = result.etag; - } - if (result.vary) { - for (const key in result.vary) { - if (result.vary[key] != null) { - headers[key] = result.vary[key]; - } + if (!staleResponseRequiresRevalidation(result, globalOpts.type)) { + const staleIfErrorExpiry = result.cacheControlDirectives["stale-if-error"] ?? reqCacheControl?.["stale-if-error"]; + if (staleIfErrorExpiry) { + withinStaleIfErrorThreshold = now < result.staleAt + staleIfErrorExpiry * 1e3; } } + const headers = makeRevalidationHeaders(opts, result); return dispatch( { ...opts, headers }, new CacheRevalidationHandler( - (success, context) => { + (success, context, statusCode, headers2) => { if (success) { + if (statusCode === 304) { + if (revalidationResponseDisallowsCachedReuse(globalOpts.type, headers2)) { + if (util.isStream(result.body)) { + result.body.on("error", nop).destroy(); + } + deleteCachedValue(globalOpts.store, cacheKey); + return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)); + } + if (revalidationResponseUpdatesCacheControl(headers2)) { + deleteCachedValue(globalOpts.store, cacheKey); + } + } sendCachedValue(handler, opts, result, age, context, stale); } else if (util.isStream(result.body)) { result.body.on("error", nop).destroy(); @@ -37473,13 +38381,22 @@ var require_cache3 = __commonJS({ cacheByDefault, type }; - const safeMethodsToNotCache = util.safeHTTPMethods.filter((method) => methods.includes(method) === false); + const safeMethodsToNotCache = []; + for (let i = 0; i < util.safeHTTPMethods.length; i++) { + const method = util.safeHTTPMethods[i]; + if (!arrayIncludes(methods, method)) { + safeMethodsToNotCache.push(method); + } + } return (dispatch) => { return (opts2, handler) => { - if (!opts2.origin || safeMethodsToNotCache.includes(opts2.method)) { + if (arrayIncludes(safeMethodsToNotCache, opts2.method)) { return dispatch(opts2, handler); } if (origins !== void 0) { + if (!opts2.origin) { + return dispatch(opts2, handler); + } const requestOrigin = opts2.origin.toString().toLowerCase(); let isAllowed = false; for (let i = 0; i < origins.length; i++) { @@ -37502,7 +38419,7 @@ var require_cache3 = __commonJS({ ...opts2, headers: normalizeHeaders(opts2) }; - const reqCacheControl = opts2.headers?.["cache-control"] ? parseCacheControlHeader(opts2.headers["cache-control"]) : void 0; + const reqCacheControl = opts2.headers?.["cache-control"] ? parseCacheControlHeader(opts2.headers["cache-control"]) : hasPragmaNoCache(opts2.headers) ? { "no-cache": true } : void 0; if (reqCacheControl?.["no-store"]) { return dispatch(opts2, handler); } @@ -37562,6 +38479,8 @@ var require_decompress = __commonJS({ var DecompressHandler = class extends DecoratorHandler { /** @type {Transform[]} */ #decompressors = []; + /** @type {Record | undefined} */ + #trailers; /** @type {Readonly} */ #skipStatusCodes; /** @type {boolean} */ @@ -37637,7 +38556,7 @@ var require_decompress = __commonJS({ const decompressor = this.#decompressors[0]; this.#setupDecompressorEvents(decompressor, controller); decompressor.on("end", () => { - super.onResponseEnd(controller, {}); + super.onResponseEnd(controller, this.#trailers); }); } /** @@ -37653,7 +38572,7 @@ var require_decompress = __commonJS({ super.onResponseError(controller, err); return; } - super.onResponseEnd(controller, {}); + super.onResponseEnd(controller, this.#trailers); }); } /** @@ -37731,6 +38650,7 @@ var require_decompress = __commonJS({ */ onResponseEnd(controller, trailers) { if (this.#decompressors.length > 0) { + this.#trailers = trailers; this.#decompressors[0].end(); this.#cleanupDecompressors(); return; @@ -37762,6 +38682,9 @@ var require_decompress = __commonJS({ } return (dispatch) => { return (opts, handler) => { + if (opts.method === "HEAD") { + return dispatch(opts, handler); + } const decompressHandler = new DecompressHandler(handler, options); return dispatch(opts, decompressHandler); }; @@ -38171,7 +39094,7 @@ var require_deduplicate = __commonJS({ const pendingRequests = /* @__PURE__ */ new Map(); return (dispatch) => { return (opts2, handler) => { - if (!opts2.origin || methods.includes(opts2.method) === false) { + if (opts2.upgrade || methods.includes(opts2.method) === false) { return dispatch(opts2, handler); } opts2 = { @@ -38569,7 +39492,12 @@ var require_sqlite_cache_store = __commonJS({ if (lhs.length !== rhs.length) { return false; } - return lhs.every((x, i) => x === rhs[i]); + for (let i = 0; i < lhs.length; i++) { + if (lhs[i] !== rhs[i]) { + return false; + } + } + return true; } return lhs === rhs; } @@ -39075,9 +40003,7 @@ var require_response2 = __commonJS({ // https://fetch.spec.whatwg.org/#dom-response-json static json(data, init = void 0) { webidl.argumentLengthCheck(arguments, 1, "Response.json"); - if (init !== null) { - init = webidl.converters.ResponseInit(init); - } + init = webidl.converters.ResponseInit(init); const bytes = textEncoder.encode( serializeJavascriptValueToJSONString(data) ); @@ -42296,8 +43222,42 @@ var require_util12 = __commonJS({ } } } + function isLetterOrDigit(code) { + return code >= 48 && code <= 57 || // 0-9 + code >= 65 && code <= 90 || // A-Z + code >= 97 && code <= 122; + } function validateCookieDomain(domain) { - if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { + if (domain === " ") { + return; + } + if (domain.length > 255) { + throw new Error("Invalid cookie domain"); + } + let labelLength = 0; + for (let i = 0; i < domain.length; ++i) { + const code = domain.charCodeAt(i); + if (code === 46) { + if (labelLength === 0) { + throw new Error("Invalid cookie domain"); + } + if (domain.charCodeAt(i - 1) === 45) { + throw new Error("Invalid cookie domain"); + } + labelLength = 0; + continue; + } + if (labelLength === 0 && !isLetterOrDigit(code)) { + throw new Error("Invalid cookie domain"); + } + if (!isLetterOrDigit(code) && code !== 45) { + throw new Error("Invalid cookie domain"); + } + if (++labelLength > 63) { + throw new Error("Invalid cookie domain"); + } + } + if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { throw new Error("Invalid cookie domain"); } } @@ -42380,7 +43340,11 @@ var require_util12 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - out.push(`${key.trim()}=${value.join("=")}`); + const trimmedKey = key.trim(); + const joinedValue = value.join("="); + validateCookieName(trimmedKey); + validateCookieValue(joinedValue); + out.push(`${trimmedKey}=${joinedValue}`); } return out.join("; "); } @@ -43980,6 +44944,8 @@ var require_websocket2 = __commonJS({ var { SendQueue } = require_sender2(); var { WebsocketFrameSend } = require_frame2(); var { channels } = require_diagnostics2(); + var kRef = /* @__PURE__ */ Symbol.for("nodejs.ref"); + var kUnref = /* @__PURE__ */ Symbol.for("nodejs.unref"); function getSocketAddress(socket) { if (typeof socket?.address === "function") { return socket.address(); @@ -43999,6 +44965,7 @@ var require_websocket2 = __commonJS({ #bufferedAmount = 0; #protocol = ""; #extensions = ""; + #refed = true; /** @type {SendQueue} */ #sendQueue; /** @type {Handler} */ @@ -44081,6 +45048,16 @@ var require_websocket2 = __commonJS({ this.#handler.readyState = _WebSocket.CONNECTING; this.#binaryType = "blob"; } + [kRef]() { + webidl.brandCheck(this, _WebSocket); + this.#refed = true; + this.#handler.socket?.ref?.(); + } + [kUnref]() { + webidl.brandCheck(this, _WebSocket); + this.#refed = false; + this.#handler.socket?.unref?.(); + } /** * @see https://websockets.spec.whatwg.org/#dom-websocket-close * @param {number|undefined} code @@ -44242,6 +45219,9 @@ var require_websocket2 = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { this.#handler.socket = response.socket; + if (!this.#refed) { + this.#handler.socket.unref?.(); + } const maxFragments = this.#handler.controller.dispatcher?.webSocketOptions?.maxFragments; const maxPayloadSize = this.#handler.controller.dispatcher?.webSocketOptions?.maxPayloadSize; const parser = new ByteParser(this.#handler, parsedExtensions, { diff --git a/package-lock.json b/package-lock.json index 5ebc14e..98cef75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,11 +16,11 @@ "@actions/io": "^3.0.2", "@actions/tool-cache": "^4.0.0", "@renovatebot/pep440": "^5.0.0", - "smol-toml": "^1.7.0", - "undici": "^8.7.0" + "smol-toml": "^1.7.1", + "undici": "^8.10.0" }, "devDependencies": { - "@biomejs/biome": "^2.5.4", + "@biomejs/biome": "^2.5.6", "@types/js-yaml": "^4.0.9", "@types/node": "^26.1.1", "@types/semver": "^7.7.1", @@ -863,9 +863,9 @@ "license": "MIT" }, "node_modules/@biomejs/biome": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.4.tgz", - "integrity": "sha512-xy5FNE5kQJKyK5MR1gJy6ztXYx4WBAbYGlK04lMEgmyPRWKybY9NFwiG9yo0XdzOU8Xvhj41u034J1ywfoWfMw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.6.tgz", + "integrity": "sha512-lxVNjv7UF6KfhMJfL9gaUHbWdJdHbsAj6OSmwSYNdhRuG67NxNQ4Xdvh3TUxsSK9sBzJBQhEJj3AopmmNJ5pSA==", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -879,20 +879,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.5.4", - "@biomejs/cli-darwin-x64": "2.5.4", - "@biomejs/cli-linux-arm64": "2.5.4", - "@biomejs/cli-linux-arm64-musl": "2.5.4", - "@biomejs/cli-linux-x64": "2.5.4", - "@biomejs/cli-linux-x64-musl": "2.5.4", - "@biomejs/cli-win32-arm64": "2.5.4", - "@biomejs/cli-win32-x64": "2.5.4" + "@biomejs/cli-darwin-arm64": "2.5.6", + "@biomejs/cli-darwin-x64": "2.5.6", + "@biomejs/cli-linux-arm64": "2.5.6", + "@biomejs/cli-linux-arm64-musl": "2.5.6", + "@biomejs/cli-linux-x64": "2.5.6", + "@biomejs/cli-linux-x64-musl": "2.5.6", + "@biomejs/cli-win32-arm64": "2.5.6", + "@biomejs/cli-win32-x64": "2.5.6" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.4.tgz", - "integrity": "sha512-4o3NFRobXHynkgcFVrlZsoDAFtF2ldlEGN8sORSws5ZQqyY4PXnPUIylu4ksfyHuwkfvDREuWh3JK+niRwGq3w==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-zMOLZP4oMrjh6m1zcSj1ud2awUPgTuMVbmQhYYWL7J8HwCnbHHBvTm7VBTRuY7epT5bez76IpKYQ11ZAqHFlnw==", "cpu": [ "arm64" ], @@ -907,9 +907,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.4.tgz", - "integrity": "sha512-D32P5HkU2Y6PySuC/WsVDTOgsDwVFmujzhhhOQjajtATpVWFDXuVd3oRbsWNSEA+aaFzyzZm22szsyydBYlSyQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.6.tgz", + "integrity": "sha512-JAC1VqzvO7Th5ZplU0G2uGfkZbxEe9uDDektPAhF0JLusoz1w+T4okp2bkykI0bbaO2vslKiRfj4gU43JaGreA==", "cpu": [ "x64" ], @@ -924,9 +924,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.4.tgz", - "integrity": "sha512-pSEfW7B8kTsXUjUxC1xVVK+y85Ht3C5XxZ9gclmC7/3Ku9Vqz8jmI7k0p/BNIjQ6t4sFERI2sFeH73ybiZl6YQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.6.tgz", + "integrity": "sha512-6XsYwCFkp5sMxl85ffhgeGpGgs6A7dRYFnkceZ7WVxvycuTnGdD5xa534Z3xfrBQ0JCMK/mujT6ZNPJoghedwg==", "cpu": [ "arm64" ], @@ -941,9 +941,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.4.tgz", - "integrity": "sha512-Rpm5/AT1m+DlJmUoYvS4/vXc+0tXJPJ2NQz25TGPyHVF5JrWy75PE0GH6kVxsKtQDuCH4OgzquZq0R4kj/wCVg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-eUa3jeeYvfMt19LBeh6E5PUZpxnTC4JqNWo+EDjTtQjAr2xLGnWaxACtVU1DQqmHYbvThlJzLX+ZsYgrqh2qVw==", "cpu": [ "arm64" ], @@ -958,9 +958,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.4.tgz", - "integrity": "sha512-FNxojWJkL7EajAuzBgoLe0T2G0y112M4lBrDIFl/DomFTx8yqenYOIdsRLNXvOvBBofE8hJi85LjzLmBDpY7/Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.6.tgz", + "integrity": "sha512-Pop9VXCFUhFTMfFefZ39S+u2rOPyNp5iHlxbZRwXGACHLy2r0jjiRgJHmaEKJzL3SyxlVeGShXhvvElvWowonA==", "cpu": [ "x64" ], @@ -975,9 +975,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.4.tgz", - "integrity": "sha512-aby/PohmmgbShcHqFsZVzG8H6D98+P+A6xRWRrQcLW1pCjabcov5UUlke4UqNQBYTkDQav+jB4zyyDDeKB2GaA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-2Vp13QdKysH3HIWLaYLhUUwbK+jbZonJD1K+Lr0d0RO4wH7mkYd43vJixEDm8cUWrowoRz4UUHF1nm9Ae7ym8A==", "cpu": [ "x64" ], @@ -992,9 +992,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.4.tgz", - "integrity": "sha512-emoXexPZIPAZkz2RKmA95WJUqK3I5MJNYtwEbL5ESciRzhmFMMyekDhNG8hpeOaK+ZGRDxAU4wvGuA5IHQ0h0w==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.6.tgz", + "integrity": "sha512-tDGshcm6BdkZOCGnTDX0Y8/U4IfBSlnUU7T56nNDuPEfed+aHg+u8G36NB43fJVl0Os6+QURXIE1yuD7AaEofA==", "cpu": [ "arm64" ], @@ -1009,9 +1009,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.4.tgz", - "integrity": "sha512-U1jaluLw1qQc2Tx7/CeSoL9N5XcqIH+GWjpUAy1ouB5nVjSCMNO+NNHdY3RAs8zxNurLWAdj6pehQdCA2zyU+Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.6.tgz", + "integrity": "sha512-WN05KwXnTO/2J45RQPvzZMXf7tZUIofHoR35xIPfCo7pQ2RFidxI8sfb5mGsaTxdMmEOzHzOPRCdA5/fCpc7xQ==", "cpu": [ "x64" ], @@ -4994,9 +4994,9 @@ } }, "node_modules/smol-toml": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", - "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.1.tgz", + "integrity": "sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -5436,9 +5436,9 @@ } }, "node_modules/undici": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.7.0.tgz", - "integrity": "sha512-N7iQtfyLhIMOFgQubvmLV26svHpO0bqKnAiWotTQCVKCmWrcGbBotPuW1x+xwYZ2VHdSTVUfPQQnlEt1/LouTQ==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.0.tgz", + "integrity": "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==", "license": "MIT", "engines": { "node": ">=22.19.0" @@ -6377,74 +6377,74 @@ "dev": true }, "@biomejs/biome": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.4.tgz", - "integrity": "sha512-xy5FNE5kQJKyK5MR1gJy6ztXYx4WBAbYGlK04lMEgmyPRWKybY9NFwiG9yo0XdzOU8Xvhj41u034J1ywfoWfMw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.6.tgz", + "integrity": "sha512-lxVNjv7UF6KfhMJfL9gaUHbWdJdHbsAj6OSmwSYNdhRuG67NxNQ4Xdvh3TUxsSK9sBzJBQhEJj3AopmmNJ5pSA==", "dev": true, "requires": { - "@biomejs/cli-darwin-arm64": "2.5.4", - "@biomejs/cli-darwin-x64": "2.5.4", - "@biomejs/cli-linux-arm64": "2.5.4", - "@biomejs/cli-linux-arm64-musl": "2.5.4", - "@biomejs/cli-linux-x64": "2.5.4", - "@biomejs/cli-linux-x64-musl": "2.5.4", - "@biomejs/cli-win32-arm64": "2.5.4", - "@biomejs/cli-win32-x64": "2.5.4" + "@biomejs/cli-darwin-arm64": "2.5.6", + "@biomejs/cli-darwin-x64": "2.5.6", + "@biomejs/cli-linux-arm64": "2.5.6", + "@biomejs/cli-linux-arm64-musl": "2.5.6", + "@biomejs/cli-linux-x64": "2.5.6", + "@biomejs/cli-linux-x64-musl": "2.5.6", + "@biomejs/cli-win32-arm64": "2.5.6", + "@biomejs/cli-win32-x64": "2.5.6" } }, "@biomejs/cli-darwin-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.4.tgz", - "integrity": "sha512-4o3NFRobXHynkgcFVrlZsoDAFtF2ldlEGN8sORSws5ZQqyY4PXnPUIylu4ksfyHuwkfvDREuWh3JK+niRwGq3w==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-zMOLZP4oMrjh6m1zcSj1ud2awUPgTuMVbmQhYYWL7J8HwCnbHHBvTm7VBTRuY7epT5bez76IpKYQ11ZAqHFlnw==", "dev": true, "optional": true }, "@biomejs/cli-darwin-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.4.tgz", - "integrity": "sha512-D32P5HkU2Y6PySuC/WsVDTOgsDwVFmujzhhhOQjajtATpVWFDXuVd3oRbsWNSEA+aaFzyzZm22szsyydBYlSyQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.6.tgz", + "integrity": "sha512-JAC1VqzvO7Th5ZplU0G2uGfkZbxEe9uDDektPAhF0JLusoz1w+T4okp2bkykI0bbaO2vslKiRfj4gU43JaGreA==", "dev": true, "optional": true }, "@biomejs/cli-linux-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.4.tgz", - "integrity": "sha512-pSEfW7B8kTsXUjUxC1xVVK+y85Ht3C5XxZ9gclmC7/3Ku9Vqz8jmI7k0p/BNIjQ6t4sFERI2sFeH73ybiZl6YQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.6.tgz", + "integrity": "sha512-6XsYwCFkp5sMxl85ffhgeGpGgs6A7dRYFnkceZ7WVxvycuTnGdD5xa534Z3xfrBQ0JCMK/mujT6ZNPJoghedwg==", "dev": true, "optional": true }, "@biomejs/cli-linux-arm64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.4.tgz", - "integrity": "sha512-Rpm5/AT1m+DlJmUoYvS4/vXc+0tXJPJ2NQz25TGPyHVF5JrWy75PE0GH6kVxsKtQDuCH4OgzquZq0R4kj/wCVg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-eUa3jeeYvfMt19LBeh6E5PUZpxnTC4JqNWo+EDjTtQjAr2xLGnWaxACtVU1DQqmHYbvThlJzLX+ZsYgrqh2qVw==", "dev": true, "optional": true }, "@biomejs/cli-linux-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.4.tgz", - "integrity": "sha512-FNxojWJkL7EajAuzBgoLe0T2G0y112M4lBrDIFl/DomFTx8yqenYOIdsRLNXvOvBBofE8hJi85LjzLmBDpY7/Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.6.tgz", + "integrity": "sha512-Pop9VXCFUhFTMfFefZ39S+u2rOPyNp5iHlxbZRwXGACHLy2r0jjiRgJHmaEKJzL3SyxlVeGShXhvvElvWowonA==", "dev": true, "optional": true }, "@biomejs/cli-linux-x64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.4.tgz", - "integrity": "sha512-aby/PohmmgbShcHqFsZVzG8H6D98+P+A6xRWRrQcLW1pCjabcov5UUlke4UqNQBYTkDQav+jB4zyyDDeKB2GaA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-2Vp13QdKysH3HIWLaYLhUUwbK+jbZonJD1K+Lr0d0RO4wH7mkYd43vJixEDm8cUWrowoRz4UUHF1nm9Ae7ym8A==", "dev": true, "optional": true }, "@biomejs/cli-win32-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.4.tgz", - "integrity": "sha512-emoXexPZIPAZkz2RKmA95WJUqK3I5MJNYtwEbL5ESciRzhmFMMyekDhNG8hpeOaK+ZGRDxAU4wvGuA5IHQ0h0w==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.6.tgz", + "integrity": "sha512-tDGshcm6BdkZOCGnTDX0Y8/U4IfBSlnUU7T56nNDuPEfed+aHg+u8G36NB43fJVl0Os6+QURXIE1yuD7AaEofA==", "dev": true, "optional": true }, "@biomejs/cli-win32-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.4.tgz", - "integrity": "sha512-U1jaluLw1qQc2Tx7/CeSoL9N5XcqIH+GWjpUAy1ouB5nVjSCMNO+NNHdY3RAs8zxNurLWAdj6pehQdCA2zyU+Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.6.tgz", + "integrity": "sha512-WN05KwXnTO/2J45RQPvzZMXf7tZUIofHoR35xIPfCo7pQ2RFidxI8sfb5mGsaTxdMmEOzHzOPRCdA5/fCpc7xQ==", "dev": true, "optional": true }, @@ -9035,9 +9035,9 @@ "dev": true }, "smol-toml": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", - "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==" + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.1.tgz", + "integrity": "sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==" }, "source-map": { "version": "0.6.1", @@ -9303,9 +9303,9 @@ "optional": true }, "undici": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.7.0.tgz", - "integrity": "sha512-N7iQtfyLhIMOFgQubvmLV26svHpO0bqKnAiWotTQCVKCmWrcGbBotPuW1x+xwYZ2VHdSTVUfPQQnlEt1/LouTQ==" + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.0.tgz", + "integrity": "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==" }, "undici-types": { "version": "8.3.0", diff --git a/package.json b/package.json index b270a32..9408c19 100644 --- a/package.json +++ b/package.json @@ -35,11 +35,11 @@ "@actions/io": "^3.0.2", "@actions/tool-cache": "^4.0.0", "@renovatebot/pep440": "^5.0.0", - "smol-toml": "^1.7.0", - "undici": "^8.7.0" + "smol-toml": "^1.7.1", + "undici": "^8.10.0" }, "devDependencies": { - "@biomejs/biome": "^2.5.4", + "@biomejs/biome": "^2.5.6", "@types/js-yaml": "^4.0.9", "@types/node": "^26.1.1", "@types/semver": "^7.7.1",