deps: update undici to 6.15.0

PR-URL: https://github.com/nodejs/node/pull/52763
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
This commit is contained in:
Khafra 2024-05-02 13:21:22 -04:00 committed by GitHub
parent 08c3256527
commit ae8a5ffcfa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 4925 additions and 4910 deletions

View File

@ -23,7 +23,7 @@ Returns: `Client`
* **headersTimeout** `number | null` (optional) - Default: `300e3` - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
* **keepAliveMaxTimeout** `number | null` (optional) - Default: `600e3` - The maximum allowed `keepAliveTimeout`, in milliseconds, when overridden by *keep-alive* hints from the server. Defaults to 10 minutes.
* **keepAliveTimeout** `number | null` (optional) - Default: `4e3` - The timeout, in milliseconds, after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details. Defaults to 4 seconds.
* **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `1e3` - A number of milliseconds subtracted from server *keep-alive* hints when overriding `keepAliveTimeout` to account for timing inaccuracies caused by e.g. transport latency. Defaults to 1 second.
* **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `2e3` - A number of milliseconds subtracted from server *keep-alive* hints when overriding `keepAliveTimeout` to account for timing inaccuracies caused by e.g. transport latency. Defaults to 2 seconds.
* **maxHeaderSize** `number | null` (optional) - Default: `--max-http-header-size` or `16384` - The maximum length of request headers in bytes. Defaults to Node.js' --max-http-header-size or 16KiB.
* **maxResponseSize** `number | null` (optional) - Default: `-1` - The maximum length of response body in bytes. Set to `-1` to disable.
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.

View File

@ -1,5 +1,7 @@
# EventSource
> ⚠️ Warning: the EventSource API is experimental.
Undici exposes a WHATWG spec-compliant implementation of [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
for [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events).
@ -11,11 +13,33 @@ follows:
```mjs
import { EventSource } from 'undici'
const evenSource = new EventSource('http://localhost:3000')
evenSource.onmessage = (event) => {
const eventSource = new EventSource('http://localhost:3000')
eventSource.onmessage = (event) => {
console.log(event.data)
}
```
## Using a custom Dispatcher
undici allows you to set your own Dispatcher in the EventSource constructor.
An example which allows you to modify the request headers is:
```mjs
import { EventSource, Agent } from 'undici'
class CustomHeaderAgent extends Agent {
dispatch (opts) {
opts.headers['x-custom-header'] = 'hello world'
return super.dispatch(...arguments)
}
}
const eventSource = new EventSource('http://localhost:3000', {
dispatcher: new CustomHeaderAgent()
})
```
More information about the EventSource API can be found on
[MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
[MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).

View File

@ -4,12 +4,6 @@ Undici exposes a fetch() method starts the process of fetching a resource from t
Documentation and examples can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/fetch).
## File
This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/File)
In Node versions v18.13.0 and above and v19.2.0 and above, undici will default to using Node's [File](https://nodejs.org/api/buffer.html#class-file) class. In versions where it's not available, it will default to the undici one.
## FormData
This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData).

View File

@ -1,5 +1,7 @@
'use strict'
const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global')
const EnvHttpProxyAgent = require('./lib/dispatcher/env-http-proxy-agent')
const fetchImpl = require('./lib/web/fetch').fetch
module.exports.fetch = function fetch (resource, init = undefined) {
@ -15,7 +17,16 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
module.exports.Response = require('./lib/web/fetch/response').Response
module.exports.Request = require('./lib/web/fetch/request').Request
const { CloseEvent, ErrorEvent, MessageEvent, createFastMessageEvent } = require('./lib/web/websocket/events')
module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket
module.exports.MessageEvent = require('./lib/web/websocket/events').MessageEvent
module.exports.CloseEvent = CloseEvent
module.exports.ErrorEvent = ErrorEvent
module.exports.MessageEvent = MessageEvent
module.exports.createFastMessageEvent = createFastMessageEvent
module.exports.EventSource = require('./lib/web/eventsource/eventsource').EventSource
// Expose the fetch implementation to be enabled in Node.js core via a flag
module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent
module.exports.getGlobalDispatcher = getGlobalDispatcher
module.exports.setGlobalDispatcher = setGlobalDispatcher

View File

@ -6,6 +6,7 @@ const Pool = require('./lib/dispatcher/pool')
const BalancedPool = require('./lib/dispatcher/balanced-pool')
const Agent = require('./lib/dispatcher/agent')
const ProxyAgent = require('./lib/dispatcher/proxy-agent')
const EnvHttpProxyAgent = require('./lib/dispatcher/env-http-proxy-agent')
const RetryAgent = require('./lib/dispatcher/retry-agent')
const errors = require('./lib/core/errors')
const util = require('./lib/core/util')
@ -30,6 +31,7 @@ module.exports.Pool = Pool
module.exports.BalancedPool = BalancedPool
module.exports.Agent = Agent
module.exports.ProxyAgent = ProxyAgent
module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent
module.exports.RetryAgent = RetryAgent
module.exports.RetryHandler = RetryHandler
@ -116,7 +118,7 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
module.exports.Response = require('./lib/web/fetch/response').Response
module.exports.Request = require('./lib/web/fetch/request').Request
module.exports.FormData = require('./lib/web/fetch/formdata').FormData
module.exports.File = require('./lib/web/fetch/file').File
module.exports.File = globalThis.File ?? require('node:buffer').File
module.exports.FileReader = require('./lib/web/fileapi/filereader').FileReader
const { setGlobalOrigin, getGlobalOrigin } = require('./lib/web/fetch/global')

View File

@ -12,18 +12,25 @@ async function getResolveErrorBodyCallback ({ callback, body, contentType, statu
let chunks = []
let length = 0
for await (const chunk of body) {
chunks.push(chunk)
length += chunk.length
if (length > CHUNK_LIMIT) {
chunks = null
break
try {
for await (const chunk of body) {
chunks.push(chunk)
length += chunk.length
if (length > CHUNK_LIMIT) {
chunks = []
length = 0
break
}
}
} catch {
chunks = []
length = 0
// Do nothing....
}
const message = `Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`
if (statusCode === 204 || !contentType || !chunks) {
if (statusCode === 204 || !contentType || !length) {
queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers)))
return
}

View File

@ -7,7 +7,7 @@ const {
const assert = require('node:assert')
const {
isValidHTTPToken,
isValidHeaderChar,
isValidHeaderValue,
isStream,
destroy,
isBuffer,
@ -336,7 +336,7 @@ function processHeader (request, key, val) {
const arr = []
for (let i = 0; i < val.length; i++) {
if (typeof val[i] === 'string') {
if (!isValidHeaderChar(val[i])) {
if (!isValidHeaderValue(val[i])) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
arr.push(val[i])
@ -350,13 +350,11 @@ function processHeader (request, key, val) {
}
val = arr
} else if (typeof val === 'string') {
if (!isValidHeaderChar(val)) {
if (!isValidHeaderValue(val)) {
throw new InvalidArgumentError(`invalid ${key} header`)
}
} else if (val === null) {
val = ''
} else if (typeof val === 'object') {
throw new InvalidArgumentError(`invalid ${key} header`)
} else {
val = `${val}`
}

View File

@ -60,5 +60,8 @@ module.exports = {
kConstruct: Symbol('constructable'),
kListeners: Symbol('listeners'),
kHTTPContext: Symbol('http context'),
kMaxConcurrentStreams: Symbol('max concurrent streams')
kMaxConcurrentStreams: Symbol('max concurrent streams'),
kNoProxyAgent: Symbol('no proxy agent'),
kHttpProxyAgent: Symbol('http proxy agent'),
kHttpsProxyAgent: Symbol('https proxy agent')
}

View File

@ -52,11 +52,37 @@ function buildURL (url, queryParams) {
return url
}
function isValidPort (port) {
const value = parseInt(port, 10)
return (
value === Number(port) &&
value >= 0 &&
value <= 65535
)
}
function isHttpOrHttpsPrefixed (value) {
return (
value != null &&
value[0] === 'h' &&
value[1] === 't' &&
value[2] === 't' &&
value[3] === 'p' &&
(
value[4] === ':' ||
(
value[4] === 's' &&
value[5] === ':'
)
)
)
}
function parseURL (url) {
if (typeof url === 'string') {
url = new URL(url)
if (!/^https?:/.test(url.origin || url.protocol)) {
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
}
@ -67,12 +93,8 @@ function parseURL (url) {
throw new InvalidArgumentError('Invalid URL: The URL argument must be a non-null object.')
}
if (!/^https?:/.test(url.origin || url.protocol)) {
throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
}
if (!(url instanceof URL)) {
if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) {
if (url.port != null && url.port !== '' && isValidPort(url.port) === false) {
throw new InvalidArgumentError('Invalid URL: port must be a valid integer or a string representation of an integer.')
}
@ -92,28 +114,36 @@ function parseURL (url) {
throw new InvalidArgumentError('Invalid URL origin: the origin must be a string or null/undefined.')
}
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
}
const port = url.port != null
? url.port
: (url.protocol === 'https:' ? 443 : 80)
let origin = url.origin != null
? url.origin
: `${url.protocol}//${url.hostname}:${port}`
: `${url.protocol || ''}//${url.hostname || ''}:${port}`
let path = url.path != null
? url.path
: `${url.pathname || ''}${url.search || ''}`
if (origin.endsWith('/')) {
origin = origin.substring(0, origin.length - 1)
if (origin[origin.length - 1] === '/') {
origin = origin.slice(0, origin.length - 1)
}
if (path && !path.startsWith('/')) {
if (path && path[0] !== '/') {
path = `/${path}`
}
// new URL(path, origin) is unsafe when `path` contains an absolute URL
// From https://developer.mozilla.org/en-US/docs/Web/API/URL/URL:
// If first parameter is a relative URL, second param is required, and will be used as the base URL.
// If first parameter is an absolute URL, a given second param will be ignored.
url = new URL(origin + path)
return new URL(`${origin}${path}`)
}
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
}
return url
@ -193,11 +223,6 @@ function isDestroyed (body) {
return body && !!(body.destroyed || body[kDestroyed] || (stream.isDestroyed?.(body)))
}
function isReadableAborted (stream) {
const state = stream?._readableState
return isDestroyed(stream) && state && !state.endEmitted
}
function destroy (stream, err) {
if (stream == null || !isStream(stream) || isDestroyed(stream)) {
return
@ -522,7 +547,7 @@ const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/
/**
* @param {string} characters
*/
function isValidHeaderChar (characters) {
function isValidHeaderValue (characters) {
return !headerCharRegex.test(characters)
}
@ -575,7 +600,6 @@ module.exports = {
isReadable,
toUSVString,
isUSVString,
isReadableAborted,
isBlobLike,
parseOrigin,
parseURL,
@ -603,11 +627,12 @@ module.exports = {
buildURL,
addAbortListener,
isValidHTTPToken,
isValidHeaderChar,
isValidHeaderValue,
isTokenCharCode,
parseRangeHeader,
isValidPort,
isHttpOrHttpsPrefixed,
nodeMajor,
nodeMinor,
nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13),
safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE']
}

View File

@ -208,10 +208,9 @@ function onHttp2SessionEnd () {
* This is the root cause of #3011
* We need to handle GOAWAY frames properly, and trigger the session close
* along with the socket right away
* Find a way to trigger the close cycle from here on.
*/
function onHTTP2GoAway (code) {
const err = new InformationalError(`HTTP/2: "GOAWAY" frame received with code ${code}`)
const err = new RequestAbortedError(`HTTP/2: "GOAWAY" frame received with code ${code}`)
// We need to trigger the close cycle right away
// We need to destroy the session and the socket
@ -220,8 +219,7 @@ function onHTTP2GoAway (code) {
this[kClient][kOnError](err)
this.unref()
// We send the GOAWAY frame response as no error
this.destroy()
util.destroy(this[kSocket], err)
}

View File

@ -203,7 +203,7 @@ class Client extends DispatcherBase {
allowH2,
socketPath,
timeout: connectTimeout,
...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
...(autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
...connect
})
}
@ -226,7 +226,7 @@ class Client extends DispatcherBase {
this[kMaxHeadersSize] = maxHeaderSize || http.maxHeaderSize
this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout
this[kKeepAliveMaxTimeout] = keepAliveMaxTimeout == null ? 600e3 : keepAliveMaxTimeout
this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold
this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 2e3 : keepAliveTimeoutThreshold
this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout]
this[kServerName] = null
this[kLocalAddress] = localAddress != null ? localAddress : null
@ -376,6 +376,7 @@ function onError (client, err) {
assert(client[kPendingIdx] === client[kRunningIdx])
const requests = client[kQueue].splice(client[kRunningIdx])
for (let i = 0; i < requests.length; i++) {
const request = requests[i]
util.errorRequest(client, request, err)

View File

@ -6,10 +6,8 @@ const {
ClientClosedError,
InvalidArgumentError
} = require('../core/errors')
const { kDestroy, kClose, kDispatch, kInterceptors } = require('../core/symbols')
const { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = require('../core/symbols')
const kDestroyed = Symbol('destroyed')
const kClosed = Symbol('closed')
const kOnDestroyed = Symbol('onDestroyed')
const kOnClosed = Symbol('onClosed')
const kInterceptedDispatch = Symbol('Intercepted Dispatch')

View File

@ -58,7 +58,7 @@ class Pool extends PoolBase {
allowH2,
socketPath,
timeout: connectTimeout,
...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
...(autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
...connect
})
}

View File

@ -7,9 +7,7 @@ const { isDisturbed, parseHeaders, parseRangeHeader } = require('../core/util')
function calculateRetryAfterHeader (retryAfter) {
const current = Date.now()
const diff = new Date(retryAfter).getTime() - current
return diff
return new Date(retryAfter).getTime() - current
}
class RetryHandler {
@ -116,11 +114,7 @@ class RetryHandler {
const { counter } = state
// Any code that is not a Undici's originated and allowed to retry
if (
code &&
code !== 'UND_ERR_REQ_RETRY' &&
!errorCodes.includes(code)
) {
if (code && code !== 'UND_ERR_REQ_RETRY' && !errorCodes.includes(code)) {
cb(err)
return
}
@ -246,10 +240,7 @@ class RetryHandler {
start != null && Number.isFinite(start),
'content-range mismatch'
)
assert(
end != null && Number.isFinite(end),
'invalid content-length'
)
assert(end != null && Number.isFinite(end), 'invalid content-length')
this.start = start
this.end = end
@ -270,6 +261,13 @@ class RetryHandler {
this.resume = resume
this.etag = headers.etag != null ? headers.etag : null
// Weak etags are not useful for comparison nor cache
// for instance not safe to assume if the response is byte-per-byte
// equal
if (this.etag != null && this.etag.startsWith('W/')) {
this.etag = null
}
return this.handler.onHeaders(
statusCode,
rawHeaders,
@ -308,7 +306,9 @@ class RetryHandler {
// and server error response
if (this.retryCount - this.retryCountCheckpoint > 0) {
// We count the difference between the last checkpoint and the current retry count
this.retryCount = this.retryCountCheckpoint + (this.retryCount - this.retryCountCheckpoint)
this.retryCount =
this.retryCountCheckpoint +
(this.retryCount - this.retryCountCheckpoint)
} else {
this.retryCount += 1
}
@ -328,11 +328,18 @@ class RetryHandler {
}
if (this.start !== 0) {
const headers = { range: `bytes=${this.start}-${this.end ?? ''}` }
// Weak etag check - weak etags will make comparison algorithms never match
if (this.etag != null) {
headers['if-match'] = this.etag
}
this.opts = {
...this.opts,
headers: {
...this.opts.headers,
range: `bytes=${this.start}-${this.end ?? ''}`
...headers
}
}
}

View File

@ -1,199 +0,0 @@
import { IEnumMap } from './utils';
export declare type HTTPMode = 'loose' | 'strict';
export declare enum ERROR {
OK = 0,
INTERNAL = 1,
STRICT = 2,
LF_EXPECTED = 3,
UNEXPECTED_CONTENT_LENGTH = 4,
CLOSED_CONNECTION = 5,
INVALID_METHOD = 6,
INVALID_URL = 7,
INVALID_CONSTANT = 8,
INVALID_VERSION = 9,
INVALID_HEADER_TOKEN = 10,
INVALID_CONTENT_LENGTH = 11,
INVALID_CHUNK_SIZE = 12,
INVALID_STATUS = 13,
INVALID_EOF_STATE = 14,
INVALID_TRANSFER_ENCODING = 15,
CB_MESSAGE_BEGIN = 16,
CB_HEADERS_COMPLETE = 17,
CB_MESSAGE_COMPLETE = 18,
CB_CHUNK_HEADER = 19,
CB_CHUNK_COMPLETE = 20,
PAUSED = 21,
PAUSED_UPGRADE = 22,
PAUSED_H2_UPGRADE = 23,
USER = 24
}
export declare enum TYPE {
BOTH = 0,
REQUEST = 1,
RESPONSE = 2
}
export declare enum FLAGS {
CONNECTION_KEEP_ALIVE = 1,
CONNECTION_CLOSE = 2,
CONNECTION_UPGRADE = 4,
CHUNKED = 8,
UPGRADE = 16,
CONTENT_LENGTH = 32,
SKIPBODY = 64,
TRAILING = 128,
TRANSFER_ENCODING = 512
}
export declare enum LENIENT_FLAGS {
HEADERS = 1,
CHUNKED_LENGTH = 2,
KEEP_ALIVE = 4
}
export declare enum METHODS {
DELETE = 0,
GET = 1,
HEAD = 2,
POST = 3,
PUT = 4,
CONNECT = 5,
OPTIONS = 6,
TRACE = 7,
COPY = 8,
LOCK = 9,
MKCOL = 10,
MOVE = 11,
PROPFIND = 12,
PROPPATCH = 13,
SEARCH = 14,
UNLOCK = 15,
BIND = 16,
REBIND = 17,
UNBIND = 18,
ACL = 19,
REPORT = 20,
MKACTIVITY = 21,
CHECKOUT = 22,
MERGE = 23,
'M-SEARCH' = 24,
NOTIFY = 25,
SUBSCRIBE = 26,
UNSUBSCRIBE = 27,
PATCH = 28,
PURGE = 29,
MKCALENDAR = 30,
LINK = 31,
UNLINK = 32,
SOURCE = 33,
PRI = 34,
DESCRIBE = 35,
ANNOUNCE = 36,
SETUP = 37,
PLAY = 38,
PAUSE = 39,
TEARDOWN = 40,
GET_PARAMETER = 41,
SET_PARAMETER = 42,
REDIRECT = 43,
RECORD = 44,
FLUSH = 45
}
export declare const METHODS_HTTP: METHODS[];
export declare const METHODS_ICE: METHODS[];
export declare const METHODS_RTSP: METHODS[];
export declare const METHOD_MAP: IEnumMap;
export declare const H_METHOD_MAP: IEnumMap;
export declare enum FINISH {
SAFE = 0,
SAFE_WITH_CB = 1,
UNSAFE = 2
}
export declare type CharList = Array<string | number>;
export declare const ALPHA: CharList;
export declare const NUM_MAP: {
0: number;
1: number;
2: number;
3: number;
4: number;
5: number;
6: number;
7: number;
8: number;
9: number;
};
export declare const HEX_MAP: {
0: number;
1: number;
2: number;
3: number;
4: number;
5: number;
6: number;
7: number;
8: number;
9: number;
A: number;
B: number;
C: number;
D: number;
E: number;
F: number;
a: number;
b: number;
c: number;
d: number;
e: number;
f: number;
};
export declare const NUM: CharList;
export declare const ALPHANUM: CharList;
export declare const MARK: CharList;
export declare const USERINFO_CHARS: CharList;
export declare const STRICT_URL_CHAR: CharList;
export declare const URL_CHAR: CharList;
export declare const HEX: CharList;
export declare const STRICT_TOKEN: CharList;
export declare const TOKEN: CharList;
export declare const HEADER_CHARS: CharList;
export declare const CONNECTION_TOKEN_CHARS: CharList;
export declare const MAJOR: {
0: number;
1: number;
2: number;
3: number;
4: number;
5: number;
6: number;
7: number;
8: number;
9: number;
};
export declare const MINOR: {
0: number;
1: number;
2: number;
3: number;
4: number;
5: number;
6: number;
7: number;
8: number;
9: number;
};
export declare enum HEADER_STATE {
GENERAL = 0,
CONNECTION = 1,
CONTENT_LENGTH = 2,
TRANSFER_ENCODING = 3,
UPGRADE = 4,
CONNECTION_KEEP_ALIVE = 5,
CONNECTION_CLOSE = 6,
CONNECTION_UPGRADE = 7,
TRANSFER_ENCODING_CHUNKED = 8
}
export declare const SPECIAL_HEADERS: {
connection: HEADER_STATE;
'content-length': HEADER_STATE;
'proxy-connection': HEADER_STATE;
'transfer-encoding': HEADER_STATE;
upgrade: HEADER_STATE;
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +0,0 @@
export interface IEnumMap {
[key: string]: number;
}
export declare function enumToMap(obj: any): IEnumMap;

View File

@ -1 +0,0 @@
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/llhttp/utils.ts"],"names":[],"mappings":";;;AAIA,SAAgB,SAAS,CAAC,GAAQ;IAChC,MAAM,GAAG,GAAa,EAAE,CAAC;IAEzB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC7B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;SAClB;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC;AAXD,8BAWC"}

View File

@ -1,32 +0,0 @@
alpine-baselayout-data-3.4.0-r0
musl-1.2.3-r4
busybox-1.35.0-r29
busybox-binsh-1.35.0-r29
alpine-baselayout-3.4.0-r0
alpine-keys-2.4-r1
ca-certificates-bundle-20220614-r4
libcrypto3-3.0.8-r3
libssl3-3.0.8-r3
ssl_client-1.35.0-r29
zlib-1.2.13-r0
apk-tools-2.12.10-r1
scanelf-1.3.5-r1
musl-utils-1.2.3-r4
libc-utils-0.7.2-r3
libgcc-12.2.1_git20220924-r4
libstdc++-12.2.1_git20220924-r4
libffi-3.4.4-r0
xz-libs-5.2.9-r0
libxml2-2.10.4-r0
zstd-libs-1.5.5-r0
llvm15-libs-15.0.7-r0
clang15-libs-15.0.7-r0
libstdc++-dev-12.2.1_git20220924-r4
clang15-15.0.7-r0
lld-libs-15.0.7-r0
lld-15.0.7-r0
wasi-libc-0.20220525-r1
wasi-libcxx-15.0.7-r0
wasi-libcxxabi-15.0.7-r0
wasi-compiler-rt-15.0.7-r0
wasi-sdk-16-r0

View File

@ -1,5 +1,7 @@
'use strict'
const TICK_MS = 499
let fastNow = Date.now()
let fastNowTimeout
@ -14,7 +16,7 @@ function onTimeout () {
const timer = fastTimers[idx]
if (timer.state === 0) {
timer.state = fastNow + timer.delay
timer.state = fastNow + timer.delay - TICK_MS
} else if (timer.state > 0 && fastNow >= timer.state) {
timer.state = -1
timer.callback(timer.opaque)
@ -43,7 +45,7 @@ function refreshTimeout () {
fastNowTimeout.refresh()
} else {
clearTimeout(fastNowTimeout)
fastNowTimeout = setTimeout(onTimeout, 1e3)
fastNowTimeout = setTimeout(onTimeout, TICK_MS)
if (fastNowTimeout.unref) {
fastNowTimeout.unref()
}
@ -83,7 +85,7 @@ class Timeout {
module.exports = {
setTimeout (callback, delay, opaque) {
return delay < 1e3
return delay <= 1e3
? setTimeout(callback, delay, opaque)
: new Timeout(callback, delay, opaque)
},

View File

@ -42,10 +42,12 @@ class Cache {
async match (request, options = {}) {
webidl.brandCheck(this, Cache)
webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.match' })
request = webidl.converters.RequestInfo(request)
options = webidl.converters.CacheQueryOptions(options)
const prefix = 'Cache.match'
webidl.argumentLengthCheck(arguments, 1, prefix)
request = webidl.converters.RequestInfo(request, prefix, 'request')
options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
const p = this.#internalMatchAll(request, options, 1)
@ -59,17 +61,20 @@ class Cache {
async matchAll (request = undefined, options = {}) {
webidl.brandCheck(this, Cache)
if (request !== undefined) request = webidl.converters.RequestInfo(request)
options = webidl.converters.CacheQueryOptions(options)
const prefix = 'Cache.matchAll'
if (request !== undefined) request = webidl.converters.RequestInfo(request, prefix, 'request')
options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
return this.#internalMatchAll(request, options)
}
async add (request) {
webidl.brandCheck(this, Cache)
webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.add' })
request = webidl.converters.RequestInfo(request)
const prefix = 'Cache.add'
webidl.argumentLengthCheck(arguments, 1, prefix)
request = webidl.converters.RequestInfo(request, prefix, 'request')
// 1.
const requests = [request]
@ -83,7 +88,9 @@ class Cache {
async addAll (requests) {
webidl.brandCheck(this, Cache)
webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.addAll' })
const prefix = 'Cache.addAll'
webidl.argumentLengthCheck(arguments, 1, prefix)
// 1.
const responsePromises = []
@ -95,7 +102,7 @@ class Cache {
for (let request of requests) {
if (request === undefined) {
throw webidl.errors.conversionFailed({
prefix: 'Cache.addAll',
prefix,
argument: 'Argument 1',
types: ['undefined is not allowed']
})
@ -113,7 +120,7 @@ class Cache {
// 3.2
if (!urlIsHttpHttpsScheme(r.url) || r.method !== 'GET') {
throw webidl.errors.exception({
header: 'Cache.addAll',
header: prefix,
message: 'Expected http/s scheme when method is not GET.'
})
}
@ -131,7 +138,7 @@ class Cache {
// 5.2
if (!urlIsHttpHttpsScheme(r.url)) {
throw webidl.errors.exception({
header: 'Cache.addAll',
header: prefix,
message: 'Expected http/s scheme.'
})
}
@ -251,10 +258,12 @@ class Cache {
async put (request, response) {
webidl.brandCheck(this, Cache)
webidl.argumentLengthCheck(arguments, 2, { header: 'Cache.put' })
request = webidl.converters.RequestInfo(request)
response = webidl.converters.Response(response)
const prefix = 'Cache.put'
webidl.argumentLengthCheck(arguments, 2, prefix)
request = webidl.converters.RequestInfo(request, prefix, 'request')
response = webidl.converters.Response(response, prefix, 'response')
// 1.
let innerRequest = null
@ -269,7 +278,7 @@ class Cache {
// 4.
if (!urlIsHttpHttpsScheme(innerRequest.url) || innerRequest.method !== 'GET') {
throw webidl.errors.exception({
header: 'Cache.put',
header: prefix,
message: 'Expected an http/s scheme when method is not GET'
})
}
@ -280,7 +289,7 @@ class Cache {
// 6.
if (innerResponse.status === 206) {
throw webidl.errors.exception({
header: 'Cache.put',
header: prefix,
message: 'Got 206 status'
})
}
@ -295,7 +304,7 @@ class Cache {
// 7.2.1
if (fieldValue === '*') {
throw webidl.errors.exception({
header: 'Cache.put',
header: prefix,
message: 'Got * vary field value'
})
}
@ -305,7 +314,7 @@ class Cache {
// 8.
if (innerResponse.body && (isDisturbed(innerResponse.body.stream) || innerResponse.body.stream.locked)) {
throw webidl.errors.exception({
header: 'Cache.put',
header: prefix,
message: 'Response body is locked or disturbed'
})
}
@ -380,10 +389,12 @@ class Cache {
async delete (request, options = {}) {
webidl.brandCheck(this, Cache)
webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.delete' })
request = webidl.converters.RequestInfo(request)
options = webidl.converters.CacheQueryOptions(options)
const prefix = 'Cache.delete'
webidl.argumentLengthCheck(arguments, 1, prefix)
request = webidl.converters.RequestInfo(request, prefix, 'request')
options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
/**
* @type {Request}
@ -445,8 +456,10 @@ class Cache {
async keys (request = undefined, options = {}) {
webidl.brandCheck(this, Cache)
if (request !== undefined) request = webidl.converters.RequestInfo(request)
options = webidl.converters.CacheQueryOptions(options)
const prefix = 'Cache.keys'
if (request !== undefined) request = webidl.converters.RequestInfo(request, prefix, 'request')
options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
// 1.
let r = null
@ -502,8 +515,7 @@ class Cache {
const requestObject = fromInnerRequest(
request,
new AbortController().signal,
'immutable',
{ settingsObject: request.client }
'immutable'
)
// 5.4.2.1
requestList.push(requestObject)
@ -779,7 +791,7 @@ class Cache {
// 5.5.2
for (const response of responses) {
// 5.5.2.1
const responseObject = fromInnerResponse(response, 'immutable', { settingsObject: {} })
const responseObject = fromInnerResponse(response, 'immutable')
responseList.push(responseObject.clone())
@ -811,17 +823,17 @@ const cacheQueryOptionConverters = [
{
key: 'ignoreSearch',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'ignoreMethod',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'ignoreVary',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
}
]

View File

@ -20,7 +20,7 @@ class CacheStorage {
async match (request, options = {}) {
webidl.brandCheck(this, CacheStorage)
webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.match' })
webidl.argumentLengthCheck(arguments, 1, 'CacheStorage.match')
request = webidl.converters.RequestInfo(request)
options = webidl.converters.MultiCacheQueryOptions(options)
@ -57,9 +57,11 @@ class CacheStorage {
*/
async has (cacheName) {
webidl.brandCheck(this, CacheStorage)
webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.has' })
cacheName = webidl.converters.DOMString(cacheName)
const prefix = 'CacheStorage.has'
webidl.argumentLengthCheck(arguments, 1, prefix)
cacheName = webidl.converters.DOMString(cacheName, prefix, 'cacheName')
// 2.1.1
// 2.2
@ -73,9 +75,11 @@ class CacheStorage {
*/
async open (cacheName) {
webidl.brandCheck(this, CacheStorage)
webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.open' })
cacheName = webidl.converters.DOMString(cacheName)
const prefix = 'CacheStorage.open'
webidl.argumentLengthCheck(arguments, 1, prefix)
cacheName = webidl.converters.DOMString(cacheName, prefix, 'cacheName')
// 2.1
if (this.#caches.has(cacheName)) {
@ -105,9 +109,11 @@ class CacheStorage {
*/
async delete (cacheName) {
webidl.brandCheck(this, CacheStorage)
webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.delete' })
cacheName = webidl.converters.DOMString(cacheName)
const prefix = 'CacheStorage.delete'
webidl.argumentLengthCheck(arguments, 1, prefix)
cacheName = webidl.converters.DOMString(cacheName, prefix, 'cacheName')
return this.#caches.delete(cacheName)
}

View File

@ -24,7 +24,7 @@ const { Headers } = require('../fetch/headers')
* @returns {Record<string, string>}
*/
function getCookies (headers) {
webidl.argumentLengthCheck(arguments, 1, { header: 'getCookies' })
webidl.argumentLengthCheck(arguments, 1, 'getCookies')
webidl.brandCheck(headers, Headers, { strict: false })
@ -51,11 +51,12 @@ function getCookies (headers) {
* @returns {void}
*/
function deleteCookie (headers, name, attributes) {
webidl.argumentLengthCheck(arguments, 2, { header: 'deleteCookie' })
webidl.brandCheck(headers, Headers, { strict: false })
name = webidl.converters.DOMString(name)
const prefix = 'deleteCookie'
webidl.argumentLengthCheck(arguments, 2, prefix)
name = webidl.converters.DOMString(name, prefix, 'name')
attributes = webidl.converters.DeleteCookieAttributes(attributes)
// Matches behavior of
@ -73,7 +74,7 @@ function deleteCookie (headers, name, attributes) {
* @returns {Cookie[]}
*/
function getSetCookies (headers) {
webidl.argumentLengthCheck(arguments, 1, { header: 'getSetCookies' })
webidl.argumentLengthCheck(arguments, 1, 'getSetCookies')
webidl.brandCheck(headers, Headers, { strict: false })
@ -93,7 +94,7 @@ function getSetCookies (headers) {
* @returns {void}
*/
function setCookie (headers, cookie) {
webidl.argumentLengthCheck(arguments, 2, { header: 'setCookie' })
webidl.argumentLengthCheck(arguments, 2, 'setCookie')
webidl.brandCheck(headers, Headers, { strict: false })
@ -110,12 +111,12 @@ webidl.converters.DeleteCookieAttributes = webidl.dictionaryConverter([
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'path',
defaultValue: null
defaultValue: () => null
},
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'domain',
defaultValue: null
defaultValue: () => null
}
])
@ -137,32 +138,32 @@ webidl.converters.Cookie = webidl.dictionaryConverter([
return new Date(value)
}),
key: 'expires',
defaultValue: null
defaultValue: () => null
},
{
converter: webidl.nullableConverter(webidl.converters['long long']),
key: 'maxAge',
defaultValue: null
defaultValue: () => null
},
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'domain',
defaultValue: null
defaultValue: () => null
},
{
converter: webidl.nullableConverter(webidl.converters.DOMString),
key: 'path',
defaultValue: null
defaultValue: () => null
},
{
converter: webidl.nullableConverter(webidl.converters.boolean),
key: 'secure',
defaultValue: null
defaultValue: () => null
},
{
converter: webidl.nullableConverter(webidl.converters.boolean),
key: 'httpOnly',
defaultValue: null
defaultValue: () => null
},
{
converter: webidl.converters.USVString,
@ -172,7 +173,7 @@ webidl.converters.Cookie = webidl.dictionaryConverter([
{
converter: webidl.sequenceConverter(webidl.converters.DOMString),
key: 'unparsed',
defaultValue: []
defaultValue: () => new Array(0)
}
])

View File

@ -3,14 +3,14 @@
const { pipeline } = require('node:stream')
const { fetching } = require('../fetch')
const { makeRequest } = require('../fetch/request')
const { getGlobalOrigin } = require('../fetch/global')
const { webidl } = require('../fetch/webidl')
const { EventSourceStream } = require('./eventsource-stream')
const { parseMIMEType } = require('../fetch/data-url')
const { MessageEvent } = require('../websocket/events')
const { createFastMessageEvent } = require('../websocket/events')
const { isNetworkError } = require('../fetch/response')
const { delay } = require('./util')
const { kEnumerableProperty } = require('../../core/util')
const { environmentSettingsObject } = require('../fetch/util')
let experimentalWarned = false
@ -65,12 +65,6 @@ const ANONYMOUS = 'anonymous'
*/
const USE_CREDENTIALS = 'use-credentials'
/**
* @typedef {object} EventSourceInit
* @property {boolean} [withCredentials] indicates whether the request
* should include credentials.
*/
/**
* The EventSource interface is used to receive server-sent events. It
* connects to a server over HTTP and receives events in text/event-stream
@ -94,13 +88,12 @@ class EventSource extends EventTarget {
#request = null
#controller = null
#dispatcher
/**
* @type {object}
* @property {string} lastEventId
* @property {number} reconnectionTime
* @property {any} reconnectionTimer
* @type {import('./eventsource-stream').eventSourceSettings}
*/
#settings = null
#state
/**
* Creates a new EventSource object.
@ -112,7 +105,8 @@ class EventSource extends EventTarget {
// 1. Let ev be a new EventSource object.
super()
webidl.argumentLengthCheck(arguments, 1, { header: 'EventSource constructor' })
const prefix = 'EventSource constructor'
webidl.argumentLengthCheck(arguments, 1, prefix)
if (!experimentalWarned) {
experimentalWarned = true
@ -121,26 +115,25 @@ class EventSource extends EventTarget {
})
}
url = webidl.converters.USVString(url)
eventSourceInitDict = webidl.converters.EventSourceInitDict(eventSourceInitDict)
url = webidl.converters.USVString(url, prefix, 'url')
eventSourceInitDict = webidl.converters.EventSourceInitDict(eventSourceInitDict, prefix, 'eventSourceInitDict')
// 2. Let settings be ev's relevant settings object.
// https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
this.#settings = {
origin: getGlobalOrigin(),
policyContainer: {
referrerPolicy: 'no-referrer'
},
this.#dispatcher = eventSourceInitDict.dispatcher
this.#state = {
lastEventId: '',
reconnectionTime: defaultReconnectionTime
}
// 2. Let settings be ev's relevant settings object.
// https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
const settings = environmentSettingsObject
let urlRecord
try {
// 3. Let urlRecord be the result of encoding-parsing a URL given url, relative to settings.
urlRecord = new URL(url, this.#settings.origin)
this.#settings.origin = urlRecord.origin
urlRecord = new URL(url, settings.settingsObject.baseUrl)
this.#state.origin = urlRecord.origin
} catch (e) {
// 4. If urlRecord is failure, then throw a "SyntaxError" DOMException.
throw new DOMException(e, 'SyntaxError')
@ -174,7 +167,7 @@ class EventSource extends EventTarget {
}
// 9. Set request's client to settings.
initRequest.client = this.#settings
initRequest.client = environmentSettingsObject.settingsObject
// 10. User agents may set (`Accept`, `text/event-stream`) in request's header list.
initRequest.headersList = [['accept', { name: 'accept', value: 'text/event-stream' }]]
@ -225,8 +218,9 @@ class EventSource extends EventTarget {
this.#readyState = CONNECTING
const fetchParam = {
request: this.#request
const fetchParams = {
request: this.#request,
dispatcher: this.#dispatcher
}
// 14. Let processEventSourceEndOfBody given response res be the following step: if res is not a network error, then reestablish the connection.
@ -240,10 +234,10 @@ class EventSource extends EventTarget {
}
// 15. Fetch request, with processResponseEndOfBody set to processEventSourceEndOfBody...
fetchParam.processResponseEndOfBody = processEventSourceEndOfBody
fetchParams.processResponseEndOfBody = processEventSourceEndOfBody
// and processResponse set to the following steps given response res:
fetchParam.processResponse = (response) => {
fetchParams.processResponse = (response) => {
// 1. If res is an aborted network error, then fail the connection.
if (isNetworkError(response)) {
@ -292,12 +286,12 @@ class EventSource extends EventTarget {
this.dispatchEvent(new Event('open'))
// If redirected to a different origin, set the origin to the new origin.
this.#settings.origin = response.urlList[response.urlList.length - 1].origin
this.#state.origin = response.urlList[response.urlList.length - 1].origin
const eventSourceStream = new EventSourceStream({
eventSourceSettings: this.#settings,
eventSourceSettings: this.#state,
push: (event) => {
this.dispatchEvent(new MessageEvent(
this.dispatchEvent(createFastMessageEvent(
event.type,
event.options
))
@ -316,7 +310,7 @@ class EventSource extends EventTarget {
})
}
this.#controller = fetching(fetchParam)
this.#controller = fetching(fetchParams)
}
/**
@ -341,7 +335,7 @@ class EventSource extends EventTarget {
this.dispatchEvent(new Event('error'))
// 2. Wait a delay equal to the reconnection time of the event source.
await delay(this.#settings.reconnectionTime)
await delay(this.#state.reconnectionTime)
// 5. Queue a task to run the following steps:
@ -356,8 +350,8 @@ class EventSource extends EventTarget {
// string, encoded as UTF-8.
// 2. Set (`Last-Event-ID`, lastEventIDValue) in request's header
// list.
if (this.#settings.lastEventId !== '') {
this.#request.headersList.set('last-event-id', this.#settings.lastEventId, true)
if (this.#state.lastEventId.length) {
this.#request.headersList.set('last-event-id', this.#state.lastEventId, true)
}
// 4. Fetch request and process the response obtained in this fashion, if any, as described earlier in this section.
@ -373,12 +367,8 @@ class EventSource extends EventTarget {
if (this.#readyState === CLOSED) return
this.#readyState = CLOSED
clearTimeout(this.#settings.reconnectionTimer)
this.#controller.abort()
if (this.#request) {
this.#request = null
}
this.#request = null
}
get onopen () {
@ -471,7 +461,15 @@ Object.defineProperties(EventSource.prototype, {
})
webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([
{ key: 'withCredentials', converter: webidl.converters.boolean, defaultValue: false }
{
key: 'withCredentials',
converter: webidl.converters.boolean,
defaultValue: () => false
},
{
key: 'dispatcher', // undici only
converter: webidl.converters.any
}
])
module.exports = {

View File

@ -309,7 +309,7 @@ function bodyMixinMethods (instance) {
// Return a Blob whose contents are bytes and type attribute
// is mimeType.
return new Blob([bytes], { type: mimeType })
}, instance)
}, instance, false)
},
arrayBuffer () {
@ -318,20 +318,21 @@ function bodyMixinMethods (instance) {
// given a byte sequence bytes: return a new ArrayBuffer
// whose contents are bytes.
return consumeBody(this, (bytes) => {
return new Uint8Array(bytes).buffer
}, instance)
// Note: arrayBuffer already cloned.
return bytes.buffer
}, instance, true)
},
text () {
// The text() method steps are to return the result of running
// consume body with this and UTF-8 decode.
return consumeBody(this, utf8DecodeBytes, instance)
return consumeBody(this, utf8DecodeBytes, instance, false)
},
json () {
// The json() method steps are to return the result of running
// consume body with this and parse JSON from bytes.
return consumeBody(this, parseJSONFromBytes, instance)
return consumeBody(this, parseJSONFromBytes, instance, false)
},
formData () {
@ -383,7 +384,7 @@ function bodyMixinMethods (instance) {
throw new TypeError(
'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".'
)
}, instance)
}, instance, false)
}
}
@ -399,14 +400,15 @@ function mixinBody (prototype) {
* @param {Response|Request} object
* @param {(value: unknown) => unknown} convertBytesToJSValue
* @param {Response|Request} instance
* @param {boolean} [shouldClone]
*/
async function consumeBody (object, convertBytesToJSValue, instance) {
async function consumeBody (object, convertBytesToJSValue, instance, shouldClone) {
webidl.brandCheck(object, instance)
// 1. If object is unusable, then return a promise rejected
// with a TypeError.
if (bodyUnusable(object[kState].body)) {
throw new TypeError('Body is unusable')
throw new TypeError('Body is unusable: Body has already been read')
}
throwIfAborted(object[kState])
@ -432,13 +434,13 @@ async function consumeBody (object, convertBytesToJSValue, instance) {
// 5. If objects body is null, then run successSteps with an
// empty byte sequence.
if (object[kState].body == null) {
successSteps(new Uint8Array())
successSteps(Buffer.allocUnsafe(0))
return promise.promise
}
// 6. Otherwise, fully read objects body given successSteps,
// errorSteps, and objects relevant global object.
await fullyReadBody(object[kState].body, successSteps, errorSteps)
await fullyReadBody(object[kState].body, successSteps, errorSteps, shouldClone)
// 7. Return promise.
return promise.promise

View File

@ -33,9 +33,10 @@ class CompatFinalizer {
}
module.exports = function () {
// FIXME: remove workaround when the Node bug is fixed
// FIXME: remove workaround when the Node bug is backported to v18
// https://github.com/nodejs/node/issues/49344#issuecomment-1741776308
if (process.env.NODE_V8_COVERAGE) {
if (process.env.NODE_V8_COVERAGE && process.version.startsWith('v18')) {
process._rawDebug('Using compatibility WeakRef and FinalizationRegistry')
return {
WeakRef: CompatWeakRef,
FinalizationRegistry: CompatFinalizer

View File

@ -1,100 +1,10 @@
'use strict'
const { EOL } = require('node:os')
const { Blob, File: NativeFile } = require('node:buffer')
const { types } = require('node:util')
const { Blob, File } = require('node:buffer')
const { kState } = require('./symbols')
const { isBlobLike } = require('./util')
const { webidl } = require('./webidl')
const { parseMIMEType, serializeAMimeType } = require('./data-url')
const { kEnumerableProperty } = require('../../core/util')
const encoder = new TextEncoder()
class File extends Blob {
constructor (fileBits, fileName, options = {}) {
// The File constructor is invoked with two or three parameters, depending
// on whether the optional dictionary parameter is used. When the File()
// constructor is invoked, user agents must run the following steps:
webidl.argumentLengthCheck(arguments, 2, { header: 'File constructor' })
fileBits = webidl.converters['sequence<BlobPart>'](fileBits)
fileName = webidl.converters.USVString(fileName)
options = webidl.converters.FilePropertyBag(options)
// 1. Let bytes be the result of processing blob parts given fileBits and
// options.
// Note: Blob handles this for us
// 2. Let n be the fileName argument to the constructor.
const n = fileName
// 3. Process FilePropertyBag dictionary argument by running the following
// substeps:
// 1. If the type member is provided and is not the empty string, let t
// be set to the type dictionary member. If t contains any characters
// outside the range U+0020 to U+007E, then set t to the empty string
// and return from these substeps.
// 2. Convert every character in t to ASCII lowercase.
let t = options.type
let d
// eslint-disable-next-line no-labels
substep: {
if (t) {
t = parseMIMEType(t)
if (t === 'failure') {
t = ''
// eslint-disable-next-line no-labels
break substep
}
t = serializeAMimeType(t).toLowerCase()
}
// 3. If the lastModified member is provided, let d be set to the
// lastModified dictionary member. If it is not provided, set d to the
// current date and time represented as the number of milliseconds since
// the Unix Epoch (which is the equivalent of Date.now() [ECMA-262]).
d = options.lastModified
}
// 4. Return a new File object F such that:
// F refers to the bytes byte sequence.
// F.size is set to the number of total bytes in bytes.
// F.name is set to n.
// F.type is set to t.
// F.lastModified is set to d.
super(processBlobParts(fileBits, options), { type: t })
this[kState] = {
name: n,
lastModified: d,
type: t
}
}
get name () {
webidl.brandCheck(this, File)
return this[kState].name
}
get lastModified () {
webidl.brandCheck(this, File)
return this[kState].lastModified
}
get type () {
webidl.brandCheck(this, File)
return this[kState].type
}
}
// TODO(@KhafraDev): remove
class FileLike {
constructor (blobLike, fileName, options = {}) {
// TODO: argument idl type check
@ -196,136 +106,15 @@ class FileLike {
}
}
Object.defineProperties(File.prototype, {
[Symbol.toStringTag]: {
value: 'File',
configurable: true
},
name: kEnumerableProperty,
lastModified: kEnumerableProperty
})
webidl.converters.Blob = webidl.interfaceConverter(Blob)
webidl.converters.BlobPart = function (V, opts) {
if (webidl.util.Type(V) === 'Object') {
if (isBlobLike(V)) {
return webidl.converters.Blob(V, { strict: false })
}
if (ArrayBuffer.isView(V) || types.isAnyArrayBuffer(V)) {
return webidl.converters.BufferSource(V, opts)
}
}
return webidl.converters.USVString(V, opts)
}
webidl.converters['sequence<BlobPart>'] = webidl.sequenceConverter(
webidl.converters.BlobPart
)
// https://www.w3.org/TR/FileAPI/#dfn-FilePropertyBag
webidl.converters.FilePropertyBag = webidl.dictionaryConverter([
{
key: 'lastModified',
converter: webidl.converters['long long'],
get defaultValue () {
return Date.now()
}
},
{
key: 'type',
converter: webidl.converters.DOMString,
defaultValue: ''
},
{
key: 'endings',
converter: (value) => {
value = webidl.converters.DOMString(value)
value = value.toLowerCase()
if (value !== 'native') {
value = 'transparent'
}
return value
},
defaultValue: 'transparent'
}
])
/**
* @see https://www.w3.org/TR/FileAPI/#process-blob-parts
* @param {(NodeJS.TypedArray|Blob|string)[]} parts
* @param {{ type: string, endings: string }} options
*/
function processBlobParts (parts, options) {
// 1. Let bytes be an empty sequence of bytes.
/** @type {NodeJS.TypedArray[]} */
const bytes = []
// 2. For each element in parts:
for (const element of parts) {
// 1. If element is a USVString, run the following substeps:
if (typeof element === 'string') {
// 1. Let s be element.
let s = element
// 2. If the endings member of options is "native", set s
// to the result of converting line endings to native
// of element.
if (options.endings === 'native') {
s = convertLineEndingsNative(s)
}
// 3. Append the result of UTF-8 encoding s to bytes.
bytes.push(encoder.encode(s))
} else if (ArrayBuffer.isView(element) || types.isArrayBuffer(element)) {
// 2. If element is a BufferSource, get a copy of the
// bytes held by the buffer source, and append those
// bytes to bytes.
if (element.buffer) {
bytes.push(
new Uint8Array(element.buffer, element.byteOffset, element.byteLength)
)
} else { // ArrayBuffer
bytes.push(new Uint8Array(element))
}
} else if (isBlobLike(element)) {
// 3. If element is a Blob, append the bytes it represents
// to bytes.
bytes.push(element)
}
}
// 3. Return bytes.
return bytes
}
/**
* @see https://www.w3.org/TR/FileAPI/#convert-line-endings-to-native
* @param {string} s
*/
function convertLineEndingsNative (s) {
// 1. Let native line ending be be the code point U+000A LF.
// 2. If the underlying platforms conventions are to
// represent newlines as a carriage return and line feed
// sequence, set native line ending to the code point
// U+000D CR followed by the code point U+000A LF.
// NOTE: We are using the native line ending for the current
// platform, provided by node's os module.
return s.replace(/\r?\n/g, EOL)
}
// If this function is moved to ./util.js, some tools (such as
// rollup) will warn about circular dependencies. See:
// https://github.com/nodejs/undici/issues/1629
function isFileLike (object) {
return (
(NativeFile && object instanceof NativeFile) ||
object instanceof File || (
(object instanceof File) ||
(
object &&
(typeof object.stream === 'function' ||
typeof object.arrayBuffer === 'function') &&
@ -334,4 +123,4 @@ function isFileLike (object) {
)
}
module.exports = { File, FileLike, isFileLike }
module.exports = { FileLike, isFileLike }

View File

@ -3,12 +3,12 @@
const { isUSVString, bufferToLowerCasedHeaderName } = require('../../core/util')
const { utf8DecodeBytes } = require('./util')
const { HTTP_TOKEN_CODEPOINTS, isomorphicDecode } = require('./data-url')
const { isFileLike, File: UndiciFile } = require('./file')
const { isFileLike } = require('./file')
const { makeEntry } = require('./formdata')
const assert = require('node:assert')
const { File: NodeFile } = require('node:buffer')
const File = globalThis.File ?? NodeFile ?? UndiciFile
const File = globalThis.File ?? NodeFile
const formDataNameBuffer = Buffer.from('form-data; name="')
const filenameBuffer = Buffer.from('; filename')

View File

@ -3,13 +3,13 @@
const { isBlobLike, iteratorMixin } = require('./util')
const { kState } = require('./symbols')
const { kEnumerableProperty } = require('../../core/util')
const { File: UndiciFile, FileLike, isFileLike } = require('./file')
const { FileLike, isFileLike } = require('./file')
const { webidl } = require('./webidl')
const { File: NativeFile } = require('node:buffer')
const nodeUtil = require('node:util')
/** @type {globalThis['File']} */
const File = NativeFile ?? UndiciFile
const File = globalThis.File ?? NativeFile
// https://xhr.spec.whatwg.org/#formdata
class FormData {
@ -28,7 +28,8 @@ class FormData {
append (name, value, filename = undefined) {
webidl.brandCheck(this, FormData)
webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.append' })
const prefix = 'FormData.append'
webidl.argumentLengthCheck(arguments, 2, prefix)
if (arguments.length === 3 && !isBlobLike(value)) {
throw new TypeError(
@ -38,12 +39,12 @@ class FormData {
// 1. Let value be value if given; otherwise blobValue.
name = webidl.converters.USVString(name)
name = webidl.converters.USVString(name, prefix, 'name')
value = isBlobLike(value)
? webidl.converters.Blob(value, { strict: false })
: webidl.converters.USVString(value)
? webidl.converters.Blob(value, prefix, 'value', { strict: false })
: webidl.converters.USVString(value, prefix, 'value')
filename = arguments.length === 3
? webidl.converters.USVString(filename)
? webidl.converters.USVString(filename, prefix, 'filename')
: undefined
// 2. Let entry be the result of creating an entry with
@ -57,9 +58,10 @@ class FormData {
delete (name) {
webidl.brandCheck(this, FormData)
webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.delete' })
const prefix = 'FormData.delete'
webidl.argumentLengthCheck(arguments, 1, prefix)
name = webidl.converters.USVString(name)
name = webidl.converters.USVString(name, prefix, 'name')
// The delete(name) method steps are to remove all entries whose name
// is name from thiss entry list.
@ -69,9 +71,10 @@ class FormData {
get (name) {
webidl.brandCheck(this, FormData)
webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.get' })
const prefix = 'FormData.get'
webidl.argumentLengthCheck(arguments, 1, prefix)
name = webidl.converters.USVString(name)
name = webidl.converters.USVString(name, prefix, 'name')
// 1. If there is no entry whose name is name in thiss entry list,
// then return null.
@ -88,9 +91,10 @@ class FormData {
getAll (name) {
webidl.brandCheck(this, FormData)
webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.getAll' })
const prefix = 'FormData.getAll'
webidl.argumentLengthCheck(arguments, 1, prefix)
name = webidl.converters.USVString(name)
name = webidl.converters.USVString(name, prefix, 'name')
// 1. If there is no entry whose name is name in thiss entry list,
// then return the empty list.
@ -104,9 +108,10 @@ class FormData {
has (name) {
webidl.brandCheck(this, FormData)
webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.has' })
const prefix = 'FormData.has'
webidl.argumentLengthCheck(arguments, 1, prefix)
name = webidl.converters.USVString(name)
name = webidl.converters.USVString(name, prefix, 'name')
// The has(name) method steps are to return true if there is an entry
// whose name is name in thiss entry list; otherwise false.
@ -116,7 +121,8 @@ class FormData {
set (name, value, filename = undefined) {
webidl.brandCheck(this, FormData)
webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.set' })
const prefix = 'FormData.set'
webidl.argumentLengthCheck(arguments, 2, prefix)
if (arguments.length === 3 && !isBlobLike(value)) {
throw new TypeError(
@ -129,12 +135,12 @@ class FormData {
// 1. Let value be value if given; otherwise blobValue.
name = webidl.converters.USVString(name)
name = webidl.converters.USVString(name, prefix, 'name')
value = isBlobLike(value)
? webidl.converters.Blob(value, { strict: false })
: webidl.converters.USVString(value)
? webidl.converters.Blob(value, prefix, 'name', { strict: false })
: webidl.converters.USVString(value, prefix, 'name')
filename = arguments.length === 3
? webidl.converters.USVString(filename)
? webidl.converters.USVString(filename, prefix, 'name')
: undefined
// 2. Let entry be the result of creating an entry with name, value, and
@ -231,7 +237,7 @@ function makeEntry (name, value, filename) {
lastModified: value.lastModified
}
value = (NativeFile && value instanceof NativeFile) || value instanceof UndiciFile
value = value instanceof NativeFile
? new File([value], filename, options)
: new FileLike(value, filename, options)
}

View File

@ -259,6 +259,24 @@ class HeadersList {
return headers
}
get entriesList () {
const headers = []
if (this[kHeadersMap].size !== 0) {
for (const { 0: lowerName, 1: { name, value } } of this[kHeadersMap]) {
if (lowerName === 'set-cookie') {
for (const cookie of this.cookies) {
headers.push([name, cookie])
}
} else {
headers.push([name, value])
}
}
}
return headers
}
// https://fetch.spec.whatwg.org/#convert-header-names-to-a-sorted-lowercase-set
toSortedArray () {
const size = this[kHeadersMap].size
@ -348,7 +366,7 @@ class Headers {
// 2. If init is given, then fill this with init.
if (init !== undefined) {
init = webidl.converters.HeadersInit(init)
init = webidl.converters.HeadersInit(init, 'Headers contructor', 'init')
fill(this, init)
}
}
@ -357,10 +375,11 @@ class Headers {
append (name, value) {
webidl.brandCheck(this, Headers)
webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.append' })
webidl.argumentLengthCheck(arguments, 2, 'Headers.append')
name = webidl.converters.ByteString(name)
value = webidl.converters.ByteString(value)
const prefix = 'Headers.append'
name = webidl.converters.ByteString(name, prefix, 'name')
value = webidl.converters.ByteString(value, prefix, 'value')
return appendHeader(this, name, value)
}
@ -369,9 +388,10 @@ class Headers {
delete (name) {
webidl.brandCheck(this, Headers)
webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.delete' })
webidl.argumentLengthCheck(arguments, 1, 'Headers.delete')
name = webidl.converters.ByteString(name)
const prefix = 'Headers.delete'
name = webidl.converters.ByteString(name, prefix, 'name')
// 1. If name is not a header name, then throw a TypeError.
if (!isValidHeaderName(name)) {
@ -414,14 +434,15 @@ class Headers {
get (name) {
webidl.brandCheck(this, Headers)
webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.get' })
webidl.argumentLengthCheck(arguments, 1, 'Headers.get')
name = webidl.converters.ByteString(name)
const prefix = 'Headers.get'
name = webidl.converters.ByteString(name, prefix, 'name')
// 1. If name is not a header name, then throw a TypeError.
if (!isValidHeaderName(name)) {
throw webidl.errors.invalidArgument({
prefix: 'Headers.get',
prefix,
value: name,
type: 'header name'
})
@ -436,14 +457,15 @@ class Headers {
has (name) {
webidl.brandCheck(this, Headers)
webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.has' })
webidl.argumentLengthCheck(arguments, 1, 'Headers.has')
name = webidl.converters.ByteString(name)
const prefix = 'Headers.has'
name = webidl.converters.ByteString(name, prefix, 'name')
// 1. If name is not a header name, then throw a TypeError.
if (!isValidHeaderName(name)) {
throw webidl.errors.invalidArgument({
prefix: 'Headers.has',
prefix,
value: name,
type: 'header name'
})
@ -458,10 +480,11 @@ class Headers {
set (name, value) {
webidl.brandCheck(this, Headers)
webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.set' })
webidl.argumentLengthCheck(arguments, 2, 'Headers.set')
name = webidl.converters.ByteString(name)
value = webidl.converters.ByteString(value)
const prefix = 'Headers.set'
name = webidl.converters.ByteString(name, prefix, 'name')
value = webidl.converters.ByteString(value, prefix, 'value')
// 1. Normalize value.
value = headerValueNormalize(value)
@ -470,13 +493,13 @@ class Headers {
// header value, then throw a TypeError.
if (!isValidHeaderName(name)) {
throw webidl.errors.invalidArgument({
prefix: 'Headers.set',
prefix,
value: name,
type: 'header name'
})
} else if (!isValidHeaderValue(value)) {
throw webidl.errors.invalidArgument({
prefix: 'Headers.set',
prefix,
value,
type: 'header value'
})
@ -598,15 +621,21 @@ Object.defineProperties(Headers.prototype, {
}
})
webidl.converters.HeadersInit = function (V) {
webidl.converters.HeadersInit = function (V, prefix, argument) {
if (webidl.util.Type(V) === 'Object') {
const iterator = Reflect.get(V, Symbol.iterator)
if (typeof iterator === 'function') {
return webidl.converters['sequence<sequence<ByteString>>'](V, iterator.bind(V))
// A work-around to ensure we send the properly-cased Headers when V is a Headers object.
// Read https://github.com/nodejs/undici/pull/3159#issuecomment-2075537226 before touching, please.
if (!util.types.isProxy(V) && kHeadersList in V && iterator === Headers.prototype.entries) { // Headers object
return V[kHeadersList].entriesList
}
return webidl.converters['record<ByteString, ByteString>'](V)
if (typeof iterator === 'function') {
return webidl.converters['sequence<sequence<ByteString>>'](V, prefix, argument, iterator.bind(V))
}
return webidl.converters['record<ByteString, ByteString>'](V, prefix, argument)
}
throw webidl.errors.conversionFailed({

View File

@ -59,7 +59,7 @@ const {
} = require('./constants')
const EE = require('node:events')
const { Readable, pipeline, finished } = require('node:stream')
const { addAbortListener, isErrored, isReadable, nodeMajor, nodeMinor, bufferToLowerCasedHeaderName } = require('../../core/util')
const { addAbortListener, isErrored, isReadable, bufferToLowerCasedHeaderName } = require('../../core/util')
const { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require('./data-url')
const { getGlobalDispatcher } = require('../../global')
const { webidl } = require('./webidl')
@ -122,7 +122,7 @@ class Fetch extends EE {
// https://fetch.spec.whatwg.org/#fetch-method
function fetch (input, init = undefined) {
webidl.argumentLengthCheck(arguments, 1, { header: 'globalThis.fetch' })
webidl.argumentLengthCheck(arguments, 1, 'globalThis.fetch')
// 1. Let p be a new promise.
const p = createDeferredPromise()
@ -165,7 +165,6 @@ function fetch (input, init = undefined) {
let responseObject = null
// 8. Let relevantRealm be thiss relevant Realm.
const relevantRealm = null
// 9. Let locallyAborted be false.
let locallyAborted = false
@ -229,7 +228,7 @@ function fetch (input, init = undefined) {
// 4. Set responseObject to the result of creating a Response object,
// given response, "immutable", and relevantRealm.
responseObject = fromInnerResponse(response, 'immutable', relevantRealm)
responseObject = fromInnerResponse(response, 'immutable')
// 5. Resolve p with responseObject.
p.resolve(responseObject)
@ -310,9 +309,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
}
// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
const markResourceTiming = (nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 2))
? performance.markResourceTiming
: () => {}
const markResourceTiming = performance.markResourceTiming
// https://fetch.spec.whatwg.org/#abort-fetch
function abortFetch (p, request, responseObject, error) {
@ -1540,7 +1537,7 @@ async function httpNetworkOrCacheFetch (
// 24. If httpRequests cache mode is neither "no-store" nor "reload",
// then:
if (httpRequest.mode !== 'no-store' && httpRequest.mode !== 'reload') {
if (httpRequest.cache !== 'no-store' && httpRequest.cache !== 'reload') {
// TODO: cache
}
@ -1551,7 +1548,7 @@ async function httpNetworkOrCacheFetch (
if (response == null) {
// 1. If httpRequests cache mode is "only-if-cached", then return a
// network error.
if (httpRequest.mode === 'only-if-cached') {
if (httpRequest.cache === 'only-if-cached') {
return makeNetworkError('only if cached')
}

View File

@ -11,7 +11,7 @@ const {
isValidHTTPToken,
sameOrigin,
normalizeMethod,
makePolicyContainer,
environmentSettingsObject,
normalizeMethodRecord
} = require('./util')
const {
@ -25,9 +25,8 @@ const {
requestDuplex
} = require('./constants')
const { kEnumerableProperty } = util
const { kHeaders, kSignal, kState, kGuard, kRealm, kDispatcher } = require('./symbols')
const { kHeaders, kSignal, kState, kGuard, kDispatcher } = require('./symbols')
const { webidl } = require('./webidl')
const { getGlobalOrigin } = require('./global')
const { URLSerializer } = require('./data-url')
const { kHeadersList, kConstruct } = require('../../core/symbols')
const assert = require('node:assert')
@ -39,6 +38,46 @@ const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => {
signal.removeEventListener('abort', abort)
})
const dependentControllerMap = new WeakMap()
function buildAbort (acRef) {
return abort
function abort () {
const ac = acRef.deref()
if (ac !== undefined) {
// Currently, there is a problem with FinalizationRegistry.
// https://github.com/nodejs/node/issues/49344
// https://github.com/nodejs/node/issues/47748
// In the case of abort, the first step is to unregister from it.
// If the controller can refer to it, it is still registered.
// It will be removed in the future.
requestFinalizer.unregister(abort)
// Unsubscribe a listener.
// FinalizationRegistry will no longer be called, so this must be done.
this.removeEventListener('abort', abort)
ac.abort(this.reason)
const controllerList = dependentControllerMap.get(ac.signal)
if (controllerList !== undefined) {
if (controllerList.size !== 0) {
for (const ref of controllerList) {
const ctrl = ref.deref()
if (ctrl !== undefined) {
ctrl.abort(this.reason)
}
}
controllerList.clear()
}
dependentControllerMap.delete(ac.signal)
}
}
}
}
let patchMethodWarning = false
// https://fetch.spec.whatwg.org/#request-class
@ -49,21 +88,11 @@ class Request {
return
}
webidl.argumentLengthCheck(arguments, 1, { header: 'Request constructor' })
const prefix = 'Request constructor'
webidl.argumentLengthCheck(arguments, 1, prefix)
input = webidl.converters.RequestInfo(input)
init = webidl.converters.RequestInit(init)
// https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
this[kRealm] = {
settingsObject: {
baseUrl: getGlobalOrigin(),
get origin () {
return this.baseUrl?.origin
},
policyContainer: makePolicyContainer()
}
}
input = webidl.converters.RequestInfo(input, prefix, 'input')
init = webidl.converters.RequestInit(init, prefix, 'init')
// 1. Let request be null.
let request = null
@ -72,7 +101,7 @@ class Request {
let fallbackMode = null
// 3. Let baseURL be thiss relevant settings objects API base URL.
const baseUrl = this[kRealm].settingsObject.baseUrl
const baseUrl = environmentSettingsObject.settingsObject.baseUrl
// 4. Let signal be null.
let signal = null
@ -119,7 +148,7 @@ class Request {
}
// 7. Let origin be thiss relevant settings objects origin.
const origin = this[kRealm].settingsObject.origin
const origin = environmentSettingsObject.settingsObject.origin
// 8. Let window be "client".
let window = 'client'
@ -155,7 +184,7 @@ class Request {
// unsafe-request flag Set.
unsafeRequest: request.unsafeRequest,
// client Thiss relevant settings object.
client: this[kRealm].settingsObject,
client: environmentSettingsObject.settingsObject,
// window window.
window,
// priority requests priority.
@ -244,7 +273,7 @@ class Request {
// then set requests referrer to "client".
if (
(parsedReferrer.protocol === 'about:' && parsedReferrer.hostname === 'client') ||
(origin && !sameOrigin(parsedReferrer, this[kRealm].settingsObject.baseUrl))
(origin && !sameOrigin(parsedReferrer, environmentSettingsObject.settingsObject.baseUrl))
) {
request.referrer = 'client'
} else {
@ -366,7 +395,6 @@ class Request {
// (https://dom.spec.whatwg.org/#dom-abortsignal-any)
const ac = new AbortController()
this[kSignal] = ac.signal
this[kSignal][kRealm] = this[kRealm]
// 29. If signal is not null, then make thiss signal follow signal.
if (signal != null) {
@ -390,24 +418,7 @@ class Request {
this[kAbortController] = ac
const acRef = new WeakRef(ac)
const abort = function () {
const ac = acRef.deref()
if (ac !== undefined) {
// Currently, there is a problem with FinalizationRegistry.
// https://github.com/nodejs/node/issues/49344
// https://github.com/nodejs/node/issues/47748
// In the case of abort, the first step is to unregister from it.
// If the controller can refer to it, it is still registered.
// It will be removed in the future.
requestFinalizer.unregister(abort)
// Unsubscribe a listener.
// FinalizationRegistry will no longer be called, so this must be done.
this.removeEventListener('abort', abort)
ac.abort(this.reason)
}
}
const abort = buildAbort(acRef)
// Third-party AbortControllers may not work with these.
// See, https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619.
@ -415,9 +426,9 @@ class Request {
// If the max amount of listeners is equal to the default, increase it
// This is only available in node >= v19.9.0
if (typeof getMaxListeners === 'function' && getMaxListeners(signal) === defaultMaxListeners) {
setMaxListeners(100, signal)
setMaxListeners(1500, signal)
} else if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) {
setMaxListeners(100, signal)
setMaxListeners(1500, signal)
}
} catch {}
@ -436,7 +447,6 @@ class Request {
this[kHeaders] = new Headers(kConstruct)
this[kHeaders][kHeadersList] = request.headersList
this[kHeaders][kGuard] = 'request'
this[kHeaders][kRealm] = this[kRealm]
// 31. If thiss requests mode is "no-cors", then:
if (mode === 'no-cors') {
@ -467,8 +477,9 @@ class Request {
// 4. If headers is a Headers object, then for each header in its header
// list, append headers name/headers value to thiss headers.
if (headers instanceof HeadersList) {
for (const [key, val] of headers) {
headersList.append(key, val)
for (const { 0: key, 1: val } of headers) {
// Note: The header names are already in lowercase.
headersList.append(key, val, true)
}
// Note: Copy the `set-cookie` meta-data.
headersList.cookies = headers.cookies
@ -761,16 +772,21 @@ class Request {
if (this.signal.aborted) {
ac.abort(this.signal.reason)
} else {
let list = dependentControllerMap.get(this.signal)
if (list === undefined) {
list = new Set()
dependentControllerMap.set(this.signal, list)
}
const acRef = new WeakRef(ac)
list.add(acRef)
util.addAbortListener(
this.signal,
() => {
ac.abort(this.signal.reason)
}
ac.signal,
buildAbort(acRef)
)
}
// 4. Return clonedRequestObject.
return fromInnerRequest(clonedRequest, ac.signal, this[kHeaders][kGuard], this[kRealm])
return fromInnerRequest(clonedRequest, ac.signal, this[kHeaders][kGuard])
}
[nodeUtil.inspect.custom] (depth, options) {
@ -873,19 +889,15 @@ function cloneRequest (request) {
* @param {any} innerRequest
* @param {AbortSignal} signal
* @param {'request' | 'immutable' | 'request-no-cors' | 'response' | 'none'} guard
* @param {any} [realm]
* @returns {Request}
*/
function fromInnerRequest (innerRequest, signal, guard, realm) {
function fromInnerRequest (innerRequest, signal, guard) {
const request = new Request(kConstruct)
request[kState] = innerRequest
request[kRealm] = realm
request[kSignal] = signal
request[kSignal][kRealm] = realm
request[kHeaders] = new Headers(kConstruct)
request[kHeaders][kHeadersList] = innerRequest.headersList
request[kHeaders][kGuard] = guard
request[kHeaders][kRealm] = realm
return request
}
@ -921,16 +933,16 @@ webidl.converters.Request = webidl.interfaceConverter(
)
// https://fetch.spec.whatwg.org/#requestinfo
webidl.converters.RequestInfo = function (V) {
webidl.converters.RequestInfo = function (V, prefix, argument) {
if (typeof V === 'string') {
return webidl.converters.USVString(V)
return webidl.converters.USVString(V, prefix, argument)
}
if (V instanceof Request) {
return webidl.converters.Request(V)
return webidl.converters.Request(V, prefix, argument)
}
return webidl.converters.USVString(V)
return webidl.converters.USVString(V, prefix, argument)
}
webidl.converters.AbortSignal = webidl.interfaceConverter(
@ -1000,6 +1012,8 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([
converter: webidl.nullableConverter(
(signal) => webidl.converters.AbortSignal(
signal,
'RequestInit',
'signal',
{ strict: false }
)
)

View File

@ -12,16 +12,16 @@ const {
isBlobLike,
serializeJavascriptValueToJSONString,
isErrorLike,
isomorphicEncode
isomorphicEncode,
environmentSettingsObject: relevantRealm
} = require('./util')
const {
redirectStatusSet,
nullBodyStatus
} = require('./constants')
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
const { kState, kHeaders, kGuard } = require('./symbols')
const { webidl } = require('./webidl')
const { FormData } = require('./formdata')
const { getGlobalOrigin } = require('./global')
const { URLSerializer } = require('./data-url')
const { kHeadersList, kConstruct } = require('../../core/symbols')
const assert = require('node:assert')
@ -33,20 +33,17 @@ const textEncoder = new TextEncoder('utf-8')
class Response {
// Creates network error Response.
static error () {
// TODO
const relevantRealm = { settingsObject: {} }
// The static error() method steps are to return the result of creating a
// Response object, given a new network error, "immutable", and thiss
// relevant Realm.
const responseObject = fromInnerResponse(makeNetworkError(), 'immutable', relevantRealm)
const responseObject = fromInnerResponse(makeNetworkError(), 'immutable')
return responseObject
}
// https://fetch.spec.whatwg.org/#dom-response-json
static json (data, init = {}) {
webidl.argumentLengthCheck(arguments, 1, { header: 'Response.json' })
webidl.argumentLengthCheck(arguments, 1, 'Response.json')
if (init !== null) {
init = webidl.converters.ResponseInit(init)
@ -62,8 +59,7 @@ class Response {
// 3. Let responseObject be the result of creating a Response object, given a new response,
// "response", and thiss relevant Realm.
const relevantRealm = { settingsObject: {} }
const responseObject = fromInnerResponse(makeResponse({}), 'response', relevantRealm)
const responseObject = fromInnerResponse(makeResponse({}), 'response')
// 4. Perform initialize a response given responseObject, init, and (body, "application/json").
initializeResponse(responseObject, init, { body: body[0], type: 'application/json' })
@ -74,9 +70,7 @@ class Response {
// Creates a redirect Response that redirects to url with status status.
static redirect (url, status = 302) {
const relevantRealm = { settingsObject: {} }
webidl.argumentLengthCheck(arguments, 1, { header: 'Response.redirect' })
webidl.argumentLengthCheck(arguments, 1, 'Response.redirect')
url = webidl.converters.USVString(url)
status = webidl.converters['unsigned short'](status)
@ -87,7 +81,7 @@ class Response {
// TODO: base-URL?
let parsedURL
try {
parsedURL = new URL(url, getGlobalOrigin())
parsedURL = new URL(url, relevantRealm.settingsObject.baseUrl)
} catch (err) {
throw new TypeError(`Failed to parse URL from ${url}`, { cause: err })
}
@ -99,7 +93,7 @@ class Response {
// 4. Let responseObject be the result of creating a Response object,
// given a new response, "immutable", and thiss relevant Realm.
const responseObject = fromInnerResponse(makeResponse({}), 'immutable', relevantRealm)
const responseObject = fromInnerResponse(makeResponse({}), 'immutable')
// 5. Set responseObjects responses status to status.
responseObject[kState].status = status
@ -126,9 +120,6 @@ class Response {
init = webidl.converters.ResponseInit(init)
// TODO
this[kRealm] = { settingsObject: {} }
// 1. Set thiss response to a new response.
this[kState] = makeResponse({})
@ -138,7 +129,6 @@ class Response {
this[kHeaders] = new Headers(kConstruct)
this[kHeaders][kGuard] = 'response'
this[kHeaders][kHeadersList] = this[kState].headersList
this[kHeaders][kRealm] = this[kRealm]
// 3. Let bodyWithType be null.
let bodyWithType = null
@ -251,7 +241,7 @@ class Response {
// 3. Return the result of creating a Response object, given
// clonedResponse, thiss headerss guard, and thiss relevant Realm.
return fromInnerResponse(clonedResponse, this[kHeaders][kGuard], this[kRealm])
return fromInnerResponse(clonedResponse, this[kHeaders][kGuard])
}
[nodeUtil.inspect.custom] (depth, options) {
@ -512,17 +502,14 @@ function initializeResponse (response, init, body) {
* @see https://fetch.spec.whatwg.org/#response-create
* @param {any} innerResponse
* @param {'request' | 'immutable' | 'request-no-cors' | 'response' | 'none'} guard
* @param {any} [realm]
* @returns {Response}
*/
function fromInnerResponse (innerResponse, guard, realm) {
function fromInnerResponse (innerResponse, guard) {
const response = new Response(kConstruct)
response[kState] = innerResponse
response[kRealm] = realm
response[kHeaders] = new Headers(kConstruct)
response[kHeaders][kHeadersList] = innerResponse.headersList
response[kHeaders][kGuard] = guard
response[kHeaders][kRealm] = realm
return response
}
@ -539,34 +526,34 @@ webidl.converters.URLSearchParams = webidl.interfaceConverter(
)
// https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit
webidl.converters.XMLHttpRequestBodyInit = function (V) {
webidl.converters.XMLHttpRequestBodyInit = function (V, prefix, name) {
if (typeof V === 'string') {
return webidl.converters.USVString(V)
return webidl.converters.USVString(V, prefix, name)
}
if (isBlobLike(V)) {
return webidl.converters.Blob(V, { strict: false })
return webidl.converters.Blob(V, prefix, name, { strict: false })
}
if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) {
return webidl.converters.BufferSource(V)
return webidl.converters.BufferSource(V, prefix, name)
}
if (util.isFormDataLike(V)) {
return webidl.converters.FormData(V, { strict: false })
return webidl.converters.FormData(V, prefix, name, { strict: false })
}
if (V instanceof URLSearchParams) {
return webidl.converters.URLSearchParams(V)
return webidl.converters.URLSearchParams(V, prefix, name)
}
return webidl.converters.DOMString(V)
return webidl.converters.DOMString(V, prefix, name)
}
// https://fetch.spec.whatwg.org/#bodyinit
webidl.converters.BodyInit = function (V) {
webidl.converters.BodyInit = function (V, prefix, argument) {
if (V instanceof ReadableStream) {
return webidl.converters.ReadableStream(V)
return webidl.converters.ReadableStream(V, prefix, argument)
}
// Note: the spec doesn't include async iterables,
@ -575,19 +562,19 @@ webidl.converters.BodyInit = function (V) {
return V
}
return webidl.converters.XMLHttpRequestBodyInit(V)
return webidl.converters.XMLHttpRequestBodyInit(V, prefix, argument)
}
webidl.converters.ResponseInit = webidl.dictionaryConverter([
{
key: 'status',
converter: webidl.converters['unsigned short'],
defaultValue: 200
defaultValue: () => 200
},
{
key: 'statusText',
converter: webidl.converters.ByteString,
defaultValue: ''
defaultValue: () => ''
},
{
key: 'headers',

View File

@ -6,6 +6,5 @@ module.exports = {
kSignal: Symbol('signal'),
kState: Symbol('state'),
kGuard: Symbol('guard'),
kRealm: Symbol('realm'),
kDispatcher: Symbol('dispatcher')
}

View File

@ -1016,7 +1016,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
configurable: true,
value: function forEach (callbackfn, thisArg = globalThis) {
webidl.brandCheck(this, object)
webidl.argumentLengthCheck(arguments, 1, { header: `${name}.forEach` })
webidl.argumentLengthCheck(arguments, 1, `${name}.forEach`)
if (typeof callbackfn !== 'function') {
throw new TypeError(
`Failed to execute 'forEach' on '${name}': parameter 1 is not of type 'Function'.`
@ -1043,7 +1043,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
/**
* @see https://fetch.spec.whatwg.org/#body-fully-read
*/
async function fullyReadBody (body, processBody, processBodyError) {
async function fullyReadBody (body, processBody, processBodyError, shouldClone) {
// 1. If taskDestination is null, then set taskDestination to
// the result of starting a new parallel queue.
@ -1069,8 +1069,7 @@ async function fullyReadBody (body, processBody, processBodyError) {
// 5. Read all bytes from reader, given successSteps and errorSteps.
try {
const result = await readAllBytes(reader)
successSteps(result)
successSteps(await readAllBytes(reader, shouldClone))
} catch (e) {
errorSteps(e)
}
@ -1098,15 +1097,15 @@ function readableStreamClose (controller) {
}
}
const invalidIsomorphicEncodeValueRegex = /[^\x00-\xFF]/ // eslint-disable-line
/**
* @see https://infra.spec.whatwg.org/#isomorphic-encode
* @param {string} input
*/
function isomorphicEncode (input) {
// 1. Assert: input contains no code points greater than U+00FF.
for (let i = 0; i < input.length; i++) {
assert(input.charCodeAt(i) <= 0xFF)
}
assert(!invalidIsomorphicEncodeValueRegex.test(input))
// 2. Return a byte sequence whose length is equal to inputs code
// point length and whose bytes have the same values as the
@ -1118,8 +1117,9 @@ function isomorphicEncode (input) {
* @see https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes
* @see https://streams.spec.whatwg.org/#read-loop
* @param {ReadableStreamDefaultReader} reader
* @param {boolean} [shouldClone]
*/
async function readAllBytes (reader) {
async function readAllBytes (reader, shouldClone) {
const bytes = []
let byteLength = 0
@ -1128,6 +1128,13 @@ async function readAllBytes (reader) {
if (done) {
// 1. Call successSteps with bytes.
if (bytes.length === 1) {
const { buffer, byteOffset, byteLength } = bytes[0]
if (shouldClone === false) {
return Buffer.from(buffer, byteOffset, byteLength)
}
return Buffer.from(buffer.slice(byteOffset, byteOffset + byteLength), 0, byteLength)
}
return Buffer.concat(bytes, byteLength)
}
@ -1562,6 +1569,24 @@ function utf8DecodeBytes (buffer) {
return output
}
class EnvironmentSettingsObjectBase {
get baseUrl () {
return getGlobalOrigin()
}
get origin () {
return this.baseUrl?.origin
}
policyContainer = makePolicyContainer()
}
class EnvironmentSettingsObject {
settingsObject = new EnvironmentSettingsObjectBase()
}
const environmentSettingsObject = new EnvironmentSettingsObject()
module.exports = {
isAborted,
isCancelled,
@ -1613,5 +1638,6 @@ module.exports = {
createInflate,
extractMimeType,
getDecodeSplit,
utf8DecodeBytes
utf8DecodeBytes,
environmentSettingsObject
}

View File

@ -33,14 +33,18 @@ webidl.errors.invalidArgument = function (context) {
}
// https://webidl.spec.whatwg.org/#implements
webidl.brandCheck = function (V, I, opts = undefined) {
webidl.brandCheck = function (V, I, opts) {
if (opts?.strict !== false) {
if (!(V instanceof I)) {
throw new TypeError('Illegal invocation')
const err = new TypeError('Illegal invocation')
err.code = 'ERR_INVALID_THIS' // node compat.
throw err
}
} else {
if (V?.[Symbol.toStringTag] !== I.prototype[Symbol.toStringTag]) {
throw new TypeError('Illegal invocation')
const err = new TypeError('Illegal invocation')
err.code = 'ERR_INVALID_THIS' // node compat.
throw err
}
}
}
@ -50,7 +54,7 @@ webidl.argumentLengthCheck = function ({ length }, min, ctx) {
throw webidl.errors.exception({
message: `${min} argument${min !== 1 ? 's' : ''} required, ` +
`but${length ? ' only' : ''} ${length} found.`,
...ctx
header: ctx
})
}
}
@ -83,7 +87,7 @@ webidl.util.Type = function (V) {
}
// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) {
webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) {
let upperBound
let lowerBound
@ -127,7 +131,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) {
// 6. If the conversion is to an IDL type associated
// with the [EnforceRange] extended attribute, then:
if (opts.enforceRange === true) {
if (opts?.enforceRange === true) {
// 1. If x is NaN, +∞, or −∞, then throw a TypeError.
if (
Number.isNaN(x) ||
@ -159,7 +163,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) {
// 7. If x is not NaN and the conversion is to an IDL
// type associated with the [Clamp] extended
// attribute, then:
if (!Number.isNaN(x) && opts.clamp === true) {
if (!Number.isNaN(x) && opts?.clamp === true) {
// 1. Set x to min(max(x, lowerBound), upperBound).
x = Math.min(Math.max(x, lowerBound), upperBound)
@ -233,12 +237,12 @@ webidl.util.Stringify = function (V) {
// https://webidl.spec.whatwg.org/#es-sequence
webidl.sequenceConverter = function (converter) {
return (V, Iterable) => {
return (V, prefix, argument, Iterable) => {
// 1. If Type(V) is not Object, throw a TypeError.
if (webidl.util.Type(V) !== 'Object') {
throw webidl.errors.exception({
header: 'Sequence',
message: `Value of type ${webidl.util.Type(V)} is not an Object.`
header: prefix,
message: `${argument} (${webidl.util.Stringify(V)}) is not iterable.`
})
}
@ -253,8 +257,8 @@ webidl.sequenceConverter = function (converter) {
typeof method.next !== 'function'
) {
throw webidl.errors.exception({
header: 'Sequence',
message: 'Object is not an iterator.'
header: prefix,
message: `${argument} is not iterable.`
})
}
@ -266,7 +270,7 @@ webidl.sequenceConverter = function (converter) {
break
}
seq.push(converter(value))
seq.push(converter(value, prefix, argument))
}
return seq
@ -275,12 +279,12 @@ webidl.sequenceConverter = function (converter) {
// https://webidl.spec.whatwg.org/#es-to-record
webidl.recordConverter = function (keyConverter, valueConverter) {
return (O) => {
return (O, prefix, argument) => {
// 1. If Type(O) is not Object, throw a TypeError.
if (webidl.util.Type(O) !== 'Object') {
throw webidl.errors.exception({
header: 'Record',
message: `Value of type ${webidl.util.Type(O)} is not an Object.`
header: prefix,
message: `${argument} ("${webidl.util.Type(O)}") is not an Object.`
})
}
@ -293,11 +297,11 @@ webidl.recordConverter = function (keyConverter, valueConverter) {
for (const key of keys) {
// 1. Let typedKey be key converted to an IDL value of type K.
const typedKey = keyConverter(key)
const typedKey = keyConverter(key, prefix, argument)
// 2. Let value be ? Get(O, key).
// 3. Let typedValue be value converted to an IDL value of type V.
const typedValue = valueConverter(O[key])
const typedValue = valueConverter(O[key], prefix, argument)
// 4. Set result[typedKey] to typedValue.
result[typedKey] = typedValue
@ -318,11 +322,11 @@ webidl.recordConverter = function (keyConverter, valueConverter) {
// 2. If desc is not undefined and desc.[[Enumerable]] is true:
if (desc?.enumerable) {
// 1. Let typedKey be key converted to an IDL value of type K.
const typedKey = keyConverter(key)
const typedKey = keyConverter(key, prefix, argument)
// 2. Let value be ? Get(O, key).
// 3. Let typedValue be value converted to an IDL value of type V.
const typedValue = valueConverter(O[key])
const typedValue = valueConverter(O[key], prefix, argument)
// 4. Set result[typedKey] to typedValue.
result[typedKey] = typedValue
@ -335,11 +339,11 @@ webidl.recordConverter = function (keyConverter, valueConverter) {
}
webidl.interfaceConverter = function (i) {
return (V, opts = {}) => {
if (opts.strict !== false && !(V instanceof i)) {
return (V, prefix, argument, opts) => {
if (opts?.strict !== false && !(V instanceof i)) {
throw webidl.errors.exception({
header: i.name,
message: `Expected ${webidl.util.Stringify(V)} to be an instance of ${i.name}.`
header: prefix,
message: `Expected ${argument} ("${webidl.util.Stringify(V)}") to be an instance of ${i.name}.`
})
}
@ -348,7 +352,7 @@ webidl.interfaceConverter = function (i) {
}
webidl.dictionaryConverter = function (converters) {
return (dictionary) => {
return (dictionary, prefix, argument) => {
const type = webidl.util.Type(dictionary)
const dict = {}
@ -356,7 +360,7 @@ webidl.dictionaryConverter = function (converters) {
return dict
} else if (type !== 'Object') {
throw webidl.errors.exception({
header: 'Dictionary',
header: prefix,
message: `Expected ${dictionary} to be one of: Null, Undefined, Object.`
})
}
@ -367,7 +371,7 @@ webidl.dictionaryConverter = function (converters) {
if (required === true) {
if (!Object.hasOwn(dictionary, key)) {
throw webidl.errors.exception({
header: 'Dictionary',
header: prefix,
message: `Missing required key "${key}".`
})
}
@ -379,21 +383,21 @@ webidl.dictionaryConverter = function (converters) {
// Only use defaultValue if value is undefined and
// a defaultValue options was provided.
if (hasDefault && value !== null) {
value = value ?? defaultValue
value ??= defaultValue()
}
// A key can be optional and have no default value.
// When this happens, do not perform a conversion,
// and do not assign the key a value.
if (required || hasDefault || value !== undefined) {
value = converter(value)
value = converter(value, prefix, `${argument}.${key}`)
if (
options.allowedValues &&
!options.allowedValues.includes(value)
) {
throw webidl.errors.exception({
header: 'Dictionary',
header: prefix,
message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(', ')}.`
})
}
@ -407,28 +411,31 @@ webidl.dictionaryConverter = function (converters) {
}
webidl.nullableConverter = function (converter) {
return (V) => {
return (V, prefix, argument) => {
if (V === null) {
return V
}
return converter(V)
return converter(V, prefix, argument)
}
}
// https://webidl.spec.whatwg.org/#es-DOMString
webidl.converters.DOMString = function (V, opts = {}) {
webidl.converters.DOMString = function (V, prefix, argument, opts) {
// 1. If V is null and the conversion is to an IDL type
// associated with the [LegacyNullToEmptyString]
// extended attribute, then return the DOMString value
// that represents the empty string.
if (V === null && opts.legacyNullToEmptyString) {
if (V === null && opts?.legacyNullToEmptyString) {
return ''
}
// 2. Let x be ? ToString(V).
if (typeof V === 'symbol') {
throw new TypeError('Could not convert argument of type symbol to string.')
throw webidl.errors.exception({
header: prefix,
message: `${argument} is a symbol, which cannot be converted to a DOMString.`
})
}
// 3. Return the IDL DOMString value that represents the
@ -438,10 +445,10 @@ webidl.converters.DOMString = function (V, opts = {}) {
}
// https://webidl.spec.whatwg.org/#es-ByteString
webidl.converters.ByteString = function (V) {
webidl.converters.ByteString = function (V, prefix, argument) {
// 1. Let x be ? ToString(V).
// Note: DOMString converter perform ? ToString(V)
const x = webidl.converters.DOMString(V)
const x = webidl.converters.DOMString(V, prefix, argument)
// 2. If the value of any element of x is greater than
// 255, then throw a TypeError.
@ -461,6 +468,7 @@ webidl.converters.ByteString = function (V) {
}
// https://webidl.spec.whatwg.org/#es-USVString
// TODO: rewrite this so we can control the errors thrown
webidl.converters.USVString = toUSVString
// https://webidl.spec.whatwg.org/#es-boolean
@ -479,9 +487,9 @@ webidl.converters.any = function (V) {
}
// https://webidl.spec.whatwg.org/#es-long-long
webidl.converters['long long'] = function (V) {
webidl.converters['long long'] = function (V, prefix, argument) {
// 1. Let x be ? ConvertToInt(V, 64, "signed").
const x = webidl.util.ConvertToInt(V, 64, 'signed')
const x = webidl.util.ConvertToInt(V, 64, 'signed', undefined, prefix, argument)
// 2. Return the IDL long long value that represents
// the same numeric value as x.
@ -489,9 +497,9 @@ webidl.converters['long long'] = function (V) {
}
// https://webidl.spec.whatwg.org/#es-unsigned-long-long
webidl.converters['unsigned long long'] = function (V) {
webidl.converters['unsigned long long'] = function (V, prefix, argument) {
// 1. Let x be ? ConvertToInt(V, 64, "unsigned").
const x = webidl.util.ConvertToInt(V, 64, 'unsigned')
const x = webidl.util.ConvertToInt(V, 64, 'unsigned', undefined, prefix, argument)
// 2. Return the IDL unsigned long long value that
// represents the same numeric value as x.
@ -499,9 +507,9 @@ webidl.converters['unsigned long long'] = function (V) {
}
// https://webidl.spec.whatwg.org/#es-unsigned-long
webidl.converters['unsigned long'] = function (V) {
webidl.converters['unsigned long'] = function (V, prefix, argument) {
// 1. Let x be ? ConvertToInt(V, 32, "unsigned").
const x = webidl.util.ConvertToInt(V, 32, 'unsigned')
const x = webidl.util.ConvertToInt(V, 32, 'unsigned', undefined, prefix, argument)
// 2. Return the IDL unsigned long value that
// represents the same numeric value as x.
@ -509,9 +517,9 @@ webidl.converters['unsigned long'] = function (V) {
}
// https://webidl.spec.whatwg.org/#es-unsigned-short
webidl.converters['unsigned short'] = function (V, opts) {
webidl.converters['unsigned short'] = function (V, prefix, argument, opts) {
// 1. Let x be ? ConvertToInt(V, 16, "unsigned").
const x = webidl.util.ConvertToInt(V, 16, 'unsigned', opts)
const x = webidl.util.ConvertToInt(V, 16, 'unsigned', opts, prefix, argument)
// 2. Return the IDL unsigned short value that represents
// the same numeric value as x.
@ -519,7 +527,7 @@ webidl.converters['unsigned short'] = function (V, opts) {
}
// https://webidl.spec.whatwg.org/#idl-ArrayBuffer
webidl.converters.ArrayBuffer = function (V, opts = {}) {
webidl.converters.ArrayBuffer = function (V, prefix, argument, opts) {
// 1. If Type(V) is not Object, or V does not have an
// [[ArrayBufferData]] internal slot, then throw a
// TypeError.
@ -530,8 +538,8 @@ webidl.converters.ArrayBuffer = function (V, opts = {}) {
!types.isAnyArrayBuffer(V)
) {
throw webidl.errors.conversionFailed({
prefix: webidl.util.Stringify(V),
argument: webidl.util.Stringify(V),
prefix,
argument: `${argument} ("${webidl.util.Stringify(V)}")`,
types: ['ArrayBuffer']
})
}
@ -540,7 +548,7 @@ webidl.converters.ArrayBuffer = function (V, opts = {}) {
// with the [AllowShared] extended attribute, and
// IsSharedArrayBuffer(V) is true, then throw a
// TypeError.
if (opts.allowShared === false && types.isSharedArrayBuffer(V)) {
if (opts?.allowShared === false && types.isSharedArrayBuffer(V)) {
throw webidl.errors.exception({
header: 'ArrayBuffer',
message: 'SharedArrayBuffer is not allowed.'
@ -563,7 +571,7 @@ webidl.converters.ArrayBuffer = function (V, opts = {}) {
return V
}
webidl.converters.TypedArray = function (V, T, opts = {}) {
webidl.converters.TypedArray = function (V, T, prefix, name, opts) {
// 1. Let T be the IDL type V is being converted to.
// 2. If Type(V) is not Object, or V does not have a
@ -575,8 +583,8 @@ webidl.converters.TypedArray = function (V, T, opts = {}) {
V.constructor.name !== T.name
) {
throw webidl.errors.conversionFailed({
prefix: `${T.name}`,
argument: webidl.util.Stringify(V),
prefix,
argument: `${name} ("${webidl.util.Stringify(V)}")`,
types: [T.name]
})
}
@ -585,7 +593,7 @@ webidl.converters.TypedArray = function (V, T, opts = {}) {
// with the [AllowShared] extended attribute, and
// IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is
// true, then throw a TypeError.
if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) {
if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) {
throw webidl.errors.exception({
header: 'ArrayBuffer',
message: 'SharedArrayBuffer is not allowed.'
@ -608,13 +616,13 @@ webidl.converters.TypedArray = function (V, T, opts = {}) {
return V
}
webidl.converters.DataView = function (V, opts = {}) {
webidl.converters.DataView = function (V, prefix, name, opts) {
// 1. If Type(V) is not Object, or V does not have a
// [[DataView]] internal slot, then throw a TypeError.
if (webidl.util.Type(V) !== 'Object' || !types.isDataView(V)) {
throw webidl.errors.exception({
header: 'DataView',
message: 'Object is not a DataView.'
header: prefix,
message: `${name} is not a DataView.`
})
}
@ -622,7 +630,7 @@ webidl.converters.DataView = function (V, opts = {}) {
// with the [AllowShared] extended attribute, and
// IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true,
// then throw a TypeError.
if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) {
if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) {
throw webidl.errors.exception({
header: 'ArrayBuffer',
message: 'SharedArrayBuffer is not allowed.'
@ -646,20 +654,24 @@ webidl.converters.DataView = function (V, opts = {}) {
}
// https://webidl.spec.whatwg.org/#BufferSource
webidl.converters.BufferSource = function (V, opts = {}) {
webidl.converters.BufferSource = function (V, prefix, name, opts) {
if (types.isAnyArrayBuffer(V)) {
return webidl.converters.ArrayBuffer(V, { ...opts, allowShared: false })
return webidl.converters.ArrayBuffer(V, prefix, name, { ...opts, allowShared: false })
}
if (types.isTypedArray(V)) {
return webidl.converters.TypedArray(V, V.constructor, { ...opts, allowShared: false })
return webidl.converters.TypedArray(V, V.constructor, prefix, name, { ...opts, allowShared: false })
}
if (types.isDataView(V)) {
return webidl.converters.DataView(V, opts, { ...opts, allowShared: false })
return webidl.converters.DataView(V, prefix, name, { ...opts, allowShared: false })
}
throw new TypeError(`Could not convert ${webidl.util.Stringify(V)} to a BufferSource.`)
throw webidl.errors.conversionFailed({
prefix,
argument: `${name} ("${webidl.util.Stringify(V)}")`,
types: ['BufferSource']
})
}
webidl.converters['sequence<ByteString>'] = webidl.sequenceConverter(

View File

@ -39,7 +39,7 @@ class FileReader extends EventTarget {
readAsArrayBuffer (blob) {
webidl.brandCheck(this, FileReader)
webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsArrayBuffer' })
webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsArrayBuffer')
blob = webidl.converters.Blob(blob, { strict: false })
@ -55,7 +55,7 @@ class FileReader extends EventTarget {
readAsBinaryString (blob) {
webidl.brandCheck(this, FileReader)
webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsBinaryString' })
webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsBinaryString')
blob = webidl.converters.Blob(blob, { strict: false })
@ -72,12 +72,12 @@ class FileReader extends EventTarget {
readAsText (blob, encoding = undefined) {
webidl.brandCheck(this, FileReader)
webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsText' })
webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsText')
blob = webidl.converters.Blob(blob, { strict: false })
if (encoding !== undefined) {
encoding = webidl.converters.DOMString(encoding)
encoding = webidl.converters.DOMString(encoding, 'FileReader.readAsText', 'encoding')
}
// The readAsText(blob, encoding) method, when invoked,
@ -92,7 +92,7 @@ class FileReader extends EventTarget {
readAsDataURL (blob) {
webidl.brandCheck(this, FileReader)
webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsDataURL' })
webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsDataURL')
blob = webidl.converters.Blob(blob, { strict: false })

View File

@ -9,7 +9,7 @@ const kState = Symbol('ProgressEvent state')
*/
class ProgressEvent extends Event {
constructor (type, eventInitDict = {}) {
type = webidl.converters.DOMString(type)
type = webidl.converters.DOMString(type, 'ProgressEvent constructor', 'type')
eventInitDict = webidl.converters.ProgressEventInit(eventInitDict ?? {})
super(type, eventInitDict)
@ -44,32 +44,32 @@ webidl.converters.ProgressEventInit = webidl.dictionaryConverter([
{
key: 'lengthComputable',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'loaded',
converter: webidl.converters['unsigned long long'],
defaultValue: 0
defaultValue: () => 0
},
{
key: 'total',
converter: webidl.converters['unsigned long long'],
defaultValue: 0
defaultValue: () => 0
},
{
key: 'bubbles',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'cancelable',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'composed',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
}
])

View File

@ -267,7 +267,7 @@ function onSocketClose () {
// decode without BOM to the WebSocket connection close
// reason.
// TODO: process.nextTick
fireEvent('close', ws, CloseEvent, {
fireEvent('close', ws, (type, init) => new CloseEvent(type, init), {
wasClean, code, reason
})

View File

@ -2,6 +2,7 @@
const { webidl } = require('../fetch/webidl')
const { kEnumerableProperty } = require('../../core/util')
const { kConstruct } = require('../../core/symbols')
const { MessagePort } = require('node:worker_threads')
/**
@ -11,10 +12,16 @@ class MessageEvent extends Event {
#eventInit
constructor (type, eventInitDict = {}) {
webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent constructor' })
if (type === kConstruct) {
super(arguments[1], arguments[2])
return
}
type = webidl.converters.DOMString(type)
eventInitDict = webidl.converters.MessageEventInit(eventInitDict)
const prefix = 'MessageEvent constructor'
webidl.argumentLengthCheck(arguments, 1, prefix)
type = webidl.converters.DOMString(type, prefix, 'type')
eventInitDict = webidl.converters.MessageEventInit(eventInitDict, prefix, 'eventInitDict')
super(type, eventInitDict)
@ -67,14 +74,28 @@ class MessageEvent extends Event {
) {
webidl.brandCheck(this, MessageEvent)
webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent.initMessageEvent' })
webidl.argumentLengthCheck(arguments, 1, 'MessageEvent.initMessageEvent')
return new MessageEvent(type, {
bubbles, cancelable, data, origin, lastEventId, source, ports
})
}
static createFastMessageEvent (type, init) {
const messageEvent = new MessageEvent(kConstruct, type, init)
messageEvent.#eventInit = init
messageEvent.#eventInit.data ??= null
messageEvent.#eventInit.origin ??= ''
messageEvent.#eventInit.lastEventId ??= ''
messageEvent.#eventInit.source ??= null
messageEvent.#eventInit.ports ??= []
return messageEvent
}
}
const { createFastMessageEvent } = MessageEvent
delete MessageEvent.createFastMessageEvent
/**
* @see https://websockets.spec.whatwg.org/#the-closeevent-interface
*/
@ -82,9 +103,10 @@ class CloseEvent extends Event {
#eventInit
constructor (type, eventInitDict = {}) {
webidl.argumentLengthCheck(arguments, 1, { header: 'CloseEvent constructor' })
const prefix = 'CloseEvent constructor'
webidl.argumentLengthCheck(arguments, 1, prefix)
type = webidl.converters.DOMString(type)
type = webidl.converters.DOMString(type, prefix, 'type')
eventInitDict = webidl.converters.CloseEventInit(eventInitDict)
super(type, eventInitDict)
@ -116,11 +138,12 @@ class ErrorEvent extends Event {
#eventInit
constructor (type, eventInitDict) {
webidl.argumentLengthCheck(arguments, 1, { header: 'ErrorEvent constructor' })
const prefix = 'ErrorEvent constructor'
webidl.argumentLengthCheck(arguments, 1, prefix)
super(type, eventInitDict)
type = webidl.converters.DOMString(type)
type = webidl.converters.DOMString(type, prefix, 'type')
eventInitDict = webidl.converters.ErrorEventInit(eventInitDict ?? {})
this.#eventInit = eventInitDict
@ -202,17 +225,17 @@ const eventInit = [
{
key: 'bubbles',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'cancelable',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'composed',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
}
]
@ -221,31 +244,29 @@ webidl.converters.MessageEventInit = webidl.dictionaryConverter([
{
key: 'data',
converter: webidl.converters.any,
defaultValue: null
defaultValue: () => null
},
{
key: 'origin',
converter: webidl.converters.USVString,
defaultValue: ''
defaultValue: () => ''
},
{
key: 'lastEventId',
converter: webidl.converters.DOMString,
defaultValue: ''
defaultValue: () => ''
},
{
key: 'source',
// Node doesn't implement WindowProxy or ServiceWorker, so the only
// valid value for source is a MessagePort.
converter: webidl.nullableConverter(webidl.converters.MessagePort),
defaultValue: null
defaultValue: () => null
},
{
key: 'ports',
converter: webidl.converters['sequence<MessagePort>'],
get defaultValue () {
return []
}
defaultValue: () => new Array(0)
}
])
@ -254,17 +275,17 @@ webidl.converters.CloseEventInit = webidl.dictionaryConverter([
{
key: 'wasClean',
converter: webidl.converters.boolean,
defaultValue: false
defaultValue: () => false
},
{
key: 'code',
converter: webidl.converters['unsigned short'],
defaultValue: 0
defaultValue: () => 0
},
{
key: 'reason',
converter: webidl.converters.USVString,
defaultValue: ''
defaultValue: () => ''
}
])
@ -273,22 +294,22 @@ webidl.converters.ErrorEventInit = webidl.dictionaryConverter([
{
key: 'message',
converter: webidl.converters.DOMString,
defaultValue: ''
defaultValue: () => ''
},
{
key: 'filename',
converter: webidl.converters.USVString,
defaultValue: ''
defaultValue: () => ''
},
{
key: 'lineno',
converter: webidl.converters['unsigned long'],
defaultValue: 0
defaultValue: () => 0
},
{
key: 'colno',
converter: webidl.converters['unsigned long'],
defaultValue: 0
defaultValue: () => 0
},
{
key: 'error',
@ -299,5 +320,6 @@ webidl.converters.ErrorEventInit = webidl.dictionaryConverter([
module.exports = {
MessageEvent,
CloseEvent,
ErrorEvent
ErrorEvent,
createFastMessageEvent
}

View File

@ -2,7 +2,7 @@
const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = require('./symbols')
const { states, opcodes } = require('./constants')
const { MessageEvent, ErrorEvent } = require('./events')
const { ErrorEvent, createFastMessageEvent } = require('./events')
const { isUtf8 } = require('node:buffer')
/* globals Blob */
@ -51,15 +51,16 @@ function isClosed (ws) {
* @see https://dom.spec.whatwg.org/#concept-event-fire
* @param {string} e
* @param {EventTarget} target
* @param {(...args: ConstructorParameters<typeof Event>) => Event} eventFactory
* @param {EventInit | undefined} eventInitDict
*/
function fireEvent (e, target, eventConstructor = Event, eventInitDict = {}) {
function fireEvent (e, target, eventFactory = (type, init) => new Event(type, init), eventInitDict = {}) {
// 1. If eventConstructor is not given, then let eventConstructor be Event.
// 2. Let event be the result of creating an event given eventConstructor,
// in the relevant realm of target.
// 3. Initialize events type attribute to e.
const event = new eventConstructor(e, eventInitDict) // eslint-disable-line new-cap
const event = eventFactory(e, eventInitDict)
// 4. Initialize any other IDL attributes of event as described in the
// invocation of this algorithm.
@ -110,7 +111,7 @@ function websocketMessageReceived (ws, type, data) {
// 3. Fire an event named message at the WebSocket object, using MessageEvent,
// with the origin attribute initialized to the serialization of the WebSocket
// objects url's origin, and the data attribute initialized to dataForEvent.
fireEvent('message', ws, MessageEvent, {
fireEvent('message', ws, createFastMessageEvent, {
origin: ws[kWebSocketURL].origin,
data: dataForEvent
})
@ -195,7 +196,7 @@ function failWebsocketConnection (ws, reason) {
if (reason) {
// TODO: process.nextTick
fireEvent('error', ws, ErrorEvent, {
fireEvent('error', ws, (type, init) => new ErrorEvent(type, init), {
error: new Error(reason)
})
}
@ -211,19 +212,12 @@ const fatalDecoder = hasIntl ? new TextDecoder('utf-8', { fatal: true }) : undef
*/
const utf8Decode = hasIntl
? fatalDecoder.decode.bind(fatalDecoder)
: !isUtf8
? function () { // TODO: remove once node 18 or < node v18.14.0 is dropped
process.emitWarning('ICU is not supported and no fallback exists. Please upgrade to at least Node v18.14.0.', {
code: 'UNDICI-WS-NO-ICU'
})
throw new TypeError('Invalid utf-8 received.')
}
: function (buffer) {
if (isUtf8(buffer)) {
return buffer.toString('utf-8')
}
throw new TypeError('Invalid utf-8 received.')
}
: function (buffer) {
if (isUtf8(buffer)) {
return buffer.toString('utf-8')
}
throw new TypeError('Invalid utf-8 received.')
}
module.exports = {
isConnecting,

View File

@ -51,7 +51,8 @@ class WebSocket extends EventTarget {
constructor (url, protocols = []) {
super()
webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket constructor' })
const prefix = 'WebSocket constructor'
webidl.argumentLengthCheck(arguments, 1, prefix)
if (!experimentalWarned) {
experimentalWarned = true
@ -60,9 +61,9 @@ class WebSocket extends EventTarget {
})
}
const options = webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'](protocols)
const options = webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'](protocols, prefix, 'options')
url = webidl.converters.USVString(url)
url = webidl.converters.USVString(url, prefix, 'url')
protocols = options.protocols
// 1. Let baseURL be this's relevant settings object's API base URL.
@ -159,12 +160,14 @@ class WebSocket extends EventTarget {
close (code = undefined, reason = undefined) {
webidl.brandCheck(this, WebSocket)
const prefix = 'WebSocket.close'
if (code !== undefined) {
code = webidl.converters['unsigned short'](code, { clamp: true })
code = webidl.converters['unsigned short'](code, prefix, 'code', { clamp: true })
}
if (reason !== undefined) {
reason = webidl.converters.USVString(reason)
reason = webidl.converters.USVString(reason, prefix, 'reason')
}
// 1. If code is present, but is neither an integer equal to 1000 nor an
@ -264,9 +267,10 @@ class WebSocket extends EventTarget {
send (data) {
webidl.brandCheck(this, WebSocket)
webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket.send' })
const prefix = 'WebSocket.send'
webidl.argumentLengthCheck(arguments, 1, prefix)
data = webidl.converters.WebSocketSendData(data)
data = webidl.converters.WebSocketSendData(data, prefix, 'data')
// 1. If this's ready state is CONNECTING, then throw an
// "InvalidStateError" DOMException.
@ -595,12 +599,12 @@ webidl.converters['sequence<DOMString>'] = webidl.sequenceConverter(
webidl.converters.DOMString
)
webidl.converters['DOMString or sequence<DOMString>'] = function (V) {
webidl.converters['DOMString or sequence<DOMString>'] = function (V, prefix, argument) {
if (webidl.util.Type(V) === 'Object' && Symbol.iterator in V) {
return webidl.converters['sequence<DOMString>'](V)
}
return webidl.converters.DOMString(V)
return webidl.converters.DOMString(V, prefix, argument)
}
// This implements the propsal made in https://github.com/whatwg/websockets/issues/42
@ -608,16 +612,12 @@ webidl.converters.WebSocketInit = webidl.dictionaryConverter([
{
key: 'protocols',
converter: webidl.converters['DOMString or sequence<DOMString>'],
get defaultValue () {
return []
}
defaultValue: () => new Array(0)
},
{
key: 'dispatcher',
converter: (V) => V,
get defaultValue () {
return getGlobalDispatcher()
}
defaultValue: () => getGlobalDispatcher()
},
{
key: 'headers',

232
deps/undici/src/package-lock.json generated vendored
View File

@ -1,19 +1,20 @@
{
"name": "undici",
"version": "6.13.0",
"version": "6.15.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "undici",
"version": "6.13.0",
"version": "6.15.0",
"license": "MIT",
"devDependencies": {
"@fastify/busboy": "2.1.1",
"@matteo.collina/tspl": "^0.1.1",
"@sinonjs/fake-timers": "^11.1.0",
"@types/node": "^18.0.3",
"abort-controller": "^3.0.0",
"borp": "^0.10.0",
"borp": "^0.12.0",
"c8": "^9.1.0",
"cross-env": "^7.0.3",
"dns-packet": "^5.4.0",
@ -34,16 +35,7 @@
"ws": "^8.11.0"
},
"engines": {
"node": ">=18.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
"node": ">=18.17"
}
},
"node_modules/@actions/core": {
@ -102,21 +94,21 @@
}
},
"node_modules/@babel/core": {
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz",
"integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz",
"integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.2",
"@babel/generator": "^7.24.4",
"@babel/generator": "^7.24.5",
"@babel/helper-compilation-targets": "^7.23.6",
"@babel/helper-module-transforms": "^7.23.3",
"@babel/helpers": "^7.24.4",
"@babel/parser": "^7.24.4",
"@babel/helper-module-transforms": "^7.24.5",
"@babel/helpers": "^7.24.5",
"@babel/parser": "^7.24.5",
"@babel/template": "^7.24.0",
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0",
"@babel/traverse": "^7.24.5",
"@babel/types": "^7.24.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@ -132,12 +124,12 @@
}
},
"node_modules/@babel/generator": {
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
"integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz",
"integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==",
"dev": true,
"dependencies": {
"@babel/types": "^7.24.0",
"@babel/types": "^7.24.5",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
@ -209,16 +201,16 @@
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
"integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz",
"integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-module-imports": "^7.22.15",
"@babel/helper-simple-access": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/helper-validator-identifier": "^7.22.20"
"@babel/helper-module-imports": "^7.24.3",
"@babel/helper-simple-access": "^7.24.5",
"@babel/helper-split-export-declaration": "^7.24.5",
"@babel/helper-validator-identifier": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
@ -228,33 +220,33 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
"version": "7.24.0",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz",
"integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-simple-access": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
"integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz",
"integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
"@babel/types": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-split-export-declaration": {
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
"integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
"@babel/types": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
@ -270,9 +262,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
"integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@ -288,26 +280,26 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz",
"integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz",
"integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==",
"dev": true,
"dependencies": {
"@babel/template": "^7.24.0",
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0"
"@babel/traverse": "^7.24.5",
"@babel/types": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
"version": "7.24.2",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
"integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz",
"integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.20",
"@babel/helper-validator-identifier": "^7.24.5",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
@ -388,9 +380,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
"integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
"integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@ -591,19 +583,19 @@
}
},
"node_modules/@babel/traverse": {
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
"integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz",
"integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.24.1",
"@babel/generator": "^7.24.1",
"@babel/code-frame": "^7.24.2",
"@babel/generator": "^7.24.5",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.24.1",
"@babel/types": "^7.24.0",
"@babel/helper-split-export-declaration": "^7.24.5",
"@babel/parser": "^7.24.5",
"@babel/types": "^7.24.5",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@ -612,13 +604,13 @@
}
},
"node_modules/@babel/types": {
"version": "7.24.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
"integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
"integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20",
"@babel/helper-string-parser": "^7.24.1",
"@babel/helper-validator-identifier": "^7.24.5",
"to-fast-properties": "^2.0.0"
},
"engines": {
@ -2146,9 +2138,9 @@
"dev": true
},
"node_modules/borp": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/borp/-/borp-0.10.0.tgz",
"integrity": "sha512-O5ToZzO0r3K+cH4x/eS0CRO7woLhiJqgufnCSb2tSjZJOe6bLIlxRaC6YQTaorNF9Nvid9HKYmfpPOuJUNKQvw==",
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/borp/-/borp-0.12.0.tgz",
"integrity": "sha512-42kZobvDzqbUFoe1jhwVWRFYNEM/7ua+7tvyDyHxWcxtZp4lppWpizlLuaSAzgci8w4DJRmWdQuhrjXs/sSr5A==",
"dev": true,
"dependencies": {
"@reporters/github": "^1.5.4",
@ -2406,9 +2398,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001609",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz",
"integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==",
"version": "1.0.30001614",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz",
"integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==",
"dev": true,
"funding": [
{
@ -2466,9 +2458,9 @@
}
},
"node_modules/cjs-module-lexer": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz",
"integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz",
"integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==",
"dev": true
},
"node_modules/cliui": {
@ -2977,9 +2969,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.736",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz",
"integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==",
"version": "1.4.751",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz",
"integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==",
"dev": true
},
"node_modules/emittery": {
@ -3103,14 +3095,14 @@
}
},
"node_modules/es-iterator-helpers": {
"version": "1.0.18",
"resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz",
"integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==",
"version": "1.0.19",
"resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz",
"integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.0",
"es-abstract": "^1.23.3",
"es-errors": "^1.3.0",
"es-set-tostringtag": "^2.0.3",
"function-bind": "^1.1.2",
@ -4052,9 +4044,9 @@
}
},
"node_modules/fast-check": {
"version": "3.17.1",
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.17.1.tgz",
"integrity": "sha512-jIKXJVe6ZO0SpwEgVtEVujTf8TwjI9wMXFJCjsDHUB3RroUbXBgF4kOSz3A7MW0UR26aqsoB8i9O2mjtjERAiA==",
"version": "3.18.0",
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.18.0.tgz",
"integrity": "sha512-/951xaT0kA40w0GXRsZXEwSTE7LugjZtSA/8vPgFkiPQ8wNp8tRvqWuNDHBgLxJYXtsK11e/7Q4ObkKW5BdTFQ==",
"dev": true,
"funding": [
{
@ -4433,12 +4425,13 @@
}
},
"node_modules/globalthis": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
"integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
"dev": true,
"dependencies": {
"define-properties": "^1.1.3"
"define-properties": "^1.2.1",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
@ -6789,9 +6782,9 @@
}
},
"node_modules/nwsapi": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
"integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==",
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz",
"integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==",
"dev": true
},
"node_modules/object-assign": {
@ -6944,17 +6937,17 @@
}
},
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
"dependencies": {
"@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
"type-check": "^0.4.0"
"type-check": "^0.4.0",
"word-wrap": "^1.2.5"
},
"engines": {
"node": ">= 0.8.0"
@ -7127,9 +7120,9 @@
}
},
"node_modules/path-scurry/node_modules/lru-cache": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
"version": "10.2.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
"integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
"dev": true,
"engines": {
"node": "14 || >=16.14"
@ -7581,9 +7574,9 @@
}
},
"node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"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
},
"node_modules/read-pkg": {
@ -8771,9 +8764,9 @@
}
},
"node_modules/tough-cookie": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"dev": true,
"dependencies": {
"psl": "^1.1.33",
@ -9312,6 +9305,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
@ -9426,9 +9428,9 @@
"dev": true
},
"node_modules/ws": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"version": "8.17.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz",
"integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==",
"dev": true,
"engines": {
"node": ">=10.0.0"

View File

@ -1,6 +1,6 @@
{
"name": "undici",
"version": "6.13.0",
"version": "6.15.0",
"description": "An HTTP/1.1 client, written from scratch for Node.js",
"homepage": "https://undici.nodejs.org",
"bugs": {
@ -100,11 +100,12 @@
"prepare": "husky install && node ./scripts/platform-shell.js"
},
"devDependencies": {
"@fastify/busboy": "2.1.1",
"@matteo.collina/tspl": "^0.1.1",
"@sinonjs/fake-timers": "^11.1.0",
"@types/node": "^18.0.3",
"abort-controller": "^3.0.0",
"borp": "^0.10.0",
"borp": "^0.12.0",
"c8": "^9.1.0",
"cross-env": "^7.0.3",
"dns-packet": "^5.4.0",
@ -125,7 +126,7 @@
"ws": "^8.11.0"
},
"engines": {
"node": ">=18.0"
"node": ">=18.17"
},
"standard": {
"env": [

View File

@ -217,7 +217,7 @@ declare namespace Dispatcher {
export type StreamFactory = (data: StreamFactoryData) => Writable;
export interface DispatchHandlers {
/** Invoked before request is dispatched on socket. May be invoked multiple times when a request is retried when the request at the head of the pipeline fails. */
onConnect?(abort: () => void): void;
onConnect?(abort: (err?: Error) => void): void;
/** Invoked when an error has occurred. */
onError?(err: Error): void;
/** Invoked when request is upgraded either due to a `Upgrade` header or `CONNECT` method. */

View File

@ -1,4 +1,5 @@
import { MessageEvent, ErrorEvent } from './websocket'
import Dispatcher from './dispatcher'
import {
EventTarget,
@ -50,12 +51,13 @@ interface EventSource extends EventTarget {
export declare const EventSource: {
prototype: EventSource
new (url: string | URL, init: EventSourceInit): EventSource
new (url: string | URL, init?: EventSourceInit): EventSource
readonly CLOSED: 2
readonly CONNECTING: 0
readonly OPEN: 1
}
interface EventSourceInit {
withCredentials?: boolean
withCredentials?: boolean,
dispatcher?: Dispatcher
}

View File

@ -14,6 +14,7 @@ import MockPool from'./mock-pool'
import MockAgent from'./mock-agent'
import mockErrors from'./mock-errors'
import ProxyAgent from'./proxy-agent'
import EnvHttpProxyAgent from './env-http-proxy-agent'
import RetryHandler from'./retry-handler'
import RetryAgent from'./retry-agent'
import { request, pipeline, stream, connect, upgrade } from './api'
@ -31,7 +32,7 @@ export * from './content-type'
export * from './cache'
export { Interceptable } from './mock-interceptor'
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent }
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, EnvHttpProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent }
export default Undici
declare namespace Undici {

View File

@ -55,7 +55,9 @@ interface WebidlUtil {
V: unknown,
bitLength: number,
signedness: 'signed' | 'unsigned',
opts?: ConvertToIntOpts
opts?: ConvertToIntOpts,
prefix: string,
argument: string
): number
/**
@ -73,14 +75,14 @@ interface WebidlConverters {
/**
* @see https://webidl.spec.whatwg.org/#es-DOMString
*/
DOMString (V: unknown, opts?: {
DOMString (V: unknown, prefix: string, argument: string, opts?: {
legacyNullToEmptyString: boolean
}): string
/**
* @see https://webidl.spec.whatwg.org/#es-ByteString
*/
ByteString (V: unknown): string
ByteString (V: unknown, prefix: string, argument: string): string
/**
* @see https://webidl.spec.whatwg.org/#es-USVString
@ -204,7 +206,7 @@ export interface Webidl {
*/
dictionaryConverter (converters: {
key: string,
defaultValue?: unknown,
defaultValue?: () => unknown,
required?: boolean,
converter: (...args: unknown[]) => unknown,
allowedValues?: unknown[]
@ -218,8 +220,5 @@ export interface Webidl {
converter: Converter<T>
): (V: unknown) => ReturnType<typeof converter> | null
argumentLengthCheck (args: { length: number }, min: number, context: {
header: string
message?: string
}): void
argumentLengthCheck (args: { length: number }, min: number, context: string): void
}

7976
deps/undici/undici.js vendored

File diff suppressed because one or more lines are too long

View File

@ -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 "6.13.0"
#define UNDICI_VERSION "6.15.0"
#endif // SRC_UNDICI_VERSION_H_

View File

@ -62,30 +62,30 @@ const dummyPort = new MessageChannel().port1;
new MessageEvent('message', { source: 1 });
}, {
name: 'TypeError',
message: /Expected 1 to be an instance of MessagePort/,
message: /MessageEvent constructor: Expected eventInitDict\.source \("1"\) to be an instance of MessagePort\./,
});
assert.throws(() => {
new MessageEvent('message', { source: {} });
}, {
name: 'TypeError',
message: /Expected {} to be an instance of MessagePort/,
message: /MessageEvent constructor: Expected eventInitDict\.source \("\{\}"\) to be an instance of MessagePort\./,
});
assert.throws(() => {
new MessageEvent('message', { ports: 0 });
}, {
message: /Sequence: Value of type Number is not an Object/,
message: /MessageEvent constructor: eventInitDict\.ports \(0\) is not iterable\./,
});
assert.throws(() => {
new MessageEvent('message', { ports: [ null ] });
}, {
name: 'TypeError',
message: /Expected null to be an instance of MessagePort/,
message: /MessageEvent constructor: Expected eventInitDict\.ports(\[0\])? \("null"\) to be an instance of MessagePort\./,
});
assert.throws(() => {
new MessageEvent('message', { ports: [ {} ] });
}, {
name: 'TypeError',
message: /Expected {} to be an instance of MessagePort/,
message: /MessageEvent constructor: Expected eventInitDict\.ports(\[0\])? \("\{\}"\) to be an instance of MessagePort\./,
});
}