Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fetch-dedupe

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fetch-dedupe - npm Package Compare versions

Comparing version 4.0.0-beta.3 to 4.0.0-beta.4

191

es/index.js

@@ -1,34 +0,112 @@

import CacheMissError from './cache-miss-error';
import responseCache from './response-cache';
function CacheMissError() {
var err = Error.apply(this, arguments);
err.name = this.name = 'CacheMissError';
this.message = err.message;
this.stack = err.stack;
}
CacheMissError.prototype = Object.create(Error.prototype, {
constructor: {
value: CacheMissError,
writable: true,
configurable: true
}
});
export { responseCache, CacheMissError };
var responseCacheStore = {};
var activeRequests = {};
var accessFn = function accessFn() {
return true;
};
export function getRequestKey() {
var responseCache = {
get: function get(requestKey) {
if (responseCache.has(requestKey)) {
var cacheObject = responseCacheStore[requestKey];
cacheObject.accessCount += 1;
cacheObject.lastAccessedAt = Date.now();
return cacheObject.res;
} else {
return undefined;
}
},
set: function set(requestKey, res) {
responseCacheStore[requestKey] = {
res: res,
createdAt: Date.now(),
accessCount: 0,
lastAccessedAt: null
};
return responseCache;
},
has: function has(requestKey) {
// `undefined` is not a valid JSON key, so we can reliably use
// it to determine if the value exists or not.dfs
return typeof responseCacheStore[requestKey] !== 'undefined';
},
delete: function _delete(requestKey) {
if (!responseCache.has(requestKey)) {
return false;
} else {
delete responseCache[requestKey];
return true;
}
},
clear: function clear() {
responseCacheStore = {};
},
useCachedResponse: function useCachedResponse(fn) {
if (typeof fn === 'function') {
accssFn = fn;
} else {
throw new TypeError('The first argument to `responseCache.useCachedResponse()` must be a function.');
}
}
};
function shouldUseCachedValue(requestKey) {
if (responseCache.has(requestKey)) {
var cacheObject = responseCache.get(requestKey);
var shouldAccess = accessFn();
if (!shouldAccess) {
responseCache.delete(requestKey);
}
return shouldAccess;
} else {
return false;
}
}
var activeRequestsStore = {};
function getRequestKey() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$url = _ref.url,
url = _ref$url === undefined ? '' : _ref$url,
url = _ref$url === void 0 ? '' : _ref$url,
_ref$method = _ref.method,
method = _ref$method === undefined ? '' : _ref$method,
method = _ref$method === void 0 ? '' : _ref$method,
_ref$responseType = _ref.responseType,
responseType = _ref$responseType === undefined ? '' : _ref$responseType,
responseType = _ref$responseType === void 0 ? '' : _ref$responseType,
_ref$body = _ref.body,
body = _ref$body === undefined ? '' : _ref$body;
body = _ref$body === void 0 ? '' : _ref$body;
return [url, method.toUpperCase(), responseType, body].join('||');
}
var activeRequests = {
// Returns `true` if a request with `requestKey` is in flight,
// and `false` otherwise.
isRequestInFlight: function isRequestInFlight(requestKey) {
var handlers = activeRequestsStore[requestKey];
// Returns `true` if a request with `requestKey` is in flight,
// and `false` otherwise.
export function isRequestInFlight(requestKey) {
return Boolean(activeRequests[requestKey]);
}
if (handlers && handlers.length) {
return Boolean(handlers.length);
} else {
return false;
}
},
clear: function clear() {
activeRequestsStore = {};
}
};
// resolves or rejects them.
export function clearActiveRequests() {
activeRequests = {};
}
// This loops through all of the handlers for the request and either
// resolves or rejects them.
function resolveRequest(_ref2) {

@@ -38,5 +116,3 @@ var requestKey = _ref2.requestKey,

err = _ref2.err;
var handlers = activeRequests[requestKey] || [];
var handlers = activeRequestsStore[requestKey] || [];
handlers.forEach(function (handler) {

@@ -48,15 +124,13 @@ if (res) {

}
});
}); // This list of handlers has been, well, handled. So we
// clear the handlers for the next request.
// This list of handlers has been, well, handled. So we
// clear the handlers for the next request.
activeRequests[requestKey] = null;
activeRequestsStore[requestKey] = null;
}
export function fetchDedupe(input) {
function fetchDedupe(input) {
var init = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var dedupeOptions = arguments[2];
var dedupeOptions = arguments.length > 2 ? arguments[2] : undefined;
var opts, initToUse;
var opts = void 0,
initToUse = void 0;
if (dedupeOptions) {

@@ -76,12 +150,10 @@ opts = dedupeOptions;

_opts$responseType = _opts.responseType,
responseType = _opts$responseType === undefined ? '' : _opts$responseType,
responseType = _opts$responseType === void 0 ? '' : _opts$responseType,
_opts$dedupe = _opts.dedupe,
dedupe = _opts$dedupe === undefined ? true : _opts$dedupe,
dedupe = _opts$dedupe === void 0 ? true : _opts$dedupe,
cachePolicy = _opts.cachePolicy;
var method = initToUse.method || input.method || '';
var upperCaseMethod = method.toUpperCase();
var appliedCachePolicy;
var appliedCachePolicy = void 0;
if (cachePolicy) {

@@ -91,6 +163,6 @@ appliedCachePolicy = cachePolicy;

var isReadRequest = upperCaseMethod === 'GET' || upperCaseMethod === 'OPTIONS' || upperCaseMethod === 'HEAD' || upperCaseMethod === '';
appliedCachePolicy = isReadRequest ? 'cache-first' : 'network-only';
} // Build the default request key if one is not passed
appliedCachePolicy = isReadRequest ? 'cache-first' : 'network-only';
}
// Build the default request key if one is not passed
var requestKeyToUse = requestKey || getRequestKey({

@@ -106,6 +178,6 @@ // If `input` is a request, then we use that URL

if (appliedCachePolicy !== 'network-only') {
if (responseCache._useCachedValue(requestKeyToUse)) {
if (shouldUseCachedValue(requestKeyToUse)) {
return Promise.resolve(responseCache.get(requestKeyToUse));
} else if (cachePolicy === 'cache-only') {
var cacheError = new CacheMissError('Response for fetch request not found in cache.');
var cacheError = new CacheMissError("Response for fetch request not found in cache.");
return Promise.reject(cacheError);

@@ -115,9 +187,10 @@ }

var proxyReq = void 0;
var proxyReq;
if (dedupe) {
if (!activeRequests[requestKeyToUse]) {
activeRequests[requestKeyToUse] = [];
if (!activeRequestsStore[requestKeyToUse]) {
activeRequestsStore[requestKeyToUse] = [];
}
var handlers = activeRequests[requestKeyToUse];
var handlers = activeRequestsStore[requestKeyToUse];
var requestInFlight = Boolean(handlers.length);

@@ -129,3 +202,2 @@ var requestHandler = {};

});
handlers.push(requestHandler);

@@ -139,3 +211,4 @@

var request = fetch(input, initToUse).then(function (res) {
var responseTypeToUse = void 0;
var responseTypeToUse;
if (responseType instanceof Function) {

@@ -149,6 +222,7 @@ responseTypeToUse = responseType(res);

responseTypeToUse = 'json';
}
// The response body is a ReadableStream. ReadableStreams can only be read a single
} // The response body is a ReadableStream. ReadableStreams can only be read a single
// time, so we must handle that in a central location, here, before resolving
// the fetch.
return res[responseTypeToUse]().then(function (data) {

@@ -159,3 +233,6 @@ res.data = data;

if (dedupe) {
resolveRequest({ requestKey: requestKeyToUse, res: res });
resolveRequest({
requestKey: requestKeyToUse,
res: res
});
} else {

@@ -168,3 +245,6 @@ return res;

if (dedupe) {
resolveRequest({ requestKey: requestKeyToUse, res: res });
resolveRequest({
requestKey: requestKeyToUse,
res: res
});
} else {

@@ -176,3 +256,6 @@ return res;

if (dedupe) {
resolveRequest({ requestKey: requestKeyToUse, err: err });
resolveRequest({
requestKey: requestKeyToUse,
err: err
});
} else {

@@ -188,2 +271,4 @@ return Promise.reject(err);

}
}
}
export { CacheMissError, activeRequests, fetchDedupe, getRequestKey, responseCache };
'use strict';
exports.__esModule = true;
exports.CacheMissError = exports.responseCache = undefined;
exports.getRequestKey = getRequestKey;
exports.isRequestInFlight = isRequestInFlight;
exports.clearActiveRequests = clearActiveRequests;
exports.fetchDedupe = fetchDedupe;
Object.defineProperty(exports, '__esModule', { value: true });
var _cacheMissError = require('./cache-miss-error');
function CacheMissError() {
var err = Error.apply(this, arguments);
err.name = this.name = 'CacheMissError';
this.message = err.message;
this.stack = err.stack;
}
CacheMissError.prototype = Object.create(Error.prototype, {
constructor: {
value: CacheMissError,
writable: true,
configurable: true
}
});
var _cacheMissError2 = _interopRequireDefault(_cacheMissError);
var responseCacheStore = {};
var _responseCache = require('./response-cache');
var accessFn = function accessFn() {
return true;
};
var _responseCache2 = _interopRequireDefault(_responseCache);
var responseCache = {
get: function get(requestKey) {
if (responseCache.has(requestKey)) {
var cacheObject = responseCacheStore[requestKey];
cacheObject.accessCount += 1;
cacheObject.lastAccessedAt = Date.now();
return cacheObject.res;
} else {
return undefined;
}
},
set: function set(requestKey, res) {
responseCacheStore[requestKey] = {
res: res,
createdAt: Date.now(),
accessCount: 0,
lastAccessedAt: null
};
return responseCache;
},
has: function has(requestKey) {
// `undefined` is not a valid JSON key, so we can reliably use
// it to determine if the value exists or not.dfs
return typeof responseCacheStore[requestKey] !== 'undefined';
},
delete: function _delete(requestKey) {
if (!responseCache.has(requestKey)) {
return false;
} else {
delete responseCache[requestKey];
return true;
}
},
clear: function clear() {
responseCacheStore = {};
},
useCachedResponse: function useCachedResponse(fn) {
if (typeof fn === 'function') {
accssFn = fn;
} else {
throw new TypeError('The first argument to `responseCache.useCachedResponse()` must be a function.');
}
}
};
function shouldUseCachedValue(requestKey) {
if (responseCache.has(requestKey)) {
var cacheObject = responseCache.get(requestKey);
var shouldAccess = accessFn();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
if (!shouldAccess) {
responseCache.delete(requestKey);
}
exports.responseCache = _responseCache2.default;
exports.CacheMissError = _cacheMissError2.default;
return shouldAccess;
} else {
return false;
}
}
var activeRequestsStore = {};
function getRequestKey() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$url = _ref.url,
url = _ref$url === void 0 ? '' : _ref$url,
_ref$method = _ref.method,
method = _ref$method === void 0 ? '' : _ref$method,
_ref$responseType = _ref.responseType,
responseType = _ref$responseType === void 0 ? '' : _ref$responseType,
_ref$body = _ref.body,
body = _ref$body === void 0 ? '' : _ref$body;
let activeRequests = {};
function getRequestKey({
url = '',
method = '',
responseType = '',
body = ''
} = {}) {
return [url, method.toUpperCase(), responseType, body].join('||');
}
var activeRequests = {
// Returns `true` if a request with `requestKey` is in flight,
// and `false` otherwise.
isRequestInFlight: function isRequestInFlight(requestKey) {
var handlers = activeRequestsStore[requestKey];
// Returns `true` if a request with `requestKey` is in flight,
// and `false` otherwise.
function isRequestInFlight(requestKey) {
return Boolean(activeRequests[requestKey]);
}
function clearActiveRequests() {
activeRequests = {};
}
// This loops through all of the handlers for the request and either
if (handlers && handlers.length) {
return Boolean(handlers.length);
} else {
return false;
}
},
clear: function clear() {
activeRequestsStore = {};
}
};
// resolves or rejects them.
function resolveRequest({ requestKey, res, err }) {
const handlers = activeRequests[requestKey] || [];
handlers.forEach(handler => {
function resolveRequest(_ref2) {
var requestKey = _ref2.requestKey,
res = _ref2.res,
err = _ref2.err;
var handlers = activeRequestsStore[requestKey] || [];
handlers.forEach(function (handler) {
if (res) {

@@ -56,11 +127,13 @@ handler.resolve(res);

}
});
}); // This list of handlers has been, well, handled. So we
// clear the handlers for the next request.
// This list of handlers has been, well, handled. So we
// clear the handlers for the next request.
activeRequests[requestKey] = null;
activeRequestsStore[requestKey] = null;
}
function fetchDedupe(input, init = {}, dedupeOptions) {
let opts, initToUse;
function fetchDedupe(input) {
var init = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var dedupeOptions = arguments.length > 2 ? arguments[2] : undefined;
var opts, initToUse;
if (dedupeOptions) {

@@ -77,17 +150,22 @@ opts = dedupeOptions;

const { requestKey, responseType = '', dedupe = true, cachePolicy } = opts;
var _opts = opts,
requestKey = _opts.requestKey,
_opts$responseType = _opts.responseType,
responseType = _opts$responseType === void 0 ? '' : _opts$responseType,
_opts$dedupe = _opts.dedupe,
dedupe = _opts$dedupe === void 0 ? true : _opts$dedupe,
cachePolicy = _opts.cachePolicy;
var method = initToUse.method || input.method || '';
var upperCaseMethod = method.toUpperCase();
var appliedCachePolicy;
const method = initToUse.method || input.method || '';
const upperCaseMethod = method.toUpperCase();
let appliedCachePolicy;
if (cachePolicy) {
appliedCachePolicy = cachePolicy;
} else {
const isReadRequest = upperCaseMethod === 'GET' || upperCaseMethod === 'OPTIONS' || upperCaseMethod === 'HEAD' || upperCaseMethod === '';
var isReadRequest = upperCaseMethod === 'GET' || upperCaseMethod === 'OPTIONS' || upperCaseMethod === 'HEAD' || upperCaseMethod === '';
appliedCachePolicy = isReadRequest ? 'cache-first' : 'network-only';
} // Build the default request key if one is not passed
appliedCachePolicy = isReadRequest ? 'cache-first' : 'network-only';
}
// Build the default request key if one is not passed
let requestKeyToUse = requestKey || getRequestKey({
var requestKeyToUse = requestKey || getRequestKey({
// If `input` is a request, then we use that URL

@@ -102,6 +180,6 @@ url: input.url || input,

if (appliedCachePolicy !== 'network-only') {
if (_responseCache2.default._useCachedValue(requestKeyToUse)) {
return Promise.resolve(_responseCache2.default.get(requestKeyToUse));
if (shouldUseCachedValue(requestKeyToUse)) {
return Promise.resolve(responseCache.get(requestKeyToUse));
} else if (cachePolicy === 'cache-only') {
const cacheError = new _cacheMissError2.default(`Response for fetch request not found in cache.`);
var cacheError = new CacheMissError("Response for fetch request not found in cache.");
return Promise.reject(cacheError);

@@ -111,16 +189,16 @@ }

let proxyReq;
var proxyReq;
if (dedupe) {
if (!activeRequests[requestKeyToUse]) {
activeRequests[requestKeyToUse] = [];
if (!activeRequestsStore[requestKeyToUse]) {
activeRequestsStore[requestKeyToUse] = [];
}
const handlers = activeRequests[requestKeyToUse];
const requestInFlight = Boolean(handlers.length);
const requestHandler = {};
proxyReq = new Promise((resolve, reject) => {
var handlers = activeRequestsStore[requestKeyToUse];
var requestInFlight = Boolean(handlers.length);
var requestHandler = {};
proxyReq = new Promise(function (resolve, reject) {
requestHandler.resolve = resolve;
requestHandler.reject = reject;
});
handlers.push(requestHandler);

@@ -133,4 +211,5 @@

const request = fetch(input, initToUse).then(res => {
let responseTypeToUse;
var request = fetch(input, initToUse).then(function (res) {
var responseTypeToUse;
if (responseType instanceof Function) {

@@ -144,20 +223,27 @@ responseTypeToUse = responseType(res);

responseTypeToUse = 'json';
}
// The response body is a ReadableStream. ReadableStreams can only be read a single
} // The response body is a ReadableStream. ReadableStreams can only be read a single
// time, so we must handle that in a central location, here, before resolving
// the fetch.
return res[responseTypeToUse]().then(data => {
return res[responseTypeToUse]().then(function (data) {
res.data = data;
_responseCache2.default.set(requestKeyToUse, res);
responseCache.set(requestKeyToUse, res);
if (dedupe) {
resolveRequest({ requestKey: requestKeyToUse, res });
resolveRequest({
requestKey: requestKeyToUse,
res: res
});
} else {
return res;
}
}, () => {
}, function () {
res.data = null;
if (dedupe) {
resolveRequest({ requestKey: requestKeyToUse, res });
resolveRequest({
requestKey: requestKeyToUse,
res: res
});
} else {

@@ -167,5 +253,8 @@ return res;

});
}, err => {
}, function (err) {
if (dedupe) {
resolveRequest({ requestKey: requestKeyToUse, err });
resolveRequest({
requestKey: requestKeyToUse,
err: err
});
} else {

@@ -181,2 +270,8 @@ return Promise.reject(err);

}
}
}
exports.CacheMissError = CacheMissError;
exports.activeRequests = activeRequests;
exports.fetchDedupe = fetchDedupe;
exports.getRequestKey = getRequestKey;
exports.responseCache = responseCache;
{
"name": "fetch-dedupe",
"version": "4.0.0-beta.3",
"version": "4.0.0-beta.4",
"description": "A thin wrapper around fetch that prevents duplicate requests.",

@@ -9,10 +9,6 @@ "main": "lib/index.js",

"clean": "rimraf dist es tmp lib",
"test": "jest",
"test": "NODE_ENV=test jest",
"test:watch": "jest --watch",
"prepublish": "in-publish && npm run build || not-in-publish",
"build": "npm run clean && npm run build:umd && npm run build:umd:min && npm run build:es && npm run build:commonjs",
"build:commonjs": "cross-env BABEL_ENV=commonjs babel src --out-dir lib",
"build:es": "cross-env BABEL_ENV=es babel src --out-dir es",
"build:umd": "cross-env NODE_ENV=development BABEL_ENV=build rollup -c -i src/index.js -o dist/fetch-dedupe.js",
"build:umd:min": "cross-env NODE_ENV=production BABEL_ENV=buildProd rollup -c -i src/index.js -o dist/fetch-dedupe.min.js"
"build": "rollup -c"
},

@@ -52,8 +48,6 @@ "repository": {

"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-jest": "^22.1.0",
"babel-plugin-external-helpers": "^6.22.0",
"babel-preset-env": "^1.6.1",
"babel-preset-stage-3": "^6.24.1",
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.2.3",
"@rollup/plugin-replace": "^2.2.1",
"babel-jest": "^24.9.0",
"cross-env": "^5.1.3",

@@ -63,10 +57,10 @@ "fetch-mock": "^6.0.0",

"isomorphic-fetch": "^2.2.1",
"jest": "^23.6.0",
"jest": "^24.9.0",
"rimraf": "^2.6.2",
"rollup": "^0.45.1",
"rollup-plugin-babel": "^2.7.1",
"rollup-plugin-commonjs": "^8.2.6",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-plugin-uglify": "^2.0.1"
"rollup": "^1.0.0",
"rollup-plugin-babel": "^4.2.0",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-uglify": "^6.0.3"
}
}

@@ -13,3 +13,3 @@ # Fetch Dedupe

### Motivation
## Motivation

@@ -25,3 +25,3 @@ Making a single HTTP request is not difficult to do in JavaScript. However, complex web applications often make many

### Installation
## Installation

@@ -40,3 +40,3 @@ Install using [npm](https://www.npmjs.com):

### Getting Started
## Getting Started

@@ -67,3 +67,3 @@ This example demonstrates using Fetch Dedupe with the

#### Important: Read this!
### Important: Read this!

@@ -92,3 +92,3 @@ When using `fetch`, you typically read the body yourself by calling, say, `.json()` on the

### API
## API

@@ -105,5 +105,6 @@ This library exports the following methods:

- `.clear()`
- `.setCacheCheck()`
- `isRequestInFlight()`
- `clearActiveRequests()`
- `.useCachedResponse()`
- `activeRequests`
- `isRequestInFlight()`
- `clear()`

@@ -233,13 +234,19 @@ ##### `fetchDedupe( input [, init] [, dedupeOptions] )`

##### `responseCache.setCacheCheck( fn )`
##### `responseCache.useCachedResponse( fn )`
By default, fetch-dedupe caches responses indefinitely. You can customize this behavior by calling this
method a single time when your app is initialized.
By default, fetch-dedupe caches responses indefinitely. You can customize this behavior using this method.
This function accepts a single argument, `fn,` which is a function. This function will be called any time
that a request is made that has a cached response. It receives two arguments: `cachedResponse, timestamp`. Return
`true` to use the cached response, or `false` to remove the value from the cache and make a network request
This method accepts a single argument, `fn,` which is a function. `fn` will be called any time
that a request is made that has a cached response. It's called with a single argument, `cacheObject`, an object
with the following properties:
- `res`: The cached response object.
- `createdAt`: A timestamp (in milliseconds) when the value was added to the cache.
- `lastAccessedAt`: A timestamp (in milliseconds) when the value was last read from the cache.
- `accessCount`: An integer representing the number of times that the value has been read from the cache.
Return `true` to use the cached response, or `false` to remove the value from the cache and make a network request
instead.
For instance, to invalidate cached responses after 10 seconds:
For instance, to invalidate cached responses that are more than 10 minutes old:

@@ -254,9 +261,9 @@ ```js

responseCache.setCacheCheck((cachedResponse, timestamp) => {
const currentTimestamp = Number(new Date());
return currentTimestamp - timestamp <= TEN_MINUTES;
responseCache.useCachedResponse(({ createdAt }) => {
const currentTimestamp = Date.now();
return currentTimestamp - createdAt <= TEN_MINUTES;
});
```
##### `isRequestInFlight( requestKey )`
##### `activeRequests.isRequestInFlight( requestKey )`

@@ -268,3 +275,3 @@ Pass in a `requestKey` to see if there's already a request in flight for it. This

```js
import { isRequestInFlight, getRequestKey } from 'fetch-dedupe';
import { activeRequests, getRequestKey } from 'fetch-dedupe';

@@ -277,19 +284,16 @@ const key = getRequestKey({

// Is there already a request in flight for this?
const readingBooksAlready = isRequestInFlight(key);
const readingBooksAlready = activeRequests(key);
```
> Now: We **strongly** recommend that you manually pass in `requestKey` to `fetchDedupe`
if you intend to use this method. In other words, _do not_ rely on being able to
reliably reproduce the request key that is created when a `requestKey` is not passed in.
##### `activeRequests.clear()`
##### `clearActiveRequests()`
Removes all of the tracked in-flight requests. In-flight requests are not cancelled: calling this
method only ensures that subsequent identical requests are not deduped.
Removes all of the tracked in-flight requests.
> Note: you typically should not need to use this method.
> Note: it is very unlikely that you would ever need to call this method.
## Guides
### Guides
### Caching
##### Caching
Any time tbat a response from the server is received, it will be cached using the request's request key.

@@ -319,5 +323,5 @@ Subsequent requests are matched with existing cached server responses using their request key.

### FAQ & Troubleshooting
## FAQ & Troubleshooting
##### Why is `response.data` set to `null` sometimes?
#### Why is `response.data` set to `null` sometimes?

@@ -335,3 +339,3 @@ If the response cannot be parsed as the `responseType`, then it will be set as `null`.

##### Why is `responseType` even an option?
#### Why is `responseType` even an option?

@@ -347,3 +351,3 @@ The argument that is returned to you in the `.then` callback of a call to `fetch()` is a

##### What request body types are supported?
#### What request body types are supported?

@@ -353,3 +357,3 @@ Just strings for now, which should work for the majority of APIs. Support for other body types

##### Is the data duplicated?
#### Is the data duplicated?

@@ -363,3 +367,3 @@ Although you receive a new `Response` object with every call to `fetch-dedupe`, the body will be read,

### Requirements
## Requirements

@@ -372,12 +376,4 @@ - a global [fetch()](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch) method. If your browser does not support it, then we

### Implementors
## Acknowledgements
These are projects that build abstractions around HTTP requests using Fetch Dedupe under the hood.
- [React Request](https://github.com/jamesplease/react-request)
Are you using it on a project? Add it to this list by opening a Pull Request
### Acknowledgements
[Apollo](https://www.apollographql.com/) inspired me to write this library.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc