node-fetch
Advanced tools
Comparing version 3.0.0 to 3.1.0
@@ -74,2 +74,10 @@ /// <reference types="node" /> | ||
signal?: AbortSignal | null; | ||
/** | ||
* A string whose value is a same-origin URL, "about:client", or the empty string, to set request’s referrer. | ||
*/ | ||
referrer?: string; | ||
/** | ||
* A referrer policy to set request’s referrerPolicy. | ||
*/ | ||
referrerPolicy?: ReferrerPolicy; | ||
@@ -99,2 +107,3 @@ // Node-fetch extensions to the whatwg/fetch spec | ||
| URLSearchParams | ||
| FormData | ||
| NodeJS.ReadableStream | ||
@@ -109,4 +118,8 @@ | string; | ||
/** | ||
* @deprecated Please use 'response.arrayBuffer()' instead of 'response.buffer() | ||
*/ | ||
buffer(): Promise<Buffer>; | ||
arrayBuffer(): Promise<ArrayBuffer>; | ||
formData(): Promise<FormData>; | ||
blob(): Promise<Blob>; | ||
@@ -121,2 +134,3 @@ json(): Promise<unknown>; | ||
export type RequestRedirect = 'error' | 'follow' | 'manual'; | ||
export type ReferrerPolicy = '' | 'no-referrer' | 'no-referrer-when-downgrade' | 'same-origin' | 'origin' | 'strict-origin' | 'origin-when-cross-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url'; | ||
export type RequestInfo = string | Request; | ||
@@ -146,2 +160,10 @@ export class Request extends BodyMixin { | ||
readonly url: string; | ||
/** | ||
* A string whose value is a same-origin URL, "about:client", or the empty string, to set request’s referrer. | ||
*/ | ||
readonly referrer: string; | ||
/** | ||
* A referrer policy to set request’s referrerPolicy. | ||
*/ | ||
readonly referrerPolicy: ReferrerPolicy; | ||
clone(): Request; | ||
@@ -165,2 +187,3 @@ } | ||
static error(): Response; | ||
static redirect(url: string, status?: number): Response; | ||
} | ||
@@ -167,0 +190,0 @@ |
{ | ||
"name": "node-fetch", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"description": "A light-weight module that brings Fetch API to node.js", | ||
@@ -58,4 +58,4 @@ "main": "./src/index.js", | ||
"form-data": "^4.0.0", | ||
"formdata-node": "^3.5.4", | ||
"mocha": "^8.3.2", | ||
"formdata-node": "^4.2.4", | ||
"mocha": "^9.1.3", | ||
"p-timeout": "^5.0.0", | ||
@@ -66,3 +66,4 @@ "tsd": "^0.14.0", | ||
"dependencies": { | ||
"data-uri-to-buffer": "^3.0.1", | ||
"data-uri-to-buffer": "^4.0.0", | ||
"formdata-polyfill": "^4.0.10", | ||
"fetch-blob": "^3.1.2" | ||
@@ -96,2 +97,3 @@ }, | ||
"capitalized-comments": 0, | ||
"node/no-unsupported-features/es-syntax": 0, | ||
"@typescript-eslint/member-ordering": 0 | ||
@@ -98,0 +100,0 @@ }, |
105
README.md
@@ -42,7 +42,5 @@ <div align="center"> | ||
- [Streams](#streams) | ||
- [Buffer](#buffer) | ||
- [Accessing Headers and other Meta data](#accessing-headers-and-other-meta-data) | ||
- [Accessing Headers and other Metadata](#accessing-headers-and-other-metadata) | ||
- [Extract Set-Cookie Header](#extract-set-cookie-header) | ||
- [Post data using a file stream](#post-data-using-a-file-stream) | ||
- [Post with form-data (detect multipart)](#post-with-form-data-detect-multipart) | ||
- [Request cancellation with AbortSignal](#request-cancellation-with-abortsignal) | ||
@@ -72,3 +70,2 @@ - [API](#api) | ||
- [body.text()](#bodytext) | ||
- [body.buffer()](#bodybuffer) | ||
- [Class: FetchError](#class-fetcherror) | ||
@@ -117,2 +114,4 @@ - [Class: AbortError](#class-aborterror) | ||
### ES Modules (ESM) | ||
```js | ||
@@ -122,14 +121,12 @@ import fetch from 'node-fetch'; | ||
If you want to patch the global object in node: | ||
### CommonJS | ||
```js | ||
import fetch from 'node-fetch'; | ||
`node-fetch` from v3 is an ESM-only module - you are not able to import it with `require()`. | ||
if (!globalThis.fetch) { | ||
globalThis.fetch = fetch; | ||
} | ||
If you cannot switch to ESM, please use v2 which remains compatible with CommonJS. Critical bug fixes will continue to be published for v2. | ||
```sh | ||
npm install node-fetch@2 | ||
``` | ||
`node-fetch` is an ESM-only module - you are not able to import it with `require`. We recommend you stay on v2 which is built with CommonJS unless you use ESM yourself. We will continue to publish critical bug fixes for it. | ||
Alternatively, you can use the async `import()` function from CommonJS to load `node-fetch` asynchronously: | ||
@@ -142,2 +139,23 @@ | ||
### Providing global access | ||
To use `fetch()` without importing it, you can patch the `global` object in node: | ||
```js | ||
// fetch-polyfill.js | ||
import fetch from 'node-fetch'; | ||
if (!globalThis.fetch) { | ||
globalThis.fetch = fetch; | ||
globalThis.Headers = Headers; | ||
globalThis.Request = Request; | ||
globalThis.Response = Response; | ||
} | ||
// index.js | ||
import './fetch-polyfill' | ||
// ... | ||
``` | ||
## Upgrading | ||
@@ -248,4 +266,4 @@ | ||
constructor(response, ...args) { | ||
super(`HTTP Error Response: ${response.status} ${response.statusText}`, ...args); | ||
this.response = response; | ||
super(`HTTP Error Response: ${response.status} ${response.statusText}`, ...args); | ||
} | ||
@@ -293,3 +311,3 @@ } | ||
const response = await fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png'); | ||
const response = await fetch('https://github.githubassets.com/images/modules/logos_page/Octocat.png'); | ||
@@ -350,22 +368,7 @@ if (!response.ok) throw new Error(`unexpected response ${response.statusText}`); | ||
### Buffer | ||
### Accessing Headers and other Metadata | ||
If you prefer to cache binary data in full, use buffer(). (NOTE: buffer() is a `node-fetch` only API) | ||
```js | ||
import fetch from 'node-fetch'; | ||
import fileType from 'file-type'; | ||
const response = await fetch('https://octodex.github.com/images/Fintechtocat.png'); | ||
const buffer = await response.buffer(); | ||
const type = await fileType.fromBuffer(buffer) | ||
console.log(type); | ||
``` | ||
### Accessing Headers and other Meta data | ||
```js | ||
import fetch from 'node-fetch'; | ||
const response = await fetch('https://github.com/'); | ||
@@ -393,11 +396,11 @@ | ||
### Post data using a file stream | ||
### Post data using a file | ||
```js | ||
import {createReadStream} from 'fs'; | ||
import {fileFromSync} from 'fetch-blob/from.js'; | ||
import fetch from 'node-fetch'; | ||
const stream = createReadStream('input.txt'); | ||
const blob = fileFromSync('./input.txt', 'text/plain'); | ||
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: stream}); | ||
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: blob}); | ||
const data = await response.json(); | ||
@@ -408,3 +411,3 @@ | ||
node-fetch also supports spec-compliant FormData implementations such as [formdata-polyfill](https://www.npmjs.com/package/formdata-polyfill) and [formdata-node](https://github.com/octet-stream/form-data): | ||
node-fetch also supports any spec-compliant FormData implementations such as [formdata-polyfill](https://www.npmjs.com/package/formdata-polyfill). But any other spec-compliant such as [formdata-node](https://github.com/octet-stream/form-data) works too, but we recommend formdata-polyfill because we use this one internally for decoding entries back to FormData. | ||
@@ -414,5 +417,6 @@ ```js | ||
import {FormData} from 'formdata-polyfill/esm-min.js'; | ||
// Alternative package: | ||
import {FormData} from 'formdata-node'; | ||
// Alternative hack to get the same FormData instance as node-fetch | ||
// const FormData = (await new Response(new URLSearchParams()).formData()).constructor | ||
const form = new FormData(); | ||
@@ -437,4 +441,6 @@ form.set('greeting', 'Hello, world!'); | ||
import fetch from 'node-fetch'; | ||
import AbortController from 'abort-controller'; | ||
// AbortController was added in node v14.17.0 globally | ||
const AbortController = globalThis.AbortController || await import('abort-controller') | ||
const controller = new AbortController(); | ||
@@ -469,3 +475,3 @@ const timeout = setTimeout(() => { | ||
`url` should be an absolute url, such as `https://example.com/`. A path-relative URL (`/file/under/root`) or protocol-relative URL (`//can-be-http-or-https.com/`) will result in a rejected `Promise`. | ||
`url` should be an absolute URL, such as `https://example.com/`. A path-relative URL (`/file/under/root`) or protocol-relative URL (`//can-be-http-or-https.com/`) will result in a rejected `Promise`. | ||
@@ -483,3 +489,3 @@ <a id="fetch-options"></a> | ||
headers: {}, // Request headers. format is the identical to that accepted by the Headers constructor (see below) | ||
body: null, // Request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream | ||
body: null, // Request body. can be null, or a Node.js Readable stream | ||
redirect: 'follow', // Set to `manual` to extract redirect headers, `error` to reject redirect | ||
@@ -508,2 +514,3 @@ signal: null, // Pass an instance of AbortSignal to optionally abort requests | ||
| `Content-Length` | _(automatically calculated, if possible)_ | | ||
| `Host` | _(host and port information from the target URI)_ | | ||
| `Transfer-Encoding` | `chunked` _(when `req.body` is a stream)_ | | ||
@@ -579,3 +586,3 @@ | `User-Agent` | `node-fetch` | | ||
const result = await res.clone().buffer(); | ||
const result = await res.clone().arrayBuffer(); | ||
console.dir(result); | ||
@@ -599,4 +606,2 @@ ``` | ||
- `destination` | ||
- `referrer` | ||
- `referrerPolicy` | ||
- `mode` | ||
@@ -710,6 +715,2 @@ - `credentials` | ||
The following methods are not yet implemented in node-fetch at this moment: | ||
- `formData()` | ||
#### body.body | ||
@@ -733,2 +734,4 @@ | ||
#### body.formData() | ||
#### body.blob() | ||
@@ -746,10 +749,2 @@ | ||
#### body.buffer() | ||
<small>_(node-fetch extension)_</small> | ||
- Returns: `Promise<Buffer>` | ||
Consume the body and return a promise that will resolve to a Buffer. | ||
<a id="class-fetcherror"></a> | ||
@@ -756,0 +751,0 @@ |
@@ -8,11 +8,11 @@ | ||
import Stream, {PassThrough} from 'stream'; | ||
import {types} from 'util'; | ||
import Stream, {PassThrough} from 'node:stream'; | ||
import {types, deprecate} from 'node:util'; | ||
import Blob from 'fetch-blob'; | ||
import {FormData, formDataToBlob} from 'formdata-polyfill/esm.min.js'; | ||
import {FetchError} from './errors/fetch-error.js'; | ||
import {FetchBaseError} from './errors/base.js'; | ||
import {formDataIterator, getBoundary, getFormDataLength} from './utils/form-data.js'; | ||
import {isBlob, isURLSearchParameters, isFormData} from './utils/is.js'; | ||
import {isBlob, isURLSearchParameters} from './utils/is.js'; | ||
@@ -40,3 +40,3 @@ const INTERNALS = Symbol('Body internals'); | ||
} else if (isURLSearchParameters(body)) { | ||
// Body is a URLSearchParams | ||
// Body is a URLSearchParams | ||
body = Buffer.from(body.toString()); | ||
@@ -55,6 +55,6 @@ } else if (isBlob(body)) { | ||
// Body is stream | ||
} else if (isFormData(body)) { | ||
// Body is an instance of formdata-node | ||
boundary = `NodeFetchFormDataBoundary${getBoundary()}`; | ||
body = Stream.Readable.from(formDataIterator(body, boundary)); | ||
} else if (body instanceof FormData) { | ||
// Body is FormData | ||
body = formDataToBlob(body); | ||
boundary = body.type.split('=')[1]; | ||
} else { | ||
@@ -66,4 +66,13 @@ // None of the above | ||
let stream = body; | ||
if (Buffer.isBuffer(body)) { | ||
stream = Stream.Readable.from(body); | ||
} else if (isBlob(body)) { | ||
stream = Stream.Readable.from(body.stream()); | ||
} | ||
this[INTERNALS] = { | ||
body, | ||
stream, | ||
boundary, | ||
@@ -86,3 +95,3 @@ disturbed: false, | ||
get body() { | ||
return this[INTERNALS].body; | ||
return this[INTERNALS].stream; | ||
} | ||
@@ -104,2 +113,20 @@ | ||
async formData() { | ||
const ct = this.headers.get('content-type'); | ||
if (ct.startsWith('application/x-www-form-urlencoded')) { | ||
const formData = new FormData(); | ||
const parameters = new URLSearchParams(await this.text()); | ||
for (const [name, value] of parameters) { | ||
formData.append(name, value); | ||
} | ||
return formData; | ||
} | ||
const {toFormData} = await import('./utils/multipart-parser.js'); | ||
return toFormData(this.body, ct); | ||
} | ||
/** | ||
@@ -149,2 +176,4 @@ * Return raw response as Blob | ||
Body.prototype.buffer = deprecate(Body.prototype.buffer, 'Please use \'response.arrayBuffer()\' instead of \'response.buffer()\'', 'node-fetch#buffer'); | ||
// In browsers, all properties are enumerable. | ||
@@ -178,3 +207,3 @@ Object.defineProperties(Body.prototype, { | ||
let {body} = data; | ||
const {body} = data; | ||
@@ -186,12 +215,2 @@ // Body is null | ||
// Body is blob | ||
if (isBlob(body)) { | ||
body = Stream.Readable.from(body.stream()); | ||
} | ||
// Body is buffer | ||
if (Buffer.isBuffer(body)) { | ||
return body; | ||
} | ||
/* c8 ignore next 3 */ | ||
@@ -248,3 +267,3 @@ if (!(body instanceof Stream)) { | ||
let p2; | ||
let {body} = instance; | ||
let {body} = instance[INTERNALS]; | ||
@@ -265,3 +284,3 @@ // Don't allow cloning a used body | ||
// Set instance body to teed body and return the other teed body | ||
instance[INTERNALS].body = p1; | ||
instance[INTERNALS].stream = p1; | ||
body = p2; | ||
@@ -273,2 +292,8 @@ } | ||
const getNonSpecFormDataBoundary = deprecate( | ||
body => body.getBoundary(), | ||
'form-data doesn\'t follow the spec and requires special treatment. Use alternative package', | ||
'https://github.com/node-fetch/node-fetch/issues/1167' | ||
); | ||
/** | ||
@@ -310,11 +335,11 @@ * Performs the operation "extract a `Content-Type` value from |object|" as | ||
if (body instanceof FormData) { | ||
return `multipart/form-data; boundary=${request[INTERNALS].boundary}`; | ||
} | ||
// Detect form data input from form-data module | ||
if (body && typeof body.getBoundary === 'function') { | ||
return `multipart/form-data;boundary=${body.getBoundary()}`; | ||
return `multipart/form-data;boundary=${getNonSpecFormDataBoundary(body)}`; | ||
} | ||
if (isFormData(body)) { | ||
return `multipart/form-data; boundary=${request[INTERNALS].boundary}`; | ||
} | ||
// Body is stream - can't really do much about this | ||
@@ -339,3 +364,3 @@ if (body instanceof Stream) { | ||
export const getTotalBytes = request => { | ||
const {body} = request; | ||
const {body} = request[INTERNALS]; | ||
@@ -362,7 +387,2 @@ // Body is null or undefined | ||
// Body is a spec-compliant form-data | ||
if (isFormData(body)) { | ||
return getFormDataLength(request[INTERNALS].boundary); | ||
} | ||
// Body is stream | ||
@@ -383,9 +403,2 @@ return null; | ||
dest.end(); | ||
} else if (isBlob(body)) { | ||
// Body is Blob | ||
Stream.Readable.from(body.stream()).pipe(dest); | ||
} else if (Buffer.isBuffer(body)) { | ||
// Body is buffer | ||
dest.write(body); | ||
dest.end(); | ||
} else { | ||
@@ -392,0 +405,0 @@ // Body is stream |
@@ -7,4 +7,4 @@ /** | ||
import {types} from 'util'; | ||
import http from 'http'; | ||
import {types} from 'node:util'; | ||
import http from 'node:http'; | ||
@@ -11,0 +11,0 @@ const validateHeaderName = typeof http.validateHeaderName === 'function' ? |
@@ -9,9 +9,9 @@ /** | ||
import http from 'http'; | ||
import https from 'https'; | ||
import zlib from 'zlib'; | ||
import Stream, {PassThrough, pipeline as pump} from 'stream'; | ||
import http from 'node:http'; | ||
import https from 'node:https'; | ||
import zlib from 'node:zlib'; | ||
import Stream, {PassThrough, pipeline as pump} from 'node:stream'; | ||
import dataUriToBuffer from 'data-uri-to-buffer'; | ||
import {writeToStream} from './body.js'; | ||
import {writeToStream, clone} from './body.js'; | ||
import Response from './response.js'; | ||
@@ -23,2 +23,3 @@ import Headers, {fromRawHeaders} from './headers.js'; | ||
import {isRedirect} from './utils/is-redirect.js'; | ||
import {parseReferrerPolicyFromHeader} from './utils/referrer.js'; | ||
@@ -40,8 +41,8 @@ export {Headers, Request, Response, FetchError, AbortError, isRedirect}; | ||
const request = new Request(url, options_); | ||
const options = getNodeRequestOptions(request); | ||
if (!supportedSchemas.has(options.protocol)) { | ||
throw new TypeError(`node-fetch cannot load ${url}. URL scheme "${options.protocol.replace(/:$/, '')}" is not supported.`); | ||
const {parsedURL, options} = getNodeRequestOptions(request); | ||
if (!supportedSchemas.has(parsedURL.protocol)) { | ||
throw new TypeError(`node-fetch cannot load ${url}. URL scheme "${parsedURL.protocol.replace(/:$/, '')}" is not supported.`); | ||
} | ||
if (options.protocol === 'data:') { | ||
if (parsedURL.protocol === 'data:') { | ||
const data = dataUriToBuffer(request.url); | ||
@@ -54,3 +55,3 @@ const response = new Response(data, {headers: {'Content-Type': data.typeFull}}); | ||
// Wrap http.request into fetch | ||
const send = (options.protocol === 'https:' ? https : http).request; | ||
const send = (parsedURL.protocol === 'https:' ? https : http).request; | ||
const {signal} = request; | ||
@@ -84,3 +85,3 @@ let response = null; | ||
// Send request | ||
const request_ = send(options); | ||
const request_ = send(parsedURL, options); | ||
@@ -174,5 +175,7 @@ if (signal) { | ||
method: request.method, | ||
body: request.body, | ||
body: clone(request), | ||
signal: request.signal, | ||
size: request.size | ||
size: request.size, | ||
referrer: request.referrer, | ||
referrerPolicy: request.referrerPolicy | ||
}; | ||
@@ -194,2 +197,8 @@ | ||
// HTTP-redirect fetch step 14 | ||
const responseReferrerPolicy = parseReferrerPolicyFromHeader(headers); | ||
if (responseReferrerPolicy) { | ||
requestOptions.referrerPolicy = responseReferrerPolicy; | ||
} | ||
// HTTP-redirect fetch step 15 | ||
@@ -196,0 +205,0 @@ resolve(fetch(new Request(locationURL, requestOptions))); |
@@ -10,3 +10,3 @@ | ||
import {format as formatUrl} from 'url'; | ||
import {format as formatUrl} from 'node:url'; | ||
import Headers from './headers.js'; | ||
@@ -16,2 +16,5 @@ import Body, {clone, extractContentType, getTotalBytes} from './body.js'; | ||
import {getSearch} from './utils/get-search.js'; | ||
import { | ||
validateReferrerPolicy, determineRequestsReferrer, DEFAULT_REFERRER_POLICY | ||
} from './utils/referrer.js'; | ||
@@ -54,2 +57,6 @@ const INTERNALS = Symbol('Request internals'); | ||
if (parsedURL.username !== '' || parsedURL.password !== '') { | ||
throw new TypeError(`${parsedURL} is an url with embedded credentails.`); | ||
} | ||
let method = init.method || input.method || 'GET'; | ||
@@ -79,3 +86,3 @@ method = method.toUpperCase(); | ||
if (contentType) { | ||
headers.append('Content-Type', contentType); | ||
headers.set('Content-Type', contentType); | ||
} | ||
@@ -96,2 +103,17 @@ } | ||
// §5.4, Request constructor steps, step 15.1 | ||
// eslint-disable-next-line no-eq-null, eqeqeq | ||
let referrer = init.referrer == null ? input.referrer : init.referrer; | ||
if (referrer === '') { | ||
// §5.4, Request constructor steps, step 15.2 | ||
referrer = 'no-referrer'; | ||
} else if (referrer) { | ||
// §5.4, Request constructor steps, step 15.3.1, 15.3.2 | ||
const parsedReferrer = new URL(referrer); | ||
// §5.4, Request constructor steps, step 15.3.3, 15.3.4 | ||
referrer = /^about:(\/\/)?client$/.test(parsedReferrer) ? 'client' : parsedReferrer; | ||
} else { | ||
referrer = undefined; | ||
} | ||
this[INTERNALS] = { | ||
@@ -102,3 +124,4 @@ method, | ||
parsedURL, | ||
signal | ||
signal, | ||
referrer | ||
}; | ||
@@ -113,2 +136,6 @@ | ||
this.insecureHTTPParser = init.insecureHTTPParser || input.insecureHTTPParser || false; | ||
// §5.4, Request constructor steps, step 16. | ||
// Default is empty string per https://fetch.spec.whatwg.org/#concept-request-referrer-policy | ||
this.referrerPolicy = init.referrerPolicy || input.referrerPolicy || ''; | ||
} | ||
@@ -136,2 +163,27 @@ | ||
// https://fetch.spec.whatwg.org/#dom-request-referrer | ||
get referrer() { | ||
if (this[INTERNALS].referrer === 'no-referrer') { | ||
return ''; | ||
} | ||
if (this[INTERNALS].referrer === 'client') { | ||
return 'about:client'; | ||
} | ||
if (this[INTERNALS].referrer) { | ||
return this[INTERNALS].referrer.toString(); | ||
} | ||
return undefined; | ||
} | ||
get referrerPolicy() { | ||
return this[INTERNALS].referrerPolicy; | ||
} | ||
set referrerPolicy(referrerPolicy) { | ||
this[INTERNALS].referrerPolicy = validateReferrerPolicy(referrerPolicy); | ||
} | ||
/** | ||
@@ -157,3 +209,5 @@ * Clone this request | ||
clone: {enumerable: true}, | ||
signal: {enumerable: true} | ||
signal: {enumerable: true}, | ||
referrer: {enumerable: true}, | ||
referrerPolicy: {enumerable: true} | ||
}); | ||
@@ -194,2 +248,25 @@ | ||
// 4.1. Main fetch, step 2.6 | ||
// > If request's referrer policy is the empty string, then set request's referrer policy to the | ||
// > default referrer policy. | ||
if (request.referrerPolicy === '') { | ||
request.referrerPolicy = DEFAULT_REFERRER_POLICY; | ||
} | ||
// 4.1. Main fetch, step 2.7 | ||
// > If request's referrer is not "no-referrer", set request's referrer to the result of invoking | ||
// > determine request's referrer. | ||
if (request.referrer && request.referrer !== 'no-referrer') { | ||
request[INTERNALS].referrer = determineRequestsReferrer(request); | ||
} else { | ||
request[INTERNALS].referrer = 'no-referrer'; | ||
} | ||
// 4.5. HTTP-network-or-cache fetch, step 6.9 | ||
// > If httpRequest's referrer is a URL, then append `Referer`/httpRequest's referrer, serialized | ||
// > and isomorphic encoded, to httpRequest's header list. | ||
if (request[INTERNALS].referrer instanceof URL) { | ||
headers.set('Referer', request.referrer); | ||
} | ||
// HTTP-network-or-cache fetch step 2.11 | ||
@@ -219,13 +296,8 @@ if (!headers.has('User-Agent')) { | ||
// Manually spread the URL object instead of spread syntax | ||
const requestOptions = { | ||
// Pass the full URL directly to request(), but overwrite the following | ||
// options: | ||
const options = { | ||
// Overwrite search to retain trailing ? (issue #776) | ||
path: parsedURL.pathname + search, | ||
pathname: parsedURL.pathname, | ||
hostname: parsedURL.hostname, | ||
protocol: parsedURL.protocol, | ||
port: parsedURL.port, | ||
hash: parsedURL.hash, | ||
search: parsedURL.search, | ||
query: parsedURL.query, | ||
href: parsedURL.href, | ||
// The following options are not expressed in the URL | ||
method: request.method, | ||
@@ -237,3 +309,6 @@ headers: headers[Symbol.for('nodejs.util.inspect.custom')](), | ||
return requestOptions; | ||
return { | ||
parsedURL, | ||
options | ||
}; | ||
}; |
@@ -32,3 +32,3 @@ /** | ||
if (body !== null && !headers.has('Content-Type')) { | ||
const contentType = extractContentType(body); | ||
const contentType = extractContentType(body, this); | ||
if (contentType) { | ||
@@ -99,3 +99,4 @@ headers.append('Content-Type', contentType); | ||
redirected: this.redirected, | ||
size: this.size | ||
size: this.size, | ||
highWaterMark: this.highWaterMark | ||
}); | ||
@@ -102,0 +103,0 @@ } |
@@ -12,4 +12,3 @@ /** | ||
* ref: https://github.com/node-fetch/node-fetch/issues/296#issuecomment-307598143 | ||
* | ||
* @param {*} obj | ||
* @param {*} object - Object to check for | ||
* @return {boolean} | ||
@@ -33,4 +32,3 @@ */ | ||
* Check if `object` is a W3C `Blob` object (which `File` inherits from) | ||
* | ||
* @param {*} obj | ||
* @param {*} object - Object to check for | ||
* @return {boolean} | ||
@@ -40,2 +38,3 @@ */ | ||
return ( | ||
object && | ||
typeof object === 'object' && | ||
@@ -51,27 +50,4 @@ typeof object.arrayBuffer === 'function' && | ||
/** | ||
* Check if `obj` is a spec-compliant `FormData` object | ||
* | ||
* @param {*} object | ||
* @return {boolean} | ||
*/ | ||
export function isFormData(object) { | ||
return ( | ||
typeof object === 'object' && | ||
typeof object.append === 'function' && | ||
typeof object.set === 'function' && | ||
typeof object.get === 'function' && | ||
typeof object.getAll === 'function' && | ||
typeof object.delete === 'function' && | ||
typeof object.keys === 'function' && | ||
typeof object.values === 'function' && | ||
typeof object.entries === 'function' && | ||
typeof object.constructor === 'function' && | ||
object[NAME] === 'FormData' | ||
); | ||
} | ||
/** | ||
* Check if `obj` is an instance of AbortSignal. | ||
* | ||
* @param {*} obj | ||
* @param {*} object - Object to check for | ||
* @return {boolean} | ||
@@ -87,2 +63,1 @@ */ | ||
}; | ||
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
99698
17
2167
2
3
780
+ Addedformdata-polyfill@^4.0.10
+ Addeddata-uri-to-buffer@4.0.1(transitive)
+ Addedformdata-polyfill@4.0.10(transitive)
- Removeddata-uri-to-buffer@3.0.1(transitive)
Updateddata-uri-to-buffer@^4.0.0