diff --git a/deps/undici/src/README.md b/deps/undici/src/README.md index 475a9c1ba45397..bd991008a90e6d 100644 --- a/deps/undici/src/README.md +++ b/deps/undici/src/README.md @@ -178,10 +178,6 @@ Implements [fetch](https://fetch.spec.whatwg.org/#fetch-method). Only supported on Node 16.8+. -This is [experimental](https://nodejs.org/api/documentation.html#documentation_stability_index) and is not yet fully compliant with the Fetch Standard. -We plan to ship breaking changes to this feature until it is out of experimental. -Help us improve the test coverage by following instructions at [nodejs/undici/#951](https://github.com/nodejs/undici/issues/951). - Basic usage example: ```js @@ -234,9 +230,15 @@ const data = { }, } -await fetch('https://example.com', { body: data, method: 'POST' }) +await fetch('https://example.com', { body: data, method: 'POST', duplex: 'half' }) ``` +#### `request.duplex` + +- half + +In this implementation of fetch, `request.duplex` must be set if `request.body` is `ReadableStream` or `Async Iterables`. And fetch requests are currently always be full duplex. More detail refer to [Fetch Standard.](https://fetch.spec.whatwg.org/#dom-requestinit-duplex) + #### `response.body` Nodejs has two kinds of streams: [web streams](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html), which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`. diff --git a/deps/undici/src/docs/assets/lifecycle-diagram.png b/deps/undici/src/docs/assets/lifecycle-diagram.png index 01d1c321e3d3a5..4ef17b5a71454b 100644 Binary files a/deps/undici/src/docs/assets/lifecycle-diagram.png and b/deps/undici/src/docs/assets/lifecycle-diagram.png differ diff --git a/deps/undici/src/index.d.ts b/deps/undici/src/index.d.ts index 1aaf14d38b2764..d663178d410d43 100644 --- a/deps/undici/src/index.d.ts +++ b/deps/undici/src/index.d.ts @@ -1,19 +1,19 @@ -import Dispatcher = require('./types/dispatcher') +import Dispatcher from'./types/dispatcher' import { setGlobalDispatcher, getGlobalDispatcher } from './types/global-dispatcher' import { setGlobalOrigin, getGlobalOrigin } from './types/global-origin' -import Pool = require('./types/pool') +import Pool from'./types/pool' import { RedirectHandler, DecoratorHandler } from './types/handlers' -import BalancedPool = require('./types/balanced-pool') -import Client = require('./types/client') -import buildConnector = require('./types/connector') -import errors = require('./types/errors') -import Agent = require('./types/agent') -import MockClient = require('./types/mock-client') -import MockPool = require('./types/mock-pool') -import MockAgent = require('./types/mock-agent') -import mockErrors = require('./types/mock-errors') -import ProxyAgent = require('./types/proxy-agent') +import BalancedPool from './types/balanced-pool' +import Client from'./types/client' +import buildConnector from'./types/connector' +import errors from'./types/errors' +import Agent from'./types/agent' +import MockClient from'./types/mock-client' +import MockPool from'./types/mock-pool' +import MockAgent from'./types/mock-agent' +import mockErrors from'./types/mock-errors' +import ProxyAgent from'./types/proxy-agent' import { request, pipeline, stream, connect, upgrade } from './types/api' export * from './types/fetch' @@ -27,16 +27,16 @@ export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, export default Undici declare namespace Undici { - var Dispatcher: typeof import('./types/dispatcher') - var Pool: typeof import('./types/pool'); + var Dispatcher: typeof import('./types/dispatcher').default + var Pool: typeof import('./types/pool').default; var RedirectHandler: typeof import ('./types/handlers').RedirectHandler var DecoratorHandler: typeof import ('./types/handlers').DecoratorHandler var createRedirectInterceptor: typeof import ('./types/interceptors').createRedirectInterceptor - var BalancedPool: typeof import('./types/balanced-pool'); - var Client: typeof import('./types/client'); - var buildConnector: typeof import('./types/connector'); - var errors: typeof import('./types/errors'); - var Agent: typeof import('./types/agent'); + var BalancedPool: typeof import('./types/balanced-pool').default; + var Client: typeof import('./types/client').default; + var buildConnector: typeof import('./types/connector').default; + var errors: typeof import('./types/errors').default; + var Agent: typeof import('./types/agent').default; var setGlobalDispatcher: typeof import('./types/global-dispatcher').setGlobalDispatcher; var getGlobalDispatcher: typeof import('./types/global-dispatcher').getGlobalDispatcher; var request: typeof import('./types/api').request; @@ -44,9 +44,9 @@ declare namespace Undici { var pipeline: typeof import('./types/api').pipeline; var connect: typeof import('./types/api').connect; var upgrade: typeof import('./types/api').upgrade; - var MockClient: typeof import('./types/mock-client'); - var MockPool: typeof import('./types/mock-pool'); - var MockAgent: typeof import('./types/mock-agent'); - var mockErrors: typeof import('./types/mock-errors'); + var MockClient: typeof import('./types/mock-client').default; + var MockPool: typeof import('./types/mock-pool').default; + var MockAgent: typeof import('./types/mock-agent').default; + var mockErrors: typeof import('./types/mock-errors').default; var fetch: typeof import('./types/fetch').fetch; } diff --git a/deps/undici/src/lib/fetch/body.js b/deps/undici/src/lib/fetch/body.js index 7de30264d6898a..130a0bc669bb40 100644 --- a/deps/undici/src/lib/fetch/body.js +++ b/deps/undici/src/lib/fetch/body.js @@ -2,7 +2,7 @@ const Busboy = require('busboy') const util = require('../core/util') -const { ReadableStreamFrom, toUSVString, isBlobLike, isReadableStreamLike, readableStreamClose } = require('./util') +const { ReadableStreamFrom, isBlobLike, isReadableStreamLike, readableStreamClose } = require('./util') const { FormData } = require('./formdata') const { kState } = require('./symbols') const { webidl } = require('./webidl') @@ -66,9 +66,13 @@ function extractBody (object, keepalive = false) { let type = null // 10. Switch on object: - if (object == null) { - // Note: The IDL processor cannot handle this situation. See - // https://crbug.com/335871. + if (typeof object === 'string') { + // Set source to the UTF-8 encoding of object. + // Note: setting source to a Uint8Array here breaks some mocking assumptions. + source = object + + // Set type to `text/plain;charset=UTF-8`. + type = 'text/plain;charset=UTF-8' } else if (object instanceof URLSearchParams) { // URLSearchParams @@ -126,7 +130,8 @@ function extractBody (object, keepalive = false) { yield * value.stream() - yield enc.encode('\r\n') + // '\r\n' encoded + yield new Uint8Array([13, 10]) } } @@ -157,6 +162,11 @@ function extractBody (object, keepalive = false) { if (object.type) { type = object.type } + } else if (object instanceof Uint8Array) { + // byte sequence + + // Set source to object. + source = object } else if (typeof object[Symbol.asyncIterator] === 'function') { // If keepalive is true, then throw a TypeError. if (keepalive) { @@ -172,17 +182,10 @@ function extractBody (object, keepalive = false) { stream = object instanceof ReadableStream ? object : ReadableStreamFrom(object) - } else { - // TODO: byte sequence? - // TODO: scalar value string? - // TODO: else? - source = toUSVString(object) - type = 'text/plain;charset=UTF-8' } // 11. If source is a byte sequence, then set action to a // step that returns source and length to source’s length. - // TODO: What is a "byte sequence?" if (typeof source === 'string' || util.isBuffer(source)) { length = Buffer.byteLength(source) } @@ -329,9 +332,7 @@ function bodyMixinMethods (instance) { }, async formData () { - if (!(this instanceof instance)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, instance) throwIfAborted(this[kState]) @@ -433,7 +434,7 @@ function bodyMixinMethods (instance) { throwIfAborted(this[kState]) // Otherwise, throw a TypeError. - webidl.errors.exception({ + throw webidl.errors.exception({ header: `${instance.name}.formData`, message: 'Could not parse content as FormData.' }) @@ -450,11 +451,8 @@ function mixinBody (prototype) { // https://fetch.spec.whatwg.org/#concept-body-consume-body async function specConsumeBody (object, type, instance) { - if (!(object instanceof instance)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(object, instance) - // TODO: why is this needed? throwIfAborted(object[kState]) // 1. If object is unusable, then return a promise rejected diff --git a/deps/undici/src/lib/fetch/constants.js b/deps/undici/src/lib/fetch/constants.js index fe5028304b07d7..bc90a031cde31a 100644 --- a/deps/undici/src/lib/fetch/constants.js +++ b/deps/undici/src/lib/fetch/constants.js @@ -8,6 +8,17 @@ const nullBodyStatus = [101, 204, 205, 304] const redirectStatus = [301, 302, 303, 307, 308] +// https://fetch.spec.whatwg.org/#block-bad-port +const badPorts = [ + '1', '7', '9', '11', '13', '15', '17', '19', '20', '21', '22', '23', '25', '37', '42', '43', '53', '69', '77', '79', + '87', '95', '101', '102', '103', '104', '109', '110', '111', '113', '115', '117', '119', '123', '135', '137', + '139', '143', '161', '179', '389', '427', '465', '512', '513', '514', '515', '526', '530', '531', '532', + '540', '548', '554', '556', '563', '587', '601', '636', '989', '990', '993', '995', '1719', '1720', '1723', + '2049', '3659', '4045', '5060', '5061', '6000', '6566', '6665', '6666', '6667', '6668', '6669', '6697', + '10080' +] + +// https://w3c.github.io/webappsec-referrer-policy/#referrer-policies const referrerPolicy = [ '', 'no-referrer', @@ -44,6 +55,11 @@ const requestBodyHeader = [ 'content-type' ] +// https://fetch.spec.whatwg.org/#enumdef-requestduplex +const requestDuplex = [ + 'half' +] + // http://fetch.spec.whatwg.org/#forbidden-method const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK'] @@ -108,5 +124,7 @@ module.exports = { redirectStatus, corsSafeListedMethods, nullBodyStatus, - safeMethods + safeMethods, + badPorts, + requestDuplex } diff --git a/deps/undici/src/lib/fetch/dataURL.js b/deps/undici/src/lib/fetch/dataURL.js index a4269120e558a9..74b6d9ec472d76 100644 --- a/deps/undici/src/lib/fetch/dataURL.js +++ b/deps/undici/src/lib/fetch/dataURL.js @@ -1,6 +1,7 @@ const assert = require('assert') const { atob } = require('buffer') -const { isValidHTTPToken } = require('./util') +const { format } = require('url') +const { isValidHTTPToken, isomorphicDecode } = require('./util') const encoder = new TextEncoder() @@ -54,7 +55,6 @@ function dataURLProcessor (dataURL) { const encodedBody = input.slice(mimeTypeLength + 1) // 10. Let body be the percent-decoding of encodedBody. - /** @type {Uint8Array|string} */ let body = stringPercentDecode(encodedBody) // 11. If mimeType ends with U+003B (;), followed by @@ -62,7 +62,8 @@ function dataURLProcessor (dataURL) { // case-insensitive match for "base64", then: if (/;(\u0020){0,}base64$/i.test(mimeType)) { // 1. Let stringBody be the isomorphic decode of body. - const stringBody = decodeURIComponent(new TextDecoder('utf-8').decode(body)) + const stringBody = isomorphicDecode(body) + // 2. Set body to the forgiving-base64 decode of // stringBody. body = forgivingBase64(stringBody) @@ -111,73 +112,7 @@ function dataURLProcessor (dataURL) { * @param {boolean} excludeFragment */ function URLSerializer (url, excludeFragment = false) { - // 1. Let output be url’s scheme and U+003A (:) concatenated. - let output = url.protocol - - // 2. If url’s host is non-null: - if (url.host.length > 0) { - // 1. Append "//" to output. - output += '//' - - // 2. If url includes credentials, then: - if (url.username.length > 0 || url.password.length > 0) { - // 1. Append url’s username to output. - output += url.username - - // 2. If url’s password is not the empty string, then append U+003A (:), - // followed by url’s password, to output. - if (url.password.length > 0) { - output += ':' + url.password - } - - // 3. Append U+0040 (@) to output. - output += '@' - } - - // 3. Append url’s host, serialized, to output. - output += decodeURIComponent(url.hostname) - - // 4. If url’s port is non-null, append U+003A (:) followed by url’s port, - // serialized, to output. - if (url.port.length > 0) { - output += ':' + url.port - } - } - - // 3. If url’s host is null, url does not have an opaque path, - // url’s path’s size is greater than 1, and url’s path[0] - // is the empty string, then append U+002F (/) followed by - // U+002E (.) to output. - // Note: This prevents web+demo:/.//not-a-host/ or web+demo:/path/..//not-a-host/, - // when parsed and then serialized, from ending up as web+demo://not-a-host/ - // (they end up as web+demo:/.//not-a-host/). - // Undici implementation note: url's path[0] can never be an - // empty string, so we have to slightly alter what the spec says. - if ( - url.host.length === 0 && - url.pathname.length > 1 && - url.href.slice(url.protocol.length + 1)[0] === '.' - ) { - output += '/.' - } - - // 4. Append the result of URL path serializing url to output. - output += url.pathname - - // 5. If url’s query is non-null, append U+003F (?), - // followed by url’s query, to output. - if (url.search.length > 0) { - output += url.search - } - - // 6. If exclude fragment is false and url’s fragment is non-null, - // then append U+0023 (#), followed by url’s fragment, to output. - if (excludeFragment === false && url.hash.length > 0) { - output += url.hash - } - - // 7. Return output. - return output + return format(url, { fragment: !excludeFragment }) } // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points diff --git a/deps/undici/src/lib/fetch/file.js b/deps/undici/src/lib/fetch/file.js index d0d8c68d79322a..f27fc7fb7be61a 100644 --- a/deps/undici/src/lib/fetch/file.js +++ b/deps/undici/src/lib/fetch/file.js @@ -13,9 +13,7 @@ class File extends Blob { // 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: - if (arguments.length < 2) { - throw new TypeError('2 arguments required') - } + webidl.argumentLengthCheck(arguments, 2, { header: 'File constructor' }) fileBits = webidl.converters['sequence'](fileBits) fileName = webidl.converters.USVString(fileName) @@ -76,32 +74,22 @@ class File extends Blob { } get name () { - if (!(this instanceof File)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, File) return this[kState].name } get lastModified () { - if (!(this instanceof File)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, File) return this[kState].lastModified } get type () { - if (!(this instanceof File)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, File) return this[kState].type } - - get [Symbol.toStringTag] () { - return this.constructor.name - } } class FileLike { @@ -153,65 +141,49 @@ class FileLike { } stream (...args) { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].blobLike.stream(...args) } arrayBuffer (...args) { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].blobLike.arrayBuffer(...args) } slice (...args) { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].blobLike.slice(...args) } text (...args) { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].blobLike.text(...args) } get size () { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].blobLike.size } get type () { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].blobLike.type } get name () { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].name } get lastModified () { - if (!(this instanceof FileLike)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileLike) return this[kState].lastModified } @@ -222,6 +194,10 @@ class FileLike { } Object.defineProperties(File.prototype, { + [Symbol.toStringTag]: { + value: 'File', + configurable: true + }, name: kEnumerableProperty, lastModified: kEnumerableProperty }) diff --git a/deps/undici/src/lib/fetch/formdata.js b/deps/undici/src/lib/fetch/formdata.js index d5e2ba661da501..5d0649ba92efce 100644 --- a/deps/undici/src/lib/fetch/formdata.js +++ b/deps/undici/src/lib/fetch/formdata.js @@ -8,11 +8,9 @@ const { Blob } = require('buffer') // https://xhr.spec.whatwg.org/#formdata class FormData { - static name = 'FormData' - constructor (form) { if (form !== undefined) { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: 'FormData constructor', argument: 'Argument 1', types: ['undefined'] @@ -23,15 +21,9 @@ class FormData { } append (name, value, filename = undefined) { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'append' on 'FormData': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.append' }) if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError( @@ -58,15 +50,9 @@ class FormData { } delete (name) { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'delete' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.delete' }) name = webidl.converters.USVString(name) @@ -83,15 +69,9 @@ class FormData { } get (name) { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'get' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.get' }) name = webidl.converters.USVString(name) @@ -108,15 +88,9 @@ class FormData { } getAll (name) { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'getAll' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.getAll' }) name = webidl.converters.USVString(name) @@ -130,15 +104,9 @@ class FormData { } has (name) { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'has' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.has' }) name = webidl.converters.USVString(name) @@ -148,15 +116,9 @@ class FormData { } set (name, value, filename = undefined) { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'set' on 'FormData': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.set' }) if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError( @@ -196,14 +158,8 @@ class FormData { } } - get [Symbol.toStringTag] () { - return this.constructor.name - } - entries () { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) return makeIterator( () => this[kState].map(pair => [pair.name, pair.value]), @@ -213,9 +169,7 @@ class FormData { } keys () { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) return makeIterator( () => this[kState].map(pair => [pair.name, pair.value]), @@ -225,9 +179,7 @@ class FormData { } values () { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) return makeIterator( () => this[kState].map(pair => [pair.name, pair.value]), @@ -241,15 +193,9 @@ class FormData { * @param {unknown} thisArg */ forEach (callbackFn, thisArg = globalThis) { - if (!(this instanceof FormData)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'forEach' on 'FormData': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.forEach' }) if (typeof callbackFn !== 'function') { throw new TypeError( @@ -265,6 +211,13 @@ class FormData { FormData.prototype[Symbol.iterator] = FormData.prototype.entries +Object.defineProperties(FormData.prototype, { + [Symbol.toStringTag]: { + value: 'FormData', + configurable: true + } +}) + /** * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#create-an-entry * @param {string} name diff --git a/deps/undici/src/lib/fetch/headers.js b/deps/undici/src/lib/fetch/headers.js index 3b0eb833e5a1a9..76d5cde578b341 100644 --- a/deps/undici/src/lib/fetch/headers.js +++ b/deps/undici/src/lib/fetch/headers.js @@ -38,7 +38,7 @@ function fill (headers, object) { for (const header of object) { // 1. If header does not contain exactly two items, then throw a TypeError. if (header.length !== 2) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Headers constructor', message: `expected name/value pair to be length 2, found ${header.length}.` }) @@ -56,7 +56,7 @@ function fill (headers, object) { headers.append(key, value) } } else { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: 'Headers constructor', argument: 'Argument 1', types: ['sequence>', 'record'] @@ -129,8 +129,6 @@ class HeadersList { // https://fetch.spec.whatwg.org/#concept-header-list-get get (name) { - name = name.toLowerCase() - // 1. If list does not contain name, then return null. if (!this.contains(name)) { return null @@ -139,12 +137,7 @@ class HeadersList { // 2. Return the values of all headers in list whose name // is a byte-case-insensitive match for name, // separated from each other by 0x2C 0x20, in order. - return this[kHeadersMap].get(name) ?? null - } - - has (name) { - name = name.toLowerCase() - return this[kHeadersMap].has(name) + return this[kHeadersMap].get(name.toLowerCase()) ?? null } * [Symbol.iterator] () { @@ -171,21 +164,11 @@ class Headers { } } - get [Symbol.toStringTag] () { - return this.constructor.name - } - // https://fetch.spec.whatwg.org/#dom-headers-append append (name, value) { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'append' on 'Headers': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.append' }) name = webidl.converters.ByteString(name) value = webidl.converters.ByteString(value) @@ -196,13 +179,13 @@ class Headers { // 2. If name is not a header name or value is not a // header value, then throw a TypeError. if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: 'Headers.append', value: name, type: 'header name' }) } else if (!isValidHeaderValue(value)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: 'Headers.append', value, type: 'header value' @@ -231,21 +214,15 @@ class Headers { // https://fetch.spec.whatwg.org/#dom-headers-delete delete (name) { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'delete' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.delete' }) name = webidl.converters.ByteString(name) // 1. If name is not a header name, then throw a TypeError. if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: 'Headers.delete', value: name, type: 'header name' @@ -282,21 +259,15 @@ class Headers { // https://fetch.spec.whatwg.org/#dom-headers-get get (name) { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'get' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.get' }) name = webidl.converters.ByteString(name) // 1. If name is not a header name, then throw a TypeError. if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: 'Headers.get', value: name, type: 'header name' @@ -310,21 +281,15 @@ class Headers { // https://fetch.spec.whatwg.org/#dom-headers-has has (name) { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'has' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.has' }) name = webidl.converters.ByteString(name) // 1. If name is not a header name, then throw a TypeError. if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: 'Headers.has', value: name, type: 'header name' @@ -338,15 +303,9 @@ class Headers { // https://fetch.spec.whatwg.org/#dom-headers-set set (name, value) { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'set' on 'Headers': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.set' }) name = webidl.converters.ByteString(name) value = webidl.converters.ByteString(value) @@ -357,13 +316,13 @@ class Headers { // 2. If name is not a header name or value is not a // header value, then throw a TypeError. if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: 'Headers.set', value: name, type: 'header name' }) } else if (!isValidHeaderValue(value)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: 'Headers.set', value, type: 'header value' @@ -399,9 +358,7 @@ class Headers { } keys () { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) return makeIterator( () => [...this[kHeadersSortedMap].entries()], @@ -411,9 +368,7 @@ class Headers { } values () { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) return makeIterator( () => [...this[kHeadersSortedMap].entries()], @@ -423,9 +378,7 @@ class Headers { } entries () { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) return makeIterator( () => [...this[kHeadersSortedMap].entries()], @@ -439,15 +392,9 @@ class Headers { * @param {unknown} thisArg */ forEach (callbackFn, thisArg = globalThis) { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'forEach' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.forEach' }) if (typeof callbackFn !== 'function') { throw new TypeError( @@ -461,9 +408,7 @@ class Headers { } [Symbol.for('nodejs.util.inspect.custom')] () { - if (!(this instanceof Headers)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Headers) return this[kHeadersList] } @@ -481,7 +426,11 @@ Object.defineProperties(Headers.prototype, { values: kEnumerableProperty, entries: kEnumerableProperty, forEach: kEnumerableProperty, - [Symbol.iterator]: { enumerable: false } + [Symbol.iterator]: { enumerable: false }, + [Symbol.toStringTag]: { + value: 'Headers', + configurable: true + } }) webidl.converters.HeadersInit = function (V) { @@ -493,7 +442,7 @@ webidl.converters.HeadersInit = function (V) { return webidl.converters['record'](V) } - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: 'Headers constructor', argument: 'Argument 1', types: ['sequence>', 'record'] diff --git a/deps/undici/src/lib/fetch/index.js b/deps/undici/src/lib/fetch/index.js index 0b99d546380fb6..94f2d1e0aca5ab 100644 --- a/deps/undici/src/lib/fetch/index.js +++ b/deps/undici/src/lib/fetch/index.js @@ -36,7 +36,8 @@ const { isAborted, isErrorLike, fullyReadBody, - readableStreamClose + readableStreamClose, + isomorphicEncode } = require('./util') const { kState, kHeaders, kGuard, kRealm } = require('./symbols') const assert = require('assert') @@ -56,6 +57,7 @@ const { isErrored, isReadable } = require('../core/util') const { dataURLProcessor, serializeAMimeType } = require('./dataURL') const { TransformStream } = require('stream/web') const { getGlobalDispatcher } = require('../../index') +const { webidl } = require('./webidl') /** @type {import('buffer').resolveObjectURL} */ let resolveObjectURL @@ -121,11 +123,7 @@ class Fetch extends EE { // https://fetch.spec.whatwg.org/#fetch-method async function fetch (input, init = {}) { - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'fetch' on 'Window': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'globalThis.fetch' }) // 1. Let p be a new promise. const p = createDeferredPromise() @@ -477,7 +475,7 @@ function fetching ({ } // 12. If request’s header list does not contain `Accept`, then: - if (!request.headersList.has('accept')) { + if (!request.headersList.contains('accept')) { // 1. Let value be `*/*`. const value = '*/*' @@ -500,7 +498,7 @@ function fetching ({ // 13. If request’s header list does not contain `Accept-Language`, then // user agents should append `Accept-Language`/an appropriate value to // request’s header list. - if (!request.headersList.has('accept-language')) { + if (!request.headersList.contains('accept-language')) { request.headersList.append('accept-language', '*') } @@ -723,7 +721,7 @@ async function mainFetch (fetchParams, recursive = false) { response.type === 'opaque' && internalResponse.status === 206 && internalResponse.rangeRequested && - !request.headers.has('range') + !request.headers.contains('range') ) { response = internalResponse = makeNetworkError() } @@ -832,7 +830,7 @@ async function schemeFetch (fetchParams) { const body = bodyWithType[0] // 5. Let length be body’s length, serialized and isomorphic encoded. - const length = `${body.length}` + const length = isomorphicEncode(`${body.length}`) // 6. Let type be bodyWithType’s type if it is non-null; otherwise the empty byte sequence. const type = bodyWithType[1] ?? '' @@ -1303,8 +1301,7 @@ async function httpNetworkOrCacheFetch ( // 7. If contentLength is non-null, then set contentLengthHeaderValue to // contentLength, serialized and isomorphic encoded. if (contentLength != null) { - // TODO: isomorphic encoded - contentLengthHeaderValue = String(contentLength) + contentLengthHeaderValue = isomorphicEncode(`${contentLength}`) } // 8. If contentLengthHeaderValue is non-null, then append @@ -1327,8 +1324,7 @@ async function httpNetworkOrCacheFetch ( // `Referer`/httpRequest’s referrer, serialized and isomorphic encoded, // to httpRequest’s header list. if (httpRequest.referrer instanceof URL) { - // TODO: isomorphic encoded - httpRequest.headersList.append('referer', httpRequest.referrer.href) + httpRequest.headersList.append('referer', isomorphicEncode(httpRequest.referrer.href)) } // 12. Append a request `Origin` header for httpRequest. @@ -1340,7 +1336,7 @@ async function httpNetworkOrCacheFetch ( // 14. If httpRequest’s header list does not contain `User-Agent`, then // user agents should append `User-Agent`/default `User-Agent` value to // httpRequest’s header list. - if (!httpRequest.headersList.has('user-agent')) { + if (!httpRequest.headersList.contains('user-agent')) { httpRequest.headersList.append('user-agent', 'undici') } @@ -1350,11 +1346,11 @@ async function httpNetworkOrCacheFetch ( // httpRequest’s cache mode to "no-store". if ( httpRequest.cache === 'default' && - (httpRequest.headersList.has('if-modified-since') || - httpRequest.headersList.has('if-none-match') || - httpRequest.headersList.has('if-unmodified-since') || - httpRequest.headersList.has('if-match') || - httpRequest.headersList.has('if-range')) + (httpRequest.headersList.contains('if-modified-since') || + httpRequest.headersList.contains('if-none-match') || + httpRequest.headersList.contains('if-unmodified-since') || + httpRequest.headersList.contains('if-match') || + httpRequest.headersList.contains('if-range')) ) { httpRequest.cache = 'no-store' } @@ -1366,7 +1362,7 @@ async function httpNetworkOrCacheFetch ( if ( httpRequest.cache === 'no-cache' && !httpRequest.preventNoCacheCacheControlHeaderModification && - !httpRequest.headersList.has('cache-control') + !httpRequest.headersList.contains('cache-control') ) { httpRequest.headersList.append('cache-control', 'max-age=0') } @@ -1375,27 +1371,27 @@ async function httpNetworkOrCacheFetch ( if (httpRequest.cache === 'no-store' || httpRequest.cache === 'reload') { // 1. If httpRequest’s header list does not contain `Pragma`, then append // `Pragma`/`no-cache` to httpRequest’s header list. - if (!httpRequest.headersList.has('pragma')) { + if (!httpRequest.headersList.contains('pragma')) { httpRequest.headersList.append('pragma', 'no-cache') } // 2. If httpRequest’s header list does not contain `Cache-Control`, // then append `Cache-Control`/`no-cache` to httpRequest’s header list. - if (!httpRequest.headersList.has('cache-control')) { + if (!httpRequest.headersList.contains('cache-control')) { httpRequest.headersList.append('cache-control', 'no-cache') } } // 18. If httpRequest’s header list contains `Range`, then append // `Accept-Encoding`/`identity` to httpRequest’s header list. - if (httpRequest.headersList.has('range')) { + if (httpRequest.headersList.contains('range')) { httpRequest.headersList.append('accept-encoding', 'identity') } // 19. Modify httpRequest’s header list per HTTP. Do not append a given // header if httpRequest’s header list contains that header’s name. // TODO: https://github.com/whatwg/fetch/issues/1285#issuecomment-896560129 - if (!httpRequest.headersList.has('accept-encoding')) { + if (!httpRequest.headersList.contains('accept-encoding')) { if (/^https:/.test(requestCurrentURL(httpRequest).protocol)) { httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate') } else { @@ -1484,7 +1480,7 @@ async function httpNetworkOrCacheFetch ( // 12. If httpRequest’s header list contains `Range`, then set response’s // range-requested flag. - if (httpRequest.headersList.has('range')) { + if (httpRequest.headersList.contains('range')) { response.rangeRequested = true } diff --git a/deps/undici/src/lib/fetch/request.js b/deps/undici/src/lib/fetch/request.js index 7c3032bd5ed372..533ee91bc1023c 100644 --- a/deps/undici/src/lib/fetch/request.js +++ b/deps/undici/src/lib/fetch/request.js @@ -18,7 +18,8 @@ const { requestRedirect, requestMode, requestCredentials, - requestCache + requestCache, + requestDuplex } = require('./constants') const { kEnumerableProperty } = util const { kHeaders, kSignal, kState, kGuard, kRealm } = require('./symbols') @@ -44,11 +45,7 @@ class Request { return } - if (arguments.length < 1) { - throw new TypeError( - `Failed to construct 'Request': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Request constructor' }) input = webidl.converters.RequestInfo(input) init = webidl.converters.RequestInit(init) @@ -243,29 +240,19 @@ class Request { // to it. if (init.referrerPolicy !== undefined) { request.referrerPolicy = init.referrerPolicy - if (!referrerPolicy.includes(request.referrerPolicy)) { - throw new TypeError( - `Failed to construct 'Request': The provided value '${request.referrerPolicy}' is not a valid enum value of type ReferrerPolicy.` - ) - } } // 16. Let mode be init["mode"] if it exists, and fallbackMode otherwise. let mode if (init.mode !== undefined) { mode = init.mode - if (!requestMode.includes(mode)) { - throw new TypeError( - `Failed to construct 'Request': The provided value '${request.mode}' is not a valid enum value of type RequestMode.` - ) - } } else { mode = fallbackMode } // 17. If mode is "navigate", then throw a TypeError. if (mode === 'navigate') { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Request constructor', message: 'invalid request mode navigate.' }) @@ -280,21 +267,11 @@ class Request { // to it. if (init.credentials !== undefined) { request.credentials = init.credentials - if (!requestCredentials.includes(request.credentials)) { - throw new TypeError( - `Failed to construct 'Request': The provided value '${request.credentials}' is not a valid enum value of type RequestCredentials.` - ) - } } // 18. If init["cache"] exists, then set request’s cache mode to it. if (init.cache !== undefined) { request.cache = init.cache - if (!requestCache.includes(request.cache)) { - throw new TypeError( - `Failed to construct 'Request': The provided value '${request.cache}' is not a valid enum value of type RequestCache.` - ) - } } // 21. If request’s cache mode is "only-if-cached" and request’s mode is @@ -308,11 +285,6 @@ class Request { // 22. If init["redirect"] exists, then set request’s redirect mode to it. if (init.redirect !== undefined) { request.redirect = init.redirect - if (!requestRedirect.includes(request.redirect)) { - throw new TypeError( - `Failed to construct 'Request': The provided value '${request.redirect}' is not a valid enum value of type RequestRedirect.` - ) - } } // 23. If init["integrity"] exists, then set request’s integrity metadata to it. @@ -461,7 +433,7 @@ class Request { // 3, If Content-Type is non-null and this’s headers’s header list does // not contain `Content-Type`, then append `Content-Type`/Content-Type to // this’s headers. - if (contentType && !this[kHeaders].has('content-type')) { + if (contentType && !this[kHeaders][kHeadersList].contains('content-type')) { this[kHeaders].append('content-type', contentType) } } @@ -522,15 +494,9 @@ class Request { this[kState].body = finalBody } - get [Symbol.toStringTag] () { - return this.constructor.name - } - // Returns request’s HTTP method, which is "GET" by default. get method () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The method getter steps are to return this’s request’s method. return this[kState].method @@ -538,9 +504,7 @@ class Request { // Returns the URL of request as a string. get url () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The url getter steps are to return this’s request’s URL, serialized. return URLSerializer(this[kState].url) @@ -550,9 +514,7 @@ class Request { // Note that headers added in the network layer by the user agent will not // be accounted for in this object, e.g., the "Host" header. get headers () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The headers getter steps are to return this’s headers. return this[kHeaders] @@ -561,9 +523,7 @@ class Request { // Returns the kind of resource requested by request, e.g., "document" // or "script". get destination () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The destination getter are to return this’s request’s destination. return this[kState].destination @@ -575,9 +535,7 @@ class Request { // during fetching to determine the value of the `Referer` header of the // request being made. get referrer () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // 1. If this’s request’s referrer is "no-referrer", then return the // empty string. @@ -599,9 +557,7 @@ class Request { // This is used during fetching to compute the value of the request’s // referrer. get referrerPolicy () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The referrerPolicy getter steps are to return this’s request’s referrer policy. return this[kState].referrerPolicy @@ -611,9 +567,7 @@ class Request { // whether the request will use CORS, or will be restricted to same-origin // URLs. get mode () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The mode getter steps are to return this’s request’s mode. return this[kState].mode @@ -631,9 +585,7 @@ class Request { // which is a string indicating how the request will // interact with the browser’s cache when fetching. get cache () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The cache getter steps are to return this’s request’s cache mode. return this[kState].cache @@ -644,9 +596,7 @@ class Request { // request will be handled during fetching. A request // will follow redirects by default. get redirect () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The redirect getter steps are to return this’s request’s redirect mode. return this[kState].redirect @@ -656,9 +606,7 @@ class Request { // cryptographic hash of the resource being fetched. Its value // consists of multiple hashes separated by whitespace. [SRI] get integrity () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The integrity getter steps are to return this’s request’s integrity // metadata. @@ -668,9 +616,7 @@ class Request { // Returns a boolean indicating whether or not request can outlive the // global in which it was created. get keepalive () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The keepalive getter steps are to return this’s request’s keepalive. return this[kState].keepalive @@ -679,9 +625,7 @@ class Request { // Returns a boolean indicating whether or not request is for a reload // navigation. get isReloadNavigation () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The isReloadNavigation getter steps are to return true if this’s // request’s reload-navigation flag is set; otherwise false. @@ -691,9 +635,7 @@ class Request { // Returns a boolean indicating whether or not request is for a history // navigation (a.k.a. back-foward navigation). get isHistoryNavigation () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The isHistoryNavigation getter steps are to return true if this’s request’s // history-navigation flag is set; otherwise false. @@ -704,43 +646,33 @@ class Request { // object indicating whether or not request has been aborted, and its // abort event handler. get signal () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // The signal getter steps are to return this’s signal. return this[kSignal] } get body () { - if (!this || !this[kState]) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) return this[kState].body ? this[kState].body.stream : null } get bodyUsed () { - if (!this || !this[kState]) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) return !!this[kState].body && util.isDisturbed(this[kState].body.stream) } get duplex () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) return 'half' } // Returns a clone of request. clone () { - if (!(this instanceof Request)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Request) // 1. If this is unusable, then throw a TypeError. if (this.bodyUsed || this.body?.locked) { @@ -866,7 +798,11 @@ Object.defineProperties(Request.prototype, { attribute: kEnumerableProperty, referrerPolicy: kEnumerableProperty, referrer: kEnumerableProperty, - mode: kEnumerableProperty + mode: kEnumerableProperty, + [Symbol.toStringTag]: { + value: 'Request', + configurable: true + } }) webidl.converters.Request = webidl.interfaceConverter( @@ -914,45 +850,31 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([ key: 'referrerPolicy', converter: webidl.converters.DOMString, // https://w3c.github.io/webappsec-referrer-policy/#referrer-policy - allowedValues: [ - '', 'no-referrer', 'no-referrer-when-downgrade', - 'same-origin', 'origin', 'strict-origin', - 'origin-when-cross-origin', 'strict-origin-when-cross-origin', - 'unsafe-url' - ] + allowedValues: referrerPolicy }, { key: 'mode', converter: webidl.converters.DOMString, // https://fetch.spec.whatwg.org/#concept-request-mode - allowedValues: [ - 'same-origin', 'cors', 'no-cors', 'navigate', 'websocket' - ] + allowedValues: requestMode }, { key: 'credentials', converter: webidl.converters.DOMString, // https://fetch.spec.whatwg.org/#requestcredentials - allowedValues: [ - 'omit', 'same-origin', 'include' - ] + allowedValues: requestCredentials }, { key: 'cache', converter: webidl.converters.DOMString, // https://fetch.spec.whatwg.org/#requestcache - allowedValues: [ - 'default', 'no-store', 'reload', 'no-cache', 'force-cache', - 'only-if-cached' - ] + allowedValues: requestCache }, { key: 'redirect', converter: webidl.converters.DOMString, // https://fetch.spec.whatwg.org/#requestredirect - allowedValues: [ - 'follow', 'error', 'manual' - ] + allowedValues: requestRedirect }, { key: 'integrity', @@ -978,7 +900,7 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([ { key: 'duplex', converter: webidl.converters.DOMString, - allowedValues: ['half'] + allowedValues: requestDuplex } ]) diff --git a/deps/undici/src/lib/fetch/response.js b/deps/undici/src/lib/fetch/response.js index be97d67ce6f436..fc6746bfa8d840 100644 --- a/deps/undici/src/lib/fetch/response.js +++ b/deps/undici/src/lib/fetch/response.js @@ -10,7 +10,8 @@ const { isAborted, isBlobLike, serializeJavascriptValueToJSONString, - isErrorLike + isErrorLike, + isomorphicEncode } = require('./util') const { redirectStatus, @@ -49,11 +50,7 @@ class Response { // https://fetch.spec.whatwg.org/#dom-response-json static json (data = undefined, init = {}) { - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'json\' on \'Response\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Response.json' }) if (init !== null) { init = webidl.converters.ResponseInit(init) @@ -86,11 +83,7 @@ class Response { static redirect (url, status = 302) { const relevantRealm = { settingsObject: {} } - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'redirect' on 'Response': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Response.redirect' }) url = webidl.converters.USVString(url) status = webidl.converters['unsigned short'](status) @@ -110,7 +103,7 @@ class Response { // 3. If status is not a redirect status, then throw a RangeError. if (!redirectStatus.includes(status)) { - throw new RangeError('Invalid status code') + throw new RangeError('Invalid status code ' + status) } // 4. Let responseObject be the result of creating a Response object, @@ -124,8 +117,7 @@ class Response { responseObject[kState].status = status // 6. Let value be parsedURL, serialized and isomorphic encoded. - // TODO: isomorphic encoded? - const value = parsedURL.toString() + const value = isomorphicEncode(URLSerializer(parsedURL)) // 7. Append `Location`/value to responseObject’s response’s header list. responseObject[kState].headersList.append('location', value) @@ -169,15 +161,9 @@ class Response { initializeResponse(this, init, bodyWithType) } - get [Symbol.toStringTag] () { - return this.constructor.name - } - // Returns response’s type, e.g., "cors". get type () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) // The type getter steps are to return this’s response’s type. return this[kState].type @@ -185,9 +171,7 @@ class Response { // Returns response’s URL, if it has one; otherwise the empty string. get url () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) const urlList = this[kState].urlList @@ -205,9 +189,7 @@ class Response { // Returns whether response was obtained through a redirect. get redirected () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) // The redirected getter steps are to return true if this’s response’s URL // list has more than one item; otherwise false. @@ -216,9 +198,7 @@ class Response { // Returns response’s status. get status () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) // The status getter steps are to return this’s response’s status. return this[kState].status @@ -226,9 +206,7 @@ class Response { // Returns whether response’s status is an ok status. get ok () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) // The ok getter steps are to return true if this’s response’s status is an // ok status; otherwise false. @@ -237,9 +215,7 @@ class Response { // Returns response’s status message. get statusText () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) // The statusText getter steps are to return this’s response’s status // message. @@ -248,39 +224,31 @@ class Response { // Returns response’s headers as Headers. get headers () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) // The headers getter steps are to return this’s headers. return this[kHeaders] } get body () { - if (!this || !this[kState]) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) return this[kState].body ? this[kState].body.stream : null } get bodyUsed () { - if (!this || !this[kState]) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) return !!this[kState].body && util.isDisturbed(this[kState].body.stream) } // Returns a clone of response. clone () { - if (!(this instanceof Response)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, Response) // 1. If this is unusable, then throw a TypeError. if (this.bodyUsed || (this.body && this.body.locked)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Response.clone', message: 'Body has already been consumed.' }) @@ -314,7 +282,11 @@ Object.defineProperties(Response.prototype, { headers: kEnumerableProperty, clone: kEnumerableProperty, body: kEnumerableProperty, - bodyUsed: kEnumerableProperty + bodyUsed: kEnumerableProperty, + [Symbol.toStringTag]: { + value: 'Response', + configurable: true + } }) Object.defineProperties(Response, { @@ -504,9 +476,9 @@ function initializeResponse (response, init, body) { if (body) { // 1. If response's status is a null body status, then throw a TypeError. if (nullBodyStatus.includes(response.status)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Response constructor', - message: 'Invalid response status code.' + message: 'Invalid response status code ' + response.status }) } @@ -515,7 +487,7 @@ function initializeResponse (response, init, body) { // 3. If body's type is non-null and response's header list does not contain // `Content-Type`, then append (`Content-Type`, body's type) to response's header list. - if (body.type != null && !response[kState].headersList.has('Content-Type')) { + if (body.type != null && !response[kState].headersList.contains('Content-Type')) { response[kState].headersList.append('content-type', body.type) } } diff --git a/deps/undici/src/lib/fetch/util.js b/deps/undici/src/lib/fetch/util.js index c71ab16eec1458..4d21e2e17b981c 100644 --- a/deps/undici/src/lib/fetch/util.js +++ b/deps/undici/src/lib/fetch/util.js @@ -1,6 +1,6 @@ 'use strict' -const { redirectStatus } = require('./constants') +const { redirectStatus, badPorts, referrerPolicy: referrerPolicyTokens } = require('./constants') const { performance } = require('perf_hooks') const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util') const assert = require('assert') @@ -16,16 +16,6 @@ try { } -// https://fetch.spec.whatwg.org/#block-bad-port -const badPorts = [ - '1', '7', '9', '11', '13', '15', '17', '19', '20', '21', '22', '23', '25', '37', '42', '43', '53', '69', '77', '79', - '87', '95', '101', '102', '103', '104', '109', '110', '111', '113', '115', '117', '119', '123', '135', '137', - '139', '143', '161', '179', '389', '427', '465', '512', '513', '514', '515', '526', '530', '531', '532', - '540', '548', '554', '556', '563', '587', '601', '636', '989', '990', '993', '995', '1719', '1720', '1723', - '2049', '3659', '4045', '5060', '5061', '6000', '6566', '6665', '6666', '6667', '6668', '6669', '6697', - '10080' -] - function responseURL (response) { // https://fetch.spec.whatwg.org/#responses // A response has an associated URL. It is a pointer to the last URL @@ -156,13 +146,7 @@ function isValidHeaderName (potentialValue) { return false } - for (const char of potentialValue) { - if (!isValidHTTPToken(char)) { - return false - } - } - - return true + return isValidHTTPToken(potentialValue) } /** @@ -200,8 +184,31 @@ function setRequestReferrerPolicyOnRedirect (request, actualResponse) { // 1. Let policy be the result of executing § 8.1 Parse a referrer policy // from a Referrer-Policy header on actualResponse. - // TODO: https://w3c.github.io/webappsec-referrer-policy/#parse-referrer-policy-from-header - const policy = '' + + // 8.1 Parse a referrer policy from a Referrer-Policy header + // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy` and response’s header list. + const { headersList } = actualResponse + // 2. Let policy be the empty string. + // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty string, then set policy to token. + // 4. Return policy. + const policyHeader = (headersList.get('referrer-policy') ?? '').split(',') + + // Note: As the referrer-policy can contain multiple policies + // separated by comma, we need to loop through all of them + // and pick the first valid one. + // Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#specify_a_fallback_policy + let policy = '' + if (policyHeader.length > 0) { + // The right-most policy takes precedence. + // The left-most policy is the fallback. + for (let i = policyHeader.length; i !== 0; i--) { + const token = policyHeader[i - 1].trim() + if (referrerPolicyTokens.includes(token)) { + policy = token + break + } + } + } // 2. If policy is not the empty string, then set request’s referrer policy to policy. if (policy !== '') { @@ -856,6 +863,23 @@ function isReadableStreamLike (stream) { ) } +/** + * @see https://infra.spec.whatwg.org/#isomorphic-decode + * @param {number[]|Uint8Array} input + */ +function isomorphicDecode (input) { + // 1. To isomorphic decode a byte sequence input, return a string whose code point + // length is equal to input’s length and whose code points have the same values + // as the values of input’s bytes, in the same order. + let output = '' + + for (let i = 0; i < input.length; i++) { + output += String.fromCharCode(input[i]) + } + + return output +} + /** * @param {ReadableStreamController} controller */ @@ -870,6 +894,22 @@ function readableStreamClose (controller) { } } +/** + * @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) + } + + // 2. Return a byte sequence whose length is equal to input’s code + // point length and whose bytes have the same values as the + // values of input’s code points, in the same order + return input +} + /** * Fetch supports node >= 16.8.0, but Object.hasOwn was added in v16.9.0. */ @@ -912,5 +952,7 @@ module.exports = { fullyReadBody, bytesMatch, isReadableStreamLike, - readableStreamClose + readableStreamClose, + isomorphicEncode, + isomorphicDecode } diff --git a/deps/undici/src/lib/fetch/webidl.js b/deps/undici/src/lib/fetch/webidl.js index cd42de2ac8adf5..32c1befab000d7 100644 --- a/deps/undici/src/lib/fetch/webidl.js +++ b/deps/undici/src/lib/fetch/webidl.js @@ -3,30 +3,16 @@ const { types } = require('util') const { hasOwn, toUSVString } = require('./util') +/** @type {import('../../types/webidl').Webidl} */ const webidl = {} webidl.converters = {} webidl.util = {} webidl.errors = {} -/** - * - * @param {{ - * header: string - * message: string - * }} message - */ webidl.errors.exception = function (message) { - throw new TypeError(`${message.header}: ${message.message}`) + return new TypeError(`${message.header}: ${message.message}`) } -/** - * Throw an error when conversion from one type to another has failed - * @param {{ - * prefix: string - * argument: string - * types: string[] - * }} context - */ webidl.errors.conversionFailed = function (context) { const plural = context.types.length === 1 ? '' : ' one of' const message = @@ -39,14 +25,6 @@ webidl.errors.conversionFailed = function (context) { }) } -/** - * Throw an error when an invalid argument is provided - * @param {{ - * prefix: string - * value: string - * type: string - * }} context - */ webidl.errors.invalidArgument = function (context) { return webidl.errors.exception({ header: context.prefix, @@ -54,6 +32,23 @@ webidl.errors.invalidArgument = function (context) { }) } +// https://webidl.spec.whatwg.org/#implements +webidl.brandCheck = function (V, I) { + if (!(V instanceof I)) { + throw new TypeError('Illegal invocation') + } +} + +webidl.argumentLengthCheck = function ({ length }, min, ctx) { + if (length < min) { + throw webidl.errors.exception({ + message: `${min} argument${min !== 1 ? 's' : ''} required, ` + + `but${length ? ' only' : ''} ${length} found.`, + ...ctx + }) + } +} + // https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values webidl.util.Type = function (V) { switch (typeof V) { @@ -113,7 +108,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { let x = Number(V) // 5. If x is −0, then set x to +0. - if (Object.is(-0, x)) { + if (x === 0) { x = 0 } @@ -126,7 +121,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY ) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Integer conversion', message: `Could not convert ${V} to an integer.` }) @@ -138,7 +133,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { // 3. If x < lowerBound or x > upperBound, then // throw a TypeError. if (x < lowerBound || x > upperBound) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Integer conversion', message: `Value must be between ${lowerBound}-${upperBound}, got ${x}.` }) @@ -171,7 +166,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { // 8. If x is NaN, +0, +∞, or −∞, then return +0. if ( Number.isNaN(x) || - Object.is(0, x) || + (x === 0 && Object.is(0, x)) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY ) { @@ -213,7 +208,7 @@ webidl.sequenceConverter = function (converter) { return (V) => { // 1. If Type(V) is not Object, throw a TypeError. if (webidl.util.Type(V) !== 'Object') { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Sequence', message: `Value of type ${webidl.util.Type(V)} is not an Object.` }) @@ -229,7 +224,7 @@ webidl.sequenceConverter = function (converter) { method === undefined || typeof method.next !== 'function' ) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Sequence', message: 'Object is not an iterator.' }) @@ -255,7 +250,7 @@ webidl.recordConverter = function (keyConverter, valueConverter) { return (O) => { // 1. If Type(O) is not Object, throw a TypeError. if (webidl.util.Type(O) !== 'Object') { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Record', message: `Value of type ${webidl.util.Type(O)} is not an Object.` }) @@ -314,7 +309,7 @@ webidl.recordConverter = function (keyConverter, valueConverter) { webidl.interfaceConverter = function (i) { return (V, opts = {}) => { if (opts.strict !== false && !(V instanceof i)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: i.name, message: `Expected ${V} to be an instance of ${i.name}.` }) @@ -324,16 +319,6 @@ webidl.interfaceConverter = function (i) { } } -/** - * @param {{ - * key: string, - * defaultValue?: any, - * required?: boolean, - * converter: (...args: unknown[]) => unknown, - * allowedValues?: any[] - * }[]} converters - * @returns - */ webidl.dictionaryConverter = function (converters) { return (dictionary) => { const type = webidl.util.Type(dictionary) @@ -342,7 +327,7 @@ webidl.dictionaryConverter = function (converters) { if (type === 'Null' || type === 'Undefined') { return dict } else if (type !== 'Object') { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Dictionary', message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` }) @@ -353,7 +338,7 @@ webidl.dictionaryConverter = function (converters) { if (required === true) { if (!hasOwn(dictionary, key)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Dictionary', message: `Missing required key "${key}".` }) @@ -379,7 +364,7 @@ webidl.dictionaryConverter = function (converters) { options.allowedValues && !options.allowedValues.includes(value) ) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'Dictionary', message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(', ')}.` }) @@ -450,7 +435,6 @@ webidl.converters.ByteString = function (V) { } // https://webidl.spec.whatwg.org/#es-USVString -// TODO: ensure that util.toUSVString follows webidl spec webidl.converters.USVString = toUSVString // https://webidl.spec.whatwg.org/#es-boolean @@ -469,9 +453,9 @@ webidl.converters.any = function (V) { } // https://webidl.spec.whatwg.org/#es-long-long -webidl.converters['long long'] = function (V, opts) { +webidl.converters['long long'] = function (V) { // 1. Let x be ? ConvertToInt(V, 64, "signed"). - const x = webidl.util.ConvertToInt(V, 64, 'signed', opts) + const x = webidl.util.ConvertToInt(V, 64, 'signed') // 2. Return the IDL long long value that represents // the same numeric value as x. @@ -509,7 +493,7 @@ webidl.converters.ArrayBuffer = function (V, opts = {}) { webidl.util.Type(V) !== 'Object' || !types.isAnyArrayBuffer(V) ) { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: `${V}`, argument: `${V}`, types: ['ArrayBuffer'] @@ -521,7 +505,7 @@ webidl.converters.ArrayBuffer = function (V, opts = {}) { // IsSharedArrayBuffer(V) is true, then throw a // TypeError. if (opts.allowShared === false && types.isSharedArrayBuffer(V)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'ArrayBuffer', message: 'SharedArrayBuffer is not allowed.' }) @@ -549,7 +533,7 @@ webidl.converters.TypedArray = function (V, T, opts = {}) { !types.isTypedArray(V) || V.constructor.name !== T.name ) { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: `${T.name}`, argument: `${V}`, types: [T.name] @@ -561,7 +545,7 @@ webidl.converters.TypedArray = function (V, T, opts = {}) { // IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is // true, then throw a TypeError. if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'ArrayBuffer', message: 'SharedArrayBuffer is not allowed.' }) @@ -582,7 +566,7 @@ webidl.converters.DataView = function (V, 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)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'DataView', message: 'Object is not a DataView.' }) @@ -593,7 +577,7 @@ webidl.converters.DataView = function (V, opts = {}) { // IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, // then throw a TypeError. if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: 'ArrayBuffer', message: 'SharedArrayBuffer is not allowed.' }) diff --git a/deps/undici/src/lib/fileapi/filereader.js b/deps/undici/src/lib/fileapi/filereader.js index fa18e8eb59354b..9a8bdd90335b87 100644 --- a/deps/undici/src/lib/fileapi/filereader.js +++ b/deps/undici/src/lib/fileapi/filereader.js @@ -37,15 +37,9 @@ class FileReader extends EventTarget { * @param {import('buffer').Blob} blob */ readAsArrayBuffer (blob) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsArrayBuffer\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsArrayBuffer' }) blob = webidl.converters.Blob(blob, { strict: false }) @@ -59,15 +53,9 @@ class FileReader extends EventTarget { * @param {import('buffer').Blob} blob */ readAsBinaryString (blob) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsBinaryString\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsBinaryString' }) blob = webidl.converters.Blob(blob, { strict: false }) @@ -82,15 +70,9 @@ class FileReader extends EventTarget { * @param {string?} encoding */ readAsText (blob, encoding = undefined) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsText\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsText' }) blob = webidl.converters.Blob(blob, { strict: false }) @@ -108,15 +90,9 @@ class FileReader extends EventTarget { * @param {import('buffer').Blob} blob */ readAsDataURL (blob) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsDataURL\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsDataURL' }) blob = webidl.converters.Blob(blob, { strict: false }) @@ -166,9 +142,7 @@ class FileReader extends EventTarget { * @see https://w3c.github.io/FileAPI/#dom-filereader-readystate */ get readyState () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) switch (this[kState]) { case 'empty': return this.EMPTY @@ -181,9 +155,7 @@ class FileReader extends EventTarget { * @see https://w3c.github.io/FileAPI/#dom-filereader-result */ get result () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) // The result attribute’s getter, when invoked, must return // this's result. @@ -194,9 +166,7 @@ class FileReader extends EventTarget { * @see https://w3c.github.io/FileAPI/#dom-filereader-error */ get error () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) // The error attribute’s getter, when invoked, must return // this's error. @@ -204,17 +174,13 @@ class FileReader extends EventTarget { } get onloadend () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) return this[kEvents].loadend } set onloadend (fn) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) if (typeof fn === 'function') { this[kEvents].loadend = fn @@ -224,17 +190,13 @@ class FileReader extends EventTarget { } get onerror () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) return this[kEvents].error } set onerror (fn) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) if (typeof fn === 'function') { this[kEvents].error = fn @@ -244,17 +206,13 @@ class FileReader extends EventTarget { } get onloadstart () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) return this[kEvents].loadstart } set onloadstart (fn) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) if (typeof fn === 'function') { this[kEvents].loadstart = fn @@ -264,17 +222,13 @@ class FileReader extends EventTarget { } get onprogress () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) return this[kEvents].progress } set onprogress (fn) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) if (typeof fn === 'function') { this[kEvents].progress = fn @@ -284,17 +238,13 @@ class FileReader extends EventTarget { } get onload () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) return this[kEvents].load } set onload (fn) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) if (typeof fn === 'function') { this[kEvents].load = fn @@ -304,17 +254,13 @@ class FileReader extends EventTarget { } get onabort () { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) return this[kEvents].abort } set onabort (fn) { - if (!(this instanceof FileReader)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, FileReader) if (typeof fn === 'function') { this[kEvents].abort = fn diff --git a/deps/undici/src/lib/fileapi/progressevent.js b/deps/undici/src/lib/fileapi/progressevent.js index ab3c6191e2dd54..778cf224c6a689 100644 --- a/deps/undici/src/lib/fileapi/progressevent.js +++ b/deps/undici/src/lib/fileapi/progressevent.js @@ -22,25 +22,19 @@ class ProgressEvent extends Event { } get lengthComputable () { - if (!(this instanceof ProgressEvent)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, ProgressEvent) return this[kState].lengthComputable } get loaded () { - if (!(this instanceof ProgressEvent)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, ProgressEvent) return this[kState].loaded } get total () { - if (!(this instanceof ProgressEvent)) { - throw new TypeError('Illegal invocation') - } + webidl.brandCheck(this, ProgressEvent) return this[kState].total } diff --git a/deps/undici/src/lib/mock/mock-utils.js b/deps/undici/src/lib/mock/mock-utils.js index 7d5ca5071d9470..9dc414d0a3578f 100644 --- a/deps/undici/src/lib/mock/mock-utils.js +++ b/deps/undici/src/lib/mock/mock-utils.js @@ -10,6 +10,11 @@ const { } = require('./mock-symbols') const { buildURL, nop } = require('../core/util') const { STATUS_CODES } = require('http') +const { + types: { + isPromise + } +} = require('util') function matchValue (match, value) { if (typeof match === 'string') { @@ -241,14 +246,27 @@ function mockDispatch (opts, handler) { handleReply(this[kDispatches]) } - function handleReply (mockDispatches) { + function handleReply (mockDispatches, _data = data) { // fetch's HeadersList is a 1D string array const optsHeaders = Array.isArray(opts.headers) ? buildHeadersFromArray(opts.headers) : opts.headers - const responseData = getResponseData( - typeof data === 'function' ? data({ ...opts, headers: optsHeaders }) : data - ) + const body = typeof _data === 'function' + ? _data({ ...opts, headers: optsHeaders }) + : _data + + // util.types.isPromise is likely needed for jest. + if (isPromise(body)) { + // If handleReply is asynchronous, throwing an error + // in the callback will reject the promise, rather than + // synchronously throw the error, which breaks some tests. + // Rather, we wait for the callback to resolve if it is a + // promise, and then re-run handleReply with the new body. + body.then((newData) => handleReply(mockDispatches, newData)) + return + } + + const responseData = getResponseData(body) const responseHeaders = generateKeyValues(headers) const responseTrailers = generateKeyValues(trailers) diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json index c82f1a6e5ab61f..a192b2d674ce61 100644 --- a/deps/undici/src/package.json +++ b/deps/undici/src/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "5.12.0", + "version": "5.13.0", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { @@ -52,7 +52,7 @@ "test:jest": "node scripts/verifyVersion.js 14 || jest", "test:tap": "tap test/*.js test/diagnostics-channel/*.js", "test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w", - "test:typescript": "tsd", + "test:typescript": "tsd && tsc test/imports/undici-import.ts", "test:wpt": "node scripts/verifyVersion 18 || (node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs)", "coverage": "nyc --reporter=text --reporter=html npm run test", "coverage:ci": "nyc --reporter=lcov npm run test", @@ -95,6 +95,7 @@ "table": "^6.8.0", "tap": "^16.1.0", "tsd": "^0.24.1", + "typescript": "^4.8.4", "wait-on": "^6.0.0" }, "engines": { @@ -116,8 +117,7 @@ "compilerOptions": { "esModuleInterop": true, "lib": [ - "esnext", - "DOM" + "esnext" ] } }, diff --git a/deps/undici/src/types/agent.d.ts b/deps/undici/src/types/agent.d.ts index c09260b29130f0..0813735805824e 100644 --- a/deps/undici/src/types/agent.d.ts +++ b/deps/undici/src/types/agent.d.ts @@ -1,9 +1,8 @@ import { URL } from 'url' -import Dispatcher = require('./dispatcher') -import Pool = require('./pool') -import {DispatchInterceptor} from "./dispatcher"; +import Pool from './pool' +import Dispatcher from "./dispatcher"; -export = Agent +export default Agent declare class Agent extends Dispatcher{ constructor(opts?: Agent.Options) @@ -22,7 +21,7 @@ declare namespace Agent { /** Integer. Default: `0` */ maxRedirections?: number; - interceptors?: { Agent?: readonly DispatchInterceptor[] } & Pool.Options["interceptors"] + interceptors?: { Agent?: readonly Dispatcher.DispatchInterceptor[] } & Pool.Options["interceptors"] } export interface DispatchOptions extends Dispatcher.DispatchOptions { diff --git a/deps/undici/src/types/api.d.ts b/deps/undici/src/types/api.d.ts index 4bc3183e84eb09..400341dddc06f7 100644 --- a/deps/undici/src/types/api.d.ts +++ b/deps/undici/src/types/api.d.ts @@ -1,6 +1,6 @@ import { URL, UrlObject } from 'url' import { Duplex } from 'stream' -import Dispatcher = require('./dispatcher') +import Dispatcher from './dispatcher' export { request, diff --git a/deps/undici/src/types/balanced-pool.d.ts b/deps/undici/src/types/balanced-pool.d.ts index 5a765e15e10f21..b5de726eeca0e1 100644 --- a/deps/undici/src/types/balanced-pool.d.ts +++ b/deps/undici/src/types/balanced-pool.d.ts @@ -1,9 +1,8 @@ -import Client = require('./client') -import Pool = require('./pool') -import Dispatcher = require('./dispatcher') +import Pool from './pool' +import Dispatcher from './dispatcher' import { URL } from 'url' -export = BalancedPool +export default BalancedPool declare class BalancedPool extends Dispatcher { constructor(url: string | URL | string[], options?: Pool.Options); diff --git a/deps/undici/src/types/client.d.ts b/deps/undici/src/types/client.d.ts index d87f08f1a08ff0..3a954ac83a1b74 100644 --- a/deps/undici/src/types/client.d.ts +++ b/deps/undici/src/types/client.d.ts @@ -1,10 +1,10 @@ import { URL } from 'url' import { TlsOptions } from 'tls' -import Dispatcher = require('./dispatcher') -import {DispatchInterceptor} from './dispatcher' -import buildConnector, {connector} from "./connector"; +import Dispatcher from './dispatcher' +import DispatchInterceptor from './dispatcher' +import buildConnector from "./connector"; -export = Client +export default Client /** A basic HTTP/1.1 client, mapped on top a single TCP/TLS connection. Pipelining is disabled by default. */ declare class Client extends Dispatcher { @@ -28,7 +28,7 @@ declare namespace Client { /** 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). Default: `1`. */ pipelining?: number | null; /** **/ - connect?: buildConnector.BuildOptions | connector | null; + connect?: buildConnector.BuildOptions | buildConnector.connector | null; /** The maximum length of request headers in bytes. Default: `16384` (16KiB). */ maxHeaderSize?: number | null; /** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `30e3` milliseconds (30s). */ diff --git a/deps/undici/src/types/connector.d.ts b/deps/undici/src/types/connector.d.ts index 9a47f87e59919f..8a425d2972c0c8 100644 --- a/deps/undici/src/types/connector.d.ts +++ b/deps/undici/src/types/connector.d.ts @@ -1,7 +1,7 @@ -import {TLSSocket, ConnectionOptions} from 'tls' -import {IpcNetConnectOpts, Socket, TcpNetConnectOpts} from 'net' +import { TLSSocket, ConnectionOptions } from 'tls' +import { IpcNetConnectOpts, Socket, TcpNetConnectOpts } from 'net' -export = buildConnector +export default buildConnector declare function buildConnector (options?: buildConnector.BuildOptions): buildConnector.connector declare namespace buildConnector { diff --git a/deps/undici/src/types/diagnostics-channel.d.ts b/deps/undici/src/types/diagnostics-channel.d.ts index 6c754491b89f3f..85d44823978df5 100644 --- a/deps/undici/src/types/diagnostics-channel.d.ts +++ b/deps/undici/src/types/diagnostics-channel.d.ts @@ -1,13 +1,13 @@ import { Socket } from "net"; import { URL } from "url"; -import { connector } from "./connector"; -import { HttpMethod } from "./dispatcher"; +import Connector from "./connector"; +import Dispatcher from "./dispatcher"; declare namespace DiagnosticsChannel { interface Request { origin?: string | URL; completed: boolean; - method?: HttpMethod; + method?: Dispatcher.HttpMethod; path: string; headers: string; addHeader(key: string, value: string): Request; @@ -25,7 +25,7 @@ declare namespace DiagnosticsChannel { port: URL["port"]; servername: string | null; } - type Connector = connector; + type Connector = Connector.connector; export interface RequestCreateMessage { request: Request; } diff --git a/deps/undici/src/types/dispatcher.d.ts b/deps/undici/src/types/dispatcher.d.ts index cbd558a932f848..adc95b9a0f336f 100644 --- a/deps/undici/src/types/dispatcher.d.ts +++ b/deps/undici/src/types/dispatcher.d.ts @@ -3,13 +3,13 @@ import { Duplex, Readable, Writable } from 'stream' import { EventEmitter } from 'events' import { IncomingHttpHeaders } from 'http' import { Blob } from 'buffer' -import type BodyReadable from './readable' +import BodyReadable from './readable' import { FormData } from './formdata' -import { UndiciError } from './errors' +import Errors from './errors' type AbortSignal = unknown; -export = Dispatcher; +export default Dispatcher /** Dispatcher is the core API used to dispatch requests. */ declare class Dispatcher extends EventEmitter { @@ -39,56 +39,56 @@ declare class Dispatcher extends EventEmitter { destroy(err: Error | null, callback: () => void): void; on(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; - on(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; - on(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + on(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; + on(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; on(eventName: 'drain', callback: (origin: URL) => void): this; once(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; - once(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; - once(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + once(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; + once(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; once(eventName: 'drain', callback: (origin: URL) => void): this; off(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; - off(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; - off(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + off(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; + off(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; off(eventName: 'drain', callback: (origin: URL) => void): this; addListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; - addListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; - addListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + addListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; + addListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; addListener(eventName: 'drain', callback: (origin: URL) => void): this; removeListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; - removeListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; - removeListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + removeListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; + removeListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; removeListener(eventName: 'drain', callback: (origin: URL) => void): this; prependListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; - prependListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; - prependListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + prependListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; + prependListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; prependListener(eventName: 'drain', callback: (origin: URL) => void): this; prependOnceListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this; - prependOnceListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; - prependOnceListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this; + prependOnceListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; + prependOnceListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this; prependOnceListener(eventName: 'drain', callback: (origin: URL) => void): this; listeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[] - listeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; - listeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; + listeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]; + listeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]; listeners(eventName: 'drain'): ((origin: URL) => void)[]; rawListeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[] - rawListeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; - rawListeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[]; + rawListeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]; + rawListeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[]; rawListeners(eventName: 'drain'): ((origin: URL) => void)[]; emit(eventName: 'connect', origin: URL, targets: readonly Dispatcher[]): boolean; - emit(eventName: 'disconnect', origin: URL, targets: readonly Dispatcher[], error: UndiciError): boolean; - emit(eventName: 'connectionError', origin: URL, targets: readonly Dispatcher[], error: UndiciError): boolean; + emit(eventName: 'disconnect', origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError): boolean; + emit(eventName: 'connectionError', origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError): boolean; emit(eventName: 'drain', origin: URL): boolean; } diff --git a/deps/undici/src/types/errors.d.ts b/deps/undici/src/types/errors.d.ts index 492e31eb228863..c4ef4b6f6333a1 100644 --- a/deps/undici/src/types/errors.d.ts +++ b/deps/undici/src/types/errors.d.ts @@ -1,7 +1,7 @@ import {IncomingHttpHeaders} from "http"; +import Client from './client' -export = Errors -import { SocketInfo } from './client' +export default Errors declare namespace Errors { export class UndiciError extends Error { } @@ -79,7 +79,7 @@ declare namespace Errors { export class SocketError extends UndiciError { name: 'SocketError'; code: 'UND_ERR_SOCKET'; - socket: SocketInfo | null + socket: Client.SocketInfo | null } /** Encountered unsupported functionality. */ diff --git a/deps/undici/src/types/fetch.d.ts b/deps/undici/src/types/fetch.d.ts index d38e0d61242093..58bd4d2a76919a 100644 --- a/deps/undici/src/types/fetch.d.ts +++ b/deps/undici/src/types/fetch.d.ts @@ -7,7 +7,7 @@ import { URL, URLSearchParams } from 'url' import { ReadableStream } from 'stream/web' import { FormData } from './formdata' -import Dispatcher = require('./dispatcher') +import Dispatcher from './dispatcher' export type RequestInfo = string | URL | Request diff --git a/deps/undici/src/types/filereader.d.ts b/deps/undici/src/types/filereader.d.ts index 8bd7e15c24237a..f05d231b2ffac7 100644 --- a/deps/undici/src/types/filereader.d.ts +++ b/deps/undici/src/types/filereader.d.ts @@ -1,8 +1,11 @@ /// import { Blob } from 'buffer' +import { DOMException, Event, EventInit, EventTarget } from './patch' + +export declare class FileReader { + __proto__: EventTarget & FileReader -export declare class FileReader extends EventTarget { constructor () readAsArrayBuffer (blob: Blob): void @@ -40,10 +43,12 @@ export interface ProgressEventInit extends EventInit { total?: number } -export declare class ProgressEvent extends Event { +export declare class ProgressEvent { + __proto__: Event & ProgressEvent + constructor (type: string, eventInitDict?: ProgressEventInit) readonly lengthComputable: boolean readonly loaded: number readonly total: number -} \ No newline at end of file +} diff --git a/deps/undici/src/types/global-dispatcher.d.ts b/deps/undici/src/types/global-dispatcher.d.ts index 56abd53d6cfd16..728f95ce23ce69 100644 --- a/deps/undici/src/types/global-dispatcher.d.ts +++ b/deps/undici/src/types/global-dispatcher.d.ts @@ -1,4 +1,4 @@ -import Dispatcher = require("./dispatcher"); +import Dispatcher from "./dispatcher"; export { getGlobalDispatcher, diff --git a/deps/undici/src/types/interceptors.d.ts b/deps/undici/src/types/interceptors.d.ts index a920ea982e8ab1..047ac175d5005f 100644 --- a/deps/undici/src/types/interceptors.d.ts +++ b/deps/undici/src/types/interceptors.d.ts @@ -1,5 +1,5 @@ -import {DispatchInterceptor} from "./dispatcher"; +import Dispatcher from "./dispatcher"; type RedirectInterceptorOpts = { maxRedirections?: number } -export declare function createRedirectInterceptor (opts: RedirectInterceptorOpts): DispatchInterceptor +export declare function createRedirectInterceptor (opts: RedirectInterceptorOpts): Dispatcher.DispatchInterceptor diff --git a/deps/undici/src/types/mock-agent.d.ts b/deps/undici/src/types/mock-agent.d.ts index 825d2aeff6dc80..98cd645b29bd16 100644 --- a/deps/undici/src/types/mock-agent.d.ts +++ b/deps/undici/src/types/mock-agent.d.ts @@ -1,9 +1,9 @@ -import Agent = require('./agent') -import Dispatcher = require('./dispatcher') +import Agent from './agent' +import Dispatcher from './dispatcher' import { Interceptable, MockInterceptor } from './mock-interceptor' import MockDispatch = MockInterceptor.MockDispatch; -export = MockAgent +export default MockAgent interface PendingInterceptor extends MockDispatch { origin: string; diff --git a/deps/undici/src/types/mock-client.d.ts b/deps/undici/src/types/mock-client.d.ts index 9e751f42f351ab..51d008cc11c5cb 100644 --- a/deps/undici/src/types/mock-client.d.ts +++ b/deps/undici/src/types/mock-client.d.ts @@ -1,9 +1,9 @@ -import Client = require('./client') -import Dispatcher = require('./dispatcher') -import MockAgent = require('./mock-agent') +import Client from './client' +import Dispatcher from './dispatcher' +import MockAgent from './mock-agent' import { MockInterceptor, Interceptable } from './mock-interceptor' -export = MockClient +export default MockClient /** MockClient extends the Client API and allows one to mock requests. */ declare class MockClient extends Client implements Interceptable { diff --git a/deps/undici/src/types/mock-errors.d.ts b/deps/undici/src/types/mock-errors.d.ts index 31e7ba23c7ffe2..3d9e727d70a46a 100644 --- a/deps/undici/src/types/mock-errors.d.ts +++ b/deps/undici/src/types/mock-errors.d.ts @@ -1,10 +1,10 @@ -import { UndiciError } from './errors' +import Errors from './errors' -export = MockErrors +export default MockErrors declare namespace MockErrors { /** The request does not match any registered mock dispatches. */ - export class MockNotMatchedError extends UndiciError { + export class MockNotMatchedError extends Errors.UndiciError { constructor(message?: string); name: 'MockNotMatchedError'; code: 'UND_MOCK_ERR_MOCK_NOT_MATCHED'; diff --git a/deps/undici/src/types/mock-interceptor.d.ts b/deps/undici/src/types/mock-interceptor.d.ts index 87eedcd406053f..9dc423c0600a8e 100644 --- a/deps/undici/src/types/mock-interceptor.d.ts +++ b/deps/undici/src/types/mock-interceptor.d.ts @@ -1,5 +1,5 @@ import { IncomingHttpHeaders } from 'http' -import Dispatcher = require('./dispatcher'); +import Dispatcher from './dispatcher'; import { BodyInit, Headers } from './fetch' export { diff --git a/deps/undici/src/types/mock-pool.d.ts b/deps/undici/src/types/mock-pool.d.ts index d0c905152680d4..39e709aaf69a2c 100644 --- a/deps/undici/src/types/mock-pool.d.ts +++ b/deps/undici/src/types/mock-pool.d.ts @@ -1,9 +1,9 @@ -import Pool = require('./pool') -import MockAgent = require('./mock-agent') +import Pool from './pool' +import MockAgent from './mock-agent' import { Interceptable, MockInterceptor } from './mock-interceptor' -import Dispatcher = require('./dispatcher') +import Dispatcher from './dispatcher' -export = MockPool +export default MockPool /** MockPool extends the Pool API and allows one to mock requests. */ declare class MockPool extends Pool implements Interceptable { diff --git a/deps/undici/src/types/patch.d.ts b/deps/undici/src/types/patch.d.ts new file mode 100644 index 00000000000000..f3500b589a4e52 --- /dev/null +++ b/deps/undici/src/types/patch.d.ts @@ -0,0 +1,51 @@ +/// + +// See https://github.com/nodejs/undici/issues/1740 + +export type DOMException = typeof globalThis extends { DOMException: infer T } + ? T + : any + +export type EventTarget = typeof globalThis extends { EventTarget: infer T } + ? T + : { + addEventListener( + type: string, + listener: any, + options?: any, + ): void + dispatchEvent(event: Event): boolean + removeEventListener( + type: string, + listener: any, + options?: any | boolean, + ): void + } + +export type Event = typeof globalThis extends { Event: infer T } + ? T + : { + readonly bubbles: boolean + cancelBubble: () => void + readonly cancelable: boolean + readonly composed: boolean + composedPath(): [EventTarget?] + readonly currentTarget: EventTarget | null + readonly defaultPrevented: boolean + readonly eventPhase: 0 | 2 + readonly isTrusted: boolean + preventDefault(): void + returnValue: boolean + readonly srcElement: EventTarget | null + stopImmediatePropagation(): void + stopPropagation(): void + readonly target: EventTarget | null + readonly timeStamp: number + readonly type: string + } + +export interface EventInit { + bubbles?: boolean + cancelable?: boolean + composed?: boolean +} diff --git a/deps/undici/src/types/pool-stats.d.ts b/deps/undici/src/types/pool-stats.d.ts index 807e68f1b81dad..8b6d2bff4ad416 100644 --- a/deps/undici/src/types/pool-stats.d.ts +++ b/deps/undici/src/types/pool-stats.d.ts @@ -1,6 +1,6 @@ -import Pool = require("./pool") +import Pool from "./pool" -export = PoolStats +export default PoolStats declare class PoolStats { constructor(pool: Pool); diff --git a/deps/undici/src/types/pool.d.ts b/deps/undici/src/types/pool.d.ts index 0ef0bc39884db9..7747d48261ba84 100644 --- a/deps/undici/src/types/pool.d.ts +++ b/deps/undici/src/types/pool.d.ts @@ -1,10 +1,9 @@ -import Client = require('./client') -import Dispatcher = require('./dispatcher') -import TPoolStats = require('./pool-stats') +import Client from './client' +import TPoolStats from './pool-stats' import { URL } from 'url' -import {DispatchInterceptor} from "./dispatcher"; +import Dispatcher from "./dispatcher"; -export = Pool +export default Pool declare class Pool extends Dispatcher { constructor(url: string | URL, options?: Pool.Options) @@ -24,6 +23,6 @@ declare namespace Pool { /** The max number of clients to create. `null` if no limit. Default `null`. */ connections?: number | null; - interceptors?: { Pool?: readonly DispatchInterceptor[] } & Client.Options["interceptors"] + interceptors?: { Pool?: readonly Dispatcher.DispatchInterceptor[] } & Client.Options["interceptors"] } } diff --git a/deps/undici/src/types/proxy-agent.d.ts b/deps/undici/src/types/proxy-agent.d.ts index 118165d00d0cd4..5e3718e9f349e7 100644 --- a/deps/undici/src/types/proxy-agent.d.ts +++ b/deps/undici/src/types/proxy-agent.d.ts @@ -1,8 +1,8 @@ import { TlsOptions } from 'tls' -import Agent = require('./agent') -import Dispatcher = require('./dispatcher') +import Agent from './agent' +import Dispatcher from './dispatcher' -export = ProxyAgent +export default ProxyAgent declare class ProxyAgent extends Dispatcher { constructor(options: ProxyAgent.Options | string) diff --git a/deps/undici/src/types/readable.d.ts b/deps/undici/src/types/readable.d.ts index 0d82ba86776e7d..032b53b01f97a0 100644 --- a/deps/undici/src/types/readable.d.ts +++ b/deps/undici/src/types/readable.d.ts @@ -1,7 +1,7 @@ import { Readable } from "stream"; import { Blob } from 'buffer' -export = BodyReadable +export default BodyReadable declare class BodyReadable extends Readable { constructor( diff --git a/deps/undici/src/types/webidl.d.ts b/deps/undici/src/types/webidl.d.ts new file mode 100644 index 00000000000000..1b49fd6d769b0e --- /dev/null +++ b/deps/undici/src/types/webidl.d.ts @@ -0,0 +1,213 @@ +// These types are not exported, and are only used internally + +/** + * Take in an unknown value and return one that is of type T + */ +type Converter = (object: unknown) => T + +type SequenceConverter = (object: unknown) => T[] + +type RecordConverter = (object: unknown) => Record + +interface ConvertToIntOpts { + clamp?: boolean + enforceRange?: boolean +} + +interface WebidlErrors { + exception (opts: { header: string, message: string }): TypeError + /** + * @description Throw an error when conversion from one type to another has failed + */ + conversionFailed (opts: { + prefix: string + argument: string + types: string[] + }): TypeError + /** + * @description Throw an error when an invalid argument is provided + */ + invalidArgument (opts: { + prefix: string + value: string + type: string + }): TypeError +} + +interface WebidlUtil { + /** + * @see https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values + */ + Type (object: unknown): + | 'Undefined' + | 'Boolean' + | 'String' + | 'Symbol' + | 'Number' + | 'BigInt' + | 'Null' + | 'Object' + + /** + * @see https://webidl.spec.whatwg.org/#abstract-opdef-converttoint + */ + ConvertToInt ( + V: unknown, + bitLength: number, + signedness: 'signed' | 'unsigned', + opts?: ConvertToIntOpts + ): number + + /** + * @see https://webidl.spec.whatwg.org/#abstract-opdef-converttoint + */ + IntegerPart (N: number): number +} + +interface WebidlConverters { + /** + * @see https://webidl.spec.whatwg.org/#es-DOMString + */ + DOMString (V: unknown, opts?: { + legacyNullToEmptyString: boolean + }): string + + /** + * @see https://webidl.spec.whatwg.org/#es-ByteString + */ + ByteString (V: unknown): string + + /** + * @see https://webidl.spec.whatwg.org/#es-USVString + */ + USVString (V: unknown): string + + /** + * @see https://webidl.spec.whatwg.org/#es-boolean + */ + boolean (V: unknown): boolean + + /** + * @see https://webidl.spec.whatwg.org/#es-any + */ + any (V: Value): Value + + /** + * @see https://webidl.spec.whatwg.org/#es-long-long + */ + ['long long'] (V: unknown): number + + /** + * @see https://webidl.spec.whatwg.org/#es-unsigned-long-long + */ + ['unsigned long long'] (V: unknown): number + + /** + * @see https://webidl.spec.whatwg.org/#es-unsigned-short + */ + ['unsigned short'] (V: unknown): number + + /** + * @see https://webidl.spec.whatwg.org/#idl-ArrayBuffer + */ + ArrayBuffer (V: unknown): ArrayBufferLike + ArrayBuffer (V: unknown, opts: { allowShared: false }): ArrayBuffer + + /** + * @see https://webidl.spec.whatwg.org/#es-buffer-source-types + */ + TypedArray ( + V: unknown, + TypedArray: NodeJS.TypedArray | ArrayBufferLike + ): NodeJS.TypedArray | ArrayBufferLike + TypedArray ( + V: unknown, + TypedArray: NodeJS.TypedArray | ArrayBufferLike, + opts?: { allowShared: false } + ): NodeJS.TypedArray | ArrayBuffer + + /** + * @see https://webidl.spec.whatwg.org/#es-buffer-source-types + */ + DataView (V: unknown, opts?: { allowShared: boolean }): DataView + + /** + * @see https://webidl.spec.whatwg.org/#BufferSource + */ + BufferSource ( + V: unknown, + opts?: { allowShared: boolean } + ): NodeJS.TypedArray | ArrayBufferLike | DataView + + ['sequence']: SequenceConverter + + ['sequence>']: SequenceConverter + + ['record']: RecordConverter + + [Key: string]: (...args: any[]) => unknown +} + +export interface Webidl { + errors: WebidlErrors + util: WebidlUtil + converters: WebidlConverters + + /** + * @description Performs a brand-check on {@param V} to ensure it is a + * {@param cls} object. + */ + brandCheck (V: unknown, cls: Interface): asserts V is Interface + + /** + * @see https://webidl.spec.whatwg.org/#es-sequence + * @description Convert a value, V, to a WebIDL sequence type. + */ + sequenceConverter (C: Converter): SequenceConverter + + /** + * @see https://webidl.spec.whatwg.org/#es-to-record + * @description Convert a value, V, to a WebIDL record type. + */ + recordConverter ( + keyConverter: Converter, + valueConverter: Converter + ): RecordConverter + + /** + * Similar to {@link Webidl.brandCheck} but allows skipping the check if third party + * interfaces are allowed. + */ + interfaceConverter (cls: Interface): ( + V: unknown, + opts?: { strict: boolean } + ) => asserts V is typeof cls + + // TODO(@KhafraDev): a type could likely be implemented that can infer the return type + // from the converters given? + /** + * Converts a value, V, to a WebIDL dictionary types. Allows limiting which keys are + * allowed, values allowed, optional and required keys. Auto converts the value to + * a type given a converter. + */ + dictionaryConverter (converters: { + key: string, + defaultValue?: unknown, + required?: boolean, + converter: (...args: unknown[]) => unknown, + allowedValues?: unknown[] + }[]): (V: unknown) => Record + + /** + * @see https://webidl.spec.whatwg.org/#idl-nullable-type + * @description allows a type, V, to be null + */ + nullableConverter ( + converter: Converter + ): (V: unknown) => ReturnType | null + + argumentLengthCheck (args: { length: number }, min: number, context: { + header: string + message?: string + }): void +} diff --git a/deps/undici/undici.js b/deps/undici/undici.js index f8040e297b109a..8fd0c48f62b597 100644 --- a/deps/undici/undici.js +++ b/deps/undici/undici.js @@ -1,14 +1,8 @@ "use strict"; -var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; -var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; -var __publicField = (obj, key, value) => { - __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); - return value; -}; // lib/core/symbols.js var require_symbols = __commonJS({ @@ -590,6 +584,88 @@ var require_constants = __commonJS({ var corsSafeListedMethods = ["GET", "HEAD", "POST"]; var nullBodyStatus = [101, 204, 205, 304]; var redirectStatus = [301, 302, 303, 307, 308]; + var badPorts = [ + "1", + "7", + "9", + "11", + "13", + "15", + "17", + "19", + "20", + "21", + "22", + "23", + "25", + "37", + "42", + "43", + "53", + "69", + "77", + "79", + "87", + "95", + "101", + "102", + "103", + "104", + "109", + "110", + "111", + "113", + "115", + "117", + "119", + "123", + "135", + "137", + "139", + "143", + "161", + "179", + "389", + "427", + "465", + "512", + "513", + "514", + "515", + "526", + "530", + "531", + "532", + "540", + "548", + "554", + "556", + "563", + "587", + "601", + "636", + "989", + "990", + "993", + "995", + "1719", + "1720", + "1723", + "2049", + "3659", + "4045", + "5060", + "5061", + "6000", + "6566", + "6665", + "6666", + "6667", + "6668", + "6669", + "6697", + "10080" + ]; var referrerPolicy = [ "", "no-referrer", @@ -619,6 +695,9 @@ var require_constants = __commonJS({ "content-location", "content-type" ]; + var requestDuplex = [ + "half" + ]; var forbiddenMethods = ["CONNECT", "TRACE", "TRACK"]; var subresource = [ "audio", @@ -668,7 +747,9 @@ var require_constants = __commonJS({ redirectStatus, corsSafeListedMethods, nullBodyStatus, - safeMethods + safeMethods, + badPorts, + requestDuplex }; } }); @@ -677,7 +758,7 @@ var require_constants = __commonJS({ var require_util2 = __commonJS({ "lib/fetch/util.js"(exports2, module2) { "use strict"; - var { redirectStatus } = require_constants(); + var { redirectStatus, badPorts, referrerPolicy: referrerPolicyTokens } = require_constants(); var { performance: performance2 } = require("perf_hooks"); var { isBlobLike, toUSVString, ReadableStreamFrom } = require_util(); var assert = require("assert"); @@ -687,88 +768,6 @@ var require_util2 = __commonJS({ crypto = require("crypto"); } catch { } - var badPorts = [ - "1", - "7", - "9", - "11", - "13", - "15", - "17", - "19", - "20", - "21", - "22", - "23", - "25", - "37", - "42", - "43", - "53", - "69", - "77", - "79", - "87", - "95", - "101", - "102", - "103", - "104", - "109", - "110", - "111", - "113", - "115", - "117", - "119", - "123", - "135", - "137", - "139", - "143", - "161", - "179", - "389", - "427", - "465", - "512", - "513", - "514", - "515", - "526", - "530", - "531", - "532", - "540", - "548", - "554", - "556", - "563", - "587", - "601", - "636", - "989", - "990", - "993", - "995", - "1719", - "1720", - "1723", - "2049", - "3659", - "4045", - "5060", - "5061", - "6000", - "6566", - "6665", - "6666", - "6667", - "6668", - "6669", - "6697", - "10080" - ]; function responseURL(response) { const urlList = response.urlList; const length = urlList.length; @@ -826,12 +825,7 @@ var require_util2 = __commonJS({ if (potentialValue.length === 0) { return false; } - for (const char of potentialValue) { - if (!isValidHTTPToken(char)) { - return false; - } - } - return true; + return isValidHTTPToken(potentialValue); } function isValidHeaderValue(potentialValue) { if (potentialValue.startsWith(" ") || potentialValue.startsWith(" ") || potentialValue.endsWith(" ") || potentialValue.endsWith(" ")) { @@ -843,7 +837,18 @@ var require_util2 = __commonJS({ return true; } function setRequestReferrerPolicyOnRedirect(request, actualResponse) { - const policy = ""; + const { headersList } = actualResponse; + const policyHeader = (headersList.get("referrer-policy") ?? "").split(","); + let policy = ""; + if (policyHeader.length > 0) { + for (let i = policyHeader.length; i !== 0; i--) { + const token = policyHeader[i - 1].trim(); + if (referrerPolicyTokens.includes(token)) { + policy = token; + break; + } + } + } if (policy !== "") { request.referrerPolicy = policy; } @@ -1152,6 +1157,13 @@ var require_util2 = __commonJS({ } return stream instanceof ReadableStream || stream[Symbol.toStringTag] === "ReadableStream" && typeof stream.tee === "function"; } + function isomorphicDecode(input) { + let output = ""; + for (let i = 0; i < input.length; i++) { + output += String.fromCharCode(input[i]); + } + return output; + } function readableStreamClose(controller) { try { controller.close(); @@ -1161,6 +1173,12 @@ var require_util2 = __commonJS({ } } } + function isomorphicEncode(input) { + for (let i = 0; i < input.length; i++) { + assert(input.charCodeAt(i) <= 255); + } + return input; + } var hasOwn = Object.hasOwn || ((dict, key) => Object.prototype.hasOwnProperty.call(dict, key)); module2.exports = { isAborted, @@ -1199,7 +1217,9 @@ var require_util2 = __commonJS({ fullyReadBody, bytesMatch, isReadableStreamLike, - readableStreamClose + readableStreamClose, + isomorphicEncode, + isomorphicDecode }; } }); @@ -1215,7 +1235,7 @@ var require_webidl = __commonJS({ webidl.util = {}; webidl.errors = {}; webidl.errors.exception = function(message) { - throw new TypeError(`${message.header}: ${message.message}`); + return new TypeError(`${message.header}: ${message.message}`); }; webidl.errors.conversionFailed = function(context) { const plural = context.types.length === 1 ? "" : " one of"; @@ -1231,6 +1251,19 @@ var require_webidl = __commonJS({ message: `"${context.value}" is an invalid ${context.type}.` }); }; + webidl.brandCheck = function(V, I) { + if (!(V instanceof I)) { + throw new TypeError("Illegal invocation"); + } + }; + webidl.argumentLengthCheck = function({ length }, min, ctx) { + if (length < min) { + throw webidl.errors.exception({ + message: `${min} argument${min !== 1 ? "s" : ""} required, but${length ? " only" : ""} ${length} found.`, + ...ctx + }); + } + }; webidl.util.Type = function(V) { switch (typeof V) { case "undefined": @@ -1272,19 +1305,19 @@ var require_webidl = __commonJS({ upperBound = Math.pow(2, bitLength - 1) - 1; } let x = Number(V); - if (Object.is(-0, x)) { + if (x === 0) { x = 0; } if (opts.enforceRange === true) { if (Number.isNaN(x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Integer conversion", message: `Could not convert ${V} to an integer.` }); } x = webidl.util.IntegerPart(x); if (x < lowerBound || x > upperBound) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Integer conversion", message: `Value must be between ${lowerBound}-${upperBound}, got ${x}.` }); @@ -1300,7 +1333,7 @@ var require_webidl = __commonJS({ } return x; } - if (Number.isNaN(x) || Object.is(0, x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { + if (Number.isNaN(x) || x === 0 && Object.is(0, x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { return 0; } x = webidl.util.IntegerPart(x); @@ -1320,7 +1353,7 @@ var require_webidl = __commonJS({ webidl.sequenceConverter = function(converter) { return (V) => { if (webidl.util.Type(V) !== "Object") { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Sequence", message: `Value of type ${webidl.util.Type(V)} is not an Object.` }); @@ -1328,7 +1361,7 @@ var require_webidl = __commonJS({ const method = V?.[Symbol.iterator]?.(); const seq = []; if (method === void 0 || typeof method.next !== "function") { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Sequence", message: "Object is not an iterator." }); @@ -1346,7 +1379,7 @@ var require_webidl = __commonJS({ webidl.recordConverter = function(keyConverter, valueConverter) { return (O) => { if (webidl.util.Type(O) !== "Object") { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Record", message: `Value of type ${webidl.util.Type(O)} is not an Object.` }); @@ -1376,7 +1409,7 @@ var require_webidl = __commonJS({ webidl.interfaceConverter = function(i) { return (V, opts = {}) => { if (opts.strict !== false && !(V instanceof i)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: i.name, message: `Expected ${V} to be an instance of ${i.name}.` }); @@ -1391,7 +1424,7 @@ var require_webidl = __commonJS({ if (type === "Null" || type === "Undefined") { return dict; } else if (type !== "Object") { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Dictionary", message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` }); @@ -1400,7 +1433,7 @@ var require_webidl = __commonJS({ const { key, defaultValue, required, converter } = options; if (required === true) { if (!hasOwn(dictionary, key)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Dictionary", message: `Missing required key "${key}".` }); @@ -1414,7 +1447,7 @@ var require_webidl = __commonJS({ if (required || hasDefault || value !== void 0) { value = converter(value); if (options.allowedValues && !options.allowedValues.includes(value)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Dictionary", message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(", ")}.` }); @@ -1460,8 +1493,8 @@ var require_webidl = __commonJS({ webidl.converters.any = function(V) { return V; }; - webidl.converters["long long"] = function(V, opts) { - const x = webidl.util.ConvertToInt(V, 64, "signed", opts); + webidl.converters["long long"] = function(V) { + const x = webidl.util.ConvertToInt(V, 64, "signed"); return x; }; webidl.converters["unsigned long long"] = function(V) { @@ -1474,14 +1507,14 @@ var require_webidl = __commonJS({ }; webidl.converters.ArrayBuffer = function(V, opts = {}) { if (webidl.util.Type(V) !== "Object" || !types.isAnyArrayBuffer(V)) { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: `${V}`, argument: `${V}`, types: ["ArrayBuffer"] }); } if (opts.allowShared === false && types.isSharedArrayBuffer(V)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "ArrayBuffer", message: "SharedArrayBuffer is not allowed." }); @@ -1490,14 +1523,14 @@ var require_webidl = __commonJS({ }; webidl.converters.TypedArray = function(V, T, opts = {}) { if (webidl.util.Type(V) !== "Object" || !types.isTypedArray(V) || V.constructor.name !== T.name) { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: `${T.name}`, argument: `${V}`, types: [T.name] }); } if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "ArrayBuffer", message: "SharedArrayBuffer is not allowed." }); @@ -1506,13 +1539,13 @@ var require_webidl = __commonJS({ }; webidl.converters.DataView = function(V, opts = {}) { if (webidl.util.Type(V) !== "Object" || !types.isDataView(V)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "DataView", message: "Object is not a DataView." }); } if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "ArrayBuffer", message: "SharedArrayBuffer is not allowed." }); @@ -1562,7 +1595,7 @@ var require_headers = __commonJS({ if (Array.isArray(object)) { for (const header of object) { if (header.length !== 2) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Headers constructor", message: `expected name/value pair to be length 2, found ${header.length}.` }); @@ -1574,7 +1607,7 @@ var require_headers = __commonJS({ headers.append(key, value); } } else { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: "Headers constructor", argument: "Argument 1", types: ["sequence>", "record"] @@ -1620,15 +1653,10 @@ var require_headers = __commonJS({ return this[kHeadersMap].delete(name); } get(name) { - name = name.toLowerCase(); if (!this.contains(name)) { return null; } - return this[kHeadersMap].get(name) ?? null; - } - has(name) { - name = name.toLowerCase(); - return this[kHeadersMap].has(name); + return this[kHeadersMap].get(name.toLowerCase()) ?? null; } *[Symbol.iterator]() { for (const pair of this[kHeadersMap]) { @@ -1645,27 +1673,20 @@ var require_headers = __commonJS({ fill(this, init); } } - get [Symbol.toStringTag]() { - return this.constructor.name; - } append(name, value) { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 2) { - throw new TypeError(`Failed to execute 'append' on 'Headers': 2 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, Headers); + webidl.argumentLengthCheck(arguments, 2, { header: "Headers.append" }); name = webidl.converters.ByteString(name); value = webidl.converters.ByteString(value); value = headerValueNormalize(value); if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: "Headers.append", value: name, type: "header name" }); } else if (!isValidHeaderValue(value)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: "Headers.append", value, type: "header value" @@ -1678,15 +1699,11 @@ var require_headers = __commonJS({ return this[kHeadersList].append(name, value); } delete(name) { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'delete' on 'Headers': 1 argument required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, Headers); + webidl.argumentLengthCheck(arguments, 1, { header: "Headers.delete" }); name = webidl.converters.ByteString(name); if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: "Headers.delete", value: name, type: "header name" @@ -1702,15 +1719,11 @@ var require_headers = __commonJS({ return this[kHeadersList].delete(name); } get(name) { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'get' on 'Headers': 1 argument required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, Headers); + webidl.argumentLengthCheck(arguments, 1, { header: "Headers.get" }); name = webidl.converters.ByteString(name); if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: "Headers.get", value: name, type: "header name" @@ -1719,15 +1732,11 @@ var require_headers = __commonJS({ return this[kHeadersList].get(name); } has(name) { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'has' on 'Headers': 1 argument required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, Headers); + webidl.argumentLengthCheck(arguments, 1, { header: "Headers.has" }); name = webidl.converters.ByteString(name); if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: "Headers.has", value: name, type: "header name" @@ -1736,23 +1745,19 @@ var require_headers = __commonJS({ return this[kHeadersList].contains(name); } set(name, value) { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 2) { - throw new TypeError(`Failed to execute 'set' on 'Headers': 2 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, Headers); + webidl.argumentLengthCheck(arguments, 2, { header: "Headers.set" }); name = webidl.converters.ByteString(name); value = webidl.converters.ByteString(value); value = headerValueNormalize(value); if (!isValidHeaderName(name)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: "Headers.set", value: name, type: "header name" }); } else if (!isValidHeaderValue(value)) { - webidl.errors.invalidArgument({ + throw webidl.errors.invalidArgument({ prefix: "Headers.set", value, type: "header value" @@ -1771,30 +1776,20 @@ var require_headers = __commonJS({ return this[kHeadersList][kHeadersSortedMap]; } keys() { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Headers); return makeIterator(() => [...this[kHeadersSortedMap].entries()], "Headers", "key"); } values() { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Headers); return makeIterator(() => [...this[kHeadersSortedMap].entries()], "Headers", "value"); } entries() { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Headers); return makeIterator(() => [...this[kHeadersSortedMap].entries()], "Headers", "key+value"); } forEach(callbackFn, thisArg = globalThis) { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'forEach' on 'Headers': 1 argument required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, Headers); + webidl.argumentLengthCheck(arguments, 1, { header: "Headers.forEach" }); if (typeof callbackFn !== "function") { throw new TypeError("Failed to execute 'forEach' on 'Headers': parameter 1 is not of type 'Function'."); } @@ -1803,9 +1798,7 @@ var require_headers = __commonJS({ } } [Symbol.for("nodejs.util.inspect.custom")]() { - if (!(this instanceof Headers)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Headers); return this[kHeadersList]; } }; @@ -1820,7 +1813,11 @@ var require_headers = __commonJS({ values: kEnumerableProperty, entries: kEnumerableProperty, forEach: kEnumerableProperty, - [Symbol.iterator]: { enumerable: false } + [Symbol.iterator]: { enumerable: false }, + [Symbol.toStringTag]: { + value: "Headers", + configurable: true + } }); webidl.converters.HeadersInit = function(V) { if (webidl.util.Type(V) === "Object") { @@ -1829,7 +1826,7 @@ var require_headers = __commonJS({ } return webidl.converters["record"](V); } - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: "Headers constructor", argument: "Argument 1", types: ["sequence>", "record"] @@ -5541,7 +5538,8 @@ var require_dataURL = __commonJS({ "lib/fetch/dataURL.js"(exports2, module2) { var assert = require("assert"); var { atob: atob2 } = require("buffer"); - var { isValidHTTPToken } = require_util2(); + var { format } = require("url"); + var { isValidHTTPToken, isomorphicDecode } = require_util2(); var encoder = new TextEncoder(); function dataURLProcessor(dataURL) { assert(dataURL.protocol === "data:"); @@ -5558,7 +5556,7 @@ var require_dataURL = __commonJS({ const encodedBody = input.slice(mimeTypeLength + 1); let body = stringPercentDecode(encodedBody); if (/;(\u0020){0,}base64$/i.test(mimeType)) { - const stringBody = decodeURIComponent(new TextDecoder("utf-8").decode(body)); + const stringBody = isomorphicDecode(body); body = forgivingBase64(stringBody); if (body === "failure") { return "failure"; @@ -5577,32 +5575,7 @@ var require_dataURL = __commonJS({ return { mimeType: mimeTypeRecord, body }; } function URLSerializer(url, excludeFragment = false) { - let output = url.protocol; - if (url.host.length > 0) { - output += "//"; - if (url.username.length > 0 || url.password.length > 0) { - output += url.username; - if (url.password.length > 0) { - output += ":" + url.password; - } - output += "@"; - } - output += decodeURIComponent(url.hostname); - if (url.port.length > 0) { - output += ":" + url.port; - } - } - if (url.host.length === 0 && url.pathname.length > 1 && url.href.slice(url.protocol.length + 1)[0] === ".") { - output += "/."; - } - output += url.pathname; - if (url.search.length > 0) { - output += url.search; - } - if (excludeFragment === false && url.hash.length > 0) { - output += url.hash; - } - return output; + return format(url, { fragment: !excludeFragment }); } function collectASequenceOfCodePoints(condition, input, position) { let result = ""; @@ -5777,9 +5750,7 @@ var require_file = __commonJS({ var { kEnumerableProperty } = require_util(); var File = class extends Blob { constructor(fileBits, fileName, options = {}) { - if (arguments.length < 2) { - throw new TypeError("2 arguments required"); - } + webidl.argumentLengthCheck(arguments, 2, { header: "File constructor" }); fileBits = webidl.converters["sequence"](fileBits); fileName = webidl.converters.USVString(fileName); options = webidl.converters.FilePropertyBag(options); @@ -5805,26 +5776,17 @@ var require_file = __commonJS({ }; } get name() { - if (!(this instanceof File)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, File); return this[kState].name; } get lastModified() { - if (!(this instanceof File)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, File); return this[kState].lastModified; } get type() { - if (!(this instanceof File)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, File); return this[kState].type; } - get [Symbol.toStringTag]() { - return this.constructor.name; - } }; var FileLike = class { constructor(blobLike, fileName, options = {}) { @@ -5839,51 +5801,35 @@ var require_file = __commonJS({ }; } stream(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].blobLike.stream(...args); } arrayBuffer(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].blobLike.arrayBuffer(...args); } slice(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].blobLike.slice(...args); } text(...args) { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].blobLike.text(...args); } get size() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].blobLike.size; } get type() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].blobLike.type; } get name() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].name; } get lastModified() { - if (!(this instanceof FileLike)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileLike); return this[kState].lastModified; } get [Symbol.toStringTag]() { @@ -5891,6 +5837,10 @@ var require_file = __commonJS({ } }; Object.defineProperties(File.prototype, { + [Symbol.toStringTag]: { + value: "File", + configurable: true + }, name: kEnumerableProperty, lastModified: kEnumerableProperty }); @@ -5977,10 +5927,10 @@ var require_formdata = __commonJS({ var { File, FileLike, isFileLike } = require_file(); var { webidl } = require_webidl(); var { Blob } = require("buffer"); - var _FormData = class { + var FormData = class { constructor(form) { if (form !== void 0) { - webidl.errors.conversionFailed({ + throw webidl.errors.conversionFailed({ prefix: "FormData constructor", argument: "Argument 1", types: ["undefined"] @@ -5989,12 +5939,8 @@ var require_formdata = __commonJS({ this[kState] = []; } append(name, value, filename = void 0) { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 2) { - throw new TypeError(`Failed to execute 'append' on 'FormData': 2 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, FormData); + webidl.argumentLengthCheck(arguments, 2, { header: "FormData.append" }); if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError("Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'"); } @@ -6005,12 +5951,8 @@ var require_formdata = __commonJS({ this[kState].push(entry); } delete(name) { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'delete' on 'FormData': 1 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, FormData); + webidl.argumentLengthCheck(arguments, 1, { header: "FormData.delete" }); name = webidl.converters.USVString(name); const next = []; for (const entry of this[kState]) { @@ -6021,12 +5963,8 @@ var require_formdata = __commonJS({ this[kState] = next; } get(name) { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'get' on 'FormData': 1 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, FormData); + webidl.argumentLengthCheck(arguments, 1, { header: "FormData.get" }); name = webidl.converters.USVString(name); const idx = this[kState].findIndex((entry) => entry.name === name); if (idx === -1) { @@ -6035,32 +5973,20 @@ var require_formdata = __commonJS({ return this[kState][idx].value; } getAll(name) { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'getAll' on 'FormData': 1 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, FormData); + webidl.argumentLengthCheck(arguments, 1, { header: "FormData.getAll" }); name = webidl.converters.USVString(name); return this[kState].filter((entry) => entry.name === name).map((entry) => entry.value); } has(name) { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'has' on 'FormData': 1 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, FormData); + webidl.argumentLengthCheck(arguments, 1, { header: "FormData.has" }); name = webidl.converters.USVString(name); return this[kState].findIndex((entry) => entry.name === name) !== -1; } set(name, value, filename = void 0) { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 2) { - throw new TypeError(`Failed to execute 'set' on 'FormData': 2 arguments required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, FormData); + webidl.argumentLengthCheck(arguments, 2, { header: "FormData.set" }); if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError("Failed to execute 'set' on 'FormData': parameter 2 is not of type 'Blob'"); } @@ -6079,34 +6005,21 @@ var require_formdata = __commonJS({ this[kState].push(entry); } } - get [Symbol.toStringTag]() { - return this.constructor.name; - } entries() { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FormData); return makeIterator(() => this[kState].map((pair) => [pair.name, pair.value]), "FormData", "key+value"); } keys() { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FormData); return makeIterator(() => this[kState].map((pair) => [pair.name, pair.value]), "FormData", "key"); } values() { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FormData); return makeIterator(() => this[kState].map((pair) => [pair.name, pair.value]), "FormData", "value"); } forEach(callbackFn, thisArg = globalThis) { - if (!(this instanceof _FormData)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'forEach' on 'FormData': 1 argument required, but only ${arguments.length} present.`); - } + webidl.brandCheck(this, FormData); + webidl.argumentLengthCheck(arguments, 1, { header: "FormData.forEach" }); if (typeof callbackFn !== "function") { throw new TypeError("Failed to execute 'forEach' on 'FormData': parameter 1 is not of type 'Function'."); } @@ -6115,9 +6028,13 @@ var require_formdata = __commonJS({ } } }; - var FormData = _FormData; - __publicField(FormData, "name", "FormData"); FormData.prototype[Symbol.iterator] = FormData.prototype.entries; + Object.defineProperties(FormData.prototype, { + [Symbol.toStringTag]: { + value: "FormData", + configurable: true + } + }); function makeEntry(name, value, filename) { name = Buffer.from(name).toString("utf8"); if (typeof value === "string") { @@ -6146,7 +6063,7 @@ var require_body = __commonJS({ "use strict"; var Busboy = require_lib(); var util = require_util(); - var { ReadableStreamFrom, toUSVString, isBlobLike, isReadableStreamLike, readableStreamClose } = require_util2(); + var { ReadableStreamFrom, isBlobLike, isReadableStreamLike, readableStreamClose } = require_util2(); var { FormData } = require_formdata(); var { kState } = require_symbols2(); var { webidl } = require_webidl(); @@ -6185,7 +6102,9 @@ var require_body = __commonJS({ let source = null; let length = null; let type = null; - if (object == null) { + if (typeof object === "string") { + source = object; + type = "text/plain;charset=UTF-8"; } else if (object instanceof URLSearchParams) { source = object.toString(); type = "application/x-www-form-urlencoded;charset=UTF-8"; @@ -6213,7 +6132,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r \r `); yield* value.stream(); - yield enc.encode("\r\n"); + yield new Uint8Array([13, 10]); } } yield enc.encode(`--${boundary}--`); @@ -6226,6 +6145,8 @@ Content-Type: ${value.type || "application/octet-stream"}\r if (object.type) { type = object.type; } + } else if (object instanceof Uint8Array) { + source = object; } else if (typeof object[Symbol.asyncIterator] === "function") { if (keepalive) { throw new TypeError("keepalive"); @@ -6234,9 +6155,6 @@ Content-Type: ${value.type || "application/octet-stream"}\r throw new TypeError("Response body object should not be disturbed or locked"); } stream = object instanceof ReadableStream ? object : ReadableStreamFrom(object); - } else { - source = toUSVString(object); - type = "text/plain;charset=UTF-8"; } if (typeof source === "string" || util.isBuffer(source)) { length = Buffer.byteLength(source); @@ -6327,9 +6245,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r return specConsumeBody(this, "JSON", instance); }, async formData() { - if (!(this instanceof instance)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, instance); throwIfAborted(this[kState]); const contentType = this.headers.get("Content-Type"); if (/multipart\/form-data/.test(contentType)) { @@ -6404,7 +6320,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r } else { await Promise.resolve(); throwIfAborted(this[kState]); - webidl.errors.exception({ + throw webidl.errors.exception({ header: `${instance.name}.formData`, message: "Could not parse content as FormData." }); @@ -6417,9 +6333,7 @@ Content-Type: ${value.type || "application/octet-stream"}\r Object.assign(prototype.prototype, bodyMixinMethods(prototype)); } async function specConsumeBody(object, type, instance) { - if (!(object instanceof instance)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(object, instance); throwIfAborted(object[kState]); if (bodyUnusable(object[kState].body)) { throw new TypeError("Body is unusable"); @@ -6566,7 +6480,8 @@ var require_response = __commonJS({ isAborted, isBlobLike, serializeJavascriptValueToJSONString, - isErrorLike + isErrorLike, + isomorphicEncode } = require_util2(); var { redirectStatus, @@ -6594,9 +6509,7 @@ var require_response = __commonJS({ return responseObject; } static json(data = void 0, init = {}) { - if (arguments.length === 0) { - throw new TypeError("Failed to execute 'json' on 'Response': 1 argument required, but 0 present."); - } + webidl.argumentLengthCheck(arguments, 1, { header: "Response.json" }); if (init !== null) { init = webidl.converters.ResponseInit(init); } @@ -6612,9 +6525,7 @@ var require_response = __commonJS({ } static redirect(url, status = 302) { const relevantRealm = { settingsObject: {} }; - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'redirect' on 'Response': 1 argument required, but only ${arguments.length} present.`); - } + webidl.argumentLengthCheck(arguments, 1, { header: "Response.redirect" }); url = webidl.converters.USVString(url); status = webidl.converters["unsigned short"](status); let parsedURL; @@ -6626,14 +6537,14 @@ var require_response = __commonJS({ }); } if (!redirectStatus.includes(status)) { - throw new RangeError("Invalid status code"); + throw new RangeError("Invalid status code " + status); } const responseObject = new Response(); responseObject[kRealm] = relevantRealm; responseObject[kHeaders][kGuard] = "immutable"; responseObject[kHeaders][kRealm] = relevantRealm; responseObject[kState].status = status; - const value = parsedURL.toString(); + const value = isomorphicEncode(URLSerializer(parsedURL)); responseObject[kState].headersList.append("location", value); return responseObject; } @@ -6655,19 +6566,12 @@ var require_response = __commonJS({ } initializeResponse(this, init, bodyWithType); } - get [Symbol.toStringTag]() { - return this.constructor.name; - } get type() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return this[kState].type; } get url() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); const urlList = this[kState].urlList; const url = urlList[urlList.length - 1] ?? null; if (url === null) { @@ -6676,53 +6580,37 @@ var require_response = __commonJS({ return URLSerializer(url, true); } get redirected() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return this[kState].urlList.length > 1; } get status() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return this[kState].status; } get ok() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return this[kState].status >= 200 && this[kState].status <= 299; } get statusText() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return this[kState].statusText; } get headers() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return this[kHeaders]; } get body() { - if (!this || !this[kState]) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return this[kState].body ? this[kState].body.stream : null; } get bodyUsed() { - if (!this || !this[kState]) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); return !!this[kState].body && util.isDisturbed(this[kState].body.stream); } clone() { - if (!(this instanceof Response)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Response); if (this.bodyUsed || this.body && this.body.locked) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Response.clone", message: "Body has already been consumed." }); @@ -6748,7 +6636,11 @@ var require_response = __commonJS({ headers: kEnumerableProperty, clone: kEnumerableProperty, body: kEnumerableProperty, - bodyUsed: kEnumerableProperty + bodyUsed: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "Response", + configurable: true + } }); Object.defineProperties(Response, { json: kEnumerableProperty, @@ -6863,13 +6755,13 @@ var require_response = __commonJS({ } if (body) { if (nullBodyStatus.includes(response.status)) { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Response constructor", - message: "Invalid response status code." + message: "Invalid response status code " + response.status }); } response[kState].body = body.body; - if (body.type != null && !response[kState].headersList.has("Content-Type")) { + if (body.type != null && !response[kState].headersList.contains("Content-Type")) { response[kState].headersList.append("content-type", body.type); } } @@ -6984,7 +6876,8 @@ var require_request = __commonJS({ requestRedirect, requestMode, requestCredentials, - requestCache + requestCache, + requestDuplex } = require_constants(); var { kEnumerableProperty } = util; var { kHeaders, kSignal, kState, kGuard, kRealm } = require_symbols2(); @@ -7003,9 +6896,7 @@ var require_request = __commonJS({ if (input === kInit) { return; } - if (arguments.length < 1) { - throw new TypeError(`Failed to construct 'Request': 1 argument required, but only ${arguments.length} present.`); - } + webidl.argumentLengthCheck(arguments, 1, { header: "Request constructor" }); input = webidl.converters.RequestInfo(input); init = webidl.converters.RequestInit(init); this[kRealm] = { @@ -7093,21 +6984,15 @@ var require_request = __commonJS({ } if (init.referrerPolicy !== void 0) { request.referrerPolicy = init.referrerPolicy; - if (!referrerPolicy.includes(request.referrerPolicy)) { - throw new TypeError(`Failed to construct 'Request': The provided value '${request.referrerPolicy}' is not a valid enum value of type ReferrerPolicy.`); - } } let mode; if (init.mode !== void 0) { mode = init.mode; - if (!requestMode.includes(mode)) { - throw new TypeError(`Failed to construct 'Request': The provided value '${request.mode}' is not a valid enum value of type RequestMode.`); - } } else { mode = fallbackMode; } if (mode === "navigate") { - webidl.errors.exception({ + throw webidl.errors.exception({ header: "Request constructor", message: "invalid request mode navigate." }); @@ -7117,24 +7002,15 @@ var require_request = __commonJS({ } if (init.credentials !== void 0) { request.credentials = init.credentials; - if (!requestCredentials.includes(request.credentials)) { - throw new TypeError(`Failed to construct 'Request': The provided value '${request.credentials}' is not a valid enum value of type RequestCredentials.`); - } } if (init.cache !== void 0) { request.cache = init.cache; - if (!requestCache.includes(request.cache)) { - throw new TypeError(`Failed to construct 'Request': The provided value '${request.cache}' is not a valid enum value of type RequestCache.`); - } } if (request.cache === "only-if-cached" && request.mode !== "same-origin") { throw new TypeError("'only-if-cached' can be set only with 'same-origin' mode"); } if (init.redirect !== void 0) { request.redirect = init.redirect; - if (!requestRedirect.includes(request.redirect)) { - throw new TypeError(`Failed to construct 'Request': The provided value '${request.redirect}' is not a valid enum value of type RequestRedirect.`); - } } if (init.integrity !== void 0 && init.integrity != null) { request.integrity = String(init.integrity); @@ -7204,7 +7080,7 @@ var require_request = __commonJS({ if (init.body !== void 0 && init.body != null) { const [extractedBody, contentType] = extractBody(init.body, request.keepalive); initBody = extractedBody; - if (contentType && !this[kHeaders].has("content-type")) { + if (contentType && !this[kHeaders][kHeadersList].contains("content-type")) { this[kHeaders].append("content-type", contentType); } } @@ -7236,37 +7112,24 @@ var require_request = __commonJS({ } this[kState].body = finalBody; } - get [Symbol.toStringTag]() { - return this.constructor.name; - } get method() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].method; } get url() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return URLSerializer(this[kState].url); } get headers() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kHeaders]; } get destination() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].destination; } get referrer() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); if (this[kState].referrer === "no-referrer") { return ""; } @@ -7276,84 +7139,58 @@ var require_request = __commonJS({ return this[kState].referrer.toString(); } get referrerPolicy() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].referrerPolicy; } get mode() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].mode; } get credentials() { return this[kState].credentials; } get cache() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].cache; } get redirect() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].redirect; } get integrity() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].integrity; } get keepalive() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].keepalive; } get isReloadNavigation() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].reloadNavigation; } get isHistoryNavigation() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].historyNavigation; } get signal() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kSignal]; } get body() { - if (!this || !this[kState]) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return this[kState].body ? this[kState].body.stream : null; } get bodyUsed() { - if (!this || !this[kState]) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return !!this[kState].body && util.isDisturbed(this[kState].body.stream); } get duplex() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); return "half"; } clone() { - if (!(this instanceof Request)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, Request); if (this.bodyUsed || this.body?.locked) { throw new TypeError("unusable"); } @@ -7448,7 +7285,11 @@ var require_request = __commonJS({ attribute: kEnumerableProperty, referrerPolicy: kEnumerableProperty, referrer: kEnumerableProperty, - mode: kEnumerableProperty + mode: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "Request", + configurable: true + } }); webidl.converters.Request = webidl.interfaceConverter(Request); webidl.converters.RequestInfo = function(V) { @@ -7481,58 +7322,27 @@ var require_request = __commonJS({ { key: "referrerPolicy", converter: webidl.converters.DOMString, - allowedValues: [ - "", - "no-referrer", - "no-referrer-when-downgrade", - "same-origin", - "origin", - "strict-origin", - "origin-when-cross-origin", - "strict-origin-when-cross-origin", - "unsafe-url" - ] + allowedValues: referrerPolicy }, { key: "mode", converter: webidl.converters.DOMString, - allowedValues: [ - "same-origin", - "cors", - "no-cors", - "navigate", - "websocket" - ] + allowedValues: requestMode }, { key: "credentials", converter: webidl.converters.DOMString, - allowedValues: [ - "omit", - "same-origin", - "include" - ] + allowedValues: requestCredentials }, { key: "cache", converter: webidl.converters.DOMString, - allowedValues: [ - "default", - "no-store", - "reload", - "no-cache", - "force-cache", - "only-if-cached" - ] + allowedValues: requestCache }, { key: "redirect", converter: webidl.converters.DOMString, - allowedValues: [ - "follow", - "error", - "manual" - ] + allowedValues: requestRedirect }, { key: "integrity", @@ -7553,7 +7363,7 @@ var require_request = __commonJS({ { key: "duplex", converter: webidl.converters.DOMString, - allowedValues: ["half"] + allowedValues: requestDuplex } ]); module2.exports = { Request, makeRequest }; @@ -11530,6 +11340,11 @@ var require_mock_utils = __commonJS({ } = require_mock_symbols(); var { buildURL, nop } = require_util(); var { STATUS_CODES } = require("http"); + var { + types: { + isPromise + } + } = require("util"); function matchValue(match, value) { if (typeof match === "string") { return match === value; @@ -11703,9 +11518,14 @@ var require_mock_utils = __commonJS({ } else { handleReply(this[kDispatches]); } - function handleReply(mockDispatches) { + function handleReply(mockDispatches, _data = data) { const optsHeaders = Array.isArray(opts.headers) ? buildHeadersFromArray(opts.headers) : opts.headers; - const responseData = getResponseData(typeof data === "function" ? data({ ...opts, headers: optsHeaders }) : data); + const body = typeof _data === "function" ? _data({ ...opts, headers: optsHeaders }) : _data; + if (isPromise(body)) { + body.then((newData) => handleReply(mockDispatches, newData)); + return; + } + const responseData = getResponseData(body); const responseHeaders = generateKeyValues(headers); const responseTrailers = generateKeyValues(trailers); handler.abort = nop; @@ -12459,21 +12279,15 @@ var require_progressevent = __commonJS({ }; } get lengthComputable() { - if (!(this instanceof ProgressEvent)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, ProgressEvent); return this[kState].lengthComputable; } get loaded() { - if (!(this instanceof ProgressEvent)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, ProgressEvent); return this[kState].loaded; } get total() { - if (!(this instanceof ProgressEvent)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, ProgressEvent); return this[kState].total; } }; @@ -13025,32 +12839,20 @@ var require_filereader = __commonJS({ }; } readAsArrayBuffer(blob) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length === 0) { - throw new TypeError("Failed to execute 'readAsArrayBuffer' on 'FileReader': 1 argument required, but 0 present."); - } + webidl.brandCheck(this, FileReader); + webidl.argumentLengthCheck(arguments, 1, { header: "FileReader.readAsArrayBuffer" }); blob = webidl.converters.Blob(blob, { strict: false }); readOperation(this, blob, "ArrayBuffer"); } readAsBinaryString(blob) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length === 0) { - throw new TypeError("Failed to execute 'readAsBinaryString' on 'FileReader': 1 argument required, but 0 present."); - } + webidl.brandCheck(this, FileReader); + webidl.argumentLengthCheck(arguments, 1, { header: "FileReader.readAsBinaryString" }); blob = webidl.converters.Blob(blob, { strict: false }); readOperation(this, blob, "BinaryString"); } readAsText(blob, encoding = void 0) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length === 0) { - throw new TypeError("Failed to execute 'readAsText' on 'FileReader': 1 argument required, but 0 present."); - } + webidl.brandCheck(this, FileReader); + webidl.argumentLengthCheck(arguments, 1, { header: "FileReader.readAsText" }); blob = webidl.converters.Blob(blob, { strict: false }); if (encoding !== void 0) { encoding = webidl.converters.DOMString(encoding); @@ -13058,12 +12860,8 @@ var require_filereader = __commonJS({ readOperation(this, blob, "Text", encoding); } readAsDataURL(blob) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } - if (arguments.length === 0) { - throw new TypeError("Failed to execute 'readAsDataURL' on 'FileReader': 1 argument required, but 0 present."); - } + webidl.brandCheck(this, FileReader); + webidl.argumentLengthCheck(arguments, 1, { header: "FileReader.readAsDataURL" }); blob = webidl.converters.Blob(blob, { strict: false }); readOperation(this, blob, "DataURL"); } @@ -13083,9 +12881,7 @@ var require_filereader = __commonJS({ } } get readyState() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); switch (this[kState]) { case "empty": return this.EMPTY; @@ -13096,27 +12892,19 @@ var require_filereader = __commonJS({ } } get result() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kResult]; } get error() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kError]; } get onloadend() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kEvents].loadend; } set onloadend(fn) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); if (typeof fn === "function") { this[kEvents].loadend = fn; } else { @@ -13124,15 +12912,11 @@ var require_filereader = __commonJS({ } } get onerror() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kEvents].error; } set onerror(fn) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); if (typeof fn === "function") { this[kEvents].error = fn; } else { @@ -13140,15 +12924,11 @@ var require_filereader = __commonJS({ } } get onloadstart() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kEvents].loadstart; } set onloadstart(fn) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); if (typeof fn === "function") { this[kEvents].loadstart = fn; } else { @@ -13156,15 +12936,11 @@ var require_filereader = __commonJS({ } } get onprogress() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kEvents].progress; } set onprogress(fn) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); if (typeof fn === "function") { this[kEvents].progress = fn; } else { @@ -13172,15 +12948,11 @@ var require_filereader = __commonJS({ } } get onload() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kEvents].load; } set onload(fn) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); if (typeof fn === "function") { this[kEvents].load = fn; } else { @@ -13188,15 +12960,11 @@ var require_filereader = __commonJS({ } } get onabort() { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); return this[kEvents].abort; } set onabort(fn) { - if (!(this instanceof FileReader)) { - throw new TypeError("Illegal invocation"); - } + webidl.brandCheck(this, FileReader); if (typeof fn === "function") { this[kEvents].abort = fn; } else { @@ -13395,7 +13163,8 @@ var require_fetch = __commonJS({ isAborted, isErrorLike, fullyReadBody, - readableStreamClose + readableStreamClose, + isomorphicEncode } = require_util2(); var { kState, kHeaders, kGuard, kRealm } = require_symbols2(); var assert = require("assert"); @@ -13415,6 +13184,7 @@ var require_fetch = __commonJS({ var { dataURLProcessor, serializeAMimeType } = require_dataURL(); var { TransformStream } = require("stream/web"); var { getGlobalDispatcher } = require_undici(); + var { webidl } = require_webidl(); var resolveObjectURL; var ReadableStream; var nodeVersion = process.versions.node.split("."); @@ -13451,9 +13221,7 @@ var require_fetch = __commonJS({ } }; async function fetch2(input, init = {}) { - if (arguments.length < 1) { - throw new TypeError(`Failed to execute 'fetch' on 'Window': 1 argument required, but only ${arguments.length} present.`); - } + webidl.argumentLengthCheck(arguments, 1, { header: "globalThis.fetch" }); const p = createDeferredPromise(); let requestObject; try { @@ -13614,11 +13382,11 @@ var require_fetch = __commonJS({ request.policyContainer = makePolicyContainer(); } } - if (!request.headersList.has("accept")) { + if (!request.headersList.contains("accept")) { const value = "*/*"; request.headersList.append("accept", value); } - if (!request.headersList.has("accept-language")) { + if (!request.headersList.contains("accept-language")) { request.headersList.append("accept-language", "*"); } if (request.priority === null) { @@ -13693,7 +13461,7 @@ var require_fetch = __commonJS({ if (!request.timingAllowFailed) { response.timingAllowPassed = true; } - if (response.type === "opaque" && internalResponse.status === 206 && internalResponse.rangeRequested && !request.headers.has("range")) { + if (response.type === "opaque" && internalResponse.status === 206 && internalResponse.rangeRequested && !request.headers.contains("range")) { response = internalResponse = makeNetworkError(); } if (response.status !== 0 && (request.method === "HEAD" || request.method === "CONNECT" || nullBodyStatus.includes(internalResponse.status))) { @@ -13743,7 +13511,7 @@ var require_fetch = __commonJS({ } const bodyWithType = safelyExtractBody(blobURLEntryObject); const body = bodyWithType[0]; - const length = `${body.length}`; + const length = isomorphicEncode(`${body.length}`); const type = bodyWithType[1] ?? ""; const response = makeResponse({ statusText: "OK", @@ -13945,7 +13713,7 @@ var require_fetch = __commonJS({ contentLengthHeaderValue = "0"; } if (contentLength != null) { - contentLengthHeaderValue = String(contentLength); + contentLengthHeaderValue = isomorphicEncode(`${contentLength}`); } if (contentLengthHeaderValue != null) { httpRequest.headersList.append("content-length", contentLengthHeaderValue); @@ -13953,31 +13721,31 @@ var require_fetch = __commonJS({ if (contentLength != null && httpRequest.keepalive) { } if (httpRequest.referrer instanceof URL) { - httpRequest.headersList.append("referer", httpRequest.referrer.href); + httpRequest.headersList.append("referer", isomorphicEncode(httpRequest.referrer.href)); } appendRequestOriginHeader(httpRequest); appendFetchMetadata(httpRequest); - if (!httpRequest.headersList.has("user-agent")) { + if (!httpRequest.headersList.contains("user-agent")) { httpRequest.headersList.append("user-agent", "undici"); } - if (httpRequest.cache === "default" && (httpRequest.headersList.has("if-modified-since") || httpRequest.headersList.has("if-none-match") || httpRequest.headersList.has("if-unmodified-since") || httpRequest.headersList.has("if-match") || httpRequest.headersList.has("if-range"))) { + if (httpRequest.cache === "default" && (httpRequest.headersList.contains("if-modified-since") || httpRequest.headersList.contains("if-none-match") || httpRequest.headersList.contains("if-unmodified-since") || httpRequest.headersList.contains("if-match") || httpRequest.headersList.contains("if-range"))) { httpRequest.cache = "no-store"; } - if (httpRequest.cache === "no-cache" && !httpRequest.preventNoCacheCacheControlHeaderModification && !httpRequest.headersList.has("cache-control")) { + if (httpRequest.cache === "no-cache" && !httpRequest.preventNoCacheCacheControlHeaderModification && !httpRequest.headersList.contains("cache-control")) { httpRequest.headersList.append("cache-control", "max-age=0"); } if (httpRequest.cache === "no-store" || httpRequest.cache === "reload") { - if (!httpRequest.headersList.has("pragma")) { + if (!httpRequest.headersList.contains("pragma")) { httpRequest.headersList.append("pragma", "no-cache"); } - if (!httpRequest.headersList.has("cache-control")) { + if (!httpRequest.headersList.contains("cache-control")) { httpRequest.headersList.append("cache-control", "no-cache"); } } - if (httpRequest.headersList.has("range")) { + if (httpRequest.headersList.contains("range")) { httpRequest.headersList.append("accept-encoding", "identity"); } - if (!httpRequest.headersList.has("accept-encoding")) { + if (!httpRequest.headersList.contains("accept-encoding")) { if (/^https:/.test(requestCurrentURL(httpRequest).protocol)) { httpRequest.headersList.append("accept-encoding", "br, gzip, deflate"); } else { @@ -14005,7 +13773,7 @@ var require_fetch = __commonJS({ } } response.urlList = [...httpRequest.urlList]; - if (httpRequest.headersList.has("range")) { + if (httpRequest.headersList.contains("range")) { response.rangeRequested = true; } response.requestIncludesCredentials = includeCredentials;