UNPKG

@remix-run/web-fetch

Version:

Web API compatible fetch implementation

1 lines 110 kB
{"version":3,"file":"lib.node.cjs","sources":["../src/errors/base.js","../src/errors/fetch-error.js","../src/utils/is.js","../src/utils/form-data.js","../src/utils/utf8.js","../src/body.js","../src/headers.js","../src/utils/is-redirect.js","../src/response.js","../src/utils/get-search.js","../src/request.js","../src/errors/abort-error.js","../src/fetch.js"],"sourcesContent":["'use strict';\n\nexport class FetchBaseError extends Error {\n\t/**\n\t * @param {string} message \n\t * @param {string} type \n\t */\n\tconstructor(message, type) {\n\t\tsuper(message);\n\t\t// Hide custom error implementation details from end-users\n\t\tError.captureStackTrace(this, this.constructor);\n\n\t\tthis.type = type;\n\t}\n\n\tget name() {\n\t\treturn this.constructor.name;\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn this.constructor.name;\n\t}\n}\n\n","\nimport {FetchBaseError} from './base.js';\n\n/**\n * @typedef {{\n * address?: string\n * code: string\n * dest?: string\n * errno: number\n * info?: object\n * message: string\n * path?: string\n * port?: number\n * syscall: string\n * }} SystemError\n*/\n\n/**\n * FetchError interface for operational errors\n */\nexport class FetchError extends FetchBaseError {\n\t/**\n\t * @param {string} message - Error message for human\n\t * @param {string} type - Error type for machine\n\t * @param {SystemError} [systemError] - For Node.js system error\n\t */\n\tconstructor(message, type, systemError) {\n\t\tsuper(message, type);\n\t\t// When err.type is `system`, err.erroredSysCall contains system error and err.code contains system error code\n\t\tif (systemError) {\n\t\t\t// eslint-disable-next-line no-multi-assign\n\t\t\tthis.code = this.errno = systemError.code;\n\t\t\tthis.erroredSysCall = systemError.syscall;\n\t\t}\n\t}\n}\n","import Stream from \"stream\";\n\n/**\n * Is.js\n *\n * Object type checks.\n */\n\nconst NAME = Symbol.toStringTag;\n\n/**\n * Check if `obj` is a URLSearchParams object\n * ref: https://github.com/node-fetch/node-fetch/issues/296#issuecomment-307598143\n *\n * @param {any} object\n * @return {obj is URLSearchParams}\n */\nexport const isURLSearchParameters = (object) => {\n\treturn (\n\t\ttypeof object === \"object\" &&\n\t\ttypeof object.append === \"function\" &&\n\t\ttypeof object.delete === \"function\" &&\n\t\ttypeof object.get === \"function\" &&\n\t\ttypeof object.getAll === \"function\" &&\n\t\ttypeof object.has === \"function\" &&\n\t\ttypeof object.set === \"function\" &&\n\t\ttypeof object.sort === \"function\" &&\n\t\tobject[NAME] === \"URLSearchParams\"\n\t);\n};\n\n/**\n * Check if `object` is a W3C `Blob` object (which `File` inherits from)\n *\n * @param {*} object\n * @return {object is Blob}\n */\nexport const isBlob = (object) => {\n\treturn (\n\t\ttypeof object === \"object\" &&\n\t\ttypeof object.arrayBuffer === \"function\" &&\n\t\ttypeof object.type === \"string\" &&\n\t\ttypeof object.stream === \"function\" &&\n\t\ttypeof object.constructor === \"function\" &&\n\t\t/^(Blob|File)$/.test(object[NAME])\n\t);\n};\n\n/**\n * Check if `obj` is a spec-compliant `FormData` object\n *\n * @param {*} object\n * @return {object is FormData}\n */\nexport function isFormData(object) {\n\treturn (\n\t\ttypeof object === \"object\" &&\n\t\ttypeof object.append === \"function\" &&\n\t\ttypeof object.set === \"function\" &&\n\t\ttypeof object.get === \"function\" &&\n\t\ttypeof object.getAll === \"function\" &&\n\t\ttypeof object.delete === \"function\" &&\n\t\ttypeof object.keys === \"function\" &&\n\t\ttypeof object.values === \"function\" &&\n\t\ttypeof object.entries === \"function\" &&\n\t\ttypeof object.constructor === \"function\" &&\n\t\tobject[NAME] === \"FormData\"\n\t);\n}\n\n/**\n * Detect form data input from form-data module\n *\n * @param {any} value\n * @returns {value is Stream & {getBoundary():string, hasKnownLength():boolean, getLengthSync():number|null}}\n */\nexport const isMultipartFormDataStream = (value) => {\n\treturn (\n\t\tvalue instanceof Stream === true &&\n\t\ttypeof value.getBoundary === \"function\" &&\n\t\ttypeof value.hasKnownLength === \"function\" &&\n\t\ttypeof value.getLengthSync === \"function\"\n\t);\n};\n\n/**\n * Check if `obj` is an instance of AbortSignal.\n *\n * @param {any} object\n * @return {obj is AbortSignal}\n */\nexport const isAbortSignal = (object) => {\n\treturn (\n\t\ttypeof object === \"object\" &&\n\t\t(object[NAME] === \"AbortSignal\" || object[NAME] === \"EventTarget\")\n\t);\n};\n\n/**\n * Check if `value` is a ReadableStream.\n *\n * @param {*} value\n * @returns {value is ReadableStream}\n */\nexport const isReadableStream = (value) => {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\ttypeof value.getReader === \"function\" &&\n\t\ttypeof value.cancel === \"function\" &&\n\t\ttypeof value.tee === \"function\"\n\t);\n};\n\n/**\n *\n * @param {any} value\n * @returns {value is Iterable<unknown>}\n */\nexport const isIterable = (value) => value && Symbol.iterator in value;\n","import {randomBytes} from 'crypto';\nimport { iterateMultipart } from '@web3-storage/multipart-parser';\nimport { FormData, File } from '../package.js';\nimport { isBlob } from './is.js';\n\nconst carriage = '\\r\\n';\nconst dashes = '-'.repeat(2);\nconst carriageLength = Buffer.byteLength(carriage);\n\n/**\n * @param {string} boundary\n */\nconst getFooter = boundary => `${dashes}${boundary}${dashes}${carriage.repeat(2)}`;\n\n/**\n * @param {string} boundary\n * @param {string} name\n * @param {*} field\n *\n * @return {string}\n */\nfunction getHeader(boundary, name, field) {\n\tlet header = '';\n\n\theader += `${dashes}${boundary}${carriage}`;\n\theader += `Content-Disposition: form-data; name=\"${name}\"`;\n\n\tif (isBlob(field)) {\n\t\tconst { name = 'blob', type } = /** @type {Blob & {name?:string}} */ (field);\n\t\theader += `; filename=\"${name}\"${carriage}`;\n\t\theader += `Content-Type: ${type || 'application/octet-stream'}`;\n\t}\n\n\treturn `${header}${carriage.repeat(2)}`;\n}\n\n/**\n * @return {string}\n */\nexport const getBoundary = () => randomBytes(8).toString('hex');\n\n/**\n * @param {FormData} form\n * @param {string} boundary\n */\nexport async function * formDataIterator(form, boundary) {\n\tconst encoder = new TextEncoder();\n\tfor (const [name, value] of form) {\n\t\tyield encoder.encode(getHeader(boundary, name, value));\n\n\t\tif (isBlob(value)) {\n\t\t\t// @ts-ignore - we know our streams implement aysnc iteration\n\t\t\tyield * value.stream();\n\t\t} else {\n\t\t\tyield encoder.encode(value);\n\t\t}\n\n\t\tyield encoder.encode(carriage);\n\t}\n\n\tyield encoder.encode(getFooter(boundary));\n}\n\n/**\n * @param {FormData} form\n * @param {string} boundary\n */\nexport function getFormDataLength(form, boundary) {\n\tlet length = 0;\n\n\tfor (const [name, value] of form) {\n\t\tlength += Buffer.byteLength(getHeader(boundary, name, value));\n\n\t\tif (isBlob(value)) {\n\t\t\tlength += value.size;\n\t\t} else {\n\t\t\tlength += Buffer.byteLength(String(value));\n\t\t}\n\n\t\tlength += carriageLength;\n\t}\n\n\tlength += Buffer.byteLength(getFooter(boundary));\n\n\treturn length;\n}\n\n/**\n * @param {Body & {headers?:Headers}} source\n */\nexport const toFormData = async (source) => {\n let { body, headers } = source;\n const contentType = headers?.get('Content-Type') || ''\n\n if (contentType.startsWith('application/x-www-form-urlencoded') && body != null) {\n\t\tconst form = new FormData();\n\t\tlet bodyText = await source.text();\n\t\tnew URLSearchParams(bodyText).forEach((v, k) => form.append(k, v));\n\t\treturn form;\n }\n\n const [type, boundary] = contentType.split(/\\s*;\\s*boundary=/)\n if (type === 'multipart/form-data' && boundary != null && body != null) {\n const form = new FormData()\n const parts = iterateMultipart(body, boundary)\n for await (const { name, data, filename, contentType } of parts) {\n if (typeof filename === 'string') {\n form.append(name, new File([data], filename, { type: contentType }))\n } else if (typeof filename !== 'undefined') {\n form.append(name, new File([], '', { type: contentType }))\n } else {\n form.append(name, new TextDecoder().decode(data), filename)\n }\n }\n return form\n } else {\n throw new TypeError('Could not parse content as FormData.')\n }\n}\n","import {TextEncoder, TextDecoder} from 'util';\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * @param {string} text\n */\nexport const encode = text => encoder.encode(text);\n\n/**\n * @param {Uint8Array} bytes\n */\nexport const decode = bytes => decoder.decode(bytes);\n","// @ts-check\n/**\n * Body.js\n *\n * Body interface provides common methods for Request and Response\n */\n\nimport Stream from 'stream';\nimport {types} from 'util';\n\nimport {Blob, ReadableStream} from './package.js';\n\nimport {FetchError} from './errors/fetch-error.js';\nimport {FetchBaseError} from './errors/base.js';\nimport {formDataIterator, getBoundary, getFormDataLength, toFormData} from './utils/form-data.js';\nimport {isBlob, isURLSearchParameters, isFormData, isMultipartFormDataStream, isReadableStream} from './utils/is.js';\nimport * as utf8 from './utils/utf8.js';\nconst {readableHighWaterMark} = new Stream.Readable();\n\nconst INTERNALS = Symbol('Body internals');\n\n/**\n * Body mixin\n *\n * Ref: https://fetch.spec.whatwg.org/#body\n * @implements {globalThis.Body}\n */\n\nexport default class Body {\n\t/**\n\t * @param {BodyInit|Stream|null} body\n\t * @param {{size?:number}} options\n\t */\n\tconstructor(body, {\n\t\tsize = 0\n\t} = {}) {\n\t\tconst state = {\n\t\t\t/** @type {null|ReadableStream<Uint8Array>} */\n\t\t\tbody: null,\n\t\t\t/** @type {string|null} */\n\t\t\ttype: null,\n\t\t\t/** @type {number|null} */\n\t\t\tsize: null,\n\t\t\t/** @type {null|string} */\n\t\t\tboundary: null,\n\t\t\tdisturbed: false,\n\t\t\t/** @type {null|Error} */\n\t\t\terror: null\n\t\t};\n\t\t/** @private */\n\t\tthis[INTERNALS] = state;\n\n\t\tif (body === null) {\n\t\t\t// Body is undefined or null\n\t\t\tstate.body = null;\n\t\t\tstate.size = 0;\n\t\t} else if (isURLSearchParameters(body)) {\n\t\t// Body is a URLSearchParams\n\t\t\tconst bytes = utf8.encode(body.toString());\n\t\t\tstate.body = fromBytes(bytes);\n\t\t\tstate.size = bytes.byteLength;\n\t\t\tstate.type = 'application/x-www-form-urlencoded;charset=UTF-8';\n\t\t} else if (isBlob(body)) {\n\t\t\t// Body is blob\n\t\t\tstate.size = body.size;\n\t\t\tstate.type = body.type || null;\n\t\t\tstate.body = body.stream();\n\t\t} else if (body instanceof Uint8Array) {\n\t\t\t// Body is Buffer\n\t\t\tstate.body = fromBytes(body);\n\t\t\tstate.size = body.byteLength;\n\t\t} else if (types.isAnyArrayBuffer(body)) {\n\t\t\t// Body is ArrayBuffer\n\t\t\tconst bytes = new Uint8Array(body);\n\t\t\tstate.body = fromBytes(bytes);\n\t\t\tstate.size = bytes.byteLength;\n\t\t} else if (ArrayBuffer.isView(body)) {\n\t\t\t// Body is ArrayBufferView\n\t\t\tconst bytes = new Uint8Array(body.buffer, body.byteOffset, body.byteLength);\n\t\t\tstate.body = fromBytes(bytes);\n\t\t\tstate.size = bytes.byteLength;\n\t\t} else if (isReadableStream(body)) {\n\t\t\t// Body is stream\n\t\t\tstate.body = body;\n\t\t} else if (isFormData(body)) {\n\t\t\t// Body is an instance of formdata-node\n\t\t\tconst boundary = `NodeFetchFormDataBoundary${getBoundary()}`;\n\t\t\tstate.type = `multipart/form-data; boundary=${boundary}`;\n\t\t\tstate.size = getFormDataLength(body, boundary);\n\t\t\tstate.body = fromAsyncIterable(formDataIterator(body, boundary));\n\t\t} else if (isMultipartFormDataStream(body)) {\n\t\t\tstate.type = `multipart/form-data; boundary=${body.getBoundary()}`;\n\t\t\tstate.size = body.hasKnownLength() ? body.getLengthSync() : null;\n\t\t\tstate.body = fromStream(body);\n\t\t} else if (body instanceof Stream) {\n\t\t\tstate.body = fromStream(body);\n\t\t} else {\n\t\t\t// None of the above\n\t\t\t// coerce to string then buffer\n\t\t\tconst bytes = utf8.encode(String(body));\n\t\t\tstate.type = 'text/plain;charset=UTF-8';\n\t\t\tstate.size = bytes.byteLength;\n\t\t\tstate.body = fromBytes(bytes);\n\t\t}\n\n\t\tthis.size = size;\n\n\t\t// if (body instanceof Stream) {\n\t\t// \tbody.on('error', err => {\n\t\t// \t\tconst error = err instanceof FetchBaseError ?\n\t\t// \t\t\terr :\n\t\t// \t\t\tnew FetchError(`Invalid response body while trying to fetch ${this.url}: ${err.message}`, 'system', err);\n\t\t// \t\tthis[INTERNALS].error = error;\n\t\t// \t});\n\t\t// }\n\t}\n\n\t/** @type {Headers} */\n\t/* c8 ignore next 3 */\n\tget headers() {\n\t\tthrow new TypeError(`'get headers' called on an object that does not implements interface.`)\n\t}\n\n\tget body() {\n\t\treturn this[INTERNALS].body;\n\t}\n\n\tget bodyUsed() {\n\t\treturn this[INTERNALS].disturbed;\n\t}\n\n\t/**\n\t * Decode response as ArrayBuffer\n\t *\n\t * @return {Promise<ArrayBuffer>}\n\t */\n\tasync arrayBuffer() {\n\t\tconst {buffer, byteOffset, byteLength} = await consumeBody(this);\n\t\treturn buffer.slice(byteOffset, byteOffset + byteLength);\n\t}\n\n\t/**\n\t * Return raw response as Blob\n\t *\n\t * @return Promise\n\t */\n\tasync blob() {\n\t\tconst ct = (this.headers && this.headers.get('content-type')) || (this[INTERNALS].body && this[INTERNALS].type) || '';\n\t\tconst buf = await consumeBody(this);\n\n\t\treturn new Blob([buf], {\n\t\t\ttype: ct\n\t\t});\n\t}\n\n\t/**\n\t * Decode response as json\n\t *\n\t * @return Promise\n\t */\n\tasync json() {\n\t\treturn JSON.parse(await this.text());\n\t}\n\n\t/**\n\t * Decode response as text\n\t *\n\t * @return Promise\n\t */\n\tasync text() {\n\t\tconst buffer = await consumeBody(this);\n\t\treturn utf8.decode(buffer);\n\t}\n\n\t/**\n\t * @returns {Promise<FormData>}\n\t */\n\tasync formData() {\n\t\treturn toFormData(this)\n\t}\n}\n\n// In browsers, all properties are enumerable.\nObject.defineProperties(Body.prototype, {\n\tbody: {enumerable: true},\n\tbodyUsed: {enumerable: true},\n\tarrayBuffer: {enumerable: true},\n\tblob: {enumerable: true},\n\tjson: {enumerable: true},\n\ttext: {enumerable: true},\n\tformData: {enumerable: true}\n});\n\n/**\n * Consume and convert an entire Body to a Buffer.\n *\n * Ref: https://fetch.spec.whatwg.org/#concept-body-consume-body\n *\n * @param {Body & {url?:string}} data\n * @return {Promise<Uint8Array>}\n */\nasync function consumeBody(data) {\n\tconst state = data[INTERNALS];\n\tif (state.disturbed) {\n\t\tthrow new TypeError(`body used already for: ${data.url}`);\n\t}\n\n\tstate.disturbed = true;\n\n\tif (state.error) {\n\t\tthrow state.error;\n\t}\n\n\tconst {body} = state;\n\n\t// Body is null\n\tif (body === null) {\n\t\treturn new Uint8Array(0);\n\t}\n\n\t// Body is stream\n\t// get ready to actually consume the body\n\t/** @type {[Uint8Array|null, Uint8Array[], number]} */\n\tconst [buffer, chunks, limit] = data.size > 0 ?\n\t\t[new Uint8Array(data.size), [], data.size] :\n\t\t[null, [], Infinity];\n\tlet offset = 0;\n\n\tconst source = streamIterator(body);\n\ttry {\n\t\tfor await (const chunk of source) {\n\t\t\tconst bytes = chunk instanceof Uint8Array ?\n\t\t\t\tchunk :\n\t\t\t\tBuffer.from(chunk);\n\n\t\t\tif (offset + bytes.byteLength > limit) {\n\t\t\t\tconst error = new FetchError(`content size at ${data.url} over limit: ${limit}`, 'max-size');\n\t\t\t\tsource.throw(error);\n\t\t\t\tthrow error;\n\t\t\t} else if (buffer) {\n\t\t\t\tbuffer.set(bytes, offset);\n\t\t\t} else {\n\t\t\t\tchunks.push(bytes);\n\t\t\t}\n\n\t\t\toffset += bytes.byteLength;\n\t\t}\n\n\t\tif (buffer) {\n\t\t\tif (offset < buffer.byteLength) {\n\t\t\t\tthrow new FetchError(`Premature close of server response while trying to fetch ${data.url}`, 'premature-close');\n\t\t\t} else {\n\t\t\t\treturn buffer;\n\t\t\t}\n\t\t} else {\n\t\t\treturn writeBytes(new Uint8Array(offset), chunks);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof FetchBaseError) {\n\t\t\tthrow error;\n\t\t// @ts-expect-error - we know it will have a name\n\t\t} else if (error && error.name === 'AbortError') {\n\t\t\tthrow error;\n\t\t} else {\n\t\t\tconst e = /** @type {import('./errors/fetch-error').SystemError} */(error)\n\t\t\t// Other errors, such as incorrect content-encoding\n\t\t\tthrow new FetchError(`Invalid response body while trying to fetch ${data.url}: ${e.message}`, 'system', e);\n\t\t}\n\t}\n}\n\n/**\n * Clone body given Res/Req instance\n *\n * @param {Body} instance Response or Request instance\n * @return {ReadableStream<Uint8Array> | null}\n */\nexport const clone = instance => {\n\tconst {body} = instance;\n\n\t// Don't allow cloning a used body\n\tif (instance.bodyUsed) {\n\t\tthrow new Error('cannot clone body after it is used');\n\t}\n\n\tif (!body) {\n\t\treturn null;\n\t}\n\n\tconst [left, right] = body.tee();\n\tinstance[INTERNALS].body = left;\n\treturn right;\n};\n\n/**\n * Performs the operation \"extract a `Content-Type` value from |object|\" as\n * specified in the specification:\n * https://fetch.spec.whatwg.org/#concept-bodyinit-extract\n *\n * This function assumes that instance.body is present.\n *\n * @param {Body} source Any options.body input\n * @returns {string | null}\n */\nexport const extractContentType = source => source[INTERNALS].type;\n\n/**\n * The Fetch Standard treats this as if \"total bytes\" is a property on the body.\n * For us, we have to explicitly get it with a function.\n *\n * ref: https://fetch.spec.whatwg.org/#concept-body-total-bytes\n *\n * @param {Body} source - Body object from the Body instance.\n * @returns {number | null}\n */\nexport const getTotalBytes = source => source[INTERNALS].size;\n\n/**\n * Write a Body to a Node.js WritableStream (e.g. http.Request) object.\n *\n * @param {Stream.Writable} dest - The stream to write to.\n * @param {Body} source - Body object from the Body instance.\n * @returns {void}\n */\nexport const writeToStream = (dest, {body}) => {\n\tif (body === null) {\n\t\t// Body is null\n\t\tdest.end();\n\t} else {\n\t\tStream.Readable.from(streamIterator(body)).pipe(dest);\n\t}\n};\n\n/**\n * @template T\n * @implements {AsyncGenerator<T, void, void>}\n */\nclass StreamIterableIterator {\n\t/**\n\t * @param {ReadableStream<T>} stream\n\t */\n\tconstructor(stream) {\n\t\tthis.stream = stream;\n\t\tthis.reader = null;\n\t}\n\n\t/**\n\t * @returns {AsyncGenerator<T, void, void>}\n\t */\n\t[Symbol.asyncIterator]() {\n\t\treturn this;\n\t}\n\n\tgetReader() {\n\t\tif (this.reader) {\n\t\t\treturn this.reader;\n\t\t}\n\n\t\tconst reader = this.stream.getReader();\n\t\tthis.reader = reader;\n\t\treturn reader;\n\t}\n\n\t/**\n\t * @returns {Promise<IteratorResult<T, void>>}\n\t */\n\tnext() {\n\t\treturn /** @type {Promise<IteratorResult<T, void>>} */ (this.getReader().read());\n\t}\n\n\t/**\n\t * @returns {Promise<IteratorResult<T, void>>}\n\t */\n\tasync return() {\n\t\tif (this.reader) {\n\t\t\tawait this.reader.cancel();\n\t\t}\n\n\t\treturn {done: true, value: undefined};\n\t}\n\n\t/**\n\t * \n\t * @param {any} error \n\t * @returns {Promise<IteratorResult<T, void>>}\n\t */\n\tasync throw(error) {\n\t\tawait this.getReader().cancel(error);\n\t\treturn {done: true, value: undefined};\n\t}\n}\n\n/**\n * @template T\n * @param {ReadableStream<T>} stream\n */\nexport const streamIterator = stream => new StreamIterableIterator(stream);\n\n/**\n * @param {Uint8Array} buffer\n * @param {Uint8Array[]} chunks\n */\nconst writeBytes = (buffer, chunks) => {\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tbuffer.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\n\treturn buffer;\n};\n\n/**\n * @param {Uint8Array} bytes\n * @returns {ReadableStream<Uint8Array>}\n */\n// @ts-ignore\nconst fromBytes = bytes => new ReadableStream({\n\tstart(controller) {\n\t\tcontroller.enqueue(bytes);\n\t\tcontroller.close();\n\t}\n});\n\n/**\n * @param {AsyncIterable<Uint8Array>} content\n * @returns {ReadableStream<Uint8Array>}\n */\nexport const fromAsyncIterable = content =>\n\tnew ReadableStream(new AsyncIterablePump(content));\n\n/**\n * @implements {UnderlyingSource<Uint8Array>}\n */\nclass AsyncIterablePump {\n\t/**\n\t * @param {AsyncIterable<Uint8Array>} source\n\t */\n\tconstructor(source) {\n\t\tthis.source = source[Symbol.asyncIterator]();\n\t}\n\n\t/**\n\t * @param {ReadableStreamController<Uint8Array>} controller\n\t */\n\tasync pull(controller) {\n\t\ttry {\n\t\t\twhile (controller.desiredSize || 0 > 0) {\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tconst next = await this.source.next();\n\t\t\t\tif (next.done) {\n\t\t\t\t\tcontroller.close();\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\tcontroller.enqueue(next.value);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tcontroller.error(error);\n\t\t}\n\t}\n\n\t/**\n\t * @param {any} [reason]\n\t */\n\tcancel(reason) {\n\t\tif (reason) {\n\t\t\tif (typeof this.source.throw === 'function') {\n\t\t\t\tthis.source.throw(reason);\n\t\t\t} else if (typeof this.source.return === 'function') {\n\t\t\t\tthis.source.return();\n\t\t\t}\n\t\t} else if (typeof this.source.return === 'function') {\n\t\t\tthis.source.return();\n\t\t}\n\t}\n}\n\n/**\n * @param {Stream & {readableHighWaterMark?:number}} source\n * @returns {ReadableStream<Uint8Array>}\n */\nexport const fromStream = source => {\n\tconst pump = new StreamPump(source);\n\tconst stream = new ReadableStream(pump, pump);\n\treturn stream;\n};\n\n/**\n * @implements {UnderlyingSource<Uint8Array>}\n * @implements {QueuingStrategy<Uint8Array>}\n */\nclass StreamPump {\n\t/**\n\t * @param {Stream & {\n\t * \treadableHighWaterMark?: number\n\t * \treadable?:boolean,\n\t * \tresume?: () => void,\n\t * \tpause?: () => void\n\t * \tdestroy?: (error?:Error) => void\n\t * }} stream\n\t */\n\tconstructor(stream) {\n\t\tthis.highWaterMark = stream.readableHighWaterMark || readableHighWaterMark;\n\t\tthis.accumalatedSize = 0;\n\t\tthis.stream = stream;\n\t\tthis.enqueue = this.enqueue.bind(this);\n\t\tthis.error = this.error.bind(this);\n\t\tthis.close = this.close.bind(this);\n\t}\n\n\t/**\n\t * @param {Uint8Array} [chunk]\n\t */\n\tsize(chunk) {\n\t\treturn chunk?.byteLength || 0;\n\t}\n\n\t/**\n\t * @param {ReadableStreamController<Uint8Array>} controller\n\t */\n\tstart(controller) {\n\t\tthis.controller = controller;\n\t\tthis.stream.on('data', this.enqueue);\n\t\tthis.stream.once('error', this.error);\n\t\tthis.stream.once('end', this.close);\n\t\tthis.stream.once('close', this.close);\n\t}\n\n\tpull() {\n\t\tthis.resume();\n\t}\n\n\t/**\n\t * @param {any} [reason]\n\t */\n\tcancel(reason) {\n\t\tif (this.stream.destroy) {\n\t\t\tthis.stream.destroy(reason);\n\t\t}\n\n\t\tthis.stream.off('data', this.enqueue);\n\t\tthis.stream.off('error', this.error);\n\t\tthis.stream.off('end', this.close);\n\t\tthis.stream.off('close', this.close);\n\t}\n\n\t/**\n\t * @param {Uint8Array|string} chunk\n\t */\n\tenqueue(chunk) {\n\t\tif (this.controller) {\n\t\t\ttry {\n\t\t\t\tconst bytes = chunk instanceof Uint8Array ?\n\t\t\t\t\tchunk :\n\t\t\t\t\tBuffer.from(chunk);\n\n\t\t\t\tconst available = (this.controller.desiredSize || 0) - bytes.byteLength;\n\t\t\t\tthis.controller.enqueue(bytes);\n\t\t\t\tif (available <= 0) {\n\t\t\t\t\tthis.pause();\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tthis.controller.error(new Error('Could not create Buffer, chunk must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object'));\n\t\t\t\tthis.cancel();\n\t\t\t}\n\t\t}\n\t}\n\n\tpause() {\n\t\tif (this.stream.pause) {\n\t\t\tthis.stream.pause();\n\t\t}\n\t}\n\n\tresume() {\n\t\tif (this.stream.readable && this.stream.resume) {\n\t\t\tthis.stream.resume();\n\t\t}\n\t}\n\n\tclose() {\n\t\tif (this.controller) {\n\t\t\tthis.controller.close();\n\t\t\tdelete this.controller;\n\t\t}\n\t}\n\n\t/**\n\t * @param {Error} error \n\t */\n\terror(error) {\n\t\tif (this.controller) {\n\t\t\tthis.controller.error(error);\n\t\t\tdelete this.controller;\n\t\t}\n\t}\n}\n","/**\n * Headers.js\n *\n * Headers class offers convenient helpers\n */\n\nimport {types} from 'util';\nimport http from 'http';\nimport { isIterable } from './utils/is.js'\n\n/** @type {{validateHeaderValue?:(name:string, value:string) => any}} */\nconst validators = (http)\n\n/**\n * @param {string} name\n */\nconst validateHeaderName = name => {\n\tif (!/^[\\^`\\-\\w!#$%&'*+.|~:]+$/.test(name)) {\n\t\tconst err = new TypeError(`Header name must be a valid HTTP token [${name}]`);\n\t\tObject.defineProperty(err, 'code', {value: 'ERR_INVALID_HTTP_TOKEN'});\n\t\tthrow err;\n\t}\n};\n\nconst validateHeaderValue = typeof validators.validateHeaderValue === 'function' ?\n\tvalidators.validateHeaderValue :\n\t/**\n\t * @param {string} name\n\t * @param {string} value\n\t */\n\t(name, value) => {\n\t\tif (/[^\\t\\u0020-\\u007E\\u0080-\\u00FF]/.test(value)) {\n\t\t\tconst err = new TypeError(`Invalid character in header content [\"${name}\"]`);\n\t\t\tObject.defineProperty(err, 'code', {value: 'ERR_INVALID_CHAR'});\n\t\t\tthrow err;\n\t\t}\n\t};\n\n/**\n * @typedef {Headers | Record<string, string> | Iterable<readonly [string, string]> | Iterable<Iterable<string>>} HeadersInit\n */\n\n/**\n * This Fetch API interface allows you to perform various actions on HTTP request and response headers.\n * These actions include retrieving, setting, adding to, and removing.\n * A Headers object has an associated header list, which is initially empty and consists of zero or more name and value pairs.\n * You can add to this using methods like append() (see Examples.)\n * In all methods of this interface, header names are matched by case-insensitive byte sequence.\n *\n * @implements {globalThis.Headers}\n */\nexport default class Headers extends URLSearchParams {\n\t/**\n\t * Headers class\n\t *\n\t * @constructor\n\t * @param {HeadersInit} [init] - Response headers\n\t */\n\tconstructor(init) {\n\t\t// Validate and normalize init object in [name, value(s)][]\n\t\t/** @type {string[][]} */\n\t\tlet result = [];\n\t\tif (init instanceof Headers) {\n\t\t\tconst raw = init.raw();\n\t\t\tfor (const [name, values] of Object.entries(raw)) {\n\t\t\t\tresult.push(...values.map(value => [name, value]));\n\t\t\t}\n\t\t} else if (init == null) { // eslint-disable-line no-eq-null, eqeqeq\n\t\t\t// No op\n\t\t} else if (isIterable(init)) {\n\t\t\t// Sequence<sequence<ByteString>>\n\t\t\t// Note: per spec we have to first exhaust the lists then process them\n\t\t\tresult = [...init]\n\t\t\t\t.map(pair => {\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof pair !== 'object' || types.isBoxedPrimitive(pair)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError('Each header pair must be an iterable object');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...pair];\n\t\t\t\t}).map(pair => {\n\t\t\t\t\tif (pair.length !== 2) {\n\t\t\t\t\t\tthrow new TypeError('Each header pair must be a name/value tuple');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...pair];\n\t\t\t\t});\n\t\t} else if (typeof init === \"object\" && init !== null) {\n\t\t\t// Record<ByteString, ByteString>\n\t\t\tresult.push(...Object.entries(init));\n\t\t} else {\n\t\t\tthrow new TypeError('Failed to construct \\'Headers\\': The provided value is not of type \\'(sequence<sequence<ByteString>> or record<ByteString, ByteString>)');\n\t\t}\n\n\t\t// Validate and lowercase\n\t\tresult =\n\t\t\tresult.length > 0 ?\n\t\t\t\tresult.map(([name, value]) => {\n\t\t\t\t\tvalidateHeaderName(name);\n\t\t\t\t\tvalidateHeaderValue(name, String(value));\n\t\t\t\t\treturn [String(name).toLowerCase(), String(value)];\n\t\t\t\t}) :\n\t\t\t\t[];\n\n\t\tsuper(result);\n\n\t\t// Returning a Proxy that will lowercase key names, validate parameters and sort keys\n\t\t// eslint-disable-next-line no-constructor-return\n\t\treturn new Proxy(this, {\n\t\t\tget(target, p, receiver) {\n\t\t\t\tswitch (p) {\n\t\t\t\t\tcase 'append':\n\t\t\t\t\tcase 'set':\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * @param {string} name\n\t\t\t\t\t\t * @param {string} value\n\t\t\t\t\t\t */\n\t\t\t\t\t\treturn (name, value) => {\n\t\t\t\t\t\t\tvalidateHeaderName(name);\n\t\t\t\t\t\t\tvalidateHeaderValue(name, String(value));\n\t\t\t\t\t\t\treturn URLSearchParams.prototype[p].call(\n\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\tString(name).toLowerCase(),\n\t\t\t\t\t\t\t\tString(value)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t};\n\n\t\t\t\t\tcase 'delete':\n\t\t\t\t\tcase 'has':\n\t\t\t\t\tcase 'getAll':\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * @param {string} name\n\t\t\t\t\t\t */\n\t\t\t\t\t\treturn name => {\n\t\t\t\t\t\t\tvalidateHeaderName(name);\n\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\treturn URLSearchParams.prototype[p].call(\n\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\tString(name).toLowerCase()\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t};\n\n\t\t\t\t\tcase 'keys':\n\t\t\t\t\t\treturn () => {\n\t\t\t\t\t\t\ttarget.sort();\n\t\t\t\t\t\t\treturn new Set(URLSearchParams.prototype.keys.call(target)).keys();\n\t\t\t\t\t\t};\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn Reflect.get(target, p, receiver);\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* c8 ignore next */\n\t\t});\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn this.constructor.name;\n\t}\n\n\ttoString() {\n\t\treturn Object.prototype.toString.call(this);\n\t}\n\n\t/**\n\t *\n\t * @param {string} name\n\t */\n\tget(name) {\n\t\tconst values = this.getAll(name);\n\t\tif (values.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet value = values.join(', ');\n\t\tif (/^content-encoding$/i.test(name)) {\n\t\t\tvalue = value.toLowerCase();\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * @param {(value: string, key: string, parent: this) => void} callback\n\t * @param {any} thisArg\n\t * @returns {void}\n\t */\n\tforEach(callback, thisArg = undefined) {\n\t\tfor (const name of this.keys()) {\n\t\t\tif (name.toLowerCase() === 'set-cookie') {\n\t\t\t\tlet cookies = this.getAll(name);\n\t\t\t\twhile (cookies.length > 0) {\n\t\t\t\t\tReflect.apply(callback, thisArg, [cookies.shift(), name, this])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tReflect.apply(callback, thisArg, [this.get(name), name, this]);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @returns {IterableIterator<string>}\n\t */\n\t* values() {\n\t\tfor (const name of this.keys()) {\n\t\t\tif (name.toLowerCase() === 'set-cookie') {\n\t\t\t\tlet cookies = this.getAll(name);\n\t\t\t\twhile (cookies.length > 0) {\n\t\t\t\t\tyield /** @type {string} */(cookies.shift());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyield /** @type {string} */(this.get(name));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @returns {IterableIterator<[string, string]>}\n\t */\n\t* entries() {\n\t\tfor (const name of this.keys()) {\n\t\t\tif (name.toLowerCase() === 'set-cookie') {\n\t\t\t\tlet cookies = this.getAll(name);\n\t\t\t\twhile (cookies.length > 0) {\n\t\t\t\t\tyield [name, /** @type {string} */(cookies.shift())];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyield [name, /** @type {string} */(this.get(name))];\n\t\t\t}\n\t\t}\n\t}\n\n\t[Symbol.iterator]() {\n\t\treturn this.entries();\n\t}\n\n\t/**\n\t * Node-fetch non-spec method\n\t * returning all headers and their values as array\n\t * @returns {Record<string, string[]>}\n\t */\n\traw() {\n\t\treturn [...this.keys()].reduce((result, key) => {\n\t\t\tresult[key] = this.getAll(key);\n\t\t\treturn result;\n\t\t}, /** @type {Record<string, string[]>} */({}));\n\t}\n\n\t/**\n\t * For better console.log(headers) and also to convert Headers into Node.js Request compatible format\n\t */\n\t[Symbol.for('nodejs.util.inspect.custom')]() {\n\t\treturn [...this.keys()].reduce((result, key) => {\n\t\t\tconst values = this.getAll(key);\n\t\t\t// Http.request() only supports string as Host header.\n\t\t\t// This hack makes specifying custom Host header possible.\n\t\t\tif (key === 'host') {\n\t\t\t\tresult[key] = values[0];\n\t\t\t} else {\n\t\t\t\tresult[key] = values.length > 1 ? values : values[0];\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}, /** @type {Record<string, string|string[]>} */({}));\n\t}\n}\n\n/**\n * Re-shaping object for Web IDL tests\n * Only need to do it for overridden methods\n */\nObject.defineProperties(\n\tHeaders.prototype,\n\t['get', 'entries', 'forEach', 'values'].reduce((result, property) => {\n\t\tresult[property] = {enumerable: true};\n\t\treturn result;\n\t}, /** @type {Record<string, {enumerable:true}>} */ ({}))\n);\n\n/**\n * Create a Headers object from an http.IncomingMessage.rawHeaders, ignoring those that do\n * not conform to HTTP grammar productions.\n * @param {import('http').IncomingMessage['rawHeaders']} headers\n */\nexport function fromRawHeaders(headers = []) {\n\treturn new Headers(\n\t\theaders\n\t\t\t// Split into pairs\n\t\t\t.reduce((result, value, index, array) => {\n\t\t\t\tif (index % 2 === 0) {\n\t\t\t\t\tresult.push(array.slice(index, index + 2));\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}, /** @type {string[][]} */([]))\n\t\t\t.filter(([name, value]) => {\n\t\t\t\ttry {\n\t\t\t\t\tvalidateHeaderName(name);\n\t\t\t\t\tvalidateHeaderValue(name, String(value));\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t})\n\n\t);\n}\n","const redirectStatus = new Set([301, 302, 303, 307, 308]);\n\n/**\n * Redirect code matching\n *\n * @param {number} code - Status code\n * @return {boolean}\n */\nexport const isRedirect = code => {\n\treturn redirectStatus.has(code);\n};\n","/**\n * Response.js\n *\n * Response class provides content decoding\n */\n\nimport Headers from './headers.js';\nimport Body, {clone, extractContentType} from './body.js';\nimport {isRedirect} from './utils/is-redirect.js';\n\nconst INTERNALS = Symbol('Response internals');\n\n/**\n * Response class\n * \n * @typedef {Object} Ext\n * @property {number} [size]\n * @property {string} [url]\n * @property {number} [counter]\n * @property {number} [highWaterMark]\n * \n * @implements {globalThis.Response}\n */\nexport default class Response extends Body {\n\t/**\n\t * @param {BodyInit|import('stream').Stream|null} [body] - Readable stream\n\t * @param {ResponseInit & Ext} [options] - Response options\n\t */\n\tconstructor(body = null, options = {}) {\n\t\tsuper(body, options);\n\n\t\tconst status = options.status || 200;\n\t\tconst headers = new Headers(options.headers);\n\n\t\tif (body !== null && !headers.has('Content-Type')) {\n\t\t\tconst contentType = extractContentType(this);\n\t\t\tif (contentType) {\n\t\t\t\theaders.append('Content-Type', contentType);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @private\n\t\t*/\n\t\tthis[INTERNALS] = {\n\t\t\turl: options.url,\n\t\t\tstatus,\n\t\t\tstatusText: options.statusText || '',\n\t\t\theaders,\n\t\t\tcounter: options.counter || 0,\n\t\t\thighWaterMark: options.highWaterMark\n\t\t};\n\t}\n\n\t/**\n\t * @type {ResponseType}\n\t */\n\tget type() {\n\t\treturn \"default\"\n\t}\n\n\tget url() {\n\t\treturn this[INTERNALS].url || '';\n\t}\n\n\tget status() {\n\t\treturn this[INTERNALS].status;\n\t}\n\n\t/**\n\t * Convenience property representing if the request ended normally\n\t */\n\tget ok() {\n\t\treturn this[INTERNALS].status >= 200 && this[INTERNALS].status < 300;\n\t}\n\n\tget redirected() {\n\t\treturn this[INTERNALS].counter > 0;\n\t}\n\n\tget statusText() {\n\t\treturn this[INTERNALS].statusText;\n\t}\n\n\t/**\n\t * @type {Headers}\n\t */\n\tget headers() {\n\t\treturn this[INTERNALS].headers;\n\t}\n\n\tget highWaterMark() {\n\t\treturn this[INTERNALS].highWaterMark;\n\t}\n\n\t/**\n\t * Clone this response\n\t *\n\t * @returns {Response}\n\t */\n\tclone() {\n\t\treturn new Response(clone(this), {\n\t\t\turl: this.url,\n\t\t\tstatus: this.status,\n\t\t\tstatusText: this.statusText,\n\t\t\theaders: this.headers,\n\t\t\tsize: this.size\n\t\t});\n\t}\n\n\t/**\n\t * @param {string} url The URL that the new response is to originate from.\n\t * @param {number} status An optional status code for the response (e.g., 302.)\n\t * @returns {Response} A Response object.\n\t */\n\tstatic redirect(url, status = 302) {\n\t\tif (!isRedirect(status)) {\n\t\t\tthrow new RangeError('Failed to execute \"redirect\" on \"response\": Invalid status code');\n\t\t}\n\n\t\treturn new Response(null, {\n\t\t\theaders: {\n\t\t\t\tlocation: new URL(url).toString()\n\t\t\t},\n\t\t\tstatus\n\t\t});\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'Response';\n\t}\n}\n\nObject.defineProperties(Response.prototype, {\n\turl: {enumerable: true},\n\tstatus: {enumerable: true},\n\tok: {enumerable: true},\n\tredirected: {enumerable: true},\n\tstatusText: {enumerable: true},\n\theaders: {enumerable: true},\n\tclone: {enumerable: true}\n});\n\n","/**\n * @param {URL} parsedURL \n * @returns {string}\n */\nexport const getSearch = parsedURL => {\n\tif (parsedURL.search) {\n\t\treturn parsedURL.search;\n\t}\n\n\tconst lastOffset = parsedURL.href.length - 1;\n\tconst hash = parsedURL.hash || (parsedURL.href[lastOffset] === '#' ? '#' : '');\n\treturn parsedURL.href[lastOffset - hash.length] === '?' ? '?' : '';\n};\n","\n/**\n * Request.js\n *\n * Request class contains server only options\n *\n * All spec algorithm step numbers are based on https://fetch.spec.whatwg.org/commit-snapshots/ae716822cb3a61843226cd090eefc6589446c1d2/.\n */\n\nimport {format as formatUrl} from 'url';\nimport {AbortController as AbortControllerPolyfill} from 'abort-controller';\nimport Headers from './headers.js';\nimport Body, {clone, extractContentType, getTotalBytes} from './body.js';\nimport {isAbortSignal} from './utils/is.js';\nimport {getSearch} from './utils/get-search.js';\n\nconst INTERNALS = Symbol('Request internals');\n\nconst forbiddenMethods = new Set([\"CONNECT\", \"TRACE\", \"TRACK\"]);\nconst normalizedMethods = new Set([\"DELETE\", \"GET\", \"HEAD\", \"OPTIONS\", \"POST\", \"PUT\"]);\n\n/**\n * Check if `obj` is an instance of Request.\n *\n * @param {any} object\n * @return {object is Request}\n */\nconst isRequest = object => {\n\treturn (\n\t\ttypeof object === 'object' &&\n\t\ttypeof object[INTERNALS] === 'object'\n\t);\n};\n\n\n/**\n * Request class\n * @implements {globalThis.Request}\n *\n * @typedef {Object} RequestState\n * @property {string} method\n * @property {RequestRedirect} redirect\n * @property {globalThis.Headers} headers\n * @property {RequestCredentials} credentials\n * @property {URL} parsedURL\n * @property {AbortSignal|null} signal\n *\n * @typedef {Object} RequestExtraOptions\n * @property {number} [follow]\n * @property {boolean} [compress]\n * @property {number} [size]\n * @property {number} [counter]\n * @property {Agent} [agent]\n * @property {number} [highWaterMark]\n * @property {boolean} [insecureHTTPParser]\n *\n * @typedef {((url:URL) => import('http').Agent | import('https').Agent) | import('http').Agent | import('https').Agent} Agent\n *\n * @typedef {Object} RequestOptions\n * @property {string} [method]\n * @property {ReadableStream<Uint8Array>|null} [body]\n * @property {globalThis.Headers} [headers]\n * @property {RequestRedirect} [redirect]\n *\n */\nexport default class Request extends Body {\n\t/**\n\t * @param {string|Request|URL} info Url or Request instance\n\t * @param {RequestInit & RequestExtraOptions} init Custom options\n\t */\n\tconstructor(info, init = {}) {\n\t\tlet parsedURL;\n\t\t/** @type {RequestOptions & RequestExtraOptions} */\n\t\tlet settings\n\n\t\t// Normalize input and force URL to be encoded as UTF-8 (https://github.com/node-fetch/node-fetch/issues/245)\n\t\tif (isRequest(info)) {\n\t\t\tparsedURL = new URL(info.url);\n\t\t\tsettings = (info)\n\t\t} else {\n\t\t\tparsedURL = new URL(info);\n\t\t\tsettings = {};\n\t\t}\n\n\n\n\t\t// Normalize method: https://fetch.spec.whatwg.org/#methods\n\t\tlet method = init.method || settings.method || 'GET';\n\t\tif (forbiddenMethods.has(method.toUpperCase())) {\n\t\t\tthrow new TypeError(`Failed to construct 'Request': '${method}' HTTP method is unsupported.`)\n\t\t} else if (normalizedMethods.has(method.toUpperCase())) {\n\t\t\tmethod = method.toUpperCase();\n\t\t}\n\n\t\tconst inputBody = init.body != null\n\t\t\t? init.body\n\t\t\t: (isRequest(info) && info.body !== null)\n\t\t\t? clone(info)\n\t\t\t: null;\n\n\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\tif (inputBody != null && (method === 'GET' || method === 'HEAD')) {\n\t\t\tthrow new TypeError('Request with GET/HEAD method cannot have body');\n\t\t}\n\n\t\tsuper(inputBody, {\n\t\t\tsize: init.size || settings.size || 0\n\t\t});\n\t\tconst input = settings\n\n\n\t\tconst headers = /** @type {globalThis.Headers} */\n\t\t\t(new Headers(init.headers || input.headers || {}));\n\n\t\tif (inputBody !== null && !headers.has('Content-Type')) {\n\t\t\tconst contentType = extractContentType(this);\n\t\t\tif (contentType) {\n\t\t\t\theaders.append('Content-Type', contentType);\n\t\t\t}\n\t\t}\n\n\t\tlet signal = 'signal' in init\n\t\t\t? init.signal\n\t\t\t: isRequest(input)\n\t\t\t? input.signal\n\t\t\t: null;\n\n\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\tif (signal != null && !isAbortSignal(signal)) {\n\t\t\tthrow new TypeError('Expected signal to be an instanceof AbortSignal or EventTarget');\n\t\t}\n\n\t\tif (!signal) {\n\t\t\tlet AbortControllerConstructor = typeof AbortController != \"undefined\"\n\t\t\t? AbortController\n\t\t\t: AbortControllerPolyfill;\n\t\t\t/** @type {any} */\n\t\t\tlet newSignal = new AbortControllerConstructor().signal;\n\t\t\tsignal = newSignal;\n\t\t}\n\n\t\t/** @type {RequestState} */\n\t\tthis[INTERNALS] = {\n\t\t\tmethod,\n\t\t\tredirect: init.redirect || input.redirect || 'follow',\n\t\t\theaders,\n\t\t\tcredentials: init.credentials || 'same-origin',\n\t\t\tparsedURL,\n\t\t\tsignal: signal || null\n\t\t};\n\n\t\t/** @type {boolean} */\n\t\tthis.keepalive\n\n\t\t// Node-fetch-only options\n\t\t/** @type {number} */\n\t\tthis.follow = init.follow === undefined ? (input.follow === undefined ? 20 : input.follow) : init.follow;\n\t\t/** @type {boolean} */\n\t\tthis.compress = init.compress === undefined ? (input.compress === undefined ? true : input.compress) : init.compress;\n\t\t/** @type {number} */\n\t\tthis.counter = init.counter || input.counter || 0;\n\t\t/** @type {Agent|undefined} */\n\t\tthis.agent = init.agent || input.agent;\n\t\t/** @type {number} */\n\t\tthis.highWaterMark = init.highWaterMark || input.highWaterMark || 16384;\n\t\t/** @type {boolean} */\n\t\tthis.insecureHTTPParser = init.insecureHTTPParser || input.insecureHTTPParser || false;\n\t}\n\n\t/**\n\t * @type {RequestCache}\n\t */\n\tget cache() {\n\t\treturn \"default\"\n\t}\n\n\t/**\n\t * @type {RequestCredentials}\n\t */\n\n\tget credentials() {\n\t\treturn this[INTERNALS].credentials\n\t}\n\n\t/**\n\t * @type {RequestDestination}\n\t */\n\tget destination() {\n\t\treturn \"\"\n\t}\n\n\tget integrity() {\n\t\treturn \"\"\n\t}\n\n\t/** @type {RequestMode} */\n\tget mode() {\n\t\treturn \"cors\"\n\t}\n\n\t/** @type {string} */\n\tget referrer() {\n\t\treturn \"\"\n\t}\n\n\t/** @type {ReferrerPolicy} */\n\tget referrerPolicy() {\n\t\treturn \"\"\n\t}\n\tget method() {\n\t\treturn this[INTERNALS].method;\n\t}\n\n\t/**\n\t * @type {string}\n\t */\n\tget url() {\n\t\treturn formatUrl(this[INTERNALS].parsedURL);\n\t}\n\n\t/**\n\t * @type {globalThis.Headers}\n\t */\n\tget headers() {\n\t\treturn this[INTERNALS].headers;\n\t}\n\n\tget redirect() {\n\t\treturn this[INTERNALS].redirect;\n\t}\n\n\t/**\n\t * @returns {AbortSignal}\n\t */\n\tget signal() {\n\t\t// @ts-ignore\n\t\treturn this[INTERNALS].signal;\n\t}\n\n\t/**\n\t * Clone this request\n\t *\n\t * @return {globalThis.Request}\n\t */\n\tclone() {\n\t\treturn new Request(this);\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'Request';\n\t}\n}\n\nObject.defineProperties(Request.prototype, {\n\tmethod: {enumerable: true},\n\turl: {enumerable: true},\n\theaders: {enumerable: true},\n\tredirect: {enumerable: true},\n\tclone: {enumerable: true},\n\tsignal: {enumerable: true}\n});\n\n/**\n * Convert a Request to Node.js http request options.\n * The options object to be passed to http.request\n *\n * @param {Request & Record<INTERNALS, RequestState>} request - A Request instance\n */\nexport const getNodeRequestOptions = request => {\n\tconst {parsedURL} = request[INTERNALS];\n\tconst headers = new Headers(request[INTERNALS].headers);\n\n\t// Fetch step 1.3\n\tif (!headers.has('Accept')) {\n\t\theaders.set('Accept', '*/*');\n\t}\n\n\t// HTTP-network-or-cache fetch steps 2.4-2.7\n\tlet contentLengthValue = null;\n\tif (request.body === null && /^(post|put)$/i.test(request.method)) {\n\t\tcontentLengthValue = '0';\n\t}\n\n\tif (request.body !== null) {\n\t\tconst totalBytes = getTotalBytes(request);\n\t\t// Set Content-Length if totalBytes is a number (that is not NaN)\n\t\tif (typeof totalBytes === 'number' && !Number.isNaN(totalBytes)) {\n\t\t\tcontentLengthValue = String(totalBytes);\n\t\t}\n\t}\n\n\tif (contentLengthValue) {\n\t\theaders.set('Content-Length', contentLengthValue);\n\t}\n\n\t// HTTP-network-or-cache fetch step 2.11\n\tif (!headers.has('User-Agent')) {\n\t\theaders.set('User-Agent', 'node-fetch');\n\t}\n\n\t// HTTP-network-or-cache fetch step 2.15\n\tif (request.compress && !headers.has('Accept-Encoding')) {\n\t\theaders.set('Accept-Encoding', 'gzip,deflate,br');\n\t}\n\n\tlet {agent} = request;\n\tif (typeof agent === 'function') {\n\t\tagent = agent(parsedURL);\n\t}\n\n\tif (!headers.has('Connection') && !agent) {\n\t\theaders.set('Connection', 'close');\n\t}\n\n\t// HTTP-network fetch step 4.2\n\t// chunked encoding is handled by Node.js\n\n\tconst search = getSearch(parsedURL);\n\n\t// Manually spread the URL object instead of spread syntax\n\tconst requestOptions = {\n\t\tpath: parsedURL.pathname + search,\n\t\tpathname: parsedURL.pathname,\n\t\thostname: parsedURL.hostname,\n\t\tprotocol: parsedURL.protocol,\n\t\tport: parsedURL.port,\n\t\thash: parsedURL.hash,\n\t\tsearch: parsedURL.search,\n\t\t// @ts-ignore - it does not has a query\n\t\tquery: parsedURL.query,\n\t\thref: parsedURL.href,\n\t\tmethod: request.method,\n\t\t// @ts-ignore - not sure what this supposed to do\n\t\theaders: headers[Symbol.for('nodejs.util.inspect.custom')](),\n\t\tinsecureHTTPParser: request.insecureHTTPParser,\n\t\tagent\n\t};\n\n\treturn requestOptions;\n};\n","import {FetchBaseError} from './base.js';\n\n/**\n * AbortError interface for cancelled requests\n */\nexport class AbortError extends FetchBaseError {\n\t/**\n\t * @param {string} message \n\t * @param {string} [type]\n\t */\n\tconstructor(message, type = 'aborted') {\n\t\tsuper(message, type);\n\t}\n}\n","/**\n * Index.js\n *\n * a request API compatible with window.fetch\n *\n * All spec algorithm step numbers are based on https://fetch.spec.whatwg.org/commit-snapshots/ae716822cb3a61843226cd090eefc6589446c1d2/.\n */\n\nimport http from 'http';\nimport https from 'https';\nimport zlib from 'zlib';\nimport fs from 'fs';\nimport * as mime from 'mrmime'\nimport dataUriToBuffer from 'data-uri-to-buffer';\nimport {Buffer} from 'buffer';\n\nimport {writeToStream, fromAsyncIterable} from './body.js';\nimport Response from './response.js';\nimport Headers, {fromRawHeaders} from './headers.js';\nimport Request, {getNodeRequestOptions} from './request.js';\nimport {FetchError} from './errors/fetch-error.js';\nimport {AbortError} from './errors/abort-error.js';\nimport {isRedirect} from './utils/is-redirect.js';\nimport {pipeline as pump, PassThrough} from 'stream';\nimport * as Stream from 'stream';\nimport { ReadableStream, Blob, FormData } from './package.js';\n\n\nexport {Headers, Request, Response, ReadableStream, Blob, FormData};\n\nconst supportedSchemas = new Set(['data:', 'http:', 'https:', 'file:']);\n\n/**\n * Fetch function\n *\n * @param {string | URL | import('./request.js').default} url - Absolute url or Request instance\n * @param {RequestInit & import('./request.js').RequestExtraOptions} [options_] - Fetch options\n * @return {Promise<import('./response.js').default>}\n */\nasync function fetch(url, options_ = {}) {\n\treturn new Promise((resolve, reject) => {\n\t\t// Build request object\n\t\tconst request = new Request(url, options_);\n\t\tconst options = getNodeRequestOptions(request);\n\t\tif (!supportedSchemas.has(options.protocol)) {\n\t\t\tthrow new TypeError(`node-fetch cannot load ${url}. URL scheme \"${options.protocol.replace(/:$/, '')}\" is not supported.`);\n\t\t}\n\n\t\tif (options.protocol === 'data:') {\n\t\t\tconst data = dataUriToBuffer(request.url.toString());\n\t\t\tconst response = new Response(data, {headers: {'Content-Type': data.typeFull}});\n\t\t\tresolve(response);\n\t\t\treturn;\n\t\t}\n\n\t\tif (options.protocol === 'file:') {\n\t\t\tconst stream = fs.createReadStream(new URL(request.url))\n\t\t\tconst type = mime.lookup(request.url) || 'application/octet-stream'\n\t\t\tconst response = new Response(stream, {headers: {'Content-Type': type }});\n\t\t\tresolve(response);\n\t\t\treturn;\n\t\t}\n\n\t\t// Wrap http.request into fetch\n\t\tconst send = (options.protocol === 'https:' ? https : http).request;\n\t\tconst {signal} = request;\n\t\t/** @type {Response|null} */\n\t\tlet response = null;\n\t\t/** @type {import('http').IncomingMessage|null} */\n\t\tlet response_ = null;\n\n\t\tconst abort = () => {\n\t\t\tconst error = new AbortError('The operation was aborted.');\n\t\t\treject(error);\n\t\t\tif (request.body) {\n\t\t\t\trequest.body.cancel(error);\n\t\t\t}\n\n\t\t\tif (!response_) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresponse_.emit('error', error);\n\t\t};\n\n\t\tif (signal && signal.aborted) {\n\t\t\tabort();\n\t\t\treturn;\n\t\t}\n\n\t\tconst abortAndFinalize = () => {\n\t\t\tabort();\n\t\t\tfinalize();\n\t\t};\n\n\t\t// Send request\n\t\tconst request_ = send(options);\n\n\t\tif (signal) {\n\t\t\tsignal.addEventListener('abort', abortAndFinalize);\n\t\t}\n\n\t\tconst finalize = () => {\n\t\t\trequest_.abort();\n\t\t\tif (signal) {\n\t\t\t\tsignal.removeEventListener('abort', abortAndFinalize);\n\t\t\t}\n\t\t};\n\n\t\trequest_.on('error', err => {\n\t\t\t// @ts-expect-error - err may not be SystemError\n\t\t\treject(new FetchError(`requ