wretch-middlewares
Version:
Middlewares for the wretch library
139 lines • 5.48 kB
JavaScript
/* Defaults */
var defaultSkip = function (url, opts) { return (opts.skipCache || opts.method !== 'GET'); };
var defaultKey = function (url, opts) { return opts.method + '@' + url; };
var defaultClear = function (url, opts) { return false; };
var defaultInvalidate = function (url, opts) { return null; };
var defaultCondition = function (response) { return response.ok; };
/**
* ## Throttling cache middleware
*
* #### A throttling cache which stores and serves server responses for a certain amount of time.
*
* **Options**
*
* - *throttle* `milliseconds`
*
* > the response will be stored for this amount of time before being deleted from the cache.
*
* - *skip* `(url, opts) => boolean`
*
* > If skip returns true, then the request is performed even if present in the cache.
*
* - *key* `(url, opts) => string`
*
* > Returns a key that is used to identify the request.
*
* - *clear* `(url, opts) => boolean`
*
* > Clears the cache if true.
*
* - *invalidate* `(url, opts) => string | RegExp | null`
*
* > Removes url(s) matching the string/RegExp from the cache.
*
* - *condition* `response => boolean`
*
* > If false then the response will not be added to the cache.
*
* - *flagResponseOnCacheHit* `string`
*
* > If set, a Response returned from the cache whill be flagged with a property name equal to this option.
*
*/
export var throttlingCache = function (_a) {
var _b = _a === void 0 ? {} : _a, _c = _b.throttle, throttle = _c === void 0 ? 1000 : _c, _d = _b.skip, skip = _d === void 0 ? defaultSkip : _d, _e = _b.key, key = _e === void 0 ? defaultKey : _e, _f = _b.clear, clear = _f === void 0 ? defaultClear : _f, _g = _b.invalidate, invalidate = _g === void 0 ? defaultInvalidate : _g, _h = _b.condition, condition = _h === void 0 ? defaultCondition : _h, _j = _b.flagResponseOnCacheHit, flagResponseOnCacheHit = _j === void 0 ? '__cached' : _j;
var cache = new Map();
var inflight = new Map();
var throttling = new Set();
var throttleRequest = function (_key) {
if (throttle && !throttling.has(_key)) {
throttling.add(_key);
setTimeout(function () { throttling.delete(_key); }, throttle);
}
};
var middleware = function (next) { return function (url, opts) {
var _key = key(url, opts);
var invalidatePatterns = invalidate(url, opts);
if (invalidatePatterns) {
if (!(invalidatePatterns instanceof Array)) {
invalidatePatterns = [invalidatePatterns];
}
invalidatePatterns.forEach(function (pattern) {
if (typeof pattern === 'string') {
cache.delete(pattern);
}
else if (pattern instanceof RegExp) {
cache.forEach(function (_, key) {
if (pattern.test(key)) {
cache.delete(key);
}
});
}
});
}
if (clear(url, opts)) {
cache.clear();
}
if (skip(url, opts)) {
return next(url, opts);
}
if (throttling.has(_key)) {
// If the cache contains a previous response and we are throttling, serve it and bypass the chain.
if (cache.has(_key)) {
var cachedClone = cache.get(_key).clone();
if (flagResponseOnCacheHit) {
// Flag the Response as cached
Object.defineProperty(cachedClone, flagResponseOnCacheHit, {
value: _key,
enumerable: false
});
}
return Promise.resolve(cachedClone);
// If the request in already in-flight, wait until it is resolved
}
else if (inflight.has(_key)) {
return new Promise(function (resolve, reject) {
inflight.get(_key).push([resolve, reject]);
});
}
}
// Init. the pending promises Map
if (!inflight.has(_key))
inflight.set(_key, []);
// If we are not throttling, activate the throttle for X milliseconds
throttleRequest(_key);
// We call the next middleware in the chain.
return next(url, opts)
.then(function (response) {
// Add a cloned response to the cache
if (condition(response.clone())) {
cache.set(_key, response.clone());
}
// Resolve pending promises
inflight.get(_key).forEach(function (_a) {
var resolve = _a[0];
return resolve(response.clone());
});
// Remove the inflight pending promises
inflight.delete(_key);
// Return the original response
return response;
})
.catch(function (error) {
// Reject pending promises on error
inflight.get(_key).forEach(function (_a) {
var resolve = _a[0], reject = _a[1];
return reject(error);
});
inflight.delete(_key);
throw error;
});
}; };
// Programmatically cache a response
middleware['cache'] = function (key, response) {
throttleRequest(key);
cache.set(key, response);
};
return middleware;
};
//# sourceMappingURL=index.js.map