diff --git a/deps/undici/src/docs/docs/api/Client.md b/deps/undici/src/docs/docs/api/Client.md index d48b2303f287..5f44ae42db86 100644 --- a/deps/undici/src/docs/docs/api/Client.md +++ b/deps/undici/src/docs/docs/api/Client.md @@ -147,6 +147,10 @@ added: v1.0.0 WebSocket messages. Applied to uncompressed messages, compressed frame payloads, and decompressed (`permessage-deflate`) messages. Set to `0` to disable the limit. **Default:** `134217728`. + * `eventSource` {Object} (optional) EventSource-specific configuration. + * `maxEventSize` {number} The maximum allowed event size, in bytes, for + EventSource messages. Set to `0` to disable the limit. + **Default:** `buffer.kStringMaxLength`. * Returns: {Client} Instantiating a `Client` does not open a connection; the connection is diff --git a/deps/undici/src/docs/docs/api/EnvHttpProxyAgent.md b/deps/undici/src/docs/docs/api/EnvHttpProxyAgent.md index 8a6b75a3d67b..f14b8760964e 100644 --- a/deps/undici/src/docs/docs/api/EnvHttpProxyAgent.md +++ b/deps/undici/src/docs/docs/api/EnvHttpProxyAgent.md @@ -25,8 +25,9 @@ it is used only for HTTPS requests. proxied. Each entry may include a leading dot or `*.` wildcard (for example `.example.com`) to match subdomains, and an optional `:port` suffix to restrict the match to a specific port. A request bypasses the proxy when its host equals -an entry or is a subdomain of one. Setting `no_proxy` to `*` bypasses the proxy -for every request. +an entry or is a subdomain of one. A trailing dot is ignored on both sides, so +`example.com.` and `example.com` match each other. Setting `no_proxy` to `*` +bypasses the proxy for every request. The uppercase variants `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` are also honored. When both the lowercase and uppercase forms of a variable are set, the diff --git a/deps/undici/src/docs/docs/api/EventSource.md b/deps/undici/src/docs/docs/api/EventSource.md index 938a7a8c6f2b..285a983379f7 100644 --- a/deps/undici/src/docs/docs/api/EventSource.md +++ b/deps/undici/src/docs/docs/api/EventSource.md @@ -66,6 +66,9 @@ added: v6.5.0 wait before re-establishing a dropped connection. The server may override this value with a `retry` field. **Default:** `3000`. +EventSource-specific limits can be configured on the dispatcher using the +`eventSource` option. See [`Client`][] for details. + Creates a new `EventSource` and immediately begins connecting to `url`. The request is sent with the `Accept: text/event-stream` header, a cache mode of `no-store`, and an initiator type of `other`. @@ -349,6 +352,7 @@ eventSource.onerror = () => { ``` [WHATWG-conformant]: https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events +[`Client`]: Client.md#new-clienturl-options [`Dispatcher`]: Dispatcher.md#class-dispatcher [`addEventListener()`]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener [server-sent events]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events diff --git a/deps/undici/src/docs/docs/api/Interceptors.md b/deps/undici/src/docs/docs/api/Interceptors.md index c692442d7f04..856877c3e4ae 100644 --- a/deps/undici/src/docs/docs/api/Interceptors.md +++ b/deps/undici/src/docs/docs/api/Interceptors.md @@ -101,8 +101,8 @@ body yourself. * `opts` {Object} (optional) * `maxSize` {number} Maximum number of bytes to read and discard. Responses - whose `Content-Length` exceeds this value are aborted. **Default:** - `1_048_576` (1 MiB). + whose declared or received body size exceeds this value are aborted. + **Default:** `1_048_576` (1 MiB). Per-request override: set `dumpMaxSize` on the dispatch options to override the global `maxSize` for a specific request. @@ -210,6 +210,9 @@ 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). **Returns:** {Dispatcher.DispatcherComposeInterceptor} @@ -221,7 +224,8 @@ import { Agent, interceptors } from 'undici' const agent = new Agent().compose( interceptors.decompress({ skipStatusCodes: [204, 304], - skipErrorResponses: false // decompress error bodies too + skipErrorResponses: false, // decompress error bodies too + maxSize: 16 * 1024 * 1024 // limit decoded bodies to 16 MiB }) ) ``` diff --git a/deps/undici/src/docs/docs/api/Socks5ProxyAgent.md b/deps/undici/src/docs/docs/api/Socks5ProxyAgent.md index 21fec19b141e..783424da5114 100644 --- a/deps/undici/src/docs/docs/api/Socks5ProxyAgent.md +++ b/deps/undici/src/docs/docs/api/Socks5ProxyAgent.md @@ -60,6 +60,11 @@ added: v7.23.0 a password embedded in `proxyUrl`. **Default:** the URL password, if any. * `connect` {Function} Custom connector used to open the socket to the proxy. **Default:** a connector built from `proxyTls`. + * `connectTimeout` {number} Maximum time in milliseconds for each proxy + connection, SOCKS5 negotiation, and target TLS negotiation stage. A value of + `0` disables these stage timeouts. `proxyTls.timeout` and + `requestTls.timeout` override it for their respective TLS stages. + **Default:** `5000`. * `proxyTls` {BuildOptions} TLS options for the connection to the proxy itself (SOCKS5 over TLS). When set, the proxy connection is established over TLS and `servername` defaults to the proxy host name. @@ -69,7 +74,8 @@ added: v7.23.0 host name. Throws an `InvalidArgumentError` if `proxyUrl` is missing or does not use the -`socks5:` or `socks:` protocol. +`socks5:` or `socks:` protocol, or if `connectTimeout`, `proxyTls.timeout`, or +`requestTls.timeout` is not a finite, non-negative number. ```mjs import { Socks5ProxyAgent } from 'undici' diff --git a/deps/undici/src/lib/cache/memory-cache-store.js b/deps/undici/src/lib/cache/memory-cache-store.js index 5ea0f7247dd7..07dba9c3988e 100644 --- a/deps/undici/src/lib/cache/memory-cache-store.js +++ b/deps/undici/src/lib/cache/memory-cache-store.js @@ -87,7 +87,7 @@ class MemoryCacheStore extends EventEmitter { } /** - * @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} req + * @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} key * @returns {import('../../types/cache-interceptor.d.ts').default.GetResult | undefined} */ get (key) { @@ -179,7 +179,7 @@ class MemoryCacheStore extends EventEmitter { // Perform eviction for (const [key, entries] of store.#entries) { - for (const entry of entries.splice(0, entries.length / 2)) { + for (const entry of entries.splice(0, Math.ceil(entries.length / 2))) { store.#size -= entry.size store.#count -= 1 } diff --git a/deps/undici/src/lib/core/symbols.js b/deps/undici/src/lib/core/symbols.js index badecb709086..5186052881bf 100644 --- a/deps/undici/src/lib/core/symbols.js +++ b/deps/undici/src/lib/core/symbols.js @@ -5,6 +5,8 @@ module.exports = { kDestroy: Symbol('destroy'), kDispatch: Symbol('dispatch'), kUrl: Symbol('url'), + kRequestOrigin: Symbol('request origin'), + kOriginless: Symbol('originless'), kWriting: Symbol('writing'), kResuming: Symbol('resuming'), kQueue: Symbol('queue'), diff --git a/deps/undici/src/lib/dispatcher/agent.js b/deps/undici/src/lib/dispatcher/agent.js index 1e670746e8e9..95c1b0923f08 100644 --- a/deps/undici/src/lib/dispatcher/agent.js +++ b/deps/undici/src/lib/dispatcher/agent.js @@ -1,7 +1,7 @@ 'use strict' const { InvalidArgumentError, MaxOriginsReachedError } = require('../core/errors') -const { kBusy, kClients, kConnected, kRunning, kClose, kDestroy, kDispatch, kUrl } = require('../core/symbols') +const { kBusy, kClients, kConnected, kRunning, kPending, kClose, kDestroy, kDispatch, kUrl } = require('../core/symbols') const DispatcherBase = require('./dispatcher-base') const Pool = require('./pool') const Client = require('./client') @@ -97,7 +97,12 @@ class Agent extends DispatcherBase { return } - if (dispatcher[kConnected] > 0 || dispatcher[kBusy]) { + // A GOAWAY detaches the HTTP/2 session before requeued requests are + // dispatched on a replacement connection. At that point the pool has + // no connected clients and is not busy, but it still has pending work. + // Closing it here lets the replacement Client finish those requests + // and then destroys that new connection with ClientDestroyedError. + if (dispatcher[kConnected] > 0 || dispatcher[kBusy] || dispatcher[kPending] > 0) { return } diff --git a/deps/undici/src/lib/dispatcher/balanced-pool.js b/deps/undici/src/lib/dispatcher/balanced-pool.js index ca14bf6ed1d5..dbd9ebc8a552 100644 --- a/deps/undici/src/lib/dispatcher/balanced-pool.js +++ b/deps/undici/src/lib/dispatcher/balanced-pool.js @@ -13,7 +13,7 @@ const { kGetDispatcher } = require('./pool-base') const Pool = require('./pool') -const { kUrl } = require('../core/symbols') +const { kOriginless, kUrl } = require('../core/symbols') const util = require('../core/util') const kFactory = Symbol('factory') @@ -49,14 +49,17 @@ function defaultFactory (origin, opts) { } class BalancedPool extends PoolBase { - constructor (upstreams = [], { factory = defaultFactory, ...opts } = {}) { + constructor (upstreams = [], { factory = defaultFactory, connect, tls, ...opts } = {}) { if (typeof factory !== 'function') { throw new InvalidArgumentError('factory must be a function.') } - super() + super(opts) - this[kOptions] = { ...util.deepClone(opts) } + this[kOriginless] = true + if (connect && typeof connect !== 'function') connect = { ...connect } + if (tls && typeof tls !== 'function') tls = { ...tls } + this[kOptions] = { ...util.deepClone(opts), connect, tls } this[kIndex] = -1 this[kCurrentWeight] = 0 diff --git a/deps/undici/src/lib/dispatcher/client-h1.js b/deps/undici/src/lib/dispatcher/client-h1.js index 9f6f17c1579b..f06ca74bfe53 100644 --- a/deps/undici/src/lib/dispatcher/client-h1.js +++ b/deps/undici/src/lib/dispatcher/client-h1.js @@ -1052,7 +1052,7 @@ function onSocketClose () { function clearIdleSocketValidation (socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]) + clearImmediate(socket[kIdleSocketValidationTimeout]) socket[kIdleSocketValidationTimeout] = null } @@ -1061,15 +1061,23 @@ function clearIdleSocketValidation (socket) { function scheduleIdleSocketValidation (client, socket) { socket[kIdleSocketValidation] = 1 - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + // Yield to the check phase (after poll) so unsolicited bytes / FIN / RST + // already pending on this idle keep-alive socket are processed before the + // next request is written (GHSA-35p6-xmwp-9g52). + // + // setTimeout(0) pays Node's ~1ms timer floor on every sequential reuse + // (#5493). setImmediate avoids that, but an *unref'd* Immediate lets poll + // block for ~500ms when the event loop is otherwise idle (#5600 / #5606). + // A ref'd Immediate both keeps the pending request alive and makes poll + // return immediately — the hybrid those issues asked for. + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null socket[kIdleSocketValidation] = 2 if (client[kSocket] === socket && !socket.destroyed) { client[kResume]() } - }, 0) - socket[kIdleSocketValidationTimeout].unref?.() + }) } /** diff --git a/deps/undici/src/lib/dispatcher/client-h2.js b/deps/undici/src/lib/dispatcher/client-h2.js index bc401008f004..55179000ebaf 100644 --- a/deps/undici/src/lib/dispatcher/client-h2.js +++ b/deps/undici/src/lib/dispatcher/client-h2.js @@ -10,7 +10,8 @@ const { InformationalError, InvalidArgumentError, HeadersTimeoutError, - BodyTimeoutError + BodyTimeoutError, + ResponseExceededMaxSizeError } = require('../core/errors.js') const { kUrl, @@ -39,7 +40,8 @@ const { kRemoteSettings, kHTTP2Stream, kHTTP2SessionState, - kHTTP2Options + kHTTP2Options, + kMaxResponseSize } = require('../core/symbols.js') const { channels } = require('../core/diagnostics.js') @@ -1022,9 +1024,11 @@ function writeH2 (client, request) { const state = { abort: null, body: request.body, + bytesRead: 0, client, contentLength: null, expectsPayload: false, + maxResponseSize: client[kMaxResponseSize], request, headersTimeout, bodyTimeout, @@ -1260,6 +1264,7 @@ function writeH2 (client, request) { // become unreachable once the stream closes, so plain `on` avoids the // per-listener `once` wrapper allocation. stream.on('response', onResponse) + stream.on('headers', onInterimResponse) stream.on('end', onEnd) stream.on('error', onError) stream.on('frameError', onFrameError) @@ -1280,6 +1285,7 @@ function removeRequestStreamListeners (stream) { stream.off('error', noop) stream.off('continue', writeBodyH2) stream.off('response', onResponse) + stream.off('headers', onInterimResponse) stream.off('end', onEnd) stream.off('error', onError) stream.off('frameError', onFrameError) @@ -1322,17 +1328,51 @@ function onData (chunk) { return } - const { request } = state + const { request, maxResponseSize } = state if (request.aborted || request.completed) { 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 + // the session usable for its siblings. + state.abort(new ResponseExceededMaxSizeError()) + return + } + + state.bytesRead += chunk.length + if (request.onResponseData(chunk) === false) { stream.pause() } } +function onInterimResponse (headers) { + const stream = this + const state = stream[kRequestStreamState] + + if (state == null) { + return + } + + const { request } = state + + if (request.aborted || request.completed) { + return + } + + // node http2 emits 'headers' for interim (1xx) informational responses, + // while the final response arrives via 'response'. Forward these to the + // handler so that onInfo is invoked, matching the HTTP/1 behaviour and the + // documented onInfo contract. + const statusCode = headers[HTTP2_HEADER_STATUS] + delete headers[HTTP2_HEADER_STATUS] + + request.onResponseStart(Number(statusCode), headers, noop, '') +} + function onResponse (headers) { const stream = this const state = stream[kRequestStreamState] diff --git a/deps/undici/src/lib/dispatcher/client.js b/deps/undici/src/lib/dispatcher/client.js index d620e8310cfb..ec81541f9a59 100644 --- a/deps/undici/src/lib/dispatcher/client.js +++ b/deps/undici/src/lib/dispatcher/client.js @@ -137,7 +137,8 @@ class Client extends DispatcherBase { connectionWindowSize, pingInterval, webSocket, - h2Options + h2Options, + eventSource } = {}) { if (keepAlive !== undefined) { throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead') @@ -276,7 +277,7 @@ class Client extends DispatcherBase { } } - super({ webSocket }) + super({ webSocket, eventSource }) if (typeof connect !== 'function') { connect = buildConnector({ diff --git a/deps/undici/src/lib/dispatcher/dispatcher-base.js b/deps/undici/src/lib/dispatcher/dispatcher-base.js index 21b5e346acad..d9d15d6441a9 100644 --- a/deps/undici/src/lib/dispatcher/dispatcher-base.js +++ b/deps/undici/src/lib/dispatcher/dispatcher-base.js @@ -1,5 +1,6 @@ 'use strict' +const buffer = require('node:buffer') const Dispatcher = require('./dispatcher') const { ClientDestroyedError, @@ -11,6 +12,7 @@ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch } = require('../core/sy const kOnDestroyed = Symbol('onDestroyed') const kOnClosed = Symbol('onClosed') const kWebSocketOptions = Symbol('webSocketOptions') +const kEventSourceOptions = Symbol('eventSourceOptions') class DispatcherBase extends Dispatcher { /** @type {boolean} */ @@ -31,10 +33,11 @@ class DispatcherBase extends Dispatcher { constructor (opts) { super() this[kWebSocketOptions] = opts?.webSocket ?? {} + this[kEventSourceOptions] = opts?.eventSource ?? {} } /** - * @returns {import('../../types/dispatcher').WebSocketOptions} + * @returns {import('../../types/client').Client.WebSocketOptions} */ get webSocketOptions () { return { @@ -43,6 +46,15 @@ class DispatcherBase extends Dispatcher { } } + /** + * @returns {import('../../types/client').Client.EventSourceOptions} + */ + get eventSourceOptions () { + return { + maxEventSize: this[kEventSourceOptions].maxEventSize ?? buffer.kStringMaxLength + } + } + /** @returns {boolean} */ get destroyed () { return this[kDestroyed] diff --git a/deps/undici/src/lib/dispatcher/dispatcher.js b/deps/undici/src/lib/dispatcher/dispatcher.js index ecff2a9b1685..11a7ab2b4476 100644 --- a/deps/undici/src/lib/dispatcher/dispatcher.js +++ b/deps/undici/src/lib/dispatcher/dispatcher.js @@ -1,5 +1,6 @@ 'use strict' const EventEmitter = require('node:events') +const { kOriginless, kUrl } = require('../core/symbols') class Dispatcher extends EventEmitter { dispatch () { @@ -17,6 +18,10 @@ class Dispatcher extends EventEmitter { compose (...args) { // So we handle [interceptor1, interceptor2] or interceptor1, interceptor2, ... const interceptors = Array.isArray(args[0]) ? args[0] : args + // null disables origin-dependent interceptors; undefined uses opts.origin. + const interceptorOrigin = this[kOriginless] === true + ? null + : this[kUrl]?.origin let dispatch = this.dispatch.bind(this) for (const interceptor of interceptors) { @@ -28,13 +33,22 @@ class Dispatcher extends EventEmitter { throw new TypeError(`invalid interceptor, expected function received ${typeof interceptor}`) } - dispatch = interceptor(dispatch) + dispatch = interceptor(dispatch, interceptorOrigin) if (dispatch == null || typeof dispatch !== 'function' || dispatch.length !== 2) { throw new TypeError('invalid interceptor') } } + const originalDispatch = dispatch + const self = this + dispatch = function (opts, handler) { + if (opts && typeof opts === 'object' && !opts.origin && self[kUrl]) { + opts = Object.assign({}, opts, { origin: self[kUrl].origin }) + } + return originalDispatch(opts, handler) + } + return new Proxy(this, { get: (target, key) => key === 'dispatch' ? dispatch : target[key] }) diff --git a/deps/undici/src/lib/dispatcher/dispatcher1-wrapper.js b/deps/undici/src/lib/dispatcher/dispatcher1-wrapper.js index f5813288cb33..e206984d5a47 100644 --- a/deps/undici/src/lib/dispatcher/dispatcher1-wrapper.js +++ b/deps/undici/src/lib/dispatcher/dispatcher1-wrapper.js @@ -3,6 +3,7 @@ const Dispatcher = require('./dispatcher') const { InvalidArgumentError } = require('../core/errors') const { toRawHeaders } = require('../core/util') +const { kOriginless, kUrl } = require('../core/symbols') class LegacyHandlerWrapper { #handler @@ -71,6 +72,8 @@ class Dispatcher1Wrapper extends Dispatcher { } this.#dispatcher = dispatcher + this[kUrl] = dispatcher[kUrl] + this[kOriginless] = dispatcher[kOriginless] } static wrapHandler (handler) { 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 51c50601714b..5d943dbd250e 100644 --- a/deps/undici/src/lib/dispatcher/env-http-proxy-agent.js +++ b/deps/undici/src/lib/dispatcher/env-http-proxy-agent.js @@ -16,7 +16,7 @@ class EnvHttpProxyAgent extends DispatcherBase { #opts = null constructor (opts = {}) { - super() + super(opts) this.#opts = opts const { httpProxy, httpsProxy, noProxy, ...agentOpts } = opts @@ -69,6 +69,13 @@ class EnvHttpProxyAgent extends DispatcherBase { // brackets from IPv6 literals (e.g. "[::1]" -> "::1") so that the // result matches the unbracketed form stored by #parseNoProxy. hostname = hostname.replace(/:\d*$/, '').replace(/^\[(.+)\]$/, '$1').toLowerCase() + // Drop a trailing dot: it only marks the fully qualified form of a domain + // name ("example.com." and "example.com" are the same name, RFC 1034 root + // label). This runs on every dispatch, so it is a charCode check rather + // than a third regex. `length > 1` leaves the degenerate host "." alone. + if (hostname.length > 1 && hostname.charCodeAt(hostname.length - 1) === 46) { + hostname = hostname.slice(0, -1) + } port = Number.parseInt(port, 10) || DEFAULT_PORTS[protocol] || 0 if (!this.#shouldProxy(hostname, port)) { return this[kNoProxyAgent] @@ -143,8 +150,8 @@ class EnvHttpProxyAgent extends DispatcherBase { } noProxyEntries.push({ - // strip leading dot or asterisk with dot - hostname: hostname.replace(/^\*?\./, '').toLowerCase(), + // strip leading dot or asterisk with dot, and any trailing dot + hostname: hostname.replace(/^\*?\./, '').replace(/^(.+)\.$/, '$1').toLowerCase(), port }) } diff --git a/deps/undici/src/lib/dispatcher/proxy-agent.js b/deps/undici/src/lib/dispatcher/proxy-agent.js index 0b07b2fe8fe0..2b118581eec8 100644 --- a/deps/undici/src/lib/dispatcher/proxy-agent.js +++ b/deps/undici/src/lib/dispatcher/proxy-agent.js @@ -9,6 +9,7 @@ const buildConnector = require('../core/connect') const Client = require('./client') const { channels } = require('../core/diagnostics') const Socks5ProxyAgent = require('./socks5-proxy-agent') +const { hasSafeIterator } = require('../core/util') const kAgent = Symbol('proxy agent') const kClient = Symbol('proxy client') @@ -120,7 +121,7 @@ class ProxyAgent extends DispatcherBase { const { proxyTunnel, connectTimeout } = opts - super() + super(opts) const url = this.#getUrl(opts) const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url @@ -161,6 +162,7 @@ class ProxyAgent extends DispatcherBase { factory: agentFactory, username: opts.username || username, password: opts.password || password, + connectTimeout, proxyTls: opts.proxyTls, requestTls: opts.requestTls }) @@ -344,6 +346,21 @@ function buildHeaders (headers) { return headersPair } + // Materialize iterable header containers (e.g. Map, Headers) into a record so + // that throwIfProxyAuthIsSent() can inspect their entries. Object.keys and + // for...in see nothing on a Map/Headers instance, so without this the + // Proxy-Authorization guard is bypassed and proxy credentials can reach the + // origin server (GHSA-6cv7-626c-qhqw). + if (headers && typeof headers === 'object' && hasSafeIterator(headers)) { + const headersPair = {} + + for (const [key, value] of headers) { + headersPair[key] = value + } + + return headersPair + } + return headers } diff --git a/deps/undici/src/lib/dispatcher/retry-agent.js b/deps/undici/src/lib/dispatcher/retry-agent.js index 0c2120d6f26a..0b50f22a3181 100644 --- a/deps/undici/src/lib/dispatcher/retry-agent.js +++ b/deps/undici/src/lib/dispatcher/retry-agent.js @@ -2,6 +2,7 @@ const Dispatcher = require('./dispatcher') const RetryHandler = require('../handler/retry-handler') +const { kOriginless, kUrl } = require('../core/symbols') class RetryAgent extends Dispatcher { #agent = null @@ -10,6 +11,8 @@ class RetryAgent extends Dispatcher { super(options) this.#agent = agent this.#options = options + this[kUrl] = agent[kUrl] + this[kOriginless] = agent[kOriginless] } dispatch (opts, handler) { diff --git a/deps/undici/src/lib/dispatcher/round-robin-pool.js b/deps/undici/src/lib/dispatcher/round-robin-pool.js index b1f4763530f5..1db82a9ccb3b 100644 --- a/deps/undici/src/lib/dispatcher/round-robin-pool.js +++ b/deps/undici/src/lib/dispatcher/round-robin-pool.js @@ -65,7 +65,7 @@ class RoundRobinPool extends PoolBase { }) } - super() + super(options) this[kConnections] = connections || null this[kUrl] = util.parseOrigin(origin) diff --git a/deps/undici/src/lib/dispatcher/socks5-proxy-agent.js b/deps/undici/src/lib/dispatcher/socks5-proxy-agent.js index 909c7f502478..e380005ffb61 100644 --- a/deps/undici/src/lib/dispatcher/socks5-proxy-agent.js +++ b/deps/undici/src/lib/dispatcher/socks5-proxy-agent.js @@ -4,22 +4,33 @@ const { URL } = require('node:url') let tls // include tls conditionally since it is not always available const DispatcherBase = require('./dispatcher-base') -const { InvalidArgumentError } = require('../core/errors') +const { ConnectTimeoutError, InvalidArgumentError } = require('../core/errors') const { Socks5Client, STATES } = require('../core/socks5-client') const { kBusy, kConnected, kDispatch, kClose, kDestroy } = require('../core/symbols') const Pool = require('./pool') const buildConnector = require('../core/connect') +const { setupConnectTimeout } = require('../core/util') const { debuglog } = require('node:util') const debug = debuglog('undici:socks5-proxy') +const DEFAULT_SOCKS5_CONNECT_TIMEOUT = 5000 + const kProxyUrl = Symbol('proxy url') const kProxyHeaders = Symbol('proxy headers') const kProxyAuth = Symbol('proxy auth') const kProxyProtocol = Symbol('proxy protocol') const kPools = Symbol('pools') const kConnector = Symbol('connector') +const kConnectTimeout = Symbol('connect timeout') const kRequestTls = Symbol('request tls settings') +const kRequestTlsTimeout = Symbol('request tls timeout') + +function createConnectTimeoutError (hostname, port, timeout) { + return new ConnectTimeoutError( + `Connect Timeout Error (attempted address: ${hostname}:${port}, timeout: ${timeout}ms)` + ) +} // Static flag to ensure warning is only emitted once per process let experimentalWarningEmitted = false @@ -29,7 +40,7 @@ let experimentalWarningEmitted = false */ class Socks5ProxyAgent extends DispatcherBase { constructor (proxyUrl, options = {}) { - super() + super(options) // Emit experimental warning only once if (!experimentalWarningEmitted) { @@ -54,7 +65,20 @@ class Socks5ProxyAgent extends DispatcherBase { this[kProxyUrl] = url this[kProxyHeaders] = options.headers || {} this[kProxyProtocol] = options.proxyTls ? 'https:' : 'http:' - this[kRequestTls] = options.requestTls + + const connectTimeout = options.connectTimeout ?? DEFAULT_SOCKS5_CONNECT_TIMEOUT + if (!Number.isFinite(connectTimeout) || connectTimeout < 0) { + throw new InvalidArgumentError('invalid connectTimeout') + } + this[kConnectTimeout] = connectTimeout + + const { timeout, ...requestTls } = options.requestTls || {} + const requestTlsTimeout = timeout ?? connectTimeout + if (!Number.isFinite(requestTlsTimeout) || requestTlsTimeout < 0) { + throw new InvalidArgumentError('invalid requestTls.timeout') + } + this[kRequestTls] = requestTls + this[kRequestTlsTimeout] = requestTlsTimeout // Extract auth from URL or options this[kProxyAuth] = { @@ -63,8 +87,13 @@ class Socks5ProxyAgent extends DispatcherBase { } // Create connector for proxy connection + const proxyTlsTimeout = options.proxyTls?.timeout ?? connectTimeout + if (!Number.isFinite(proxyTlsTimeout) || proxyTlsTimeout < 0) { + throw new InvalidArgumentError('invalid proxyTls.timeout') + } this[kConnector] = options.connect || buildConnector({ ...options.proxyTls, + timeout: proxyTlsTimeout, servername: options.proxyTls?.servername || url.hostname }) @@ -113,20 +142,29 @@ class Socks5ProxyAgent extends DispatcherBase { // Wait for authentication (if required) const authenticationReady = Promise.withResolvers() - - const authenticationTimeout = setTimeout(() => { - authenticationReady.reject(new Error('SOCKS5 authentication timeout')) - }, 5000) - - const onAuthenticated = () => { + const authenticationTimeout = this[kConnectTimeout] === 0 + ? null + : setTimeout(() => { + cleanupAuthenticationListeners() + socks5Client.destroy() + authenticationReady.reject( + createConnectTimeoutError(proxyHost, proxyPort, this[kConnectTimeout]) + ) + }, this[kConnectTimeout]) + + const cleanupAuthenticationListeners = () => { clearTimeout(authenticationTimeout) + socks5Client.removeListener('authenticated', onAuthenticated) socks5Client.removeListener('error', onAuthenticationError) + } + + const onAuthenticated = () => { + cleanupAuthenticationListeners() authenticationReady.resolve() } const onAuthenticationError = (err) => { - clearTimeout(authenticationTimeout) - socks5Client.removeListener('authenticated', onAuthenticated) + cleanupAuthenticationListeners() authenticationReady.reject(err) } @@ -146,21 +184,30 @@ class Socks5ProxyAgent extends DispatcherBase { // Wait for connection const connectionReady = Promise.withResolvers() - - const connectionTimeout = setTimeout(() => { - connectionReady.reject(new Error('SOCKS5 connection timeout')) - }, 5000) + const connectionTimeout = this[kConnectTimeout] === 0 + ? null + : setTimeout(() => { + cleanupConnectionListeners() + socks5Client.destroy() + connectionReady.reject( + createConnectTimeoutError(targetHost, targetPort, this[kConnectTimeout]) + ) + }, this[kConnectTimeout]) + + const cleanupConnectionListeners = () => { + clearTimeout(connectionTimeout) + socks5Client.removeListener('connected', onConnected) + socks5Client.removeListener('error', onConnectionError) + } const onConnected = (info) => { debug('SOCKS5 tunnel established to', targetHost, targetPort, 'via', info) - clearTimeout(connectionTimeout) - socks5Client.removeListener('error', onConnectionError) + cleanupConnectionListeners() connectionReady.resolve() } const onConnectionError = (err) => { - clearTimeout(connectionTimeout) - socks5Client.removeListener('connected', onConnected) + cleanupConnectionListeners() connectionReady.reject(err) } @@ -213,8 +260,31 @@ class Socks5ProxyAgent extends DispatcherBase { }) const tlsReady = Promise.withResolvers() - finalSocket.once('secureConnect', tlsReady.resolve) - finalSocket.once('error', tlsReady.reject) + + const cleanupTlsListeners = () => { + queueMicrotask(clearTlsTimeout) + finalSocket.removeListener('secureConnect', onSecureConnect) + finalSocket.removeListener('error', onTlsError) + } + + const onSecureConnect = () => { + cleanupTlsListeners() + tlsReady.resolve() + } + + const onTlsError = (err) => { + cleanupTlsListeners() + tlsReady.reject(err) + } + + const clearTlsTimeout = setupConnectTimeout(new WeakRef(finalSocket), { + timeout: this[kRequestTlsTimeout], + hostname: targetHost, + port: targetPort + }) + + finalSocket.once('secureConnect', onSecureConnect) + finalSocket.once('error', onTlsError) await tlsReady.promise } diff --git a/deps/undici/src/lib/handler/cache-handler.js b/deps/undici/src/lib/handler/cache-handler.js index bdfc0d94a433..2ec550b431ad 100644 --- a/deps/undici/src/lib/handler/cache-handler.js +++ b/deps/undici/src/lib/handler/cache-handler.js @@ -173,6 +173,14 @@ class CacheHandler { this.#handler.onRequestStart?.(controller, context) } + onBodySent (chunk) { + this.#handler.onBodySent?.(chunk) + } + + onRequestSent () { + this.#handler.onRequestSent?.() + } + onRequestUpgrade (controller, statusCode, headers, socket) { this.#handler.onRequestUpgrade?.(controller, statusCode, headers, socket) } @@ -210,6 +218,13 @@ class CacheHandler { } const cacheControlHeader = resHeaders['cache-control'] + const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {} + + if (revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives)) { + deleteCachedValue(this.#store, this.#cacheKey) + return downstreamOnHeaders() + } + const heuristicallyCacheable = resHeaders['last-modified'] && arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode) if ( !cacheControlHeader && @@ -226,8 +241,7 @@ class CacheHandler { return downstreamOnHeaders() } - const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {} - if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { + if (!canCacheResponse(this.#cacheType, this.#cacheKey.method, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) { if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) { deleteCachedValue(this.#store, this.#cacheKey) } @@ -476,7 +490,10 @@ function deleteCachedValueIfNotModified (statusCode, store, cacheKey) { */ function revalidationResponseDisallowsCachedReuse (cacheType, resHeaders, cacheControlDirectives) { return cacheControlDirectives['no-store'] === true || - (cacheType === 'shared' && cacheControlDirectives.private === true) || + (cacheType === 'shared' && ( + cacheControlDirectives.private === true || + Object.hasOwn(resHeaders, 'set-cookie') + )) || (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false) } @@ -484,12 +501,16 @@ function revalidationResponseDisallowsCachedReuse (cacheType, resHeaders, cacheC * @see https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen * * @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType + * @param {string} method * @param {number} statusCode * @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders * @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives * @param {import('../../types/header.d.ts').IncomingHttpHeaders} [reqHeaders] */ -function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { +function canCacheResponse (cacheType, method, statusCode, resHeaders, cacheControlDirectives, reqHeaders) { + if (!arrayIncludes(util.safeHTTPMethods, method)) { + return false + } // Status code must be final and understood. if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) { return false @@ -510,7 +531,10 @@ function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirect return false } - if (cacheType === 'shared' && cacheControlDirectives.private === true) { + if (cacheType === 'shared' && ( + cacheControlDirectives.private === true || + Object.hasOwn(resHeaders, 'set-cookie') + )) { return false } diff --git a/deps/undici/src/lib/handler/decorator-handler.js b/deps/undici/src/lib/handler/decorator-handler.js index 1b53c711324a..bc99893cda0b 100644 --- a/deps/undici/src/lib/handler/decorator-handler.js +++ b/deps/undici/src/lib/handler/decorator-handler.js @@ -62,5 +62,11 @@ module.exports = class DecoratorHandler { /** * @deprecated */ - onBodySent () {} + onBodySent (...args) { + return this.#handler.onBodySent?.(...args) + } + + onRequestSent (...args) { + return this.#handler.onRequestSent?.(...args) + } } diff --git a/deps/undici/src/lib/handler/deduplication-handler.js b/deps/undici/src/lib/handler/deduplication-handler.js index 537c4f70e974..4d85e9cde3bf 100644 --- a/deps/undici/src/lib/handler/deduplication-handler.js +++ b/deps/undici/src/lib/handler/deduplication-handler.js @@ -365,12 +365,22 @@ class DeduplicationHandler { get aborted () { return state.aborted }, get reason () { return state.reason }, abort: (reason) => { + if (state.aborted) { + return + } + state.aborted = true state.reason = reason ?? null waitingHandler.done = true waitingHandler.pendingTrailers = null waitingHandler.bufferedChunks = [] waitingHandler.bufferedBytes = 0 + + try { + handler.onResponseError?.(waitingHandler.controller, state.reason ?? new RequestAbortedError()) + } catch { + // Ignore errors from waiting handlers + } } } @@ -444,12 +454,8 @@ class DeduplicationHandler { waitingHandler.bufferedChunks = [] waitingHandler.bufferedBytes = 0 - try { - waitingHandler.controller.abort(err) - waitingHandler.handler.onResponseError?.(waitingHandler.controller, err) - } catch { - // Ignore errors from waiting handlers - } + // controller.abort(err) notifies the handler via onResponseError + waitingHandler.controller.abort(err) } #pruneDoneWaitingHandlers () { diff --git a/deps/undici/src/lib/handler/redirect-handler.js b/deps/undici/src/lib/handler/redirect-handler.js index 1b813dac98b9..a5d925086319 100644 --- a/deps/undici/src/lib/handler/redirect-handler.js +++ b/deps/undici/src/lib/handler/redirect-handler.js @@ -3,6 +3,7 @@ const util = require('../core/util') const assert = require('node:assert') const { InvalidArgumentError } = require('../core/errors') +const { kRequestOrigin } = require('../core/symbols') const redirectableStatusCodes = [300, 301, 302, 303, 307, 308] @@ -43,6 +44,14 @@ class RedirectHandler { this.handler.onRequestStart?.(controller, { ...context, history: this.history }) } + onBodySent (chunk) { + this.handler.onBodySent?.(chunk) + } + + onRequestSent () { + this.handler.onRequestSent?.() + } + onRequestUpgrade (controller, statusCode, headers, socket) { this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket) } @@ -81,8 +90,12 @@ class RedirectHandler { ? null : headers.location - if (this.opts.origin) { - this.history.push(new URL(this.opts.path, this.opts.origin)) + const requestOrigin = this.opts[kRequestOrigin] === undefined + ? this.opts.origin + : this.opts[kRequestOrigin] + + if (requestOrigin) { + this.history.push(new URL(this.opts.path, requestOrigin)) } if (!this.location) { @@ -90,7 +103,10 @@ class RedirectHandler { return } - const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))) + const baseUrl = requestOrigin + ? new URL(this.opts.path, requestOrigin) + : undefined + const { origin, pathname, search } = util.parseURL(new URL(this.location, baseUrl)) const path = search ? `${pathname}${search}` : pathname // Check for redirect loops by seeing if we've already visited this URL in our history @@ -106,9 +122,10 @@ class RedirectHandler { // Remove headers referring to the original URL. // By default it is Host only. A 303 or a 301/302 POST-to-GET redirect also removes all Content-* headers. // https://tools.ietf.org/html/rfc7231#section-6.4 - this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect) + this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, requestOrigin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect) this.opts.path = path this.opts.origin = origin + this.opts[kRequestOrigin] = origin this.opts.query = null } diff --git a/deps/undici/src/lib/handler/retry-handler.js b/deps/undici/src/lib/handler/retry-handler.js index c098b510c26c..5703f145d74c 100644 --- a/deps/undici/src/lib/handler/retry-handler.js +++ b/deps/undici/src/lib/handler/retry-handler.js @@ -2,7 +2,7 @@ const assert = require('node:assert') const { kRetryHandlerDefaultRetry } = require('../core/symbols') -const { RequestRetryError } = require('../core/errors') +const { RequestRetryError, RequestAbortedError } = require('../core/errors') const { isDisturbed, parseRangeHeader, @@ -41,19 +41,42 @@ function validatePartialResponseContentLength (headers, range, statusCode, retry // new one: backpressure pauses the new connection's controller, but the // consumer's resume() targets the old one, so the resumed body stalls forever. // The proxy always forwards to the controller of the currently active connection. +// An abort is additionally reported to the handler so it can cancel a pending +// retry backoff instead of letting the request hang until the backoff elapses. +// The notification is a private callback the handler hands over on construction, +// so nothing outside the handler can trigger it. class RetryController { - constructor () { + #onAbort + + constructor (onAbort) { + this.#onAbort = onAbort this.target = null } pause () { this.target?.pause() } resume () { this.target?.resume() } - abort (reason) { this.target?.abort(reason) } + + 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 } + 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 + } + } } class RetryHandler { @@ -112,15 +135,32 @@ class RetryHandler { this.etag = null this.statusCode = null this.headers = null - this.controllerProxy = new RetryController() + this.controllerProxy = new RetryController(reason => this.#onAbort(reason)) + // A retry decision is in flight (the policy may be holding a backoff + // timer). While pending, a consumer abort cancels the wait. + this.retryPending = false + // 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 + // Set once an abort during the backoff delivered the terminal error + // downstream; late policy callbacks and connection errors are then moot. + this.aborted = false } onResponseStartWithRetry (controller, statusCode, headers, statusMessage, err) { if (this.retryOpts.throwOnError) { // Preserve old behavior for status codes that are not eligible for retry if (this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true - this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage) + if (this.headersSent) { + // The downstream handler already received the response from an + // earlier attempt. Forwarding this response would replace the + // downstream body and leave the original body pending forever. + this.handler.onResponseError?.(this.controllerProxy, err) + } else { + this.headersSent = true + this.checkpointResponseEnd(headers) + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage) + } } else { this.error = err } @@ -130,14 +170,30 @@ class RetryHandler { if (isDisturbed(this.opts.body)) { this.headersSent = true + this.checkpointResponseEnd(headers) this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage) return } function shouldRetry (passedErr) { + if (this.aborted) { + // Aborted while the policy was deciding; the decision is moot. + return + } + this.retryPending = false + this.retryTimer = null + if (passedErr) { - this.headersSent = true - this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage) + if (this.headersSent) { + // The downstream handler already received the response from an + // earlier attempt. Forwarding this response would replace the + // downstream body and leave the original body pending forever. + this.handler.onResponseError?.(this.controllerProxy, passedErr) + } else { + this.headersSent = true + this.checkpointResponseEnd(headers) + this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage) + } controller.resume() return } @@ -154,14 +210,31 @@ class RetryHandler { // between, leaving this one paused forever -- the very stall the proxy exists // to prevent. controller.pause() - this.retryOpts.retry( + // 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.retryTimer = this.retryOpts.retry( err, { state: { counter: this.retryCount }, opts: { retryOptions: this.retryOpts, ...this.opts } }, shouldRetry.bind(this) - ) + ) ?? null + } + + checkpointResponseEnd (headers) { + if (this.end == null && this.opts.method !== 'HEAD') { + const contentLength = headers['content-length'] + this.end = contentLength != null ? Number(contentLength) - 1 : null + + assert( + this.end == null || Number.isFinite(this.end), + 'invalid content-length' + ) + + this.resume = this.end != null + } } onRequestStart (controller, context) { @@ -176,6 +249,14 @@ class RetryHandler { } } + onBodySent (chunk) { + this.handler.onBodySent?.(chunk) + } + + onRequestSent () { + this.handler.onRequestSent?.() + } + onRequestUpgrade (_controller, statusCode, headers, socket) { this.handler.onRequestUpgrade?.(this.controllerProxy, statusCode, headers, socket) } @@ -190,7 +271,8 @@ class RetryHandler { timeoutFactor, statusCodes, errorCodes, - methods + methods, + retryAfter } = retryOptions const { counter } = state @@ -222,7 +304,7 @@ class RetryHandler { return } - let retryAfterHeader = headers?.['retry-after'] + let retryAfterHeader = retryAfter === false ? undefined : headers?.['retry-after'] if (retryAfterHeader) { retryAfterHeader = Number(retryAfterHeader) retryAfterHeader = Number.isNaN(retryAfterHeader) @@ -237,7 +319,9 @@ class RetryHandler { ? Math.min(retryAfterHeader, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout) - setTimeout(() => cb(null), retryTimeout) + // Return the backoff timer so the handler can cancel it when the + // consumer aborts while the retry decision is pending. + return setTimeout(() => cb(null), retryTimeout) } onResponseStart (controller, statusCode, headers, statusMessage) { @@ -251,18 +335,6 @@ class RetryHandler { this.statusCode = statusCode this.headers = headers - if (statusCode >= 300) { - const err = new RequestRetryError('Request failed', statusCode, { - headers, - data: { - count: this.retryCount - } - }) - - this.onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err) - return - } - // Checkpoint for resume from where we left it if (this.headersSent) { // Only Partial Content 206 supposed to provide Content-Range, @@ -299,12 +371,28 @@ class RetryHandler { const { start, size, end = size ? size - 1 : null } = contentRange - assert(this.start === start, 'content-range mismatch') - assert(this.end == null || this.end === end, 'content-range mismatch') + if (this.start !== start || (this.end != null && this.end !== end)) { + throw new RequestRetryError('Content-Range mismatch', statusCode, { + headers, + data: { count: this.retryCount } + }) + } return } + if (statusCode >= 300) { + const err = new RequestRetryError('Request failed', statusCode, { + headers, + data: { + count: this.retryCount + } + }) + + this.onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err) + return + } + if (this.end == null) { if (statusCode === 206) { // First time we receive 206 @@ -435,14 +523,27 @@ class RetryHandler { } onResponseError (controller, err) { + if (this.aborted) { + // #onAbort already delivered the terminal error downstream; the late + // error of the torn-down connection must not be forwarded twice. + return + } + // controller is THIS failed connection (not the proxy): we inspect whether // the consumer aborted it to decide retry-vs-propagate. - if (controller?.aborted || isDisturbed(this.opts.body)) { + if (controller?.aborted || isDisturbed(this.opts.body) || (this.headersSent && !this.resume)) { this.handler.onResponseError?.(this.controllerProxy, err) return } function shouldRetry (returnedErr) { + if (this.aborted) { + // Aborted while the policy was deciding; the decision is moot. + return + } + this.retryPending = false + this.retryTimer = null + if (!returnedErr) { this.retry() return @@ -462,14 +563,31 @@ class RetryHandler { this.retryCount += 1 } - this.retryOpts.retry( + this.retryPending = true + this.retryTimer = this.retryOpts.retry( err, { state: { counter: this.retryCount }, opts: { retryOptions: this.retryOpts, ...this.opts } }, shouldRetry.bind(this) - ) + ) ?? null + } + + #onAbort (reason) { + // A consumer abort lands on the controller proxy. If the retry policy is + // still deciding (typically holding a backoff timer), cancel the wait and + // surface the abort immediately instead of letting the request hang until + // the backoff elapses. + if (!this.retryPending) { + return + } + + this.aborted = true + this.retryPending = false + clearTimeout(this.retryTimer) + this.retryTimer = null + 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 2d7d01f130aa..0b8593f7ee6d 100644 --- a/deps/undici/src/lib/interceptor/cache.js +++ b/deps/undici/src/lib/interceptor/cache.js @@ -6,7 +6,16 @@ const util = require('../core/util') const CacheHandler = require('../handler/cache-handler') const MemoryCacheStore = require('../cache/memory-cache-store') const CacheRevalidationHandler = require('../handler/cache-revalidation-handler') -const { assertCacheStore, assertCacheMethods, makeCacheKey, normalizeHeaders, parseCacheControlHeader, isInvalidOrWildcardVaryHeader } = require('../util/cache.js') +const { + assertCacheStore, + assertCacheMethods, + getInterceptorOrigin, + makeCacheKey, + normalizeHeaders, + parseCacheControlHeader, + isInvalidOrWildcardVaryHeader, + parseVaryHeader +} = require('../util/cache.js') const { AbortError } = require('../core/errors.js') const { parseHttpDate } = require('../util/date.js') @@ -117,7 +126,10 @@ function staleResponseRequiresRevalidation (result, cacheType) { * @returns {boolean} */ function revalidationResponseDisallowsCachedReuse (cacheType, headers) { - if (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) { + if ( + (headers.vary && isInvalidOrWildcardVaryHeader(headers.vary)) || + (cacheType === 'shared' && Object.hasOwn(headers, 'set-cookie')) + ) { return true } @@ -135,6 +147,25 @@ function revalidationResponseUpdatesCacheControl (headers) { return headers['cache-control'] !== undefined } +/** + * @param {import('../../types/cache-interceptor.d.ts').default.GetResult} result + * @param {Record | undefined} varyDirectives + * @returns {boolean} + */ +function revalidationResponseAddsVary (result, varyDirectives) { + if (!varyDirectives) { + return false + } + + for (const key in varyDirectives) { + if (result.vary == null || !Object.hasOwn(result.vary, key)) { + return true + } + } + + return false +} + function deleteCachedValue (store, cacheKey) { try { store.delete(cacheKey)?.catch?.(nop) @@ -389,6 +420,17 @@ function handleResult ( return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl) } + // Shared stores may outlive the Undici version that wrote them. Do not + // re-serve a Set-Cookie header from an existing shared-cache entry. + if (globalOpts.type === 'shared' && Object.hasOwn(result.headers, 'set-cookie')) { + if (util.isStream(result.body)) { + result.body.on('error', nop).destroy() + } + + deleteCachedValue(globalOpts.store, cacheKey) + return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl) + } + const now = Date.now() if (now > result.deleteAt) { // Response is expired, cache store shouldn't have given this to us @@ -471,6 +513,13 @@ function handleResult ( if (revalidationResponseUpdatesCacheControl(headers)) { deleteCachedValue(globalOpts.store, cacheKey) + } else if (revalidationResponseAddsVary(result, headers.vary ? parseVaryHeader(headers.vary, opts.headers) : undefined)) { + if (util.isStream(result.body)) { + result.body.on('error', nop).destroy() + } + + deleteCachedValue(globalOpts.store, cacheKey) + return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)) } } @@ -538,29 +587,28 @@ module.exports = (opts = {}) => { } } - return dispatch => { + return (dispatch, interceptorOrigin) => { return (opts, handler) => { - if (arrayIncludes(safeMethodsToNotCache, opts.method)) { - // Not a method we want to cache, skip + const requestOrigin = getInterceptorOrigin(opts, interceptorOrigin) + if (!requestOrigin || arrayIncludes(safeMethodsToNotCache, opts.method)) { + // We cannot safely cache without an authoritative origin, or this is + // not a method we want to cache. return dispatch(opts, handler) } // Check if origin is in whitelist if (origins !== undefined) { - if (!opts.origin) { - return dispatch(opts, handler) - } - const requestOrigin = opts.origin.toString().toLowerCase() + const normalizedRequestOrigin = requestOrigin.toString().toLowerCase() let isAllowed = false for (let i = 0; i < origins.length; i++) { const allowed = origins[i] if (typeof allowed === 'string') { - if (allowed.toLowerCase() === requestOrigin) { + if (allowed.toLowerCase() === normalizedRequestOrigin) { isAllowed = true break } - } else if (allowed.test(requestOrigin)) { + } else if (allowed.test(normalizedRequestOrigin)) { isAllowed = true break } @@ -589,7 +637,12 @@ module.exports = (opts = {}) => { /** * @type {import('../../types/cache-interceptor.d.ts').default.CacheKey} */ - const cacheKey = makeCacheKey(opts) + const cacheKey = makeCacheKey(opts, requestOrigin) + + if (!arrayIncludes(util.safeHTTPMethods, opts.method)) { + return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler)) + } + const result = store.get(cacheKey) if (result && typeof result.then === 'function') { diff --git a/deps/undici/src/lib/interceptor/decompress.js b/deps/undici/src/lib/interceptor/decompress.js index c675de4197c3..a0e77a37c8c4 100644 --- a/deps/undici/src/lib/interceptor/decompress.js +++ b/deps/undici/src/lib/interceptor/decompress.js @@ -1,7 +1,8 @@ 'use strict' const { createInflate, createGunzip, createBrotliDecompress, createZstdDecompress } = require('node:zlib') -const { pipeline } = require('node:stream') +const { pipeline, Transform: TransformStream } = require('node:stream') +const { InvalidArgumentError, ResponseExceededMaxSizeError } = require('../core/errors') const DecoratorHandler = require('../handler/decorator-handler') /** @typedef {import('node:stream').Transform} Transform */ @@ -20,6 +21,31 @@ const supportedEncodings = { } const defaultSkipStatusCodes = /** @type {const} */ ([204, 304]) +const defaultMaxSize = 64 * 1024 * 1024 + +/** + * Limits the output of one stage in a decompression chain. + * @param {number} maxSize - Maximum output size in bytes + * @returns {Transform} + */ +function createMaxSizeLimiter (maxSize) { + let size = 0 + + return new TransformStream({ + transform (chunk, _encoding, callback) { + const decompressedSize = size + chunk.length + if (decompressedSize > maxSize) { + callback(new ResponseExceededMaxSizeError( + `Decompressed response size (${decompressedSize}) exceeded maxSize (${maxSize})` + )) + return + } + + size = decompressedSize + callback(null, chunk) + } + }) +} let warningEmitted = /** @type {boolean} */ (false) @@ -27,6 +53,7 @@ let warningEmitted = /** @type {boolean} */ (false) * @typedef {Object} DecompressHandlerOptions * @property {number[]|Readonly} [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 */ class DecompressHandler extends DecoratorHandler { @@ -38,11 +65,24 @@ class DecompressHandler extends DecoratorHandler { #skipStatusCodes /** @type {boolean} */ #skipErrorResponses + /** @type {number} */ + #maxSize + /** @type {number} */ + #decompressedSize = 0 + /** @type {boolean} */ + #terminated = false + /** @type {boolean} */ + #inputEnded = false + + constructor (handler, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true, maxSize = defaultMaxSize } = {}) { + if (!Number.isSafeInteger(maxSize) || maxSize < 1) { + throw new InvalidArgumentError('maxSize must be a positive integer') + } - constructor (handler, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true } = {}) { super(handler) this.#skipStatusCodes = skipStatusCodes this.#skipErrorResponses = skipErrorResponses + this.#maxSize = maxSize } /** @@ -62,7 +102,7 @@ class DecompressHandler extends DecoratorHandler { * Creates a chain of decompressors for multiple content encodings * * @param {string} encodings - Comma-separated list of content encodings - * @returns {Array} - Array of decompressor streams + * @returns {Array} - Array of decompressor and limiting streams * @throws {Error} - If the number of content-encodings exceeds the maximum allowed */ #createDecompressionChain (encodings) { @@ -90,7 +130,40 @@ class DecompressHandler extends DecoratorHandler { decompressors.push(supportedEncodings[encoding]()) } - return decompressors + if (decompressors.length < 2) { + return decompressors + } + + /** @type {Transform[]} */ + const streams = [] + for (let i = 0; i < decompressors.length; i++) { + streams.push(decompressors[i]) + if (i < decompressors.length - 1) { + streams.push(createMaxSizeLimiter(this.#maxSize)) + } + } + + return streams + } + + /** + * 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) { + if (this.#terminated) { + return + } + + 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) + } else { + controller.abort(error) + } } /** @@ -101,8 +174,21 @@ class DecompressHandler extends DecoratorHandler { */ #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 @@ -111,7 +197,7 @@ class DecompressHandler extends DecoratorHandler { }) decompressor.on('error', (error) => { - super.onResponseError(controller, error) + this.#fail(controller, error) }) } @@ -125,6 +211,12 @@ class DecompressHandler extends DecoratorHandler { this.#setupDecompressorEvents(decompressor, controller) decompressor.on('end', () => { + if (this.#terminated) { + return + } + + this.#terminated = true + this.#cleanupDecompressors() super.onResponseEnd(controller, this.#trailers) }) } @@ -139,10 +231,17 @@ class DecompressHandler extends DecoratorHandler { this.#setupDecompressorEvents(lastDecompressor, controller) pipeline(this.#decompressors, (err) => { + if (this.#terminated) { + return + } + if (err) { - super.onResponseError(controller, err) + this.#fail(controller, err) return } + + this.#terminated = true + this.#cleanupDecompressors() super.onResponseEnd(controller, this.#trailers) }) } @@ -198,7 +297,7 @@ class DecompressHandler extends DecoratorHandler { filteredHeaders.push(rawHeaders[i], rawHeaders[i + 1]) } - controller.rawHeaders = filteredHeaders + rawHeaders.splice(0, rawHeaders.length, ...filteredHeaders) } else if (typeof rawHeaders === 'object') { for (const name of Object.keys(rawHeaders)) { const lowerName = name.toLowerCase() @@ -238,9 +337,9 @@ class DecompressHandler extends DecoratorHandler { */ onResponseEnd (controller, trailers) { if (this.#decompressors.length > 0) { + this.#inputEnded = true this.#trailers = trailers this.#decompressors[0].end() - this.#cleanupDecompressors() return } super.onResponseEnd(controller, trailers) @@ -252,12 +351,15 @@ class DecompressHandler extends DecoratorHandler { * @returns {void} */ onResponseError (controller, err) { - if (this.#decompressors.length > 0) { - for (const decompressor of this.#decompressors) { - decompressor.destroy(err) - } - this.#cleanupDecompressors() + if (this.#terminated) { + return + } + + this.#terminated = true + for (const decompressor of this.#decompressors) { + decompressor.destroy() } + this.#cleanupDecompressors() super.onResponseError(controller, err) } } diff --git a/deps/undici/src/lib/interceptor/deduplicate.js b/deps/undici/src/lib/interceptor/deduplicate.js index bacfeb3fb37e..12598130e8f9 100644 --- a/deps/undici/src/lib/interceptor/deduplicate.js +++ b/deps/undici/src/lib/interceptor/deduplicate.js @@ -3,7 +3,7 @@ const diagnosticsChannel = require('node:diagnostics_channel') const util = require('../core/util') const DeduplicationHandler = require('../handler/deduplication-handler') -const { normalizeHeaders, makeCacheKey, makeDeduplicationKey } = require('../util/cache.js') +const { getInterceptorOrigin, normalizeHeaders, makeCacheKey, makeDeduplicationKey } = require('../util/cache.js') const pendingRequestsChannel = diagnosticsChannel.channel('undici:request:pending-requests') @@ -57,9 +57,10 @@ module.exports = (opts = {}) => { */ const pendingRequests = new Map() - return dispatch => { + return (dispatch, interceptorOrigin) => { return (opts, handler) => { - if (opts.upgrade || methods.includes(opts.method) === false) { + const requestOrigin = getInterceptorOrigin(opts, interceptorOrigin) + if (!requestOrigin || opts.upgrade || methods.includes(opts.method) === false) { return dispatch(opts, handler) } @@ -77,7 +78,7 @@ module.exports = (opts = {}) => { } } - const cacheKey = makeCacheKey(opts) + const cacheKey = makeCacheKey(opts, requestOrigin) const dedupeKey = makeDeduplicationKey(cacheKey, excludeHeaderNamesSet) // Check if there's already a pending request for this key diff --git a/deps/undici/src/lib/interceptor/dns.js b/deps/undici/src/lib/interceptor/dns.js index ebc9a5383036..ecca6efeb660 100644 --- a/deps/undici/src/lib/interceptor/dns.js +++ b/deps/undici/src/lib/interceptor/dns.js @@ -3,6 +3,7 @@ const { isIP } = require('node:net') const { lookup } = require('node:dns') const DecoratorHandler = require('../handler/decorator-handler') const { InvalidArgumentError, InformationalError } = require('../core/errors') +const { kRequestOrigin } = require('../core/symbols') const maxInt = Math.pow(2, 31) - 1 function hasSafeIterator (headers) { @@ -434,6 +435,9 @@ class DNSDispatchHandler extends DecoratorHandler { origin: `${this.#origin.protocol}//${ ip.family === 6 ? `[${ip.address}]` : ip.address }${port}`, + [kRequestOrigin]: this.#opts[kRequestOrigin] === undefined + ? this.#origin + : this.#opts[kRequestOrigin], headers: withHostHeader(this.#origin.host, this.#opts.headers) } this.#dispatch(dispatchOpts, this) @@ -557,6 +561,9 @@ module.exports = interceptorOpts => { ...origDispatchOpts, servername: origin.hostname, // For SNI on TLS origin: newOrigin.origin, + [kRequestOrigin]: origDispatchOpts[kRequestOrigin] === undefined + ? origin + : origDispatchOpts[kRequestOrigin], headers: withHostHeader(origin.host, origDispatchOpts.headers) } diff --git a/deps/undici/src/lib/interceptor/dump.js b/deps/undici/src/lib/interceptor/dump.js index 4810a09f3824..09b57f2163fb 100644 --- a/deps/undici/src/lib/interceptor/dump.js +++ b/deps/undici/src/lib/interceptor/dump.js @@ -7,7 +7,6 @@ class DumpHandler extends DecoratorHandler { #maxSize = 1024 * 1024 #dumped = false #size = 0 - #controller = null aborted = false reason = false @@ -29,7 +28,6 @@ class DumpHandler extends DecoratorHandler { onRequestStart (controller, context) { controller.abort = this.#abort.bind(this) - this.#controller = controller return super.onRequestStart(controller, context) } @@ -53,43 +51,32 @@ class DumpHandler extends DecoratorHandler { } onResponseError (controller, err) { - if (this.#dumped) { - return - } - - // On network errors before connect, controller will be null - err = this.#controller?.reason ?? err - - super.onResponseError(controller, err) + super.onResponseError(controller, this.aborted === true ? this.reason : err) } onResponseData (controller, chunk) { this.#size = this.#size + chunk.length - if (this.#size >= this.#maxSize) { - this.#dumped = true + if (this.#size > this.#maxSize) { + throw new RequestAbortedError( + `Response size (${this.#size}) larger than maxSize (${this.#maxSize})` + ) + } - if (this.aborted === true) { - super.onResponseError(controller, this.reason) - } else { - super.onResponseEnd(controller, {}) - } + if (this.#size === this.#maxSize) { + this.#dumped = true } return true } onResponseEnd (controller, trailers) { - if (this.#dumped) { - return - } - - if (this.#controller.aborted === true) { + if (this.aborted === true) { super.onResponseError(controller, this.reason) return } - super.onResponseEnd(controller, trailers) + super.onResponseEnd(controller, this.#dumped ? {} : trailers) } } diff --git a/deps/undici/src/lib/llhttp/wasm_build_env.txt b/deps/undici/src/lib/llhttp/wasm_build_env.txt index 82569ca62dd1..9085bb4e260d 100644 --- a/deps/undici/src/lib/llhttp/wasm_build_env.txt +++ b/deps/undici/src/lib/llhttp/wasm_build_env.txt @@ -1,5 +1,5 @@ -> undici@8.10.0 build:wasm +> 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/mock/mock-agent.js b/deps/undici/src/lib/mock/mock-agent.js index 17a7b717c213..6051d5aab7c0 100644 --- a/deps/undici/src/lib/mock/mock-agent.js +++ b/deps/undici/src/lib/mock/mock-agent.js @@ -73,7 +73,7 @@ class MockAgent extends Dispatcher { opts.origin = normalizeOrigin(opts.origin) // Call MockAgent.get to perform additional setup before dispatching as normal - this.get(opts.origin) + const mockDispatcher = this.get(opts.origin) this[kMockAgentAddCallHistoryLog](opts) @@ -81,6 +81,18 @@ class MockAgent extends Dispatcher { const dispatchOpts = { ...opts } + // Agent keeps HTTP/1.1-only dispatchers under a separate key. Legacy + // global dispatcher consumers use that path, so mirror the mock dispatches + // before delegating to the internal Agent. + if (dispatchOpts.allowH2 === false) { + const http1OnlyKey = `${dispatchOpts.origin}#http1-only` + if (!this[kClients].has(http1OnlyKey)) { + const http1OnlyDispatcher = this[kFactory](dispatchOpts.origin) + http1OnlyDispatcher[kDispatches] = mockDispatcher[kDispatches] + this[kMockAgentSet](http1OnlyKey, http1OnlyDispatcher) + } + } + if (acceptNonStandardSearchParameters && dispatchOpts.path) { const [path, searchParams] = dispatchOpts.path.split('?') const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters) diff --git a/deps/undici/src/lib/mock/mock-utils.js b/deps/undici/src/lib/mock/mock-utils.js index e43f7218d0b4..00c1a0bbe13c 100644 --- a/deps/undici/src/lib/mock/mock-utils.js +++ b/deps/undici/src/lib/mock/mock-utils.js @@ -333,8 +333,7 @@ function mockDispatch (opts, handler) { handler.onResponseError(null, new InvalidArgumentError('reply options callback must return an object')) return } - mockDispatch.data = { ...responseDefaults, ...resolvedData } - dispatchMockReply(mockDispatches, mockDispatch, key, opts, handler) + dispatchMockReply(mockDispatches, mockDispatch, key, opts, handler, { ...responseDefaults, ...resolvedData }) }, (error) => { handler.onResponseError(null, error) @@ -347,7 +346,7 @@ function mockDispatch (opts, handler) { throw new InvalidArgumentError('reply options callback must return an object') } - mockDispatch.data = { ...responseDefaults, ...callbackResult } + return dispatchMockReply(mockDispatches, mockDispatch, key, opts, handler, { ...responseDefaults, ...callbackResult }) } return dispatchMockReply(mockDispatches, mockDispatch, key, opts, handler) @@ -356,9 +355,13 @@ function mockDispatch (opts, handler) { /** * Replies to a request once the mock dispatch data is fully resolved */ -function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) { - // Parse mockDispatch data - const { data: response, delay } = mockDispatch +function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler, resolvedResponse) { + // Parse mockDispatch data. When a reply callback has already been resolved + // in mockDispatch() (i.e. no body lifecycle hooks are involved), the resolved + // response is passed in here, leaving mockDispatch.data untouched so the + // callback can be re-invoked for persistent / times() replies. + const { data: responseData, delay } = mockDispatch + const response = resolvedResponse ?? responseData // If specified, trigger dispatch error if (response.error !== null) { @@ -454,8 +457,7 @@ function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) { handler.onResponseError(null, new InvalidArgumentError('reply options callback must return an object')) return } - mockDispatch.data = { ...responseDefaults, ...resolvedData } - handleReply(dispatches, mockDispatch.data) + handleReply(dispatches, { ...responseDefaults, ...resolvedData }) }, (err) => { handler.onResponseError(null, err) @@ -468,8 +470,7 @@ function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) { throw new InvalidArgumentError('reply options callback must return an object') } - mockDispatch.data = { ...responseDefaults, ...callbackResult } - handleReply(dispatches, mockDispatch.data) + handleReply(dispatches, { ...responseDefaults, ...callbackResult }) return } diff --git a/deps/undici/src/lib/util/cache.js b/deps/undici/src/lib/util/cache.js index 1fac28af5d97..ad2524fad3a4 100644 --- a/deps/undici/src/lib/util/cache.js +++ b/deps/undici/src/lib/util/cache.js @@ -8,6 +8,7 @@ const { } = require('../core/util') const { serializePathWithQuery } = require('../core/util') +const { kRequestOrigin } = require('../core/symbols') const MAX_DELTA_SECONDS = 2147483647 const RESTRICTIVE_DIRECTIVE_NAMES = ['no-store', 'private', 'no-cache'] @@ -147,8 +148,47 @@ function getMalformedRestrictiveDirectiveName (key) { /** * @param {import('../../types/dispatcher.d.ts').default.DispatchOptions} opts */ -function makeCacheKey (opts) { - const origin = opts.origin ? opts.origin.toString() : '' +function getRequestOrigin (opts) { + const origin = opts[kRequestOrigin] === undefined + ? opts.origin + : opts[kRequestOrigin] + return typeof origin === 'string' || origin instanceof URL + ? origin + : null +} + +/** + * @param {import('../../types/dispatcher.d.ts').default.DispatchOptions} opts + * @param {string|null|undefined} interceptorOrigin + */ +function getInterceptorOrigin (opts, interceptorOrigin) { + const requestOrigin = getRequestOrigin(opts) + if (interceptorOrigin === undefined) { + return requestOrigin + } + if (interceptorOrigin === null) { + return null + } + if (requestOrigin) { + try { + if (new URL(requestOrigin).origin !== interceptorOrigin) { + return null + } + } catch { + return interceptorOrigin + } + } + return interceptorOrigin +} + +/** + * @param {import('../../types/dispatcher.d.ts').default.DispatchOptions} opts + * @param {string|URL|null} [origin] + */ +function makeCacheKey (opts, origin = getRequestOrigin(opts)) { + if (!origin) { + throw new Error('opts.origin is undefined') + } let fullPath = opts.path || '/' @@ -157,7 +197,7 @@ function makeCacheKey (opts) { } return { - origin, + origin: origin.toString(), method: opts.method, path: fullPath, headers: opts.headers @@ -700,6 +740,8 @@ function makeDeduplicationKey (cacheKey, excludeHeaders) { } module.exports = { + getInterceptorOrigin, + getRequestOrigin, makeCacheKey, normalizeHeaders, assertCacheKey, diff --git a/deps/undici/src/lib/web/cookies/parse.js b/deps/undici/src/lib/web/cookies/parse.js index 51854822a8b6..27606b230d1c 100644 --- a/deps/undici/src/lib/web/cookies/parse.js +++ b/deps/undici/src/lib/web/cookies/parse.js @@ -92,221 +92,224 @@ function parseSetCookie (header) { * @param {Object.} [cookieAttributeList={}] */ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {}) { - // 1. If the unparsed-attributes string is empty, skip the rest of - // these steps. - if (unparsedAttributes.length === 0) { - return cookieAttributeList - } + while (true) { + // 1. If the unparsed-attributes string is empty, skip the rest of + // these steps. + if (unparsedAttributes.length === 0) { + return cookieAttributeList + } - // 2. Discard the first character of the unparsed-attributes (which - // will be a %x3B (";") character). - assert(unparsedAttributes[0] === ';') - unparsedAttributes = unparsedAttributes.slice(1) + // 2. Discard the first character of the unparsed-attributes (which + // will be a %x3B (";") character). + assert(unparsedAttributes[0] === ';') + unparsedAttributes = unparsedAttributes.slice(1) - let cookieAv = '' + let cookieAv = '' - // 3. If the remaining unparsed-attributes contains a %x3B (";") - // character: - if (unparsedAttributes.includes(';')) { + // 3. If the remaining unparsed-attributes contains a %x3B (";") + // character: + if (unparsedAttributes.includes(';')) { // 1. Consume the characters of the unparsed-attributes up to, but // not including, the first %x3B (";") character. - cookieAv = collectASequenceOfCodePointsFast( - ';', - unparsedAttributes, - { position: 0 } - ) - unparsedAttributes = unparsedAttributes.slice(cookieAv.length) - } else { + cookieAv = collectASequenceOfCodePointsFast( + ';', + unparsedAttributes, + { position: 0 } + ) + unparsedAttributes = unparsedAttributes.slice(cookieAv.length) + } else { // Otherwise: - // 1. Consume the remainder of the unparsed-attributes. - cookieAv = unparsedAttributes - unparsedAttributes = '' - } + // 1. Consume the remainder of the unparsed-attributes. + cookieAv = unparsedAttributes + unparsedAttributes = '' + } - // Let the cookie-av string be the characters consumed in this step. + // Let the cookie-av string be the characters consumed in this step. - let attributeName = '' - let attributeValue = '' + let attributeName = '' + let attributeValue = '' - // 4. If the cookie-av string contains a %x3D ("=") character: - if (cookieAv.includes('=')) { + // 4. If the cookie-av string contains a %x3D ("=") character: + if (cookieAv.includes('=')) { // 1. The (possibly empty) attribute-name string consists of the // characters up to, but not including, the first %x3D ("=") // character, and the (possibly empty) attribute-value string // consists of the characters after the first %x3D ("=") // character. - const position = { position: 0 } - - attributeName = collectASequenceOfCodePointsFast( - '=', - cookieAv, - position - ) - attributeValue = cookieAv.slice(position.position + 1) - } else { + const position = { position: 0 } + + attributeName = collectASequenceOfCodePointsFast( + '=', + cookieAv, + position + ) + attributeValue = cookieAv.slice(position.position + 1) + } else { // Otherwise: - // 1. The attribute-name string consists of the entire cookie-av - // string, and the attribute-value string is empty. - attributeName = cookieAv - } + // 1. The attribute-name string consists of the entire cookie-av + // string, and the attribute-value string is empty. + attributeName = cookieAv + } - // 5. Remove any leading or trailing WSP characters from the attribute- - // name string and the attribute-value string. - attributeName = attributeName.trim() - attributeValue = attributeValue.trim() + // 5. Remove any leading or trailing WSP characters from the attribute- + // name string and the attribute-value string. + attributeName = attributeName.trim() + attributeValue = attributeValue.trim() - // 6. If the attribute-value is longer than 1024 octets, ignore the - // cookie-av string and return to Step 1 of this algorithm. - if (attributeValue.length > maxAttributeValueSize) { - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) - } + // 6. If the attribute-value is longer than 1024 octets, ignore the + // cookie-av string and return to Step 1 of this algorithm. + if (attributeValue.length > maxAttributeValueSize) { + continue + } - // 7. Process the attribute-name and attribute-value according to the - // requirements in the following subsections. (Notice that - // attributes with unrecognized attribute-names are ignored.) - const attributeNameLowercase = attributeName.toLowerCase() + // 7. Process the attribute-name and attribute-value according to the + // requirements in the following subsections. (Notice that + // attributes with unrecognized attribute-names are ignored.) + const attributeNameLowercase = attributeName.toLowerCase() - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.1 - // If the attribute-name case-insensitively matches the string - // "Expires", the user agent MUST process the cookie-av as follows. - if (attributeNameLowercase === 'expires') { + // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.1 + // If the attribute-name case-insensitively matches the string + // "Expires", the user agent MUST process the cookie-av as follows. + if (attributeNameLowercase === 'expires') { // 1. Let the expiry-time be the result of parsing the attribute-value // as cookie-date (see Section 5.1.1). - const expiryTime = new Date(attributeValue) - - // 2. If the attribute-value failed to parse as a cookie date, ignore - // the cookie-av. - if (!Number.isNaN(expiryTime.getTime())) { - cookieAttributeList.expires = expiryTime - } - } else if (attributeNameLowercase === 'max-age') { + const expiryTime = new Date(attributeValue) + + // 2. If the attribute-value failed to parse as a cookie date, ignore + // the cookie-av. + if (!Number.isNaN(expiryTime.getTime())) { + cookieAttributeList.expires = expiryTime + } + } else if (attributeNameLowercase === 'max-age') { // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.2 // If the attribute-name case-insensitively matches the string "Max- // Age", the user agent MUST process the cookie-av as follows. - // 1. If the first character of the attribute-value is not a DIGIT or a - // "-" character, ignore the cookie-av. - const charCode = attributeValue.charCodeAt(0) - - if ((charCode < 48 || charCode > 57) && attributeValue[0] !== '-') { - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) - } - - // 2. If the remainder of attribute-value contains a non-DIGIT - // character, ignore the cookie-av. - if (!/^\d+$/.test(attributeValue)) { - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) - } - - // 3. Let delta-seconds be the attribute-value converted to an integer. - const deltaSeconds = Number(attributeValue) - - // 4. Let cookie-age-limit be the maximum age of the cookie (which - // SHOULD be 400 days or less, see Section 4.1.2.2). - - // 5. Set delta-seconds to the smaller of its present value and cookie- - // age-limit. - // deltaSeconds = Math.min(deltaSeconds * 1000, maxExpiresMs) - - // 6. If delta-seconds is less than or equal to zero (0), let expiry- - // time be the earliest representable date and time. Otherwise, let - // the expiry-time be the current date and time plus delta-seconds - // seconds. - // const expiryTime = deltaSeconds <= 0 ? Date.now() : Date.now() + deltaSeconds - - // 7. Append an attribute to the cookie-attribute-list with an - // attribute-name of Max-Age and an attribute-value of expiry-time. - cookieAttributeList.maxAge = deltaSeconds - } else if (attributeNameLowercase === 'domain') { + // 1. If the first character of the attribute-value is not a DIGIT or a + // "-" character, ignore the cookie-av. + const charCode = attributeValue.charCodeAt(0) + const startsWithDigit = charCode >= 48 && charCode <= 57 + const startsWithSignedDigit = attributeValue[0] === '-' && attributeValue.length > 1 + + if (!startsWithDigit && !startsWithSignedDigit) { + continue + } + + // 2. If the remainder of attribute-value contains a non-DIGIT + // character, ignore the cookie-av. + if (/[^\d]/.test(attributeValue.slice(1))) { + continue + } + + // 3. Let delta-seconds be the attribute-value converted to an integer. + const deltaSeconds = Number(attributeValue) + + // 4. Let cookie-age-limit be the maximum age of the cookie (which + // SHOULD be 400 days or less, see Section 4.1.2.2). + + // 5. Set delta-seconds to the smaller of its present value and cookie- + // age-limit. + // deltaSeconds = Math.min(deltaSeconds * 1000, maxExpiresMs) + + // 6. If delta-seconds is less than or equal to zero (0), let expiry- + // time be the earliest representable date and time. Otherwise, let + // the expiry-time be the current date and time plus delta-seconds + // seconds. + // const expiryTime = deltaSeconds <= 0 ? Date.now() : Date.now() + deltaSeconds + + // 7. Append an attribute to the cookie-attribute-list with an + // attribute-name of Max-Age and an attribute-value of expiry-time. + cookieAttributeList.maxAge = deltaSeconds + } else if (attributeNameLowercase === 'domain') { // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.3 // If the attribute-name case-insensitively matches the string "Domain", // the user agent MUST process the cookie-av as follows. - // 1. Let cookie-domain be the attribute-value. - let cookieDomain = attributeValue + // 1. Let cookie-domain be the attribute-value. + let cookieDomain = attributeValue - // 2. If cookie-domain starts with %x2E ("."), let cookie-domain be - // cookie-domain without its leading %x2E ("."). - if (cookieDomain[0] === '.') { - cookieDomain = cookieDomain.slice(1) - } + // 2. If cookie-domain starts with %x2E ("."), let cookie-domain be + // cookie-domain without its leading %x2E ("."). + if (cookieDomain[0] === '.') { + cookieDomain = cookieDomain.slice(1) + } - // 3. Convert the cookie-domain to lower case. - cookieDomain = cookieDomain.toLowerCase() + // 3. Convert the cookie-domain to lower case. + cookieDomain = cookieDomain.toLowerCase() - // 4. Append an attribute to the cookie-attribute-list with an - // attribute-name of Domain and an attribute-value of cookie-domain. - cookieAttributeList.domain = cookieDomain - } else if (attributeNameLowercase === 'path') { + // 4. Append an attribute to the cookie-attribute-list with an + // attribute-name of Domain and an attribute-value of cookie-domain. + cookieAttributeList.domain = cookieDomain + } else if (attributeNameLowercase === 'path') { // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.4 // If the attribute-name case-insensitively matches the string "Path", // the user agent MUST process the cookie-av as follows. - // 1. If the attribute-value is empty or if the first character of the - // attribute-value is not %x2F ("/"): - let cookiePath = '' - if (attributeValue.length === 0 || attributeValue[0] !== '/') { + // 1. If the attribute-value is empty or if the first character of the + // attribute-value is not %x2F ("/"): + let cookiePath = '' + if (attributeValue.length === 0 || attributeValue[0] !== '/') { // 1. Let cookie-path be the default-path. - cookiePath = '/' - } else { + cookiePath = '/' + } else { // Otherwise: - // 1. Let cookie-path be the attribute-value. - cookiePath = attributeValue - } + // 1. Let cookie-path be the attribute-value. + cookiePath = attributeValue + } - // 2. Append an attribute to the cookie-attribute-list with an - // attribute-name of Path and an attribute-value of cookie-path. - cookieAttributeList.path = cookiePath - } else if (attributeNameLowercase === 'secure') { + // 2. Append an attribute to the cookie-attribute-list with an + // attribute-name of Path and an attribute-value of cookie-path. + cookieAttributeList.path = cookiePath + } else if (attributeNameLowercase === 'secure') { // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.5 // If the attribute-name case-insensitively matches the string "Secure", // the user agent MUST append an attribute to the cookie-attribute-list // with an attribute-name of Secure and an empty attribute-value. - cookieAttributeList.secure = true - } else if (attributeNameLowercase === 'httponly') { + cookieAttributeList.secure = true + } else if (attributeNameLowercase === 'httponly') { // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.6 // If the attribute-name case-insensitively matches the string // "HttpOnly", the user agent MUST append an attribute to the cookie- // attribute-list with an attribute-name of HttpOnly and an empty // attribute-value. - cookieAttributeList.httpOnly = true - } else if (attributeNameLowercase === 'samesite') { + cookieAttributeList.httpOnly = true + } else if (attributeNameLowercase === 'samesite') { // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.7 // If the attribute-name case-insensitively matches the string // "SameSite", the user agent MUST process the cookie-av as follows: - const attributeValueLowercase = attributeValue.toLowerCase() + const attributeValueLowercase = attributeValue.toLowerCase() - // 1. If cookie-av's attribute-value is a case-insensitive match for - // "None", append an attribute to the cookie-attribute-list with an - // attribute-name of "SameSite" and an attribute-value of "None". - if (attributeValueLowercase === 'none') { - cookieAttributeList.sameSite = 'None' - } else if (attributeValueLowercase === 'strict') { + // 1. If cookie-av's attribute-value is a case-insensitive match for + // "None", append an attribute to the cookie-attribute-list with an + // attribute-name of "SameSite" and an attribute-value of "None". + if (attributeValueLowercase === 'none') { + cookieAttributeList.sameSite = 'None' + } else if (attributeValueLowercase === 'strict') { // 2. If cookie-av's attribute-value is a case-insensitive match for // "Strict", append an attribute to the cookie-attribute-list with // an attribute-name of "SameSite" and an attribute-value of // "Strict". - cookieAttributeList.sameSite = 'Strict' - } else if (attributeValueLowercase === 'lax') { + cookieAttributeList.sameSite = 'Strict' + } else if (attributeValueLowercase === 'lax') { // 3. If cookie-av's attribute-value is a case-insensitive match for // "Lax", append an attribute to the cookie-attribute-list with an // attribute-name of "SameSite" and an attribute-value of "Lax". - cookieAttributeList.sameSite = 'Lax' - } - } else { - cookieAttributeList.unparsed ??= [] + cookieAttributeList.sameSite = 'Lax' + } + } else { + cookieAttributeList.unparsed ??= [] - cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`) - } + cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`) + } // 8. Return to Step 1 of this algorithm. - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) + } } module.exports = { diff --git a/deps/undici/src/lib/web/eventsource/eventsource-stream.js b/deps/undici/src/lib/web/eventsource/eventsource-stream.js index 7b9e2f8cbba8..03000e67dd0f 100644 --- a/deps/undici/src/lib/web/eventsource/eventsource-stream.js +++ b/deps/undici/src/lib/web/eventsource/eventsource-stream.js @@ -1,4 +1,5 @@ 'use strict' +const buffer = require('node:buffer') const { Transform } = require('node:stream') const { isASCIINumber, isValidLastEventId } = require('./util') @@ -23,6 +24,8 @@ const COLON = 0x3A */ const SPACE = 0x20 +const defaultMaxEventSize = buffer.kStringMaxLength + const DATA = Buffer.from('data') const EVENT = Buffer.from('event') const ID = Buffer.from('id') @@ -66,6 +69,12 @@ function isFieldName (line, length, field) { return true } +function createMaxEventSizeExceededError () { + const error = new Error('EventSource message size exceeded') + error.aborted = false + return error +} + /** * @typedef {object} EventSourceStreamEvent * @type {object} @@ -114,6 +123,8 @@ class EventSourceStream extends Transform { pos = 0 lineChunkIndex = 0 linePos = 0 + eventDataSize = 0 + maxEventSize event = { data: undefined, @@ -125,6 +136,7 @@ class EventSourceStream extends Transform { /** * @param {object} options * @param {boolean} [options.readableObjectMode] + * @param {number} [options.maxEventSize] * @param {eventSourceSettings} [options.eventSourceSettings] * @param {(chunk: any, encoding?: BufferEncoding | undefined) => boolean} [options.push] */ @@ -136,6 +148,7 @@ class EventSourceStream extends Transform { super(options) this.state = options.eventSourceSettings || {} + this.maxEventSize = options.maxEventSize ?? defaultMaxEventSize if (options.push) { this.push = options.push } @@ -231,7 +244,12 @@ class EventSourceStream extends Transform { // In any case, we can process the line as we reached an // end-of-line character - this.parseLine(this.readLine(), this.event) + try { + this.parseLine(this.readLine(), this.event) + } catch (error) { + callback(error) + return + } this.consumeCurrentByte() // A line was processed and this could be the end of the event. We need // to check if the next line is empty to determine if the event is @@ -282,6 +300,13 @@ class EventSourceStream extends Transform { } if (isFieldName(line, fieldLength, DATA)) { + const valueBytes = line.length - valueStart + const eventDataSize = this.eventDataSize + (event.data === undefined ? 0 : 1) + valueBytes + + if (this.maxEventSize > 0 && eventDataSize > this.maxEventSize) { + throw createMaxEventSizeExceededError() + } + const value = line.toString('utf8', valueStart) if (event.data === undefined) { @@ -289,6 +314,7 @@ class EventSourceStream extends Transform { } else { event.data += `\n${value}` } + this.eventDataSize = eventDataSize return } @@ -345,6 +371,7 @@ class EventSourceStream extends Transform { this.event.event = undefined this.event.id = undefined this.event.retry = undefined + this.eventDataSize = 0 } hasPendingEvent () { diff --git a/deps/undici/src/lib/web/eventsource/eventsource.js b/deps/undici/src/lib/web/eventsource/eventsource.js index 17a1de7b7ba6..657c0643ca88 100644 --- a/deps/undici/src/lib/web/eventsource/eventsource.js +++ b/deps/undici/src/lib/web/eventsource/eventsource.js @@ -7,9 +7,13 @@ const { EventSourceStream } = require('./eventsource-stream') const { parseMIMEType } = require('../fetch/data-url') const { createFastMessageEvent } = require('../websocket/events') const { isNetworkError } = require('../fetch/response') -const { kEnumerableProperty } = require('../../core/util') +const { isValidHeaderValue, kEnumerableProperty } = require('../../core/util') const { environmentSettingsObject } = require('../fetch/util') const { createPotentialCORSRequest } = require('./util') +const { getGlobalDispatcher } = require('../../global') +const { isomorphicDecode } = require('../infra') + +const textEncoder = new TextEncoder() let experimentalWarned = false @@ -281,6 +285,7 @@ class EventSource extends EventTarget { const eventSourceStream = new EventSourceStream({ eventSourceSettings: this.#state, + maxEventSize: this.#dispatcher.eventSourceOptions?.maxEventSize, push: (event) => { this.dispatchEvent(createFastMessageEvent( event.type, @@ -340,8 +345,12 @@ class EventSource extends EventTarget { // string, encoded as UTF-8. // 2. Set (`Last-Event-ID`, lastEventIDValue) in request's header // list. + this.#request.headersList.delete('last-event-id', true) if (this.#state.lastEventId.length) { - this.#request.headersList.set('last-event-id', this.#state.lastEventId, true) + const lastEventId = isomorphicDecode(textEncoder.encode(this.#state.lastEventId)) + if (isValidHeaderValue(lastEventId)) { + this.#request.headersList.set('last-event-id', lastEventId, true) + } } // 4. Fetch request and process the response obtained in this fashion, if any, as described earlier in this section. @@ -465,7 +474,8 @@ webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([ }, { key: 'dispatcher', // undici only - converter: webidl.converters.any + converter: webidl.converters.any, + defaultValue: () => getGlobalDispatcher() }, { key: 'node', // undici only diff --git a/deps/undici/src/lib/web/fetch/index.js b/deps/undici/src/lib/web/fetch/index.js index 935bc9d4c90e..4ac812ad6220 100644 --- a/deps/undici/src/lib/web/fetch/index.js +++ b/deps/undici/src/lib/web/fetch/index.js @@ -59,6 +59,7 @@ const { const EE = require('node:events') const { Readable, pipeline, finished, isErrored, isReadable } = require('node:stream') const { addAbortListener, bufferToLowerCasedHeaderName } = require('../../core/util') +const { SocketError } = require('../../core/errors') const { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require('./data-url') const { getGlobalDispatcher } = require('../../global') const { webidl } = require('../webidl') @@ -2396,6 +2397,11 @@ async function httpNetworkFetch ( // We need to support 200 for websocket over h2 as per RFC-8441 // Absence of session means H1 if ((socket.session != null && status !== 200) || (socket.session == null && status !== 101)) { + if (socket.session != null) { + // The server refused the extended CONNECT, and nothing further + // will settle this request. Fail the opening handshake here. + controller.abort(new SocketError('bad upgrade', null)) + } return false } diff --git a/deps/undici/src/lib/web/fetch/request.js b/deps/undici/src/lib/web/fetch/request.js index dbe809c289c7..56945ec02ee5 100644 --- a/deps/undici/src/lib/web/fetch/request.js +++ b/deps/undici/src/lib/web/fetch/request.js @@ -923,7 +923,7 @@ function makeRequest (init) { serviceWorkers: init.serviceWorkers ?? 'all', initiator: init.initiator ?? '', destination: init.destination ?? '', - priority: init.priority ?? null, + priority: init.priority ?? 'auto', origin: init.origin ?? 'client', policyContainer: init.policyContainer ?? 'client', referrer: init.referrer ?? 'client', @@ -1129,8 +1129,7 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([ { key: 'priority', converter: webidl.converters.DOMString, - allowedValues: ['high', 'low', 'auto'], - defaultValue: () => 'auto' + allowedValues: ['high', 'low', 'auto'] } ]) diff --git a/deps/undici/src/lib/web/fetch/util.js b/deps/undici/src/lib/web/fetch/util.js index eb0ece355b7e..20cbb5c58f6c 100644 --- a/deps/undici/src/lib/web/fetch/util.js +++ b/deps/undici/src/lib/web/fetch/util.js @@ -227,14 +227,19 @@ function TAOCheck () { return 'success' } +// https://w3c.github.io/webappsec-fetch-metadata/#abstract-opdef-append-the-fetch-metadata-headers-for-a-request function appendFetchMetadata (httpRequest) { + // 1. If r’s url is not a potentially trustworthy URL, return. + if (!isURLPotentiallyTrustworthy(requestCurrentURL(httpRequest))) { + return + } + // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-dest-header // TODO // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-mode-header // 1. Assert: r’s url is a potentially trustworthy URL. - // TODO // 2. Let header be a Structured Header whose value is a token. let header = null diff --git a/deps/undici/src/lib/web/webidl/index.js b/deps/undici/src/lib/web/webidl/index.js index 05a6a4bce580..ce81c1e323af 100644 --- a/deps/undici/src/lib/web/webidl/index.js +++ b/deps/undici/src/lib/web/webidl/index.js @@ -26,9 +26,9 @@ const webidl = { /** * @description Instantiate an error. * - * @param {Object} opts - * @param {string} opts.header - * @param {string} opts.message + * @param {Object} message + * @param {string} message.header + * @param {string} message.message * @returns {TypeError} */ webidl.errors.exception = function (message) { diff --git a/deps/undici/src/lib/web/websocket/connection.js b/deps/undici/src/lib/web/websocket/connection.js index 4ecc8a195fcd..cd95d2ca76ec 100644 --- a/deps/undici/src/lib/web/websocket/connection.js +++ b/deps/undici/src/lib/web/websocket/connection.js @@ -200,7 +200,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options) // is specified, the server needs to include the same field and one of // the selected subprotocol values in its response for the connection to // be established. - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(handler, 1002, 'Protocol was not set in the opening handshake.') return } diff --git a/deps/undici/src/lib/web/websocket/permessage-deflate.js b/deps/undici/src/lib/web/websocket/permessage-deflate.js index 6a6e43899c5a..0b3d493db820 100644 --- a/deps/undici/src/lib/web/websocket/permessage-deflate.js +++ b/deps/undici/src/lib/web/websocket/permessage-deflate.js @@ -63,7 +63,12 @@ class PerMessageDeflate { if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()) + // The inflater may still hold buffered input that can emit a late + // zlib error. Remove the data listener, then deterministically stop + // the stream so a subsequent 'error' cannot fire without a listener + // (which would terminate the process as an unhandled error event). this.#inflate.removeAllListeners() + this.#inflate.destroy() this.#inflate = null return } diff --git a/deps/undici/src/lib/web/websocket/stream/websocketstream.js b/deps/undici/src/lib/web/websocket/stream/websocketstream.js index 383fd0bf7aab..1c13a30677dc 100644 --- a/deps/undici/src/lib/web/websocket/stream/websocketstream.js +++ b/deps/undici/src/lib/web/websocket/stream/websocketstream.js @@ -34,9 +34,9 @@ class WebSocketStream { /** @type {ReadableStreamDefaultController} */ #readableStreamController - // Each WebSocketStream object has an associated writable stream , which is a WritableStream . - /** @type {WritableStream} */ - #writableStream + // Retain the controller so the writable stream can be errored while locked. + /** @type {WritableStreamDefaultController} */ + #writableStreamController // Each WebSocketStream object has an associated boolean handshake aborted , which is initially false. #handshakeAborted = false @@ -300,6 +300,9 @@ class WebSocketStream { // 12. Let writable be a new WritableStream . // 13. Set up writable with writeAlgorithm , closeAlgorithm , and abortAlgorithm . const writable = new WritableStream({ + start: (controller) => { + this.#writableStreamController = controller + }, write: (chunk) => this.#write(chunk), close: () => closeWebSocketConnection(this.#handler, null, null), abort: (reason) => this.#closeUsingReason(reason) @@ -308,9 +311,6 @@ class WebSocketStream { // Set stream ’s readable stream to readable . this.#readableStream = readable - // Set stream ’s writable stream to writable . - this.#writableStream = writable - // Resolve stream ’s opened promise with WebSocketOpenInfo «[ " extensions " → extensions , " protocol " → protocol , " readable " → readable , " writable " → writable ]». this.#openedPromise.resolve({ extensions, @@ -396,9 +396,7 @@ class WebSocketStream { readableStreamClose(this.#readableStreamController) // 6.2. Error stream ’s writable stream with an " InvalidStateError " DOMException indicating that a closed WebSocketStream cannot be written to. - if (!this.#writableStream.locked) { - this.#writableStream.abort(new DOMException('A closed WebSocketStream cannot be written to', 'InvalidStateError')) - } + this.#writableStreamController.error(new DOMException('A closed WebSocketStream cannot be written to', 'InvalidStateError')) // 6.3. Resolve stream ’s closed promise with WebSocketCloseInfo «[ " closeCode " → code , " reason " → reason ]». this.#closedPromise.resolve({ @@ -415,7 +413,7 @@ class WebSocketStream { this.#readableStreamController?.error(error) // 7.3. Error stream ’s writable stream with error . - this.#writableStream?.abort(error) + this.#writableStreamController?.error(error) // 7.4. Reject stream ’s closed promise with error . this.#closedPromise.reject(error) diff --git a/deps/undici/src/package-lock.json b/deps/undici/src/package-lock.json index 28d9db8de52e..c0f6d19a83a8 100644 --- a/deps/undici/src/package-lock.json +++ b/deps/undici/src/package-lock.json @@ -1,15 +1,15 @@ { "name": "undici", - "version": "8.10.0", + "version": "8.10.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "undici", - "version": "8.10.0", + "version": "8.10.2", "license": "MIT", "devDependencies": { - "@fastify/busboy": "3.2.0", + "@fastify/busboy": "3.2.2", "@matteo.collina/tspl": "^0.2.0", "@metcoder95/https-pem": "^1.0.0", "@sinonjs/fake-timers": "^12.0.0", @@ -76,13 +76,13 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -91,9 +91,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", - "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -101,21 +101,21 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -132,14 +132,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -149,14 +149,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -166,9 +166,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -176,29 +176,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -208,9 +208,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "dev": true, "license": "MIT", "engines": { @@ -218,9 +218,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -228,9 +228,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -238,9 +238,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -248,27 +248,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -333,13 +333,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -375,13 +375,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", - "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -501,13 +501,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -517,33 +517,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -551,14 +551,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -623,9 +623,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", "cpu": [ "ppc64" ], @@ -640,9 +640,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ "arm" ], @@ -657,9 +657,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], @@ -674,9 +674,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], @@ -691,9 +691,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", "cpu": [ "arm64" ], @@ -708,9 +708,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ "x64" ], @@ -725,9 +725,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], @@ -742,9 +742,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ "x64" ], @@ -759,9 +759,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ "arm" ], @@ -776,9 +776,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", "cpu": [ "arm64" ], @@ -793,9 +793,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", "cpu": [ "ia32" ], @@ -810,9 +810,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", "cpu": [ "loong64" ], @@ -827,9 +827,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", "cpu": [ "mips64el" ], @@ -844,9 +844,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", "cpu": [ "ppc64" ], @@ -861,9 +861,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", "cpu": [ "riscv64" ], @@ -878,9 +878,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", "cpu": [ "s390x" ], @@ -895,9 +895,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", "cpu": [ "x64" ], @@ -912,9 +912,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", "cpu": [ "arm64" ], @@ -929,9 +929,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", "cpu": [ "x64" ], @@ -946,9 +946,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", "cpu": [ "arm64" ], @@ -963,9 +963,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", "cpu": [ "x64" ], @@ -980,9 +980,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", "cpu": [ "arm64" ], @@ -997,9 +997,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", "cpu": [ "x64" ], @@ -1014,9 +1014,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", "cpu": [ "arm64" ], @@ -1031,9 +1031,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", "cpu": [ "ia32" ], @@ -1048,9 +1048,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", "cpu": [ "x64" ], @@ -1209,36 +1209,50 @@ } }, "node_modules/@fastify/busboy": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.2.0.tgz", - "integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.2.2.tgz", + "integrity": "sha512-yXSS27qPExaXeuLvMRMXOLtpipzfQYNjG3FkunDWKGfMYjKuhFXko9CVzqxm8jcF+lmtS9Fd89QNdh9XDjnbNg==", "dev": true, "license": "MIT" }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/gitignore-to-minimatch": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", @@ -1338,9 +1352,9 @@ } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, "license": "MIT", "dependencies": { @@ -1424,17 +1438,17 @@ } }, "node_modules/@jest/console": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.4.1.tgz", - "integrity": "sha512-v3bhyxUh9Hgmo5p6hAOXe14/R3ZxZDOsvHleh4B07z3m/x4/ngPUXEm9XwK4sF4u+f+P2ORb0Ge+MgpaqRMVDA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.5.0.tgz", + "integrity": "sha512-BI1DpOedrJqbrYVi9yNhDWGjqphR/+gsM4STmg2+VaeXm7851hvpBDyKOZGMXATTrGEnFuEseQvLCtrrRmG0GQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.0", "@types/node": "*", "chalk": "^4.1.2", - "jest-message-util": "30.4.1", - "jest-util": "30.4.1", + "jest-message-util": "30.5.0", + "jest-util": "30.5.0", "slash": "^3.0.0" }, "engines": { @@ -1442,18 +1456,18 @@ } }, "node_modules/@jest/core": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.4.2.tgz", - "integrity": "sha512-TZJA6cPJUFxoWhxaLo8t0VX/MZX2wPWr0uIDvLSHIvN4gu9h02vSzqI2kBADG1ExqQlC+cY09xKMSreivvrChQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.5.0.tgz", + "integrity": "sha512-DLjRME+NY//j+UDTSfWnjoP0srrdR3DrJRy7yFZktGIwzpN2iVy2vMo0jziZ5c2Ij7bOwlJRXKVWtxZusazOJg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.4.1", - "@jest/pattern": "30.4.0", - "@jest/reporters": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@jest/console": "30.5.0", + "@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", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", @@ -1461,20 +1475,20 @@ "exit-x": "^0.2.2", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-changed-files": "30.4.1", - "jest-config": "30.4.2", - "jest-haste-map": "30.4.1", - "jest-message-util": "30.4.1", - "jest-regex-util": "30.4.0", - "jest-resolve": "30.4.1", - "jest-resolve-dependencies": "30.4.2", - "jest-runner": "30.4.2", - "jest-runtime": "30.4.2", - "jest-snapshot": "30.4.1", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", - "jest-watcher": "30.4.1", - "pretty-format": "30.4.1", + "jest-changed-files": "30.5.0", + "jest-config": "30.5.0", + "jest-haste-map": "30.5.0", + "jest-message-util": "30.5.0", + "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", "slash": "^3.0.0" }, "engines": { @@ -1490,9 +1504,9 @@ } }, "node_modules/@jest/diff-sequences": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", - "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", + "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", "dev": true, "license": "MIT", "engines": { @@ -1500,61 +1514,61 @@ } }, "node_modules/@jest/environment": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.4.1.tgz", - "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.5.0.tgz", + "integrity": "sha512-HUaqexIauIh69IQ4NTuPDEUCB8g8T4TOPSIzQOS18mwI/KEHKQk1j013K2o6ra031szZE2t5jGmVx3xbzdjgKA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/fake-timers": "30.4.1", - "@jest/types": "30.4.1", + "@jest/fake-timers": "30.5.0", + "@jest/types": "30.5.0", "@types/node": "*", - "jest-mock": "30.4.1" + "jest-mock": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.4.1.tgz", - "integrity": "sha512-ginrj6TMgh2GshLUGCjO94Ptx9HhdZA/I6A9iUfyeLKFtdAjnKzHDgzgP9HYQgbxM1lbXScQ2eUBz2lGeVDPWA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.5.0.tgz", + "integrity": "sha512-jEmgmgJEobJ3zEhDOGp1VAJ6JkoVelpS8uZ1ae1Ul/5lP78UKJKmmU0lciJwd6JdnqOXHaaS/QCKwbf1dHI9MA==", "dev": true, "license": "MIT", "dependencies": { - "expect": "30.4.1", - "jest-snapshot": "30.4.1" + "expect": "30.5.0", + "jest-snapshot": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", - "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.0.tgz", + "integrity": "sha512-5j0ztPxSy3McUJihjkDdCyCfjvT2hxykFTWsgEBZKB8qsw9ALdCiGTpTRH5gnf/d+qI4SflYUJ0dWNbzjQCWbA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0" + "@jest/get-type": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.4.1.tgz", - "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.5.0.tgz", + "integrity": "sha512-sg8xIbYwe5GdB/vT3/0qrDIpO7Ov9mazHi++M95uynmDKEZ70G1r169AWct73H07VrTZhrz1SJEfLtjYv8tE3A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.0", "@sinonjs/fake-timers": "^15.4.0", "@types/node": "*", - "jest-message-util": "30.4.1", - "jest-mock": "30.4.1", - "jest-util": "30.4.1" + "jest-message-util": "30.5.0", + "jest-mock": "30.5.0", + "jest-util": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -1571,9 +1585,9 @@ } }, "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", + "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", "dev": true, "license": "MIT", "engines": { @@ -1581,62 +1595,78 @@ } }, "node_modules/@jest/globals": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.4.1.tgz", - "integrity": "sha512-ZbuY4cmXC8DkxYjfvT2DbcHWL2T6vmsMhXCDcmTB2T0y0gaezBI77ufq5ZAIdcRkYZ7NEQEDg1xFeKbxUJ5v5Q==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.5.0.tgz", + "integrity": "sha512-h7eJx534czwL8lQMYB0hwLT4/HquO8EX/RtYL7RNUHyUyWWVciYjoudN4Ns5JmNvn2/jh0Vm9UstZjEzJJ5EsQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/expect": "30.4.1", - "@jest/types": "30.4.1", - "jest-mock": "30.4.1" + "@jest/environment": "30.5.0", + "@jest/expect": "30.5.0", + "@jest/types": "30.5.0", + "jest-mock": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/pattern": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", - "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", + "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", - "jest-regex-util": "30.4.0" + "jest-regex-util": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/@jest/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/reporters": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.4.1.tgz", - "integrity": "sha512-/SnkPCzEQpUaBH81kjdEdDdo2WZl5hxw+BmLDGWjRkm8o7XlhjwsU36cqwe5PGBE5WYpBvDzRSdXx9rbGuJtNA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.5.0.tgz", + "integrity": "sha512-FEAuusWm+PUOn9ydjaHhpOpyPmS6IbGE04HaKTuUI4zd8eqYZiXiNLoCsdCog/l2XnNj53E9pFy64UltcvfJKg==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", - "@jridgewell/trace-mapping": "^0.3.25", + "@jest/console": "30.5.0", + "@jest/test-result": "30.5.0", + "@jest/transform": "30.5.0", + "@jest/types": "30.5.0", + "@jridgewell/trace-mapping": "^0.3.31", "@types/node": "*", "chalk": "^4.1.2", "collect-v8-coverage": "^1.0.2", "exit-x": "^0.2.2", - "glob": "^10.5.0", + "glob": "^13.0.6", "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "30.4.1", - "jest-util": "30.4.1", - "jest-worker": "30.4.1", + "jest-message-util": "30.5.0", + "jest-util": "30.5.0", + "jest-worker": "30.5.0", "slash": "^3.0.0", "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" @@ -1660,10 +1690,94 @@ "dev": true, "license": "MIT" }, + "node_modules/@jest/reporters/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", "dev": true, "license": "MIT", "dependencies": { @@ -1674,13 +1788,13 @@ } }, "node_modules/@jest/snapshot-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.4.1.tgz", - "integrity": "sha512-ObY4ljvQ95mt6iwKtVLetR/4yXiAgl3H4nJxhztr0MTjrN97TwDYrnCp/kF60Ec9HdhkWTHSu+Hg05aXfngpOA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.5.0.tgz", + "integrity": "sha512-iWQtIsi2dRsO2oWzVceOeynuRJiYTW8gsDVp5wFQ02ipHluQsNgBpasWSHiawVxukIlsGLdCtCSbIEK7fPtpvQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" @@ -1690,14 +1804,15 @@ } }, "node_modules/@jest/source-map": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", - "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.5.0.tgz", + "integrity": "sha512-xWpTJP9D0bDFGbPGT8XuWSwwha/iHADyyKzUnMx4UbdgnHugxrDaQFO4RZ8x4ZsFzRP6pNii8uvlgKCDxCIuDg==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", + "@jridgewell/trace-mapping": "^0.3.31", "callsites": "^3.1.0", + "convert-source-map": "^2.0.0", "graceful-fs": "^4.2.11" }, "engines": { @@ -1705,14 +1820,14 @@ } }, "node_modules/@jest/test-result": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.4.1.tgz", - "integrity": "sha512-/ZG7pgEiOmmWkN9TplKbOu4id2N5lh7FHwRwlkgBVAzGdRH+OkkQ8wX/kIxg4zmd3ZQvAL1RwL2yWsvNYYECTw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.5.0.tgz", + "integrity": "sha512-9IlPqUzUMkVDmoDqSSrVVLroVotgN3hTUPWPwq24XWXhh1Zpg915RXZ5pgRJ/7j4YE/kng5nqjSn4p3S68SZJA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.4.1", - "@jest/types": "30.4.1", + "@jest/console": "30.5.0", + "@jest/types": "30.5.0", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" }, @@ -1721,15 +1836,15 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.4.1.tgz", - "integrity": "sha512-PeYE+4td5rKjoRPxztObrXU+H8hsjZfxKMXOcmrr34JerSyB/ROOxbbicz8B7A5j9R9VayDnVPvBmedqCsFCdw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.5.0.tgz", + "integrity": "sha512-TXlvSDIVv482b83hD8A8WtxDJEmGF47f60W6jRXOQL0Isfs3hKtk4rZIm9R/jLzAibg8+c56y+Q00BQs8R7Xcg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.4.1", + "@jest/test-result": "30.5.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.4.1", + "jest-haste-map": "30.5.0", "slash": "^3.0.0" }, "engines": { @@ -1737,23 +1852,23 @@ } }, "node_modules/@jest/transform": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.4.1.tgz", - "integrity": "sha512-Wz0LyktlTvRefoymh+n64hQ84KNXsRGcwdoZ8CSa0Ea+fgYcHZlnk+hDP7v2MS7il2bQ5uTEIxf4/NNfhMN4KQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.5.0.tgz", + "integrity": "sha512-n1cYhoByyULEIXi64wbT4Lq91qeT1E6bwpM//sprFXhw955qaiHTdAmy1c1rNFGB6fCf1J+nxDUSf3RGwgZP5A==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/types": "30.4.1", - "@jridgewell/trace-mapping": "^0.3.25", - "babel-plugin-istanbul": "^7.0.1", + "@jest/types": "30.5.0", + "@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.4.1", - "jest-regex-util": "30.4.0", - "jest-util": "30.4.1", + "jest-haste-map": "30.5.0", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.0", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" @@ -1763,14 +1878,14 @@ } }, "node_modules/@jest/types": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", - "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.0.tgz", + "integrity": "sha512-s1N+79S4Yp9ZgklCauZXi+YPJdCdtStNYQT32stuD6EeQaIBGHoUfyj2P0YWy8RmuQfaJboO+ulxEvEheR/POQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/pattern": "30.4.0", - "@jest/schemas": "30.4.1", + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", @@ -1860,16 +1975,25 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "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==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "node_modules/@nodelib/fs.scandir": { @@ -1910,6 +2034,311 @@ "node": ">= 8" } }, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1922,13 +2351,13 @@ } }, "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/pkgr" @@ -1953,9 +2382,9 @@ "license": "MIT" }, "node_modules/@sinclair/typebox": { - "version": "0.34.49", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", - "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", "dev": true, "license": "MIT" }, @@ -2023,9 +2452,9 @@ } }, "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "dev": true, "license": "MIT", "optional": true, @@ -2377,16 +2806,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { @@ -2474,16 +2903,16 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", - "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "dev": true, "license": "ISC" }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", "cpu": [ "arm" ], @@ -2495,9 +2924,9 @@ ] }, "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", "cpu": [ "arm64" ], @@ -2509,9 +2938,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", "cpu": [ "arm64" ], @@ -2523,9 +2952,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", "cpu": [ "x64" ], @@ -2537,9 +2966,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", "cpu": [ "x64" ], @@ -2551,9 +2980,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", "cpu": [ "arm" ], @@ -2565,9 +2994,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", "cpu": [ "arm" ], @@ -2579,13 +3008,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2593,13 +3025,50 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2607,13 +3076,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2621,13 +3093,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2635,13 +3110,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2649,13 +3127,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2663,13 +3144,16 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2677,23 +3161,40 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ] }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", "cpu": [ "wasm32" ], @@ -2701,16 +3202,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", "cpu": [ "arm64" ], @@ -2722,9 +3225,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", "cpu": [ "ia32" ], @@ -2736,9 +3239,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", "cpu": [ "x64" ], @@ -3180,16 +3683,16 @@ } }, "node_modules/babel-jest": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.4.1.tgz", - "integrity": "sha512-fATAbM8piYxkiXQp3RBXmZHxZVNJZAVXXfyeyCN2Tida3+qJ8ea9UxhiJ2y4fLO90ZImKt6k9FlcH2+rLkJGhw==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@jest/transform": "30.4.1", + "@jest/transform": "30.5.0", "@types/babel__core": "^7.20.5", - "babel-plugin-istanbul": "^7.0.1", - "babel-preset-jest": "30.4.0", + "babel-plugin-istanbul": "^8.0.0", + "babel-preset-jest": "30.5.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" @@ -3202,9 +3705,9 @@ } }, "node_modules/babel-plugin-istanbul": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", - "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-8.0.0.tgz", + "integrity": "sha512-18wCskrN3DgbuBmp1gr7LBGT8xdz5xhQQqFvFhVxbkl8VBCrMKQ2YtqBWtUal1Zrc1HTuX0011+Brjw78TCFkg==", "dev": true, "license": "BSD-3-Clause", "workspaces": [ @@ -3215,53 +3718,70 @@ "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", - "test-exclude": "^6.0.0" + "test-exclude": "^7.0.1" }, "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/babel-plugin-istanbul/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "node_modules/babel-plugin-istanbul/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "ISC", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "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==", + "dev": true, + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "balanced-match": "^4.0.2" }, "engines": { - "node": "*" + "node": "20 || >=22" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/babel-plugin-istanbul/node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "glob": "^10.4.1", + "minimatch": "^10.2.2" }, "engines": { - "node": ">=8" + "node": ">=18" } }, "node_modules/babel-plugin-jest-hoist": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.4.0.tgz", - "integrity": "sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.5.0.tgz", + "integrity": "sha512-gtGo1B+u14jrZQv6TdSWIWkTqclboo7Qn+dFAGUOIuXLFuJKAdg3U5MIWzZnW4vfUb4dX9skmAMiby86e/SF4A==", "dev": true, "license": "MIT", "dependencies": { @@ -3299,20 +3819,20 @@ } }, "node_modules/babel-preset-jest": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.4.0.tgz", - "integrity": "sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.5.0.tgz", + "integrity": "sha512-ZGPn5ClP4lBDpuOK8W1yQIOy359HmbnZv3suucAlIe+SEE9yDsxV4S2PjSbH2Vc97U+WmzYD7vw3kr8NsQ/i6w==", "dev": true, "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "30.4.0", + "babel-plugin-jest-hoist": "30.5.0", "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + "@babel/core": "^7.11.0 || ^8.0.0-beta.1 || ^8.0.0" } }, "node_modules/balanced-match": { @@ -3323,9 +3843,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.29", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz", - "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3367,16 +3887,16 @@ } }, "node_modules/borp/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/borp/node_modules/c8": { @@ -3504,9 +4024,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -3528,9 +4048,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", "dev": true, "funding": [ { @@ -3548,11 +4068,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" + "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" }, "bin": { "browserslist": "cli.js" @@ -3571,13 +4091,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, "node_modules/c8": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/c8/-/c8-12.0.0.tgz", @@ -3859,9 +4372,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001792", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", - "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "dev": true, "funding": [ { @@ -3923,9 +4436,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", - "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.1.tgz", + "integrity": "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==", "dev": true, "license": "MIT" }, @@ -4269,6 +4782,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -4351,9 +4874,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.354", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.354.tgz", - "integrity": "sha512-JaBHwWcfIdmSAfWM5l3uwjGd431j8YEMikZ+K/2nXVuBqJKyZ0f+2h4n4JY5AyNiZmnY9qQr2RU3v9DxDmHMNg==", + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", "dev": true, "license": "ISC" }, @@ -4518,6 +5041,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -4579,9 +5109,9 @@ } }, "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4592,32 +5122,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" } }, "node_modules/escalade": { @@ -5149,18 +5679,18 @@ } }, "node_modules/expect": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", - "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.0.tgz", + "integrity": "sha512-8fiMWcEjPU7B9nErC4FtFcCzf2tC6I75Qf7m8wzBAWC2taZmcno3yAFEjIQL34SwoGZNgPf63UDiJLyh4SMPaw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.4.1", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.4.1", - "jest-message-util": "30.4.1", - "jest-mock": "30.4.1", - "jest-util": "30.4.1" + "@jest/expect-utils": "30.5.0", + "@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" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -5392,28 +5922,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5631,9 +6139,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -5971,25 +6479,6 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -6515,9 +7004,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -6606,16 +7095,16 @@ } }, "node_modules/jest": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.4.2.tgz", - "integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.5.0.tgz", + "integrity": "sha512-HeFeOUEKh5gjnp1rjuSCse8Dhj0Y3KA8lsZ3azr4Wnq1nCxwMBu35MDc9mp8iblZxmeAz6wV4P241tyUB7J2Ew==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.4.2", - "@jest/types": "30.4.1", + "@jest/core": "30.5.0", + "@jest/types": "30.5.0", "import-local": "^3.2.0", - "jest-cli": "30.4.2" + "jest-cli": "30.5.0" }, "bin": { "jest": "bin/jest.js" @@ -6633,14 +7122,14 @@ } }, "node_modules/jest-changed-files": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.4.1.tgz", - "integrity": "sha512-IuctmYrxi21iOSOaIXpJWalHyPAsVv0GeBHKDn8C1CA4W5htHn7INL+wdnL4Bo0+olEndvAFkmb++tIQJG+vvg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.5.0.tgz", + "integrity": "sha512-dq1x8JiEnHkJDxxOrF6UJDivBRAQMwAa5tzr+VX3um0SfyMFseUPQUbe51wLwggfoa5h/EmOtSpdJxxkzSlNRQ==", "dev": true, "license": "MIT", "dependencies": { "execa": "^5.1.1", - "jest-util": "30.4.1", + "jest-util": "30.5.0", "p-limit": "^3.1.0" }, "engines": { @@ -6738,29 +7227,29 @@ } }, "node_modules/jest-circus": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.4.2.tgz", - "integrity": "sha512-rvHH7VlY6LgbJXJTQ87GW62g1FntOtbhh0zT+v04kC+pgL6aBKyYINXxWukCpj3dcIBMw5/XUbtDS9dU9JTXeQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.5.0.tgz", + "integrity": "sha512-T3v7uM4wwCu+RQicjsAWCgoL3CiyuX3THSKwv2uMb9N2bMUgb+HfwDWEUma85vOGbvQNQ/YfoCXF1OCZot0ZEw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/expect": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/types": "30.4.1", + "@jest/environment": "30.5.0", + "@jest/expect": "30.5.0", + "@jest/test-result": "30.5.0", + "@jest/types": "30.5.0", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", - "jest-each": "30.4.1", - "jest-matcher-utils": "30.4.1", - "jest-message-util": "30.4.1", - "jest-runtime": "30.4.2", - "jest-snapshot": "30.4.1", - "jest-util": "30.4.1", + "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", "p-limit": "^3.1.0", - "pretty-format": "30.4.1", + "pretty-format": "30.5.0", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" @@ -6787,21 +7276,21 @@ "license": "MIT" }, "node_modules/jest-cli": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.4.2.tgz", - "integrity": "sha512-jfA2ocvVHMXS2QijrJ0d31ektP+d/W0T5RpcTX2Pq+3sVqHlsXVCM2+FmwpL+bdY8OfHpIg9xMxLF17Zg0U49Q==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.5.0.tgz", + "integrity": "sha512-QHZMiy32x2K+NzJ1AuuoCAVc1Y5co0VXib3R7kD9MWcWFflzsD1eJN0wR+mkNlM+ts7C+Bjz0oOoFE5IiHylCg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.4.2", - "@jest/test-result": "30.4.1", - "@jest/types": "30.4.1", + "@jest/core": "30.5.0", + "@jest/test-result": "30.5.0", + "@jest/types": "30.5.0", "chalk": "^4.1.2", "exit-x": "^0.2.2", "import-local": "^3.2.0", - "jest-config": "30.4.2", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", + "jest-config": "30.5.0", + "jest-util": "30.5.0", + "jest-validate": "30.5.0", "yargs": "^17.7.2" }, "bin": { @@ -6820,33 +7309,33 @@ } }, "node_modules/jest-config": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.4.2.tgz", - "integrity": "sha512-rNHAShJQqQwFNoL0hbf3BphSBOWnpOUAKvidLS/AjNVLPfoj5mSf4jQMfW3cYOs6hXeZC7nF7mDHaBnbxELOzg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.5.0.tgz", + "integrity": "sha512-gYQl2FqYgiVpyuB7DutBIbJRWaq5VcHdzOXJJ51HNa8J5JrsZehIlzNFW0/9s5uvvcbzM5/LTUizYSbsFErv+w==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/get-type": "30.1.0", - "@jest/pattern": "30.4.0", - "@jest/test-sequencer": "30.4.1", - "@jest/types": "30.4.1", - "babel-jest": "30.4.1", + "@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", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", - "glob": "^10.5.0", + "glob": "^13.0.6", "graceful-fs": "^4.2.11", - "jest-circus": "30.4.2", - "jest-docblock": "30.4.0", - "jest-environment-node": "30.4.1", - "jest-regex-util": "30.4.0", - "jest-resolve": "30.4.1", - "jest-runner": "30.4.2", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", + "jest-circus": "30.5.0", + "jest-docblock": "30.5.0", + "jest-environment-node": "30.5.0", + "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", "parse-json": "^5.2.0", - "pretty-format": "30.4.1", + "pretty-format": "30.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -6870,26 +7359,110 @@ } } }, + "node_modules/jest-config/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-diff": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", - "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.0.tgz", + "integrity": "sha512-QjCfDMwdPFvLxTQmS4/Dswx3PUCiqmSXVLGljMC3SU7YG1qHVoR6b86IH/O2G9k9OMyKXz2vS2Q60VnAozNDwA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.4.0", - "@jest/get-type": "30.1.0", + "@jest/diff-sequences": "30.5.0", + "@jest/get-type": "30.5.0", "chalk": "^4.1.2", - "pretty-format": "30.4.1" + "pretty-format": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-docblock": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.4.0.tgz", - "integrity": "sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.5.0.tgz", + "integrity": "sha512-NwDqcxtoZi33RhuW+zJS/RVA3rmheQ8BnwpYZuc/Eruaz6seQb7+aoCeDZu/3X7W2XmD8DbSo9Pn72DbKsBFYw==", "dev": true, "license": "MIT", "dependencies": { @@ -6900,36 +7473,36 @@ } }, "node_modules/jest-each": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.4.1.tgz", - "integrity": "sha512-/8MJbH6fuj48TstjrMf+u/pd06Qezz5xOXvZA6442heNOWr8bdeoGZX2d9fCn028CoMgYmroH9//zky5GfyYmA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.5.0.tgz", + "integrity": "sha512-NiMFNhRygJEFqYNt8pnkxppUF6CR486GEpt9rSU6lPBf7KeccaOL0zbjxG8fgJgD//6e7zYdssnlt6j+1kI31A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.4.1", + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.0", "chalk": "^4.1.2", - "jest-util": "30.4.1", - "pretty-format": "30.4.1" + "jest-util": "30.5.0", + "pretty-format": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-environment-node": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.4.1.tgz", - "integrity": "sha512-4FZYVOk85hz2AyT6BbarKy9u37g6DbrDyCdFhsnDdXqyrueYQvB+0zO4f/kqLCRD0BsPRXPMNJeQwihKZV8naw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.5.0.tgz", + "integrity": "sha512-bTc79ywKLz0ogbT3JIYuEhgWV4Ffd/cJe06co4v8CyRtlmju8x5gokMlGFR8ARWhmk5SnbDRxmf50XWnlZVhDg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/fake-timers": "30.4.1", - "@jest/types": "30.4.1", + "@jest/environment": "30.5.0", + "@jest/fake-timers": "30.5.0", + "@jest/types": "30.5.0", "@types/node": "*", - "jest-mock": "30.4.1", - "jest-util": "30.4.1", - "jest-validate": "30.4.1" + "jest-mock": "30.5.0", + "jest-util": "30.5.0", + "jest-validate": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -6946,75 +7519,73 @@ } }, "node_modules/jest-haste-map": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.4.1.tgz", - "integrity": "sha512-rFrcONd8jeFsyw+Z9CrScJgglRf2+NFmNam8dKu7n+SoHqNYT47mn0DdEcVUZJpvh7Iz6/si7f7yUH7GJHVgnw==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.0", + "@parcel/watcher": "^2.6.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", + "fdir": "^6.5.0", "graceful-fs": "^4.2.11", - "jest-regex-util": "30.4.0", - "jest-util": "30.4.1", - "jest-worker": "30.4.1", - "picomatch": "^4.0.3", - "walker": "^1.0.8" + "jest-regex-util": "30.5.0", + "jest-util": "30.5.0", + "jest-worker": "30.5.0", + "picomatch": "^4.0.3" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.3" } }, "node_modules/jest-leak-detector": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.4.1.tgz", - "integrity": "sha512-IpmyiioeHxiWDhesHnUFmOxcTzwCwKpgACgWajtAP+nYQXiY7DakTxB6Bx9JFiRMljr0AX1PvnQdaU1KFoz6NQ==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "pretty-format": "30.4.1" + "@jest/get-type": "30.5.0", + "pretty-format": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", - "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", + "@jest/get-type": "30.5.0", "chalk": "^4.1.2", - "jest-diff": "30.4.1", - "pretty-format": "30.4.1" + "jest-diff": "30.5.0", + "pretty-format": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-message-util": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", - "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.0.tgz", + "integrity": "sha512-dBYMhplGfspKaCnVk9TUy1cZnknWubpuPNEputjz0YJk1G/92R45rn45BvbPMPMtC5LVcIdxJGPOaOSQTiuzJw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.4.1", + "@jest/types": "30.5.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-util": "30.4.1", + "jest-util": "30.5.0", "picomatch": "^4.0.3", - "pretty-format": "30.4.1", + "pretty-format": "30.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -7023,42 +7594,25 @@ } }, "node_modules/jest-mock": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", - "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.0.tgz", + "integrity": "sha512-bP5MHZpkYrV7xpV+yvhl36DPcXoEmTR57Un5EACcdVpMY7mpkDefCBq+V4mhcjE/3rwUajT6OTrcJTN7EwN1BA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/expect-utils": "30.5.0", + "@jest/types": "30.5.0", "@types/node": "*", - "jest-util": "30.4.1" + "jest-util": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, "node_modules/jest-regex-util": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", - "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", + "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", "dev": true, "license": "MIT", "engines": { @@ -7066,100 +7620,100 @@ } }, "node_modules/jest-resolve": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.4.1.tgz", - "integrity": "sha512-Zry8Yq/yJcNAZ7dJ5F2heic8AheXvbFZ7XI5V+h28nrYZ7Qoyy4dItq8OodjnYD270mvX+ZudmrNV9cysqhW5Q==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.5.0.tgz", + "integrity": "sha512-NFvQWJ4G7e2kN5712iG+12Xr325NRFGAIhovrwLfgq5Oqd4bFHITw4CzcFkZGp1GTCqemC4v1l8/yZzedKZkjw==", "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.4.1", - "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.4.1", - "jest-validate": "30.4.1", + "jest-haste-map": "30.5.0", + "jest-util": "30.5.0", + "jest-validate": "30.5.0", "slash": "^3.0.0", - "unrs-resolver": "^1.7.11" + "unrs-resolver": "^1.12.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.4.2.tgz", - "integrity": "sha512-gDiVh1I+GxYzz9oXlyw+1wv6VOYX1WYxMOfjsA3iGKePV2oxmbHhwxfkALxNxYy1ciw6APWwkW2zZONwP97aEQ==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "jest-regex-util": "30.4.0", - "jest-snapshot": "30.4.1" + "jest-regex-util": "30.5.0", + "jest-snapshot": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runner": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.4.2.tgz", - "integrity": "sha512-2dw0PslVYXxffXGpLo+Ejad+KcI1Qkjn7f4X4619gf21oCUmL+SPfjqIa/losUem3yEOvfNZe/F1HWUcNpODcg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.5.0.tgz", + "integrity": "sha512-Q6Yt+1LvXvEstvru6sQLT7OQYC77VNl6dK0KEvBkeOHgThmXDqNp3Ox9TglDWFHU85pemqTNdKwxfnmO3vgrdA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.4.1", - "@jest/environment": "30.4.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@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", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-docblock": "30.4.0", - "jest-environment-node": "30.4.1", - "jest-haste-map": "30.4.1", - "jest-leak-detector": "30.4.1", - "jest-message-util": "30.4.1", - "jest-resolve": "30.4.1", - "jest-runtime": "30.4.2", - "jest-util": "30.4.1", - "jest-watcher": "30.4.1", - "jest-worker": "30.4.1", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" + "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", + "p-limit": "^3.1.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-runtime": { - "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.4.2.tgz", - "integrity": "sha512-3/5e8iPz2k/VLqlr8DgTftYyLUv8Su3FkCAO2/Od81UsUTpSxOrS6O5x5KkoQwyUjmpYyDJKeyAvg2T2nvpNkQ==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.5.0.tgz", + "integrity": "sha512-VTRz0sRIw2EISeHigx1O+CMuwoG4+RKJjF8dp8okzFaDNQEcv5Mw0h5QW8VJXgb2CRF4gZIjSEBb2jdzXPagFQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.4.1", - "@jest/fake-timers": "30.4.1", - "@jest/globals": "30.4.1", - "@jest/source-map": "30.0.1", - "@jest/test-result": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@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", "@types/node": "*", "chalk": "^4.1.2", - "cjs-module-lexer": "^2.1.0", + "cjs-module-lexer": "^2.2.0", "collect-v8-coverage": "^1.0.2", - "glob": "^10.5.0", + "es-module-lexer": "^2.1.0", + "glob": "^13.0.6", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.4.1", - "jest-message-util": "30.4.1", - "jest-mock": "30.4.1", - "jest-regex-util": "30.4.0", - "jest-resolve": "30.4.1", - "jest-snapshot": "30.4.1", - "jest-util": "30.4.1", + "jest-haste-map": "30.5.0", + "jest-message-util": "30.5.0", + "jest-mock": "30.5.0", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.0", + "jest-snapshot": "30.5.0", + "jest-util": "30.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -7167,10 +7721,94 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-runtime/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-snapshot": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.4.1.tgz", - "integrity": "sha512-tEOkkfOMppUyeiHwjZswOQ3lcnoTnws/q5FnGIaeIh/jmoU0ZlgMYRR8sTlTj+nNGCoJ0RDq6SfxGxCsyMTPmw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.5.0.tgz", + "integrity": "sha512-pZWETdcqmKve9MDTE/AX6RaeAbRhzKhhAXGozAW8Pg2FfOSdUrQ/7D+VdwE3fLQsqjpITXJVQvYVZoMEzrUl0Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7179,20 +7817,20 @@ "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.4.1", - "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.4.1", - "@jest/transform": "30.4.1", - "@jest/types": "30.4.1", + "@jest/expect-utils": "30.5.0", + "@jest/get-type": "30.5.0", + "@jest/snapshot-utils": "30.5.0", + "@jest/transform": "30.5.0", + "@jest/types": "30.5.0", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", - "expect": "30.4.1", + "expect": "30.5.0", "graceful-fs": "^4.2.11", - "jest-diff": "30.4.1", - "jest-matcher-utils": "30.4.1", - "jest-message-util": "30.4.1", - "jest-util": "30.4.1", - "pretty-format": "30.4.1", + "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", "semver": "^7.7.2", "synckit": "^0.11.8" }, @@ -7201,9 +7839,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -7214,13 +7852,13 @@ } }, "node_modules/jest-util": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", - "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.0.tgz", + "integrity": "sha512-lzU4aGUWaS+2X/B0CmgheDasfnsVlRfZh/rNQxB9b9s8cSYUq5BcqdQA95ld+KqJXBUVVt1sqnMQ2T3OxIalmg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -7232,18 +7870,18 @@ } }, "node_modules/jest-validate": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.4.1.tgz", - "integrity": "sha512-PDWi4SOwLnwqNDfHZjOcsEFyZ4fc/2W2gVL3DEoyqnB6jCQMLRtfBong8s6omIw3lI0HWOus12xfnFmQtjW3fw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.5.0.tgz", + "integrity": "sha512-N/hsPYKgBSzBeVZ2RHCs3yvBbTZNPX7Be8q33zhyo/yeFneBL1swzly31LYU4LJ3zJM9e8TxSM8IYLo2SDJZYQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.4.1", + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "30.4.1" + "pretty-format": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -7263,19 +7901,19 @@ } }, "node_modules/jest-watcher": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.4.1.tgz", - "integrity": "sha512-/l9UonmvCwjHH7d2h3iAwIloLc1H0S8mJZ/LNK3i86hqwPAz8otUJjP9MfYtz9Tt77Su5FD2xGjZn8d31IZHlw==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.4.1", - "@jest/types": "30.4.1", + "@jest/test-result": "30.5.0", + "@jest/types": "30.5.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", - "jest-util": "30.4.1", + "jest-util": "30.5.0", "string-length": "^4.0.2" }, "engines": { @@ -7283,15 +7921,15 @@ } }, "node_modules/jest-worker": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.1.tgz", - "integrity": "sha512-SHynN/q/QD++iNyvMdy+WMmbCGk8jIsNcRxycXbWubSOhvo6T+j2afcfUSl+3hYsiBebOTo0cT7c2H7CXugu1g==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.5.0.tgz", + "integrity": "sha512-7kFk/607EoynNHLJa20daivkElM+c9PrCLduYy6AlMkYrXbh5TmVtW1BLXE05Y8baAFsJHMoC3xs2QRRTotwLw==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.4.1", + "jest-util": "30.5.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" }, @@ -7577,16 +8215,6 @@ "node": ">=10" } }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -7898,6 +8526,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, "node_modules/node-exports-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", @@ -7935,11 +8570,14 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.44", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", - "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/normalize-package-data": { "version": "3.0.3", @@ -8131,16 +8769,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -8326,16 +8954,6 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8544,16 +9162,16 @@ } }, "node_modules/pretty-format": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.0.tgz", + "integrity": "sha512-mzNzBErpHwM0zpmWS7ExOv62yhQhvd546nUuFqVR0dmnJB59tfrw9sjDF0DJknwsr59OXP0buwJ7PaKguczHSg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.4.1", - "ansi-styles": "^5.2.0", - "react-is-18": "npm:react-is@^18.3.1", - "react-is-19": "npm:react-is@^19.2.5" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -8689,22 +9307,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-is-18": { - "name": "react-is", - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-is-19": { - "name": "react-is", - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", - "dev": true, - "license": "MIT" - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -9296,27 +9898,6 @@ "node": ">=8" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -9726,13 +10307,13 @@ } }, "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.9" + "@pkgr/core": "^0.3.6" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -9781,16 +10362,16 @@ } }, "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/test-exclude/node_modules/glob": { @@ -9871,13 +10452,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -10223,9 +10797,9 @@ } }, "node_modules/undici": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", - "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz", + "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==", "dev": true, "license": "MIT", "engines": { @@ -10253,44 +10827,47 @@ } }, "node_modules/unrs-resolver": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", - "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "napi-postinstall": "^0.3.0" + "napi-postinstall": "^0.3.4" }, "funding": { "url": "https://opencollective.com/unrs-resolver" }, "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "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==", "dev": true, "funding": [ { @@ -10354,16 +10931,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10574,13 +11141,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", @@ -10596,9 +11156,9 @@ } }, "node_modules/ws": { - "version": "8.21.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", - "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json index 270b572dfc89..bc78602fe5b9 100644 --- a/deps/undici/src/package.json +++ b/deps/undici/src/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "8.10.0", + "version": "8.10.2", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { @@ -97,7 +97,7 @@ "test:websocket:autobahn": "node test/autobahn/client.js", "test:websocket:autobahn:report": "node test/autobahn/report.js", "test:wpt:setup": "node test/web-platform-tests/wpt-runner.mjs setup", - "test:wpt": "npm run test:wpt:setup && node test/web-platform-tests/wpt-runner.mjs run /fetch /mimesniff /websockets /serviceWorkers /eventsource", + "test:wpt": "npm run test:wpt:setup && node test/web-platform-tests/wpt-runner.mjs run /fetch /mimesniff /xhr /websockets /eventsource", "test:cache-tests": "node test/cache-interceptor/cache-tests.mjs --ci", "coverage": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report", "coverage:ci": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report:ci", @@ -109,7 +109,7 @@ "prepare": "husky && node ./scripts/platform-shell.js" }, "devDependencies": { - "@fastify/busboy": "3.2.0", + "@fastify/busboy": "3.2.2", "@matteo.collina/tspl": "^0.2.0", "@metcoder95/https-pem": "^1.0.0", "@sinonjs/fake-timers": "^12.0.0", diff --git a/deps/undici/src/types/client.d.ts b/deps/undici/src/types/client.d.ts index 064d3d69f2c1..1edaeb05f1e0 100644 --- a/deps/undici/src/types/client.d.ts +++ b/deps/undici/src/types/client.d.ts @@ -80,6 +80,8 @@ export declare namespace Client { maxResponseSize?: number; /** WebSocket-specific options */ webSocket?: Client.WebSocketOptions; + /** EventSource-specific options */ + eventSource?: Client.EventSourceOptions; /** Enables a family autodetection algorithm that loosely implements section 5 of RFC 8305. */ autoSelectFamily?: boolean; /** The amount of time in milliseconds to wait for a connection attempt to finish before trying the next address when using the `autoSelectFamily` option. */ @@ -169,6 +171,14 @@ export declare namespace Client { */ settings?: Omit } + export interface EventSourceOptions { + /** + * Maximum allowed event size in bytes for EventSource messages. + * Set to 0 to disable the limit. + * @default buffer.kStringMaxLength + */ + maxEventSize?: number; + } } export default Client diff --git a/deps/undici/src/types/interceptors.d.ts b/deps/undici/src/types/interceptors.d.ts index d21d717cec51..c11d4017b11e 100644 --- a/deps/undici/src/types/interceptors.d.ts +++ b/deps/undici/src/types/interceptors.d.ts @@ -12,6 +12,8 @@ declare namespace Interceptors { export type DecompressInterceptorOpts = { skipErrorResponses?: boolean skipStatusCodes?: number[] + /** Maximum decompressed response size in bytes. @default 67108864 */ + maxSize?: number } export type ResponseErrorInterceptorOpts = { throwOnError: boolean } diff --git a/deps/undici/src/types/mock-agent.d.ts b/deps/undici/src/types/mock-agent.d.ts index 330926be1919..c718df1a4334 100644 --- a/deps/undici/src/types/mock-agent.d.ts +++ b/deps/undici/src/types/mock-agent.d.ts @@ -6,10 +6,6 @@ import { MockCallHistory } from './mock-call-history' export default MockAgent -interface PendingInterceptor extends MockDispatch { - origin: string; -} - /** A mocked Agent class that implements the Agent API. It allows one to intercept HTTP requests made through undici and return mocked responses instead. */ declare class MockAgent extends Dispatcher { constructor (options?: TMockAgentOptions) @@ -40,17 +36,22 @@ declare class MockAgent key === "dispatch" ? dispatch : target[key], "get") }); @@ -642,6 +654,7 @@ var require_dispatcher = __commonJS({ var require_dispatcher_base = __commonJS({ "lib/dispatcher/dispatcher-base.js"(exports2, module2) { "use strict"; + var buffer = require("node:buffer"); var Dispatcher2 = require_dispatcher(); var { ClientDestroyedError, @@ -652,6 +665,7 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); + var kEventSourceOptions = /* @__PURE__ */ Symbol("eventSourceOptions"); var DispatcherBase = class extends Dispatcher2 { static { __name(this, "DispatcherBase"); @@ -670,9 +684,10 @@ var require_dispatcher_base = __commonJS({ constructor(opts) { super(); this[kWebSocketOptions] = opts?.webSocket ?? {}; + this[kEventSourceOptions] = opts?.eventSource ?? {}; } /** - * @returns {import('../../types/dispatcher').WebSocketOptions} + * @returns {import('../../types/client').Client.WebSocketOptions} */ get webSocketOptions() { return { @@ -681,6 +696,14 @@ var require_dispatcher_base = __commonJS({ // 128 MB default }; } + /** + * @returns {import('../../types/client').Client.EventSourceOptions} + */ + get eventSourceOptions() { + return { + maxEventSize: this[kEventSourceOptions].maxEventSize ?? buffer.kStringMaxLength + }; + } /** @returns {boolean} */ get destroyed() { return this[kDestroyed]; @@ -5425,6 +5448,9 @@ var require_util2 = __commonJS({ } __name(TAOCheck, "TAOCheck"); function appendFetchMetadata(httpRequest) { + if (!isURLPotentiallyTrustworthy(requestCurrentURL(httpRequest))) { + return; + } let header = null; header = httpRequest.mode; httpRequest.headersList.set("sec-fetch-mode", header, true); @@ -7856,7 +7882,7 @@ var require_client_h1 = __commonJS({ __name(onSocketClose, "onSocketClose"); function clearIdleSocketValidation(socket) { if (socket[kIdleSocketValidationTimeout]) { - clearTimeout(socket[kIdleSocketValidationTimeout]); + clearImmediate(socket[kIdleSocketValidationTimeout]); socket[kIdleSocketValidationTimeout] = null; } socket[kIdleSocketValidation] = 0; @@ -7864,14 +7890,13 @@ var require_client_h1 = __commonJS({ __name(clearIdleSocketValidation, "clearIdleSocketValidation"); function scheduleIdleSocketValidation(client, socket) { socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = setImmediate(() => { socket[kIdleSocketValidationTimeout] = null; socket[kIdleSocketValidation] = 2; if (client[kSocket] === socket && !socket.destroyed) { client[kResume](); } - }, 0); - socket[kIdleSocketValidationTimeout].unref?.(); + }); } __name(scheduleIdleSocketValidation, "scheduleIdleSocketValidation"); function resumeH1(client) { @@ -8391,7 +8416,8 @@ var require_client_h2 = __commonJS({ InformationalError, InvalidArgumentError, HeadersTimeoutError, - BodyTimeoutError + BodyTimeoutError, + ResponseExceededMaxSizeError } = require_errors(); var { kUrl, @@ -8420,7 +8446,8 @@ var require_client_h2 = __commonJS({ kRemoteSettings, kHTTP2Stream, kHTTP2SessionState, - kHTTP2Options + kHTTP2Options, + kMaxResponseSize } = require_symbols(); var { channels } = require_diagnostics(); var kOpenStreams = /* @__PURE__ */ Symbol("open streams"); @@ -9175,9 +9202,11 @@ var require_client_h2 = __commonJS({ const state = { abort: null, body: request.body, + bytesRead: 0, client, contentLength: null, expectsPayload: false, + maxResponseSize: client[kMaxResponseSize], request, headersTimeout, bodyTimeout, @@ -9316,6 +9345,7 @@ var require_client_h2 = __commonJS({ stream.once("continue", writeBodyH2); } stream.on("response", onResponse); + stream.on("headers", onInterimResponse); stream.on("end", onEnd); stream.on("error", onError); stream.on("frameError", onFrameError); @@ -9334,6 +9364,7 @@ var require_client_h2 = __commonJS({ stream.off("error", noop); stream.off("continue", writeBodyH2); stream.off("response", onResponse); + stream.off("headers", onInterimResponse); stream.off("end", onEnd); stream.off("error", onError); stream.off("frameError", onFrameError); @@ -9367,15 +9398,35 @@ var require_client_h2 = __commonJS({ if (state == null) { return; } - const { request } = state; + const { request, maxResponseSize } = state; if (request.aborted || request.completed) { return; } + if (maxResponseSize > -1 && state.bytesRead + chunk.length > maxResponseSize) { + state.abort(new ResponseExceededMaxSizeError()); + return; + } + state.bytesRead += chunk.length; if (request.onResponseData(chunk) === false) { stream.pause(); } } __name(onData, "onData"); + function onInterimResponse(headers) { + const stream = this; + const state = stream[kRequestStreamState]; + if (state == null) { + return; + } + const { request } = state; + if (request.aborted || request.completed) { + return; + } + const statusCode = headers[HTTP2_HEADER_STATUS]; + delete headers[HTTP2_HEADER_STATUS]; + request.onResponseStart(Number(statusCode), headers, noop, ""); + } + __name(onInterimResponse, "onInterimResponse"); function onResponse(headers) { const stream = this; const state = stream[kRequestStreamState]; @@ -9816,7 +9867,8 @@ var require_client = __commonJS({ connectionWindowSize, pingInterval, webSocket, - h2Options + h2Options, + eventSource } = {}) { if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); @@ -9919,7 +9971,7 @@ var require_client = __commonJS({ } } } - super({ webSocket }); + super({ webSocket, eventSource }); if (typeof connect2 !== "function") { connect2 = buildConnector({ ...tls, @@ -10420,7 +10472,7 @@ var require_agent = __commonJS({ "lib/dispatcher/agent.js"(exports2, module2) { "use strict"; var { InvalidArgumentError, MaxOriginsReachedError } = require_errors(); - var { kBusy, kClients, kConnected, kRunning, kClose, kDestroy, kDispatch, kUrl } = require_symbols(); + var { kBusy, kClients, kConnected, kRunning, kPending, kClose, kDestroy, kDispatch, kUrl } = require_symbols(); var DispatcherBase = require_dispatcher_base(); var Pool = require_pool(); var Client = require_client(); @@ -10497,7 +10549,7 @@ var require_agent = __commonJS({ if (this[kClients].get(key) !== dispatcher) { return; } - if (dispatcher[kConnected] > 0 || dispatcher[kBusy]) { + if (dispatcher[kConnected] > 0 || dispatcher[kBusy] || dispatcher[kPending] > 0) { return; } this[kClients].delete(key); @@ -10564,6 +10616,7 @@ var require_dispatcher1_wrapper = __commonJS({ var Dispatcher2 = require_dispatcher(); var { InvalidArgumentError } = require_errors(); var { toRawHeaders } = require_util(); + var { kOriginless, kUrl } = require_symbols(); var LegacyHandlerWrapper = class { static { __name(this, "LegacyHandlerWrapper"); @@ -10621,6 +10674,8 @@ var require_dispatcher1_wrapper = __commonJS({ throw new InvalidArgumentError("Argument dispatcher must implement dispatch"); } this.#dispatcher = dispatcher; + this[kUrl] = dispatcher[kUrl]; + this[kOriginless] = dispatcher[kOriginless]; } static wrapHandler(handler) { if (!handler || typeof handler !== "object") { @@ -11230,27 +11285,37 @@ var require_socks5_proxy_agent = __commonJS({ var { URL: URL2 } = require("node:url"); var tls; var DispatcherBase = require_dispatcher_base(); - var { InvalidArgumentError } = require_errors(); + var { ConnectTimeoutError, InvalidArgumentError } = require_errors(); var { Socks5Client, STATES } = require_socks5_client(); var { kBusy, kConnected, kDispatch, kClose, kDestroy } = require_symbols(); var Pool = require_pool(); var buildConnector = require_connect(); + var { setupConnectTimeout } = require_util(); var { debuglog } = require("node:util"); var debug = debuglog("undici:socks5-proxy"); + var DEFAULT_SOCKS5_CONNECT_TIMEOUT = 5e3; var kProxyUrl = /* @__PURE__ */ Symbol("proxy url"); var kProxyHeaders = /* @__PURE__ */ Symbol("proxy headers"); var kProxyAuth = /* @__PURE__ */ Symbol("proxy auth"); var kProxyProtocol = /* @__PURE__ */ Symbol("proxy protocol"); var kPools = /* @__PURE__ */ Symbol("pools"); var kConnector = /* @__PURE__ */ Symbol("connector"); + var kConnectTimeout = /* @__PURE__ */ Symbol("connect timeout"); var kRequestTls = /* @__PURE__ */ Symbol("request tls settings"); + var kRequestTlsTimeout = /* @__PURE__ */ Symbol("request tls timeout"); + function createConnectTimeoutError(hostname, port, timeout) { + return new ConnectTimeoutError( + `Connect Timeout Error (attempted address: ${hostname}:${port}, timeout: ${timeout}ms)` + ); + } + __name(createConnectTimeoutError, "createConnectTimeoutError"); var experimentalWarningEmitted = false; var Socks5ProxyAgent = class extends DispatcherBase { static { __name(this, "Socks5ProxyAgent"); } constructor(proxyUrl, options = {}) { - super(); + super(options); if (!experimentalWarningEmitted) { process.emitWarning( "SOCKS5 proxy support is experimental and subject to change", @@ -11268,13 +11333,29 @@ var require_socks5_proxy_agent = __commonJS({ this[kProxyUrl] = url; this[kProxyHeaders] = options.headers || {}; this[kProxyProtocol] = options.proxyTls ? "https:" : "http:"; - this[kRequestTls] = options.requestTls; + const connectTimeout = options.connectTimeout ?? DEFAULT_SOCKS5_CONNECT_TIMEOUT; + if (!Number.isFinite(connectTimeout) || connectTimeout < 0) { + throw new InvalidArgumentError("invalid connectTimeout"); + } + this[kConnectTimeout] = connectTimeout; + const { timeout, ...requestTls } = options.requestTls || {}; + const requestTlsTimeout = timeout ?? connectTimeout; + if (!Number.isFinite(requestTlsTimeout) || requestTlsTimeout < 0) { + throw new InvalidArgumentError("invalid requestTls.timeout"); + } + this[kRequestTls] = requestTls; + this[kRequestTlsTimeout] = requestTlsTimeout; this[kProxyAuth] = { username: options.username || (url.username ? decodeURIComponent(url.username) : null), password: options.password || (url.password ? decodeURIComponent(url.password) : null) }; + const proxyTlsTimeout = options.proxyTls?.timeout ?? connectTimeout; + if (!Number.isFinite(proxyTlsTimeout) || proxyTlsTimeout < 0) { + throw new InvalidArgumentError("invalid proxyTls.timeout"); + } this[kConnector] = options.connect || buildConnector({ ...options.proxyTls, + timeout: proxyTlsTimeout, servername: options.proxyTls?.servername || url.hostname }); this[kPools] = /* @__PURE__ */ new Map(); @@ -11307,17 +11388,24 @@ var require_socks5_proxy_agent = __commonJS({ }); await socks5Client.handshake(); const authenticationReady = Promise.withResolvers(); - const authenticationTimeout = setTimeout(() => { - authenticationReady.reject(new Error("SOCKS5 authentication timeout")); - }, 5e3); - const onAuthenticated = /* @__PURE__ */ __name(() => { + const authenticationTimeout = this[kConnectTimeout] === 0 ? null : setTimeout(() => { + cleanupAuthenticationListeners(); + socks5Client.destroy(); + authenticationReady.reject( + createConnectTimeoutError(proxyHost, proxyPort, this[kConnectTimeout]) + ); + }, this[kConnectTimeout]); + const cleanupAuthenticationListeners = /* @__PURE__ */ __name(() => { clearTimeout(authenticationTimeout); + socks5Client.removeListener("authenticated", onAuthenticated); socks5Client.removeListener("error", onAuthenticationError); + }, "cleanupAuthenticationListeners"); + const onAuthenticated = /* @__PURE__ */ __name(() => { + cleanupAuthenticationListeners(); authenticationReady.resolve(); }, "onAuthenticated"); const onAuthenticationError = /* @__PURE__ */ __name((err) => { - clearTimeout(authenticationTimeout); - socks5Client.removeListener("authenticated", onAuthenticated); + cleanupAuthenticationListeners(); authenticationReady.reject(err); }, "onAuthenticationError"); if (socks5Client.state === STATES.AUTHENTICATED) { @@ -11330,18 +11418,25 @@ var require_socks5_proxy_agent = __commonJS({ await authenticationReady.promise; await socks5Client.connect(targetHost, targetPort); const connectionReady = Promise.withResolvers(); - const connectionTimeout = setTimeout(() => { - connectionReady.reject(new Error("SOCKS5 connection timeout")); - }, 5e3); - const onConnected = /* @__PURE__ */ __name((info) => { - debug("SOCKS5 tunnel established to", targetHost, targetPort, "via", info); + const connectionTimeout = this[kConnectTimeout] === 0 ? null : setTimeout(() => { + cleanupConnectionListeners(); + socks5Client.destroy(); + connectionReady.reject( + createConnectTimeoutError(targetHost, targetPort, this[kConnectTimeout]) + ); + }, this[kConnectTimeout]); + const cleanupConnectionListeners = /* @__PURE__ */ __name(() => { clearTimeout(connectionTimeout); + socks5Client.removeListener("connected", onConnected); socks5Client.removeListener("error", onConnectionError); + }, "cleanupConnectionListeners"); + const onConnected = /* @__PURE__ */ __name((info) => { + debug("SOCKS5 tunnel established to", targetHost, targetPort, "via", info); + cleanupConnectionListeners(); connectionReady.resolve(); }, "onConnected"); const onConnectionError = /* @__PURE__ */ __name((err) => { - clearTimeout(connectionTimeout); - socks5Client.removeListener("connected", onConnected); + cleanupConnectionListeners(); connectionReady.reject(err); }, "onConnectionError"); socks5Client.once("connected", onConnected); @@ -11381,8 +11476,26 @@ var require_socks5_proxy_agent = __commonJS({ servername: this[kRequestTls]?.servername || targetHost }); const tlsReady = Promise.withResolvers(); - finalSocket.once("secureConnect", tlsReady.resolve); - finalSocket.once("error", tlsReady.reject); + const cleanupTlsListeners = /* @__PURE__ */ __name(() => { + queueMicrotask(clearTlsTimeout); + finalSocket.removeListener("secureConnect", onSecureConnect); + finalSocket.removeListener("error", onTlsError); + }, "cleanupTlsListeners"); + const onSecureConnect = /* @__PURE__ */ __name(() => { + cleanupTlsListeners(); + tlsReady.resolve(); + }, "onSecureConnect"); + const onTlsError = /* @__PURE__ */ __name((err) => { + cleanupTlsListeners(); + tlsReady.reject(err); + }, "onTlsError"); + const clearTlsTimeout = setupConnectTimeout(new WeakRef(finalSocket), { + timeout: this[kRequestTlsTimeout], + hostname: targetHost, + port: targetPort + }); + finalSocket.once("secureConnect", onSecureConnect); + finalSocket.once("error", onTlsError); await tlsReady.promise; } callback(null, finalSocket); @@ -11453,6 +11566,7 @@ var require_proxy_agent = __commonJS({ var Client = require_client(); var { channels } = require_diagnostics(); var Socks5ProxyAgent = require_socks5_proxy_agent(); + var { hasSafeIterator } = require_util(); var kAgent = /* @__PURE__ */ Symbol("proxy agent"); var kClient = /* @__PURE__ */ Symbol("proxy client"); var kProxyHeaders = /* @__PURE__ */ Symbol("proxy headers"); @@ -11549,7 +11663,7 @@ var require_proxy_agent = __commonJS({ throw new InvalidArgumentError("Proxy opts.clientFactory must be a function."); } const { proxyTunnel, connectTimeout } = opts; - super(); + super(opts); const url = this.#getUrl(opts); const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url; this[kProxy] = { uri: href, protocol }; @@ -11582,6 +11696,7 @@ var require_proxy_agent = __commonJS({ factory: agentFactory, username: opts.username || username, password: opts.password || password, + connectTimeout, proxyTls: opts.proxyTls, requestTls: opts.requestTls }); @@ -11723,6 +11838,13 @@ var require_proxy_agent = __commonJS({ } return headersPair; } + if (headers && typeof headers === "object" && hasSafeIterator(headers)) { + const headersPair = {}; + for (const [key, value] of headers) { + headersPair[key] = value; + } + return headersPair; + } return headers; } __name(buildHeaders, "buildHeaders"); @@ -11766,7 +11888,7 @@ var require_env_http_proxy_agent = __commonJS({ #noProxyEntries = null; #opts = null; constructor(opts = {}) { - super(); + super(opts); this.#opts = opts; const { httpProxy, httpsProxy, noProxy, ...agentOpts } = opts; this[kNoProxyAgent] = new Agent(agentOpts); @@ -11806,6 +11928,9 @@ var require_env_http_proxy_agent = __commonJS({ #getProxyAgentForUrl(url) { let { protocol, host: hostname, port } = url; hostname = hostname.replace(/:\d*$/, "").replace(/^\[(.+)\]$/, "$1").toLowerCase(); + if (hostname.length > 1 && hostname.charCodeAt(hostname.length - 1) === 46) { + hostname = hostname.slice(0, -1); + } port = Number.parseInt(port, 10) || DEFAULT_PORTS[protocol] || 0; if (!this.#shouldProxy(hostname, port)) { return this[kNoProxyAgent]; @@ -11861,8 +11986,8 @@ var require_env_http_proxy_agent = __commonJS({ port = parsed ? Number.parseInt(parsed[2], 10) : 0; } noProxyEntries.push({ - // strip leading dot or asterisk with dot - hostname: hostname.replace(/^\*?\./, "").toLowerCase(), + // strip leading dot or asterisk with dot, and any trailing dot + hostname: hostname.replace(/^\*?\./, "").replace(/^(.+)\.$/, "$1").toLowerCase(), port }); } @@ -13386,7 +13511,7 @@ var require_request2 = __commonJS({ serviceWorkers: init.serviceWorkers ?? "all", initiator: init.initiator ?? "", destination: init.destination ?? "", - priority: init.priority ?? null, + priority: init.priority ?? "auto", origin: init.origin ?? "client", policyContainer: init.policyContainer ?? "client", referrer: init.referrer ?? "client", @@ -13558,8 +13683,7 @@ var require_request2 = __commonJS({ { key: "priority", converter: webidl.converters.DOMString, - allowedValues: ["high", "low", "auto"], - defaultValue: /* @__PURE__ */ __name(() => "auto", "defaultValue") + allowedValues: ["high", "low", "auto"] } ]); module2.exports = { @@ -13777,6 +13901,7 @@ var require_fetch = __commonJS({ var EE = require("node:events"); var { Readable, pipeline, finished, isErrored, isReadable } = require("node:stream"); var { addAbortListener, bufferToLowerCasedHeaderName } = require_util(); + var { SocketError } = require_errors(); var { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require_data_url(); var { getGlobalDispatcher: getGlobalDispatcher2 } = require_global2(); var { webidl } = require_webidl(); @@ -14854,6 +14979,9 @@ var require_fetch = __commonJS({ }, onRequestUpgrade(controller, status, headers, socket) { if (socket.session != null && status !== 200 || socket.session == null && status !== 101) { + if (socket.session != null) { + controller.abort(new SocketError("bad upgrade", null)); + } return false; } const rawHeaders = controller?.rawHeaders ?? []; @@ -15605,7 +15733,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request.headersList); - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(handler, 1002, "Protocol was not set in the opening handshake."); return; } @@ -15729,6 +15857,7 @@ var require_permessage_deflate = __commonJS({ if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); + this.#inflate.destroy(); this.#inflate = null; return; } @@ -16768,6 +16897,7 @@ var require_util4 = __commonJS({ var require_eventsource_stream = __commonJS({ "lib/web/eventsource/eventsource-stream.js"(exports2, module2) { "use strict"; + var buffer = require("node:buffer"); var { Transform } = require("node:stream"); var { isASCIINumber, isValidLastEventId } = require_util4(); var BOM = [239, 187, 191]; @@ -16775,25 +16905,26 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var defaultMaxEventSize = buffer.kStringMaxLength; var DATA = Buffer.from("data"); var EVENT = Buffer.from("event"); var ID = Buffer.from("id"); var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { + function isASCIINumberBytes(buffer2, start) { + if (start >= buffer2.length) { return false; } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { + for (let i = start; i < buffer2.length; i++) { + if (buffer2[i] < 48 || buffer2[i] > 57) { return false; } } return true; } __name(isASCIINumberBytes, "isASCIINumberBytes"); - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { + function isValidLastEventIdBytes(buffer2, start) { + for (let i = start; i < buffer2.length; i++) { + if (buffer2[i] === 0) { return false; } } @@ -16812,6 +16943,12 @@ var require_eventsource_stream = __commonJS({ return true; } __name(isFieldName, "isFieldName"); + function createMaxEventSizeExceededError() { + const error = new Error("EventSource message size exceeded"); + error.aborted = false; + return error; + } + __name(createMaxEventSizeExceededError, "createMaxEventSizeExceededError"); var EventSourceStream = class extends Transform { static { __name(this, "EventSourceStream"); @@ -16841,6 +16978,8 @@ var require_eventsource_stream = __commonJS({ pos = 0; lineChunkIndex = 0; linePos = 0; + eventDataSize = 0; + maxEventSize; event = { data: void 0, event: void 0, @@ -16850,6 +16989,7 @@ var require_eventsource_stream = __commonJS({ /** * @param {object} options * @param {boolean} [options.readableObjectMode] + * @param {number} [options.maxEventSize] * @param {eventSourceSettings} [options.eventSourceSettings] * @param {(chunk: any, encoding?: BufferEncoding | undefined) => boolean} [options.push] */ @@ -16857,6 +16997,7 @@ var require_eventsource_stream = __commonJS({ options.readableObjectMode = true; super(options); this.state = options.eventSourceSettings || {}; + this.maxEventSize = options.maxEventSize ?? defaultMaxEventSize; if (options.push) { this.push = options.push; } @@ -16908,7 +17049,12 @@ var require_eventsource_stream = __commonJS({ if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); + try { + this.parseLine(this.readLine(), this.event); + } catch (error) { + callback(error); + return; + } this.consumeCurrentByte(); this.eventEndCheck = true; continue; @@ -16939,6 +17085,11 @@ var require_eventsource_stream = __commonJS({ } } if (isFieldName(line, fieldLength, DATA)) { + const valueBytes = line.length - valueStart; + const eventDataSize = this.eventDataSize + (event.data === void 0 ? 0 : 1) + valueBytes; + if (this.maxEventSize > 0 && eventDataSize > this.maxEventSize) { + throw createMaxEventSizeExceededError(); + } const value = line.toString("utf8", valueStart); if (event.data === void 0) { event.data = value; @@ -16946,6 +17097,7 @@ var require_eventsource_stream = __commonJS({ event.data += ` ${value}`; } + this.eventDataSize = eventDataSize; return; } if (isFieldName(line, fieldLength, RETRY)) { @@ -16993,6 +17145,7 @@ ${value}`; this.event.event = void 0; this.event.id = void 0; this.event.retry = void 0; + this.eventDataSize = 0; } hasPendingEvent() { return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; @@ -17122,9 +17275,12 @@ var require_eventsource = __commonJS({ var { parseMIMEType } = require_data_url(); var { createFastMessageEvent: createFastMessageEvent2 } = require_events(); var { isNetworkError } = require_response(); - var { kEnumerableProperty } = require_util(); + var { isValidHeaderValue, kEnumerableProperty } = require_util(); var { environmentSettingsObject } = require_util2(); var { createPotentialCORSRequest } = require_util4(); + var { getGlobalDispatcher: getGlobalDispatcher2 } = require_global2(); + var { isomorphicDecode } = require_infra(); + var textEncoder = new TextEncoder(); var experimentalWarned = false; var defaultReconnectionTime = 3e3; var CONNECTING = 0; @@ -17261,6 +17417,7 @@ var require_eventsource = __commonJS({ this.#state.origin = response.urlList[response.urlList.length - 1].origin; const eventSourceStream = new EventSourceStream({ eventSourceSettings: this.#state, + maxEventSize: this.#dispatcher.eventSourceOptions?.maxEventSize, push: /* @__PURE__ */ __name((event) => { this.dispatchEvent(createFastMessageEvent2( event.type, @@ -17291,8 +17448,12 @@ var require_eventsource = __commonJS({ this.dispatchEvent(new Event("error")); setTimeout(() => { if (this.#readyState !== CONNECTING) return; + this.#request.headersList.delete("last-event-id", true); if (this.#state.lastEventId.length) { - this.#request.headersList.set("last-event-id", this.#state.lastEventId, true); + const lastEventId = isomorphicDecode(textEncoder.encode(this.#state.lastEventId)); + if (isValidHeaderValue(lastEventId)) { + this.#request.headersList.set("last-event-id", lastEventId, true); + } } this.#connect(); }, this.#state.reconnectionTime)?.unref(); @@ -17397,7 +17558,8 @@ var require_eventsource = __commonJS({ { key: "dispatcher", // undici only - converter: webidl.converters.any + converter: webidl.converters.any, + defaultValue: /* @__PURE__ */ __name(() => getGlobalDispatcher2(), "defaultValue") }, { key: "node", diff --git a/src/undici_version.h b/src/undici_version.h index 8afd91ad6f9a..3dd10c8a2aa7 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.0" +#define UNDICI_VERSION "8.10.2" #endif // SRC_UNDICI_VERSION_H_