Commit 914c1c8a6f0 for nodejs
commit 914c1c8a6f0765eb0b0f030e52234d69a220bc2e
Author: Node.js GitHub Bot <github-bot@iojs.org>
Date: Mon Sep 28 21:40:06 2026 -0400
deps: update undici to 8.11.2
PR-URL: https://github.com/nodejs/node/pull/66332
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
diff --git a/deps/undici/src/README.md b/deps/undici/src/README.md
index 8ccd602b5c5..169d0cab13d 100644
--- a/deps/undici/src/README.md
+++ b/deps/undici/src/README.md
@@ -378,7 +378,16 @@ The `body` mixins are the most common way to format the request/response body. M
> The body returned from `undici.request` does not implement `.formData()`.
> [!WARNING]
-> Calling `body.formData()` on a fetch response causes undici to buffer and parse the entire body. Since this is dictated by the spec, `body.formData()` must only be called on responses from trusted servers.
+> The body mixins `.arrayBuffer()`, `.blob()`, `.bytes()`, `.json()`, `.text()`,
+> and `.formData()` buffer the entire body in memory before returning. Where
+> applicable, they also decode or parse the payload and retain that
+> representation in memory. Calling these methods therefore means trusting that
+> the response body is small enough to fit in the available memory. Do not use
+> them for responses from untrusted or user-controlled sources. Instead, consume
+> the response body as a stream and enforce an application-specific size limit:
+> use `response.body` for fetch responses or the `body` returned by
+> `undici.request()`. For streaming decoded text, use `body.textStream()` on a
+> fetch `Request` or `Response`.
Example usage:
diff --git a/deps/undici/src/SECURITY.md b/deps/undici/src/SECURITY.md
index ad984a32f28..6fed3847fba 100644
--- a/deps/undici/src/SECURITY.md
+++ b/deps/undici/src/SECURITY.md
@@ -153,16 +153,26 @@ lead to a loss of confidentiality, integrity, or availability.
resources, that is not considered a vulnerability. Applications are
responsible for setting appropriate limits on response sizes.
-#### Calling `body.formData()` on untrusted responses
-
-* `body.formData()` buffers and parses the entire response body. Multipart
- parsing has inherent security risks, especially when the body is supplied by
- an untrusted or user-controlled server. Applications must only call
- `body.formData()` on responses from trusted servers. For untrusted responses,
- applications should use a dedicated streaming multipart parser and enforce
- application-specific limits. Resource exhaustion or parser exposure caused by
- calling `body.formData()` on untrusted responses is considered an application
- responsibility, not a vulnerability in undici.
+#### Calling body-consuming methods on untrusted responses
+
+* The `body.arrayBuffer()`, `body.blob()`, `body.bytes()`, `body.formData()`,
+ `body.json()`, and `body.text()` methods buffer the entire response body in
+ memory before returning. Where applicable, they also decode or parse the
+ payload and retain that representation in memory. Calling one of these
+ methods means the application trusts that the response is small enough to
+ fit in the available memory. Applications must not use these methods on
+ responses from untrusted or user-controlled servers. They should instead
+ process the response with a streaming API, such as `Response.body`,
+ `body.textStream()`, or the `Readable` body returned by `undici.request()`,
+ and enforce application-specific size limits while streaming. Resource
+ exhaustion caused by buffering an untrusted response is considered an
+ application responsibility, not a vulnerability in undici.
+
+* Multipart parsing has additional inherent security risks. Applications
+ processing untrusted multipart responses should use a dedicated streaming
+ multipart parser and enforce application-specific limits. Parser exposure
+ caused by calling `body.formData()` on an untrusted response is considered an
+ application responsibility, not a vulnerability in undici.
#### HTTP/1.1 keep-alive with untrusted servers
diff --git a/deps/undici/src/docs/docs/api/Agent.md b/deps/undici/src/docs/docs/api/Agent.md
index 0c59b6eac56..7d2a093634d 100644
--- a/deps/undici/src/docs/docs/api/Agent.md
+++ b/deps/undici/src/docs/docs/api/Agent.md
@@ -56,16 +56,16 @@ changes:
`Infinity`, no limit is enforced. Must be a number greater than `0`.
**Default:** `Infinity`.
-`Agent` inherits all {PoolOptions} (and therefore all {ClientOptions}). The
-per-origin {Pool} it creates uses the default unlimited `connections`, so
-concurrent requests to the same origin are spread across separate {Client}
-instances on separate sockets.
+`Agent` inherits all {PoolOptions} (and therefore all {ClientOptions}). Each
+origin gets a separate {Pool}, with `connections` acting as the maximum number
+of clients that pool may create.
> [!NOTE]
-> Because each concurrent request to an origin may use a different {Client},
-> HTTP/2 multiplexing on a shared session does not apply unless `connections` is
-> set to a small value (for example `connections: 1`). See {PoolOptions} and
-> {ClientOptions} for the full set of inherited options such as `allowH2`
+> For an h2-capable HTTPS origin, the per-origin pool waits for the first TLS
+> connection to finish ALPN negotiation. If the server selects h2, concurrent
+> requests share that session up to `maxConcurrentStreams`. If it selects
+> HTTP/1.1, normal connection fan-out resumes up to `connections`. See
+> {PoolOptions} and {ClientOptions} for inherited options such as `allowH2`
> (default `true`) and `maxConcurrentStreams` (default `100`).
### `agent.closed`
diff --git a/deps/undici/src/docs/docs/api/DiagnosticsChannel.md b/deps/undici/src/docs/docs/api/DiagnosticsChannel.md
index aee300302fc..8ff80ecdbad 100644
--- a/deps/undici/src/docs/docs/api/DiagnosticsChannel.md
+++ b/deps/undici/src/docs/docs/api/DiagnosticsChannel.md
@@ -120,7 +120,8 @@ diagnosticsChannel.channel('undici:request:bodySent').subscribe(({ request }) =>
added: v6.3.0
-->
-Published after the response headers have been received.
+Published after the response headers have been received. This includes a
+successful CONNECT or protocol upgrade response.
* `message` {Object}
* `request` {Object} The same object published by
@@ -128,8 +129,9 @@ Published after the response headers have been received.
* `response` {Object} The response being received.
* `statusCode` {number} The HTTP status code.
* `statusText` {string} The HTTP status message.
- * `headers` {Buffer[]} The raw response headers as an array of buffers,
- alternating between header name and value.
+ * `headers` {Buffer[]|Object} HTTP/1.1 response headers are an array of
+ buffers alternating between header name and value. HTTP/2 response
+ headers are an object.
```mjs
import diagnosticsChannel from 'node:diagnostics_channel'
@@ -137,7 +139,7 @@ import diagnosticsChannel from 'node:diagnostics_channel'
diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, response }) => {
console.log('statusCode', response.statusCode)
console.log(response.statusText)
- console.log(response.headers.map((x) => x.toString()))
+ console.log(response.headers)
})
```
@@ -168,8 +170,9 @@ diagnosticsChannel.channel('undici:request:bodyChunkReceived').subscribe(({ requ
added: v6.3.0
-->
-Published after the response body and trailers have been received, that is, once
-the response has fully completed.
+Published once the response has fully completed. After an upgraded socket has
+been passed to the request handler, this event is published with an empty
+`trailers` array.
* `message` {Object}
* `request` {Object} The same object published by
diff --git a/deps/undici/src/docs/docs/api/Dispatcher.md b/deps/undici/src/docs/docs/api/Dispatcher.md
index 10d4fcf1968..c85705b4c52 100644
--- a/deps/undici/src/docs/docs/api/Dispatcher.md
+++ b/deps/undici/src/docs/docs/api/Dispatcher.md
@@ -466,6 +466,15 @@ example, calling `text()` after `json()` throws a `TypeError`. The body also
provides `dump({ limit })`, which discards up to `limit` bytes (default
`131072`) without destroying the socket.
+> [!WARNING]
+> The `arrayBuffer()`, `blob()`, `bytes()`, `json()`, and `text()` methods buffer
+> the entire body in memory before returning. Where applicable, they also decode
+> or parse the payload and retain that representation in memory. Calling these
+> methods therefore means trusting that the body is small enough to fit in the
+> available memory. Do not use them for bodies received from untrusted or
+> user-controlled sources. Instead, process `body` as a `Readable` stream and
+> enforce an application-specific size limit.
+
The body is always a `Readable`, even when empty. Deserializing an empty body
with `json()` throws. To guard against this, verify the status code is not `204`
and the `content-type` header starts with `application/json` before calling
diff --git a/deps/undici/src/docs/docs/api/Errors.md b/deps/undici/src/docs/docs/api/Errors.md
index 713537395b2..d390bfaeb00 100644
--- a/deps/undici/src/docs/docs/api/Errors.md
+++ b/deps/undici/src/docs/docs/api/Errors.md
@@ -446,6 +446,31 @@ The response returned an error status code. This is raised, for example, when th
* `headers` {Object|string[]|null} The response headers. (optional)
* `body` {Object|string|null} The response body. (optional)
+## Class: `ProxyConnectionError`
+
+<!-- YAML
+added: v8.10.1
+changes:
+ - version: v8.10.1
+ pr-url: https://github.com/nodejs/undici/pull/5707
+ description: Added to fail the request instead of retrying forever when the proxy connection is torn down.
+-->
+
+* Extends: {UndiciError}
+
+A connection to the proxy failed in a way that cannot be recovered on the
+same connection, so the request fails instead of being retried.
+
+* `name` {string} Always `'ProxyConnectionError'`.
+* `code` {string} Always `'UND_ERR_PRX_CONN'`.
+* `cause` {Error} The underlying error that caused the proxy connection to fail.
+
+### `new ProxyConnectionError(cause[, message[, options]])`
+
+* `cause` {Error} The underlying error. (optional)
+* `message` {string} The error message. (optional)
+* `options` {Object} Additional `Error` options merged with `cause`. (optional)
+
## Class: `SecureProxyConnectionError`
<!-- YAML
diff --git a/deps/undici/src/docs/docs/api/Fetch.md b/deps/undici/src/docs/docs/api/Fetch.md
index af352742232..86bc8d70c20 100644
--- a/deps/undici/src/docs/docs/api/Fetch.md
+++ b/deps/undici/src/docs/docs/api/Fetch.md
@@ -596,6 +596,16 @@ properties for reading a body. Each consuming method reads the body once; after
the body has been consumed, [`bodyUsed`](#bodybodyused) becomes `true` and
calling another consuming method throws a `TypeError`.
+> [!WARNING]
+> The `arrayBuffer()`, `blob()`, `bytes()`, `formData()`, `json()`, and `text()`
+> methods buffer the entire body in memory before returning. Where applicable,
+> they also decode or parse the payload and retain that representation in
+> memory. Calling these methods therefore means trusting that the body is small
+> enough to fit in the available memory. Do not use them for bodies received
+> from untrusted or user-controlled sources. Instead, process `body.body` or
+> `body.textStream()` incrementally and enforce an application-specific size
+> limit.
+
### `body.arrayBuffer()`
<!-- YAML
diff --git a/deps/undici/src/docs/docs/api/Interceptors.md b/deps/undici/src/docs/docs/api/Interceptors.md
index 856877c3e4a..4eefc17aec6 100644
--- a/deps/undici/src/docs/docs/api/Interceptors.md
+++ b/deps/undici/src/docs/docs/api/Interceptors.md
@@ -210,9 +210,10 @@ Automatically decompresses response bodies encoded with `gzip`, `x-gzip`,
skipped. **Default:** `[204, 304]`.
* `skipErrorResponses` {boolean} When `true`, responses with a status code
>= 400 are not decompressed. **Default:** `true`.
- * `maxSize` {number} Maximum decompressed response size in bytes. The request
- fails with a `ResponseExceededMaxSizeError` if the decoded body exceeds
- this limit. **Default:** `67108864` (64 MiB).
+ * `maxSize` {number} Maximum decompressed response size in bytes for each
+ decompression stage. The request fails with a
+ `ResponseExceededMaxSizeError` if a stage exceeds this limit. Set to `0` to
+ disable the limit. **Default:** `0`.
**Returns:** {Dispatcher.DispatcherComposeInterceptor}
diff --git a/deps/undici/src/docs/docs/api/Pool.md b/deps/undici/src/docs/docs/api/Pool.md
index dc0bd2d0f68..871d4bf9bff 100644
--- a/deps/undici/src/docs/docs/api/Pool.md
+++ b/deps/undici/src/docs/docs/api/Pool.md
@@ -73,12 +73,11 @@ connector shared by every pooled client.
> [!NOTE]
> `Pool` inherits all {ClientOptions}, including `allowH2` and
-> `maxConcurrentStreams`. With the default unlimited `connections`, the pool
-> opens a new client - and therefore a new TCP/TLS socket - per concurrent
-> dispatch, which defeats HTTP/2 multiplexing over a shared session. To benefit
-> from h2 multiplexing on a single session, cap `connections` (for example
-> `connections: 1`) so that concurrent requests share a session up to
-> `maxConcurrentStreams`.
+> `maxConcurrentStreams`. For an h2-capable HTTPS origin, the pool waits for
+> the first TLS connection to finish ALPN negotiation before opening more
+> clients. If the server selects h2, concurrent requests share that session up
+> to `maxConcurrentStreams`. If it selects HTTP/1.1, the pool resumes normal
+> connection fan-out up to `connections`.
```mjs
import { Pool } from 'undici'
diff --git a/deps/undici/src/docs/docs/index.md b/deps/undici/src/docs/docs/index.md
index ab28166fcf3..341f2d0ab56 100644
--- a/deps/undici/src/docs/docs/index.md
+++ b/deps/undici/src/docs/docs/index.md
@@ -380,7 +380,16 @@ The `body` mixins are the most common way to format the request/response body. M
> The body returned from `undici.request` does not implement `.formData()`.
> [!WARNING]
-> Calling `body.formData()` on a fetch response causes undici to buffer and parse the entire body. Since this is dictated by the spec, `body.formData()` must only be called on responses from trusted servers.
+> The body mixins `.arrayBuffer()`, `.blob()`, `.bytes()`, `.json()`, `.text()`,
+> and `.formData()` buffer the entire body in memory before returning. Where
+> applicable, they also decode or parse the payload and retain that
+> representation in memory. Calling these methods therefore means trusting that
+> the response body is small enough to fit in the available memory. Do not use
+> them for responses from untrusted or user-controlled sources. Instead, consume
+> the response body as a stream and enforce an application-specific size limit:
+> use `response.body` for fetch responses or the `body` returned by
+> `undici.request()`. For streaming decoded text, use `body.textStream()` on a
+> fetch `Request` or `Response`.
Example usage:
diff --git a/deps/undici/src/lib/api/readable.js b/deps/undici/src/lib/api/readable.js
index e3dd3dcce4b..cfdcc13a552 100644
--- a/deps/undici/src/lib/api/readable.js
+++ b/deps/undici/src/lib/api/readable.js
@@ -5,7 +5,6 @@ const { addAbortListener } = require('node:events')
const { Readable } = require('node:stream')
const { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = require('../core/errors')
const util = require('../core/util')
-const { ReadableStreamFrom } = require('../core/util')
const kConsume = Symbol('kConsume')
const kReading = Symbol('kReading')
@@ -246,7 +245,7 @@ class BodyReadable extends Readable {
*/
get body () {
if (!this[kBody]) {
- this[kBody] = ReadableStreamFrom(this)
+ this[kBody] = ReadableStream.from(this)
if (this[kConsume]) {
// TODO: Is this the best way to force a lock?
this[kBody].getReader() // Ensure stream is locked.
diff --git a/deps/undici/src/lib/core/request.js b/deps/undici/src/lib/core/request.js
index a7493c3c97c..a66d9311664 100644
--- a/deps/undici/src/lib/core/request.js
+++ b/deps/undici/src/lib/core/request.js
@@ -368,10 +368,22 @@ class Request {
}
}
- onRequestUpgrade (statusCode, headers, socket) {
+ /**
+ * @param {number} statusCode
+ * @param {Buffer[]|string[]|import('../../types/header.d.ts').IncomingHttpHeaders} headers
+ * @param {import('node:stream').Duplex} socket
+ * @param {string} [statusText]
+ */
+ onRequestUpgrade (statusCode, headers, socket, statusText = '') {
+ this.onFinally()
+
assert(!this.aborted)
assert(!this.completed)
+ if (channels.headers.hasSubscribers) {
+ channels.headers.publish({ request: this, response: { statusCode, headers, statusText } })
+ }
+
const controller = this[kController]
if (controller) {
controller.rawHeaders = headers
@@ -379,7 +391,16 @@ class Request {
const parsedHeaders = Array.isArray(headers) ? parseHeaders(headers) : headers
- return this[kHandler].onRequestUpgrade?.(controller, statusCode, parsedHeaders, socket)
+ const result = this[kHandler].onRequestUpgrade?.(controller, statusCode, parsedHeaders, socket)
+
+ if (!this.aborted) {
+ this.completed = true
+ if (channels.trailers.hasSubscribers) {
+ channels.trailers.publish({ request: this, trailers: [] })
+ }
+ }
+
+ return result
}
onResponseEnd (trailers) {
diff --git a/deps/undici/src/lib/core/util.js b/deps/undici/src/lib/core/util.js
index f00ddfce0d1..98cb7228fff 100644
--- a/deps/undici/src/lib/core/util.js
+++ b/deps/undici/src/lib/core/util.js
@@ -644,44 +644,6 @@ function getSocketInfo (socket) {
}
}
-/**
- * @param {Iterable} iterable
- * @returns {ReadableStream}
- */
-function ReadableStreamFrom (iterable) {
- // We cannot use ReadableStream.from here because it does not return a byte stream.
-
- let iterator
- return new ReadableStream(
- {
- start () {
- iterator = iterable[Symbol.asyncIterator]()
- },
- pull (controller) {
- return iterator.next().then(({ done, value }) => {
- if (done) {
- return queueMicrotask(() => {
- controller.close()
- controller.byobRequest?.respond(0)
- })
- } else {
- const buf = Buffer.isBuffer(value) ? value : Buffer.from(value)
- if (buf.byteLength) {
- return controller.enqueue(new Uint8Array(buf))
- } else {
- return this.pull(controller)
- }
- }
- })
- },
- cancel () {
- return iterator.return()
- },
- type: 'bytes'
- }
- )
-}
-
/**
* The object should be a FormData instance and contains all the required
* methods.
@@ -1026,7 +988,6 @@ module.exports = {
destroy,
bodyLength,
deepClone,
- ReadableStreamFrom,
isBuffer,
assertRequestHandler,
getSocketInfo,
diff --git a/deps/undici/src/lib/dispatcher/client-h1.js b/deps/undici/src/lib/dispatcher/client-h1.js
index f06ca74bfe5..3cc24713a37 100644
--- a/deps/undici/src/lib/dispatcher/client-h1.js
+++ b/deps/undici/src/lib/dispatcher/client-h1.js
@@ -70,8 +70,14 @@ function lazyllhttp () {
let mod
- // We disable wasm SIMD on ppc64 as it seems to be broken on Power 9 architectures.
- let useWasmSIMD = process.arch !== 'ppc64'
+ // We disable wasm SIMD on older versions of Node.js on ppc64 that are broken on Power >=9 architectures.
+ 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
+ }
+ }
// The Env Variable UNDICI_NO_WASM_SIMD allows explicitly overriding the default behavior
if (process.env.UNDICI_NO_WASM_SIMD === '1') {
useWasmSIMD = false
@@ -561,7 +567,7 @@ class Parser {
* @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)
@@ -596,8 +602,9 @@ class Parser {
client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade'))
try {
- request.onRequestUpgrade(statusCode, headers, socket)
+ request.onRequestUpgrade(statusCode, headers, socket, statusText)
} catch (err) {
+ util.errorRequest(client, request, err)
util.destroy(socket, err)
}
diff --git a/deps/undici/src/lib/dispatcher/client-h2.js b/deps/undici/src/lib/dispatcher/client-h2.js
index 55179000eba..44d1c13da73 100644
--- a/deps/undici/src/lib/dispatcher/client-h2.js
+++ b/deps/undici/src/lib/dispatcher/client-h2.js
@@ -5,6 +5,7 @@ const { pipeline } = require('node:stream')
const util = require('../core/util.js')
const {
RequestContentLengthMismatchError,
+ ResponseContentLengthMismatchError,
RequestAbortedError,
SocketError,
InformationalError,
@@ -193,6 +194,11 @@ function canReplayRequest (request) {
return body == null || util.isBuffer(body) || util.isBlobLike(body)
}
+function hasResponseStarted (request) {
+ const state = request[kRequestStream]?.[kRequestStreamState]
+ return state?.responseReceived === true
+}
+
// Count a GOAWAY refusal against the request's replay budget. A peer that
// refuses every connection must eventually surface an error to the caller
// rather than being retried forever. Kept separate from canReplayRequest so
@@ -406,7 +412,8 @@ function resumeH2 (client) {
const session = client[kHTTP2Session]
if (socket?.destroyed === false) {
- if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) {
+ // After an upgrade the queue is empty but its stream is still in use, so never unref while a stream is open.
+ if (session[kOpenStreams] === 0 && client[kSize] === 0) {
unrefH2Session(session)
} else {
refH2Session(session)
@@ -640,9 +647,12 @@ function onHttp2SessionGoAway (errorCode, lastStreamID) {
const request = client[kQueue][i]
if (request != null) {
+ // Read before detaching, which drops the stream state.
+ const responseStarted = hasResponseStarted(request)
+
streamsToClose.push(detachRequestStreamForClose(request))
- if (canReplayRequest(request) && registerGoAwayRefusal(request)) {
+ if (!responseStarted && canReplayRequest(request) && registerGoAwayRefusal(request)) {
retriableRequests.push(request)
} else {
util.errorRequest(client, request, err)
@@ -770,10 +780,12 @@ function noop () {}
function closeStreamSession (stream) {
const session = stream[kHTTP2Session]
+ const client = session[kClient]
stream[kHTTP2Session] = null
session[kOpenStreams] -= 1
- if (session[kOpenStreams] === 0) {
+ // A session that received GOAWAY does not need to stay ref'd for queued requests.
+ if (session[kOpenStreams] === 0 && (client[kSize] === 0 || session[kReceivedGoAway])) {
unrefH2Session(session)
setHttp2IdleTimeout(session)
}
@@ -931,9 +943,14 @@ function onUpgradeResponse (headers, _flags) {
const statusCode = headers[HTTP2_HEADER_STATUS]
delete headers[HTTP2_HEADER_STATUS]
- request.onRequestUpgrade(statusCode, headers, stream)
+ try {
+ request.onRequestUpgrade(statusCode, headers, stream)
+ } catch (err) {
+ state.abort(err)
+ return
+ }
- if (request.aborted || request.completed) {
+ if (request.aborted) {
return
}
@@ -1033,6 +1050,7 @@ function writeH2 (client, request) {
headersTimeout,
bodyTimeout,
requestFinalized: false,
+ responseContentLength: null,
responseReceived: false,
bodySent: false,
pendingEnd: false,
@@ -1328,12 +1346,17 @@ function onData (chunk) {
return
}
- const { request, maxResponseSize } = state
+ const { request, maxResponseSize, responseContentLength } = state
if (request.aborted || request.completed) {
return
}
+ if (responseContentLength != null && state.bytesRead + chunk.length > responseContentLength) {
+ state.abort(new ResponseContentLengthMismatchError())
+ return
+ }
+
if (maxResponseSize > -1 && state.bytesRead + chunk.length > maxResponseSize) {
// Unlike HTTP/1.1, which destroys the socket because it cannot abandon one
// response without losing framing, resetting the offending stream leaves
@@ -1392,11 +1415,20 @@ function onResponse (headers) {
stream.end()
}
- const statusCode = headers[HTTP2_HEADER_STATUS]
+ const statusCode = Number(headers[HTTP2_HEADER_STATUS])
delete headers[HTTP2_HEADER_STATUS]
request.onResponseStarted()
state.responseReceived = true
+ // A Content-Length in HEAD and 304 responses describes the selected
+ // representation rather than DATA on this stream. Successful CONNECT uses
+ // the upgrade path above; all other final responses use Content-Length as
+ // their DATA payload length.
+ if (request.method !== 'HEAD' && statusCode !== 304) {
+ const contentLength = headers[HTTP2_HEADER_CONTENT_LENGTH]
+ state.responseContentLength = contentLength == null ? null : Number(contentLength)
+ }
+
if (state.headersTimeout || state.bodyTimeout) {
stream.setTimeout(state.bodyTimeout)
}
@@ -1414,7 +1446,7 @@ function onResponse (headers) {
return
}
- if (request.onResponseStart(Number(statusCode), headers, stream.resume.bind(stream), '') === false) {
+ if (request.onResponseStart(statusCode, headers, stream.resume.bind(stream), '') === false) {
stream.pause()
}
@@ -1437,6 +1469,11 @@ function onEnd () {
// trailers on the state by now, so completing here still delivers them.
if (state.responseReceived) {
if (!request.aborted && !request.completed) {
+ if (state.responseContentLength != null && state.bytesRead !== state.responseContentLength) {
+ state.abort(new ResponseContentLengthMismatchError())
+ return
+ }
+
state.pendingEnd = true
// Complete on 'end': a blocked event loop can keep the stream's 'close'
@@ -1493,6 +1530,13 @@ function onError (err) {
stream.off('error', onError)
+ // Node's HTTP/2 implementation can turn an incomplete Content-Length body
+ // into a protocol stream error instead of emitting 'end'. Prefer the
+ // content-length mismatch error when the received byte count proves it.
+ if (state.responseContentLength != null && state.bytesRead !== state.responseContentLength) {
+ err = new ResponseContentLengthMismatchError()
+ }
+
if (typeof stream.rstCode === 'number' && stream.rstCode !== NGHTTP2_NO_ERROR) {
err.http2ErrorCode = stream.rstCode
}
diff --git a/deps/undici/src/lib/dispatcher/client.js b/deps/undici/src/lib/dispatcher/client.js
index ec81541f9a5..6acca434fbf 100644
--- a/deps/undici/src/lib/dispatcher/client.js
+++ b/deps/undici/src/lib/dispatcher/client.js
@@ -238,7 +238,7 @@ class Client extends DispatcherBase {
throw new InvalidArgumentError('h2Options.settings.initialWindowSize must be a positive integer, greater than 0')
}
- if (h2Options.maxConcurrentStreams != null && (!Number.isInteger(h2Options.connectionWindowSize) || h2Options.maxConcurrentStreams < 1)) {
+ if (h2Options.maxConcurrentStreams != null && (!Number.isInteger(h2Options.maxConcurrentStreams) || h2Options.maxConcurrentStreams < 1)) {
throw new InvalidArgumentError('h2Options.maxConcurrentStreams must be a positive integer, greater than 0')
}
@@ -700,6 +700,11 @@ function _resume (client, sync) {
return
}
+ if (request.aborted) {
+ client[kQueue].splice(client[kPendingIdx], 1)
+ continue
+ }
+
if (client[kUrl].protocol === 'https:' && client[kServerName] !== request.servername) {
if (client[kRunning] > 0) {
return
diff --git a/deps/undici/src/lib/dispatcher/env-http-proxy-agent.js b/deps/undici/src/lib/dispatcher/env-http-proxy-agent.js
index 5d943dbd250..7fe52dcc7cb 100644
--- a/deps/undici/src/lib/dispatcher/env-http-proxy-agent.js
+++ b/deps/undici/src/lib/dispatcher/env-http-proxy-agent.js
@@ -94,17 +94,25 @@ class EnvHttpProxyAgent extends DispatcherBase {
if (this.#noProxyEntries.length === 0) {
return true // Always proxy if NO_PROXY is not set or empty.
}
- if (this.#noProxyValue === '*') {
- return false // Never proxy if wildcard is set.
- }
for (let i = 0; i < this.#noProxyEntries.length; i++) {
const entry = this.#noProxyEntries[i]
+ // A bare `*` entry matches all hosts regardless of its position or the
+ // surrounding whitespace (e.g. ` * ` or `none.invalid,*`). If a port is
+ // attached (`*:80`) it only bypasses that port.
+ if (entry.hostname === '*') {
+ if (entry.port && entry.port !== port) {
+ continue
+ }
+ return false // Never proxy if a wildcard entry is present.
+ }
if (entry.port && entry.port !== port) {
continue // Skip if ports don't match.
}
- // Don't proxy if the hostname is equal with the no_proxy host.
- if (hostname === entry.hostname) {
+ // Don't proxy if the hostname is equal with the no_proxy host. A
+ // `*.example.com` wildcard matches subdomains only, not the apex
+ // `example.com`, so exact matches are skipped for wildcard entries.
+ if (!entry.wildcard && hostname === entry.hostname) {
return false
}
// Don't proxy if the hostname is the subdomain of the no_proxy host.
@@ -149,10 +157,17 @@ class EnvHttpProxyAgent extends DispatcherBase {
port = parsed ? Number.parseInt(parsed[2], 10) : 0
}
+ // A leading `*` marks a subdomain wildcard (`*.example.com`), distinct
+ // from a plain or leading-dot suffix (`example.com` / `.example.com`)
+ // which also matches the apex. `*.example.com` must only match
+ // subdomains, never the apex `example.com` itself.
+ const wildcard = entry.charCodeAt(0) === 42 /* '*' */
+
noProxyEntries.push({
// strip leading dot or asterisk with dot, and any trailing dot
hostname: hostname.replace(/^\*?\./, '').replace(/^(.+)\.$/, '$1').toLowerCase(),
- port
+ port,
+ wildcard
})
}
diff --git a/deps/undici/src/lib/dispatcher/pool-base.js b/deps/undici/src/lib/dispatcher/pool-base.js
index c8a91d42ba5..1aaa708c7fc 100644
--- a/deps/undici/src/lib/dispatcher/pool-base.js
+++ b/deps/undici/src/lib/dispatcher/pool-base.js
@@ -13,6 +13,9 @@ const kOnDrain = Symbol('onDrain')
const kOnConnect = Symbol('onConnect')
const kOnDisconnect = Symbol('onDisconnect')
const kOnConnectionError = Symbol('onConnectionError')
+const kOnClientBusy = Symbol('on client busy')
+const kOnClientDrain = Symbol('on client drain')
+const kDrainQueue = Symbol('drain queue')
const kGetDispatcher = Symbol('get dispatcher')
const kHasDispatcher = Symbol('has dispatcher')
const kAddClient = Symbol('add client')
@@ -28,10 +31,15 @@ class PoolBase extends DispatcherBase {
[kNeedDrain] = false;
[kOnDrain] (client, origin, targets) {
- const queue = this[kQueue]
+ if (client.closed || client.destroyed) {
+ return
+ }
+ const queue = this[kQueue]
let needDrain = false
+ this[kOnClientDrain](client)
+
while (!needDrain) {
const item = queue.shift()
if (!item) {
@@ -42,6 +50,9 @@ class PoolBase extends DispatcherBase {
}
client[kNeedDrain] = needDrain
+ if (needDrain) {
+ this[kOnClientBusy](client)
+ }
if (!needDrain && this[kNeedDrain]) {
this[kNeedDrain] = false
@@ -61,6 +72,52 @@ class PoolBase extends DispatcherBase {
}
}
+ [kOnClientBusy] () {}
+
+ [kOnClientDrain] () {}
+
+ [kDrainQueue] (origin, targets) {
+ const queue = this[kQueue]
+ let hasDispatcher = true
+
+ while (!queue.isEmpty()) {
+ const dispatcher = this[kGetDispatcher]()
+ if (!dispatcher) {
+ hasDispatcher = false
+ break
+ }
+
+ const item = queue.shift()
+ this[kQueued]--
+
+ if (!dispatcher.dispatch(item.opts, item.handler)) {
+ dispatcher[kNeedDrain] = true
+ this[kOnClientBusy](dispatcher)
+ hasDispatcher = this[kHasDispatcher]()
+ if (!hasDispatcher) {
+ break
+ }
+ }
+ }
+
+ if (hasDispatcher && this[kNeedDrain]) {
+ this[kNeedDrain] = false
+ this.emit('drain', origin, [this, ...targets])
+ }
+
+ if (this[kClosedResolve] && queue.isEmpty()) {
+ const closeAll = []
+ for (let i = 0; i < this[kClients].length; i++) {
+ const client = this[kClients][i]
+ if (!client.destroyed) {
+ closeAll.push(client.close())
+ }
+ }
+ return Promise.all(closeAll)
+ .then(this[kClosedResolve])
+ }
+ }
+
[kOnConnect] = (origin, targets) => {
this.emit('connect', origin, [this, ...targets])
};
@@ -163,6 +220,7 @@ class PoolBase extends DispatcherBase {
this[kQueued]++
} else if (!dispatcher.dispatch(opts, handler)) {
dispatcher[kNeedDrain] = true
+ this[kOnClientBusy](dispatcher)
this[kNeedDrain] = !this[kHasDispatcher]()
}
@@ -196,7 +254,7 @@ class PoolBase extends DispatcherBase {
if (this[kNeedDrain]) {
queueMicrotask(() => {
- if (this[kNeedDrain]) {
+ if (this[kNeedDrain] && !client[kNeedDrain]) {
this[kOnDrain](client, client[kUrl], [client, this])
}
})
@@ -227,6 +285,9 @@ module.exports = {
kNeedDrain,
kAddClient,
kRemoveClient,
+ kDrainQueue,
+ kOnClientBusy,
+ kOnClientDrain,
kGetDispatcher,
kHasDispatcher
}
diff --git a/deps/undici/src/lib/dispatcher/pool.js b/deps/undici/src/lib/dispatcher/pool.js
index 39bf7403236..64b5ca2947a 100644
--- a/deps/undici/src/lib/dispatcher/pool.js
+++ b/deps/undici/src/lib/dispatcher/pool.js
@@ -5,6 +5,9 @@ const {
kClients,
kNeedDrain,
kAddClient,
+ kDrainQueue,
+ kOnClientBusy,
+ kOnClientDrain,
kGetDispatcher,
kHasDispatcher,
kRemoveClient
@@ -14,17 +17,41 @@ const {
InvalidArgumentError
} = require('../core/errors')
const util = require('../core/util')
-const { kUrl } = require('../core/symbols')
+const { kConnecting, kHTTPContext, kUrl } = require('../core/symbols')
const buildConnector = require('../core/connect')
const kOptions = Symbol('options')
const kConnections = Symbol('connections')
const kFactory = Symbol('factory')
+const kProtocol = Symbol('protocol')
+const kProtocolProbe = Symbol('protocol probe')
function defaultFactory (origin, opts) {
return new Client(origin, opts)
}
+function shouldCreateProtocolProbe (pool, dispatcher) {
+ return dispatcher instanceof Client &&
+ pool[kProtocol] !== 'h1' &&
+ (pool[kOptions].useH2c === true || (pool[kUrl].protocol === 'https:' && pool[kOptions].allowH2 !== false))
+}
+
+function createClient (pool) {
+ const dispatcher = pool[kFactory](pool[kUrl], pool[kOptions])
+
+ // HTTPS does not reveal whether the peer selected h1 or h2 until ALPN
+ // completes. While h2 is still possible, let one Client probe the protocol
+ // and keep later requests in the Pool queue instead of opening one TLS
+ // connection per request. A confirmed h1 connection disables this gate and
+ // restores the usual Pool fan-out.
+ if (shouldCreateProtocolProbe(pool, dispatcher)) {
+ pool[kProtocolProbe] = dispatcher
+ }
+
+ pool[kAddClient](dispatcher)
+ return dispatcher
+}
+
class Pool extends PoolBase {
constructor (origin, {
connections,
@@ -72,6 +99,8 @@ class Pool extends PoolBase {
this[kUrl] = util.parseOrigin(origin)
this[kOptions] = { ...util.deepClone(options), connect, allowH2, useH2c, clientTtl, socketPath }
this[kFactory] = factory
+ this[kProtocol] = null
+ this[kProtocolProbe] = null
this.on('connect', (origin, targets) => {
if (clientTtl != null && clientTtl > 0) {
@@ -79,13 +108,42 @@ class Pool extends PoolBase {
Object.assign(target, { ttl: Date.now() })
}
}
+
+ const client = targets[targets.length - 1]
+ if (client instanceof Client) {
+ this[kProtocol] = client[kHTTPContext]?.version
+ }
+
+ if (client === this[kProtocolProbe]) {
+ // An h2 Client's drain event releases the requests accumulated during
+ // negotiation onto that Client. If ALPN selected h1, release the probe
+ // immediately and restore normal Pool fan-out instead.
+ if (this[kProtocol] !== 'h2') {
+ this[kProtocolProbe] = null
+ this[kDrainQueue](origin, targets.slice(1))
+ }
+ }
+ })
+
+ this.on('disconnect', (origin, targets) => {
+ if (targets.includes(this[kProtocolProbe])) {
+ this[kProtocolProbe] = null
+ this[kDrainQueue](origin, targets.slice(1))
+ }
})
- this.on('connectionError', (origin, targets, error) => {
+ this.on('connectionError', (origin, targets) => {
+ let resumeQueued = false
+
// If a connection error occurs, we remove the client from the pool,
// and emit a connectionError event. They will not be re-used.
// Fixes https://github.com/nodejs/undici/issues/3895
for (const target of targets) {
+ if (target === this[kProtocolProbe]) {
+ this[kProtocolProbe] = null
+ resumeQueued = true
+ }
+
// Do not use kRemoveClient here, as it will close the client,
// but the client cannot be closed in this state.
const idx = this[kClients].indexOf(target)
@@ -93,9 +151,29 @@ class Pool extends PoolBase {
this[kClients].splice(idx, 1)
}
}
+
+ if (resumeQueued) {
+ this[kDrainQueue](origin, targets.slice(1))
+ }
})
}
+ [kOnClientBusy] (client) {
+ if (
+ this[kProtocolProbe] === null &&
+ client[kConnecting] &&
+ shouldCreateProtocolProbe(this, client)
+ ) {
+ this[kProtocolProbe] = client
+ }
+ }
+
+ [kOnClientDrain] (client) {
+ if (client === this[kProtocolProbe]) {
+ this[kProtocolProbe] = null
+ }
+ }
+
[kGetDispatcher] () {
const clientTtlOption = this[kOptions].clientTtl
for (let i = 0; i < this[kClients].length; i++) {
@@ -110,10 +188,12 @@ class Pool extends PoolBase {
}
}
+ if (this[kProtocolProbe] !== null) {
+ return
+ }
+
if (!this[kConnections] || this[kClients].length < this[kConnections]) {
- const dispatcher = this[kFactory](this[kUrl], this[kOptions])
- this[kAddClient](dispatcher)
- return dispatcher
+ return createClient(this)
}
}
@@ -130,9 +210,12 @@ class Pool extends PoolBase {
}
}
+ if (this[kProtocolProbe] !== null) {
+ return false
+ }
+
if (!this[kConnections] || this[kClients].length < this[kConnections]) {
- const dispatcher = this[kFactory](this[kUrl], this[kOptions])
- this[kAddClient](dispatcher)
+ createClient(this)
return true
}
diff --git a/deps/undici/src/lib/dispatcher/proxy-agent.js b/deps/undici/src/lib/dispatcher/proxy-agent.js
index 2b118581eec..f82ee8d17fd 100644
--- a/deps/undici/src/lib/dispatcher/proxy-agent.js
+++ b/deps/undici/src/lib/dispatcher/proxy-agent.js
@@ -325,8 +325,8 @@ class ProxyAgent extends DispatcherBase {
}
/**
- * @param {string[] | Record<string, string>} headers
- * @returns {Record<string, string>}
+ * @param {string[] | Record<string, string> | Iterable<[string, string | string[] | undefined]>} headers
+ * @returns {Record<string, string | string[] | undefined>}
*/
function buildHeaders (headers) {
// When using undici.fetch, the headers list is stored
@@ -355,7 +355,20 @@ function buildHeaders (headers) {
const headersPair = {}
for (const [key, value] of headers) {
- headersPair[key] = value
+ if (!Object.hasOwn(headersPair, key)) {
+ headersPair[key] = value
+ continue
+ }
+
+ const previous = headersPair[key]
+ const values = []
+ if (previous !== undefined) {
+ values.push(...(Array.isArray(previous) ? previous : [previous]))
+ }
+ if (value !== undefined) {
+ values.push(...(Array.isArray(value) ? value : [value]))
+ }
+ headersPair[key] = values.length > 1 ? values : values[0]
}
return headersPair
diff --git a/deps/undici/src/lib/handler/deduplication-handler.js b/deps/undici/src/lib/handler/deduplication-handler.js
index 4d85e9cde3b..27bd14d7468 100644
--- a/deps/undici/src/lib/handler/deduplication-handler.js
+++ b/deps/undici/src/lib/handler/deduplication-handler.js
@@ -251,8 +251,11 @@ class DeduplicationHandler {
return
}
- this.#completed = true
+ // Remove the entry before callbacks can synchronously dispatch a retry.
+ this.#cleanup()
this.#primaryHandler.onResponseEnd?.(controller, trailers)
+ // A throwing end callback must still be handled by onResponseError.
+ this.#completed = true
for (const waitingHandler of this.#waitingHandlers) {
if (waitingHandler.done || waitingHandler.controller.aborted) {
@@ -267,22 +270,21 @@ class DeduplicationHandler {
continue
}
- if (waitingHandler.controller.paused && waitingHandler.bufferedChunks.length > 0) {
+ if (waitingHandler.controller.paused) {
waitingHandler.pendingTrailers = trailers
continue
}
try {
waitingHandler.handler.onResponseEnd?.(waitingHandler.controller, trailers)
- } catch {
- // Ignore errors from waiting handlers
+ } catch (err) {
+ this.#errorWaitingHandler(waitingHandler, err)
}
waitingHandler.done = true
}
this.#pruneDoneWaitingHandlers()
- this.#onComplete?.()
}
/**
@@ -296,6 +298,7 @@ class DeduplicationHandler {
this.#aborted = true
this.#completed = true
+ this.#cleanup()
this.#primaryHandler.onResponseError?.(controller, err)
@@ -304,7 +307,12 @@ class DeduplicationHandler {
}
this.#waitingHandlers = []
- this.#onComplete?.()
+ }
+
+ #cleanup () {
+ const onComplete = this.#onComplete
+ this.#onComplete = null
+ onComplete?.()
}
/**
@@ -346,8 +354,8 @@ class DeduplicationHandler {
) {
try {
waitingHandler.handler.onResponseEnd?.(waitingHandler.controller, waitingHandler.pendingTrailers)
- } catch {
- // Ignore errors from waiting handlers
+ } catch (err) {
+ this.#errorWaitingHandler(waitingHandler, err)
}
waitingHandler.pendingTrailers = null
@@ -405,7 +413,7 @@ class DeduplicationHandler {
if (waitingHandler.bufferedBytes > this.#maxBufferSize) {
const err = new RequestAbortedError(`Deduplicated waiting handler exceeded maxBufferSize (${this.#maxBufferSize} bytes) while paused`)
- this.#errorWaitingHandler(waitingHandler, err)
+ waitingHandler.controller.abort(err)
}
}
@@ -454,8 +462,13 @@ class DeduplicationHandler {
waitingHandler.bufferedChunks = []
waitingHandler.bufferedBytes = 0
- // controller.abort(err) notifies the handler via onResponseError
- waitingHandler.controller.abort(err)
+ // A response failure is not a consumer abort: retry handlers must be able
+ // to retry it just as they would a failure of the primary request.
+ try {
+ waitingHandler.handler.onResponseError?.(waitingHandler.controller, err)
+ } catch {
+ // Ignore errors from waiting handlers
+ }
}
#pruneDoneWaitingHandlers () {
diff --git a/deps/undici/src/lib/handler/redirect-handler.js b/deps/undici/src/lib/handler/redirect-handler.js
index a5d92508631..7b0a0cf927d 100644
--- a/deps/undici/src/lib/handler/redirect-handler.js
+++ b/deps/undici/src/lib/handler/redirect-handler.js
@@ -57,6 +57,11 @@ class RedirectHandler {
}
onResponseStart (controller, statusCode, headers, statusMessage) {
+ if (statusCode < 200) {
+ this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage)
+ return
+ }
+
if (this.opts.throwOnMaxRedirect && this.history.length >= this.maxRedirections) {
throw new Error('max redirects')
}
diff --git a/deps/undici/src/lib/handler/retry-handler.js b/deps/undici/src/lib/handler/retry-handler.js
index 5703f145d74..38b178d276e 100644
--- a/deps/undici/src/lib/handler/retry-handler.js
+++ b/deps/undici/src/lib/handler/retry-handler.js
@@ -47,34 +47,51 @@ function validatePartialResponseContentLength (headers, range, statusCode, retry
// so nothing outside the handler can trigger it.
class RetryController {
#onAbort
+ #paused = false
+ #target = null
constructor (onAbort) {
this.#onAbort = onAbort
- this.target = null
}
- pause () { this.target?.pause() }
- resume () { this.target?.resume() }
+ 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)
+ this.#target?.abort(reason)
this.#onAbort(reason)
}
- get paused () { return 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 }
+ 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
+ if (this.#target) {
+ this.#target.rawHeaders = value
}
}
- get rawTrailers () { return this.target?.rawTrailers ?? null }
+ get rawTrailers () { return this.#target?.rawTrailers ?? null }
set rawTrailers (value) {
- if (this.target) {
- this.target.rawTrailers = value
+ if (this.#target) {
+ this.#target.rawTrailers = value
}
}
}
@@ -142,6 +159,12 @@ class RetryHandler {
// Backoff timer returned by the retry policy, so #onAbort can cancel it.
// Null for custom policies that do not return their timer.
this.retryTimer = null
+ // A response can complete while its controller is paused if the peer closes
+ // the connection. Hold its body until the retry policy decides whether to
+ // discard it for a retry or forward it as the final response.
+ this.pendingResponseData = null
+ this.pendingResponseTrailers = null
+ this.pendingResponseEnded = false
// Set once an abort during the backoff delivered the terminal error
// downstream; late policy callbacks and connection errors are then moot.
this.aborted = false
@@ -183,6 +206,13 @@ class RetryHandler {
this.retryPending = false
this.retryTimer = null
+ const pendingData = this.pendingResponseData
+ const pendingTrailers = this.pendingResponseTrailers
+ const pendingEnd = this.pendingResponseEnded
+ this.pendingResponseData = null
+ this.pendingResponseTrailers = null
+ this.pendingResponseEnded = false
+
if (passedErr) {
if (this.headersSent) {
// The downstream handler already received the response from an
@@ -193,6 +223,15 @@ class RetryHandler {
this.headersSent = true
this.checkpointResponseEnd(headers)
this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage)
+ controller.resume()
+
+ if (pendingEnd) {
+ for (const chunk of pendingData) {
+ this.onResponseData(controller, chunk)
+ }
+ this.onResponseEnd(controller, pendingTrailers)
+ }
+ return
}
controller.resume()
return
@@ -200,6 +239,9 @@ class RetryHandler {
this.error = err
controller.resume()
+ if (pendingEnd) {
+ this.onResponseEnd(controller, pendingTrailers)
+ }
}
// The pause()/resume() pair (here and in shouldRetry) acts on THIS
@@ -213,6 +255,9 @@ class RetryHandler {
// The default policy returns its backoff timer so an abort can cancel it;
// a custom policy may return anything (or nothing), which is ignored.
this.retryPending = true
+ this.pendingResponseData = []
+ this.pendingResponseTrailers = null
+ this.pendingResponseEnded = false
this.retryTimer = this.retryOpts.retry(
err,
{
@@ -464,6 +509,11 @@ class RetryHandler {
}
onResponseData (_controller, chunk) {
+ if (this.pendingResponseData !== null) {
+ this.pendingResponseData.push(chunk)
+ return
+ }
+
if (this.error) {
return
}
@@ -474,6 +524,12 @@ class RetryHandler {
}
onResponseEnd (_controller, trailers) {
+ if (this.pendingResponseData !== null) {
+ this.pendingResponseTrailers = trailers
+ this.pendingResponseEnded = true
+ return
+ }
+
if (this.error && this.retryOpts.throwOnError) {
throw this.error
}
@@ -587,6 +643,9 @@ class RetryHandler {
this.retryPending = false
clearTimeout(this.retryTimer)
this.retryTimer = null
+ this.pendingResponseData = null
+ this.pendingResponseTrailers = null
+ this.pendingResponseEnded = false
this.handler.onResponseError?.(this.controllerProxy, reason ?? new RequestAbortedError())
}
}
diff --git a/deps/undici/src/lib/interceptor/cache.js b/deps/undici/src/lib/interceptor/cache.js
index 0b8593f7ee6..42252028d3e 100644
--- a/deps/undici/src/lib/interceptor/cache.js
+++ b/deps/undici/src/lib/interceptor/cache.js
@@ -330,6 +330,8 @@ function sendCachedValue (handler, opts, result, age, context, isStale) {
assert(!stream.destroyed, 'stream should not be destroyed')
assert(!stream.readableDidRead, 'stream should not be readableDidRead')
+ let aborted = false
+
const controller = {
rawHeaders: [],
rawTrailers: [],
@@ -343,12 +345,13 @@ function sendCachedValue (handler, opts, result, age, context, isStale) {
return stream.isPaused()
},
get aborted () {
- return stream.destroyed
+ return aborted
},
get reason () {
return stream.errored
},
abort (reason) {
+ aborted = true
stream.destroy(reason ?? new AbortError())
}
}
diff --git a/deps/undici/src/lib/interceptor/decompress.js b/deps/undici/src/lib/interceptor/decompress.js
index a0e77a37c8c..ee02f91f897 100644
--- a/deps/undici/src/lib/interceptor/decompress.js
+++ b/deps/undici/src/lib/interceptor/decompress.js
@@ -9,8 +9,63 @@ const DecoratorHandler = require('../handler/decorator-handler')
/** @typedef {import('node:stream').Transform} Controller */
/** @typedef {Transform&import('node:zlib').Zlib} DecompressorStream */
+class DecompressController {
+ #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
+ }
+ }
+}
+
/** @type {Record<string, () => DecompressorStream>} */
const supportedEncodings = {
+ __proto__: null,
gzip: createGunzip,
'x-gzip': createGunzip,
br: createBrotliDecompress,
@@ -21,7 +76,7 @@ const supportedEncodings = {
}
const defaultSkipStatusCodes = /** @type {const} */ ([204, 304])
-const defaultMaxSize = 64 * 1024 * 1024
+const defaultMaxSize = 0
/**
* Limits the output of one stage in a decompression chain.
@@ -53,7 +108,7 @@ let warningEmitted = /** @type {boolean} */ (false)
* @typedef {Object} DecompressHandlerOptions
* @property {number[]|Readonly<number[]>} [skipStatusCodes=[204, 304]] - List of status codes to skip decompression for
* @property {boolean} [skipErrorResponses] - Whether to skip decompression for error responses (status codes >= 400)
- * @property {number} [maxSize=67108864] - Maximum decompressed response size in bytes
+ * @property {number} [maxSize=0] - Maximum decompressed response size in bytes. 0 disables the limit
*/
class DecompressHandler extends DecoratorHandler {
@@ -73,16 +128,130 @@ class DecompressHandler extends DecoratorHandler {
#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 (handler, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true, maxSize = defaultMaxSize } = {}) {
- if (!Number.isSafeInteger(maxSize) || maxSize < 1) {
- throw new InvalidArgumentError('maxSize must be a positive integer')
+ if (!Number.isSafeInteger(maxSize) || maxSize < 0) {
+ throw new InvalidArgumentError('maxSize must be a non-negative integer')
}
super(handler)
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()
}
/**
@@ -138,7 +307,7 @@ class DecompressHandler extends DecoratorHandler {
const streams = []
for (let i = 0; i < decompressors.length; i++) {
streams.push(decompressors[i])
- if (i < decompressors.length - 1) {
+ if (i < decompressors.length - 1 && this.#maxSize > 0) {
streams.push(createMaxSizeLimiter(this.#maxSize))
}
}
@@ -148,11 +317,10 @@ class DecompressHandler extends DecoratorHandler {
/**
* Stops decompression and reports an error.
- * @param {Controller} controller - The controller to coordinate with
* @param {Error} error - The decompression error
* @returns {void}
*/
- #fail (controller, error) {
+ #fail (error) {
if (this.#terminated) {
return
}
@@ -160,75 +328,41 @@ class DecompressHandler extends DecoratorHandler {
if (this.#inputEnded) {
// The request is already marked complete once the compressed input ends,
// so controller.abort() can no longer propagate decoder flush errors.
- this.onResponseError(controller, error)
+ this.onResponseError(this.#controller, error)
} else {
- controller.abort(error)
+ 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', () => {
- if (this.#terminated) {
- return
- }
-
- let chunk
- while ((chunk = decompressor.read()) !== null) {
- const decompressedSize = this.#decompressedSize + chunk.length
- if (decompressedSize > this.#maxSize) {
- this.#fail(controller, new ResponseExceededMaxSizeError(
- `Decompressed response size (${decompressedSize}) exceeded maxSize (${this.#maxSize})`
- ))
- return
- }
-
- this.#decompressedSize = decompressedSize
- const result = super.onResponseData(controller, chunk)
- if (result === false) {
- break
- }
- }
- })
-
- decompressor.on('error', (error) => {
- this.#fail(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)
+ this.#setupDecompressorEvents(decompressor)
- decompressor.on('end', () => {
- if (this.#terminated) {
- return
- }
-
- this.#terminated = true
- this.#cleanupDecompressors()
- super.onResponseEnd(controller, this.#trailers)
- })
+ 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) {
@@ -236,13 +370,26 @@ class DecompressHandler extends DecoratorHandler {
}
if (err) {
- this.#fail(controller, err)
+ this.#fail(err)
return
}
- this.#terminated = true
- this.#cleanupDecompressors()
- super.onResponseEnd(controller, this.#trailers)
+ 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()
+ }
})
}
@@ -252,6 +399,16 @@ class DecompressHandler extends DecoratorHandler {
*/
#cleanupDecompressors () {
this.#decompressors.length = 0
+ this.#finalDecompressor = undefined
+ }
+
+ 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)
}
/**
@@ -262,18 +419,24 @@ class DecompressHandler extends DecoratorHandler {
* @returns {void}
*/
onResponseStart (controller, statusCode, headers, statusMessage) {
- const contentEncoding = headers['content-encoding']
+ // Repeated field lines reach us as an array. RFC 9110 section 5.3 lets a
+ // recipient join them with commas, which yields the single-line form the
+ // decompression chain already handles.
+ const rawContentEncoding = headers['content-encoding']
+ const contentEncoding = Array.isArray(rawContentEncoding)
+ ? rawContentEncoding.join(',')
+ : rawContentEncoding
// If content encoding is not supported or status code is in skip list
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
@@ -281,8 +444,8 @@ class DecompressHandler extends DecoratorHandler {
// Remove compression headers since we're decompressing
const { 'content-encoding': _, 'content-length': __, ...newHeaders } = headers
- if (controller?.rawHeaders) {
- const rawHeaders = controller.rawHeaders
+ if (this.#controller.rawHeaders) {
+ const rawHeaders = this.#controller.rawHeaders
if (Array.isArray(rawHeaders)) {
const filteredHeaders = []
@@ -308,13 +471,14 @@ class DecompressHandler extends DecoratorHandler {
}
}
+ 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)
}
/**
@@ -324,10 +488,13 @@ class DecompressHandler extends DecoratorHandler {
*/
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)
}
/**
@@ -342,7 +509,7 @@ class DecompressHandler extends DecoratorHandler {
this.#decompressors[0].end()
return
}
- super.onResponseEnd(controller, trailers)
+ return super.onResponseEnd(this.#controller, trailers)
}
/**
@@ -360,7 +527,7 @@ class DecompressHandler extends DecoratorHandler {
decompressor.destroy()
}
this.#cleanupDecompressors()
- super.onResponseError(controller, err)
+ super.onResponseError(this.#controller, err)
}
}
diff --git a/deps/undici/src/lib/llhttp/wasm_build_env.txt b/deps/undici/src/lib/llhttp/wasm_build_env.txt
index 9085bb4e260..1564ebae0de 100644
--- a/deps/undici/src/lib/llhttp/wasm_build_env.txt
+++ b/deps/undici/src/lib/llhttp/wasm_build_env.txt
@@ -1,7 +1,3 @@
-
-> undici@8.10.2 build:wasm
-> node build/wasm.js --docker
-
> docker run --rm --platform=linux/x86_64 --user 1001:1001 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/build/lib/llhttp --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/build,target=/home/node/build/build --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/deps,target=/home/node/build/deps -t ghcr.io/nodejs/wasm-builder@sha256:975f391d907e42a75b8c72eb77c782181e941608687d4d8694c3e9df415a0970 node build/wasm.js
diff --git a/deps/undici/src/lib/web/cache/cache.js b/deps/undici/src/lib/web/cache/cache.js
index 1f41a66a01b..a8f1606041b 100644
--- a/deps/undici/src/lib/web/cache/cache.js
+++ b/deps/undici/src/lib/web/cache/cache.js
@@ -41,7 +41,7 @@ class Cache {
}
async match (request, options = {}) {
- webidl.brandCheck(this, Cache)
+ webidl.brandCheck(this, webidl.is.Cache)
const prefix = 'Cache.match'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -59,7 +59,7 @@ class Cache {
}
async matchAll (request = undefined, options = {}) {
- webidl.brandCheck(this, Cache)
+ webidl.brandCheck(this, webidl.is.Cache)
const prefix = 'Cache.matchAll'
if (request !== undefined) request = webidl.converters.RequestInfo(request)
@@ -69,7 +69,7 @@ class Cache {
}
async add (request) {
- webidl.brandCheck(this, Cache)
+ webidl.brandCheck(this, webidl.is.Cache)
const prefix = 'Cache.add'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -87,7 +87,7 @@ class Cache {
}
async addAll (requests) {
- webidl.brandCheck(this, Cache)
+ webidl.brandCheck(this, webidl.is.Cache)
const prefix = 'Cache.addAll'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -185,7 +185,10 @@ class Cache {
}
}
},
- processResponseEndOfBody (response) {
+ // Possible spec bug. If the body is never read, `processResponseEndOfBody` (which is attached to a TransformStream's flush hook)
+ // never runs, so this would hang. This hook, on the other hand, always reads the body.
+ // https://github.com/nodejs/undici/issues/5615
+ processResponseConsumeBody (response) {
// 1.
if (response.aborted) {
responsePromise.reject(new DOMException('aborted', 'AbortError'))
@@ -257,7 +260,7 @@ class Cache {
}
async put (request, response) {
- webidl.brandCheck(this, Cache)
+ webidl.brandCheck(this, webidl.is.Cache)
const prefix = 'Cache.put'
webidl.argumentLengthCheck(arguments, 2, prefix)
@@ -388,7 +391,7 @@ class Cache {
}
async delete (request, options = {}) {
- webidl.brandCheck(this, Cache)
+ webidl.brandCheck(this, webidl.is.Cache)
const prefix = 'Cache.delete'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -454,7 +457,7 @@ class Cache {
* @returns {Promise<readonly Request[]>}
*/
async keys (request = undefined, options = {}) {
- webidl.brandCheck(this, Cache)
+ webidl.brandCheck(this, webidl.is.Cache)
const prefix = 'Cache.keys'
@@ -804,6 +807,12 @@ class Cache {
// 6.
return Object.freeze(responseList)
}
+
+ static {
+ webidl.is.Cache = (arg) => {
+ return arg != null && typeof arg === 'object' && #relevantRequestResponseList in arg
+ }
+ }
}
Object.defineProperties(Cache.prototype, {
diff --git a/deps/undici/src/lib/web/cache/cachestorage.js b/deps/undici/src/lib/web/cache/cachestorage.js
index c49b1e82ec1..8602dc32b6f 100644
--- a/deps/undici/src/lib/web/cache/cachestorage.js
+++ b/deps/undici/src/lib/web/cache/cachestorage.js
@@ -21,7 +21,7 @@ class CacheStorage {
}
async match (request, options = {}) {
- webidl.brandCheck(this, CacheStorage)
+ webidl.brandCheck(this, webidl.is.CacheStorage)
webidl.argumentLengthCheck(arguments, 1, 'CacheStorage.match')
request = webidl.converters.RequestInfo(request)
@@ -58,7 +58,7 @@ class CacheStorage {
* @returns {Promise<boolean>}
*/
async has (cacheName) {
- webidl.brandCheck(this, CacheStorage)
+ webidl.brandCheck(this, webidl.is.CacheStorage)
const prefix = 'CacheStorage.has'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -76,7 +76,7 @@ class CacheStorage {
* @returns {Promise<Cache>}
*/
async open (cacheName) {
- webidl.brandCheck(this, CacheStorage)
+ webidl.brandCheck(this, webidl.is.CacheStorage)
const prefix = 'CacheStorage.open'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -110,7 +110,7 @@ class CacheStorage {
* @returns {Promise<boolean>}
*/
async delete (cacheName) {
- webidl.brandCheck(this, CacheStorage)
+ webidl.brandCheck(this, webidl.is.CacheStorage)
const prefix = 'CacheStorage.delete'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -125,7 +125,7 @@ class CacheStorage {
* @returns {Promise<string[]>}
*/
async keys () {
- webidl.brandCheck(this, CacheStorage)
+ webidl.brandCheck(this, webidl.is.CacheStorage)
// 2.1
const keys = this.#caches.keys()
@@ -133,6 +133,12 @@ class CacheStorage {
// 2.2
return [...keys]
}
+
+ static {
+ webidl.is.CacheStorage = (arg) => {
+ return arg != null && typeof arg === 'object' && #caches in arg
+ }
+ }
}
Object.defineProperties(CacheStorage.prototype, {
diff --git a/deps/undici/src/lib/web/cookies/index.js b/deps/undici/src/lib/web/cookies/index.js
index be99f6f3dd2..a612ca86f73 100644
--- a/deps/undici/src/lib/web/cookies/index.js
+++ b/deps/undici/src/lib/web/cookies/index.js
@@ -3,9 +3,19 @@
const { parseSetCookie } = require('./parse')
const { stringify } = require('./util')
const { webidl } = require('../webidl')
-const { Headers } = require('../fetch/headers')
-const brandChecks = webidl.brandCheckMultiple([Headers, globalThis.Headers].filter(Boolean))
+const globalHeadersBrandCheck = (arg) => webidl.brandCheck(arg, webidl.util.MakeTypeAssertion(globalThis.Headers))
+const undiciHeadersBrandCheck = (arg) => webidl.brandCheck(arg, webidl.is.Headers)
+
+function brandCheckHeaders (arg) {
+ try {
+ undiciHeadersBrandCheck(arg)
+ return
+ } catch {
+ }
+
+ globalHeadersBrandCheck(arg)
+}
/**
* @typedef {Object} Cookie
@@ -28,12 +38,14 @@ const brandChecks = webidl.brandCheckMultiple([Headers, globalThis.Headers].filt
function getCookies (headers) {
webidl.argumentLengthCheck(arguments, 1, 'getCookies')
- brandChecks(headers)
+ brandCheckHeaders(headers)
const cookie = headers.get('cookie')
+ // A null prototype keeps a cookie named `__proto__` from hitting the
+ // Object.prototype setter, which would silently drop it.
/** @type {Record<string, string>} */
- const out = {}
+ const out = { __proto__: null }
if (!cookie) {
return out
@@ -55,7 +67,7 @@ function getCookies (headers) {
* @returns {void}
*/
function deleteCookie (headers, name, attributes) {
- brandChecks(headers)
+ brandCheckHeaders(headers)
const prefix = 'deleteCookie'
webidl.argumentLengthCheck(arguments, 2, prefix)
@@ -80,7 +92,7 @@ function deleteCookie (headers, name, attributes) {
function getSetCookies (headers) {
webidl.argumentLengthCheck(arguments, 1, 'getSetCookies')
- brandChecks(headers)
+ brandCheckHeaders(headers)
const cookies = headers.getSetCookie()
@@ -109,7 +121,7 @@ function parseCookie (cookie) {
function setCookie (headers, cookie) {
webidl.argumentLengthCheck(arguments, 2, 'setCookie')
- brandChecks(headers)
+ brandCheckHeaders(headers)
cookie = webidl.converters.Cookie(cookie)
diff --git a/deps/undici/src/lib/web/cookies/util.js b/deps/undici/src/lib/web/cookies/util.js
index 9ed048be874..78680118788 100644
--- a/deps/undici/src/lib/web/cookies/util.js
+++ b/deps/undici/src/lib/web/cookies/util.js
@@ -315,7 +315,9 @@ function stringify (cookie) {
out.push(`Path=${cookie.path}`)
}
- if (cookie.expires && cookie.expires.toString() !== 'Invalid Date') {
+ // A numeric 0 is the Unix epoch, not an absent value -- the same reason the
+ // Max-Age check above tests the type rather than truthiness.
+ if (cookie.expires != null && cookie.expires.toString() !== 'Invalid Date') {
out.push(`Expires=${toIMFDate(cookie.expires)}`)
}
diff --git a/deps/undici/src/lib/web/eventsource/eventsource.js b/deps/undici/src/lib/web/eventsource/eventsource.js
index 657c0643ca8..93fb1f23436 100644
--- a/deps/undici/src/lib/web/eventsource/eventsource.js
+++ b/deps/undici/src/lib/web/eventsource/eventsource.js
@@ -191,6 +191,8 @@ class EventSource extends EventTarget {
* @readonly
*/
get readyState () {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
return this.#readyState
}
@@ -200,6 +202,8 @@ class EventSource extends EventTarget {
* @returns {string}
*/
get url () {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
return this.#url
}
@@ -208,6 +212,8 @@ class EventSource extends EventTarget {
* instantiated with CORS credentials set (true), or not (false, the default).
*/
get withCredentials () {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
return this.#withCredentials
}
@@ -363,7 +369,7 @@ class EventSource extends EventTarget {
* CLOSED.
*/
close () {
- webidl.brandCheck(this, EventSource)
+ webidl.brandCheck(this, webidl.is.EventSource)
if (this.#readyState === CLOSED) return
this.#readyState = CLOSED
@@ -372,10 +378,14 @@ class EventSource extends EventTarget {
}
get onopen () {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
return this.#events.open
}
set onopen (fn) {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
if (this.#events.open) {
this.removeEventListener('open', this.#events.open)
}
@@ -391,10 +401,14 @@ class EventSource extends EventTarget {
}
get onmessage () {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
return this.#events.message
}
set onmessage (fn) {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
if (this.#events.message) {
this.removeEventListener('message', this.#events.message)
}
@@ -410,10 +424,14 @@ class EventSource extends EventTarget {
}
get onerror () {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
return this.#events.error
}
set onerror (fn) {
+ webidl.brandCheck(this, webidl.is.EventSource)
+
if (this.#events.error) {
this.removeEventListener('error', this.#events.error)
}
@@ -427,6 +445,12 @@ class EventSource extends EventTarget {
this.#events.error = null
}
}
+
+ static {
+ webidl.is.EventSource = (arg) => {
+ return arg != null && typeof arg === 'object' && #events in arg
+ }
+ }
}
const constantsPropertyDescriptors = {
diff --git a/deps/undici/src/lib/web/fetch/body.js b/deps/undici/src/lib/web/fetch/body.js
index a81ddfba437..9c2f4df1b8f 100644
--- a/deps/undici/src/lib/web/fetch/body.js
+++ b/deps/undici/src/lib/web/fetch/body.js
@@ -2,7 +2,6 @@
const util = require('../../core/util')
const {
- ReadableStreamFrom,
readableStreamClose,
fullyReadBody,
extractMimeType
@@ -197,8 +196,16 @@ function extractBody (object, keepalive = false) {
)
}
- stream =
- webidl.is.ReadableStream(object) ? object : ReadableStreamFrom(object)
+ stream = webidl.is.ReadableStream(object)
+ ? object
+ : ReadableStream.from(object).pipeThrough(new TransformStream({
+ transform (chunk, controller) {
+ const bytes = isUint8Array(chunk) ? chunk : Buffer.from(chunk)
+ if (bytes.byteLength) {
+ controller.enqueue(bytes)
+ }
+ }
+ }))
}
// 11. If source is a byte sequence, then set action to a
@@ -293,7 +300,7 @@ function cloneBody (body) {
}
}
-function bodyMixinMethods (instance, getInternalState) {
+function bodyMixinMethods (brandCheck, getInternalState) {
const methods = {
blob () {
// The blob() method steps are to return the result of
@@ -313,7 +320,7 @@ function bodyMixinMethods (instance, getInternalState) {
// Return a Blob whose contents are bytes and type attribute
// is mimeType.
return new Blob([bytes], { type: mimeType })
- }, instance, getInternalState)
+ }, brandCheck, getInternalState)
},
arrayBuffer () {
@@ -323,19 +330,19 @@ function bodyMixinMethods (instance, getInternalState) {
// whose contents are bytes.
return consumeBody(this, (bytes) => {
return new Uint8Array(bytes).buffer
- }, instance, getInternalState)
+ }, brandCheck, getInternalState)
},
text () {
// The text() method steps are to return the result of running
// consume body with this and UTF-8 decode.
- return consumeBody(this, utf8DecodeBytes, instance, getInternalState)
+ return consumeBody(this, utf8DecodeBytes, brandCheck, getInternalState)
},
json () {
// The json() method steps are to return the result of running
// consume body with this and parse JSON from bytes.
- return consumeBody(this, parseJSONFromBytes, instance, getInternalState)
+ return consumeBody(this, parseJSONFromBytes, brandCheck, getInternalState)
},
formData () {
@@ -383,7 +390,7 @@ function bodyMixinMethods (instance, getInternalState) {
throw new TypeError(
'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".'
)
- }, instance, getInternalState)
+ }, brandCheck, getInternalState)
},
bytes () {
@@ -392,7 +399,7 @@ function bodyMixinMethods (instance, getInternalState) {
// result of creating a Uint8Array from bytes in this’s relevant realm.
return consumeBody(this, (bytes) => {
return new Uint8Array(bytes)
- }, instance, getInternalState)
+ }, brandCheck, getInternalState)
},
textStream () {
@@ -442,20 +449,20 @@ function bodyMixinMethods (instance, getInternalState) {
return methods
}
-function mixinBody (prototype, getInternalState) {
- Object.assign(prototype.prototype, bodyMixinMethods(prototype, getInternalState))
+function mixinBody (prototype, getInternalState, brandCheck) {
+ Object.assign(prototype.prototype, bodyMixinMethods(brandCheck, getInternalState))
}
/**
* @see https://fetch.spec.whatwg.org/#concept-body-consume-body
* @param {any} object internal state
* @param {(value: unknown) => unknown} convertBytesToJSValue
- * @param {any} instance
+ * @param {import('../../../types/webidl').WebidlIsFunction} brandCheck
* @param {(target: any) => any} getInternalState
*/
-function consumeBody (object, convertBytesToJSValue, instance, getInternalState) {
+function consumeBody (object, convertBytesToJSValue, brandCheck, getInternalState) {
try {
- webidl.brandCheck(object, instance)
+ webidl.brandCheck(object, brandCheck)
} catch (e) {
return Promise.reject(e)
}
diff --git a/deps/undici/src/lib/web/fetch/data-url.js b/deps/undici/src/lib/web/fetch/data-url.js
index 27ad7ae5924..1719da8b50b 100644
--- a/deps/undici/src/lib/web/fetch/data-url.js
+++ b/deps/undici/src/lib/web/fetch/data-url.js
@@ -1,14 +1,14 @@
'use strict'
const assert = require('node:assert')
-const { forgivingBase64, collectASequenceOfCodePoints, collectASequenceOfCodePointsFast, isomorphicDecode, removeASCIIWhitespace, removeChars } = require('../infra')
+const { asciiLowercase, forgivingBase64, collectASequenceOfCodePoints, collectASequenceOfCodePointsFast, isomorphicDecode, removeASCIIWhitespace, removeChars } = require('../infra')
const encoder = new TextEncoder()
/**
* @see https://mimesniff.spec.whatwg.org/#http-token-code-point
*/
-const HTTP_TOKEN_CODEPOINTS = /^[-!#$%&'*+.^_|~A-Za-z0-9]+$/u
+const HTTP_TOKEN_CODEPOINTS = /^[-!#$%&'*+.^_`|~A-Za-z0-9]+$/u
const HTTP_WHITESPACE_REGEX = /[\u000A\u000D\u0009\u0020]/u // eslint-disable-line
/**
@@ -69,7 +69,7 @@ function dataURLProcessor (dataURL) {
// 11. If mimeType ends with U+003B (;), followed by
// zero or more U+0020 SPACE, followed by an ASCII
// case-insensitive match for "base64", then:
- if (/;(?:\u0020*)base64$/ui.test(mimeType)) {
+ if (/;\u0020*[Bb][Aa][Ss][Ee]64$/u.test(mimeType)) {
// 1. Let stringBody be the isomorphic decode of body.
const stringBody = isomorphicDecode(body)
@@ -268,8 +268,8 @@ function parseMIMEType (input) {
return 'failure'
}
- const typeLowercase = type.toLowerCase()
- const subtypeLowercase = subtype.toLowerCase()
+ const typeLowercase = asciiLowercase(type)
+ const subtypeLowercase = asciiLowercase(subtype)
// 10. Let mimeType be a new MIME type record whose type
// is type, in ASCII lowercase, and subtype is subtype,
@@ -309,7 +309,7 @@ function parseMIMEType (input) {
// 4. Set parameterName to parameterName, in ASCII
// lowercase.
- parameterName = parameterName.toLowerCase()
+ parameterName = asciiLowercase(parameterName)
// 5. If position is not past the end of input, then:
if (position.position < input.length) {
diff --git a/deps/undici/src/lib/web/fetch/formdata.js b/deps/undici/src/lib/web/fetch/formdata.js
index 226bd329587..e7b8c4c3fb2 100644
--- a/deps/undici/src/lib/web/fetch/formdata.js
+++ b/deps/undici/src/lib/web/fetch/formdata.js
@@ -10,6 +10,8 @@ const random = runtimeFeatures.has('crypto')
? require('node:crypto').randomInt
: (max) => Math.floor(Math.random() * max)
+let getFormDataState, setFormDataState, getFormDataBoundary
+
// https://xhr.spec.whatwg.org/#formdata
class FormData {
#state = []
@@ -28,7 +30,7 @@ class FormData {
}
append (name, value, filename = undefined) {
- webidl.brandCheck(this, FormData)
+ webidl.brandCheck(this, webidl.is.FormData)
const prefix = 'FormData.append'
webidl.argumentLengthCheck(arguments, 2, prefix)
@@ -56,7 +58,7 @@ class FormData {
}
delete (name) {
- webidl.brandCheck(this, FormData)
+ webidl.brandCheck(this, webidl.is.FormData)
const prefix = 'FormData.delete'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -69,7 +71,7 @@ class FormData {
}
get (name) {
- webidl.brandCheck(this, FormData)
+ webidl.brandCheck(this, webidl.is.FormData)
const prefix = 'FormData.get'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -89,7 +91,7 @@ class FormData {
}
getAll (name) {
- webidl.brandCheck(this, FormData)
+ webidl.brandCheck(this, webidl.is.FormData)
const prefix = 'FormData.getAll'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -106,7 +108,7 @@ class FormData {
}
has (name) {
- webidl.brandCheck(this, FormData)
+ webidl.brandCheck(this, webidl.is.FormData)
const prefix = 'FormData.has'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -119,7 +121,7 @@ class FormData {
}
set (name, value, filename = undefined) {
- webidl.brandCheck(this, FormData)
+ webidl.brandCheck(this, webidl.is.FormData)
const prefix = 'FormData.set'
webidl.argumentLengthCheck(arguments, 2, prefix)
@@ -184,40 +186,34 @@ class FormData {
return `FormData ${output.slice(output.indexOf(']') + 2)}`
}
- /**
- * @param {FormData} formData
- */
- static getFormDataState (formData) {
- return formData.#state
- }
+ static {
+ /** @param {FormData} formData */
+ getFormDataState = (formData) => formData.#state
- /**
- * @param {FormData} formData
- * @param {any[]} newState
- */
- static setFormDataState (formData, newState) {
- formData.#state = newState
- }
+ /**
+ * @param {FormData} formData
+ * @param {any[]} newState
+ */
+ setFormDataState = (formData, newState) => {
+ formData.#state = newState
+ }
- /**
- * @param {FormData} formData
- * @returns {string | null}
- */
- static getFormDataBoundary (formData) {
- const boundary = formData.#boundary
- if (boundary != null) return boundary
+ /**
+ * @param {FormData} formData
+ * @returns {string | null}
+ */
+ getFormDataBoundary = (formData) => {
+ // eslint-disable-next-line no-return-assign
+ return formData.#boundary ??= `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
+ }
- // eslint-disable-next-line no-return-assign
- return formData.#boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
+ webidl.is.FormData = (arg) => {
+ return arg != null && typeof arg === 'object' && #state in arg
+ }
}
}
-const { getFormDataState, setFormDataState, getFormDataBoundary } = FormData
-Reflect.deleteProperty(FormData, 'getFormDataState')
-Reflect.deleteProperty(FormData, 'setFormDataState')
-Reflect.deleteProperty(FormData, 'getFormDataBoundary')
-
-iteratorMixin('FormData', FormData, getFormDataState, 'name', 'value')
+iteratorMixin('FormData', FormData, getFormDataState, 'name', 'value', webidl.is.FormData)
Object.defineProperties(FormData.prototype, {
append: kEnumerableProperty,
@@ -273,6 +269,4 @@ function makeEntry (name, value, filename) {
return { name, value }
}
-webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData)
-
module.exports = { FormData, makeEntry, setFormDataState, getFormDataBoundary }
diff --git a/deps/undici/src/lib/web/fetch/headers.js b/deps/undici/src/lib/web/fetch/headers.js
index 024d1989588..8f9fdfb327e 100644
--- a/deps/undici/src/lib/web/fetch/headers.js
+++ b/deps/undici/src/lib/web/fetch/headers.js
@@ -423,6 +423,8 @@ class HeadersList {
}
}
+let getHeadersGuard, setHeadersGuard, getHeadersList, setHeadersList
+
// https://fetch.spec.whatwg.org/#headers-class
class Headers {
#guard
@@ -458,7 +460,7 @@ class Headers {
// https://fetch.spec.whatwg.org/#dom-headers-append
append (name, value) {
- webidl.brandCheck(this, Headers)
+ webidl.brandCheck(this, webidl.is.Headers)
webidl.argumentLengthCheck(arguments, 2, 'Headers.append')
@@ -471,7 +473,7 @@ class Headers {
// https://fetch.spec.whatwg.org/#dom-headers-delete
delete (name) {
- webidl.brandCheck(this, Headers)
+ webidl.brandCheck(this, webidl.is.Headers)
webidl.argumentLengthCheck(arguments, 1, 'Headers.delete')
@@ -515,7 +517,7 @@ class Headers {
// https://fetch.spec.whatwg.org/#dom-headers-get
get (name) {
- webidl.brandCheck(this, Headers)
+ webidl.brandCheck(this, webidl.is.Headers)
webidl.argumentLengthCheck(arguments, 1, 'Headers.get')
@@ -538,7 +540,7 @@ class Headers {
// https://fetch.spec.whatwg.org/#dom-headers-has
has (name) {
- webidl.brandCheck(this, Headers)
+ webidl.brandCheck(this, webidl.is.Headers)
webidl.argumentLengthCheck(arguments, 1, 'Headers.has')
@@ -561,7 +563,7 @@ class Headers {
// https://fetch.spec.whatwg.org/#dom-headers-set
set (name, value) {
- webidl.brandCheck(this, Headers)
+ webidl.brandCheck(this, webidl.is.Headers)
webidl.argumentLengthCheck(arguments, 2, 'Headers.set')
@@ -609,7 +611,7 @@ class Headers {
// https://fetch.spec.whatwg.org/#dom-headers-getsetcookie
getSetCookie () {
- webidl.brandCheck(this, Headers)
+ webidl.brandCheck(this, webidl.is.Headers)
// 1. If this’s header list does not contain `Set-Cookie`, then return « ».
// 2. Return the values of all headers in this’s header list whose name is
@@ -630,37 +632,38 @@ class Headers {
return `Headers ${util.formatWithOptions(options, this.#headersList.entries)}`
}
- static getHeadersGuard (o) {
- return o.#guard
- }
+ static {
+ /** @param {Headers} headers */
+ getHeadersGuard = (headers) => headers.#guard
- static setHeadersGuard (o, guard) {
- o.#guard = guard
- }
+ /**
+ * @param {Headers} headers
+ * @param {string} guard
+ */
+ setHeadersGuard = (headers, guard) => {
+ headers.#guard = guard
+ }
- /**
- * @param {Headers} o
- */
- static getHeadersList (o) {
- return o.#headersList
- }
+ /**
+ * @param {Headers} headers
+ */
+ getHeadersList = (headers) => headers.#headersList
+
+ /**
+ * @param {Headers} target
+ * @param {HeadersList} list
+ */
+ setHeadersList = (target, list) => {
+ target.#headersList = list
+ }
- /**
- * @param {Headers} target
- * @param {HeadersList} list
- */
- static setHeadersList (target, list) {
- target.#headersList = list
+ webidl.is.Headers = (arg) => {
+ return arg != null && typeof arg === 'object' && #guard in arg
+ }
}
}
-const { getHeadersGuard, setHeadersGuard, getHeadersList, setHeadersList } = Headers
-Reflect.deleteProperty(Headers, 'getHeadersGuard')
-Reflect.deleteProperty(Headers, 'setHeadersGuard')
-Reflect.deleteProperty(Headers, 'getHeadersList')
-Reflect.deleteProperty(Headers, 'setHeadersList')
-
-iteratorMixin('Headers', Headers, headersListSortAndCombine, 0, 1)
+iteratorMixin('Headers', Headers, headersListSortAndCombine, 0, 1, webidl.is.Headers)
Object.defineProperties(Headers.prototype, {
append: kEnumerableProperty,
diff --git a/deps/undici/src/lib/web/fetch/index.js b/deps/undici/src/lib/web/fetch/index.js
index 4ac812ad622..81fd8bb279c 100644
--- a/deps/undici/src/lib/web/fetch/index.js
+++ b/deps/undici/src/lib/web/fetch/index.js
@@ -812,11 +812,8 @@ async function mainFetch (fetchParams, recursive) {
// https://fetch.spec.whatwg.org/#concept-scheme-fetch
// given a fetch params fetchParams
function schemeFetch (fetchParams) {
- // Note: since the connection is destroyed on redirect, which sets fetchParams to a
- // cancelled state, we do not want this condition to trigger *unless* there have been
- // no redirects. See https://github.com/nodejs/undici/issues/1776
// 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
- if (isCancelled(fetchParams) && fetchParams.request.redirectCount === 0) {
+ if (isCancelled(fetchParams)) {
return Promise.resolve(makeAppropriateNetworkError(fetchParams))
}
@@ -1030,18 +1027,18 @@ function fetchFinale (fetchParams, response) {
// `Server-Timing` from response’s internal response’s header list.
// TODO
- // 3. Let processResponseEndOfBody be the following steps:
+ // 3. If fetchParams’s request’s destination is "document", then set fetchParams’s controller’s
+ // full timing info to fetchParams’s timing info.
+ if (fetchParams.request.destination === 'document') {
+ fetchParams.controller.fullTimingInfo = timingInfo
+ }
+
+ // 4. Let processResponseEndOfBody be the following steps:
const processResponseEndOfBody = () => {
// 1. Let unsafeEndTime be the unsafe shared current time.
const unsafeEndTime = Date.now() // ?
- // 2. If fetchParams’s request’s destination is "document", then set fetchParams’s controller’s
- // full timing info to fetchParams’s timing info.
- if (fetchParams.request.destination === 'document') {
- fetchParams.controller.fullTimingInfo = timingInfo
- }
-
- // 3. Set fetchParams’s controller’s report timing steps to the following steps given a global object global:
+ // 2. Set fetchParams’s controller’s report timing steps to the following steps given a global object global:
fetchParams.controller.reportTimingSteps = () => {
// 1. If fetchParams’s request’s URL’s scheme is not an HTTP(S) scheme, then return.
if (!urlIsHttpHttpsScheme(fetchParams.request.url)) {
@@ -1090,7 +1087,7 @@ function fetchFinale (fetchParams, response) {
}
}
- // 4. Let processResponseEndOfBodyTask be the following steps:
+ // 3. Let processResponseEndOfBodyTask be the following steps:
const processResponseEndOfBodyTask = () => {
// 1. Set fetchParams’s request’s done flag.
fetchParams.request.done = true
@@ -1109,11 +1106,11 @@ function fetchFinale (fetchParams, response) {
}
}
- // 5. Queue a fetch task to run processResponseEndOfBodyTask with fetchParams’s task destination
+ // 4. Queue a fetch task to run processResponseEndOfBodyTask with fetchParams’s task destination
queueMicrotask(() => processResponseEndOfBodyTask())
}
- // 4. If fetchParams’s process response is non-null, then queue a fetch task to run fetchParams’s
+ // 5. If fetchParams’s process response is non-null, then queue a fetch task to run fetchParams’s
// process response given response, with fetchParams’s task destination.
if (fetchParams.processResponse != null) {
queueMicrotask(() => {
@@ -1122,11 +1119,14 @@ function fetchFinale (fetchParams, response) {
})
}
- // 5. Let internalResponse be response, if response is a network error; otherwise response’s internal response.
+ // 6. Let internalResponse be response, if response is a network error; otherwise response’s internal response.
const internalResponse = response.type === 'error' ? response : (response.internalResponse ?? response)
- // 6. If internalResponse’s body is null, then run processResponseEndOfBody.
- // 7. Otherwise:
+ // 7. If response is a network error, then run the WebDriver BiDi fetch error steps with request.
+ // Otherwise, run the WebDriver BiDi response completed steps with request and response.
+
+ // 8. If internalResponse’s body is null, then run processResponseEndOfBody.
+ // 9. Otherwise:
if (internalResponse.body == null) {
processResponseEndOfBody()
} else {
@@ -1144,6 +1144,27 @@ function fetchFinale (fetchParams, response) {
processResponseEndOfBody()
})
}
+
+ // 10. If fetchParams’s process response consume body is non-null, then:
+ if (fetchParams.processResponseConsumeBody != null) {
+ // 1. Let processBody given nullOrBytes be this step: run fetchParams’s
+ // process response consume body given response and nullOrBytes.
+ const processBody = (nullOrBytes) => fetchParams.processResponseConsumeBody(response, nullOrBytes)
+
+ // 2. Let processBodyError be this step: run fetchParams’s process
+ // response consume body given response and failure.
+ const processBodyError = () => fetchParams.processResponseConsumeBody(response, 'failure')
+
+ // 3. If internalResponse’s body is null, then queue a fetch task to run
+ // processBody given null, with fetchParams’s task destination.
+ if (internalResponse.body == null) {
+ queueMicrotask(() => processBody(null))
+ } else {
+ // 4. Otherwise, fully read internalResponse’s body given processBody,
+ // processBodyError, and fetchParams’s task destination.
+ fullyReadBody(internalResponse.body, processBody, processBodyError)
+ }
+ }
}
// https://fetch.spec.whatwg.org/#http-fetch
@@ -1219,7 +1240,7 @@ async function httpFetch (fetchParams) {
// encouraged to, transmit an RST_STREAM frame.
// See, https://github.com/whatwg/fetch/issues/1288
if (request.redirect !== 'manual') {
- fetchParams.controller.connection.destroy(undefined, false)
+ fetchParams.controller.connection.destroy()
}
// 2. Switch on request’s redirect mode:
@@ -1828,12 +1849,10 @@ async function httpNetworkFetch (
fetchParams.controller.connection = {
abort: null,
destroyed: false,
- destroy (err, abort = true) {
+ destroy (err) {
if (!this.destroyed) {
this.destroyed = true
- if (abort) {
- this.abort?.(err ?? new DOMException('The operation was aborted.', 'AbortError'))
- }
+ this.abort?.(err ?? new DOMException('The operation was aborted.', 'AbortError'))
}
}
}
@@ -2369,7 +2388,7 @@ async function httpNetworkFetch (
this.body?.push(null)
},
- onResponseError (_controller, error) {
+ onResponseError (controller, error) {
if (this.abort) {
fetchParams.controller.off('terminated', this.abort)
}
@@ -2388,7 +2407,9 @@ async function httpNetworkFetch (
this.body?.destroy(error)
- fetchParams.controller.terminate(error)
+ if (!controller?.aborted) {
+ fetchParams.controller.terminate(error)
+ }
reject(error)
},
diff --git a/deps/undici/src/lib/web/fetch/request.js b/deps/undici/src/lib/web/fetch/request.js
index 56945ec02ee..66f8150cb82 100644
--- a/deps/undici/src/lib/web/fetch/request.js
+++ b/deps/undici/src/lib/web/fetch/request.js
@@ -83,6 +83,7 @@ function buildAbort (acRef) {
}
let patchMethodWarning = false
+let setRequestSignal, getRequestDispatcher, setRequestDispatcher, setRequestHeaders, getRequestState, setRequestState, removeRequestAbortListener
// https://fetch.spec.whatwg.org/#request-class
class Request {
@@ -600,7 +601,7 @@ class Request {
// Returns request’s HTTP method, which is "GET" by default.
get method () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The method getter steps are to return this’s request’s method.
return this.#state.method
@@ -608,7 +609,7 @@ class Request {
// Returns the URL of request as a string.
get url () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The url getter steps are to return this’s request’s URL, serialized.
return URLSerializer(this.#state.url)
@@ -618,7 +619,7 @@ class Request {
// Note that headers added in the network layer by the user agent will not
// be accounted for in this object, e.g., the "Host" header.
get headers () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The headers getter steps are to return this’s headers.
return this.#headers
@@ -627,7 +628,7 @@ class Request {
// Returns the kind of resource requested by request, e.g., "document"
// or "script".
get destination () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The destination getter are to return this’s request’s destination.
return this.#state.destination
@@ -639,7 +640,7 @@ class Request {
// during fetching to determine the value of the `Referer` header of the
// request being made.
get referrer () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// 1. If this’s request’s referrer is "no-referrer", then return the
// empty string.
@@ -661,7 +662,7 @@ class Request {
// This is used during fetching to compute the value of the request’s
// referrer.
get referrerPolicy () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The referrerPolicy getter steps are to return this’s request’s referrer policy.
return this.#state.referrerPolicy
@@ -671,7 +672,7 @@ class Request {
// whether the request will use CORS, or will be restricted to same-origin
// URLs.
get mode () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The mode getter steps are to return this’s request’s mode.
return this.#state.mode
@@ -681,7 +682,7 @@ class Request {
// which is a string indicating whether credentials will be sent with the
// request always, never, or only when sent to a same-origin URL.
get credentials () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The credentials getter steps are to return this’s request’s credentials mode.
return this.#state.credentials
@@ -691,7 +692,7 @@ class Request {
// which is a string indicating how the request will
// interact with the browser’s cache when fetching.
get cache () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The cache getter steps are to return this’s request’s cache mode.
return this.#state.cache
@@ -702,7 +703,7 @@ class Request {
// request will be handled during fetching. A request
// will follow redirects by default.
get redirect () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The redirect getter steps are to return this’s request’s redirect mode.
return this.#state.redirect
@@ -712,7 +713,7 @@ class Request {
// cryptographic hash of the resource being fetched. Its value
// consists of multiple hashes separated by whitespace. [SRI]
get integrity () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The integrity getter steps are to return this’s request’s integrity
// metadata.
@@ -722,7 +723,7 @@ class Request {
// Returns a boolean indicating whether or not request can outlive the
// global in which it was created.
get keepalive () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The keepalive getter steps are to return this’s request’s keepalive.
return this.#state.keepalive
@@ -731,7 +732,7 @@ class Request {
// Returns a boolean indicating whether or not request is for a reload
// navigation.
get isReloadNavigation () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The isReloadNavigation getter steps are to return true if this’s
// request’s reload-navigation flag is set; otherwise false.
@@ -741,7 +742,7 @@ class Request {
// Returns a boolean indicating whether or not request is for a history
// navigation (a.k.a. back-forward navigation).
get isHistoryNavigation () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The isHistoryNavigation getter steps are to return true if this’s request’s
// history-navigation flag is set; otherwise false.
@@ -752,33 +753,33 @@ class Request {
// object indicating whether or not request has been aborted, and its
// abort event handler.
get signal () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// The signal getter steps are to return this’s signal.
return this.#signal
}
get body () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
return this.#state.body ? this.#state.body.stream : null
}
get bodyUsed () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
return !!this.#state.body && util.isDisturbed(this.#state.body.stream)
}
get duplex () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
return 'half'
}
// Returns a clone of request.
clone () {
- webidl.brandCheck(this, Request)
+ webidl.brandCheck(this, webidl.is.Request)
// 1. If this is unusable, then throw a TypeError.
if (bodyUnusable(this.#state)) {
@@ -840,73 +841,69 @@ class Request {
return `Request ${nodeUtil.formatWithOptions(options, properties)}`
}
- /**
- * @param {Request} request
- * @param {AbortSignal} newSignal
- */
- static setRequestSignal (request, newSignal) {
- request.#signal = newSignal
- return request
- }
+ static {
+ /**
+ * @param {Request} request
+ * @param {AbortSignal} newSignal
+ */
+ setRequestSignal = (request, newSignal) => {
+ request.#signal = newSignal
+ }
- /**
- * @param {Request} request
- */
- static getRequestDispatcher (request) {
- return request.#dispatcher
- }
+ /**
+ * @param {Request} request
+ */
+ getRequestDispatcher = (request) => {
+ return request.#dispatcher
+ }
- /**
- * @param {Request} request
- * @param {import('../../dispatcher/dispatcher')} newDispatcher
- */
- static setRequestDispatcher (request, newDispatcher) {
- request.#dispatcher = newDispatcher
- }
+ /**
+ * @param {Request} request
+ * @param {import('../../dispatcher/dispatcher')} newDispatcher
+ */
+ setRequestDispatcher = (request, newDispatcher) => {
+ request.#dispatcher = newDispatcher
+ }
- /**
- * @param {Request} request
- * @param {Headers} newHeaders
- */
- static setRequestHeaders (request, newHeaders) {
- request.#headers = newHeaders
- }
+ /**
+ * @param {Request} request
+ * @param {Headers} newHeaders
+ */
+ setRequestHeaders = (request, newHeaders) => {
+ request.#headers = newHeaders
+ }
- /**
- * @param {Request} request
- */
- static getRequestState (request) {
- return request.#state
- }
+ /**
+ * @param {Request} request
+ */
+ getRequestState = (request) => {
+ return request.#state
+ }
- /**
- * @param {Request} request
- * @param {any} newState
- */
- static setRequestState (request, newState) {
- request.#state = newState
- }
+ /**
+ * @param {Request} request
+ * @param {any} newState
+ */
+ setRequestState = (request, newState) => {
+ request.#state = newState
+ }
- /**
- * Removes the `abort` listener that makes this request's signal follow the
- * signal passed to its constructor, if any. Idempotent.
- * @param {Request} request
- */
- static removeRequestAbortListener (request) {
- request.#abortCleanup?.()
+ /**
+ * Removes the `abort` listener that makes this request's signal follow the
+ * signal passed to its constructor, if any. Idempotent.
+ * @param {Request} request
+ */
+ removeRequestAbortListener = (request) => {
+ request.#abortCleanup?.()
+ }
+
+ webidl.is.Request = (arg) => {
+ return arg != null && typeof arg === 'object' && #state in arg
+ }
}
}
-const { setRequestSignal, getRequestDispatcher, setRequestDispatcher, setRequestHeaders, getRequestState, setRequestState, removeRequestAbortListener } = Request
-Reflect.deleteProperty(Request, 'setRequestSignal')
-Reflect.deleteProperty(Request, 'getRequestDispatcher')
-Reflect.deleteProperty(Request, 'setRequestDispatcher')
-Reflect.deleteProperty(Request, 'setRequestHeaders')
-Reflect.deleteProperty(Request, 'getRequestState')
-Reflect.deleteProperty(Request, 'setRequestState')
-Reflect.deleteProperty(Request, 'removeRequestAbortListener')
-
-mixinBody(Request, getRequestState)
+mixinBody(Request, getRequestState, webidl.is.Request)
// https://fetch.spec.whatwg.org/#requests
function makeRequest (init) {
@@ -1021,8 +1018,6 @@ Object.defineProperties(Request.prototype, {
}
})
-webidl.is.Request = webidl.util.MakeTypeAssertion(Request)
-
/**
* @param {*} V
* @returns {import('../../../types/fetch').Request|string}
diff --git a/deps/undici/src/lib/web/fetch/response.js b/deps/undici/src/lib/web/fetch/response.js
index f555ea94b15..5e40c164a50 100644
--- a/deps/undici/src/lib/web/fetch/response.js
+++ b/deps/undici/src/lib/web/fetch/response.js
@@ -23,6 +23,7 @@ const assert = require('node:assert')
const { isomorphicEncode, serializeJavascriptValueToJSONString } = require('../infra')
const textEncoder = new TextEncoder('utf-8')
+let getResponseHeaders, setResponseHeaders, getResponseState, setResponseState
// https://fetch.spec.whatwg.org/#response-class
class Response {
@@ -145,7 +146,7 @@ class Response {
// Returns response’s type, e.g., "cors".
get type () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
// The type getter steps are to return this’s response’s type.
return this.#state.type
@@ -153,7 +154,7 @@ class Response {
// Returns response’s URL, if it has one; otherwise the empty string.
get url () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
const urlList = this.#state.urlList
@@ -171,7 +172,7 @@ class Response {
// Returns whether response was obtained through a redirect.
get redirected () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
// The redirected getter steps are to return true if this’s response’s URL
// list has more than one item; otherwise false.
@@ -180,7 +181,7 @@ class Response {
// Returns response’s status.
get status () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
// The status getter steps are to return this’s response’s status.
return this.#state.status
@@ -188,7 +189,7 @@ class Response {
// Returns whether response’s status is an ok status.
get ok () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
// The ok getter steps are to return true if this’s response’s status is an
// ok status; otherwise false.
@@ -197,7 +198,7 @@ class Response {
// Returns response’s status message.
get statusText () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
// The statusText getter steps are to return this’s response’s status
// message.
@@ -206,27 +207,27 @@ class Response {
// Returns response’s headers as Headers.
get headers () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
// The headers getter steps are to return this’s headers.
return this.#headers
}
get body () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
return this.#state.body ? this.#state.body.stream : null
}
get bodyUsed () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
return !!this.#state.body && util.isDisturbed(this.#state.body.stream)
}
// Returns a clone of response.
clone () {
- webidl.brandCheck(this, Response)
+ webidl.brandCheck(this, webidl.is.Response)
// 1. If this is unusable, then throw a TypeError.
if (bodyUnusable(this.#state)) {
@@ -272,44 +273,44 @@ class Response {
return `Response ${nodeUtil.formatWithOptions(options, properties)}`
}
- /**
- * @param {Response} response
- */
- static getResponseHeaders (response) {
- return response.#headers
- }
+ static {
+ /**
+ * @param {Response} response
+ */
+ getResponseHeaders = (response) => {
+ return response.#headers
+ }
- /**
- * @param {Response} response
- * @param {Headers} newHeaders
- */
- static setResponseHeaders (response, newHeaders) {
- response.#headers = newHeaders
- }
+ /**
+ * @param {Response} response
+ * @param {Headers} newHeaders
+ */
+ setResponseHeaders = (response, newHeaders) => {
+ response.#headers = newHeaders
+ }
- /**
- * @param {Response} response
- */
- static getResponseState (response) {
- return response.#state
- }
+ /**
+ * @param {Response} response
+ */
+ getResponseState = (response) => {
+ return response.#state
+ }
- /**
- * @param {Response} response
- * @param {any} newState
- */
- static setResponseState (response, newState) {
- response.#state = newState
+ /**
+ * @param {Response} response
+ * @param {any} newState
+ */
+ setResponseState = (response, newState) => {
+ response.#state = newState
+ }
+
+ webidl.is.Response = (arg) => {
+ return arg != null && typeof arg === 'object' && #state in arg
+ }
}
}
-const { getResponseHeaders, setResponseHeaders, getResponseState, setResponseState } = Response
-Reflect.deleteProperty(Response, 'getResponseHeaders')
-Reflect.deleteProperty(Response, 'setResponseHeaders')
-Reflect.deleteProperty(Response, 'getResponseState')
-Reflect.deleteProperty(Response, 'setResponseState')
-
-mixinBody(Response, getResponseState)
+mixinBody(Response, getResponseState, webidl.is.Response)
Object.defineProperties(Response.prototype, {
type: kEnumerableProperty,
@@ -624,8 +625,6 @@ webidl.converters.ResponseInit = webidl.dictionaryConverter([
}
])
-webidl.is.Response = webidl.util.MakeTypeAssertion(Response)
-
module.exports = {
isNetworkError,
makeNetworkError,
diff --git a/deps/undici/src/lib/web/fetch/util.js b/deps/undici/src/lib/web/fetch/util.js
index 20cbb5c58f6..c51c89d2fb4 100644
--- a/deps/undici/src/lib/web/fetch/util.js
+++ b/deps/undici/src/lib/web/fetch/util.js
@@ -6,7 +6,7 @@ const { redirectStatusSet, referrerPolicyTokens, badPortsSet } = require('./cons
const { getGlobalOrigin } = require('./global')
const { collectAnHTTPQuotedString, parseMIMEType } = require('./data-url')
const { performance } = require('node:perf_hooks')
-const { ReadableStreamFrom, isValidHTTPToken, normalizedMethodRecordsBase } = require('../../core/util')
+const { isValidHTTPToken, normalizedMethodRecordsBase } = require('../../core/util')
const assert = require('node:assert')
const { isUint8Array } = require('node:util/types')
const { webidl } = require('../webidl')
@@ -872,8 +872,9 @@ function createIterator (name, kInternalIterator, keyIndex = 0, valueIndex = 1)
* @param {(target: any) => any} kInternalIterator
* @param {string | number} [keyIndex]
* @param {string | number} [valueIndex]
+ * @param {import('../../../types/webidl').WebidlIsFunction} brandCheck
*/
-function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueIndex = 1) {
+function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueIndex = 1, brandCheck) {
const makeIterator = createIterator(name, kInternalIterator, keyIndex, valueIndex)
const properties = {
@@ -882,7 +883,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
enumerable: true,
configurable: true,
value: function keys () {
- webidl.brandCheck(this, object)
+ webidl.brandCheck(this, brandCheck)
return makeIterator(this, 'key')
}
},
@@ -891,7 +892,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
enumerable: true,
configurable: true,
value: function values () {
- webidl.brandCheck(this, object)
+ webidl.brandCheck(this, brandCheck)
return makeIterator(this, 'value')
}
},
@@ -900,7 +901,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
enumerable: true,
configurable: true,
value: function entries () {
- webidl.brandCheck(this, object)
+ webidl.brandCheck(this, brandCheck)
return makeIterator(this, 'key+value')
}
},
@@ -909,7 +910,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
enumerable: true,
configurable: true,
value: function forEach (callbackfn, thisArg = globalThis) {
- webidl.brandCheck(this, object)
+ webidl.brandCheck(this, brandCheck)
webidl.argumentLengthCheck(arguments, 1, `${name}.forEach`)
if (typeof callbackfn !== 'function') {
throw new TypeError(
@@ -1483,7 +1484,6 @@ module.exports = {
isAborted,
isCancelled,
isValidEncodedURL,
- ReadableStreamFrom,
tryUpgradeRequestToAPotentiallyTrustworthyURL,
clampAndCoarsenConnectionTimingInfo,
coarsenedSharedCurrentTime,
diff --git a/deps/undici/src/lib/web/infra/index.js b/deps/undici/src/lib/web/infra/index.js
index 391bb2e3d7d..060c86f602c 100644
--- a/deps/undici/src/lib/web/infra/index.js
+++ b/deps/undici/src/lib/web/infra/index.js
@@ -156,6 +156,20 @@ function isomorphicEncode (input) {
return input
}
+const nonASCIIRegex = /[^\x00-\x7F]/ // eslint-disable-line no-control-regex
+
+/**
+ * @param {string} str
+ * @returns {string}
+ *
+ * @see https://infra.spec.whatwg.org/#ascii-lowercase
+ */
+function asciiLowercase (str) {
+ return nonASCIIRegex.test(str)
+ ? str.replace(/[A-Z]+/g, (upper) => upper.toLowerCase())
+ : str.toLowerCase()
+}
+
/**
* @see https://infra.spec.whatwg.org/#parse-json-bytes-to-a-javascript-value
* @param {Uint8Array} bytes
@@ -192,7 +206,7 @@ function removeChars (str, leading, trailing, predicate) {
}
if (trailing) {
- while (trail > 0 && predicate(str.charCodeAt(trail))) trail--
+ while (trail >= lead && predicate(str.charCodeAt(trail))) trail--
}
return lead === 0 && trail === str.length - 1 ? str : str.slice(lead, trail + 1)
@@ -216,6 +230,7 @@ function serializeJavascriptValueToJSONString (value) {
}
module.exports = {
+ asciiLowercase,
collectASequenceOfCodePoints,
collectASequenceOfCodePointsFast,
forgivingBase64,
diff --git a/deps/undici/src/lib/web/webidl/index.js b/deps/undici/src/lib/web/webidl/index.js
index ce81c1e323a..6f4bd5036c0 100644
--- a/deps/undici/src/lib/web/webidl/index.js
+++ b/deps/undici/src/lib/web/webidl/index.js
@@ -73,26 +73,14 @@ webidl.errors.invalidArgument = function (context) {
}
// https://webidl.spec.whatwg.org/#implements
-webidl.brandCheck = function (V, I) {
- if (!FunctionPrototypeSymbolHasInstance(I, V)) {
+webidl.brandCheck = function (V, is) {
+ if (!is(V)) {
const err = new TypeError('Illegal invocation')
err.code = 'ERR_INVALID_THIS' // node compat.
throw err
}
}
-webidl.brandCheckMultiple = function (List) {
- const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c))
-
- return (V) => {
- if (prototypes.every(typeCheck => !typeCheck(V))) {
- const err = new TypeError('Illegal invocation')
- err.code = 'ERR_INVALID_THIS' // node compat.
- throw err
- }
- }
-}
-
webidl.argumentLengthCheck = function ({ length }, min, ctx) {
if (length < min) {
throw webidl.errors.exception({
diff --git a/deps/undici/src/lib/web/websocket/connection.js b/deps/undici/src/lib/web/websocket/connection.js
index cd95d2ca76e..79601177198 100644
--- a/deps/undici/src/lib/web/websocket/connection.js
+++ b/deps/undici/src/lib/web/websocket/connection.js
@@ -101,13 +101,13 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
// The presence of a session property on the socket indicates HTTP2
// HTTP1
if (response.socket?.session == null) {
- failWebsocketConnection(handler, 1002, 'Received network error or non-101 status code.', response.error)
+ failHandshake(handler, response, 1002, 'Received network error or non-101 status code.', response.error)
return
}
// HTTP2
if (response.status !== 200) {
- failWebsocketConnection(handler, 1002, 'Received network error or non-200 status code.', response.error)
+ failHandshake(handler, response, 1002, 'Received network error or non-200 status code.', response.error)
return
}
}
@@ -122,7 +122,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
// header list results in null, failure, or the empty byte
// sequence, then fail the WebSocket connection.
if (protocols.length !== 0 && !response.headersList.get('Sec-WebSocket-Protocol')) {
- failWebsocketConnection(handler, 1002, 'Server did not respond with sent protocols.')
+ failHandshake(handler, response, 1002, 'Server did not respond with sent protocols.')
return
}
@@ -138,7 +138,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
// _Fail the WebSocket Connection_.
// For H2, no upgrade header is expected.
if (response.socket.session == null && response.headersList.get('Upgrade')?.toLowerCase() !== 'websocket') {
- failWebsocketConnection(handler, 1002, 'Server did not set Upgrade header to "websocket".')
+ failHandshake(handler, response, 1002, 'Server did not set Upgrade header to "websocket".')
return
}
@@ -148,7 +148,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
// MUST _Fail the WebSocket Connection_.
// For H2, no connection header is expected.
if (response.socket.session == null && response.headersList.get('Connection')?.toLowerCase() !== 'upgrade') {
- failWebsocketConnection(handler, 1002, 'Server did not set Connection header to "upgrade".')
+ failHandshake(handler, response, 1002, 'Server did not set Connection header to "upgrade".')
return
}
@@ -159,11 +159,15 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
// E914-47DA-95CA-C5AB0DC85B11" but ignoring any leading and
// trailing whitespace, the client MUST _Fail the WebSocket
// Connection_.
- const secWSAccept = response.headersList.get('Sec-WebSocket-Accept')
- const digest = crypto.hash('sha1', keyValue + uid, 'base64')
- if (secWSAccept !== digest) {
- failWebsocketConnection(handler, 1002, 'Incorrect hash received in Sec-WebSocket-Accept header.')
- return
+ // For H2, implementations "do not do the processing of the Sec-WebSocket-Key and
+ // Sec-WebSocket-Accept header fields". https://datatracker.ietf.org/doc/html/rfc8441#section-5
+ if (response.socket.session == null) {
+ const secWSAccept = response.headersList.get('Sec-WebSocket-Accept')
+ const digest = crypto.hash('sha1', keyValue + uid, 'base64')
+ if (secWSAccept !== digest) {
+ failHandshake(handler, response, 1002, 'Incorrect hash received in Sec-WebSocket-Accept header.')
+ return
+ }
}
// 5. If the response includes a |Sec-WebSocket-Extensions| header
@@ -180,7 +184,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
extensions = parseExtensions(secExtension)
if (!extensions.has('permessage-deflate')) {
- failWebsocketConnection(handler, 1002, 'Sec-WebSocket-Extensions header does not match.')
+ failHandshake(handler, response, 1002, 'Sec-WebSocket-Extensions header does not match.')
return
}
}
@@ -201,11 +205,18 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
// the selected subprotocol values in its response for the connection to
// be established.
if (requestProtocols === null || !requestProtocols.includes(secProtocol)) {
- failWebsocketConnection(handler, 1002, 'Protocol was not set in the opening handshake.')
+ failHandshake(handler, response, 1002, 'Protocol was not set in the opening handshake.')
return
}
}
+ // For H2, "Orderly TCP-level closures are represented as END_STREAM flags", so
+ // end our side of the stream when the server ends its side, as a TCP socket would.
+ // https://datatracker.ietf.org/doc/html/rfc8441#section-5
+ if (response.socket.session != null) {
+ response.socket.allowHalfOpen = false
+ }
+
response.socket.on('data', handler.onSocketData)
response.socket.on('close', handler.onSocketClose)
response.socket.on('error', handler.onSocketError)
@@ -296,6 +307,16 @@ function closeWebSocketConnection (object, code, reason, validate = false) {
}
}
+function failHandshake (handler, response, code, reason, cause) {
+ // The H2 upgrade request has already completed and handed off its stream.
+ // Aborting the request cannot close that stream after handshake validation fails.
+ if (response.socket?.session != null && !response.socket.destroyed) {
+ response.socket.destroy()
+ }
+
+ failWebsocketConnection(handler, code, reason, cause)
+}
+
/**
* @param {import('./websocket').Handler} handler
* @param {number} code
diff --git a/deps/undici/src/lib/web/websocket/events.js b/deps/undici/src/lib/web/websocket/events.js
index 7ac9566be46..b31c1d94293 100644
--- a/deps/undici/src/lib/web/websocket/events.js
+++ b/deps/undici/src/lib/web/websocket/events.js
@@ -4,6 +4,8 @@ const { webidl } = require('../webidl')
const { kEnumerableProperty } = require('../../core/util')
const { kConstruct } = require('../../core/symbols')
+let createFastMessageEvent
+
/**
* @see https://html.spec.whatwg.org/multipage/comms.html#messageevent
*/
@@ -30,31 +32,31 @@ class MessageEvent extends Event {
}
get data () {
- webidl.brandCheck(this, MessageEvent)
+ webidl.brandCheck(this, webidl.is.MessageEvent)
return this.#eventInit.data
}
get origin () {
- webidl.brandCheck(this, MessageEvent)
+ webidl.brandCheck(this, webidl.is.MessageEvent)
return this.#eventInit.origin
}
get lastEventId () {
- webidl.brandCheck(this, MessageEvent)
+ webidl.brandCheck(this, webidl.is.MessageEvent)
return this.#eventInit.lastEventId
}
get source () {
- webidl.brandCheck(this, MessageEvent)
+ webidl.brandCheck(this, webidl.is.MessageEvent)
return this.#eventInit.source
}
get ports () {
- webidl.brandCheck(this, MessageEvent)
+ webidl.brandCheck(this, webidl.is.MessageEvent)
if (!Object.isFrozen(this.#eventInit.ports)) {
Object.freeze(this.#eventInit.ports)
@@ -73,7 +75,7 @@ class MessageEvent extends Event {
source = null,
ports = []
) {
- webidl.brandCheck(this, MessageEvent)
+ webidl.brandCheck(this, webidl.is.MessageEvent)
webidl.argumentLengthCheck(arguments, 1, 'MessageEvent.initMessageEvent')
@@ -82,21 +84,24 @@ class MessageEvent extends Event {
})
}
- static createFastMessageEvent (type, init) {
- const messageEvent = new MessageEvent(kConstruct, type, init)
- messageEvent.#eventInit = init
- messageEvent.#eventInit.data ??= null
- messageEvent.#eventInit.origin ??= ''
- messageEvent.#eventInit.lastEventId ??= ''
- messageEvent.#eventInit.source ??= null
- messageEvent.#eventInit.ports ??= []
- return messageEvent
+ static {
+ createFastMessageEvent = (type, init) => {
+ const messageEvent = new MessageEvent(kConstruct, type, init)
+ messageEvent.#eventInit = init
+ messageEvent.#eventInit.data ??= null
+ messageEvent.#eventInit.origin ??= ''
+ messageEvent.#eventInit.lastEventId ??= ''
+ messageEvent.#eventInit.source ??= null
+ messageEvent.#eventInit.ports ??= []
+ return messageEvent
+ }
+
+ webidl.is.MessageEvent = (arg) => {
+ return arg != null && typeof arg === 'object' && #eventInit in arg
+ }
}
}
-const { createFastMessageEvent } = MessageEvent
-delete MessageEvent.createFastMessageEvent
-
/**
* @see https://websockets.spec.whatwg.org/#the-closeevent-interface
*/
@@ -117,22 +122,28 @@ class CloseEvent extends Event {
}
get wasClean () {
- webidl.brandCheck(this, CloseEvent)
+ webidl.brandCheck(this, webidl.is.CloseEvent)
return this.#eventInit.wasClean
}
get code () {
- webidl.brandCheck(this, CloseEvent)
+ webidl.brandCheck(this, webidl.is.CloseEvent)
return this.#eventInit.code
}
get reason () {
- webidl.brandCheck(this, CloseEvent)
+ webidl.brandCheck(this, webidl.is.CloseEvent)
return this.#eventInit.reason
}
+
+ static {
+ webidl.is.CloseEvent = (arg) => {
+ return arg != null && typeof arg === 'object' && #eventInit in arg
+ }
+ }
}
// https://html.spec.whatwg.org/multipage/webappapis.html#the-errorevent-interface
@@ -153,34 +164,40 @@ class ErrorEvent extends Event {
}
get message () {
- webidl.brandCheck(this, ErrorEvent)
+ webidl.brandCheck(this, webidl.is.ErrorEvent)
return this.#eventInit.message
}
get filename () {
- webidl.brandCheck(this, ErrorEvent)
+ webidl.brandCheck(this, webidl.is.ErrorEvent)
return this.#eventInit.filename
}
get lineno () {
- webidl.brandCheck(this, ErrorEvent)
+ webidl.brandCheck(this, webidl.is.ErrorEvent)
return this.#eventInit.lineno
}
get colno () {
- webidl.brandCheck(this, ErrorEvent)
+ webidl.brandCheck(this, webidl.is.ErrorEvent)
return this.#eventInit.colno
}
get error () {
- webidl.brandCheck(this, ErrorEvent)
+ webidl.brandCheck(this, webidl.is.ErrorEvent)
return this.#eventInit.error
}
+
+ static {
+ webidl.is.ErrorEvent = (arg) => {
+ return arg != null && typeof arg === 'object' && #eventInit in arg
+ }
+ }
}
Object.defineProperties(MessageEvent.prototype, {
diff --git a/deps/undici/src/lib/web/websocket/receiver.js b/deps/undici/src/lib/web/websocket/receiver.js
index cfb5a54cbc6..63a5a2e7a52 100644
--- a/deps/undici/src/lib/web/websocket/receiver.js
+++ b/deps/undici/src/lib/web/websocket/receiver.js
@@ -369,6 +369,8 @@ class ByteParser extends Writable {
consumeFragments () {
const fragments = this.#fragments
+ this.#info.compressed = false
+
if (fragments.length === 1) {
// single fragment
this.#fragmentsBytes = 0
diff --git a/deps/undici/src/lib/web/websocket/stream/websocketerror.js b/deps/undici/src/lib/web/websocket/stream/websocketerror.js
index a34c5213a39..04937c271ed 100644
--- a/deps/undici/src/lib/web/websocket/stream/websocketerror.js
+++ b/deps/undici/src/lib/web/websocket/stream/websocketerror.js
@@ -26,6 +26,8 @@ function createInheritableDOMException () {
})
}
+let createUnvalidatedWebSocketError
+
class WebSocketError extends createInheritableDOMException() {
#closeCode
#reason
@@ -77,17 +79,20 @@ class WebSocketError extends createInheritableDOMException() {
* @param {number|null} code
* @param {string} reason
*/
- static createUnvalidatedWebSocketError (message, code, reason) {
- const error = new WebSocketError(message, kConstruct)
- error.#closeCode = code
- error.#reason = reason
- return error
+ static {
+ createUnvalidatedWebSocketError = (message, code, reason) => {
+ const error = new WebSocketError(message, kConstruct)
+ error.#closeCode = code
+ error.#reason = reason
+ return error
+ }
+
+ webidl.is.WebSocketError = (arg) => {
+ return arg != null && typeof arg === 'object' && #reason in arg
+ }
}
}
-const { createUnvalidatedWebSocketError } = WebSocketError
-delete WebSocketError.createUnvalidatedWebSocketError
-
Object.defineProperties(WebSocketError.prototype, {
closeCode: kEnumerableProperty,
reason: kEnumerableProperty,
@@ -99,6 +104,4 @@ Object.defineProperties(WebSocketError.prototype, {
}
})
-webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError)
-
module.exports = { WebSocketError, createUnvalidatedWebSocketError }
diff --git a/deps/undici/src/lib/web/websocket/stream/websocketstream.js b/deps/undici/src/lib/web/websocket/stream/websocketstream.js
index 1c13a30677d..2e0094de7f9 100644
--- a/deps/undici/src/lib/web/websocket/stream/websocketstream.js
+++ b/deps/undici/src/lib/web/websocket/stream/websocketstream.js
@@ -62,7 +62,9 @@ class WebSocketStream {
this.#handler.socket.destroy()
},
- onSocketClose: () => this.#onSocketClose(),
+ // When the WebSocket connection is closed for a WebSocketStream stream, possibly cleanly, the user agent must
+ // queue a global task on the WebSocket task source given stream ’s relevant global object to run the following substeps:
+ onSocketClose: () => queueMicrotask(() => this.#onSocketClose()),
onPing: () => {},
onPong: () => {},
@@ -246,11 +248,15 @@ class WebSocketStream {
const frame = new WebsocketFrameSend(data)
this.#handler.socket.write(frame.createFrame(opcode), () => {
+ // 6.3. Queue a global task on the WebSocket task source given stream ’s relevant global object to resolve promise with undefined.
promise.resolve(undefined)
})
+ } else {
+ // 6.3. Queue a global task on the WebSocket task source given stream ’s relevant global object to resolve promise with undefined.
+ promise.resolve(undefined)
}
- // 6.3. Queue a global task on the WebSocket task source given stream ’s relevant global object to resolve promise with undefined.
+ // 7. Return promise.
return promise.promise
}
@@ -278,7 +284,7 @@ class WebSocketStream {
// This is done in the opening handshake.
// 3. Let extensions be the extensions in use .
- const extensions = parsedExtensions ?? ''
+ const extensions = response.headersList.get('sec-websocket-extensions') ?? ''
// 4. Let protocol be the subprotocol in use .
const protocol = response.headersList.get('sec-websocket-protocol') ?? ''
@@ -291,6 +297,7 @@ class WebSocketStream {
start: (controller) => {
this.#readableStreamController = controller
},
+ pull: () => this.#pull(),
cancel: (reason) => this.#cancel(reason)
})
@@ -350,6 +357,9 @@ class WebSocketStream {
this.#readableStreamController.enqueue(chunk)
// 4. Apply backpressure to the WebSocket.
+ if (this.#readableStreamController.desiredSize <= 0) {
+ this.#handler.socket.pause()
+ }
}
/** @type {import('../websocket').Handler['onSocketClose']} */
@@ -383,7 +393,7 @@ class WebSocketStream {
// 1006.
let code = result?.code ?? 1005
- if (!this.#handler.closeState.has(sentCloseFrameState.SENT) && !this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
+ if (!this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
code = 1006
}
@@ -441,6 +451,11 @@ class WebSocketStream {
closeWebSocketConnection(this.#handler, code, reasonString)
}
+ // To pull bytes from a WebSocketStream stream , if stream is currently applying backpressure, release backpressure.
+ #pull () {
+ this.#handler.socket.resume()
+ }
+
// To cancel a WebSocketStream stream given reason , close using reason giving stream and reason .
#cancel (reason) {
this.#closeUsingReason(reason)
diff --git a/deps/undici/src/lib/web/websocket/websocket.js b/deps/undici/src/lib/web/websocket/websocket.js
index 45dbce1bea9..e83343bb4d8 100644
--- a/deps/undici/src/lib/web/websocket/websocket.js
+++ b/deps/undici/src/lib/web/websocket/websocket.js
@@ -28,6 +28,8 @@ const { channels } = require('../../core/diagnostics')
const kRef = Symbol.for('nodejs.ref')
const kUnref = Symbol.for('nodejs.unref')
+let ping
+
function getSocketAddress (socket) {
if (typeof socket?.address === 'function') {
return socket.address()
@@ -198,16 +200,14 @@ class WebSocket extends EventTarget {
this.#binaryType = 'blob'
}
+ // TODO: remove this
[kRef] () {
- webidl.brandCheck(this, WebSocket)
-
this.#refed = true
this.#handler.socket?.ref?.()
}
+ // TODO: remove this
[kUnref] () {
- webidl.brandCheck(this, WebSocket)
-
this.#refed = false
this.#handler.socket?.unref?.()
}
@@ -218,7 +218,7 @@ class WebSocket extends EventTarget {
* @param {string|undefined} reason
*/
close (code = undefined, reason = undefined) {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
const prefix = 'WebSocket.close'
@@ -245,7 +245,7 @@ class WebSocket extends EventTarget {
* @param {NodeJS.TypedArray|ArrayBuffer|Blob|string} data
*/
send (data) {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
const prefix = 'WebSocket.send'
webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -339,45 +339,45 @@ class WebSocket extends EventTarget {
}
get readyState () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
// The readyState getter steps are to return this's ready state.
return this.#handler.readyState
}
get bufferedAmount () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#bufferedAmount
}
get url () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
// The url getter steps are to return this's url, serialized.
return URLSerializer(this.#url)
}
get extensions () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#extensions
}
get protocol () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#protocol
}
get onopen () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#events.open
}
set onopen (fn) {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
if (this.#events.open) {
this.removeEventListener('open', this.#events.open)
@@ -394,13 +394,13 @@ class WebSocket extends EventTarget {
}
get onerror () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#events.error
}
set onerror (fn) {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
if (this.#events.error) {
this.removeEventListener('error', this.#events.error)
@@ -417,13 +417,13 @@ class WebSocket extends EventTarget {
}
get onclose () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#events.close
}
set onclose (fn) {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
if (this.#events.close) {
this.removeEventListener('close', this.#events.close)
@@ -440,13 +440,13 @@ class WebSocket extends EventTarget {
}
get onmessage () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#events.message
}
set onmessage (fn) {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
if (this.#events.message) {
this.removeEventListener('message', this.#events.message)
@@ -463,13 +463,13 @@ class WebSocket extends EventTarget {
}
get binaryType () {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
return this.#binaryType
}
set binaryType (type) {
- webidl.brandCheck(this, WebSocket)
+ webidl.brandCheck(this, webidl.is.WebSocket)
if (type !== 'blob' && type !== 'arraybuffer') {
this.#binaryType = 'blob'
@@ -654,33 +654,36 @@ class WebSocket extends EventTarget {
}
}
- /**
- * @param {WebSocket} ws
- * @param {Buffer|undefined} buffer
- */
- static ping (ws, buffer) {
- if (Buffer.isBuffer(buffer)) {
- if (buffer.length > 125) {
- throw new TypeError('A PING frame cannot have a body larger than 125 bytes.')
+ static {
+ /**
+ * @param {WebSocket} ws
+ * @param {Buffer|undefined} buffer
+ */
+ ping = (ws, buffer) => {
+ if (Buffer.isBuffer(buffer)) {
+ if (buffer.length > 125) {
+ throw new TypeError('A PING frame cannot have a body larger than 125 bytes.')
+ }
+ } else if (buffer !== undefined) {
+ throw new TypeError('Expected buffer payload')
}
- } else if (buffer !== undefined) {
- throw new TypeError('Expected buffer payload')
- }
- // An endpoint MAY send a Ping frame any time after the connection is
- // established and before the connection is closed.
- const readyState = ws.#handler.readyState
+ // An endpoint MAY send a Ping frame any time after the connection is
+ // established and before the connection is closed.
+ const readyState = ws.#handler.readyState
- if (isEstablished(readyState) && !isClosing(readyState) && !isClosed(readyState)) {
- const frame = new WebsocketFrameSend(buffer)
- ws.#handler.socket.write(frame.createFrame(opcodes.PING))
+ if (isEstablished(readyState) && !isClosing(readyState) && !isClosed(readyState)) {
+ const frame = new WebsocketFrameSend(buffer)
+ ws.#handler.socket.write(frame.createFrame(opcodes.PING))
+ }
+ }
+
+ webidl.is.WebSocket = (arg) => {
+ return arg != null && typeof arg === 'object' && #handler in arg
}
}
}
-const { ping } = WebSocket
-Reflect.deleteProperty(WebSocket, 'ping')
-
// https://websockets.spec.whatwg.org/#dom-websocket-connecting
WebSocket.CONNECTING = WebSocket.prototype.CONNECTING = states.CONNECTING
// https://websockets.spec.whatwg.org/#dom-websocket-open
diff --git a/deps/undici/src/package-lock.json b/deps/undici/src/package-lock.json
index c0f6d19a83a..b4b31465c51 100644
--- a/deps/undici/src/package-lock.json
+++ b/deps/undici/src/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "undici",
- "version": "8.10.2",
+ "version": "8.11.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "undici",
- "version": "8.10.2",
+ "version": "8.11.2",
"license": "MIT",
"devDependencies": {
"@fastify/busboy": "3.2.2",
@@ -262,9 +262,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
- "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "version": "7.29.9",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz",
+ "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1438,17 +1438,17 @@
}
},
"node_modules/@jest/console": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.5.0.tgz",
- "integrity": "sha512-BI1DpOedrJqbrYVi9yNhDWGjqphR/+gsM4STmg2+VaeXm7851hvpBDyKOZGMXATTrGEnFuEseQvLCtrrRmG0GQ==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.5.2.tgz",
+ "integrity": "sha512-e8sQC4pCMHPBrPX7Hk8TJr+DM5dkUnImSTNag8SEWFAFAF6xIz4AJvCKapnrdHnZxep4bxw4PhG+ZbimYBMyKw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"@types/node": "*",
"chalk": "^4.1.2",
- "jest-message-util": "30.5.0",
- "jest-util": "30.5.0",
+ "jest-message-util": "30.5.1",
+ "jest-util": "30.5.1",
"slash": "^3.0.0"
},
"engines": {
@@ -1456,18 +1456,18 @@
}
},
"node_modules/@jest/core": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.5.0.tgz",
- "integrity": "sha512-DLjRME+NY//j+UDTSfWnjoP0srrdR3DrJRy7yFZktGIwzpN2iVy2vMo0jziZ5c2Ij7bOwlJRXKVWtxZusazOJg==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.5.2.tgz",
+ "integrity": "sha512-/jqvFWoJF7LV1a6AUpYMbMm+2yIYsHJfR474H0SCzr9k8tnO/jl9wRg6zSG6lxgf6EozNlCG4amFzWsbZSvvZA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/console": "30.5.0",
+ "@jest/console": "30.5.2",
"@jest/pattern": "30.5.0",
- "@jest/reporters": "30.5.0",
- "@jest/test-result": "30.5.0",
- "@jest/transform": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/reporters": "30.5.2",
+ "@jest/test-result": "30.5.2",
+ "@jest/transform": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
"ansi-escapes": "^4.3.2",
"chalk": "^4.1.2",
@@ -1475,20 +1475,20 @@
"exit-x": "^0.2.2",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
- "jest-changed-files": "30.5.0",
- "jest-config": "30.5.0",
- "jest-haste-map": "30.5.0",
- "jest-message-util": "30.5.0",
+ "jest-changed-files": "30.5.1",
+ "jest-config": "30.5.2",
+ "jest-haste-map": "30.5.1",
+ "jest-message-util": "30.5.1",
"jest-regex-util": "30.5.0",
- "jest-resolve": "30.5.0",
- "jest-resolve-dependencies": "30.5.0",
- "jest-runner": "30.5.0",
- "jest-runtime": "30.5.0",
- "jest-snapshot": "30.5.0",
- "jest-util": "30.5.0",
- "jest-validate": "30.5.0",
- "jest-watcher": "30.5.0",
- "pretty-format": "30.5.0",
+ "jest-resolve": "30.5.1",
+ "jest-resolve-dependencies": "30.5.2",
+ "jest-runner": "30.5.2",
+ "jest-runtime": "30.5.2",
+ "jest-snapshot": "30.5.2",
+ "jest-util": "30.5.1",
+ "jest-validate": "30.5.1",
+ "jest-watcher": "30.5.2",
+ "pretty-format": "30.5.1",
"slash": "^3.0.0"
},
"engines": {
@@ -1514,39 +1514,39 @@
}
},
"node_modules/@jest/environment": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.5.0.tgz",
- "integrity": "sha512-HUaqexIauIh69IQ4NTuPDEUCB8g8T4TOPSIzQOS18mwI/KEHKQk1j013K2o6ra031szZE2t5jGmVx3xbzdjgKA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.5.2.tgz",
+ "integrity": "sha512-nwFPOUMbmsjNNRCpnJpB9HbSZu4C07wDDds++5j+j1MezzPLxMPDdbdUVjr2o4RULDOValnDd70taPFI1EtxAg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/fake-timers": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/fake-timers": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
- "jest-mock": "30.5.0"
+ "jest-mock": "30.5.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.5.0.tgz",
- "integrity": "sha512-jEmgmgJEobJ3zEhDOGp1VAJ6JkoVelpS8uZ1ae1Ul/5lP78UKJKmmU0lciJwd6JdnqOXHaaS/QCKwbf1dHI9MA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.5.2.tgz",
+ "integrity": "sha512-2E+1Pg6jJxbRjLNLpciC71iri/3qsKJL222/aXJEFwC0VdUSvfS+JZQQLEVjUYYc8t8pQu2MGE3cF2+bNTYRsg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "expect": "30.5.0",
- "jest-snapshot": "30.5.0"
+ "expect": "30.5.2",
+ "jest-snapshot": "30.5.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect-utils": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.0.tgz",
- "integrity": "sha512-5j0ztPxSy3McUJihjkDdCyCfjvT2hxykFTWsgEBZKB8qsw9ALdCiGTpTRH5gnf/d+qI4SflYUJ0dWNbzjQCWbA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.2.tgz",
+ "integrity": "sha512-d/HOLSrJUlBIl6n3LzOa7cjW3xdePm5H5gQw2lixZ/0h157l9sw3mLblzFqnPcTbhDzhRQdBOX3A3KcG73nm5Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1557,18 +1557,18 @@
}
},
"node_modules/@jest/fake-timers": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.5.0.tgz",
- "integrity": "sha512-sg8xIbYwe5GdB/vT3/0qrDIpO7Ov9mazHi++M95uynmDKEZ70G1r169AWct73H07VrTZhrz1SJEfLtjYv8tE3A==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.5.2.tgz",
+ "integrity": "sha512-GKk0h0tKT5SpDPxDhPg3r9mm5s8/YCBzVNMOGdRiQXwUiMsjU10mVPlMaQstH6/cu50vOb8N9oQUMETHuwwxKw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"@sinonjs/fake-timers": "^15.4.0",
"@types/node": "*",
- "jest-message-util": "30.5.0",
- "jest-mock": "30.5.0",
- "jest-util": "30.5.0"
+ "jest-message-util": "30.5.1",
+ "jest-mock": "30.5.2",
+ "jest-util": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -1595,16 +1595,16 @@
}
},
"node_modules/@jest/globals": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.5.0.tgz",
- "integrity": "sha512-h7eJx534czwL8lQMYB0hwLT4/HquO8EX/RtYL7RNUHyUyWWVciYjoudN4Ns5JmNvn2/jh0Vm9UstZjEzJJ5EsQ==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.5.2.tgz",
+ "integrity": "sha512-62zfS+dL+M5aTNHXCNLyqD+j4oqxTIzDYrZbpqMP8Yn+gvlAGyzC6BSPNb1ZmFOakV1RtFYX/O3FCQXSWmQdgg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "30.5.0",
- "@jest/expect": "30.5.0",
- "@jest/types": "30.5.0",
- "jest-mock": "30.5.0"
+ "@jest/environment": "30.5.2",
+ "@jest/expect": "30.5.2",
+ "@jest/types": "30.5.1",
+ "jest-mock": "30.5.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -1634,24 +1634,24 @@
},
"node_modules/@jest/react-is-19": {
"name": "react-is",
- "version": "19.2.8",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz",
- "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==",
+ "version": "19.3.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz",
+ "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==",
"dev": true,
"license": "MIT"
},
"node_modules/@jest/reporters": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.5.0.tgz",
- "integrity": "sha512-FEAuusWm+PUOn9ydjaHhpOpyPmS6IbGE04HaKTuUI4zd8eqYZiXiNLoCsdCog/l2XnNj53E9pFy64UltcvfJKg==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.5.2.tgz",
+ "integrity": "sha512-ev6E9iG73twQcfAfoTnviuYkr3yOrYbzAtMFCimv2fxHXPIp9PBt2u1wNMt0aYWgl8FPwIcS8oqRJg6alnht4Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "30.5.0",
- "@jest/test-result": "30.5.0",
- "@jest/transform": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/console": "30.5.2",
+ "@jest/test-result": "30.5.2",
+ "@jest/transform": "30.5.2",
+ "@jest/types": "30.5.1",
"@jridgewell/trace-mapping": "^0.3.31",
"@types/node": "*",
"chalk": "^4.1.2",
@@ -1664,9 +1664,9 @@
"istanbul-lib-report": "^3.0.0",
"istanbul-lib-source-maps": "^5.0.0",
"istanbul-reports": "^3.1.3",
- "jest-message-util": "30.5.0",
- "jest-util": "30.5.0",
- "jest-worker": "30.5.0",
+ "jest-message-util": "30.5.1",
+ "jest-util": "30.5.1",
+ "jest-worker": "30.5.1",
"slash": "^3.0.0",
"string-length": "^4.0.2",
"v8-to-istanbul": "^9.0.1"
@@ -1701,9 +1701,9 @@
}
},
"node_modules/@jest/reporters/node_modules/brace-expansion": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
- "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1788,13 +1788,13 @@
}
},
"node_modules/@jest/snapshot-utils": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.5.0.tgz",
- "integrity": "sha512-iWQtIsi2dRsO2oWzVceOeynuRJiYTW8gsDVp5wFQ02ipHluQsNgBpasWSHiawVxukIlsGLdCtCSbIEK7fPtpvQ==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.5.1.tgz",
+ "integrity": "sha512-V3wnxNtiVmw5PPVg433Cn3VdXnsOeu/ofLw3KC04Bn2y1wIlU5kozXQn48rhrgj/02LrCVtntTEF1yBha0XSUw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"natural-compare": "^1.4.0"
@@ -1804,9 +1804,9 @@
}
},
"node_modules/@jest/source-map": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.5.0.tgz",
- "integrity": "sha512-xWpTJP9D0bDFGbPGT8XuWSwwha/iHADyyKzUnMx4UbdgnHugxrDaQFO4RZ8x4ZsFzRP6pNii8uvlgKCDxCIuDg==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.5.2.tgz",
+ "integrity": "sha512-c5CehvkbfHX6yyNg7bMn2ylqlp9AHXuZ/3hPH/Lh5bxD/vefd/lV9HBjMqXef9yQNqkdwyZvkLSVSwB38hy8Qw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1820,14 +1820,14 @@
}
},
"node_modules/@jest/test-result": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.5.0.tgz",
- "integrity": "sha512-9IlPqUzUMkVDmoDqSSrVVLroVotgN3hTUPWPwq24XWXhh1Zpg915RXZ5pgRJ/7j4YE/kng5nqjSn4p3S68SZJA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.5.2.tgz",
+ "integrity": "sha512-eO6YU5rsLfs60ne694e0IAmRgeBnoA8mu0nlxXDbl/1j5km0o2vO9/VbbUIKIH+WRKKEI+ELgwraRGn2Lhep8g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/console": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/console": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"collect-v8-coverage": "^1.0.2"
},
@@ -1836,15 +1836,15 @@
}
},
"node_modules/@jest/test-sequencer": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.5.0.tgz",
- "integrity": "sha512-TXlvSDIVv482b83hD8A8WtxDJEmGF47f60W6jRXOQL0Isfs3hKtk4rZIm9R/jLzAibg8+c56y+Q00BQs8R7Xcg==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.5.2.tgz",
+ "integrity": "sha512-bmij8jZyYAC47ExT2GeP7PcrlwSNS+Bp3KeRuBH88gpcxqDv6fljN8PemS4J/lLZ79xb6mpaennQTTq0zUAVVg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/test-result": "30.5.0",
+ "@jest/test-result": "30.5.2",
"graceful-fs": "^4.2.11",
- "jest-haste-map": "30.5.0",
+ "jest-haste-map": "30.5.1",
"slash": "^3.0.0"
},
"engines": {
@@ -1852,23 +1852,23 @@
}
},
"node_modules/@jest/transform": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.5.0.tgz",
- "integrity": "sha512-n1cYhoByyULEIXi64wbT4Lq91qeT1E6bwpM//sprFXhw955qaiHTdAmy1c1rNFGB6fCf1J+nxDUSf3RGwgZP5A==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.5.2.tgz",
+ "integrity": "sha512-LBGwmaE886C41jDZ65eqR1YbXM7642MK3ZhTowZd5+xDlrDLuf4ePuDdDmVSvcr8NTVJ3MqxLkMbUCzuigUaoQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"@jridgewell/trace-mapping": "^0.3.31",
"babel-plugin-istanbul": "^8.0.0",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
- "jest-haste-map": "30.5.0",
+ "jest-haste-map": "30.5.1",
"jest-regex-util": "30.5.0",
- "jest-util": "30.5.0",
+ "jest-util": "30.5.1",
"pirates": "^4.0.7",
"slash": "^3.0.0",
"write-file-atomic": "^5.0.1"
@@ -1878,9 +1878,9 @@
}
},
"node_modules/@jest/types": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.0.tgz",
- "integrity": "sha512-s1N+79S4Yp9ZgklCauZXi+YPJdCdtStNYQT32stuD6EeQaIBGHoUfyj2P0YWy8RmuQfaJboO+ulxEvEheR/POQ==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz",
+ "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1961,9 +1961,9 @@
"license": "MIT"
},
"node_modules/@metcoder95/https-pem": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@metcoder95/https-pem/-/https-pem-1.0.0.tgz",
- "integrity": "sha512-v+nv59Y6SqdtbXBmAlVx++Vrc2DkBt4F7AVOmbNMB+pjD8QLCoReRdsTCydJC/wY4iZX8O4Cm0F1DhgDgwhIsg==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@metcoder95/https-pem/-/https-pem-1.0.1.tgz",
+ "integrity": "sha512-GdS1XahiLv6n67vkDNwWqa2o6Sm6yYGC3SXyDuifs9gIF4rMMqB53mSguS9uMx8ZjMd8ICRf+KfP9B0mSpWv+g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -1975,9 +1975,9 @@
}
},
"node_modules/@napi-rs/wasm-runtime": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz",
- "integrity": "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==",
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz",
+ "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -2452,9 +2452,9 @@
}
},
"node_modules/@tybys/wasm-util": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
- "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz",
+ "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -3683,13 +3683,13 @@
}
},
"node_modules/babel-jest": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.5.0.tgz",
- "integrity": "sha512-PrhPHlKC+MsLnuNzgIH/y1dkz1f6cSfKWaQeaG8WxLMuG44dYWQ8E9uRrsBbAGCU/3+BEFYPN4d6G3Zc5Y+waA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.5.2.tgz",
+ "integrity": "sha512-ES8WeJ2fNWPEDunyAtUfJ12nHyaWUloCHdkfK2oW5uSoQSUmjNKdWiGaXJITJwvFEWoD/evHEg/QoCXAvLaQqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/transform": "30.5.0",
+ "@jest/transform": "30.5.2",
"@types/babel__core": "^7.20.5",
"babel-plugin-istanbul": "^8.0.0",
"babel-preset-jest": "30.5.0",
@@ -3735,9 +3735,9 @@
}
},
"node_modules/babel-plugin-istanbul/node_modules/brace-expansion": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
- "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3843,9 +3843,9 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
- "version": "2.11.20",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz",
- "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==",
+ "version": "2.11.25",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz",
+ "integrity": "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -4048,9 +4048,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.28.8",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz",
- "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==",
+ "version": "4.29.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz",
+ "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==",
"dev": true,
"funding": [
{
@@ -4068,11 +4068,11 @@
],
"license": "MIT",
"dependencies": {
- "baseline-browser-mapping": "^2.11.12",
- "caniuse-lite": "^1.0.30001809",
- "electron-to-chromium": "^1.5.402",
- "node-releases": "^2.0.53",
- "update-browserslist-db": "^1.3.0"
+ "baseline-browser-mapping": "^2.11.23",
+ "caniuse-lite": "^1.0.30001810",
+ "electron-to-chromium": "^1.5.427",
+ "node-releases": "^2.0.55",
+ "update-browserslist-db": "^1.3.3"
},
"bin": {
"browserslist": "cli.js"
@@ -4874,9 +4874,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.416",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz",
- "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==",
+ "version": "1.5.433",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.433.tgz",
+ "integrity": "sha512-5lCAbyZBjtmUt/RAGHRqrL2q0oEFRThDAsZHHDn9XHa89Qw7gMYOeSicBTy+AHfvo0r6vwsZvqNJTQIQy1BLzA==",
"dev": true,
"license": "ISC"
},
@@ -5679,27 +5679,27 @@
}
},
"node_modules/expect": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.0.tgz",
- "integrity": "sha512-8fiMWcEjPU7B9nErC4FtFcCzf2tC6I75Qf7m8wzBAWC2taZmcno3yAFEjIQL34SwoGZNgPf63UDiJLyh4SMPaw==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.2.tgz",
+ "integrity": "sha512-0LNuMvs8/5mRYhnCR4k+lGV7fqPMs6Bnksda4S3zsCUmdxBpAn4zU4NNzXdq1pMKe/H4W5t/zVIDSJ/H3e0vDA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/expect-utils": "30.5.0",
+ "@jest/expect-utils": "30.5.2",
"@jest/get-type": "30.5.0",
- "jest-matcher-utils": "30.5.0",
- "jest-message-util": "30.5.0",
- "jest-mock": "30.5.0",
- "jest-util": "30.5.0"
+ "jest-matcher-utils": "30.5.2",
+ "jest-message-util": "30.5.1",
+ "jest-mock": "30.5.2",
+ "jest-util": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/fast-check": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.9.0.tgz",
- "integrity": "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg==",
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.10.1.tgz",
+ "integrity": "sha512-sB5Vghiu8MyCyToHoBVGsT0baZg3sZWNIY+a6Ct2EDrQJlT4YdH6MC1BSLNe3kX1k5i5g0q1O52XFgcKK/rGHg==",
"dev": true,
"funding": [
{
@@ -7095,16 +7095,16 @@
}
},
"node_modules/jest": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest/-/jest-30.5.0.tgz",
- "integrity": "sha512-HeFeOUEKh5gjnp1rjuSCse8Dhj0Y3KA8lsZ3azr4Wnq1nCxwMBu35MDc9mp8iblZxmeAz6wV4P241tyUB7J2Ew==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-30.5.2.tgz",
+ "integrity": "sha512-3gnpdBIza8ijCl3iMV9ChE3hSt1+46865qqod863gQtJr1DixOkAU5DoGbi3u+XlRcw++BhZQMu/y4xBdHBvSQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/core": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/core": "30.5.2",
+ "@jest/types": "30.5.1",
"import-local": "^3.2.0",
- "jest-cli": "30.5.0"
+ "jest-cli": "30.5.2"
},
"bin": {
"jest": "bin/jest.js"
@@ -7122,14 +7122,14 @@
}
},
"node_modules/jest-changed-files": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.5.0.tgz",
- "integrity": "sha512-dq1x8JiEnHkJDxxOrF6UJDivBRAQMwAa5tzr+VX3um0SfyMFseUPQUbe51wLwggfoa5h/EmOtSpdJxxkzSlNRQ==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.5.1.tgz",
+ "integrity": "sha512-0+bvMM/ENhDI29Z8q1r4HxiDIi4G5tnBmSw4esfPQoj9q8Nik7KIyuxHkTVnnniJQf05SxpGaKDQ+4h28ynGPg==",
"dev": true,
"license": "MIT",
"dependencies": {
"execa": "^5.1.1",
- "jest-util": "30.5.0",
+ "jest-util": "30.5.1",
"p-limit": "^3.1.0"
},
"engines": {
@@ -7227,29 +7227,29 @@
}
},
"node_modules/jest-circus": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.5.0.tgz",
- "integrity": "sha512-T3v7uM4wwCu+RQicjsAWCgoL3CiyuX3THSKwv2uMb9N2bMUgb+HfwDWEUma85vOGbvQNQ/YfoCXF1OCZot0ZEw==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.5.2.tgz",
+ "integrity": "sha512-vffFgjs5JSJ9q4ds1vNW3klKYPJfYfIY61LT/zaZgvTeASJOWZUt8LBfHgIcV4rwxlPBLl/ePBGccHEclS4PlQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "30.5.0",
- "@jest/expect": "30.5.0",
- "@jest/test-result": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/environment": "30.5.2",
+ "@jest/expect": "30.5.2",
+ "@jest/test-result": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
"chalk": "^4.1.2",
"co": "^4.6.0",
"dedent": "^1.6.0",
"is-generator-fn": "^2.1.0",
- "jest-each": "30.5.0",
- "jest-matcher-utils": "30.5.0",
- "jest-message-util": "30.5.0",
- "jest-runtime": "30.5.0",
- "jest-snapshot": "30.5.0",
- "jest-util": "30.5.0",
+ "jest-each": "30.5.2",
+ "jest-matcher-utils": "30.5.2",
+ "jest-message-util": "30.5.1",
+ "jest-runtime": "30.5.2",
+ "jest-snapshot": "30.5.2",
+ "jest-util": "30.5.1",
"p-limit": "^3.1.0",
- "pretty-format": "30.5.0",
+ "pretty-format": "30.5.1",
"pure-rand": "^7.0.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
@@ -7276,21 +7276,21 @@
"license": "MIT"
},
"node_modules/jest-cli": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.5.0.tgz",
- "integrity": "sha512-QHZMiy32x2K+NzJ1AuuoCAVc1Y5co0VXib3R7kD9MWcWFflzsD1eJN0wR+mkNlM+ts7C+Bjz0oOoFE5IiHylCg==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.5.2.tgz",
+ "integrity": "sha512-YYYxUUVjFgPvgEleKNKMaYGIFgR3l3832Cl0kRL/oCiDZ03v7wImUtquHl2OOBCCNgprjZgBN5bczS/JklPBDg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/core": "30.5.0",
- "@jest/test-result": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/core": "30.5.2",
+ "@jest/test-result": "30.5.2",
+ "@jest/types": "30.5.1",
"chalk": "^4.1.2",
"exit-x": "^0.2.2",
"import-local": "^3.2.0",
- "jest-config": "30.5.0",
- "jest-util": "30.5.0",
- "jest-validate": "30.5.0",
+ "jest-config": "30.5.2",
+ "jest-util": "30.5.1",
+ "jest-validate": "30.5.1",
"yargs": "^17.7.2"
},
"bin": {
@@ -7309,33 +7309,33 @@
}
},
"node_modules/jest-config": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.5.0.tgz",
- "integrity": "sha512-gYQl2FqYgiVpyuB7DutBIbJRWaq5VcHdzOXJJ51HNa8J5JrsZehIlzNFW0/9s5uvvcbzM5/LTUizYSbsFErv+w==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.5.2.tgz",
+ "integrity": "sha512-U6221OZekabePvGcGPf4raIBKMvYQWFHvhobDJRojOYaFMj2HaGytAdknjDhYc6JTz2fdHW9+6k0wWUDaNeOFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/get-type": "30.5.0",
"@jest/pattern": "30.5.0",
- "@jest/test-sequencer": "30.5.0",
- "@jest/types": "30.5.0",
- "babel-jest": "30.5.0",
+ "@jest/test-sequencer": "30.5.2",
+ "@jest/types": "30.5.1",
+ "babel-jest": "30.5.2",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
"deepmerge": "^4.3.1",
"glob": "^13.0.6",
"graceful-fs": "^4.2.11",
- "jest-circus": "30.5.0",
+ "jest-circus": "30.5.2",
"jest-docblock": "30.5.0",
- "jest-environment-node": "30.5.0",
+ "jest-environment-node": "30.5.2",
"jest-regex-util": "30.5.0",
- "jest-resolve": "30.5.0",
- "jest-runner": "30.5.0",
- "jest-util": "30.5.0",
- "jest-validate": "30.5.0",
+ "jest-resolve": "30.5.1",
+ "jest-runner": "30.5.2",
+ "jest-util": "30.5.1",
+ "jest-validate": "30.5.1",
"parse-json": "^5.2.0",
- "pretty-format": "30.5.0",
+ "pretty-format": "30.5.1",
"slash": "^3.0.0",
"strip-json-comments": "^3.1.1"
},
@@ -7370,9 +7370,9 @@
}
},
"node_modules/jest-config/node_modules/brace-expansion": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
- "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7444,16 +7444,16 @@
}
},
"node_modules/jest-diff": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.0.tgz",
- "integrity": "sha512-QjCfDMwdPFvLxTQmS4/Dswx3PUCiqmSXVLGljMC3SU7YG1qHVoR6b86IH/O2G9k9OMyKXz2vS2Q60VnAozNDwA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.2.tgz",
+ "integrity": "sha512-rBtHnI6BWTiWj3lM7fOLVfChx7R9B0u9VV3PRHawKs79x6ZjW1QoSrKenaigNGWlvhtoi2BqvDbABDie+Os3xQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/diff-sequences": "30.5.0",
"@jest/get-type": "30.5.0",
"chalk": "^4.1.2",
- "pretty-format": "30.5.0"
+ "pretty-format": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -7473,36 +7473,37 @@
}
},
"node_modules/jest-each": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.5.0.tgz",
- "integrity": "sha512-NiMFNhRygJEFqYNt8pnkxppUF6CR486GEpt9rSU6lPBf7KeccaOL0zbjxG8fgJgD//6e7zYdssnlt6j+1kI31A==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.5.2.tgz",
+ "integrity": "sha512-GRrW+7fmmgmkvyfEBqc1QFdWnF1Ex5yG6Y6AWL4TTxnkWlKIT98dsKh3P3UuWm6v4XsQwVE6DEzXIPMzWJ3ZbA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"chalk": "^4.1.2",
- "jest-util": "30.5.0",
- "pretty-format": "30.5.0"
+ "jest-regex-util": "30.5.0",
+ "jest-util": "30.5.1",
+ "pretty-format": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-environment-node": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.5.0.tgz",
- "integrity": "sha512-bTc79ywKLz0ogbT3JIYuEhgWV4Ffd/cJe06co4v8CyRtlmju8x5gokMlGFR8ARWhmk5SnbDRxmf50XWnlZVhDg==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.5.2.tgz",
+ "integrity": "sha512-Ciz4KgTGIbojxSKpuFImgWJj5EyqfE8xMq9NxWmOXnQywHHS03H9Mv+vaCB29J5pr3JBrY27WbRV18rBdjh8Dg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "30.5.0",
- "@jest/fake-timers": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/environment": "30.5.2",
+ "@jest/fake-timers": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
- "jest-mock": "30.5.0",
- "jest-util": "30.5.0",
- "jest-validate": "30.5.0"
+ "jest-mock": "30.5.2",
+ "jest-util": "30.5.1",
+ "jest-validate": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -7519,13 +7520,13 @@
}
},
"node_modules/jest-haste-map": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.5.0.tgz",
- "integrity": "sha512-0FStogBslBVOEqTOJr4oXMtFitmrWp9WscG6Gbns88i0YAuMXijCT2G5VMfg/HCR4QAnL+OF2C2ednag+HlDuA==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.5.1.tgz",
+ "integrity": "sha512-VIFgt67jW480YDxKfEv9IYQKrFpYt7bOCMn3VsnjK7AK9qo7p6acpnA1DHwsVOULE3dTaYew/6JaTD/d0VDHoQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"@parcel/watcher": "^2.6.0",
"@types/node": "*",
"anymatch": "^3.1.3",
@@ -7533,8 +7534,8 @@
"fdir": "^6.5.0",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.5.0",
- "jest-util": "30.5.0",
- "jest-worker": "30.5.0",
+ "jest-util": "30.5.1",
+ "jest-worker": "30.5.1",
"picomatch": "^4.0.3"
},
"engines": {
@@ -7542,50 +7543,50 @@
}
},
"node_modules/jest-leak-detector": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.5.0.tgz",
- "integrity": "sha512-Mq11ceAkNR250Iv45RoOwuG9fb4kYbJ02qoyL7A0nCI8FV5+aG/THmcEUx5uR2dNSa4KOtz+xBKrJ8cZPhPpuQ==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.5.1.tgz",
+ "integrity": "sha512-gt4GT2aWgEoCNTcBe4rqS74xTIUJxi+UD9SNSu9aOk5LmTEd6fS5KSTmAKAfitCCktQHNN+upUuL6EkBfFbMDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.5.0",
- "pretty-format": "30.5.0"
+ "pretty-format": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-matcher-utils": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.0.tgz",
- "integrity": "sha512-EfaYMC9f9ds7fahB/LYFTgd1Z2RS9Vpm2e46gazij0onkpoQG7Daq+MLm8/gQVqWwRVjL/RNDggbFx9MsrJEmQ==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.2.tgz",
+ "integrity": "sha512-lFkB365PTIHOhPzwrb9T6gvlDnPpOZ7/c3ewOKKB7bzztqjVrtlyRL2MkyfJXpyY2u2SKw001JKrTx14fBUFcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.5.0",
"chalk": "^4.1.2",
- "jest-diff": "30.5.0",
- "pretty-format": "30.5.0"
+ "jest-diff": "30.5.2",
+ "pretty-format": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-message-util": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.0.tgz",
- "integrity": "sha512-dBYMhplGfspKaCnVk9TUy1cZnknWubpuPNEputjz0YJk1G/92R45rn45BvbPMPMtC5LVcIdxJGPOaOSQTiuzJw==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz",
+ "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
- "jest-util": "30.5.0",
+ "jest-util": "30.5.1",
"picomatch": "^4.0.3",
- "pretty-format": "30.5.0",
+ "pretty-format": "30.5.1",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -7594,16 +7595,16 @@
}
},
"node_modules/jest-mock": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.0.tgz",
- "integrity": "sha512-bP5MHZpkYrV7xpV+yvhl36DPcXoEmTR57Un5EACcdVpMY7mpkDefCBq+V4mhcjE/3rwUajT6OTrcJTN7EwN1BA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.2.tgz",
+ "integrity": "sha512-KTHb37Fhj8xY8qPFvTFaFJHcdsumQp+ExsUlgoX232Agmc706gagBs53+CYvulV7MVQo9AgXOUxsqzzVBoJlrA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/expect-utils": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/expect-utils": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
- "jest-util": "30.5.0"
+ "jest-util": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -7620,17 +7621,17 @@
}
},
"node_modules/jest-resolve": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.5.0.tgz",
- "integrity": "sha512-NFvQWJ4G7e2kN5712iG+12Xr325NRFGAIhovrwLfgq5Oqd4bFHITw4CzcFkZGp1GTCqemC4v1l8/yZzedKZkjw==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.5.1.tgz",
+ "integrity": "sha512-wprhLejRtwN6h8ZgaqC0eYjGJ1uMdGPT/+b3eFncbG4NWuuP9QL+vWwRinu9waw7hkOLcpMJGVJAMgBwsPssMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
- "jest-haste-map": "30.5.0",
- "jest-util": "30.5.0",
- "jest-validate": "30.5.0",
+ "jest-haste-map": "30.5.1",
+ "jest-util": "30.5.1",
+ "jest-validate": "30.5.1",
"slash": "^3.0.0",
"unrs-resolver": "^1.12.1"
},
@@ -7639,47 +7640,47 @@
}
},
"node_modules/jest-resolve-dependencies": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.5.0.tgz",
- "integrity": "sha512-TnSBAp3wGOnqXBmLT3OXtJkugw6Vj2KU0IPde2EJmbGns/QMoNlkauJ7jZ8KYaxONSpx0o4pUvi+u1Q/LSk3Pg==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.5.2.tgz",
+ "integrity": "sha512-GMI0DP5enX9Z2qW2zFy1bOkrCfWAOPRJQ7qHt0pdfrxBPsgWxglMPrRSK2TX/wRWYxcPRSLFg3Z88qPOzHx7FQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"jest-regex-util": "30.5.0",
- "jest-snapshot": "30.5.0"
+ "jest-snapshot": "30.5.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-runner": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.5.0.tgz",
- "integrity": "sha512-Q6Yt+1LvXvEstvru6sQLT7OQYC77VNl6dK0KEvBkeOHgThmXDqNp3Ox9TglDWFHU85pemqTNdKwxfnmO3vgrdA==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.5.2.tgz",
+ "integrity": "sha512-/B6px7hiiNhVSRwuv9AGn0nawYvwsHeQZ3ItTd5Gp2diFd0EOKaWVeWqcbw3L88vx1GfpCKjQkxWItZCTl11Rw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/console": "30.5.0",
- "@jest/environment": "30.5.0",
- "@jest/source-map": "30.5.0",
- "@jest/test-result": "30.5.0",
- "@jest/transform": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/console": "30.5.2",
+ "@jest/environment": "30.5.2",
+ "@jest/source-map": "30.5.2",
+ "@jest/test-result": "30.5.2",
+ "@jest/transform": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
"chalk": "^4.1.2",
"emittery": "^0.13.1",
"exit-x": "^0.2.2",
"graceful-fs": "^4.2.11",
"jest-docblock": "30.5.0",
- "jest-environment-node": "30.5.0",
- "jest-haste-map": "30.5.0",
- "jest-leak-detector": "30.5.0",
- "jest-message-util": "30.5.0",
- "jest-resolve": "30.5.0",
- "jest-runtime": "30.5.0",
- "jest-util": "30.5.0",
- "jest-watcher": "30.5.0",
- "jest-worker": "30.5.0",
+ "jest-environment-node": "30.5.2",
+ "jest-haste-map": "30.5.1",
+ "jest-leak-detector": "30.5.1",
+ "jest-message-util": "30.5.1",
+ "jest-resolve": "30.5.1",
+ "jest-runtime": "30.5.2",
+ "jest-util": "30.5.1",
+ "jest-watcher": "30.5.2",
+ "jest-worker": "30.5.1",
"p-limit": "^3.1.0"
},
"engines": {
@@ -7687,19 +7688,19 @@
}
},
"node_modules/jest-runtime": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.5.0.tgz",
- "integrity": "sha512-VTRz0sRIw2EISeHigx1O+CMuwoG4+RKJjF8dp8okzFaDNQEcv5Mw0h5QW8VJXgb2CRF4gZIjSEBb2jdzXPagFQ==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.5.2.tgz",
+ "integrity": "sha512-0paUAHBlheai10A3XSy9Xh+YBG0IROy+/qzcDPzQ/nbbXrznQzeWy5qniICWK6d3W3scaRQCVAbXdcK0ibBq4w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "30.5.0",
- "@jest/fake-timers": "30.5.0",
- "@jest/globals": "30.5.0",
- "@jest/source-map": "30.5.0",
- "@jest/test-result": "30.5.0",
- "@jest/transform": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/environment": "30.5.2",
+ "@jest/fake-timers": "30.5.2",
+ "@jest/globals": "30.5.2",
+ "@jest/source-map": "30.5.2",
+ "@jest/test-result": "30.5.2",
+ "@jest/transform": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
"chalk": "^4.1.2",
"cjs-module-lexer": "^2.2.0",
@@ -7707,13 +7708,13 @@
"es-module-lexer": "^2.1.0",
"glob": "^13.0.6",
"graceful-fs": "^4.2.11",
- "jest-haste-map": "30.5.0",
- "jest-message-util": "30.5.0",
- "jest-mock": "30.5.0",
+ "jest-haste-map": "30.5.1",
+ "jest-message-util": "30.5.1",
+ "jest-mock": "30.5.2",
"jest-regex-util": "30.5.0",
- "jest-resolve": "30.5.0",
- "jest-snapshot": "30.5.0",
- "jest-util": "30.5.0",
+ "jest-resolve": "30.5.1",
+ "jest-snapshot": "30.5.2",
+ "jest-util": "30.5.1",
"slash": "^3.0.0",
"strip-bom": "^4.0.0"
},
@@ -7732,9 +7733,9 @@
}
},
"node_modules/jest-runtime/node_modules/brace-expansion": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
- "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7806,9 +7807,9 @@
}
},
"node_modules/jest-snapshot": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.5.0.tgz",
- "integrity": "sha512-pZWETdcqmKve9MDTE/AX6RaeAbRhzKhhAXGozAW8Pg2FfOSdUrQ/7D+VdwE3fLQsqjpITXJVQvYVZoMEzrUl0Q==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.5.2.tgz",
+ "integrity": "sha512-jKIdes25AnAH73dOCi2qE6J6vHJ6L2vyBS11M89kT50DVJcLTf2AOjvcc+2vVaN8lUbY5v2R83aqXo3Ro9fqYA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7817,20 +7818,20 @@
"@babel/plugin-syntax-jsx": "^7.27.1",
"@babel/plugin-syntax-typescript": "^7.27.1",
"@babel/types": "^7.27.3",
- "@jest/expect-utils": "30.5.0",
+ "@jest/expect-utils": "30.5.2",
"@jest/get-type": "30.5.0",
- "@jest/snapshot-utils": "30.5.0",
- "@jest/transform": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/snapshot-utils": "30.5.1",
+ "@jest/transform": "30.5.2",
+ "@jest/types": "30.5.1",
"babel-preset-current-node-syntax": "^1.2.0",
"chalk": "^4.1.2",
- "expect": "30.5.0",
+ "expect": "30.5.2",
"graceful-fs": "^4.2.11",
- "jest-diff": "30.5.0",
- "jest-matcher-utils": "30.5.0",
- "jest-message-util": "30.5.0",
- "jest-util": "30.5.0",
- "pretty-format": "30.5.0",
+ "jest-diff": "30.5.2",
+ "jest-matcher-utils": "30.5.2",
+ "jest-message-util": "30.5.1",
+ "jest-util": "30.5.1",
+ "pretty-format": "30.5.1",
"semver": "^7.7.2",
"synckit": "^0.11.8"
},
@@ -7852,13 +7853,13 @@
}
},
"node_modules/jest-util": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.0.tgz",
- "integrity": "sha512-lzU4aGUWaS+2X/B0CmgheDasfnsVlRfZh/rNQxB9b9s8cSYUq5BcqdQA95ld+KqJXBUVVt1sqnMQ2T3OxIalmg==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz",
+ "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -7870,18 +7871,18 @@
}
},
"node_modules/jest-validate": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.5.0.tgz",
- "integrity": "sha512-N/hsPYKgBSzBeVZ2RHCs3yvBbTZNPX7Be8q33zhyo/yeFneBL1swzly31LYU4LJ3zJM9e8TxSM8IYLo2SDJZYQ==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.5.1.tgz",
+ "integrity": "sha512-i/buJ56wTpxihE93hQYNMfdOThS87+HGvLZzZJmU4xggPcdTYQq051iwALLCHp3q+SkCGH+EFejQZz5EbBSkkg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/types": "30.5.1",
"camelcase": "^6.3.0",
"chalk": "^4.1.2",
"leven": "^3.1.0",
- "pretty-format": "30.5.0"
+ "pretty-format": "30.5.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -7901,19 +7902,19 @@
}
},
"node_modules/jest-watcher": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.5.0.tgz",
- "integrity": "sha512-ujjnEoL4Uu+Swu3WRwYenWMB9JMEiD2T3OypnveMJ64S/1r/5G8eC4OQ1wEOgYWQqMi+mT+buzccflCHr/XJ9Q==",
+ "version": "30.5.2",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.5.2.tgz",
+ "integrity": "sha512-rqRgg4R11GA9m1UsEZwQeixHsgZReCn6TOHAHtIH33yXrIvoX0OGPA20Yzzjkz7X40fZvcRSxEpQppYPcWzmcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/test-result": "30.5.0",
- "@jest/types": "30.5.0",
+ "@jest/test-result": "30.5.2",
+ "@jest/types": "30.5.1",
"@types/node": "*",
"ansi-escapes": "^4.3.2",
"chalk": "^4.1.2",
"emittery": "^0.13.1",
- "jest-util": "30.5.0",
+ "jest-util": "30.5.1",
"string-length": "^4.0.2"
},
"engines": {
@@ -7921,15 +7922,15 @@
}
},
"node_modules/jest-worker": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.5.0.tgz",
- "integrity": "sha512-7kFk/607EoynNHLJa20daivkElM+c9PrCLduYy6AlMkYrXbh5TmVtW1BLXE05Y8baAFsJHMoC3xs2QRRTotwLw==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.5.1.tgz",
+ "integrity": "sha512-Cbxh5v7AoLuFRmFJSM4/aHdQ68rjXvUWr716EE0Dh3I7T+T/3FgFKhOERGXHcU2Meftq9+9zxPM3TSNyI9D+HA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"@ungap/structured-clone": "^1.3.0",
- "jest-util": "30.5.0",
+ "jest-util": "30.5.1",
"merge-stream": "^2.0.0",
"supports-color": "^8.1.1"
},
@@ -8570,9 +8571,9 @@
"license": "MIT"
},
"node_modules/node-releases": {
- "version": "2.0.54",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz",
- "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==",
+ "version": "2.0.56",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.56.tgz",
+ "integrity": "sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9162,9 +9163,9 @@
}
},
"node_modules/pretty-format": {
- "version": "30.5.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.0.tgz",
- "integrity": "sha512-mzNzBErpHwM0zpmWS7ExOv62yhQhvd546nUuFqVR0dmnJB59tfrw9sjDF0DJknwsr59OXP0buwJ7PaKguczHSg==",
+ "version": "30.5.1",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz",
+ "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10865,9 +10866,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz",
- "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==",
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz",
+ "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==",
"dev": true,
"funding": [
{
diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json
index bc78602fe5b..fd425598742 100644
--- a/deps/undici/src/package.json
+++ b/deps/undici/src/package.json
@@ -1,6 +1,6 @@
{
"name": "undici",
- "version": "8.10.2",
+ "version": "8.11.2",
"description": "An HTTP/1.1 client, written from scratch for Node.js",
"homepage": "https://undici.nodejs.org",
"bugs": {
diff --git a/deps/undici/src/types/diagnostics-channel.d.ts b/deps/undici/src/types/diagnostics-channel.d.ts
index 3c6a5299d38..10523d65c72 100644
--- a/deps/undici/src/types/diagnostics-channel.d.ts
+++ b/deps/undici/src/types/diagnostics-channel.d.ts
@@ -2,6 +2,7 @@ import { Socket } from 'node:net'
import { URL } from 'node:url'
import buildConnector from './connector'
import Dispatcher from './dispatcher'
+import { IncomingHttpHeaders } from './header'
declare namespace DiagnosticsChannel {
interface Request {
@@ -14,7 +15,7 @@ declare namespace DiagnosticsChannel {
interface Response {
statusCode: number;
statusText: string;
- headers: Array<Buffer>;
+ headers: Array<Buffer> | IncomingHttpHeaders;
}
interface ConnectParams {
host: URL['host'];
diff --git a/deps/undici/src/types/interceptors.d.ts b/deps/undici/src/types/interceptors.d.ts
index c11d4017b11..4383454baf5 100644
--- a/deps/undici/src/types/interceptors.d.ts
+++ b/deps/undici/src/types/interceptors.d.ts
@@ -12,7 +12,7 @@ declare namespace Interceptors {
export type DecompressInterceptorOpts = {
skipErrorResponses?: boolean
skipStatusCodes?: number[]
- /** Maximum decompressed response size in bytes. @default 67108864 */
+ /** Maximum decompressed response size in bytes per stage. 0 disables the limit. @default 0 */
maxSize?: number
}
diff --git a/deps/undici/src/types/webidl.d.ts b/deps/undici/src/types/webidl.d.ts
index b1873b9e52d..6bfe674c9ed 100644
--- a/deps/undici/src/types/webidl.d.ts
+++ b/deps/undici/src/types/webidl.d.ts
@@ -248,13 +248,22 @@ type WebidlIsFunction<T> = (arg: any) => arg is T
interface WebidlIs {
Request: WebidlIsFunction<undici.Request>
Response: WebidlIsFunction<undici.Response>
+ Headers: WebidlIsFunction<undici.Headers>
+ FormData: WebidlIsFunction<undici.FormData>
+ WebSocket: WebidlIsFunction<undici.WebSocket>
+ WebSocketError: WebidlIsFunction<undici.WebSocketError>
+ Cache: WebidlIsFunction<undici.Cache>
+ CacheStorage: WebidlIsFunction<undici.CacheStorage>
+ EventSource: WebidlIsFunction<undici.EventSource>
+ MessageEvent: WebidlIsFunction<undici.MessageEvent>
+ CloseEvent: WebidlIsFunction<undici.CloseEvent>
+ ErrorEvent: WebidlIsFunction<undici.ErrorEvent>
+
ReadableStream: WebidlIsFunction<ReadableStream>
Blob: WebidlIsFunction<Blob>
URLSearchParams: WebidlIsFunction<URLSearchParams>
File: WebidlIsFunction<File>
- FormData: WebidlIsFunction<undici.FormData>
URL: WebidlIsFunction<URL>
- WebSocketError: WebidlIsFunction<undici.WebSocketError>
AbortSignal: WebidlIsFunction<AbortSignal>
MessagePort: WebidlIsFunction<MessagePort>
USVString: WebidlIsFunction<string>
@@ -272,12 +281,9 @@ export interface Webidl {
attributes: WebIDLExtendedAttributes
/**
- * @description Performs a brand-check on {@param V} to ensure it is a
- * {@param cls} object.
+ * @description Performs a brand-check on {@param V}.
*/
- brandCheck <Interface extends new () => unknown>(V: unknown, cls: Interface): asserts V is Interface
-
- brandCheckMultiple <Interfaces extends (new () => unknown)[]> (list: Interfaces): (V: any) => asserts V is Interfaces[number]
+ brandCheck <T>(V: unknown, assertion: WebidlIsFunction<T>): asserts V is T
/**
* @see https://webidl.spec.whatwg.org/#es-sequence
diff --git a/deps/undici/undici.js b/deps/undici/undici.js
index b67af93f365..944a6fa5fce 100644
--- a/deps/undici/undici.js
+++ b/deps/undici/undici.js
@@ -950,6 +950,9 @@ var require_pool_base = __commonJS({
var kOnConnect = /* @__PURE__ */ Symbol("onConnect");
var kOnDisconnect = /* @__PURE__ */ Symbol("onDisconnect");
var kOnConnectionError = /* @__PURE__ */ Symbol("onConnectionError");
+ var kOnClientBusy = /* @__PURE__ */ Symbol("on client busy");
+ var kOnClientDrain = /* @__PURE__ */ Symbol("on client drain");
+ var kDrainQueue = /* @__PURE__ */ Symbol("drain queue");
var kGetDispatcher = /* @__PURE__ */ Symbol("get dispatcher");
var kHasDispatcher = /* @__PURE__ */ Symbol("has dispatcher");
var kAddClient = /* @__PURE__ */ Symbol("add client");
@@ -963,8 +966,12 @@ var require_pool_base = __commonJS({
[kClients] = [];
[kNeedDrain] = false;
[kOnDrain](client, origin, targets) {
+ if (client.closed || client.destroyed) {
+ return;
+ }
const queue = this[kQueue];
let needDrain = false;
+ this[kOnClientDrain](client);
while (!needDrain) {
const item = queue.shift();
if (!item) {
@@ -974,6 +981,9 @@ var require_pool_base = __commonJS({
needDrain = !client.dispatch(item.opts, item.handler);
}
client[kNeedDrain] = needDrain;
+ if (needDrain) {
+ this[kOnClientBusy](client);
+ }
if (!needDrain && this[kNeedDrain]) {
this[kNeedDrain] = false;
this.emit("drain", origin, [this, ...targets]);
@@ -989,6 +999,45 @@ var require_pool_base = __commonJS({
return Promise.all(closeAll).then(this[kClosedResolve]);
}
}
+ [kOnClientBusy]() {
+ }
+ [kOnClientDrain]() {
+ }
+ [kDrainQueue](origin, targets) {
+ const queue = this[kQueue];
+ let hasDispatcher = true;
+ while (!queue.isEmpty()) {
+ const dispatcher = this[kGetDispatcher]();
+ if (!dispatcher) {
+ hasDispatcher = false;
+ break;
+ }
+ const item = queue.shift();
+ this[kQueued]--;
+ if (!dispatcher.dispatch(item.opts, item.handler)) {
+ dispatcher[kNeedDrain] = true;
+ this[kOnClientBusy](dispatcher);
+ hasDispatcher = this[kHasDispatcher]();
+ if (!hasDispatcher) {
+ break;
+ }
+ }
+ }
+ if (hasDispatcher && this[kNeedDrain]) {
+ this[kNeedDrain] = false;
+ this.emit("drain", origin, [this, ...targets]);
+ }
+ if (this[kClosedResolve] && queue.isEmpty()) {
+ const closeAll = [];
+ for (let i = 0; i < this[kClients].length; i++) {
+ const client = this[kClients][i];
+ if (!client.destroyed) {
+ closeAll.push(client.close());
+ }
+ }
+ return Promise.all(closeAll).then(this[kClosedResolve]);
+ }
+ }
[kOnConnect] = (origin, targets) => {
this.emit("connect", origin, [this, ...targets]);
};
@@ -1077,6 +1126,7 @@ var require_pool_base = __commonJS({
this[kQueued]++;
} else if (!dispatcher.dispatch(opts, handler)) {
dispatcher[kNeedDrain] = true;
+ this[kOnClientBusy](dispatcher);
this[kNeedDrain] = !this[kHasDispatcher]();
}
return !this[kNeedDrain];
@@ -1095,7 +1145,7 @@ var require_pool_base = __commonJS({
this[kClients].push(client);
if (this[kNeedDrain]) {
queueMicrotask(() => {
- if (this[kNeedDrain]) {
+ if (this[kNeedDrain] && !client[kNeedDrain]) {
this[kOnDrain](client, client[kUrl], [client, this]);
}
});
@@ -1118,6 +1168,9 @@ var require_pool_base = __commonJS({
kNeedDrain,
kAddClient,
kRemoveClient,
+ kDrainQueue,
+ kOnClientBusy,
+ kOnClientDrain,
kGetDispatcher,
kHasDispatcher
};
@@ -2003,38 +2056,6 @@ var require_util = __commonJS({
};
}
__name(getSocketInfo, "getSocketInfo");
- function ReadableStreamFrom(iterable) {
- let iterator;
- return new ReadableStream(
- {
- start() {
- iterator = iterable[Symbol.asyncIterator]();
- },
- pull(controller) {
- return iterator.next().then(({ done, value }) => {
- if (done) {
- return queueMicrotask(() => {
- controller.close();
- controller.byobRequest?.respond(0);
- });
- } else {
- const buf = Buffer.isBuffer(value) ? value : Buffer.from(value);
- if (buf.byteLength) {
- return controller.enqueue(new Uint8Array(buf));
- } else {
- return this.pull(controller);
- }
- }
- });
- },
- cancel() {
- return iterator.return();
- },
- type: "bytes"
- }
- );
- }
- __name(ReadableStreamFrom, "ReadableStreamFrom");
function isFormDataLike(object) {
return object && typeof object === "object" && typeof object.append === "function" && typeof object.delete === "function" && typeof object.get === "function" && typeof object.getAll === "function" && typeof object.has === "function" && typeof object.set === "function" && object[Symbol.toStringTag] === "FormData";
}
@@ -2507,7 +2528,6 @@ var require_util = __commonJS({
destroy,
bodyLength,
deepClone,
- ReadableStreamFrom,
isBuffer,
assertRequestHandler,
getSocketInfo,
@@ -3052,15 +3072,32 @@ var require_request = __commonJS({
return false;
}
}
- onRequestUpgrade(statusCode, headers, socket) {
+ /**
+ * @param {number} statusCode
+ * @param {Buffer[]|string[]|import('../../types/header.d.ts').IncomingHttpHeaders} headers
+ * @param {import('node:stream').Duplex} socket
+ * @param {string} [statusText]
+ */
+ onRequestUpgrade(statusCode, headers, socket, statusText = "") {
+ this.onFinally();
assert(!this.aborted);
assert(!this.completed);
+ if (channels.headers.hasSubscribers) {
+ channels.headers.publish({ request: this, response: { statusCode, headers, statusText } });
+ }
const controller = this[kController];
if (controller) {
controller.rawHeaders = headers;
}
const parsedHeaders = Array.isArray(headers) ? parseHeaders(headers) : headers;
- return this[kHandler].onRequestUpgrade?.(controller, statusCode, parsedHeaders, socket);
+ const result = this[kHandler].onRequestUpgrade?.(controller, statusCode, parsedHeaders, socket);
+ if (!this.aborted) {
+ this.completed = true;
+ if (channels.trailers.hasSubscribers) {
+ channels.trailers.publish({ request: this, trailers: [] });
+ }
+ }
+ return result;
}
onResponseEnd(trailers) {
this.onFinally();
@@ -4391,6 +4428,11 @@ var require_infra = __commonJS({
return input;
}
__name(isomorphicEncode, "isomorphicEncode");
+ var nonASCIIRegex = /[^\x00-\x7F]/;
+ function asciiLowercase(str) {
+ return nonASCIIRegex.test(str) ? str.replace(/[A-Z]+/g, (upper) => upper.toLowerCase()) : str.toLowerCase();
+ }
+ __name(asciiLowercase, "asciiLowercase");
function parseJSONFromBytes(bytes) {
return JSON.parse(utf8DecodeBytes(bytes));
}
@@ -4406,7 +4448,7 @@ var require_infra = __commonJS({
while (lead < str.length && predicate(str.charCodeAt(lead))) lead++;
}
if (trailing) {
- while (trail > 0 && predicate(str.charCodeAt(trail))) trail--;
+ while (trail >= lead && predicate(str.charCodeAt(trail))) trail--;
}
return lead === 0 && trail === str.length - 1 ? str : str.slice(lead, trail + 1);
}
@@ -4421,6 +4463,7 @@ var require_infra = __commonJS({
}
__name(serializeJavascriptValueToJSONString, "serializeJavascriptValueToJSONString");
module2.exports = {
+ asciiLowercase,
collectASequenceOfCodePoints,
collectASequenceOfCodePointsFast,
forgivingBase64,
@@ -4440,9 +4483,9 @@ var require_data_url = __commonJS({
"lib/web/fetch/data-url.js"(exports2, module2) {
"use strict";
var assert = require("node:assert");
- var { forgivingBase64, collectASequenceOfCodePoints, collectASequenceOfCodePointsFast, isomorphicDecode, removeASCIIWhitespace, removeChars } = require_infra();
+ var { asciiLowercase, forgivingBase64, collectASequenceOfCodePoints, collectASequenceOfCodePointsFast, isomorphicDecode, removeASCIIWhitespace, removeChars } = require_infra();
var encoder = new TextEncoder();
- var HTTP_TOKEN_CODEPOINTS = /^[-!#$%&'*+.^_|~A-Za-z0-9]+$/u;
+ var HTTP_TOKEN_CODEPOINTS = /^[-!#$%&'*+.^_`|~A-Za-z0-9]+$/u;
var HTTP_WHITESPACE_REGEX = /[\u000A\u000D\u0009\u0020]/u;
var HTTP_QUOTED_STRING_TOKENS = /^[\u0009\u0020-\u007E\u0080-\u00FF]+$/u;
function dataURLProcessor(dataURL) {
@@ -4463,7 +4506,7 @@ var require_data_url = __commonJS({
position.position++;
const encodedBody = input.slice(mimeTypeLength + 1);
let body = stringPercentDecode(encodedBody);
- if (/;(?:\u0020*)base64$/ui.test(mimeType)) {
+ if (/;\u0020*[Bb][Aa][Ss][Ee]64$/u.test(mimeType)) {
const stringBody = isomorphicDecode(body);
body = forgivingBase64(stringBody);
if (body === "failure") {
@@ -4556,8 +4599,8 @@ var require_data_url = __commonJS({
if (subtype.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(subtype)) {
return "failure";
}
- const typeLowercase = type.toLowerCase();
- const subtypeLowercase = subtype.toLowerCase();
+ const typeLowercase = asciiLowercase(type);
+ const subtypeLowercase = asciiLowercase(subtype);
const mimeType = {
type: typeLowercase,
subtype: subtypeLowercase,
@@ -4579,7 +4622,7 @@ var require_data_url = __commonJS({
input,
position
);
- parameterName = parameterName.toLowerCase();
+ parameterName = asciiLowercase(parameterName);
if (position.position < input.length) {
if (input[position.position] === ";") {
continue;
@@ -4765,23 +4808,13 @@ var require_webidl = __commonJS({
message: `"${context.value}" is an invalid ${context.type}.`
});
};
- webidl.brandCheck = function(V, I) {
- if (!FunctionPrototypeSymbolHasInstance(I, V)) {
+ webidl.brandCheck = function(V, is) {
+ if (!is(V)) {
const err = new TypeError("Illegal invocation");
err.code = "ERR_INVALID_THIS";
throw err;
}
};
- webidl.brandCheckMultiple = function(List) {
- const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c));
- return (V) => {
- if (prototypes.every((typeCheck) => !typeCheck(V))) {
- const err = new TypeError("Illegal invocation");
- err.code = "ERR_INVALID_THIS";
- throw err;
- }
- };
- };
webidl.argumentLengthCheck = function({ length }, min, ctx) {
if (length < min) {
throw webidl.errors.exception({
@@ -5337,7 +5370,7 @@ var require_util2 = __commonJS({
var { getGlobalOrigin } = require_global();
var { collectAnHTTPQuotedString, parseMIMEType } = require_data_url();
var { performance: performance2 } = require("node:perf_hooks");
- var { ReadableStreamFrom, isValidHTTPToken, normalizedMethodRecordsBase } = require_util();
+ var { isValidHTTPToken, normalizedMethodRecordsBase } = require_util();
var assert = require("node:assert");
var { isUint8Array } = require("node:util/types");
var { webidl } = require_webidl();
@@ -5769,7 +5802,7 @@ var require_util2 = __commonJS({
};
}
__name(createIterator, "createIterator");
- function iteratorMixin(name, object, kInternalIterator, keyIndex = 0, valueIndex = 1) {
+ function iteratorMixin(name, object, kInternalIterator, keyIndex = 0, valueIndex = 1, brandCheck) {
const makeIterator = createIterator(name, kInternalIterator, keyIndex, valueIndex);
const properties = {
keys: {
@@ -5777,7 +5810,7 @@ var require_util2 = __commonJS({
enumerable: true,
configurable: true,
value: /* @__PURE__ */ __name(function keys() {
- webidl.brandCheck(this, object);
+ webidl.brandCheck(this, brandCheck);
return makeIterator(this, "key");
}, "keys")
},
@@ -5786,7 +5819,7 @@ var require_util2 = __commonJS({
enumerable: true,
configurable: true,
value: /* @__PURE__ */ __name(function values() {
- webidl.brandCheck(this, object);
+ webidl.brandCheck(this, brandCheck);
return makeIterator(this, "value");
}, "values")
},
@@ -5795,7 +5828,7 @@ var require_util2 = __commonJS({
enumerable: true,
configurable: true,
value: /* @__PURE__ */ __name(function entries() {
- webidl.brandCheck(this, object);
+ webidl.brandCheck(this, brandCheck);
return makeIterator(this, "key+value");
}, "entries")
},
@@ -5804,7 +5837,7 @@ var require_util2 = __commonJS({
enumerable: true,
configurable: true,
value: /* @__PURE__ */ __name(function forEach(callbackfn, thisArg = globalThis) {
- webidl.brandCheck(this, object);
+ webidl.brandCheck(this, brandCheck);
webidl.argumentLengthCheck(arguments, 1, `${name}.forEach`);
if (typeof callbackfn !== "function") {
throw new TypeError(
@@ -6110,7 +6143,6 @@ var require_util2 = __commonJS({
isAborted,
isCancelled,
isValidEncodedURL,
- ReadableStreamFrom,
tryUpgradeRequestToAPotentiallyTrustworthyURL,
clampAndCoarsenConnectionTimingInfo,
coarsenedSharedCurrentTime,
@@ -6248,7 +6280,10 @@ var require_formdata = __commonJS({
var nodeUtil = require("node:util");
var { runtimeFeatures } = require_runtime_features();
var random = runtimeFeatures.has("crypto") ? require("node:crypto").randomInt : (max) => Math.floor(Math.random() * max);
- var FormData = class _FormData {
+ var getFormDataState;
+ var setFormDataState;
+ var getFormDataBoundary;
+ var FormData = class {
static {
__name(this, "FormData");
}
@@ -6265,7 +6300,7 @@ var require_formdata = __commonJS({
}
}
append(name, value, filename = void 0) {
- webidl.brandCheck(this, _FormData);
+ webidl.brandCheck(this, webidl.is.FormData);
const prefix = "FormData.append";
webidl.argumentLengthCheck(arguments, 2, prefix);
name = webidl.converters.USVString(name);
@@ -6281,14 +6316,14 @@ var require_formdata = __commonJS({
this.#state.push(entry);
}
delete(name) {
- webidl.brandCheck(this, _FormData);
+ webidl.brandCheck(this, webidl.is.FormData);
const prefix = "FormData.delete";
webidl.argumentLengthCheck(arguments, 1, prefix);
name = webidl.converters.USVString(name);
this.#state = this.#state.filter((entry) => entry.name !== name);
}
get(name) {
- webidl.brandCheck(this, _FormData);
+ webidl.brandCheck(this, webidl.is.FormData);
const prefix = "FormData.get";
webidl.argumentLengthCheck(arguments, 1, prefix);
name = webidl.converters.USVString(name);
@@ -6299,21 +6334,21 @@ var require_formdata = __commonJS({
return this.#state[idx].value;
}
getAll(name) {
- webidl.brandCheck(this, _FormData);
+ webidl.brandCheck(this, webidl.is.FormData);
const prefix = "FormData.getAll";
webidl.argumentLengthCheck(arguments, 1, prefix);
name = webidl.converters.USVString(name);
return this.#state.filter((entry) => entry.name === name).map((entry) => entry.value);
}
has(name) {
- webidl.brandCheck(this, _FormData);
+ webidl.brandCheck(this, webidl.is.FormData);
const prefix = "FormData.has";
webidl.argumentLengthCheck(arguments, 1, prefix);
name = webidl.converters.USVString(name);
return this.#state.findIndex((entry) => entry.name === name) !== -1;
}
set(name, value, filename = void 0) {
- webidl.brandCheck(this, _FormData);
+ webidl.brandCheck(this, webidl.is.FormData);
const prefix = "FormData.set";
webidl.argumentLengthCheck(arguments, 2, prefix);
name = webidl.converters.USVString(name);
@@ -6355,34 +6390,20 @@ var require_formdata = __commonJS({
const output = nodeUtil.formatWithOptions(options, state);
return `FormData ${output.slice(output.indexOf("]") + 2)}`;
}
- /**
- * @param {FormData} formData
- */
- static getFormDataState(formData) {
- return formData.#state;
- }
- /**
- * @param {FormData} formData
- * @param {any[]} newState
- */
- static setFormDataState(formData, newState) {
- formData.#state = newState;
- }
- /**
- * @param {FormData} formData
- * @returns {string | null}
- */
- static getFormDataBoundary(formData) {
- const boundary = formData.#boundary;
- if (boundary != null) return boundary;
- return formData.#boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, "0")}`;
+ static {
+ getFormDataState = /* @__PURE__ */ __name((formData) => formData.#state, "getFormDataState");
+ setFormDataState = /* @__PURE__ */ __name((formData, newState) => {
+ formData.#state = newState;
+ }, "setFormDataState");
+ getFormDataBoundary = /* @__PURE__ */ __name((formData) => {
+ return formData.#boundary ??= `----formdata-undici-0${`${random(1e11)}`.padStart(11, "0")}`;
+ }, "getFormDataBoundary");
+ webidl.is.FormData = (arg) => {
+ return arg != null && typeof arg === "object" && #state in arg;
+ };
}
};
- var { getFormDataState, setFormDataState, getFormDataBoundary } = FormData;
- Reflect.deleteProperty(FormData, "getFormDataState");
- Reflect.deleteProperty(FormData, "setFormDataState");
- Reflect.deleteProperty(FormData, "getFormDataBoundary");
- iteratorMixin("FormData", FormData, getFormDataState, "name", "value");
+ iteratorMixin("FormData", FormData, getFormDataState, "name", "value", webidl.is.FormData);
Object.defineProperties(FormData.prototype, {
append: kEnumerableProperty,
delete: kEnumerableProperty,
@@ -6412,7 +6433,6 @@ var require_formdata = __commonJS({
return { name, value };
}
__name(makeEntry, "makeEntry");
- webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData);
module2.exports = { FormData, makeEntry, setFormDataState, getFormDataBoundary };
}
});
@@ -6765,7 +6785,6 @@ var require_body = __commonJS({
"use strict";
var util = require_util();
var {
- ReadableStreamFrom,
readableStreamClose,
fullyReadBody,
extractMimeType
@@ -6886,7 +6905,14 @@ Content-Type: ${value.type || "application/octet-stream"}\r
"Response body object should not be disturbed or locked"
);
}
- stream = webidl.is.ReadableStream(object) ? object : ReadableStreamFrom(object);
+ stream = webidl.is.ReadableStream(object) ? object : ReadableStream.from(object).pipeThrough(new TransformStream({
+ transform(chunk, controller2) {
+ const bytes = isUint8Array(chunk) ? chunk : Buffer.from(chunk);
+ if (bytes.byteLength) {
+ controller2.enqueue(bytes);
+ }
+ }
+ }));
}
if (typeof source === "string" || isUint8Array(source)) {
action = /* @__PURE__ */ __name(() => {
@@ -6934,7 +6960,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r
};
}
__name(cloneBody, "cloneBody");
- function bodyMixinMethods(instance, getInternalState) {
+ function bodyMixinMethods(brandCheck, getInternalState) {
const methods = {
blob() {
return consumeBody(this, (bytes) => {
@@ -6945,18 +6971,18 @@ Content-Type: ${value.type || "application/octet-stream"}\r
mimeType = serializeAMimeType(mimeType);
}
return new Blob([bytes], { type: mimeType });
- }, instance, getInternalState);
+ }, brandCheck, getInternalState);
},
arrayBuffer() {
return consumeBody(this, (bytes) => {
return new Uint8Array(bytes).buffer;
- }, instance, getInternalState);
+ }, brandCheck, getInternalState);
},
text() {
- return consumeBody(this, utf8DecodeBytes, instance, getInternalState);
+ return consumeBody(this, utf8DecodeBytes, brandCheck, getInternalState);
},
json() {
- return consumeBody(this, parseJSONFromBytes, instance, getInternalState);
+ return consumeBody(this, parseJSONFromBytes, brandCheck, getInternalState);
},
formData() {
return consumeBody(this, (value) => {
@@ -6982,12 +7008,12 @@ Content-Type: ${value.type || "application/octet-stream"}\r
throw new TypeError(
'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".'
);
- }, instance, getInternalState);
+ }, brandCheck, getInternalState);
},
bytes() {
return consumeBody(this, (bytes) => {
return new Uint8Array(bytes);
- }, instance, getInternalState);
+ }, brandCheck, getInternalState);
},
textStream() {
const this_ = getInternalState(this);
@@ -7016,13 +7042,13 @@ Content-Type: ${value.type || "application/octet-stream"}\r
return methods;
}
__name(bodyMixinMethods, "bodyMixinMethods");
- function mixinBody(prototype, getInternalState) {
- Object.assign(prototype.prototype, bodyMixinMethods(prototype, getInternalState));
+ function mixinBody(prototype, getInternalState, brandCheck) {
+ Object.assign(prototype.prototype, bodyMixinMethods(brandCheck, getInternalState));
}
__name(mixinBody, "mixinBody");
- function consumeBody(object, convertBytesToJSValue, instance, getInternalState) {
+ function consumeBody(object, convertBytesToJSValue, brandCheck, getInternalState) {
try {
- webidl.brandCheck(object, instance);
+ webidl.brandCheck(object, brandCheck);
} catch (e) {
return Promise.reject(e);
}
@@ -7139,7 +7165,13 @@ var require_client_h1 = __commonJS({
function lazyllhttp() {
const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : 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") {
@@ -7518,7 +7550,7 @@ var require_client_h1 = __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);
@@ -7543,8 +7575,9 @@ var require_client_h1 = __commonJS({
client[kQueue][client[kRunningIdx]++] = null;
client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade"));
try {
- request.onRequestUpgrade(statusCode, headers, socket);
+ request.onRequestUpgrade(statusCode, headers, socket, statusText);
} catch (err) {
+ util.errorRequest(client, request, err);
util.destroy(socket, err);
}
client[kResume]();
@@ -8411,6 +8444,7 @@ var require_client_h2 = __commonJS({
var util = require_util();
var {
RequestContentLengthMismatchError,
+ ResponseContentLengthMismatchError,
RequestAbortedError,
SocketError,
InformationalError,
@@ -8569,6 +8603,11 @@ var require_client_h2 = __commonJS({
return body == null || util.isBuffer(body) || util.isBlobLike(body);
}
__name(canReplayRequest, "canReplayRequest");
+ function hasResponseStarted(request) {
+ const state = request[kRequestStream]?.[kRequestStreamState];
+ return state?.responseReceived === true;
+ }
+ __name(hasResponseStarted, "hasResponseStarted");
function registerGoAwayRefusal(request) {
const attempts = (request[kGoAwayReplayAttempts] ?? 0) + 1;
request[kGoAwayReplayAttempts] = attempts;
@@ -8732,7 +8771,7 @@ var require_client_h2 = __commonJS({
const socket = client[kSocket];
const session = client[kHTTP2Session];
if (socket?.destroyed === false) {
- if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) {
+ if (session[kOpenStreams] === 0 && client[kSize] === 0) {
unrefH2Session(session);
} else {
refH2Session(session);
@@ -8902,8 +8941,9 @@ var require_client_h2 = __commonJS({
for (let i = pendingIdx; i < previousPendingIdx; i++) {
const request = client[kQueue][i];
if (request != null) {
+ const responseStarted = hasResponseStarted(request);
streamsToClose.push(detachRequestStreamForClose(request));
- if (canReplayRequest(request) && registerGoAwayRefusal(request)) {
+ if (!responseStarted && canReplayRequest(request) && registerGoAwayRefusal(request)) {
retriableRequests.push(request);
} else {
util.errorRequest(client, request, err);
@@ -9002,9 +9042,10 @@ var require_client_h2 = __commonJS({
__name(noop, "noop");
function closeStreamSession(stream) {
const session = stream[kHTTP2Session];
+ const client = session[kClient];
stream[kHTTP2Session] = null;
session[kOpenStreams] -= 1;
- if (session[kOpenStreams] === 0) {
+ if (session[kOpenStreams] === 0 && (client[kSize] === 0 || session[kReceivedGoAway])) {
unrefH2Session(session);
setHttp2IdleTimeout(session);
}
@@ -9130,8 +9171,13 @@ var require_client_h2 = __commonJS({
state.responseReceived = true;
const statusCode = headers[HTTP2_HEADER_STATUS];
delete headers[HTTP2_HEADER_STATUS];
- request.onRequestUpgrade(statusCode, headers, stream);
- if (request.aborted || request.completed) {
+ try {
+ request.onRequestUpgrade(statusCode, headers, stream);
+ } catch (err) {
+ state.abort(err);
+ return;
+ }
+ if (request.aborted) {
return;
}
removeUpgradeStreamListeners(stream);
@@ -9211,6 +9257,7 @@ var require_client_h2 = __commonJS({
headersTimeout,
bodyTimeout,
requestFinalized: false,
+ responseContentLength: null,
responseReceived: false,
bodySent: false,
pendingEnd: false,
@@ -9398,10 +9445,14 @@ var require_client_h2 = __commonJS({
if (state == null) {
return;
}
- const { request, maxResponseSize } = state;
+ const { request, maxResponseSize, responseContentLength } = state;
if (request.aborted || request.completed) {
return;
}
+ if (responseContentLength != null && state.bytesRead + chunk.length > responseContentLength) {
+ state.abort(new ResponseContentLengthMismatchError());
+ return;
+ }
if (maxResponseSize > -1 && state.bytesRead + chunk.length > maxResponseSize) {
state.abort(new ResponseExceededMaxSizeError());
return;
@@ -9439,10 +9490,14 @@ var require_client_h2 = __commonJS({
stream.removeListener("continue", writeBodyH2);
stream.end();
}
- const statusCode = headers[HTTP2_HEADER_STATUS];
+ const statusCode = Number(headers[HTTP2_HEADER_STATUS]);
delete headers[HTTP2_HEADER_STATUS];
request.onResponseStarted();
state.responseReceived = true;
+ if (request.method !== "HEAD" && statusCode !== 304) {
+ const contentLength = headers[HTTP2_HEADER_CONTENT_LENGTH];
+ state.responseContentLength = contentLength == null ? null : Number(contentLength);
+ }
if (state.headersTimeout || state.bodyTimeout) {
stream.setTimeout(state.bodyTimeout);
}
@@ -9450,7 +9505,7 @@ var require_client_h2 = __commonJS({
releaseRequestStream(stream);
return;
}
- if (request.onResponseStart(Number(statusCode), headers, stream.resume.bind(stream), "") === false) {
+ if (request.onResponseStart(statusCode, headers, stream.resume.bind(stream), "") === false) {
stream.pause();
}
stream.on("data", onData);
@@ -9466,6 +9521,10 @@ var require_client_h2 = __commonJS({
stream.off("end", onEnd);
if (state.responseReceived) {
if (!request.aborted && !request.completed) {
+ if (state.responseContentLength != null && state.bytesRead !== state.responseContentLength) {
+ state.abort(new ResponseContentLengthMismatchError());
+ return;
+ }
state.pendingEnd = true;
completeRequestStream.call(stream);
}
@@ -9496,6 +9555,9 @@ var require_client_h2 = __commonJS({
return;
}
stream.off("error", onError);
+ if (state.responseContentLength != null && state.bytesRead !== state.responseContentLength) {
+ err = new ResponseContentLengthMismatchError();
+ }
if (typeof stream.rstCode === "number" && stream.rstCode !== NGHTTP2_NO_ERROR) {
err.http2ErrorCode = stream.rstCode;
}
@@ -9939,7 +10001,7 @@ var require_client = __commonJS({
if (h2Options.settings?.initialWindowSize != null && (!Number.isInteger(h2Options.settings.initialWindowSize) || h2Options.settings.initialWindowSize < 1)) {
throw new InvalidArgumentError("h2Options.settings.initialWindowSize must be a positive integer, greater than 0");
}
- if (h2Options.maxConcurrentStreams != null && (!Number.isInteger(h2Options.connectionWindowSize) || h2Options.maxConcurrentStreams < 1)) {
+ if (h2Options.maxConcurrentStreams != null && (!Number.isInteger(h2Options.maxConcurrentStreams) || h2Options.maxConcurrentStreams < 1)) {
throw new InvalidArgumentError("h2Options.maxConcurrentStreams must be a positive integer, greater than 0");
}
if (h2Options.connectionWindowSize != null && (!Number.isInteger(h2Options.connectionWindowSize) || h2Options.connectionWindowSize < 1)) {
@@ -10303,6 +10365,10 @@ var require_client = __commonJS({
if (request === null) {
return;
}
+ if (request.aborted) {
+ client[kQueue].splice(client[kPendingIdx], 1);
+ continue;
+ }
if (client[kUrl].protocol === "https:" && client[kServerName] !== request.servername) {
if (client[kRunning] > 0) {
return;
@@ -10348,6 +10414,9 @@ var require_pool = __commonJS({
kClients,
kNeedDrain,
kAddClient,
+ kDrainQueue,
+ kOnClientBusy,
+ kOnClientDrain,
kGetDispatcher,
kHasDispatcher,
kRemoveClient
@@ -10357,15 +10426,30 @@ var require_pool = __commonJS({
InvalidArgumentError
} = require_errors();
var util = require_util();
- var { kUrl } = require_symbols();
+ var { kConnecting, kHTTPContext, kUrl } = require_symbols();
var buildConnector = require_connect();
var kOptions = /* @__PURE__ */ Symbol("options");
var kConnections = /* @__PURE__ */ Symbol("connections");
var kFactory = /* @__PURE__ */ Symbol("factory");
+ var kProtocol = /* @__PURE__ */ Symbol("protocol");
+ var kProtocolProbe = /* @__PURE__ */ Symbol("protocol probe");
function defaultFactory(origin, opts) {
return new Client(origin, opts);
}
__name(defaultFactory, "defaultFactory");
+ function shouldCreateProtocolProbe(pool, dispatcher) {
+ return dispatcher instanceof Client && pool[kProtocol] !== "h1" && (pool[kOptions].useH2c === true || pool[kUrl].protocol === "https:" && pool[kOptions].allowH2 !== false);
+ }
+ __name(shouldCreateProtocolProbe, "shouldCreateProtocolProbe");
+ function createClient(pool) {
+ const dispatcher = pool[kFactory](pool[kUrl], pool[kOptions]);
+ if (shouldCreateProtocolProbe(pool, dispatcher)) {
+ pool[kProtocolProbe] = dispatcher;
+ }
+ pool[kAddClient](dispatcher);
+ return dispatcher;
+ }
+ __name(createClient, "createClient");
var Pool = class extends PoolBase {
static {
__name(this, "Pool");
@@ -10411,22 +10495,58 @@ var require_pool = __commonJS({
this[kUrl] = util.parseOrigin(origin);
this[kOptions] = { ...util.deepClone(options), connect, allowH2, useH2c, clientTtl, socketPath };
this[kFactory] = factory;
+ this[kProtocol] = null;
+ this[kProtocolProbe] = null;
this.on("connect", (origin2, targets) => {
if (clientTtl != null && clientTtl > 0) {
for (const target of targets) {
Object.assign(target, { ttl: Date.now() });
}
}
+ const client = targets[targets.length - 1];
+ if (client instanceof Client) {
+ this[kProtocol] = client[kHTTPContext]?.version;
+ }
+ if (client === this[kProtocolProbe]) {
+ if (this[kProtocol] !== "h2") {
+ this[kProtocolProbe] = null;
+ this[kDrainQueue](origin2, targets.slice(1));
+ }
+ }
+ });
+ this.on("disconnect", (origin2, targets) => {
+ if (targets.includes(this[kProtocolProbe])) {
+ this[kProtocolProbe] = null;
+ this[kDrainQueue](origin2, targets.slice(1));
+ }
});
- this.on("connectionError", (origin2, targets, error) => {
+ this.on("connectionError", (origin2, targets) => {
+ let resumeQueued = false;
for (const target of targets) {
+ if (target === this[kProtocolProbe]) {
+ this[kProtocolProbe] = null;
+ resumeQueued = true;
+ }
const idx = this[kClients].indexOf(target);
if (idx !== -1) {
this[kClients].splice(idx, 1);
}
}
+ if (resumeQueued) {
+ this[kDrainQueue](origin2, targets.slice(1));
+ }
});
}
+ [kOnClientBusy](client) {
+ if (this[kProtocolProbe] === null && client[kConnecting] && shouldCreateProtocolProbe(this, client)) {
+ this[kProtocolProbe] = client;
+ }
+ }
+ [kOnClientDrain](client) {
+ if (client === this[kProtocolProbe]) {
+ this[kProtocolProbe] = null;
+ }
+ }
[kGetDispatcher]() {
const clientTtlOption = this[kOptions].clientTtl;
for (let i = 0; i < this[kClients].length; i++) {
@@ -10438,10 +10558,11 @@ var require_pool = __commonJS({
return client;
}
}
+ if (this[kProtocolProbe] !== null) {
+ return;
+ }
if (!this[kConnections] || this[kClients].length < this[kConnections]) {
- const dispatcher = this[kFactory](this[kUrl], this[kOptions]);
- this[kAddClient](dispatcher);
- return dispatcher;
+ return createClient(this);
}
}
[kHasDispatcher]() {
@@ -10455,9 +10576,11 @@ var require_pool = __commonJS({
return true;
}
}
+ if (this[kProtocolProbe] !== null) {
+ return false;
+ }
if (!this[kConnections] || this[kClients].length < this[kConnections]) {
- const dispatcher = this[kFactory](this[kUrl], this[kOptions]);
- this[kAddClient](dispatcher);
+ createClient(this);
return true;
}
return false;
@@ -11841,7 +11964,19 @@ var require_proxy_agent = __commonJS({
if (headers && typeof headers === "object" && hasSafeIterator(headers)) {
const headersPair = {};
for (const [key, value] of headers) {
- headersPair[key] = value;
+ if (!Object.hasOwn(headersPair, key)) {
+ headersPair[key] = value;
+ continue;
+ }
+ const previous = headersPair[key];
+ const values = [];
+ if (previous !== void 0) {
+ values.push(...Array.isArray(previous) ? previous : [previous]);
+ }
+ if (value !== void 0) {
+ values.push(...Array.isArray(value) ? value : [value]);
+ }
+ headersPair[key] = values.length > 1 ? values : values[0];
}
return headersPair;
}
@@ -11947,15 +12082,18 @@ var require_env_http_proxy_agent = __commonJS({
if (this.#noProxyEntries.length === 0) {
return true;
}
- if (this.#noProxyValue === "*") {
- return false;
- }
for (let i = 0; i < this.#noProxyEntries.length; i++) {
const entry = this.#noProxyEntries[i];
+ if (entry.hostname === "*") {
+ if (entry.port && entry.port !== port) {
+ continue;
+ }
+ return false;
+ }
if (entry.port && entry.port !== port) {
continue;
}
- if (hostname === entry.hostname) {
+ if (!entry.wildcard && hostname === entry.hostname) {
return false;
}
if (hostname.slice(-(entry.hostname.length + 1)) === `.${entry.hostname}`) {
@@ -11985,10 +12123,12 @@ var require_env_http_proxy_agent = __commonJS({
hostname = parsed ? parsed[1] : unbracketed;
port = parsed ? Number.parseInt(parsed[2], 10) : 0;
}
+ const wildcard = entry.charCodeAt(0) === 42;
noProxyEntries.push({
// strip leading dot or asterisk with dot, and any trailing dot
hostname: hostname.replace(/^\*?\./, "").replace(/^(.+)\.$/, "$1").toLowerCase(),
- port
+ port,
+ wildcard
});
}
this.#noProxyValue = noProxyValue;
@@ -12282,7 +12422,11 @@ var require_headers = __commonJS({
}
}
};
- var Headers = class _Headers {
+ var getHeadersGuard;
+ var setHeadersGuard;
+ var getHeadersList;
+ var setHeadersList;
+ var Headers = class {
static {
__name(this, "Headers");
}
@@ -12309,7 +12453,7 @@ var require_headers = __commonJS({
}
// https://fetch.spec.whatwg.org/#dom-headers-append
append(name, value) {
- webidl.brandCheck(this, _Headers);
+ webidl.brandCheck(this, webidl.is.Headers);
webidl.argumentLengthCheck(arguments, 2, "Headers.append");
const prefix = "Headers.append";
name = webidl.converters.ByteString(name, prefix, "name");
@@ -12318,7 +12462,7 @@ var require_headers = __commonJS({
}
// https://fetch.spec.whatwg.org/#dom-headers-delete
delete(name) {
- webidl.brandCheck(this, _Headers);
+ webidl.brandCheck(this, webidl.is.Headers);
webidl.argumentLengthCheck(arguments, 1, "Headers.delete");
const prefix = "Headers.delete";
name = webidl.converters.ByteString(name, prefix, "name");
@@ -12339,7 +12483,7 @@ var require_headers = __commonJS({
}
// https://fetch.spec.whatwg.org/#dom-headers-get
get(name) {
- webidl.brandCheck(this, _Headers);
+ webidl.brandCheck(this, webidl.is.Headers);
webidl.argumentLengthCheck(arguments, 1, "Headers.get");
const prefix = "Headers.get";
name = webidl.converters.ByteString(name, prefix, "name");
@@ -12354,7 +12498,7 @@ var require_headers = __commonJS({
}
// https://fetch.spec.whatwg.org/#dom-headers-has
has(name) {
- webidl.brandCheck(this, _Headers);
+ webidl.brandCheck(this, webidl.is.Headers);
webidl.argumentLengthCheck(arguments, 1, "Headers.has");
const prefix = "Headers.has";
name = webidl.converters.ByteString(name, prefix, "name");
@@ -12369,7 +12513,7 @@ var require_headers = __commonJS({
}
// https://fetch.spec.whatwg.org/#dom-headers-set
set(name, value) {
- webidl.brandCheck(this, _Headers);
+ webidl.brandCheck(this, webidl.is.Headers);
webidl.argumentLengthCheck(arguments, 2, "Headers.set");
const prefix = "Headers.set";
name = webidl.converters.ByteString(name, prefix, "name");
@@ -12395,7 +12539,7 @@ var require_headers = __commonJS({
}
// https://fetch.spec.whatwg.org/#dom-headers-getsetcookie
getSetCookie() {
- webidl.brandCheck(this, _Headers);
+ webidl.brandCheck(this, webidl.is.Headers);
const list = this.#headersList.cookies;
if (list) {
return [...list];
@@ -12406,32 +12550,21 @@ var require_headers = __commonJS({
options.depth ??= depth;
return `Headers ${util.formatWithOptions(options, this.#headersList.entries)}`;
}
- static getHeadersGuard(o) {
- return o.#guard;
- }
- static setHeadersGuard(o, guard) {
- o.#guard = guard;
- }
- /**
- * @param {Headers} o
- */
- static getHeadersList(o) {
- return o.#headersList;
- }
- /**
- * @param {Headers} target
- * @param {HeadersList} list
- */
- static setHeadersList(target, list) {
- target.#headersList = list;
+ static {
+ getHeadersGuard = /* @__PURE__ */ __name((headers) => headers.#guard, "getHeadersGuard");
+ setHeadersGuard = /* @__PURE__ */ __name((headers, guard) => {
+ headers.#guard = guard;
+ }, "setHeadersGuard");
+ getHeadersList = /* @__PURE__ */ __name((headers) => headers.#headersList, "getHeadersList");
+ setHeadersList = /* @__PURE__ */ __name((target, list) => {
+ target.#headersList = list;
+ }, "setHeadersList");
+ webidl.is.Headers = (arg) => {
+ return arg != null && typeof arg === "object" && #guard in arg;
+ };
}
};
- var { getHeadersGuard, setHeadersGuard, getHeadersList, setHeadersList } = Headers;
- Reflect.deleteProperty(Headers, "getHeadersGuard");
- Reflect.deleteProperty(Headers, "setHeadersGuard");
- Reflect.deleteProperty(Headers, "getHeadersList");
- Reflect.deleteProperty(Headers, "setHeadersList");
- iteratorMixin("Headers", Headers, headersListSortAndCombine, 0, 1);
+ iteratorMixin("Headers", Headers, headersListSortAndCombine, 0, 1, webidl.is.Headers);
Object.defineProperties(Headers.prototype, {
append: kEnumerableProperty,
delete: kEnumerableProperty,
@@ -12507,7 +12640,11 @@ var require_response = __commonJS({
var assert = require("node:assert");
var { isomorphicEncode, serializeJavascriptValueToJSONString } = require_infra();
var textEncoder = new TextEncoder("utf-8");
- var Response = class _Response {
+ var getResponseHeaders;
+ var setResponseHeaders;
+ var getResponseState;
+ var setResponseState;
+ var Response = class {
static {
__name(this, "Response");
}
@@ -12574,12 +12711,12 @@ var require_response = __commonJS({
}
// Returns response?s type, e.g., "cors".
get type() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return this.#state.type;
}
// Returns response?s URL, if it has one; otherwise the empty string.
get url() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
const urlList = this.#state.urlList;
const url = urlList[urlList.length - 1] ?? null;
if (url === null) {
@@ -12589,40 +12726,40 @@ var require_response = __commonJS({
}
// Returns whether response was obtained through a redirect.
get redirected() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return this.#state.urlList.length > 1;
}
// Returns response?s status.
get status() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return this.#state.status;
}
// Returns whether response?s status is an ok status.
get ok() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return this.#state.status >= 200 && this.#state.status <= 299;
}
// Returns response?s status message.
get statusText() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return this.#state.statusText;
}
// Returns response?s headers as Headers.
get headers() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return this.#headers;
}
get body() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return this.#state.body ? this.#state.body.stream : null;
}
get bodyUsed() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
return !!this.#state.body && util.isDisturbed(this.#state.body.stream);
}
// Returns a clone of response.
clone() {
- webidl.brandCheck(this, _Response);
+ webidl.brandCheck(this, webidl.is.Response);
if (bodyUnusable(this.#state)) {
throw webidl.errors.exception({
header: "Response.clone",
@@ -12653,39 +12790,25 @@ var require_response = __commonJS({
};
return `Response ${nodeUtil.formatWithOptions(options, properties)}`;
}
- /**
- * @param {Response} response
- */
- static getResponseHeaders(response) {
- return response.#headers;
- }
- /**
- * @param {Response} response
- * @param {Headers} newHeaders
- */
- static setResponseHeaders(response, newHeaders) {
- response.#headers = newHeaders;
- }
- /**
- * @param {Response} response
- */
- static getResponseState(response) {
- return response.#state;
- }
- /**
- * @param {Response} response
- * @param {any} newState
- */
- static setResponseState(response, newState) {
- response.#state = newState;
+ static {
+ getResponseHeaders = /* @__PURE__ */ __name((response) => {
+ return response.#headers;
+ }, "getResponseHeaders");
+ setResponseHeaders = /* @__PURE__ */ __name((response, newHeaders) => {
+ response.#headers = newHeaders;
+ }, "setResponseHeaders");
+ getResponseState = /* @__PURE__ */ __name((response) => {
+ return response.#state;
+ }, "getResponseState");
+ setResponseState = /* @__PURE__ */ __name((response, newState) => {
+ response.#state = newState;
+ }, "setResponseState");
+ webidl.is.Response = (arg) => {
+ return arg != null && typeof arg === "object" && #state in arg;
+ };
}
};
- var { getResponseHeaders, setResponseHeaders, getResponseState, setResponseState } = Response;
- Reflect.deleteProperty(Response, "getResponseHeaders");
- Reflect.deleteProperty(Response, "setResponseHeaders");
- Reflect.deleteProperty(Response, "getResponseState");
- Reflect.deleteProperty(Response, "setResponseState");
- mixinBody(Response, getResponseState);
+ mixinBody(Response, getResponseState, webidl.is.Response);
Object.defineProperties(Response.prototype, {
type: kEnumerableProperty,
url: kEnumerableProperty,
@@ -12898,7 +13021,6 @@ var require_response = __commonJS({
converter: webidl.converters.HeadersInit
}
]);
- webidl.is.Response = webidl.util.MakeTypeAssertion(Response);
module2.exports = {
isNetworkError,
makeNetworkError,
@@ -12980,7 +13102,14 @@ var require_request2 = __commonJS({
}
__name(buildAbort, "buildAbort");
var patchMethodWarning = false;
- var Request = class _Request {
+ var setRequestSignal;
+ var getRequestDispatcher;
+ var setRequestDispatcher;
+ var setRequestHeaders;
+ var getRequestState;
+ var setRequestState;
+ var removeRequestAbortListener;
+ var Request = class {
static {
__name(this, "Request");
}
@@ -13273,25 +13402,25 @@ var require_request2 = __commonJS({
}
// Returns request?s HTTP method, which is "GET" by default.
get method() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.method;
}
// Returns the URL of request as a string.
get url() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return URLSerializer(this.#state.url);
}
// Returns a Headers object consisting of the headers associated with request.
// Note that headers added in the network layer by the user agent will not
// be accounted for in this object, e.g., the "Host" header.
get headers() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#headers;
}
// Returns the kind of resource requested by request, e.g., "document"
// or "script".
get destination() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.destination;
}
// Returns the referrer of request. Its value can be a same-origin URL if
@@ -13300,7 +13429,7 @@ var require_request2 = __commonJS({
// during fetching to determine the value of the `Referer` header of the
// request being made.
get referrer() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
if (this.#state.referrer === "no-referrer") {
return "";
}
@@ -13313,28 +13442,28 @@ var require_request2 = __commonJS({
// This is used during fetching to compute the value of the request?s
// referrer.
get referrerPolicy() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.referrerPolicy;
}
// Returns the mode associated with request, which is a string indicating
// whether the request will use CORS, or will be restricted to same-origin
// URLs.
get mode() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.mode;
}
// Returns the credentials mode associated with request,
// which is a string indicating whether credentials will be sent with the
// request always, never, or only when sent to a same-origin URL.
get credentials() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.credentials;
}
// Returns the cache mode associated with request,
// which is a string indicating how the request will
// interact with the browser?s cache when fetching.
get cache() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.cache;
}
// Returns the redirect mode associated with request,
@@ -13342,56 +13471,56 @@ var require_request2 = __commonJS({
// request will be handled during fetching. A request
// will follow redirects by default.
get redirect() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.redirect;
}
// Returns request?s subresource integrity metadata, which is a
// cryptographic hash of the resource being fetched. Its value
// consists of multiple hashes separated by whitespace. [SRI]
get integrity() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.integrity;
}
// Returns a boolean indicating whether or not request can outlive the
// global in which it was created.
get keepalive() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.keepalive;
}
// Returns a boolean indicating whether or not request is for a reload
// navigation.
get isReloadNavigation() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.reloadNavigation;
}
// Returns a boolean indicating whether or not request is for a history
// navigation (a.k.a. back-forward navigation).
get isHistoryNavigation() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.historyNavigation;
}
// Returns the signal associated with request, which is an AbortSignal
// object indicating whether or not request has been aborted, and its
// abort event handler.
get signal() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#signal;
}
get body() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return this.#state.body ? this.#state.body.stream : null;
}
get bodyUsed() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return !!this.#state.body && util.isDisturbed(this.#state.body.stream);
}
get duplex() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
return "half";
}
// Returns a clone of request.
clone() {
- webidl.brandCheck(this, _Request);
+ webidl.brandCheck(this, webidl.is.Request);
if (bodyUnusable(this.#state)) {
throw new TypeError("unusable");
}
@@ -13438,65 +13567,34 @@ var require_request2 = __commonJS({
};
return `Request ${nodeUtil.formatWithOptions(options, properties)}`;
}
- /**
- * @param {Request} request
- * @param {AbortSignal} newSignal
- */
- static setRequestSignal(request, newSignal) {
- request.#signal = newSignal;
- return request;
- }
- /**
- * @param {Request} request
- */
- static getRequestDispatcher(request) {
- return request.#dispatcher;
- }
- /**
- * @param {Request} request
- * @param {import('../../dispatcher/dispatcher')} newDispatcher
- */
- static setRequestDispatcher(request, newDispatcher) {
- request.#dispatcher = newDispatcher;
- }
- /**
- * @param {Request} request
- * @param {Headers} newHeaders
- */
- static setRequestHeaders(request, newHeaders) {
- request.#headers = newHeaders;
- }
- /**
- * @param {Request} request
- */
- static getRequestState(request) {
- return request.#state;
- }
- /**
- * @param {Request} request
- * @param {any} newState
- */
- static setRequestState(request, newState) {
- request.#state = newState;
- }
- /**
- * Removes the `abort` listener that makes this request's signal follow the
- * signal passed to its constructor, if any. Idempotent.
- * @param {Request} request
- */
- static removeRequestAbortListener(request) {
- request.#abortCleanup?.();
+ static {
+ setRequestSignal = /* @__PURE__ */ __name((request, newSignal) => {
+ request.#signal = newSignal;
+ }, "setRequestSignal");
+ getRequestDispatcher = /* @__PURE__ */ __name((request) => {
+ return request.#dispatcher;
+ }, "getRequestDispatcher");
+ setRequestDispatcher = /* @__PURE__ */ __name((request, newDispatcher) => {
+ request.#dispatcher = newDispatcher;
+ }, "setRequestDispatcher");
+ setRequestHeaders = /* @__PURE__ */ __name((request, newHeaders) => {
+ request.#headers = newHeaders;
+ }, "setRequestHeaders");
+ getRequestState = /* @__PURE__ */ __name((request) => {
+ return request.#state;
+ }, "getRequestState");
+ setRequestState = /* @__PURE__ */ __name((request, newState) => {
+ request.#state = newState;
+ }, "setRequestState");
+ removeRequestAbortListener = /* @__PURE__ */ __name((request) => {
+ request.#abortCleanup?.();
+ }, "removeRequestAbortListener");
+ webidl.is.Request = (arg) => {
+ return arg != null && typeof arg === "object" && #state in arg;
+ };
}
};
- var { setRequestSignal, getRequestDispatcher, setRequestDispatcher, setRequestHeaders, getRequestState, setRequestState, removeRequestAbortListener } = Request;
- Reflect.deleteProperty(Request, "setRequestSignal");
- Reflect.deleteProperty(Request, "getRequestDispatcher");
- Reflect.deleteProperty(Request, "setRequestDispatcher");
- Reflect.deleteProperty(Request, "setRequestHeaders");
- Reflect.deleteProperty(Request, "getRequestState");
- Reflect.deleteProperty(Request, "setRequestState");
- Reflect.deleteProperty(Request, "removeRequestAbortListener");
- mixinBody(Request, getRequestState);
+ mixinBody(Request, getRequestState, webidl.is.Request);
function makeRequest(init) {
return {
method: init.method ?? "GET",
@@ -13589,7 +13687,6 @@ var require_request2 = __commonJS({
configurable: true
}
});
- webidl.is.Request = webidl.util.MakeTypeAssertion(Request);
webidl.converters.RequestInfo = function(V) {
if (typeof V === "string") {
return webidl.converters.USVString(V);
@@ -14271,7 +14368,7 @@ var require_fetch = __commonJS({
}
__name(mainFetch, "mainFetch");
function schemeFetch(fetchParams) {
- if (isCancelled(fetchParams) && fetchParams.request.redirectCount === 0) {
+ if (isCancelled(fetchParams)) {
return Promise.resolve(makeAppropriateNetworkError(fetchParams));
}
const { request } = fetchParams;
@@ -14371,11 +14468,11 @@ var require_fetch = __commonJS({
__name(finalizeResponse, "finalizeResponse");
function fetchFinale(fetchParams, response) {
let timingInfo = fetchParams.timingInfo;
+ if (fetchParams.request.destination === "document") {
+ fetchParams.controller.fullTimingInfo = timingInfo;
+ }
const processResponseEndOfBody = /* @__PURE__ */ __name(() => {
const unsafeEndTime = Date.now();
- if (fetchParams.request.destination === "document") {
- fetchParams.controller.fullTimingInfo = timingInfo;
- }
fetchParams.controller.reportTimingSteps = () => {
if (!urlIsHttpHttpsScheme(fetchParams.request.url)) {
return;
@@ -14424,6 +14521,15 @@ var require_fetch = __commonJS({
processResponseEndOfBody();
});
}
+ if (fetchParams.processResponseConsumeBody != null) {
+ const processBody = /* @__PURE__ */ __name((nullOrBytes) => fetchParams.processResponseConsumeBody(response, nullOrBytes), "processBody");
+ const processBodyError = /* @__PURE__ */ __name(() => fetchParams.processResponseConsumeBody(response, "failure"), "processBodyError");
+ if (internalResponse.body == null) {
+ queueMicrotask(() => processBody(null));
+ } else {
+ fullyReadBody(internalResponse.body, processBody, processBodyError);
+ }
+ }
}
__name(fetchFinale, "fetchFinale");
async function httpFetch(fetchParams) {
@@ -14455,7 +14561,7 @@ var require_fetch = __commonJS({
}
if (redirectStatusSet.has(actualResponse.status)) {
if (request.redirect !== "manual") {
- fetchParams.controller.connection.destroy(void 0, false);
+ fetchParams.controller.connection.destroy();
}
if (request.redirect === "error") {
response = makeNetworkError("unexpected redirect");
@@ -14689,12 +14795,10 @@ var require_fetch = __commonJS({
fetchParams.controller.connection = {
abort: null,
destroyed: false,
- destroy(err, abort = true) {
+ destroy(err) {
if (!this.destroyed) {
this.destroyed = true;
- if (abort) {
- this.abort?.(err ?? new DOMException("The operation was aborted.", "AbortError"));
- }
+ this.abort?.(err ?? new DOMException("The operation was aborted.", "AbortError"));
}
}
};
@@ -14965,7 +15069,7 @@ var require_fetch = __commonJS({
fetchParams.controller.ended = true;
this.body?.push(null);
},
- onResponseError(_controller, error) {
+ onResponseError(controller, error) {
if (this.abort) {
fetchParams.controller.off("terminated", this.abort);
}
@@ -14974,7 +15078,9 @@ var require_fetch = __commonJS({
return;
}
this.body?.destroy(error);
- fetchParams.controller.terminate(error);
+ if (!controller?.aborted) {
+ fetchParams.controller.terminate(error);
+ }
reject(error);
},
onRequestUpgrade(controller, status, headers, socket) {
@@ -15019,6 +15125,7 @@ var require_events = __commonJS({
var { webidl } = require_webidl();
var { kEnumerableProperty } = require_util();
var { kConstruct } = require_symbols();
+ var createFastMessageEvent2;
var MessageEvent2 = class _MessageEvent extends Event {
static {
__name(this, "MessageEvent");
@@ -15039,30 +15146,30 @@ var require_events = __commonJS({
webidl.util.markAsUncloneable(this);
}
get data() {
- webidl.brandCheck(this, _MessageEvent);
+ webidl.brandCheck(this, webidl.is.MessageEvent);
return this.#eventInit.data;
}
get origin() {
- webidl.brandCheck(this, _MessageEvent);
+ webidl.brandCheck(this, webidl.is.MessageEvent);
return this.#eventInit.origin;
}
get lastEventId() {
- webidl.brandCheck(this, _MessageEvent);
+ webidl.brandCheck(this, webidl.is.MessageEvent);
return this.#eventInit.lastEventId;
}
get source() {
- webidl.brandCheck(this, _MessageEvent);
+ webidl.brandCheck(this, webidl.is.MessageEvent);
return this.#eventInit.source;
}
get ports() {
- webidl.brandCheck(this, _MessageEvent);
+ webidl.brandCheck(this, webidl.is.MessageEvent);
if (!Object.isFrozen(this.#eventInit.ports)) {
Object.freeze(this.#eventInit.ports);
}
return this.#eventInit.ports;
}
initMessageEvent(type, bubbles = false, cancelable = false, data = null, origin = "", lastEventId = "", source = null, ports = []) {
- webidl.brandCheck(this, _MessageEvent);
+ webidl.brandCheck(this, webidl.is.MessageEvent);
webidl.argumentLengthCheck(arguments, 1, "MessageEvent.initMessageEvent");
return new _MessageEvent(type, {
bubbles,
@@ -15074,20 +15181,23 @@ var require_events = __commonJS({
ports
});
}
- static createFastMessageEvent(type, init) {
- const messageEvent = new _MessageEvent(kConstruct, type, init);
- messageEvent.#eventInit = init;
- messageEvent.#eventInit.data ??= null;
- messageEvent.#eventInit.origin ??= "";
- messageEvent.#eventInit.lastEventId ??= "";
- messageEvent.#eventInit.source ??= null;
- messageEvent.#eventInit.ports ??= [];
- return messageEvent;
+ static {
+ createFastMessageEvent2 = /* @__PURE__ */ __name((type, init) => {
+ const messageEvent = new _MessageEvent(kConstruct, type, init);
+ messageEvent.#eventInit = init;
+ messageEvent.#eventInit.data ??= null;
+ messageEvent.#eventInit.origin ??= "";
+ messageEvent.#eventInit.lastEventId ??= "";
+ messageEvent.#eventInit.source ??= null;
+ messageEvent.#eventInit.ports ??= [];
+ return messageEvent;
+ }, "createFastMessageEvent");
+ webidl.is.MessageEvent = (arg) => {
+ return arg != null && typeof arg === "object" && #eventInit in arg;
+ };
}
};
- var { createFastMessageEvent: createFastMessageEvent2 } = MessageEvent2;
- delete MessageEvent2.createFastMessageEvent;
- var CloseEvent2 = class _CloseEvent extends Event {
+ var CloseEvent2 = class extends Event {
static {
__name(this, "CloseEvent");
}
@@ -15102,19 +15212,24 @@ var require_events = __commonJS({
webidl.util.markAsUncloneable(this);
}
get wasClean() {
- webidl.brandCheck(this, _CloseEvent);
+ webidl.brandCheck(this, webidl.is.CloseEvent);
return this.#eventInit.wasClean;
}
get code() {
- webidl.brandCheck(this, _CloseEvent);
+ webidl.brandCheck(this, webidl.is.CloseEvent);
return this.#eventInit.code;
}
get reason() {
- webidl.brandCheck(this, _CloseEvent);
+ webidl.brandCheck(this, webidl.is.CloseEvent);
return this.#eventInit.reason;
}
+ static {
+ webidl.is.CloseEvent = (arg) => {
+ return arg != null && typeof arg === "object" && #eventInit in arg;
+ };
+ }
};
- var ErrorEvent2 = class _ErrorEvent extends Event {
+ var ErrorEvent2 = class extends Event {
static {
__name(this, "ErrorEvent");
}
@@ -15129,25 +15244,30 @@ var require_events = __commonJS({
this.#eventInit = eventInitDict;
}
get message() {
- webidl.brandCheck(this, _ErrorEvent);
+ webidl.brandCheck(this, webidl.is.ErrorEvent);
return this.#eventInit.message;
}
get filename() {
- webidl.brandCheck(this, _ErrorEvent);
+ webidl.brandCheck(this, webidl.is.ErrorEvent);
return this.#eventInit.filename;
}
get lineno() {
- webidl.brandCheck(this, _ErrorEvent);
+ webidl.brandCheck(this, webidl.is.ErrorEvent);
return this.#eventInit.lineno;
}
get colno() {
- webidl.brandCheck(this, _ErrorEvent);
+ webidl.brandCheck(this, webidl.is.ErrorEvent);
return this.#eventInit.colno;
}
get error() {
- webidl.brandCheck(this, _ErrorEvent);
+ webidl.brandCheck(this, webidl.is.ErrorEvent);
return this.#eventInit.error;
}
+ static {
+ webidl.is.ErrorEvent = (arg) => {
+ return arg != null && typeof arg === "object" && #eventInit in arg;
+ };
+ }
};
Object.defineProperties(MessageEvent2.prototype, {
[Symbol.toStringTag]: {
@@ -15691,11 +15811,11 @@ var require_connection = __commonJS({
processResponse(response) {
if (response.type === "error" || response.status !== 101) {
if (response.socket?.session == null) {
- failWebsocketConnection(handler, 1002, "Received network error or non-101 status code.", response.error);
+ failHandshake(handler, response, 1002, "Received network error or non-101 status code.", response.error);
return;
}
if (response.status !== 200) {
- failWebsocketConnection(handler, 1002, "Received network error or non-200 status code.", response.error);
+ failHandshake(handler, response, 1002, "Received network error or non-200 status code.", response.error);
return;
}
}
@@ -15704,29 +15824,31 @@ var require_connection = __commonJS({
warningEmitted = true;
}
if (protocols.length !== 0 && !response.headersList.get("Sec-WebSocket-Protocol")) {
- failWebsocketConnection(handler, 1002, "Server did not respond with sent protocols.");
+ failHandshake(handler, response, 1002, "Server did not respond with sent protocols.");
return;
}
if (response.socket.session == null && response.headersList.get("Upgrade")?.toLowerCase() !== "websocket") {
- failWebsocketConnection(handler, 1002, 'Server did not set Upgrade header to "websocket".');
+ failHandshake(handler, response, 1002, 'Server did not set Upgrade header to "websocket".');
return;
}
if (response.socket.session == null && response.headersList.get("Connection")?.toLowerCase() !== "upgrade") {
- failWebsocketConnection(handler, 1002, 'Server did not set Connection header to "upgrade".');
+ failHandshake(handler, 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(handler, 1002, "Incorrect hash received in Sec-WebSocket-Accept header.");
- return;
+ if (response.socket.session == null) {
+ const secWSAccept = response.headersList.get("Sec-WebSocket-Accept");
+ const digest = crypto.hash("sha1", keyValue + uid, "base64");
+ if (secWSAccept !== digest) {
+ failHandshake(handler, response, 1002, "Incorrect hash received in Sec-WebSocket-Accept header.");
+ return;
+ }
}
const secExtension = response.headersList.get("Sec-WebSocket-Extensions");
let extensions;
if (secExtension !== null) {
extensions = parseExtensions(secExtension);
if (!extensions.has("permessage-deflate")) {
- failWebsocketConnection(handler, 1002, "Sec-WebSocket-Extensions header does not match.");
+ failHandshake(handler, response, 1002, "Sec-WebSocket-Extensions header does not match.");
return;
}
}
@@ -15734,10 +15856,13 @@ var require_connection = __commonJS({
if (secProtocol !== null) {
const requestProtocols = getDecodeSplit("sec-websocket-protocol", request.headersList);
if (requestProtocols === null || !requestProtocols.includes(secProtocol)) {
- failWebsocketConnection(handler, 1002, "Protocol was not set in the opening handshake.");
+ failHandshake(handler, response, 1002, "Protocol was not set in the opening handshake.");
return;
}
}
+ if (response.socket.session != null) {
+ response.socket.allowHalfOpen = false;
+ }
response.socket.on("data", handler.onSocketData);
response.socket.on("close", handler.onSocketClose);
response.socket.on("error", handler.onSocketError);
@@ -15782,6 +15907,13 @@ var require_connection = __commonJS({
}
}
__name(closeWebSocketConnection, "closeWebSocketConnection");
+ function failHandshake(handler, response, code, reason, cause) {
+ if (response.socket?.session != null && !response.socket.destroyed) {
+ response.socket.destroy();
+ }
+ failWebsocketConnection(handler, code, reason, cause);
+ }
+ __name(failHandshake, "failHandshake");
function failWebsocketConnection(handler, code, reason, cause) {
if (isEstablished(handler.readyState)) {
closeWebSocketConnection(handler, code, reason, false);
@@ -16163,6 +16295,7 @@ var require_receiver = __commonJS({
}
consumeFragments() {
const fragments = this.#fragments;
+ this.#info.compressed = false;
if (fragments.length === 1) {
this.#fragmentsBytes = 0;
return fragments.shift();
@@ -16371,6 +16504,7 @@ var require_websocket = __commonJS({
var { channels } = require_diagnostics();
var kRef = /* @__PURE__ */ Symbol.for("nodejs.ref");
var kUnref = /* @__PURE__ */ Symbol.for("nodejs.unref");
+ var ping;
function getSocketAddress(socket) {
if (typeof socket?.address === "function") {
return socket.address();
@@ -16477,13 +16611,13 @@ var require_websocket = __commonJS({
this.#handler.readyState = _WebSocket.CONNECTING;
this.#binaryType = "blob";
}
+ // TODO: remove this
[kRef]() {
- webidl.brandCheck(this, _WebSocket);
this.#refed = true;
this.#handler.socket?.ref?.();
}
+ // TODO: remove this
[kUnref]() {
- webidl.brandCheck(this, _WebSocket);
this.#refed = false;
this.#handler.socket?.unref?.();
}
@@ -16493,7 +16627,7 @@ var require_websocket = __commonJS({
* @param {string|undefined} reason
*/
close(code = void 0, reason = void 0) {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
const prefix = "WebSocket.close";
if (code !== void 0) {
code = webidl.converters["unsigned short"](code, prefix, "code", webidl.attributes.Clamp);
@@ -16510,7 +16644,7 @@ var require_websocket = __commonJS({
* @param {NodeJS.TypedArray|ArrayBuffer|Blob|string} data
*/
send(data) {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
const prefix = "WebSocket.send";
webidl.argumentLengthCheck(arguments, 1, prefix);
data = webidl.converters.WebSocketSendData(data, prefix, "data");
@@ -16544,31 +16678,31 @@ var require_websocket = __commonJS({
}
}
get readyState() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#handler.readyState;
}
get bufferedAmount() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#bufferedAmount;
}
get url() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return URLSerializer(this.#url);
}
get extensions() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#extensions;
}
get protocol() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#protocol;
}
get onopen() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#events.open;
}
set onopen(fn) {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
if (this.#events.open) {
this.removeEventListener("open", this.#events.open);
}
@@ -16581,11 +16715,11 @@ var require_websocket = __commonJS({
}
}
get onerror() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#events.error;
}
set onerror(fn) {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
if (this.#events.error) {
this.removeEventListener("error", this.#events.error);
}
@@ -16598,11 +16732,11 @@ var require_websocket = __commonJS({
}
}
get onclose() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#events.close;
}
set onclose(fn) {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
if (this.#events.close) {
this.removeEventListener("close", this.#events.close);
}
@@ -16615,11 +16749,11 @@ var require_websocket = __commonJS({
}
}
get onmessage() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#events.message;
}
set onmessage(fn) {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
if (this.#events.message) {
this.removeEventListener("message", this.#events.message);
}
@@ -16632,11 +16766,11 @@ var require_websocket = __commonJS({
}
}
get binaryType() {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
return this.#binaryType;
}
set binaryType(type) {
- webidl.brandCheck(this, _WebSocket);
+ webidl.brandCheck(this, webidl.is.WebSocket);
if (type !== "blob" && type !== "arraybuffer") {
this.#binaryType = "blob";
} else {
@@ -16746,27 +16880,26 @@ var require_websocket = __commonJS({
});
}
}
- /**
- * @param {WebSocket} ws
- * @param {Buffer|undefined} buffer
- */
- static ping(ws, buffer) {
- if (Buffer.isBuffer(buffer)) {
- if (buffer.length > 125) {
- throw new TypeError("A PING frame cannot have a body larger than 125 bytes.");
+ static {
+ ping = /* @__PURE__ */ __name((ws, buffer) => {
+ if (Buffer.isBuffer(buffer)) {
+ if (buffer.length > 125) {
+ throw new TypeError("A PING frame cannot have a body larger than 125 bytes.");
+ }
+ } else if (buffer !== void 0) {
+ throw new TypeError("Expected buffer payload");
}
- } else if (buffer !== void 0) {
- throw new TypeError("Expected buffer payload");
- }
- const readyState = ws.#handler.readyState;
- if (isEstablished(readyState) && !isClosing(readyState) && !isClosed(readyState)) {
- const frame = new WebsocketFrameSend(buffer);
- ws.#handler.socket.write(frame.createFrame(opcodes.PING));
- }
+ const readyState = ws.#handler.readyState;
+ if (isEstablished(readyState) && !isClosing(readyState) && !isClosed(readyState)) {
+ const frame = new WebsocketFrameSend(buffer);
+ ws.#handler.socket.write(frame.createFrame(opcodes.PING));
+ }
+ }, "ping");
+ webidl.is.WebSocket = (arg) => {
+ return arg != null && typeof arg === "object" && #handler in arg;
+ };
}
};
- var { ping } = WebSocket;
- Reflect.deleteProperty(WebSocket, "ping");
WebSocket.CONNECTING = WebSocket.prototype.CONNECTING = states.CONNECTING;
WebSocket.OPEN = WebSocket.prototype.OPEN = states.OPEN;
WebSocket.CLOSING = WebSocket.prototype.CLOSING = states.CLOSING;
@@ -17288,7 +17421,7 @@ var require_eventsource = __commonJS({
var CLOSED = 2;
var ANONYMOUS = "anonymous";
var USE_CREDENTIALS = "use-credentials";
- var EventSource = class _EventSource extends EventTarget {
+ var EventSource = class extends EventTarget {
static {
__name(this, "EventSource");
}
@@ -17363,6 +17496,7 @@ var require_eventsource = __commonJS({
* @readonly
*/
get readyState() {
+ webidl.brandCheck(this, webidl.is.EventSource);
return this.#readyState;
}
/**
@@ -17371,6 +17505,7 @@ var require_eventsource = __commonJS({
* @returns {string}
*/
get url() {
+ webidl.brandCheck(this, webidl.is.EventSource);
return this.#url;
}
/**
@@ -17378,6 +17513,7 @@ var require_eventsource = __commonJS({
* instantiated with CORS credentials set (true), or not (false, the default).
*/
get withCredentials() {
+ webidl.brandCheck(this, webidl.is.EventSource);
return this.#withCredentials;
}
#connect() {
@@ -17463,16 +17599,18 @@ var require_eventsource = __commonJS({
* CLOSED.
*/
close() {
- webidl.brandCheck(this, _EventSource);
+ webidl.brandCheck(this, webidl.is.EventSource);
if (this.#readyState === CLOSED) return;
this.#readyState = CLOSED;
this.#controller.abort();
this.#request = null;
}
get onopen() {
+ webidl.brandCheck(this, webidl.is.EventSource);
return this.#events.open;
}
set onopen(fn) {
+ webidl.brandCheck(this, webidl.is.EventSource);
if (this.#events.open) {
this.removeEventListener("open", this.#events.open);
}
@@ -17485,9 +17623,11 @@ var require_eventsource = __commonJS({
}
}
get onmessage() {
+ webidl.brandCheck(this, webidl.is.EventSource);
return this.#events.message;
}
set onmessage(fn) {
+ webidl.brandCheck(this, webidl.is.EventSource);
if (this.#events.message) {
this.removeEventListener("message", this.#events.message);
}
@@ -17500,9 +17640,11 @@ var require_eventsource = __commonJS({
}
}
get onerror() {
+ webidl.brandCheck(this, webidl.is.EventSource);
return this.#events.error;
}
set onerror(fn) {
+ webidl.brandCheck(this, webidl.is.EventSource);
if (this.#events.error) {
this.removeEventListener("error", this.#events.error);
}
@@ -17514,6 +17656,11 @@ var require_eventsource = __commonJS({
this.#events.error = null;
}
}
+ static {
+ webidl.is.EventSource = (arg) => {
+ return arg != null && typeof arg === "object" && #events in arg;
+ };
+ }
};
var constantsPropertyDescriptors = {
CONNECTING: {
@@ -17594,7 +17741,6 @@ var require_readable = __commonJS({
var { Readable } = require("node:stream");
var { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = require_errors();
var util = require_util();
- var { ReadableStreamFrom } = require_util();
var kConsume = /* @__PURE__ */ Symbol("kConsume");
var kReading = /* @__PURE__ */ Symbol("kReading");
var kBody = /* @__PURE__ */ Symbol("kBody");
@@ -17784,7 +17930,7 @@ var require_readable = __commonJS({
*/
get body() {
if (!this[kBody]) {
- this[kBody] = ReadableStreamFrom(this);
+ this[kBody] = ReadableStream.from(this);
if (this[kConsume]) {
this[kBody].getReader();
assert(this[kBody].locked);
diff --git a/src/undici_version.h b/src/undici_version.h
index 3dd10c8a2aa..22dc13300b7 100644
--- a/src/undici_version.h
+++ b/src/undici_version.h
@@ -2,5 +2,5 @@
// Refer to tools/dep_updaters/update-undici.sh
#ifndef SRC_UNDICI_VERSION_H_
#define SRC_UNDICI_VERSION_H_
-#define UNDICI_VERSION "8.10.2"
+#define UNDICI_VERSION "8.11.2"
#endif // SRC_UNDICI_VERSION_H_