fetch-har
Advanced tools
Comparing version 9.0.0 to 10.0.0
@@ -16,8 +16,7 @@ /// <reference types="node" /> | ||
export interface FetchHAROptions { | ||
userAgent?: string; | ||
files?: Record<string, Blob | Buffer>; | ||
multipartEncoder?: any; | ||
init?: RequestInitWithDuplex; | ||
userAgent?: string; | ||
} | ||
export default function fetchHAR(har: Har, opts?: FetchHAROptions): Promise<Response>; | ||
export {}; |
@@ -18,7 +18,7 @@ "use strict"; | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies | ||
globalThis.Blob = require('formdata-node').Blob; | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
globalThis.Blob = require('node:buffer').Blob; | ||
} | ||
catch (e) { | ||
throw new Error('Since you do not have the Blob API available in this environment you must install the optional `formdata-node` dependency.'); | ||
throw new Error('The Blob API is required for this library. https://developer.mozilla.org/en-US/docs/Web/API/Blob'); | ||
} | ||
@@ -28,18 +28,11 @@ } | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies | ||
globalThis.File = require('formdata-node').File; | ||
// Node's native `fetch` implementation unfortunately does not make this API global so we need | ||
// to pull it in if we don't have it. | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
globalThis.File = require('undici').File; | ||
} | ||
catch (e) { | ||
throw new Error('Since you do not have the File API available in this environment you must install the optional `formdata-node` dependency.'); | ||
throw new Error('The File API is required for this library. https://developer.mozilla.org/en-US/docs/Web/API/File'); | ||
} | ||
} | ||
if (!globalThis.FormData) { | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies | ||
globalThis.FormData = require('formdata-node').FormData; | ||
} | ||
catch (e) { | ||
throw new Error('Since you do not have the FormData API available in this environment you must install the optional `formdata-node` dependency.'); | ||
} | ||
} | ||
function isBrowser() { | ||
@@ -63,26 +56,2 @@ return typeof window !== 'undefined' && typeof document !== 'undefined'; | ||
} | ||
/** | ||
* @license MIT | ||
* @see {@link https://github.com/octet-stream/form-data-encoder/blob/master/lib/util/isFunction.ts} | ||
*/ | ||
function isFunction(value) { | ||
return typeof value === 'function'; | ||
} | ||
/** | ||
* We're using this library in here instead of loading it from `form-data-encoder` because that | ||
* uses lookbehind regex in its main encoder that Safari doesn't support so it throws a fatal page | ||
* exception. | ||
* | ||
* @license MIT | ||
* @see {@link https://github.com/octet-stream/form-data-encoder/blob/master/lib/util/isFormData.ts} | ||
*/ | ||
function isFormData(value) { | ||
return (value && | ||
isFunction(value.constructor) && | ||
value[Symbol.toStringTag] === 'FormData' && | ||
isFunction(value.append) && | ||
isFunction(value.getAll) && | ||
isFunction(value.entries) && | ||
isFunction(value[Symbol.iterator])); | ||
} | ||
function getFileFromSuppliedFiles(filename, files) { | ||
@@ -188,27 +157,2 @@ if (filename in files) { | ||
var form_1 = new FormData(); | ||
if (!isFormData(form_1)) { | ||
/** | ||
* The `form-data` NPM module returns one of two things: a native `FormData` API or its | ||
* own polyfill. Unfortunately this polyfill does not support the full API of the native | ||
* FormData object so when you load `form-data` within a browser environment you'll | ||
* have two major differences in API: | ||
* | ||
* - The `.append()` API in `form-data` requires that the third argument is an object | ||
* containing various, undocumented, options. In the browser, `.append()`'s third | ||
* argument should only be present when the second is a `Blob` or `USVString`, and | ||
* when it is present, it should be a filename string. | ||
* - `form-data` does not expose an `.entries()` API, so the only way to retrieve data | ||
* out of it for construction of boundary-separated payload content is to use its | ||
* `.pipe()` API. Since the browser doesn't have this API, you'll be unable to | ||
* retrieve data out of it. | ||
* | ||
* Now since the native `FormData` API is iterable, and has the `.entries()` iterator, | ||
* we can easily detect if we have a native copy of the FormData API. It's for all of | ||
* these reasons that we're opting to hard crash here because supporting this | ||
* non-compliant API is more trouble than its worth. | ||
* | ||
* @see {@link https://github.com/form-data/form-data/issues/124} | ||
*/ | ||
throw new Error("We've detected you're using a non-spec compliant FormData library. We recommend polyfilling FormData with https://npm.im/formdata-node"); | ||
} | ||
request.postData.params.forEach(function (param) { | ||
@@ -252,23 +196,3 @@ if ('fileName' in param) { | ||
}); | ||
/** | ||
* If a the `fetch` polyfill that's being used here doesn't have spec-compliant handling | ||
* for the `FormData` API (like `node-fetch@2`), then you should pass in a handler (like | ||
* the `form-data-encoder` library) to transform its contents into something that can be | ||
* used with the `Request` object. | ||
* | ||
* @see {@link https://www.npmjs.com/package/formdata-node} | ||
*/ | ||
if (opts.multipartEncoder) { | ||
// eslint-disable-next-line new-cap | ||
var encoder_1 = new opts.multipartEncoder(form_1); | ||
Object.keys(encoder_1.headers).forEach(function (header) { | ||
headers.set(header, encoder_1.headers[header]); | ||
}); | ||
// @ts-expect-error "Property 'from' does not exist on type 'typeof Readable'." but it does! | ||
options.body = readable_stream_1.Readable.from(encoder_1); | ||
shouldSetDuplex = true; | ||
} | ||
else { | ||
options.body = form_1; | ||
} | ||
options.body = form_1; | ||
break; | ||
@@ -275,0 +199,0 @@ default: |
@@ -1,6 +0,1 @@ | ||
require('isomorphic-fetch'); | ||
// If executing from an environment that doesn't normally provide `fetch()` | ||
// we'll automatically polyfill in the `Blob`, `File`, and `FormData` APIs | ||
// with the optional `formdata-node` package (provided you've installed it). | ||
const fetchHAR = require('.').default; | ||
@@ -7,0 +2,0 @@ |
{ | ||
"name": "fetch-har", | ||
"version": "9.0.0", | ||
"version": "10.0.0", | ||
"description": "Make a fetch request from a HAR definition", | ||
@@ -8,3 +8,3 @@ "main": "dist/index.js", | ||
"engines": { | ||
"node": ">=16" | ||
"node": ">=18" | ||
}, | ||
@@ -18,7 +18,4 @@ "scripts": { | ||
"prettier": "prettier --list-different --write \"./**/**.{js,ts}\"", | ||
"release": "npx conventional-changelog-cli -i CHANGELOG.md -s", | ||
"test:browser": "karma start --single-run", | ||
"test:browser:chrome": "karma start --browsers=Chrome --single-run=false", | ||
"test:browser:debug": "karma start --single-run=false", | ||
"test": "nyc mocha \"test/**/*.test.ts\"" | ||
"test": "vitest --coverage", | ||
"test:browser": "vitest --browser.name=chrome --browser.headless" | ||
}, | ||
@@ -36,40 +33,26 @@ "repository": { | ||
"@readme/data-urls": "^1.0.1", | ||
"@types/har-format": "^1.2.8", | ||
"readable-stream": "^3.6.0" | ||
"@types/har-format": "^1.2.12", | ||
"readable-stream": "^3.6.0", | ||
"undici": "^5.24.0" | ||
}, | ||
"optionalDependencies": { | ||
"formdata-node": "^4.3.2" | ||
}, | ||
"devDependencies": { | ||
"@jsdevtools/host-environment": "^2.1.2", | ||
"@jsdevtools/karma-config": "^3.1.7", | ||
"@readme/eslint-config": "^10.5.3", | ||
"@types/chai": "^4.3.1", | ||
"@readme/eslint-config": "^12.2.0", | ||
"@types/express": "^4.17.17", | ||
"@types/mocha": "^10.0.0", | ||
"@types/multer": "^1.4.7", | ||
"@types/node": "^20.2.5", | ||
"@types/node": "^20.5.7", | ||
"@types/readable-stream": "^2.3.15", | ||
"chai": "^4.3.4", | ||
"@vitest/browser": "^0.34.3", | ||
"@vitest/coverage-v8": "^0.34.3", | ||
"datauri": "^4.1.0", | ||
"eslint": "^8.41.0", | ||
"eslint": "^8.48.0", | ||
"express": "^4.18.1", | ||
"fetch-mock": "^9.11.0", | ||
"form-data": "^4.0.0", | ||
"form-data-encoder": "^1.7.1", | ||
"formdata-node": "^4.3.2", | ||
"har-examples": "^3.1.1", | ||
"isomorphic-fetch": "^3.0.0", | ||
"mocha": "^10.2.0", | ||
"multer": "^1.4.5-lts.1", | ||
"nock": "^13.3.0", | ||
"node-fetch": "^2.6.0", | ||
"nyc": "^15.1.0", | ||
"prettier": "^2.8.7", | ||
"prettier": "^3.0.3", | ||
"temp-dir": "^2.0.0", | ||
"ts-loader": "^8.4.0", | ||
"ts-node": "^10.7.0", | ||
"typescript": "^5.0.4", | ||
"undici": "^5.22.1", | ||
"webpack": "^4.46.0" | ||
"typescript": "^5.2.2", | ||
"vitest": "^0.34.3", | ||
"webdriverio": "^8.15.10" | ||
}, | ||
@@ -76,0 +59,0 @@ "browserslist": [ |
@@ -12,6 +12,6 @@ # fetch-har | ||
- Supports Node 14+ (including the native `fetch` implementation in Node 18!). | ||
- Supports Node 18+ | ||
- Natively works in all browsers that support [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) without having to use any polyfils. | ||
- [Tested](https://github.com/readmeio/fetch-har/actions) across Chrome, Safari, Firefox on Mac, Windows, and Linux. | ||
- Requests can be mocked with [nock](https://npm.im/nock) or [fetch-mock](https://npm.im/fetch-mock). | ||
- Requests can be mocked with [fetch-mock](https://npm.im/fetch-mock) or [msw](https://npm.im/msw). | ||
@@ -26,10 +26,5 @@ ## Installation | ||
```js | ||
require('isomorphic-fetch'); | ||
import fetchHAR from 'fetch-har'; | ||
// const fetchHAR = require('fetch-har').default; | ||
// If executing from an environment that doesn't normally provide `fetch()` we'll automatically | ||
// polyfill in the `Blob`, `File`, and `FormData` APIs with the optional `formdata-node` package | ||
// (provided you've installed it). | ||
const fetchHAR = require('fetch-har').default; | ||
// import fetchHAR from 'fetch-har'); // Or if you're in an ESM codebase. | ||
const har = { | ||
@@ -72,8 +67,2 @@ log: { | ||
### API | ||
If you are executing `fetch-har` in a browser environment that supports the [FormData API](https://developer.mozilla.org/en-US/docs/Web/API/FormData) then you don't need to do anything. If you arent, however, you'll need to polyfill it. | ||
Unfortunately the most popular NPM package [form-data](https://npm.im/form-data) ships with a [non-spec compliant API](https://github.com/form-data/form-data/issues/124), and for this we don't recommend you use it, as if you use `fetch-har` to upload files it may not work. | ||
Though we recommend either [formdata-node](https://npm.im/formdata-node) or [formdata-polyfill](https://npm.im/formdata-polyfill) we prefer [formdata-node](https://npm.im/formdata-node) right now as it's CJS-compatible. | ||
#### Options | ||
@@ -99,17 +88,2 @@ ##### userAgent | ||
##### multipartEncoder | ||
> ❗ If you are using `fetch-har` in Node you may need this option to execute `multipart/form-data` requests! | ||
If you are running `fetch-har` within a Node environment and you're using `node-fetch@2`, or another `fetch` polyfill that does not support a spec-compliant `FormData` API, you will need to specify an encoder that will transform your `FormData` object into something that can be used with [Request.body](https://developer.mozilla.org/en-US/docs/Web/API/Request/body). | ||
We recommend [form-data-encoder](https://npm.im/form-data-encoder). | ||
```js | ||
const { FormDataEncoder } = require('form-data-encoder'); | ||
await fetchHAR(har, { multipartEncoder: FormDataEncoder }); | ||
``` | ||
You do **not**, and shouldn't, need to use this option in browser environments. | ||
##### init | ||
@@ -116,0 +90,0 @@ This optional argument lets you supply any option that's available to supply to the [Request constructor](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request). |
117
src/index.ts
@@ -9,8 +9,6 @@ import type { DataURL as npmDataURL } from '@readme/data-urls'; | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies | ||
globalThis.Blob = require('formdata-node').Blob; | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
globalThis.Blob = require('node:buffer').Blob; | ||
} catch (e) { | ||
throw new Error( | ||
'Since you do not have the Blob API available in this environment you must install the optional `formdata-node` dependency.' | ||
); | ||
throw new Error('The Blob API is required for this library. https://developer.mozilla.org/en-US/docs/Web/API/Blob'); | ||
} | ||
@@ -21,22 +19,11 @@ } | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies | ||
globalThis.File = require('formdata-node').File; | ||
// Node's native `fetch` implementation unfortunately does not make this API global so we need | ||
// to pull it in if we don't have it. | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
globalThis.File = require('undici').File; | ||
} catch (e) { | ||
throw new Error( | ||
'Since you do not have the File API available in this environment you must install the optional `formdata-node` dependency.' | ||
); | ||
throw new Error('The File API is required for this library. https://developer.mozilla.org/en-US/docs/Web/API/File'); | ||
} | ||
} | ||
if (!globalThis.FormData) { | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies | ||
globalThis.FormData = require('formdata-node').FormData; | ||
} catch (e) { | ||
throw new Error( | ||
'Since you do not have the FormData API available in this environment you must install the optional `formdata-node` dependency.' | ||
); | ||
} | ||
} | ||
interface RequestInitWithDuplex extends RequestInit { | ||
@@ -56,6 +43,5 @@ /** | ||
export interface FetchHAROptions { | ||
userAgent?: string; | ||
files?: Record<string, Blob | Buffer>; | ||
multipartEncoder?: any; // form-data-encoder | ||
init?: RequestInitWithDuplex; | ||
userAgent?: string; | ||
} | ||
@@ -91,30 +77,2 @@ | ||
/** | ||
* @license MIT | ||
* @see {@link https://github.com/octet-stream/form-data-encoder/blob/master/lib/util/isFunction.ts} | ||
*/ | ||
function isFunction(value: any) { | ||
return typeof value === 'function'; | ||
} | ||
/** | ||
* We're using this library in here instead of loading it from `form-data-encoder` because that | ||
* uses lookbehind regex in its main encoder that Safari doesn't support so it throws a fatal page | ||
* exception. | ||
* | ||
* @license MIT | ||
* @see {@link https://github.com/octet-stream/form-data-encoder/blob/master/lib/util/isFormData.ts} | ||
*/ | ||
function isFormData(value: any) { | ||
return ( | ||
value && | ||
isFunction(value.constructor) && | ||
value[Symbol.toStringTag] === 'FormData' && | ||
isFunction(value.append) && | ||
isFunction(value.getAll) && | ||
isFunction(value.entries) && | ||
isFunction(value[Symbol.iterator]) | ||
); | ||
} | ||
function getFileFromSuppliedFiles(filename: string, files: FetchHAROptions['files']) { | ||
@@ -187,3 +145,3 @@ if (filename in files) { | ||
.map(cookie => `${encodeURIComponent(cookie.name)}=${encodeURIComponent(cookie.value)}`) | ||
.join('; ') | ||
.join('; '), | ||
); | ||
@@ -235,29 +193,2 @@ } | ||
const form = new FormData(); | ||
if (!isFormData(form)) { | ||
/** | ||
* The `form-data` NPM module returns one of two things: a native `FormData` API or its | ||
* own polyfill. Unfortunately this polyfill does not support the full API of the native | ||
* FormData object so when you load `form-data` within a browser environment you'll | ||
* have two major differences in API: | ||
* | ||
* - The `.append()` API in `form-data` requires that the third argument is an object | ||
* containing various, undocumented, options. In the browser, `.append()`'s third | ||
* argument should only be present when the second is a `Blob` or `USVString`, and | ||
* when it is present, it should be a filename string. | ||
* - `form-data` does not expose an `.entries()` API, so the only way to retrieve data | ||
* out of it for construction of boundary-separated payload content is to use its | ||
* `.pipe()` API. Since the browser doesn't have this API, you'll be unable to | ||
* retrieve data out of it. | ||
* | ||
* Now since the native `FormData` API is iterable, and has the `.entries()` iterator, | ||
* we can easily detect if we have a native copy of the FormData API. It's for all of | ||
* these reasons that we're opting to hard crash here because supporting this | ||
* non-compliant API is more trouble than its worth. | ||
* | ||
* @see {@link https://github.com/form-data/form-data/issues/124} | ||
*/ | ||
throw new Error( | ||
"We've detected you're using a non-spec compliant FormData library. We recommend polyfilling FormData with https://npm.im/formdata-node" | ||
); | ||
} | ||
@@ -277,3 +208,3 @@ request.postData.params.forEach(param => { | ||
}), | ||
param.fileName | ||
param.fileName, | ||
); | ||
@@ -288,3 +219,3 @@ | ||
throw new TypeError( | ||
'An unknown object has been supplied into the `files` config for use. We only support instances of the File API and Node Buffer objects.' | ||
'An unknown object has been supplied into the `files` config for use. We only support instances of the File API and Node Buffer objects.', | ||
); | ||
@@ -310,3 +241,3 @@ } | ||
throw new Error( | ||
"The supplied HAR has a postData parameter with `fileName`, but neither `value` content within the HAR or any file buffers were supplied with the `files` option. Since this library doesn't have access to the filesystem, it can't fetch that file." | ||
"The supplied HAR has a postData parameter with `fileName`, but neither `value` content within the HAR or any file buffers were supplied with the `files` option. Since this library doesn't have access to the filesystem, it can't fetch that file.", | ||
); | ||
@@ -318,23 +249,3 @@ } | ||
/** | ||
* If a the `fetch` polyfill that's being used here doesn't have spec-compliant handling | ||
* for the `FormData` API (like `node-fetch@2`), then you should pass in a handler (like | ||
* the `form-data-encoder` library) to transform its contents into something that can be | ||
* used with the `Request` object. | ||
* | ||
* @see {@link https://www.npmjs.com/package/formdata-node} | ||
*/ | ||
if (opts.multipartEncoder) { | ||
// eslint-disable-next-line new-cap | ||
const encoder = new opts.multipartEncoder(form); | ||
Object.keys(encoder.headers).forEach(header => { | ||
headers.set(header, encoder.headers[header]); | ||
}); | ||
// @ts-expect-error "Property 'from' does not exist on type 'typeof Readable'." but it does! | ||
options.body = Readable.from(encoder); | ||
shouldSetDuplex = true; | ||
} else { | ||
options.body = form; | ||
} | ||
options.body = form; | ||
break; | ||
@@ -341,0 +252,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
19
12
96485
660
99
+ Addedundici@^5.24.0
+ Added@fastify/busboy@2.1.1(transitive)
+ Addedundici@5.28.4(transitive)
- Removedformdata-node@4.4.1(transitive)
- Removednode-domexception@1.0.0(transitive)
- Removedweb-streams-polyfill@4.0.0-beta.3(transitive)
Updated@types/har-format@^1.2.12