From 7e8ef3489c60f0f518b8b7948361725ec39f2d5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 04:30:31 +0000 Subject: [PATCH 1/2] Bump undici Bumps and [undici](https://github.com/nodejs/undici). These dependencies needed to be updated together. Updates `undici` from 6.28.0 to 6.29.0 - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v6.28.0...v6.29.0) Updates `undici` from 7.29.0 to 7.30.0 - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v6.28.0...v6.29.0) --- updated-dependencies: - dependency-name: undici dependency-version: 6.29.0 dependency-type: indirect - dependency-name: undici dependency-version: 7.30.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3322f173..104165db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -983,9 +983,9 @@ } }, "node_modules/@octokit/action/node_modules/undici": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", - "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.0.tgz", + "integrity": "sha512-dkrQXeHSaoamnItlYbmzG0wFYrM0ZwDxCIg0A7aKjTyyhh9svRzCNFEzV+Vm05/yehjCzjDZ31KXfGEjYSztDQ==", "license": "MIT", "engines": { "node": ">=20.18.1" @@ -7377,9 +7377,9 @@ } }, "node_modules/undici": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz", - "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==", + "version": "6.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz", + "integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==", "license": "MIT", "engines": { "node": ">=18.17" From 345bbc466f5a8ee74ffffa9f430b7f4518d2ae1d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 04:31:06 +0000 Subject: [PATCH 2/2] Rebuild --- dist/query.js | 1463 ++++++++++++++++++++++------- dist/update-repo-task-status.js | 1463 ++++++++++++++++++++++------- dist/update-repo-task-statuses.js | 1463 ++++++++++++++++++++++------- 3 files changed, 3327 insertions(+), 1062 deletions(-) diff --git a/dist/query.js b/dist/query.js index e532549e..4c7d945a 100644 --- a/dist/query.js +++ b/dist/query.js @@ -1854,10 +1854,66 @@ var require_request = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number|null} statusCode + * @param {Buffer[]|null} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (statusCode !== null) { + this.#publishUpgradeHeaders(statusCode, headers, statusText); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (statusCode !== null) { + this.#publishUpgradeTrailers(); + } + } + return result; + } + /** + * @param {number} statusCode + * @param {import('node:http2').IncomingHttpHeaders} headers + * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders + * @param {string} [statusText] + */ + onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { + assert(!this.aborted); + assert(this.completed); + if (channels.headers.hasSubscribers) { + this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); + } + this.#publishUpgradeTrailers(); + } + /** + * @param {Error} error + */ + onUpgradeError(error2) { + assert(!this.aborted); + assert(this.completed); + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error: error2 }); + } + } + /** + * @param {number} statusCode + * @param {Buffer[]} headers + * @param {string} statusText + */ + #publishUpgradeHeaders(statusCode, headers, statusText) { + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + } + #publishUpgradeTrailers() { + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } } onComplete(trailers) { this.onFinally(); @@ -6000,7 +6056,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6025,9 +6081,10 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); - } catch (err) { - util3.destroy(socket, err); + request2.onUpgrade(statusCode, headers, socket, statusText); + } catch (error2) { + util3.errorRequest(client, request2, error2); + util3.destroy(socket, error2); } client[kResume](); } @@ -6319,21 +6376,20 @@ var require_client_h1 = __commonJS({ } function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; } function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } function resumeH1(client) { const socket = client[kSocket]; @@ -6431,11 +6487,17 @@ var require_client_h1 = __commonJS({ } const socket = client[kSocket]; clearIdleSocketValidation(socket); - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error2) => { + if (request2.aborted) { return; } - util3.errorRequest(client, request2, err || new RequestAbortedError()); + if (request2.completed) { + if (request2.upgrade || request2.method === "CONNECT") { + util3.destroy(socket, new InformationalError("aborted")); + } + return; + } + util3.errorRequest(client, request2, error2 || new RequestAbortedError()); util3.destroy(body); util3.destroy(socket, new InformationalError("aborted")); }; @@ -6791,6 +6853,7 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports2, module2) { "use strict"; var assert = require("node:assert"); + var { errorMonitor } = require("node:events"); var { pipeline: pipeline3 } = require("node:stream"); var util3 = require_util(); var { @@ -6851,6 +6914,10 @@ var require_client_h2 = __commonJS({ } return result; } + function parseH2ResponseHeaders(headers) { + const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; + return parseH2Headers(realHeaders); + } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7014,16 +7081,22 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error2) => { + if (request2.aborted) { return; } - err = err || new RequestAbortedError(); - util3.errorRequest(client, request2, err); + if (request2.completed) { + if (method === "CONNECT" && stream3 != null) { + util3.destroy(stream3, error2 || new RequestAbortedError()); + } + return; + } + error2 = error2 || new RequestAbortedError(); + util3.errorRequest(client, request2, error2); if (stream3 != null) { - util3.destroy(stream3, err); + util3.destroy(stream3, error2); } - util3.destroy(body, err); + util3.destroy(body, error2); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7038,18 +7111,42 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream3 = session.request(headers, { endStream: false, signal }); - if (stream3.id && !stream3.pending) { - request2.onUpgrade(null, null, stream3); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - } else { - stream3.once("ready", () => { + let upgradeResponseFinished = false; + const onResponse = (headers2) => { + upgradeResponseFinished = true; + stream3.off(errorMonitor, onUpgradeError); + request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); + }; + const onUpgradeError = (error2) => { + upgradeResponseFinished = true; + stream3.off("response", onResponse); + request2.onUpgradeError(error2); + }; + const onReady = () => { + try { request2.onUpgrade(null, null, stream3); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - }); - } + } catch (error2) { + stream3.off("response", onResponse); + abort(error2); + return; + } + if (request2.aborted) { + return; + } + stream3.off("error", abort); + stream3.once(errorMonitor, onUpgradeError); + client[kQueue][client[kRunningIdx]++] = null; + }; + stream3.once("response", onResponse); + stream3.once("error", abort); + ++session[kOpenStreams]; + onReady(); stream3.once("close", () => { + if (!upgradeResponseFinished && request2.completed) { + stream3.off("response", onResponse); + stream3.off(errorMonitor, onUpgradeError); + request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream3.rstCode}`)); + } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -9032,6 +9129,7 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; + this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9041,6 +9139,17 @@ var require_retry_handler = __commonJS({ } }); } + checkpointResponseEnd(headers, resume) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + } + this.resume = this.end != null ? resume : null; + } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9102,7 +9211,9 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (this.retryOpts.statusCodes.includes(statusCode) === false) { + if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { + this.headersSent = true; + this.checkpointResponseEnd(headers, resume); return this.handler.onHeaders( statusCode, rawHeaders, @@ -9157,8 +9268,15 @@ var require_retry_handler = __commonJS({ return false; } const { start, size, end = size - 1 } = contentRange; - assert(this.start === start, "content-range mismatch"); - assert(this.end == null || this.end === end, "content-range mismatch"); + if (this.start !== start || this.end != null && this.end !== end) { + this.abort( + new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } this.resume = resume; return true; } @@ -9166,6 +9284,7 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { + this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9197,6 +9316,7 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; + this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9224,7 +9344,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body)) { + if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -17110,7 +17230,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17258,6 +17378,7 @@ var require_permessage_deflate = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -18169,6 +18290,40 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18188,10 +18343,13 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -18222,63 +18380,30 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -18287,17 +18412,16 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -18313,43 +18437,42 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -18374,12 +18497,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { @@ -43228,10 +43459,27 @@ var require_request3 = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number} statusCode + * @param {Buffer[]|string[]} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } + } + return result; } onComplete(trailers) { this.onFinally(); @@ -47528,7 +47776,13 @@ var require_client_h12 = __commonJS({ function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm2() : void 0; let mod; - let useWasmSIMD = process.arch !== "ppc64"; + let useWasmSIMD = true; + if (process.arch === "ppc64") { + const [major, minor] = process.versions.node.split(".").map((n) => parseInt(n, 10)); + if (major < 24 || major === 24 && minor < 12) { + useWasmSIMD = false; + } + } if (process.env.UNDICI_NO_WASM_SIMD === "1") { useWasmSIMD = false; } else if (process.env.UNDICI_NO_WASM_SIMD === "0") { @@ -47882,7 +48136,7 @@ var require_client_h12 = __commonJS({ * @param {Buffer} head */ onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -47907,8 +48161,9 @@ var require_client_h12 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); + request2.onUpgrade(statusCode, headers, socket, statusText); } catch (err) { + util3.errorRequest(client, request2, err); util3.destroy(socket, err); } client[kResume](); @@ -48239,21 +48494,20 @@ var require_client_h12 = __commonJS({ } function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; } function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } function resumeH1(client) { const socket = client[kSocket]; @@ -48743,7 +48997,9 @@ var require_client_h22 = __commonJS({ RequestAbortedError, SocketError, InformationalError, - InvalidArgumentError + InvalidArgumentError, + HeadersTimeoutError, + BodyTimeoutError } = require_errors2(); var { kUrl, @@ -48768,6 +49024,7 @@ var require_client_h22 = __commonJS({ kHTTPContext, kClosed, kBodyTimeout, + kHeadersTimeout, kEnableConnectProtocol, kRemoteSettings, kHTTP2Stream, @@ -48904,7 +49161,7 @@ var require_client_h22 = __commonJS({ function resumeH2(client) { const socket = client[kSocket]; if (socket?.destroyed === false) { - if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) { + if (client[kSize] === 0) { socket.unref(); client[kHTTP2Session].unref(); } else { @@ -48970,6 +49227,24 @@ var require_client_h22 = __commonJS({ this.destroy(err); util3.destroy(this[kSocket], err); } + function completeRequest(client, request2, resetPendingIdx = false) { + const queue = client[kQueue]; + const runningIdx = client[kRunningIdx]; + if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request2) { + queue[runningIdx] = null; + client[kRunningIdx] = runningIdx + 1; + return; + } + const index = queue.indexOf(request2, runningIdx); + if (index === -1 || index >= client[kPendingIdx]) { + return; + } + queue.splice(index, 1); + client[kPendingIdx]--; + if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) { + client[kPendingIdx] = client[kRunningIdx]; + } + } function onHttp2SessionGoAway(errorCode) { const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${errorCode}`, util3.getSocketInfo(this[kSocket])); const client = this[kClient]; @@ -48981,7 +49256,9 @@ var require_client_h22 = __commonJS({ if (client[kRunningIdx] < client[kQueue].length) { const request2 = client[kQueue][client[kRunningIdx]]; client[kQueue][client[kRunningIdx]++] = null; - util3.errorRequest(client, request2, err); + if (request2 != null) { + util3.errorRequest(client, request2, err); + } client[kPendingIdx] = client[kRunningIdx]; } assert(client[kRunning] === 0); @@ -49004,7 +49281,9 @@ var require_client_h22 = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util3.errorRequest(client, request2, err); + if (request2 != null) { + util3.errorRequest(client, request2, err); + } } } } @@ -49036,7 +49315,8 @@ var require_client_h22 = __commonJS({ return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; } function writeH2(client, request2) { - const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout]; + const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout]; + const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout]; const session = client[kHTTP2Session]; const { method, path: path8, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2; let { body } = request2; @@ -49084,6 +49364,7 @@ var require_client_h22 = __commonJS({ stream3.removeAllListeners("data"); stream3.close(); client[kOnError](err); + completeRequest(client, request2); client[kResume](); } util3.destroy(body, err); @@ -49114,11 +49395,16 @@ var require_client_h22 = __commonJS({ } stream3 = session.request(headers, { endStream: false, signal }); stream3[kHTTP2Stream] = true; + ++session[kOpenStreams]; stream3.once("response", (headers2, _flags) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; - request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream3); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + try { + request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream3); + } catch (err) { + abort(err); + return; + } + completeRequest(client, request2); }); stream3.on("error", () => { if (stream3.rstCode === NGHTTP2_REFUSED_STREAM || stream3.rstCode === NGHTTP2_CANCEL) { @@ -49129,22 +49415,28 @@ var require_client_h22 = __commonJS({ session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream3.setTimeout(requestTimeout); + stream3.setTimeout(headersTimeout); return true; } stream3 = session.request(headers, { endStream: false, signal }); stream3[kHTTP2Stream] = true; + ++session[kOpenStreams]; stream3.on("response", (headers2) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; - request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream3); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + try { + request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream3); + } catch (err) { + abort(err); + return; + } + completeRequest(client, request2); }); + stream3.on("error", abort); stream3.once("close", () => { session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream3.setTimeout(requestTimeout); + stream3.setTimeout(headersTimeout); return true; } headers[HTTP2_HEADER_PATH] = path8; @@ -49202,12 +49494,13 @@ var require_client_h22 = __commonJS({ writeBodyH2(); } ++session[kOpenStreams]; - stream3.setTimeout(requestTimeout); + stream3.setTimeout(headersTimeout); let responseReceived = false; stream3.once("response", (headers2) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; request2.onResponseStarted(); responseReceived = true; + stream3.setTimeout(bodyTimeout); if (request2.aborted) { stream3.removeAllListeners("data"); return; @@ -49230,12 +49523,11 @@ var require_client_h22 = __commonJS({ if (!request2.aborted && !request2.completed) { request2.onComplete({}); } - client[kQueue][client[kRunningIdx]++] = null; + completeRequest(client, request2); client[kResume](); } else { abort(new InformationalError("HTTP/2: stream half-closed (remote)")); - client[kQueue][client[kRunningIdx]++] = null; - client[kPendingIdx] = client[kRunningIdx]; + completeRequest(client, request2, true); client[kResume](); } }); @@ -49245,6 +49537,9 @@ var require_client_h22 = __commonJS({ if (session[kOpenStreams] === 0) { session.unref(); } + if (!request2.aborted && !request2.completed) { + abort(new InformationalError("HTTP/2: stream closed before the response was complete")); + } }); stream3.once("error", function(err) { stream3.removeAllListeners("data"); @@ -49258,7 +49553,7 @@ var require_client_h22 = __commonJS({ stream3.removeAllListeners("data"); }); stream3.on("timeout", () => { - const err = new InformationalError(`HTTP/2: "stream timeout after ${requestTimeout}"`); + const err = responseReceived ? new BodyTimeoutError(`HTTP/2: "body timeout after ${bodyTimeout}"`) : new HeadersTimeoutError(`HTTP/2: "headers timeout after ${headersTimeout}"`); stream3.removeAllListeners("data"); session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) { @@ -49756,7 +50051,9 @@ var require_client2 = __commonJS({ const requests = this[kQueue].splice(this[kPendingIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util3.errorRequest(this, request2, err); + if (request2 != null) { + util3.errorRequest(this, request2, err); + } } const callback = () => { if (this[kClosedResolve]) { @@ -49781,7 +50078,9 @@ var require_client2 = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util3.errorRequest(client, request2, err); + if (request2 != null) { + util3.errorRequest(client, request2, err); + } } assert(client[kSize] === 0); } @@ -50374,12 +50673,14 @@ var require_balanced_pool2 = __commonJS({ return new Pool(origin, opts); } var BalancedPool = class extends PoolBase { - constructor(upstreams = [], { factory = defaultFactory, ...opts } = {}) { + constructor(upstreams = [], { factory = defaultFactory, connect, tls, ...opts } = {}) { if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } super(opts); - this[kOptions] = { ...util3.deepClone(opts) }; + if (connect && typeof connect !== "function") connect = { ...connect }; + if (tls && typeof tls !== "function") tls = { ...tls }; + this[kOptions] = { ...util3.deepClone(opts), connect, tls }; this[kOptions].interceptors = opts.interceptors ? { ...opts.interceptors } : void 0; this[kIndex] = -1; this[kCurrentWeight] = 0; @@ -51843,6 +52144,55 @@ var require_retry_handler2 = __commonJS({ }); } } + var RetryController = class { + #paused = false; + #target = null; + set target(target) { + this.#target = target; + if (this.#paused) { + target?.pause(); + } + } + get target() { + return this.#target; + } + pause() { + this.#paused = true; + this.#target?.pause(); + } + resume() { + this.#paused = false; + this.#target?.resume(); + } + abort(reason) { + this.#target?.abort(reason); + } + get paused() { + return this.#paused || (this.#target?.paused ?? false); + } + get aborted() { + return this.#target?.aborted ?? false; + } + get reason() { + return this.#target?.reason ?? null; + } + get rawHeaders() { + return this.#target?.rawHeaders ?? null; + } + set rawHeaders(value) { + if (this.#target) { + this.#target.rawHeaders = value; + } + } + get rawTrailers() { + return this.#target?.rawTrailers ?? null; + } + set rawTrailers(value) { + if (this.#target) { + this.#target.rawTrailers = value; + } + } + }; var RetryHandler = class _RetryHandler { constructor(opts, { dispatch, handler: handler2 }) { const { retryOptions, ...dispatchOpts } = opts; @@ -51897,12 +52247,18 @@ var require_retry_handler2 = __commonJS({ this.start = 0; this.end = null; this.etag = null; + this.controllerProxy = new RetryController(); } onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err) { if (this.retryOpts.throwOnError) { if (this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + if (this.headersSent) { + this.handler.onResponseError?.(this.controllerProxy, err); + } else { + this.headersSent = true; + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + } } else { this.error = err; } @@ -51910,13 +52266,19 @@ var require_retry_handler2 = __commonJS({ } if (isDisturbed(this.opts.body)) { this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); return; } function shouldRetry(passedErr) { if (passedErr) { - this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + if (this.headersSent) { + this.handler.onResponseError?.(this.controllerProxy, passedErr); + } else { + this.headersSent = true; + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + } controller.resume(); return; } @@ -51933,13 +52295,25 @@ var require_retry_handler2 = __commonJS({ shouldRetry.bind(this) ); } + checkpointResponseEnd(headers) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + this.resume = this.end != null; + } + } onRequestStart(controller, context) { + this.controllerProxy.target = controller; if (!this.headersSent) { - this.handler.onRequestStart?.(controller, context); + this.handler.onRequestStart?.(this.controllerProxy, context); } } - onRequestUpgrade(controller, statusCode, headers, socket) { - this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket); + onRequestUpgrade(_controller, statusCode, headers, socket) { + this.handler.onRequestUpgrade?.(this.controllerProxy, statusCode, headers, socket); } static [kRetryHandlerDefaultRetry](err, { state, opts }, cb) { const { statusCode, code, headers } = err; @@ -52013,8 +52387,12 @@ var require_retry_handler2 = __commonJS({ } 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"); + if (this.start !== start || this.end != null && this.end !== end) { + throw new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }); + } return; } if (this.end == null) { @@ -52023,7 +52401,7 @@ var require_retry_handler2 = __commonJS({ if (range == null) { this.headersSent = true; this.handler.onResponseStart?.( - controller, + this.controllerProxy, statusCode, headers, statusMessage @@ -52056,7 +52434,7 @@ var require_retry_handler2 = __commonJS({ } this.headersSent = true; this.handler.onResponseStart?.( - controller, + this.controllerProxy, statusCode, headers, statusMessage @@ -52068,24 +52446,24 @@ var require_retry_handler2 = __commonJS({ }); } } - onResponseData(controller, chunk) { + onResponseData(_controller, chunk) { if (this.error) { return; } this.start += chunk.length; - this.handler.onResponseData?.(controller, chunk); + this.handler.onResponseData?.(this.controllerProxy, chunk); } - onResponseEnd(controller, trailers) { + onResponseEnd(_controller, trailers) { if (this.error && this.retryOpts.throwOnError) { throw this.error; } if (!this.error) { this.retryCount = 0; - return this.handler.onResponseEnd?.(controller, trailers); + return this.handler.onResponseEnd?.(this.controllerProxy, trailers); } - this.retry(controller); + this.retry(); } - retry(controller) { + retry() { if (this.start !== 0) { const headers = { range: `bytes=${this.start}-${this.end ?? ""}` }; if (this.etag != null) { @@ -52103,20 +52481,20 @@ var require_retry_handler2 = __commonJS({ this.retryCountCheckpoint = this.retryCount; this.dispatch(this.opts, this); } catch (err) { - this.handler.onResponseError?.(controller, err); + this.handler.onResponseError?.(this.controllerProxy, err); } } onResponseError(controller, err) { - if (controller?.aborted || isDisturbed(this.opts.body)) { - this.handler.onResponseError?.(controller, err); + if (controller?.aborted || isDisturbed(this.opts.body) || this.headersSent && !this.resume) { + this.handler.onResponseError?.(this.controllerProxy, err); return; } function shouldRetry(returnedErr) { if (!returnedErr) { - this.retry(controller); + this.retry(); return; } - this.handler?.onResponseError?.(controller, returnedErr); + this.handler?.onResponseError?.(this.controllerProxy, returnedErr); } if (this.retryCount - this.retryCountCheckpoint > 0) { this.retryCount = this.retryCountCheckpoint + (this.retryCount - this.retryCountCheckpoint); @@ -55714,7 +56092,6 @@ var require_dump2 = __commonJS({ #maxSize = 1024 * 1024; #dumped = false; #size = 0; - #controller = null; aborted = false; reason = false; constructor({ maxSize, signal }, handler2) { @@ -55730,7 +56107,6 @@ var require_dump2 = __commonJS({ } onRequestStart(controller, context) { controller.abort = this.#abort.bind(this); - this.#controller = controller; return super.onRequestStart(controller, context); } onResponseStart(controller, statusCode, headers, statusMessage) { @@ -55746,33 +56122,26 @@ var require_dump2 = __commonJS({ return super.onResponseStart(controller, statusCode, headers, statusMessage); } onResponseError(controller, err) { - if (this.#dumped) { - return; - } - err = this.#controller?.reason ?? err; - super.onResponseError(controller, err); + super.onResponseError(controller, this.aborted === true ? this.reason : err); } onResponseData(controller, chunk) { this.#size = this.#size + chunk.length; - if (this.#size >= this.#maxSize) { + if (this.#size > this.#maxSize) { + throw new RequestAbortedError( + `Response size (${this.#size}) larger than maxSize (${this.#maxSize})` + ); + } + if (this.#size === this.#maxSize) { this.#dumped = true; - if (this.aborted === true) { - super.onResponseError(controller, this.reason); - } else { - super.onResponseEnd(controller, {}); - } } return true; } onResponseEnd(controller, trailers) { - if (this.#dumped) { - return; - } - if (this.#controller.aborted === true) { + if (this.aborted === true) { super.onResponseError(controller, this.reason); return; } - super.onResponseEnd(controller, trailers); + super.onResponseEnd(controller, this.#dumped ? {} : trailers); } }; function createDumpInterceptor({ maxSize: defaultMaxSize } = { @@ -57384,6 +57753,11 @@ var require_cache_handler = __commonJS({ return downstreamOnHeaders(); } const cacheControlHeader = resHeaders["cache-control"]; + const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; + if (revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives)) { + deleteCachedValue(this.#store, this.#cacheKey); + return downstreamOnHeaders(); + } 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)) { @@ -57391,8 +57765,7 @@ var require_cache_handler = __commonJS({ } return downstreamOnHeaders(); } - const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; - if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { + if (!canCacheResponse(this.#cacheType, this.#cacheKey.method, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) { deleteCachedValue(this.#store, this.#cacheKey); } @@ -57555,9 +57928,12 @@ var require_cache_handler = __commonJS({ } } function revalidationResponseDisallowsCachedReuse(cacheType, resHeaders, cacheControlDirectives) { - return cacheControlDirectives["no-store"] === true || cacheType === "shared" && cacheControlDirectives.private === true || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); + return cacheControlDirectives["no-store"] === true || cacheType === "shared" && (cacheControlDirectives.private === true || Object.hasOwn(resHeaders, "set-cookie")) || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); } - function canCacheResponse(cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + function canCacheResponse(cacheType, method, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + if (!arrayIncludes(util3.safeHTTPMethods, method)) { + return false; + } if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) { return false; } @@ -57568,7 +57944,7 @@ var require_cache_handler = __commonJS({ if (cacheControlDirectives["no-store"]) { return false; } - if (cacheType === "shared" && cacheControlDirectives.private === true) { + if (cacheType === "shared" && (cacheControlDirectives.private === true || Object.hasOwn(resHeaders, "set-cookie"))) { return false; } if (resHeaders.vary && hasVaryStar(resHeaders.vary)) { @@ -58101,7 +58477,7 @@ var require_cache3 = __commonJS({ result.cacheControlDirectives?.["s-maxage"] !== void 0); } function revalidationResponseDisallowsCachedReuse(cacheType, headers) { - if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) { + if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary) || cacheType === "shared" && Object.hasOwn(headers, "set-cookie")) { return true; } const cacheControl = headers["cache-control"]; @@ -58256,6 +58632,13 @@ var require_cache3 = __commonJS({ if (!result) { return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler2, opts, reqCacheControl); } + if (globalOpts.type === "shared" && Object.hasOwn(result.headers, "set-cookie")) { + if (util3.isStream(result.body)) { + result.body.on("error", nop).destroy(); + } + deleteCachedValue(globalOpts.store, cacheKey); + return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler2, opts, reqCacheControl); + } const now = Date.now(); if (now > result.deleteAt) { return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler2)); @@ -58405,6 +58788,9 @@ var require_cache3 = __commonJS({ return dispatch(opts2, handler2); } const cacheKey = makeCacheKey(opts2); + if (!arrayIncludes(util3.safeHTTPMethods, opts2.method)) { + return dispatch(opts2, new CacheHandler(globalOpts, cacheKey, handler2)); + } const result = store.get(cacheKey); if (result && typeof result.then === "function") { return result.then((result2) => handleResult( @@ -58438,9 +58824,65 @@ var require_decompress = __commonJS({ "node_modules/@octokit/action/node_modules/undici/lib/interceptor/decompress.js"(exports2, module2) { "use strict"; var { createInflate, createGunzip, createBrotliDecompress, createZstdDecompress } = require("node:zlib"); - var { pipeline: pipeline3 } = require("node:stream"); + var { pipeline: pipeline3, Transform: TransformStream2 } = require("node:stream"); + var { InvalidArgumentError, ResponseExceededMaxSizeError } = require_errors2(); var DecoratorHandler = require_decorator_handler2(); var { runtimeFeatures } = require_runtime_features(); + var DecompressController = class { + #onPause; + #onResume; + #onAbort; + #paused = false; + constructor(onPause, onResume, onAbort) { + this.#onPause = onPause; + this.#onResume = onResume; + this.#onAbort = onAbort; + this.target = null; + } + pause() { + if (this.#paused) { + return; + } + this.#paused = true; + this.#onPause(); + } + resume() { + if (!this.#paused) { + return; + } + this.#paused = false; + this.#onResume(); + } + abort(reason) { + this.target?.abort(reason); + this.#onAbort(reason); + } + get paused() { + return this.#paused; + } + get aborted() { + return this.target?.aborted ?? false; + } + get reason() { + return this.target?.reason ?? null; + } + get rawHeaders() { + return this.target?.rawHeaders ?? null; + } + set rawHeaders(value) { + if (this.target) { + this.target.rawHeaders = value; + } + } + get rawTrailers() { + return this.target?.rawTrailers ?? null; + } + set rawTrailers(value) { + if (this.target) { + this.target.rawTrailers = value; + } + } + }; var supportedEncodings = { gzip: createGunzip, "x-gzip": createGunzip, @@ -58454,6 +58896,23 @@ var require_decompress = __commonJS({ /** @type {const} */ [204, 304] ); + var defaultMaxSize = 0; + function createMaxSizeLimiter(maxSize) { + let size = 0; + return new TransformStream2({ + transform(chunk, _encoding, callback) { + const decompressedSize = size + chunk.length; + if (decompressedSize > maxSize) { + callback(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${maxSize})` + )); + return; + } + size = decompressedSize; + callback(null, chunk); + } + }); + } var warningEmitted = ( /** @type {boolean} */ false @@ -58461,14 +58920,128 @@ var require_decompress = __commonJS({ var DecompressHandler = class extends DecoratorHandler { /** @type {Transform[]} */ #decompressors = []; + /** @type {Record | undefined} */ + #trailers; /** @type {Readonly} */ #skipStatusCodes; /** @type {boolean} */ #skipErrorResponses; - constructor(handler2, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true } = {}) { + /** @type {number} */ + #maxSize; + /** @type {number} */ + #decompressedSize = 0; + /** @type {boolean} */ + #terminated = false; + /** @type {boolean} */ + #inputEnded = false; + /** @type {boolean} */ + #inputBackpressured = false; + /** @type {boolean} */ + #upstreamPaused = false; + /** @type {boolean} */ + #draining = false; + /** @type {boolean} */ + #drainRequested = false; + /** @type {boolean} */ + #completionPending = false; + /** @type {DecompressorStream | undefined} */ + #finalDecompressor; + /** @type {DecompressController} */ + #controller; + constructor(handler2, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true, maxSize = defaultMaxSize } = {}) { + if (!Number.isSafeInteger(maxSize) || maxSize < 0) { + throw new InvalidArgumentError("maxSize must be a non-negative integer"); + } super(handler2); this.#skipStatusCodes = skipStatusCodes; this.#skipErrorResponses = skipErrorResponses; + this.#maxSize = maxSize; + this.#controller = new DecompressController( + () => this.#onDownstreamPause(), + () => this.#onDownstreamResume(), + (reason) => { + if (this.#inputEnded && !this.#terminated) { + this.onResponseError(this.#controller, reason); + } + } + ); + } + #onDownstreamPause() { + this.#pauseUpstream(); + } + #onDownstreamResume() { + const drainWasDeferred = this.#draining; + this.#drainOutput(); + if (!drainWasDeferred) { + this.#resumeUpstreamIfNeeded(); + this.#finishIfReady(); + } + } + #pauseUpstream() { + if (!this.#upstreamPaused && !this.#terminated) { + this.#upstreamPaused = true; + this.#controller.target?.pause(); + } + } + #resumeUpstreamIfNeeded() { + if (this.#upstreamPaused && !this.#controller.paused && !this.#inputBackpressured) { + this.#upstreamPaused = false; + if (!this.#inputEnded) { + this.#controller.target?.resume(); + } + } + } + #drainOutput() { + if (this.#terminated || this.#controller.paused || !this.#finalDecompressor) { + return; + } + if (this.#draining) { + this.#drainRequested = true; + return; + } + this.#draining = true; + try { + do { + this.#drainRequested = false; + let chunk; + while (!this.#terminated && !this.#controller.paused && (chunk = this.#finalDecompressor.read()) !== null) { + if (this.#maxSize > 0) { + const decompressedSize = this.#decompressedSize + chunk.length; + if (decompressedSize > this.#maxSize) { + this.#fail(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${this.#maxSize})` + )); + return; + } + this.#decompressedSize = decompressedSize; + } + const result = super.onResponseData(this.#controller, chunk); + if (result === false && !this.#controller.paused) { + this.#controller.pause(); + } + } + } while (this.#drainRequested && !this.#terminated && !this.#controller.paused); + } finally { + this.#draining = false; + } + this.#resumeUpstreamIfNeeded(); + this.#finishIfReady(); + } + #finishIfReady() { + if (this.#terminated || !this.#completionPending || this.#controller.paused || this.#draining) { + return; + } + this.#terminated = true; + this.#cleanupDecompressors(); + super.onResponseEnd(this.#controller, this.#trailers); + } + #onDecompressionEnd() { + if (this.#terminated) { + return; + } + this.#completionPending = true; + this.#drainOutput(); + this.#finishIfReady(); } /** * Determines if decompression should be skipped based on encoding and status code @@ -58486,7 +59059,7 @@ var require_decompress = __commonJS({ * Creates a chain of decompressors for multiple content encodings * * @param {string} encodings - Comma-separated list of content encodings - * @returns {Array} - Array of decompressor streams + * @returns {Array} - Array of decompressor and limiting streams * @throws {Error} - If the number of content-encodings exceeds the maximum allowed */ #createDecompressionChain(encodings) { @@ -58505,54 +59078,81 @@ var require_decompress = __commonJS({ } decompressors.push(supportedEncodings[encoding]()); } - return decompressors; + if (decompressors.length < 2) { + return decompressors; + } + const streams = []; + for (let i = 0; i < decompressors.length; i++) { + streams.push(decompressors[i]); + if (i < decompressors.length - 1 && this.#maxSize > 0) { + streams.push(createMaxSizeLimiter(this.#maxSize)); + } + } + return streams; } /** - * Sets up event handlers for a decompressor stream using readable events + * Stops decompression and reports an error. + * @param {Error} error - The decompression error + * @returns {void} + */ + #fail(error2) { + if (this.#terminated) { + return; + } + if (this.#inputEnded) { + this.onResponseError(this.#controller, error2); + } else { + this.#controller.abort(error2); + } + } + /** + * Sets up event handlers for the final decompressor stream. * @param {DecompressorStream} decompressor - The decompressor stream - * @param {Controller} controller - The controller to coordinate with * @returns {void} */ - #setupDecompressorEvents(decompressor, controller) { - decompressor.on("readable", () => { - let chunk; - while ((chunk = decompressor.read()) !== null) { - const result = super.onResponseData(controller, chunk); - if (result === false) { - break; - } - } - }); - decompressor.on("error", (error2) => { - super.onResponseError(controller, error2); - }); + #setupDecompressorEvents(decompressor) { + this.#finalDecompressor = decompressor; + decompressor.on("readable", () => this.#drainOutput()); + decompressor.on("error", (error2) => this.#fail(error2)); } /** * Sets up event handling for a single decompressor - * @param {Controller} controller - The controller to handle events * @returns {void} */ - #setupSingleDecompressor(controller) { + #setupSingleDecompressor() { const decompressor = this.#decompressors[0]; - this.#setupDecompressorEvents(decompressor, controller); - decompressor.on("end", () => { - super.onResponseEnd(controller, {}); - }); + this.#setupDecompressorEvents(decompressor); + decompressor.on("end", () => this.#onDecompressionEnd()); } /** * Sets up event handling for multiple chained decompressors using pipeline - * @param {Controller} controller - The controller to handle events * @returns {void} */ - #setupMultipleDecompressors(controller) { + #setupMultipleDecompressors() { const lastDecompressor = this.#decompressors[this.#decompressors.length - 1]; - this.#setupDecompressorEvents(lastDecompressor, controller); + this.#setupDecompressorEvents(lastDecompressor); pipeline3(this.#decompressors, (err) => { + if (this.#terminated) { + return; + } if (err) { - super.onResponseError(controller, err); + this.#fail(err); return; } - super.onResponseEnd(controller, {}); + this.#onDecompressionEnd(); + }); + } + #setupInputBackpressure() { + const decompressor = this.#decompressors[0]; + decompressor.on("drain", () => { + if (this.#terminated) { + return; + } + this.#inputBackpressured = false; + if (!this.#controller.paused) { + this.#drainOutput(); + this.#resumeUpstreamIfNeeded(); + } }); } /** @@ -58561,6 +59161,14 @@ var require_decompress = __commonJS({ */ #cleanupDecompressors() { this.#decompressors.length = 0; + this.#finalDecompressor = void 0; + } + onRequestStart(controller, context) { + this.#controller.target = controller; + return super.onRequestStart(this.#controller, context); + } + onRequestUpgrade(controller, statusCode, headers, socket) { + return super.onRequestUpgrade(this.#controller, statusCode, headers, socket); } /** * @param {Controller} controller @@ -58572,21 +59180,45 @@ var require_decompress = __commonJS({ onResponseStart(controller, statusCode, headers, statusMessage) { const contentEncoding = headers["content-encoding"]; if (this.#shouldSkipDecompression(contentEncoding, statusCode)) { - return super.onResponseStart(controller, statusCode, headers, statusMessage); + return super.onResponseStart(this.#controller, statusCode, headers, statusMessage); } const decompressors = this.#createDecompressionChain(contentEncoding.toLowerCase()); if (decompressors.length === 0) { this.#cleanupDecompressors(); - return super.onResponseStart(controller, statusCode, headers, statusMessage); + return super.onResponseStart(this.#controller, statusCode, headers, statusMessage); } this.#decompressors = decompressors; const { "content-encoding": _, "content-length": __, ...newHeaders } = headers; + if (this.#controller.rawHeaders) { + const rawHeaders = this.#controller.rawHeaders; + if (Array.isArray(rawHeaders)) { + const filteredHeaders = []; + for (let i = 0; i < rawHeaders.length; i += 2) { + const headerName = rawHeaders[i]; + const name = Buffer.isBuffer(headerName) ? headerName.toString("latin1") : `${headerName}`; + const lowerName = name.toLowerCase(); + if (lowerName === "content-encoding" || lowerName === "content-length") { + continue; + } + filteredHeaders.push(rawHeaders[i], rawHeaders[i + 1]); + } + rawHeaders.splice(0, rawHeaders.length, ...filteredHeaders); + } else if (typeof rawHeaders === "object") { + for (const name of Object.keys(rawHeaders)) { + const lowerName = name.toLowerCase(); + if (lowerName === "content-encoding" || lowerName === "content-length") { + delete rawHeaders[name]; + } + } + } + } + this.#setupInputBackpressure(); if (this.#decompressors.length === 1) { - this.#setupSingleDecompressor(controller); + this.#setupSingleDecompressor(); } else { - this.#setupMultipleDecompressors(controller); + this.#setupMultipleDecompressors(); } - return super.onResponseStart(controller, statusCode, newHeaders, statusMessage); + return super.onResponseStart(this.#controller, statusCode, newHeaders, statusMessage); } /** * @param {Controller} controller @@ -58595,10 +59227,13 @@ var require_decompress = __commonJS({ */ onResponseData(controller, chunk) { if (this.#decompressors.length > 0) { - this.#decompressors[0].write(chunk); + if (!this.#decompressors[0].write(chunk)) { + this.#inputBackpressured = true; + this.#pauseUpstream(); + } return; } - super.onResponseData(controller, chunk); + return super.onResponseData(this.#controller, chunk); } /** * @param {Controller} controller @@ -58607,11 +59242,12 @@ var require_decompress = __commonJS({ */ onResponseEnd(controller, trailers) { if (this.#decompressors.length > 0) { + this.#inputEnded = true; + this.#trailers = trailers; this.#decompressors[0].end(); - this.#cleanupDecompressors(); return; } - super.onResponseEnd(controller, trailers); + return super.onResponseEnd(this.#controller, trailers); } /** * @param {Controller} controller @@ -58619,13 +59255,15 @@ var require_decompress = __commonJS({ * @returns {void} */ onResponseError(controller, err) { - if (this.#decompressors.length > 0) { - for (const decompressor of this.#decompressors) { - decompressor.destroy(err); - } - this.#cleanupDecompressors(); + if (this.#terminated) { + return; } - super.onResponseError(controller, err); + this.#terminated = true; + for (const decompressor of this.#decompressors) { + decompressor.destroy(); + } + this.#cleanupDecompressors(); + super.onResponseError(this.#controller, err); } }; function createDecompressInterceptor(options = {}) { @@ -64212,11 +64850,11 @@ var require_connection2 = __commonJS({ processResponse(response) { if (response.type === "error" || response.status !== 101) { if (response.socket?.session == null) { - failWebsocketConnection(handler2, 1002, "Received network error or non-101 status code.", response.error); + failHandshake(handler2, response, 1002, "Received network error or non-101 status code.", response.error); return; } if (response.status !== 200) { - failWebsocketConnection(handler2, 1002, "Received network error or non-200 status code.", response.error); + failHandshake(handler2, response, 1002, "Received network error or non-200 status code.", response.error); return; } } @@ -64225,21 +64863,21 @@ var require_connection2 = __commonJS({ warningEmitted = true; } if (protocols.length !== 0 && !response.headersList.get("Sec-WebSocket-Protocol")) { - failWebsocketConnection(handler2, 1002, "Server did not respond with sent protocols."); + failHandshake(handler2, response, 1002, "Server did not respond with sent protocols."); return; } if (response.socket.session == null && response.headersList.get("Upgrade")?.toLowerCase() !== "websocket") { - failWebsocketConnection(handler2, 1002, 'Server did not set Upgrade header to "websocket".'); + failHandshake(handler2, response, 1002, 'Server did not set Upgrade header to "websocket".'); return; } if (response.socket.session == null && response.headersList.get("Connection")?.toLowerCase() !== "upgrade") { - failWebsocketConnection(handler2, 1002, 'Server did not set Connection header to "upgrade".'); + failHandshake(handler2, response, 1002, 'Server did not set Connection header to "upgrade".'); return; } const secWSAccept = response.headersList.get("Sec-WebSocket-Accept"); const digest = crypto3.hash("sha1", keyValue + uid, "base64"); if (secWSAccept !== digest) { - failWebsocketConnection(handler2, 1002, "Incorrect hash received in Sec-WebSocket-Accept header."); + failHandshake(handler2, response, 1002, "Incorrect hash received in Sec-WebSocket-Accept header."); return; } const secExtension = response.headersList.get("Sec-WebSocket-Extensions"); @@ -64247,15 +64885,15 @@ var require_connection2 = __commonJS({ if (secExtension !== null) { extensions = parseExtensions(secExtension); if (!extensions.has("permessage-deflate")) { - failWebsocketConnection(handler2, 1002, "Sec-WebSocket-Extensions header does not match."); + failHandshake(handler2, response, 1002, "Sec-WebSocket-Extensions header does not match."); return; } } const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { - failWebsocketConnection(handler2, 1002, "Protocol was not set in the opening handshake."); + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + failHandshake(handler2, response, 1002, "Protocol was not set in the opening handshake."); return; } } @@ -64301,6 +64939,12 @@ var require_connection2 = __commonJS({ object.readyState = states.CLOSING; } } + function failHandshake(handler2, response, code, reason, cause) { + if (response.socket?.session != null && !response.socket.destroyed) { + response.socket.destroy(); + } + failWebsocketConnection(handler2, code, reason, cause); + } function failWebsocketConnection(handler2, code, reason, cause) { if (isEstablished(handler2.readyState)) { closeWebSocketConnection(handler2, code, reason, false); @@ -64372,6 +65016,7 @@ var require_permessage_deflate2 = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -65449,9 +66094,9 @@ var require_websocketstream = __commonJS({ #readableStream; /** @type {ReadableStreamDefaultController} */ #readableStreamController; - // Each WebSocketStream object has an associated writable stream , which is a WritableStream . - /** @type {WritableStream} */ - #writableStream; + // Retain the controller so the writable stream can be errored while locked. + /** @type {WritableStreamDefaultController} */ + #writableStreamController; // Each WebSocketStream object has an associated boolean handshake aborted , which is initially false. #handshakeAborted = false; /** @type {import('../websocket').Handler} */ @@ -65606,12 +66251,14 @@ var require_websocketstream = __commonJS({ cancel: (reason) => this.#cancel(reason) }); const writable = new WritableStream({ + start: (controller) => { + this.#writableStreamController = controller; + }, write: (chunk) => this.#write(chunk), close: () => closeWebSocketConnection(this.#handler, null, null), abort: (reason) => this.#closeUsingReason(reason) }); this.#readableStream = readable; - this.#writableStream = writable; this.#openedPromise.resolve({ extensions, protocol, @@ -65655,9 +66302,7 @@ var require_websocketstream = __commonJS({ const reason = result?.reason == null ? "" : utf8DecodeBytes(Buffer.from(result.reason)); if (wasClean) { this.#readableStreamController.close(); - if (!this.#writableStream.locked) { - this.#writableStream.abort(new DOMException("A closed WebSocketStream cannot be written to", "InvalidStateError")); - } + this.#writableStreamController.error(new DOMException("A closed WebSocketStream cannot be written to", "InvalidStateError")); this.#closedPromise.resolve({ closeCode: code, reason @@ -65665,7 +66310,7 @@ var require_websocketstream = __commonJS({ } else { const error2 = createUnvalidatedWebSocketError("unclean close", code, reason); this.#readableStreamController?.error(error2); - this.#writableStream?.abort(error2); + this.#writableStreamController?.error(error2); this.#closedPromise.reject(error2); } } @@ -65760,6 +66405,40 @@ var require_eventsource_stream2 = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -65779,10 +66458,13 @@ var require_eventsource_stream2 = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer|null} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -65814,63 +66496,30 @@ var require_eventsource_stream2 = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id !== void 0 || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -65879,17 +66528,16 @@ var require_eventsource_stream2 = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -65905,43 +66553,42 @@ var require_eventsource_stream2 = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -65966,12 +66613,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { diff --git a/dist/update-repo-task-status.js b/dist/update-repo-task-status.js index 8c3c6ced..ed3fb2b7 100644 --- a/dist/update-repo-task-status.js +++ b/dist/update-repo-task-status.js @@ -1854,10 +1854,66 @@ var require_request = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number|null} statusCode + * @param {Buffer[]|null} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (statusCode !== null) { + this.#publishUpgradeHeaders(statusCode, headers, statusText); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (statusCode !== null) { + this.#publishUpgradeTrailers(); + } + } + return result; + } + /** + * @param {number} statusCode + * @param {import('node:http2').IncomingHttpHeaders} headers + * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders + * @param {string} [statusText] + */ + onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { + assert(!this.aborted); + assert(this.completed); + if (channels.headers.hasSubscribers) { + this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); + } + this.#publishUpgradeTrailers(); + } + /** + * @param {Error} error + */ + onUpgradeError(error) { + assert(!this.aborted); + assert(this.completed); + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error }); + } + } + /** + * @param {number} statusCode + * @param {Buffer[]} headers + * @param {string} statusText + */ + #publishUpgradeHeaders(statusCode, headers, statusText) { + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + } + #publishUpgradeTrailers() { + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } } onComplete(trailers) { this.onFinally(); @@ -6000,7 +6056,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6025,9 +6081,10 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); - } catch (err) { - util.destroy(socket, err); + request2.onUpgrade(statusCode, headers, socket, statusText); + } catch (error) { + util.errorRequest(client, request2, error); + util.destroy(socket, error); } client[kResume](); } @@ -6319,21 +6376,20 @@ var require_client_h1 = __commonJS({ } function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; } function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } function resumeH1(client) { const socket = client[kSocket]; @@ -6431,11 +6487,17 @@ var require_client_h1 = __commonJS({ } const socket = client[kSocket]; clearIdleSocketValidation(socket); - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error) => { + if (request2.aborted) { return; } - util.errorRequest(client, request2, err || new RequestAbortedError()); + if (request2.completed) { + if (request2.upgrade || request2.method === "CONNECT") { + util.destroy(socket, new InformationalError("aborted")); + } + return; + } + util.errorRequest(client, request2, error || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6791,6 +6853,7 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports2, module2) { "use strict"; var assert = require("node:assert"); + var { errorMonitor } = require("node:events"); var { pipeline } = require("node:stream"); var util = require_util(); var { @@ -6851,6 +6914,10 @@ var require_client_h2 = __commonJS({ } return result; } + function parseH2ResponseHeaders(headers) { + const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; + return parseH2Headers(realHeaders); + } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7014,16 +7081,22 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error) => { + if (request2.aborted) { return; } - err = err || new RequestAbortedError(); - util.errorRequest(client, request2, err); + if (request2.completed) { + if (method === "CONNECT" && stream != null) { + util.destroy(stream, error || new RequestAbortedError()); + } + return; + } + error = error || new RequestAbortedError(); + util.errorRequest(client, request2, error); if (stream != null) { - util.destroy(stream, err); + util.destroy(stream, error); } - util.destroy(body, err); + util.destroy(body, error); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7038,18 +7111,42 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - if (stream.id && !stream.pending) { - request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - } else { - stream.once("ready", () => { + let upgradeResponseFinished = false; + const onResponse = (headers2) => { + upgradeResponseFinished = true; + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); + }; + const onUpgradeError = (error) => { + upgradeResponseFinished = true; + stream.off("response", onResponse); + request2.onUpgradeError(error); + }; + const onReady = () => { + try { request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - }); - } + } catch (error) { + stream.off("response", onResponse); + abort(error); + return; + } + if (request2.aborted) { + return; + } + stream.off("error", abort); + stream.once(errorMonitor, onUpgradeError); + client[kQueue][client[kRunningIdx]++] = null; + }; + stream.once("response", onResponse); + stream.once("error", abort); + ++session[kOpenStreams]; + onReady(); stream.once("close", () => { + if (!upgradeResponseFinished && request2.completed) { + stream.off("response", onResponse); + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); + } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -9032,6 +9129,7 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; + this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9041,6 +9139,17 @@ var require_retry_handler = __commonJS({ } }); } + checkpointResponseEnd(headers, resume) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + } + this.resume = this.end != null ? resume : null; + } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9102,7 +9211,9 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (this.retryOpts.statusCodes.includes(statusCode) === false) { + if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { + this.headersSent = true; + this.checkpointResponseEnd(headers, resume); return this.handler.onHeaders( statusCode, rawHeaders, @@ -9157,8 +9268,15 @@ var require_retry_handler = __commonJS({ return false; } const { start, size, end = size - 1 } = contentRange; - assert(this.start === start, "content-range mismatch"); - assert(this.end == null || this.end === end, "content-range mismatch"); + if (this.start !== start || this.end != null && this.end !== end) { + this.abort( + new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } this.resume = resume; return true; } @@ -9166,6 +9284,7 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { + this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9197,6 +9316,7 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; + this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9224,7 +9344,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body)) { + if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -17110,7 +17230,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17258,6 +17378,7 @@ var require_permessage_deflate = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -18169,6 +18290,40 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18188,10 +18343,13 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -18222,63 +18380,30 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -18287,17 +18412,16 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -18313,43 +18437,42 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -18374,12 +18497,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { @@ -28074,10 +28305,27 @@ var require_request3 = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number} statusCode + * @param {Buffer[]|string[]} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } + } + return result; } onComplete(trailers) { this.onFinally(); @@ -32374,7 +32622,13 @@ var require_client_h12 = __commonJS({ function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm2() : void 0; let mod; - let useWasmSIMD = process.arch !== "ppc64"; + let useWasmSIMD = true; + if (process.arch === "ppc64") { + const [major, minor] = process.versions.node.split(".").map((n) => parseInt(n, 10)); + if (major < 24 || major === 24 && minor < 12) { + useWasmSIMD = false; + } + } if (process.env.UNDICI_NO_WASM_SIMD === "1") { useWasmSIMD = false; } else if (process.env.UNDICI_NO_WASM_SIMD === "0") { @@ -32728,7 +32982,7 @@ var require_client_h12 = __commonJS({ * @param {Buffer} head */ onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -32753,8 +33007,9 @@ var require_client_h12 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); + request2.onUpgrade(statusCode, headers, socket, statusText); } catch (err) { + util.errorRequest(client, request2, err); util.destroy(socket, err); } client[kResume](); @@ -33085,21 +33340,20 @@ var require_client_h12 = __commonJS({ } function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; } function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } function resumeH1(client) { const socket = client[kSocket]; @@ -33589,7 +33843,9 @@ var require_client_h22 = __commonJS({ RequestAbortedError, SocketError, InformationalError, - InvalidArgumentError + InvalidArgumentError, + HeadersTimeoutError, + BodyTimeoutError } = require_errors3(); var { kUrl, @@ -33614,6 +33870,7 @@ var require_client_h22 = __commonJS({ kHTTPContext, kClosed, kBodyTimeout, + kHeadersTimeout, kEnableConnectProtocol, kRemoteSettings, kHTTP2Stream, @@ -33750,7 +34007,7 @@ var require_client_h22 = __commonJS({ function resumeH2(client) { const socket = client[kSocket]; if (socket?.destroyed === false) { - if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) { + if (client[kSize] === 0) { socket.unref(); client[kHTTP2Session].unref(); } else { @@ -33816,6 +34073,24 @@ var require_client_h22 = __commonJS({ this.destroy(err); util.destroy(this[kSocket], err); } + function completeRequest(client, request2, resetPendingIdx = false) { + const queue = client[kQueue]; + const runningIdx = client[kRunningIdx]; + if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request2) { + queue[runningIdx] = null; + client[kRunningIdx] = runningIdx + 1; + return; + } + const index = queue.indexOf(request2, runningIdx); + if (index === -1 || index >= client[kPendingIdx]) { + return; + } + queue.splice(index, 1); + client[kPendingIdx]--; + if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) { + client[kPendingIdx] = client[kRunningIdx]; + } + } function onHttp2SessionGoAway(errorCode) { const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${errorCode}`, util.getSocketInfo(this[kSocket])); const client = this[kClient]; @@ -33827,7 +34102,9 @@ var require_client_h22 = __commonJS({ if (client[kRunningIdx] < client[kQueue].length) { const request2 = client[kQueue][client[kRunningIdx]]; client[kQueue][client[kRunningIdx]++] = null; - util.errorRequest(client, request2, err); + if (request2 != null) { + util.errorRequest(client, request2, err); + } client[kPendingIdx] = client[kRunningIdx]; } assert(client[kRunning] === 0); @@ -33850,7 +34127,9 @@ var require_client_h22 = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util.errorRequest(client, request2, err); + if (request2 != null) { + util.errorRequest(client, request2, err); + } } } } @@ -33882,7 +34161,8 @@ var require_client_h22 = __commonJS({ return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; } function writeH2(client, request2) { - const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout]; + const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout]; + const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout]; const session = client[kHTTP2Session]; const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2; let { body } = request2; @@ -33930,6 +34210,7 @@ var require_client_h22 = __commonJS({ stream.removeAllListeners("data"); stream.close(); client[kOnError](err); + completeRequest(client, request2); client[kResume](); } util.destroy(body, err); @@ -33960,11 +34241,16 @@ var require_client_h22 = __commonJS({ } stream = session.request(headers, { endStream: false, signal }); stream[kHTTP2Stream] = true; + ++session[kOpenStreams]; stream.once("response", (headers2, _flags) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; - request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + try { + request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); + } catch (err) { + abort(err); + return; + } + completeRequest(client, request2); }); stream.on("error", () => { if (stream.rstCode === NGHTTP2_REFUSED_STREAM || stream.rstCode === NGHTTP2_CANCEL) { @@ -33975,22 +34261,28 @@ var require_client_h22 = __commonJS({ session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); return true; } stream = session.request(headers, { endStream: false, signal }); stream[kHTTP2Stream] = true; + ++session[kOpenStreams]; stream.on("response", (headers2) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; - request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + try { + request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); + } catch (err) { + abort(err); + return; + } + completeRequest(client, request2); }); + stream.on("error", abort); stream.once("close", () => { session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); return true; } headers[HTTP2_HEADER_PATH] = path; @@ -34048,12 +34340,13 @@ var require_client_h22 = __commonJS({ writeBodyH2(); } ++session[kOpenStreams]; - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); let responseReceived = false; stream.once("response", (headers2) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; request2.onResponseStarted(); responseReceived = true; + stream.setTimeout(bodyTimeout); if (request2.aborted) { stream.removeAllListeners("data"); return; @@ -34076,12 +34369,11 @@ var require_client_h22 = __commonJS({ if (!request2.aborted && !request2.completed) { request2.onComplete({}); } - client[kQueue][client[kRunningIdx]++] = null; + completeRequest(client, request2); client[kResume](); } else { abort(new InformationalError("HTTP/2: stream half-closed (remote)")); - client[kQueue][client[kRunningIdx]++] = null; - client[kPendingIdx] = client[kRunningIdx]; + completeRequest(client, request2, true); client[kResume](); } }); @@ -34091,6 +34383,9 @@ var require_client_h22 = __commonJS({ if (session[kOpenStreams] === 0) { session.unref(); } + if (!request2.aborted && !request2.completed) { + abort(new InformationalError("HTTP/2: stream closed before the response was complete")); + } }); stream.once("error", function(err) { stream.removeAllListeners("data"); @@ -34104,7 +34399,7 @@ var require_client_h22 = __commonJS({ stream.removeAllListeners("data"); }); stream.on("timeout", () => { - const err = new InformationalError(`HTTP/2: "stream timeout after ${requestTimeout}"`); + const err = responseReceived ? new BodyTimeoutError(`HTTP/2: "body timeout after ${bodyTimeout}"`) : new HeadersTimeoutError(`HTTP/2: "headers timeout after ${headersTimeout}"`); stream.removeAllListeners("data"); session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) { @@ -34602,7 +34897,9 @@ var require_client2 = __commonJS({ const requests = this[kQueue].splice(this[kPendingIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util.errorRequest(this, request2, err); + if (request2 != null) { + util.errorRequest(this, request2, err); + } } const callback = () => { if (this[kClosedResolve]) { @@ -34627,7 +34924,9 @@ var require_client2 = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util.errorRequest(client, request2, err); + if (request2 != null) { + util.errorRequest(client, request2, err); + } } assert(client[kSize] === 0); } @@ -35220,12 +35519,14 @@ var require_balanced_pool2 = __commonJS({ return new Pool(origin, opts); } var BalancedPool = class extends PoolBase { - constructor(upstreams = [], { factory = defaultFactory, ...opts } = {}) { + constructor(upstreams = [], { factory = defaultFactory, connect, tls, ...opts } = {}) { if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } super(opts); - this[kOptions] = { ...util.deepClone(opts) }; + if (connect && typeof connect !== "function") connect = { ...connect }; + if (tls && typeof tls !== "function") tls = { ...tls }; + this[kOptions] = { ...util.deepClone(opts), connect, tls }; this[kOptions].interceptors = opts.interceptors ? { ...opts.interceptors } : void 0; this[kIndex] = -1; this[kCurrentWeight] = 0; @@ -36689,6 +36990,55 @@ var require_retry_handler2 = __commonJS({ }); } } + var RetryController = class { + #paused = false; + #target = null; + set target(target) { + this.#target = target; + if (this.#paused) { + target?.pause(); + } + } + get target() { + return this.#target; + } + pause() { + this.#paused = true; + this.#target?.pause(); + } + resume() { + this.#paused = false; + this.#target?.resume(); + } + abort(reason) { + this.#target?.abort(reason); + } + get paused() { + return this.#paused || (this.#target?.paused ?? false); + } + get aborted() { + return this.#target?.aborted ?? false; + } + get reason() { + return this.#target?.reason ?? null; + } + get rawHeaders() { + return this.#target?.rawHeaders ?? null; + } + set rawHeaders(value) { + if (this.#target) { + this.#target.rawHeaders = value; + } + } + get rawTrailers() { + return this.#target?.rawTrailers ?? null; + } + set rawTrailers(value) { + if (this.#target) { + this.#target.rawTrailers = value; + } + } + }; var RetryHandler = class _RetryHandler { constructor(opts, { dispatch, handler: handler2 }) { const { retryOptions, ...dispatchOpts } = opts; @@ -36743,12 +37093,18 @@ var require_retry_handler2 = __commonJS({ this.start = 0; this.end = null; this.etag = null; + this.controllerProxy = new RetryController(); } onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err) { if (this.retryOpts.throwOnError) { if (this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + if (this.headersSent) { + this.handler.onResponseError?.(this.controllerProxy, err); + } else { + this.headersSent = true; + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + } } else { this.error = err; } @@ -36756,13 +37112,19 @@ var require_retry_handler2 = __commonJS({ } if (isDisturbed(this.opts.body)) { this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); return; } function shouldRetry(passedErr) { if (passedErr) { - this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + if (this.headersSent) { + this.handler.onResponseError?.(this.controllerProxy, passedErr); + } else { + this.headersSent = true; + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + } controller.resume(); return; } @@ -36779,13 +37141,25 @@ var require_retry_handler2 = __commonJS({ shouldRetry.bind(this) ); } + checkpointResponseEnd(headers) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + this.resume = this.end != null; + } + } onRequestStart(controller, context) { + this.controllerProxy.target = controller; if (!this.headersSent) { - this.handler.onRequestStart?.(controller, context); + this.handler.onRequestStart?.(this.controllerProxy, context); } } - onRequestUpgrade(controller, statusCode, headers, socket) { - this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket); + onRequestUpgrade(_controller, statusCode, headers, socket) { + this.handler.onRequestUpgrade?.(this.controllerProxy, statusCode, headers, socket); } static [kRetryHandlerDefaultRetry](err, { state, opts }, cb) { const { statusCode, code, headers } = err; @@ -36859,8 +37233,12 @@ var require_retry_handler2 = __commonJS({ } 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"); + if (this.start !== start || this.end != null && this.end !== end) { + throw new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }); + } return; } if (this.end == null) { @@ -36869,7 +37247,7 @@ var require_retry_handler2 = __commonJS({ if (range == null) { this.headersSent = true; this.handler.onResponseStart?.( - controller, + this.controllerProxy, statusCode, headers, statusMessage @@ -36902,7 +37280,7 @@ var require_retry_handler2 = __commonJS({ } this.headersSent = true; this.handler.onResponseStart?.( - controller, + this.controllerProxy, statusCode, headers, statusMessage @@ -36914,24 +37292,24 @@ var require_retry_handler2 = __commonJS({ }); } } - onResponseData(controller, chunk) { + onResponseData(_controller, chunk) { if (this.error) { return; } this.start += chunk.length; - this.handler.onResponseData?.(controller, chunk); + this.handler.onResponseData?.(this.controllerProxy, chunk); } - onResponseEnd(controller, trailers) { + onResponseEnd(_controller, trailers) { if (this.error && this.retryOpts.throwOnError) { throw this.error; } if (!this.error) { this.retryCount = 0; - return this.handler.onResponseEnd?.(controller, trailers); + return this.handler.onResponseEnd?.(this.controllerProxy, trailers); } - this.retry(controller); + this.retry(); } - retry(controller) { + retry() { if (this.start !== 0) { const headers = { range: `bytes=${this.start}-${this.end ?? ""}` }; if (this.etag != null) { @@ -36949,20 +37327,20 @@ var require_retry_handler2 = __commonJS({ this.retryCountCheckpoint = this.retryCount; this.dispatch(this.opts, this); } catch (err) { - this.handler.onResponseError?.(controller, err); + this.handler.onResponseError?.(this.controllerProxy, err); } } onResponseError(controller, err) { - if (controller?.aborted || isDisturbed(this.opts.body)) { - this.handler.onResponseError?.(controller, err); + if (controller?.aborted || isDisturbed(this.opts.body) || this.headersSent && !this.resume) { + this.handler.onResponseError?.(this.controllerProxy, err); return; } function shouldRetry(returnedErr) { if (!returnedErr) { - this.retry(controller); + this.retry(); return; } - this.handler?.onResponseError?.(controller, returnedErr); + this.handler?.onResponseError?.(this.controllerProxy, returnedErr); } if (this.retryCount - this.retryCountCheckpoint > 0) { this.retryCount = this.retryCountCheckpoint + (this.retryCount - this.retryCountCheckpoint); @@ -40560,7 +40938,6 @@ var require_dump2 = __commonJS({ #maxSize = 1024 * 1024; #dumped = false; #size = 0; - #controller = null; aborted = false; reason = false; constructor({ maxSize, signal }, handler2) { @@ -40576,7 +40953,6 @@ var require_dump2 = __commonJS({ } onRequestStart(controller, context) { controller.abort = this.#abort.bind(this); - this.#controller = controller; return super.onRequestStart(controller, context); } onResponseStart(controller, statusCode, headers, statusMessage) { @@ -40592,33 +40968,26 @@ var require_dump2 = __commonJS({ return super.onResponseStart(controller, statusCode, headers, statusMessage); } onResponseError(controller, err) { - if (this.#dumped) { - return; - } - err = this.#controller?.reason ?? err; - super.onResponseError(controller, err); + super.onResponseError(controller, this.aborted === true ? this.reason : err); } onResponseData(controller, chunk) { this.#size = this.#size + chunk.length; - if (this.#size >= this.#maxSize) { + if (this.#size > this.#maxSize) { + throw new RequestAbortedError( + `Response size (${this.#size}) larger than maxSize (${this.#maxSize})` + ); + } + if (this.#size === this.#maxSize) { this.#dumped = true; - if (this.aborted === true) { - super.onResponseError(controller, this.reason); - } else { - super.onResponseEnd(controller, {}); - } } return true; } onResponseEnd(controller, trailers) { - if (this.#dumped) { - return; - } - if (this.#controller.aborted === true) { + if (this.aborted === true) { super.onResponseError(controller, this.reason); return; } - super.onResponseEnd(controller, trailers); + super.onResponseEnd(controller, this.#dumped ? {} : trailers); } }; function createDumpInterceptor({ maxSize: defaultMaxSize } = { @@ -42230,6 +42599,11 @@ var require_cache_handler = __commonJS({ return downstreamOnHeaders(); } const cacheControlHeader = resHeaders["cache-control"]; + const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; + if (revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives)) { + deleteCachedValue(this.#store, this.#cacheKey); + return downstreamOnHeaders(); + } 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)) { @@ -42237,8 +42611,7 @@ var require_cache_handler = __commonJS({ } return downstreamOnHeaders(); } - const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; - if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { + if (!canCacheResponse(this.#cacheType, this.#cacheKey.method, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) { deleteCachedValue(this.#store, this.#cacheKey); } @@ -42401,9 +42774,12 @@ var require_cache_handler = __commonJS({ } } function revalidationResponseDisallowsCachedReuse(cacheType, resHeaders, cacheControlDirectives) { - return cacheControlDirectives["no-store"] === true || cacheType === "shared" && cacheControlDirectives.private === true || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); + return cacheControlDirectives["no-store"] === true || cacheType === "shared" && (cacheControlDirectives.private === true || Object.hasOwn(resHeaders, "set-cookie")) || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); } - function canCacheResponse(cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + function canCacheResponse(cacheType, method, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + if (!arrayIncludes(util.safeHTTPMethods, method)) { + return false; + } if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) { return false; } @@ -42414,7 +42790,7 @@ var require_cache_handler = __commonJS({ if (cacheControlDirectives["no-store"]) { return false; } - if (cacheType === "shared" && cacheControlDirectives.private === true) { + if (cacheType === "shared" && (cacheControlDirectives.private === true || Object.hasOwn(resHeaders, "set-cookie"))) { return false; } if (resHeaders.vary && hasVaryStar(resHeaders.vary)) { @@ -42947,7 +43323,7 @@ var require_cache3 = __commonJS({ result.cacheControlDirectives?.["s-maxage"] !== void 0); } function revalidationResponseDisallowsCachedReuse(cacheType, headers) { - if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) { + if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary) || cacheType === "shared" && Object.hasOwn(headers, "set-cookie")) { return true; } const cacheControl = headers["cache-control"]; @@ -43102,6 +43478,13 @@ var require_cache3 = __commonJS({ if (!result) { return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler2, opts, reqCacheControl); } + if (globalOpts.type === "shared" && Object.hasOwn(result.headers, "set-cookie")) { + if (util.isStream(result.body)) { + result.body.on("error", nop).destroy(); + } + deleteCachedValue(globalOpts.store, cacheKey); + return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler2, opts, reqCacheControl); + } const now = Date.now(); if (now > result.deleteAt) { return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler2)); @@ -43251,6 +43634,9 @@ var require_cache3 = __commonJS({ return dispatch(opts2, handler2); } const cacheKey = makeCacheKey(opts2); + if (!arrayIncludes(util.safeHTTPMethods, opts2.method)) { + return dispatch(opts2, new CacheHandler(globalOpts, cacheKey, handler2)); + } const result = store.get(cacheKey); if (result && typeof result.then === "function") { return result.then((result2) => handleResult( @@ -43284,9 +43670,65 @@ var require_decompress = __commonJS({ "node_modules/@octokit/action/node_modules/undici/lib/interceptor/decompress.js"(exports2, module2) { "use strict"; var { createInflate, createGunzip, createBrotliDecompress, createZstdDecompress } = require("node:zlib"); - var { pipeline } = require("node:stream"); + var { pipeline, Transform: TransformStream2 } = require("node:stream"); + var { InvalidArgumentError, ResponseExceededMaxSizeError } = require_errors3(); var DecoratorHandler = require_decorator_handler2(); var { runtimeFeatures } = require_runtime_features(); + var DecompressController = class { + #onPause; + #onResume; + #onAbort; + #paused = false; + constructor(onPause, onResume, onAbort) { + this.#onPause = onPause; + this.#onResume = onResume; + this.#onAbort = onAbort; + this.target = null; + } + pause() { + if (this.#paused) { + return; + } + this.#paused = true; + this.#onPause(); + } + resume() { + if (!this.#paused) { + return; + } + this.#paused = false; + this.#onResume(); + } + abort(reason) { + this.target?.abort(reason); + this.#onAbort(reason); + } + get paused() { + return this.#paused; + } + get aborted() { + return this.target?.aborted ?? false; + } + get reason() { + return this.target?.reason ?? null; + } + get rawHeaders() { + return this.target?.rawHeaders ?? null; + } + set rawHeaders(value) { + if (this.target) { + this.target.rawHeaders = value; + } + } + get rawTrailers() { + return this.target?.rawTrailers ?? null; + } + set rawTrailers(value) { + if (this.target) { + this.target.rawTrailers = value; + } + } + }; var supportedEncodings = { gzip: createGunzip, "x-gzip": createGunzip, @@ -43300,6 +43742,23 @@ var require_decompress = __commonJS({ /** @type {const} */ [204, 304] ); + var defaultMaxSize = 0; + function createMaxSizeLimiter(maxSize) { + let size = 0; + return new TransformStream2({ + transform(chunk, _encoding, callback) { + const decompressedSize = size + chunk.length; + if (decompressedSize > maxSize) { + callback(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${maxSize})` + )); + return; + } + size = decompressedSize; + callback(null, chunk); + } + }); + } var warningEmitted = ( /** @type {boolean} */ false @@ -43307,14 +43766,128 @@ var require_decompress = __commonJS({ var DecompressHandler = class extends DecoratorHandler { /** @type {Transform[]} */ #decompressors = []; + /** @type {Record | undefined} */ + #trailers; /** @type {Readonly} */ #skipStatusCodes; /** @type {boolean} */ #skipErrorResponses; - constructor(handler2, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true } = {}) { + /** @type {number} */ + #maxSize; + /** @type {number} */ + #decompressedSize = 0; + /** @type {boolean} */ + #terminated = false; + /** @type {boolean} */ + #inputEnded = false; + /** @type {boolean} */ + #inputBackpressured = false; + /** @type {boolean} */ + #upstreamPaused = false; + /** @type {boolean} */ + #draining = false; + /** @type {boolean} */ + #drainRequested = false; + /** @type {boolean} */ + #completionPending = false; + /** @type {DecompressorStream | undefined} */ + #finalDecompressor; + /** @type {DecompressController} */ + #controller; + constructor(handler2, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true, maxSize = defaultMaxSize } = {}) { + if (!Number.isSafeInteger(maxSize) || maxSize < 0) { + throw new InvalidArgumentError("maxSize must be a non-negative integer"); + } super(handler2); this.#skipStatusCodes = skipStatusCodes; this.#skipErrorResponses = skipErrorResponses; + this.#maxSize = maxSize; + this.#controller = new DecompressController( + () => this.#onDownstreamPause(), + () => this.#onDownstreamResume(), + (reason) => { + if (this.#inputEnded && !this.#terminated) { + this.onResponseError(this.#controller, reason); + } + } + ); + } + #onDownstreamPause() { + this.#pauseUpstream(); + } + #onDownstreamResume() { + const drainWasDeferred = this.#draining; + this.#drainOutput(); + if (!drainWasDeferred) { + this.#resumeUpstreamIfNeeded(); + this.#finishIfReady(); + } + } + #pauseUpstream() { + if (!this.#upstreamPaused && !this.#terminated) { + this.#upstreamPaused = true; + this.#controller.target?.pause(); + } + } + #resumeUpstreamIfNeeded() { + if (this.#upstreamPaused && !this.#controller.paused && !this.#inputBackpressured) { + this.#upstreamPaused = false; + if (!this.#inputEnded) { + this.#controller.target?.resume(); + } + } + } + #drainOutput() { + if (this.#terminated || this.#controller.paused || !this.#finalDecompressor) { + return; + } + if (this.#draining) { + this.#drainRequested = true; + return; + } + this.#draining = true; + try { + do { + this.#drainRequested = false; + let chunk; + while (!this.#terminated && !this.#controller.paused && (chunk = this.#finalDecompressor.read()) !== null) { + if (this.#maxSize > 0) { + const decompressedSize = this.#decompressedSize + chunk.length; + if (decompressedSize > this.#maxSize) { + this.#fail(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${this.#maxSize})` + )); + return; + } + this.#decompressedSize = decompressedSize; + } + const result = super.onResponseData(this.#controller, chunk); + if (result === false && !this.#controller.paused) { + this.#controller.pause(); + } + } + } while (this.#drainRequested && !this.#terminated && !this.#controller.paused); + } finally { + this.#draining = false; + } + this.#resumeUpstreamIfNeeded(); + this.#finishIfReady(); + } + #finishIfReady() { + if (this.#terminated || !this.#completionPending || this.#controller.paused || this.#draining) { + return; + } + this.#terminated = true; + this.#cleanupDecompressors(); + super.onResponseEnd(this.#controller, this.#trailers); + } + #onDecompressionEnd() { + if (this.#terminated) { + return; + } + this.#completionPending = true; + this.#drainOutput(); + this.#finishIfReady(); } /** * Determines if decompression should be skipped based on encoding and status code @@ -43332,7 +43905,7 @@ var require_decompress = __commonJS({ * Creates a chain of decompressors for multiple content encodings * * @param {string} encodings - Comma-separated list of content encodings - * @returns {Array} - Array of decompressor streams + * @returns {Array} - Array of decompressor and limiting streams * @throws {Error} - If the number of content-encodings exceeds the maximum allowed */ #createDecompressionChain(encodings) { @@ -43351,54 +43924,81 @@ var require_decompress = __commonJS({ } decompressors.push(supportedEncodings[encoding]()); } - return decompressors; + if (decompressors.length < 2) { + return decompressors; + } + const streams = []; + for (let i = 0; i < decompressors.length; i++) { + streams.push(decompressors[i]); + if (i < decompressors.length - 1 && this.#maxSize > 0) { + streams.push(createMaxSizeLimiter(this.#maxSize)); + } + } + return streams; + } + /** + * Stops decompression and reports an error. + * @param {Error} error - The decompression error + * @returns {void} + */ + #fail(error) { + if (this.#terminated) { + return; + } + if (this.#inputEnded) { + this.onResponseError(this.#controller, error); + } else { + this.#controller.abort(error); + } } /** - * Sets up event handlers for a decompressor stream using readable events + * Sets up event handlers for the final decompressor stream. * @param {DecompressorStream} decompressor - The decompressor stream - * @param {Controller} controller - The controller to coordinate with * @returns {void} */ - #setupDecompressorEvents(decompressor, controller) { - decompressor.on("readable", () => { - let chunk; - while ((chunk = decompressor.read()) !== null) { - const result = super.onResponseData(controller, chunk); - if (result === false) { - break; - } - } - }); - decompressor.on("error", (error) => { - super.onResponseError(controller, error); - }); + #setupDecompressorEvents(decompressor) { + this.#finalDecompressor = decompressor; + decompressor.on("readable", () => this.#drainOutput()); + decompressor.on("error", (error) => this.#fail(error)); } /** * Sets up event handling for a single decompressor - * @param {Controller} controller - The controller to handle events * @returns {void} */ - #setupSingleDecompressor(controller) { + #setupSingleDecompressor() { const decompressor = this.#decompressors[0]; - this.#setupDecompressorEvents(decompressor, controller); - decompressor.on("end", () => { - super.onResponseEnd(controller, {}); - }); + this.#setupDecompressorEvents(decompressor); + decompressor.on("end", () => this.#onDecompressionEnd()); } /** * Sets up event handling for multiple chained decompressors using pipeline - * @param {Controller} controller - The controller to handle events * @returns {void} */ - #setupMultipleDecompressors(controller) { + #setupMultipleDecompressors() { const lastDecompressor = this.#decompressors[this.#decompressors.length - 1]; - this.#setupDecompressorEvents(lastDecompressor, controller); + this.#setupDecompressorEvents(lastDecompressor); pipeline(this.#decompressors, (err) => { + if (this.#terminated) { + return; + } if (err) { - super.onResponseError(controller, err); + this.#fail(err); return; } - super.onResponseEnd(controller, {}); + this.#onDecompressionEnd(); + }); + } + #setupInputBackpressure() { + const decompressor = this.#decompressors[0]; + decompressor.on("drain", () => { + if (this.#terminated) { + return; + } + this.#inputBackpressured = false; + if (!this.#controller.paused) { + this.#drainOutput(); + this.#resumeUpstreamIfNeeded(); + } }); } /** @@ -43407,6 +44007,14 @@ var require_decompress = __commonJS({ */ #cleanupDecompressors() { this.#decompressors.length = 0; + this.#finalDecompressor = void 0; + } + onRequestStart(controller, context) { + this.#controller.target = controller; + return super.onRequestStart(this.#controller, context); + } + onRequestUpgrade(controller, statusCode, headers, socket) { + return super.onRequestUpgrade(this.#controller, statusCode, headers, socket); } /** * @param {Controller} controller @@ -43418,21 +44026,45 @@ var require_decompress = __commonJS({ onResponseStart(controller, statusCode, headers, statusMessage) { const contentEncoding = headers["content-encoding"]; if (this.#shouldSkipDecompression(contentEncoding, statusCode)) { - return super.onResponseStart(controller, statusCode, headers, statusMessage); + return super.onResponseStart(this.#controller, statusCode, headers, statusMessage); } const decompressors = this.#createDecompressionChain(contentEncoding.toLowerCase()); if (decompressors.length === 0) { this.#cleanupDecompressors(); - return super.onResponseStart(controller, statusCode, headers, statusMessage); + return super.onResponseStart(this.#controller, statusCode, headers, statusMessage); } this.#decompressors = decompressors; const { "content-encoding": _, "content-length": __, ...newHeaders } = headers; + if (this.#controller.rawHeaders) { + const rawHeaders = this.#controller.rawHeaders; + if (Array.isArray(rawHeaders)) { + const filteredHeaders = []; + for (let i = 0; i < rawHeaders.length; i += 2) { + const headerName = rawHeaders[i]; + const name = Buffer.isBuffer(headerName) ? headerName.toString("latin1") : `${headerName}`; + const lowerName = name.toLowerCase(); + if (lowerName === "content-encoding" || lowerName === "content-length") { + continue; + } + filteredHeaders.push(rawHeaders[i], rawHeaders[i + 1]); + } + rawHeaders.splice(0, rawHeaders.length, ...filteredHeaders); + } else if (typeof rawHeaders === "object") { + for (const name of Object.keys(rawHeaders)) { + const lowerName = name.toLowerCase(); + if (lowerName === "content-encoding" || lowerName === "content-length") { + delete rawHeaders[name]; + } + } + } + } + this.#setupInputBackpressure(); if (this.#decompressors.length === 1) { - this.#setupSingleDecompressor(controller); + this.#setupSingleDecompressor(); } else { - this.#setupMultipleDecompressors(controller); + this.#setupMultipleDecompressors(); } - return super.onResponseStart(controller, statusCode, newHeaders, statusMessage); + return super.onResponseStart(this.#controller, statusCode, newHeaders, statusMessage); } /** * @param {Controller} controller @@ -43441,10 +44073,13 @@ var require_decompress = __commonJS({ */ onResponseData(controller, chunk) { if (this.#decompressors.length > 0) { - this.#decompressors[0].write(chunk); + if (!this.#decompressors[0].write(chunk)) { + this.#inputBackpressured = true; + this.#pauseUpstream(); + } return; } - super.onResponseData(controller, chunk); + return super.onResponseData(this.#controller, chunk); } /** * @param {Controller} controller @@ -43453,11 +44088,12 @@ var require_decompress = __commonJS({ */ onResponseEnd(controller, trailers) { if (this.#decompressors.length > 0) { + this.#inputEnded = true; + this.#trailers = trailers; this.#decompressors[0].end(); - this.#cleanupDecompressors(); return; } - super.onResponseEnd(controller, trailers); + return super.onResponseEnd(this.#controller, trailers); } /** * @param {Controller} controller @@ -43465,13 +44101,15 @@ var require_decompress = __commonJS({ * @returns {void} */ onResponseError(controller, err) { - if (this.#decompressors.length > 0) { - for (const decompressor of this.#decompressors) { - decompressor.destroy(err); - } - this.#cleanupDecompressors(); + if (this.#terminated) { + return; } - super.onResponseError(controller, err); + this.#terminated = true; + for (const decompressor of this.#decompressors) { + decompressor.destroy(); + } + this.#cleanupDecompressors(); + super.onResponseError(this.#controller, err); } }; function createDecompressInterceptor(options = {}) { @@ -49058,11 +49696,11 @@ var require_connection2 = __commonJS({ processResponse(response) { if (response.type === "error" || response.status !== 101) { if (response.socket?.session == null) { - failWebsocketConnection(handler2, 1002, "Received network error or non-101 status code.", response.error); + failHandshake(handler2, response, 1002, "Received network error or non-101 status code.", response.error); return; } if (response.status !== 200) { - failWebsocketConnection(handler2, 1002, "Received network error or non-200 status code.", response.error); + failHandshake(handler2, response, 1002, "Received network error or non-200 status code.", response.error); return; } } @@ -49071,21 +49709,21 @@ var require_connection2 = __commonJS({ warningEmitted = true; } if (protocols.length !== 0 && !response.headersList.get("Sec-WebSocket-Protocol")) { - failWebsocketConnection(handler2, 1002, "Server did not respond with sent protocols."); + failHandshake(handler2, response, 1002, "Server did not respond with sent protocols."); return; } if (response.socket.session == null && response.headersList.get("Upgrade")?.toLowerCase() !== "websocket") { - failWebsocketConnection(handler2, 1002, 'Server did not set Upgrade header to "websocket".'); + failHandshake(handler2, response, 1002, 'Server did not set Upgrade header to "websocket".'); return; } if (response.socket.session == null && response.headersList.get("Connection")?.toLowerCase() !== "upgrade") { - failWebsocketConnection(handler2, 1002, 'Server did not set Connection header to "upgrade".'); + failHandshake(handler2, response, 1002, 'Server did not set Connection header to "upgrade".'); return; } const secWSAccept = response.headersList.get("Sec-WebSocket-Accept"); const digest = crypto.hash("sha1", keyValue + uid, "base64"); if (secWSAccept !== digest) { - failWebsocketConnection(handler2, 1002, "Incorrect hash received in Sec-WebSocket-Accept header."); + failHandshake(handler2, response, 1002, "Incorrect hash received in Sec-WebSocket-Accept header."); return; } const secExtension = response.headersList.get("Sec-WebSocket-Extensions"); @@ -49093,15 +49731,15 @@ var require_connection2 = __commonJS({ if (secExtension !== null) { extensions = parseExtensions(secExtension); if (!extensions.has("permessage-deflate")) { - failWebsocketConnection(handler2, 1002, "Sec-WebSocket-Extensions header does not match."); + failHandshake(handler2, response, 1002, "Sec-WebSocket-Extensions header does not match."); return; } } const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { - failWebsocketConnection(handler2, 1002, "Protocol was not set in the opening handshake."); + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + failHandshake(handler2, response, 1002, "Protocol was not set in the opening handshake."); return; } } @@ -49147,6 +49785,12 @@ var require_connection2 = __commonJS({ object.readyState = states.CLOSING; } } + function failHandshake(handler2, response, code, reason, cause) { + if (response.socket?.session != null && !response.socket.destroyed) { + response.socket.destroy(); + } + failWebsocketConnection(handler2, code, reason, cause); + } function failWebsocketConnection(handler2, code, reason, cause) { if (isEstablished(handler2.readyState)) { closeWebSocketConnection(handler2, code, reason, false); @@ -49218,6 +49862,7 @@ var require_permessage_deflate2 = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -50295,9 +50940,9 @@ var require_websocketstream = __commonJS({ #readableStream; /** @type {ReadableStreamDefaultController} */ #readableStreamController; - // Each WebSocketStream object has an associated writable stream , which is a WritableStream . - /** @type {WritableStream} */ - #writableStream; + // Retain the controller so the writable stream can be errored while locked. + /** @type {WritableStreamDefaultController} */ + #writableStreamController; // Each WebSocketStream object has an associated boolean handshake aborted , which is initially false. #handshakeAborted = false; /** @type {import('../websocket').Handler} */ @@ -50452,12 +51097,14 @@ var require_websocketstream = __commonJS({ cancel: (reason) => this.#cancel(reason) }); const writable = new WritableStream({ + start: (controller) => { + this.#writableStreamController = controller; + }, write: (chunk) => this.#write(chunk), close: () => closeWebSocketConnection(this.#handler, null, null), abort: (reason) => this.#closeUsingReason(reason) }); this.#readableStream = readable; - this.#writableStream = writable; this.#openedPromise.resolve({ extensions, protocol, @@ -50501,9 +51148,7 @@ var require_websocketstream = __commonJS({ const reason = result?.reason == null ? "" : utf8DecodeBytes(Buffer.from(result.reason)); if (wasClean) { this.#readableStreamController.close(); - if (!this.#writableStream.locked) { - this.#writableStream.abort(new DOMException("A closed WebSocketStream cannot be written to", "InvalidStateError")); - } + this.#writableStreamController.error(new DOMException("A closed WebSocketStream cannot be written to", "InvalidStateError")); this.#closedPromise.resolve({ closeCode: code, reason @@ -50511,7 +51156,7 @@ var require_websocketstream = __commonJS({ } else { const error = createUnvalidatedWebSocketError("unclean close", code, reason); this.#readableStreamController?.error(error); - this.#writableStream?.abort(error); + this.#writableStreamController?.error(error); this.#closedPromise.reject(error); } } @@ -50606,6 +51251,40 @@ var require_eventsource_stream2 = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -50625,10 +51304,13 @@ var require_eventsource_stream2 = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer|null} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -50660,63 +51342,30 @@ var require_eventsource_stream2 = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id !== void 0 || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -50725,17 +51374,16 @@ var require_eventsource_stream2 = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -50751,43 +51399,42 @@ var require_eventsource_stream2 = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -50812,12 +51459,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { diff --git a/dist/update-repo-task-statuses.js b/dist/update-repo-task-statuses.js index 793e3a73..38369365 100644 --- a/dist/update-repo-task-statuses.js +++ b/dist/update-repo-task-statuses.js @@ -1854,10 +1854,66 @@ var require_request = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number|null} statusCode + * @param {Buffer[]|null} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (statusCode !== null) { + this.#publishUpgradeHeaders(statusCode, headers, statusText); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (statusCode !== null) { + this.#publishUpgradeTrailers(); + } + } + return result; + } + /** + * @param {number} statusCode + * @param {import('node:http2').IncomingHttpHeaders} headers + * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders + * @param {string} [statusText] + */ + onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { + assert(!this.aborted); + assert(this.completed); + if (channels.headers.hasSubscribers) { + this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); + } + this.#publishUpgradeTrailers(); + } + /** + * @param {Error} error + */ + onUpgradeError(error) { + assert(!this.aborted); + assert(this.completed); + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error }); + } + } + /** + * @param {number} statusCode + * @param {Buffer[]} headers + * @param {string} statusText + */ + #publishUpgradeHeaders(statusCode, headers, statusText) { + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + } + #publishUpgradeTrailers() { + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } } onComplete(trailers) { this.onFinally(); @@ -6000,7 +6056,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6025,9 +6081,10 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); - } catch (err) { - util.destroy(socket, err); + request2.onUpgrade(statusCode, headers, socket, statusText); + } catch (error) { + util.errorRequest(client, request2, error); + util.destroy(socket, error); } client[kResume](); } @@ -6319,21 +6376,20 @@ var require_client_h1 = __commonJS({ } function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; } function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } function resumeH1(client) { const socket = client[kSocket]; @@ -6431,11 +6487,17 @@ var require_client_h1 = __commonJS({ } const socket = client[kSocket]; clearIdleSocketValidation(socket); - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error) => { + if (request2.aborted) { return; } - util.errorRequest(client, request2, err || new RequestAbortedError()); + if (request2.completed) { + if (request2.upgrade || request2.method === "CONNECT") { + util.destroy(socket, new InformationalError("aborted")); + } + return; + } + util.errorRequest(client, request2, error || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6791,6 +6853,7 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports2, module2) { "use strict"; var assert = require("node:assert"); + var { errorMonitor } = require("node:events"); var { pipeline } = require("node:stream"); var util = require_util(); var { @@ -6851,6 +6914,10 @@ var require_client_h2 = __commonJS({ } return result; } + function parseH2ResponseHeaders(headers) { + const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; + return parseH2Headers(realHeaders); + } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7014,16 +7081,22 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error) => { + if (request2.aborted) { return; } - err = err || new RequestAbortedError(); - util.errorRequest(client, request2, err); + if (request2.completed) { + if (method === "CONNECT" && stream != null) { + util.destroy(stream, error || new RequestAbortedError()); + } + return; + } + error = error || new RequestAbortedError(); + util.errorRequest(client, request2, error); if (stream != null) { - util.destroy(stream, err); + util.destroy(stream, error); } - util.destroy(body, err); + util.destroy(body, error); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7038,18 +7111,42 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - if (stream.id && !stream.pending) { - request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - } else { - stream.once("ready", () => { + let upgradeResponseFinished = false; + const onResponse = (headers2) => { + upgradeResponseFinished = true; + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); + }; + const onUpgradeError = (error) => { + upgradeResponseFinished = true; + stream.off("response", onResponse); + request2.onUpgradeError(error); + }; + const onReady = () => { + try { request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - }); - } + } catch (error) { + stream.off("response", onResponse); + abort(error); + return; + } + if (request2.aborted) { + return; + } + stream.off("error", abort); + stream.once(errorMonitor, onUpgradeError); + client[kQueue][client[kRunningIdx]++] = null; + }; + stream.once("response", onResponse); + stream.once("error", abort); + ++session[kOpenStreams]; + onReady(); stream.once("close", () => { + if (!upgradeResponseFinished && request2.completed) { + stream.off("response", onResponse); + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); + } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -9032,6 +9129,7 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; + this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9041,6 +9139,17 @@ var require_retry_handler = __commonJS({ } }); } + checkpointResponseEnd(headers, resume) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + } + this.resume = this.end != null ? resume : null; + } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9102,7 +9211,9 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (this.retryOpts.statusCodes.includes(statusCode) === false) { + if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { + this.headersSent = true; + this.checkpointResponseEnd(headers, resume); return this.handler.onHeaders( statusCode, rawHeaders, @@ -9157,8 +9268,15 @@ var require_retry_handler = __commonJS({ return false; } const { start, size, end = size - 1 } = contentRange; - assert(this.start === start, "content-range mismatch"); - assert(this.end == null || this.end === end, "content-range mismatch"); + if (this.start !== start || this.end != null && this.end !== end) { + this.abort( + new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } this.resume = resume; return true; } @@ -9166,6 +9284,7 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { + this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9197,6 +9316,7 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; + this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9224,7 +9344,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body)) { + if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -17110,7 +17230,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17258,6 +17378,7 @@ var require_permessage_deflate = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -18169,6 +18290,40 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18188,10 +18343,13 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -18222,63 +18380,30 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -18287,17 +18412,16 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -18313,43 +18437,42 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -18374,12 +18497,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { @@ -28074,10 +28305,27 @@ var require_request3 = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number} statusCode + * @param {Buffer[]|string[]} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } + } + return result; } onComplete(trailers) { this.onFinally(); @@ -32374,7 +32622,13 @@ var require_client_h12 = __commonJS({ function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm2() : void 0; let mod; - let useWasmSIMD = process.arch !== "ppc64"; + let useWasmSIMD = true; + if (process.arch === "ppc64") { + const [major, minor] = process.versions.node.split(".").map((n) => parseInt(n, 10)); + if (major < 24 || major === 24 && minor < 12) { + useWasmSIMD = false; + } + } if (process.env.UNDICI_NO_WASM_SIMD === "1") { useWasmSIMD = false; } else if (process.env.UNDICI_NO_WASM_SIMD === "0") { @@ -32728,7 +32982,7 @@ var require_client_h12 = __commonJS({ * @param {Buffer} head */ onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -32753,8 +33007,9 @@ var require_client_h12 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); + request2.onUpgrade(statusCode, headers, socket, statusText); } catch (err) { + util.errorRequest(client, request2, err); util.destroy(socket, err); } client[kResume](); @@ -33085,21 +33340,20 @@ var require_client_h12 = __commonJS({ } function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; } function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } function resumeH1(client) { const socket = client[kSocket]; @@ -33589,7 +33843,9 @@ var require_client_h22 = __commonJS({ RequestAbortedError, SocketError, InformationalError, - InvalidArgumentError + InvalidArgumentError, + HeadersTimeoutError, + BodyTimeoutError } = require_errors3(); var { kUrl, @@ -33614,6 +33870,7 @@ var require_client_h22 = __commonJS({ kHTTPContext, kClosed, kBodyTimeout, + kHeadersTimeout, kEnableConnectProtocol, kRemoteSettings, kHTTP2Stream, @@ -33750,7 +34007,7 @@ var require_client_h22 = __commonJS({ function resumeH2(client) { const socket = client[kSocket]; if (socket?.destroyed === false) { - if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) { + if (client[kSize] === 0) { socket.unref(); client[kHTTP2Session].unref(); } else { @@ -33816,6 +34073,24 @@ var require_client_h22 = __commonJS({ this.destroy(err); util.destroy(this[kSocket], err); } + function completeRequest(client, request2, resetPendingIdx = false) { + const queue = client[kQueue]; + const runningIdx = client[kRunningIdx]; + if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request2) { + queue[runningIdx] = null; + client[kRunningIdx] = runningIdx + 1; + return; + } + const index = queue.indexOf(request2, runningIdx); + if (index === -1 || index >= client[kPendingIdx]) { + return; + } + queue.splice(index, 1); + client[kPendingIdx]--; + if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) { + client[kPendingIdx] = client[kRunningIdx]; + } + } function onHttp2SessionGoAway(errorCode) { const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${errorCode}`, util.getSocketInfo(this[kSocket])); const client = this[kClient]; @@ -33827,7 +34102,9 @@ var require_client_h22 = __commonJS({ if (client[kRunningIdx] < client[kQueue].length) { const request2 = client[kQueue][client[kRunningIdx]]; client[kQueue][client[kRunningIdx]++] = null; - util.errorRequest(client, request2, err); + if (request2 != null) { + util.errorRequest(client, request2, err); + } client[kPendingIdx] = client[kRunningIdx]; } assert(client[kRunning] === 0); @@ -33850,7 +34127,9 @@ var require_client_h22 = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util.errorRequest(client, request2, err); + if (request2 != null) { + util.errorRequest(client, request2, err); + } } } } @@ -33882,7 +34161,8 @@ var require_client_h22 = __commonJS({ return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; } function writeH2(client, request2) { - const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout]; + const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout]; + const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout]; const session = client[kHTTP2Session]; const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2; let { body } = request2; @@ -33930,6 +34210,7 @@ var require_client_h22 = __commonJS({ stream.removeAllListeners("data"); stream.close(); client[kOnError](err); + completeRequest(client, request2); client[kResume](); } util.destroy(body, err); @@ -33960,11 +34241,16 @@ var require_client_h22 = __commonJS({ } stream = session.request(headers, { endStream: false, signal }); stream[kHTTP2Stream] = true; + ++session[kOpenStreams]; stream.once("response", (headers2, _flags) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; - request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + try { + request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); + } catch (err) { + abort(err); + return; + } + completeRequest(client, request2); }); stream.on("error", () => { if (stream.rstCode === NGHTTP2_REFUSED_STREAM || stream.rstCode === NGHTTP2_CANCEL) { @@ -33975,22 +34261,28 @@ var require_client_h22 = __commonJS({ session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); return true; } stream = session.request(headers, { endStream: false, signal }); stream[kHTTP2Stream] = true; + ++session[kOpenStreams]; stream.on("response", (headers2) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; - request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; + try { + request2.onUpgrade(statusCode, parseH2Headers(realHeaders), stream); + } catch (err) { + abort(err); + return; + } + completeRequest(client, request2); }); + stream.on("error", abort); stream.once("close", () => { session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); return true; } headers[HTTP2_HEADER_PATH] = path; @@ -34048,12 +34340,13 @@ var require_client_h22 = __commonJS({ writeBodyH2(); } ++session[kOpenStreams]; - stream.setTimeout(requestTimeout); + stream.setTimeout(headersTimeout); let responseReceived = false; stream.once("response", (headers2) => { const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; request2.onResponseStarted(); responseReceived = true; + stream.setTimeout(bodyTimeout); if (request2.aborted) { stream.removeAllListeners("data"); return; @@ -34076,12 +34369,11 @@ var require_client_h22 = __commonJS({ if (!request2.aborted && !request2.completed) { request2.onComplete({}); } - client[kQueue][client[kRunningIdx]++] = null; + completeRequest(client, request2); client[kResume](); } else { abort(new InformationalError("HTTP/2: stream half-closed (remote)")); - client[kQueue][client[kRunningIdx]++] = null; - client[kPendingIdx] = client[kRunningIdx]; + completeRequest(client, request2, true); client[kResume](); } }); @@ -34091,6 +34383,9 @@ var require_client_h22 = __commonJS({ if (session[kOpenStreams] === 0) { session.unref(); } + if (!request2.aborted && !request2.completed) { + abort(new InformationalError("HTTP/2: stream closed before the response was complete")); + } }); stream.once("error", function(err) { stream.removeAllListeners("data"); @@ -34104,7 +34399,7 @@ var require_client_h22 = __commonJS({ stream.removeAllListeners("data"); }); stream.on("timeout", () => { - const err = new InformationalError(`HTTP/2: "stream timeout after ${requestTimeout}"`); + const err = responseReceived ? new BodyTimeoutError(`HTTP/2: "body timeout after ${bodyTimeout}"`) : new HeadersTimeoutError(`HTTP/2: "headers timeout after ${headersTimeout}"`); stream.removeAllListeners("data"); session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) { @@ -34602,7 +34897,9 @@ var require_client2 = __commonJS({ const requests = this[kQueue].splice(this[kPendingIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util.errorRequest(this, request2, err); + if (request2 != null) { + util.errorRequest(this, request2, err); + } } const callback = () => { if (this[kClosedResolve]) { @@ -34627,7 +34924,9 @@ var require_client2 = __commonJS({ const requests = client[kQueue].splice(client[kRunningIdx]); for (let i = 0; i < requests.length; i++) { const request2 = requests[i]; - util.errorRequest(client, request2, err); + if (request2 != null) { + util.errorRequest(client, request2, err); + } } assert(client[kSize] === 0); } @@ -35220,12 +35519,14 @@ var require_balanced_pool2 = __commonJS({ return new Pool(origin, opts); } var BalancedPool = class extends PoolBase { - constructor(upstreams = [], { factory = defaultFactory, ...opts } = {}) { + constructor(upstreams = [], { factory = defaultFactory, connect, tls, ...opts } = {}) { if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } super(opts); - this[kOptions] = { ...util.deepClone(opts) }; + if (connect && typeof connect !== "function") connect = { ...connect }; + if (tls && typeof tls !== "function") tls = { ...tls }; + this[kOptions] = { ...util.deepClone(opts), connect, tls }; this[kOptions].interceptors = opts.interceptors ? { ...opts.interceptors } : void 0; this[kIndex] = -1; this[kCurrentWeight] = 0; @@ -36689,6 +36990,55 @@ var require_retry_handler2 = __commonJS({ }); } } + var RetryController = class { + #paused = false; + #target = null; + set target(target) { + this.#target = target; + if (this.#paused) { + target?.pause(); + } + } + get target() { + return this.#target; + } + pause() { + this.#paused = true; + this.#target?.pause(); + } + resume() { + this.#paused = false; + this.#target?.resume(); + } + abort(reason) { + this.#target?.abort(reason); + } + get paused() { + return this.#paused || (this.#target?.paused ?? false); + } + get aborted() { + return this.#target?.aborted ?? false; + } + get reason() { + return this.#target?.reason ?? null; + } + get rawHeaders() { + return this.#target?.rawHeaders ?? null; + } + set rawHeaders(value) { + if (this.#target) { + this.#target.rawHeaders = value; + } + } + get rawTrailers() { + return this.#target?.rawTrailers ?? null; + } + set rawTrailers(value) { + if (this.#target) { + this.#target.rawTrailers = value; + } + } + }; var RetryHandler = class _RetryHandler { constructor(opts, { dispatch, handler: handler2 }) { const { retryOptions, ...dispatchOpts } = opts; @@ -36743,12 +37093,18 @@ var require_retry_handler2 = __commonJS({ this.start = 0; this.end = null; this.etag = null; + this.controllerProxy = new RetryController(); } onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err) { if (this.retryOpts.throwOnError) { if (this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + if (this.headersSent) { + this.handler.onResponseError?.(this.controllerProxy, err); + } else { + this.headersSent = true; + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + } } else { this.error = err; } @@ -36756,13 +37112,19 @@ var require_retry_handler2 = __commonJS({ } if (isDisturbed(this.opts.body)) { this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); return; } function shouldRetry(passedErr) { if (passedErr) { - this.headersSent = true; - this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage); + if (this.headersSent) { + this.handler.onResponseError?.(this.controllerProxy, passedErr); + } else { + this.headersSent = true; + this.checkpointResponseEnd(headers); + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage); + } controller.resume(); return; } @@ -36779,13 +37141,25 @@ var require_retry_handler2 = __commonJS({ shouldRetry.bind(this) ); } + checkpointResponseEnd(headers) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + this.resume = this.end != null; + } + } onRequestStart(controller, context) { + this.controllerProxy.target = controller; if (!this.headersSent) { - this.handler.onRequestStart?.(controller, context); + this.handler.onRequestStart?.(this.controllerProxy, context); } } - onRequestUpgrade(controller, statusCode, headers, socket) { - this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket); + onRequestUpgrade(_controller, statusCode, headers, socket) { + this.handler.onRequestUpgrade?.(this.controllerProxy, statusCode, headers, socket); } static [kRetryHandlerDefaultRetry](err, { state, opts }, cb) { const { statusCode, code, headers } = err; @@ -36859,8 +37233,12 @@ var require_retry_handler2 = __commonJS({ } 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"); + if (this.start !== start || this.end != null && this.end !== end) { + throw new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }); + } return; } if (this.end == null) { @@ -36869,7 +37247,7 @@ var require_retry_handler2 = __commonJS({ if (range == null) { this.headersSent = true; this.handler.onResponseStart?.( - controller, + this.controllerProxy, statusCode, headers, statusMessage @@ -36902,7 +37280,7 @@ var require_retry_handler2 = __commonJS({ } this.headersSent = true; this.handler.onResponseStart?.( - controller, + this.controllerProxy, statusCode, headers, statusMessage @@ -36914,24 +37292,24 @@ var require_retry_handler2 = __commonJS({ }); } } - onResponseData(controller, chunk) { + onResponseData(_controller, chunk) { if (this.error) { return; } this.start += chunk.length; - this.handler.onResponseData?.(controller, chunk); + this.handler.onResponseData?.(this.controllerProxy, chunk); } - onResponseEnd(controller, trailers) { + onResponseEnd(_controller, trailers) { if (this.error && this.retryOpts.throwOnError) { throw this.error; } if (!this.error) { this.retryCount = 0; - return this.handler.onResponseEnd?.(controller, trailers); + return this.handler.onResponseEnd?.(this.controllerProxy, trailers); } - this.retry(controller); + this.retry(); } - retry(controller) { + retry() { if (this.start !== 0) { const headers = { range: `bytes=${this.start}-${this.end ?? ""}` }; if (this.etag != null) { @@ -36949,20 +37327,20 @@ var require_retry_handler2 = __commonJS({ this.retryCountCheckpoint = this.retryCount; this.dispatch(this.opts, this); } catch (err) { - this.handler.onResponseError?.(controller, err); + this.handler.onResponseError?.(this.controllerProxy, err); } } onResponseError(controller, err) { - if (controller?.aborted || isDisturbed(this.opts.body)) { - this.handler.onResponseError?.(controller, err); + if (controller?.aborted || isDisturbed(this.opts.body) || this.headersSent && !this.resume) { + this.handler.onResponseError?.(this.controllerProxy, err); return; } function shouldRetry(returnedErr) { if (!returnedErr) { - this.retry(controller); + this.retry(); return; } - this.handler?.onResponseError?.(controller, returnedErr); + this.handler?.onResponseError?.(this.controllerProxy, returnedErr); } if (this.retryCount - this.retryCountCheckpoint > 0) { this.retryCount = this.retryCountCheckpoint + (this.retryCount - this.retryCountCheckpoint); @@ -40560,7 +40938,6 @@ var require_dump2 = __commonJS({ #maxSize = 1024 * 1024; #dumped = false; #size = 0; - #controller = null; aborted = false; reason = false; constructor({ maxSize, signal }, handler2) { @@ -40576,7 +40953,6 @@ var require_dump2 = __commonJS({ } onRequestStart(controller, context) { controller.abort = this.#abort.bind(this); - this.#controller = controller; return super.onRequestStart(controller, context); } onResponseStart(controller, statusCode, headers, statusMessage) { @@ -40592,33 +40968,26 @@ var require_dump2 = __commonJS({ return super.onResponseStart(controller, statusCode, headers, statusMessage); } onResponseError(controller, err) { - if (this.#dumped) { - return; - } - err = this.#controller?.reason ?? err; - super.onResponseError(controller, err); + super.onResponseError(controller, this.aborted === true ? this.reason : err); } onResponseData(controller, chunk) { this.#size = this.#size + chunk.length; - if (this.#size >= this.#maxSize) { + if (this.#size > this.#maxSize) { + throw new RequestAbortedError( + `Response size (${this.#size}) larger than maxSize (${this.#maxSize})` + ); + } + if (this.#size === this.#maxSize) { this.#dumped = true; - if (this.aborted === true) { - super.onResponseError(controller, this.reason); - } else { - super.onResponseEnd(controller, {}); - } } return true; } onResponseEnd(controller, trailers) { - if (this.#dumped) { - return; - } - if (this.#controller.aborted === true) { + if (this.aborted === true) { super.onResponseError(controller, this.reason); return; } - super.onResponseEnd(controller, trailers); + super.onResponseEnd(controller, this.#dumped ? {} : trailers); } }; function createDumpInterceptor({ maxSize: defaultMaxSize } = { @@ -42230,6 +42599,11 @@ var require_cache_handler = __commonJS({ return downstreamOnHeaders(); } const cacheControlHeader = resHeaders["cache-control"]; + const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; + if (revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives)) { + deleteCachedValue(this.#store, this.#cacheKey); + return downstreamOnHeaders(); + } 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)) { @@ -42237,8 +42611,7 @@ var require_cache_handler = __commonJS({ } return downstreamOnHeaders(); } - const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}; - if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { + if (!canCacheResponse(this.#cacheType, this.#cacheKey.method, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) { deleteCachedValue(this.#store, this.#cacheKey); } @@ -42401,9 +42774,12 @@ var require_cache_handler = __commonJS({ } } function revalidationResponseDisallowsCachedReuse(cacheType, resHeaders, cacheControlDirectives) { - return cacheControlDirectives["no-store"] === true || cacheType === "shared" && cacheControlDirectives.private === true || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); + return cacheControlDirectives["no-store"] === true || cacheType === "shared" && (cacheControlDirectives.private === true || Object.hasOwn(resHeaders, "set-cookie")) || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false); } - function canCacheResponse(cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + function canCacheResponse(cacheType, method, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + if (!arrayIncludes(util.safeHTTPMethods, method)) { + return false; + } if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) { return false; } @@ -42414,7 +42790,7 @@ var require_cache_handler = __commonJS({ if (cacheControlDirectives["no-store"]) { return false; } - if (cacheType === "shared" && cacheControlDirectives.private === true) { + if (cacheType === "shared" && (cacheControlDirectives.private === true || Object.hasOwn(resHeaders, "set-cookie"))) { return false; } if (resHeaders.vary && hasVaryStar(resHeaders.vary)) { @@ -42947,7 +43323,7 @@ var require_cache3 = __commonJS({ result.cacheControlDirectives?.["s-maxage"] !== void 0); } function revalidationResponseDisallowsCachedReuse(cacheType, headers) { - if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) { + if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary) || cacheType === "shared" && Object.hasOwn(headers, "set-cookie")) { return true; } const cacheControl = headers["cache-control"]; @@ -43102,6 +43478,13 @@ var require_cache3 = __commonJS({ if (!result) { return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler2, opts, reqCacheControl); } + if (globalOpts.type === "shared" && Object.hasOwn(result.headers, "set-cookie")) { + if (util.isStream(result.body)) { + result.body.on("error", nop).destroy(); + } + deleteCachedValue(globalOpts.store, cacheKey); + return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler2, opts, reqCacheControl); + } const now = Date.now(); if (now > result.deleteAt) { return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler2)); @@ -43251,6 +43634,9 @@ var require_cache3 = __commonJS({ return dispatch(opts2, handler2); } const cacheKey = makeCacheKey(opts2); + if (!arrayIncludes(util.safeHTTPMethods, opts2.method)) { + return dispatch(opts2, new CacheHandler(globalOpts, cacheKey, handler2)); + } const result = store.get(cacheKey); if (result && typeof result.then === "function") { return result.then((result2) => handleResult( @@ -43284,9 +43670,65 @@ var require_decompress = __commonJS({ "node_modules/@octokit/action/node_modules/undici/lib/interceptor/decompress.js"(exports2, module2) { "use strict"; var { createInflate, createGunzip, createBrotliDecompress, createZstdDecompress } = require("node:zlib"); - var { pipeline } = require("node:stream"); + var { pipeline, Transform: TransformStream2 } = require("node:stream"); + var { InvalidArgumentError, ResponseExceededMaxSizeError } = require_errors3(); var DecoratorHandler = require_decorator_handler2(); var { runtimeFeatures } = require_runtime_features(); + var DecompressController = class { + #onPause; + #onResume; + #onAbort; + #paused = false; + constructor(onPause, onResume, onAbort) { + this.#onPause = onPause; + this.#onResume = onResume; + this.#onAbort = onAbort; + this.target = null; + } + pause() { + if (this.#paused) { + return; + } + this.#paused = true; + this.#onPause(); + } + resume() { + if (!this.#paused) { + return; + } + this.#paused = false; + this.#onResume(); + } + abort(reason) { + this.target?.abort(reason); + this.#onAbort(reason); + } + get paused() { + return this.#paused; + } + get aborted() { + return this.target?.aborted ?? false; + } + get reason() { + return this.target?.reason ?? null; + } + get rawHeaders() { + return this.target?.rawHeaders ?? null; + } + set rawHeaders(value) { + if (this.target) { + this.target.rawHeaders = value; + } + } + get rawTrailers() { + return this.target?.rawTrailers ?? null; + } + set rawTrailers(value) { + if (this.target) { + this.target.rawTrailers = value; + } + } + }; var supportedEncodings = { gzip: createGunzip, "x-gzip": createGunzip, @@ -43300,6 +43742,23 @@ var require_decompress = __commonJS({ /** @type {const} */ [204, 304] ); + var defaultMaxSize = 0; + function createMaxSizeLimiter(maxSize) { + let size = 0; + return new TransformStream2({ + transform(chunk, _encoding, callback) { + const decompressedSize = size + chunk.length; + if (decompressedSize > maxSize) { + callback(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${maxSize})` + )); + return; + } + size = decompressedSize; + callback(null, chunk); + } + }); + } var warningEmitted = ( /** @type {boolean} */ false @@ -43307,14 +43766,128 @@ var require_decompress = __commonJS({ var DecompressHandler = class extends DecoratorHandler { /** @type {Transform[]} */ #decompressors = []; + /** @type {Record | undefined} */ + #trailers; /** @type {Readonly} */ #skipStatusCodes; /** @type {boolean} */ #skipErrorResponses; - constructor(handler2, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true } = {}) { + /** @type {number} */ + #maxSize; + /** @type {number} */ + #decompressedSize = 0; + /** @type {boolean} */ + #terminated = false; + /** @type {boolean} */ + #inputEnded = false; + /** @type {boolean} */ + #inputBackpressured = false; + /** @type {boolean} */ + #upstreamPaused = false; + /** @type {boolean} */ + #draining = false; + /** @type {boolean} */ + #drainRequested = false; + /** @type {boolean} */ + #completionPending = false; + /** @type {DecompressorStream | undefined} */ + #finalDecompressor; + /** @type {DecompressController} */ + #controller; + constructor(handler2, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true, maxSize = defaultMaxSize } = {}) { + if (!Number.isSafeInteger(maxSize) || maxSize < 0) { + throw new InvalidArgumentError("maxSize must be a non-negative integer"); + } super(handler2); this.#skipStatusCodes = skipStatusCodes; this.#skipErrorResponses = skipErrorResponses; + this.#maxSize = maxSize; + this.#controller = new DecompressController( + () => this.#onDownstreamPause(), + () => this.#onDownstreamResume(), + (reason) => { + if (this.#inputEnded && !this.#terminated) { + this.onResponseError(this.#controller, reason); + } + } + ); + } + #onDownstreamPause() { + this.#pauseUpstream(); + } + #onDownstreamResume() { + const drainWasDeferred = this.#draining; + this.#drainOutput(); + if (!drainWasDeferred) { + this.#resumeUpstreamIfNeeded(); + this.#finishIfReady(); + } + } + #pauseUpstream() { + if (!this.#upstreamPaused && !this.#terminated) { + this.#upstreamPaused = true; + this.#controller.target?.pause(); + } + } + #resumeUpstreamIfNeeded() { + if (this.#upstreamPaused && !this.#controller.paused && !this.#inputBackpressured) { + this.#upstreamPaused = false; + if (!this.#inputEnded) { + this.#controller.target?.resume(); + } + } + } + #drainOutput() { + if (this.#terminated || this.#controller.paused || !this.#finalDecompressor) { + return; + } + if (this.#draining) { + this.#drainRequested = true; + return; + } + this.#draining = true; + try { + do { + this.#drainRequested = false; + let chunk; + while (!this.#terminated && !this.#controller.paused && (chunk = this.#finalDecompressor.read()) !== null) { + if (this.#maxSize > 0) { + const decompressedSize = this.#decompressedSize + chunk.length; + if (decompressedSize > this.#maxSize) { + this.#fail(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${this.#maxSize})` + )); + return; + } + this.#decompressedSize = decompressedSize; + } + const result = super.onResponseData(this.#controller, chunk); + if (result === false && !this.#controller.paused) { + this.#controller.pause(); + } + } + } while (this.#drainRequested && !this.#terminated && !this.#controller.paused); + } finally { + this.#draining = false; + } + this.#resumeUpstreamIfNeeded(); + this.#finishIfReady(); + } + #finishIfReady() { + if (this.#terminated || !this.#completionPending || this.#controller.paused || this.#draining) { + return; + } + this.#terminated = true; + this.#cleanupDecompressors(); + super.onResponseEnd(this.#controller, this.#trailers); + } + #onDecompressionEnd() { + if (this.#terminated) { + return; + } + this.#completionPending = true; + this.#drainOutput(); + this.#finishIfReady(); } /** * Determines if decompression should be skipped based on encoding and status code @@ -43332,7 +43905,7 @@ var require_decompress = __commonJS({ * Creates a chain of decompressors for multiple content encodings * * @param {string} encodings - Comma-separated list of content encodings - * @returns {Array} - Array of decompressor streams + * @returns {Array} - Array of decompressor and limiting streams * @throws {Error} - If the number of content-encodings exceeds the maximum allowed */ #createDecompressionChain(encodings) { @@ -43351,54 +43924,81 @@ var require_decompress = __commonJS({ } decompressors.push(supportedEncodings[encoding]()); } - return decompressors; + if (decompressors.length < 2) { + return decompressors; + } + const streams = []; + for (let i = 0; i < decompressors.length; i++) { + streams.push(decompressors[i]); + if (i < decompressors.length - 1 && this.#maxSize > 0) { + streams.push(createMaxSizeLimiter(this.#maxSize)); + } + } + return streams; + } + /** + * Stops decompression and reports an error. + * @param {Error} error - The decompression error + * @returns {void} + */ + #fail(error) { + if (this.#terminated) { + return; + } + if (this.#inputEnded) { + this.onResponseError(this.#controller, error); + } else { + this.#controller.abort(error); + } } /** - * Sets up event handlers for a decompressor stream using readable events + * Sets up event handlers for the final decompressor stream. * @param {DecompressorStream} decompressor - The decompressor stream - * @param {Controller} controller - The controller to coordinate with * @returns {void} */ - #setupDecompressorEvents(decompressor, controller) { - decompressor.on("readable", () => { - let chunk; - while ((chunk = decompressor.read()) !== null) { - const result = super.onResponseData(controller, chunk); - if (result === false) { - break; - } - } - }); - decompressor.on("error", (error) => { - super.onResponseError(controller, error); - }); + #setupDecompressorEvents(decompressor) { + this.#finalDecompressor = decompressor; + decompressor.on("readable", () => this.#drainOutput()); + decompressor.on("error", (error) => this.#fail(error)); } /** * Sets up event handling for a single decompressor - * @param {Controller} controller - The controller to handle events * @returns {void} */ - #setupSingleDecompressor(controller) { + #setupSingleDecompressor() { const decompressor = this.#decompressors[0]; - this.#setupDecompressorEvents(decompressor, controller); - decompressor.on("end", () => { - super.onResponseEnd(controller, {}); - }); + this.#setupDecompressorEvents(decompressor); + decompressor.on("end", () => this.#onDecompressionEnd()); } /** * Sets up event handling for multiple chained decompressors using pipeline - * @param {Controller} controller - The controller to handle events * @returns {void} */ - #setupMultipleDecompressors(controller) { + #setupMultipleDecompressors() { const lastDecompressor = this.#decompressors[this.#decompressors.length - 1]; - this.#setupDecompressorEvents(lastDecompressor, controller); + this.#setupDecompressorEvents(lastDecompressor); pipeline(this.#decompressors, (err) => { + if (this.#terminated) { + return; + } if (err) { - super.onResponseError(controller, err); + this.#fail(err); return; } - super.onResponseEnd(controller, {}); + this.#onDecompressionEnd(); + }); + } + #setupInputBackpressure() { + const decompressor = this.#decompressors[0]; + decompressor.on("drain", () => { + if (this.#terminated) { + return; + } + this.#inputBackpressured = false; + if (!this.#controller.paused) { + this.#drainOutput(); + this.#resumeUpstreamIfNeeded(); + } }); } /** @@ -43407,6 +44007,14 @@ var require_decompress = __commonJS({ */ #cleanupDecompressors() { this.#decompressors.length = 0; + this.#finalDecompressor = void 0; + } + onRequestStart(controller, context) { + this.#controller.target = controller; + return super.onRequestStart(this.#controller, context); + } + onRequestUpgrade(controller, statusCode, headers, socket) { + return super.onRequestUpgrade(this.#controller, statusCode, headers, socket); } /** * @param {Controller} controller @@ -43418,21 +44026,45 @@ var require_decompress = __commonJS({ onResponseStart(controller, statusCode, headers, statusMessage) { const contentEncoding = headers["content-encoding"]; if (this.#shouldSkipDecompression(contentEncoding, statusCode)) { - return super.onResponseStart(controller, statusCode, headers, statusMessage); + return super.onResponseStart(this.#controller, statusCode, headers, statusMessage); } const decompressors = this.#createDecompressionChain(contentEncoding.toLowerCase()); if (decompressors.length === 0) { this.#cleanupDecompressors(); - return super.onResponseStart(controller, statusCode, headers, statusMessage); + return super.onResponseStart(this.#controller, statusCode, headers, statusMessage); } this.#decompressors = decompressors; const { "content-encoding": _, "content-length": __, ...newHeaders } = headers; + if (this.#controller.rawHeaders) { + const rawHeaders = this.#controller.rawHeaders; + if (Array.isArray(rawHeaders)) { + const filteredHeaders = []; + for (let i = 0; i < rawHeaders.length; i += 2) { + const headerName = rawHeaders[i]; + const name = Buffer.isBuffer(headerName) ? headerName.toString("latin1") : `${headerName}`; + const lowerName = name.toLowerCase(); + if (lowerName === "content-encoding" || lowerName === "content-length") { + continue; + } + filteredHeaders.push(rawHeaders[i], rawHeaders[i + 1]); + } + rawHeaders.splice(0, rawHeaders.length, ...filteredHeaders); + } else if (typeof rawHeaders === "object") { + for (const name of Object.keys(rawHeaders)) { + const lowerName = name.toLowerCase(); + if (lowerName === "content-encoding" || lowerName === "content-length") { + delete rawHeaders[name]; + } + } + } + } + this.#setupInputBackpressure(); if (this.#decompressors.length === 1) { - this.#setupSingleDecompressor(controller); + this.#setupSingleDecompressor(); } else { - this.#setupMultipleDecompressors(controller); + this.#setupMultipleDecompressors(); } - return super.onResponseStart(controller, statusCode, newHeaders, statusMessage); + return super.onResponseStart(this.#controller, statusCode, newHeaders, statusMessage); } /** * @param {Controller} controller @@ -43441,10 +44073,13 @@ var require_decompress = __commonJS({ */ onResponseData(controller, chunk) { if (this.#decompressors.length > 0) { - this.#decompressors[0].write(chunk); + if (!this.#decompressors[0].write(chunk)) { + this.#inputBackpressured = true; + this.#pauseUpstream(); + } return; } - super.onResponseData(controller, chunk); + return super.onResponseData(this.#controller, chunk); } /** * @param {Controller} controller @@ -43453,11 +44088,12 @@ var require_decompress = __commonJS({ */ onResponseEnd(controller, trailers) { if (this.#decompressors.length > 0) { + this.#inputEnded = true; + this.#trailers = trailers; this.#decompressors[0].end(); - this.#cleanupDecompressors(); return; } - super.onResponseEnd(controller, trailers); + return super.onResponseEnd(this.#controller, trailers); } /** * @param {Controller} controller @@ -43465,13 +44101,15 @@ var require_decompress = __commonJS({ * @returns {void} */ onResponseError(controller, err) { - if (this.#decompressors.length > 0) { - for (const decompressor of this.#decompressors) { - decompressor.destroy(err); - } - this.#cleanupDecompressors(); + if (this.#terminated) { + return; } - super.onResponseError(controller, err); + this.#terminated = true; + for (const decompressor of this.#decompressors) { + decompressor.destroy(); + } + this.#cleanupDecompressors(); + super.onResponseError(this.#controller, err); } }; function createDecompressInterceptor(options = {}) { @@ -49058,11 +49696,11 @@ var require_connection2 = __commonJS({ processResponse(response) { if (response.type === "error" || response.status !== 101) { if (response.socket?.session == null) { - failWebsocketConnection(handler2, 1002, "Received network error or non-101 status code.", response.error); + failHandshake(handler2, response, 1002, "Received network error or non-101 status code.", response.error); return; } if (response.status !== 200) { - failWebsocketConnection(handler2, 1002, "Received network error or non-200 status code.", response.error); + failHandshake(handler2, response, 1002, "Received network error or non-200 status code.", response.error); return; } } @@ -49071,21 +49709,21 @@ var require_connection2 = __commonJS({ warningEmitted = true; } if (protocols.length !== 0 && !response.headersList.get("Sec-WebSocket-Protocol")) { - failWebsocketConnection(handler2, 1002, "Server did not respond with sent protocols."); + failHandshake(handler2, response, 1002, "Server did not respond with sent protocols."); return; } if (response.socket.session == null && response.headersList.get("Upgrade")?.toLowerCase() !== "websocket") { - failWebsocketConnection(handler2, 1002, 'Server did not set Upgrade header to "websocket".'); + failHandshake(handler2, response, 1002, 'Server did not set Upgrade header to "websocket".'); return; } if (response.socket.session == null && response.headersList.get("Connection")?.toLowerCase() !== "upgrade") { - failWebsocketConnection(handler2, 1002, 'Server did not set Connection header to "upgrade".'); + failHandshake(handler2, response, 1002, 'Server did not set Connection header to "upgrade".'); return; } const secWSAccept = response.headersList.get("Sec-WebSocket-Accept"); const digest = crypto.hash("sha1", keyValue + uid, "base64"); if (secWSAccept !== digest) { - failWebsocketConnection(handler2, 1002, "Incorrect hash received in Sec-WebSocket-Accept header."); + failHandshake(handler2, response, 1002, "Incorrect hash received in Sec-WebSocket-Accept header."); return; } const secExtension = response.headersList.get("Sec-WebSocket-Extensions"); @@ -49093,15 +49731,15 @@ var require_connection2 = __commonJS({ if (secExtension !== null) { extensions = parseExtensions(secExtension); if (!extensions.has("permessage-deflate")) { - failWebsocketConnection(handler2, 1002, "Sec-WebSocket-Extensions header does not match."); + failHandshake(handler2, response, 1002, "Sec-WebSocket-Extensions header does not match."); return; } } const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { - failWebsocketConnection(handler2, 1002, "Protocol was not set in the opening handshake."); + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + failHandshake(handler2, response, 1002, "Protocol was not set in the opening handshake."); return; } } @@ -49147,6 +49785,12 @@ var require_connection2 = __commonJS({ object.readyState = states.CLOSING; } } + function failHandshake(handler2, response, code, reason, cause) { + if (response.socket?.session != null && !response.socket.destroyed) { + response.socket.destroy(); + } + failWebsocketConnection(handler2, code, reason, cause); + } function failWebsocketConnection(handler2, code, reason, cause) { if (isEstablished(handler2.readyState)) { closeWebSocketConnection(handler2, code, reason, false); @@ -49218,6 +49862,7 @@ var require_permessage_deflate2 = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -50295,9 +50940,9 @@ var require_websocketstream = __commonJS({ #readableStream; /** @type {ReadableStreamDefaultController} */ #readableStreamController; - // Each WebSocketStream object has an associated writable stream , which is a WritableStream . - /** @type {WritableStream} */ - #writableStream; + // Retain the controller so the writable stream can be errored while locked. + /** @type {WritableStreamDefaultController} */ + #writableStreamController; // Each WebSocketStream object has an associated boolean handshake aborted , which is initially false. #handshakeAborted = false; /** @type {import('../websocket').Handler} */ @@ -50452,12 +51097,14 @@ var require_websocketstream = __commonJS({ cancel: (reason) => this.#cancel(reason) }); const writable = new WritableStream({ + start: (controller) => { + this.#writableStreamController = controller; + }, write: (chunk) => this.#write(chunk), close: () => closeWebSocketConnection(this.#handler, null, null), abort: (reason) => this.#closeUsingReason(reason) }); this.#readableStream = readable; - this.#writableStream = writable; this.#openedPromise.resolve({ extensions, protocol, @@ -50501,9 +51148,7 @@ var require_websocketstream = __commonJS({ const reason = result?.reason == null ? "" : utf8DecodeBytes(Buffer.from(result.reason)); if (wasClean) { this.#readableStreamController.close(); - if (!this.#writableStream.locked) { - this.#writableStream.abort(new DOMException("A closed WebSocketStream cannot be written to", "InvalidStateError")); - } + this.#writableStreamController.error(new DOMException("A closed WebSocketStream cannot be written to", "InvalidStateError")); this.#closedPromise.resolve({ closeCode: code, reason @@ -50511,7 +51156,7 @@ var require_websocketstream = __commonJS({ } else { const error = createUnvalidatedWebSocketError("unclean close", code, reason); this.#readableStreamController?.error(error); - this.#writableStream?.abort(error); + this.#writableStreamController?.error(error); this.#closedPromise.reject(error); } } @@ -50606,6 +51251,40 @@ var require_eventsource_stream2 = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -50625,10 +51304,13 @@ var require_eventsource_stream2 = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer|null} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -50660,63 +51342,30 @@ var require_eventsource_stream2 = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id !== void 0 || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -50725,17 +51374,16 @@ var require_eventsource_stream2 = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -50751,43 +51399,42 @@ var require_eventsource_stream2 = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -50812,12 +51459,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = {