New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

flashheart

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flashheart - npm Package Compare versions

Comparing version 2.7.1 to 2.8.0

68

lib/cachingClient.js

@@ -8,2 +8,3 @@ var _ = require('lodash');

this.cache = opts.cache;
this.staleIfError = opts.staleIfError;
this.doNotVary = opts.doNotVary || [];

@@ -16,3 +17,6 @@ }

if (cacheControl) {
return !cacheControl['no-cache'] && !cacheControl.private && cacheControl['max-age'] > 0;
const hasMaxAge = cacheControl['max-age'] > 0;
const hasStaleIfError = cacheControl['stale-if-error'] > 0;
return !cacheControl['no-cache'] && !cacheControl.private && (hasMaxAge || hasStaleIfError);
}

@@ -23,13 +27,20 @@

function getMaxAge(res) {
var maxAge = -1;
function getCacheTime(res, directive) {
var cacheControl = getCacheControl(res);
if (cacheControl) {
maxAge = (cacheControl['max-age'] || 0) * 1000;
return (cacheControl[directive] || 0) * 1000;
}
return maxAge;
return -1;
}
function getMaxAge(res) {
return getCacheTime(res, 'max-age');
}
function getStaleIfError(res) {
return getCacheTime(res, 'stale-if-error');
}
function getCacheControl(res) {

@@ -66,2 +77,6 @@ var cacheControl = res.headers['cache-control'];

function createStaleKeyObject(url, opts, doNotVary) {
return _.extend({}, createKeyObject(url, opts, doNotVary), { stale: true });
}
CachingClient.prototype.get = function (url, opts, cb) {

@@ -80,5 +95,7 @@ if (typeof opts === 'function') {

var maxAge;
var staleIfError;
if (!servedFromCache && res && isCacheable(res)) {
maxAge = getMaxAge(res);
staleIfError = getStaleIfError(res);
cachedObject = {};

@@ -101,3 +118,9 @@

cache.set(createKeyObject(url, opts, doNotVary), cachedObject, maxAge, client._handleCacheError.bind(client));
if (maxAge) {
cache.set(createKeyObject(url, opts, doNotVary), cachedObject, maxAge, client._handleCacheError.bind(client));
}
if (client.staleIfError && staleIfError) {
cache.set(createStaleKeyObject(url, opts, doNotVary), cachedObject, staleIfError, client._handleCacheError.bind(client));
}
}

@@ -109,2 +132,12 @@

function createErrorFromCache(cachedError) {
var err = new Error(cachedError.message);
err.statusCode = cachedError.statusCode;
err.body = cachedError.body;
err.headers = cachedError.headers;
return err;
}
CachingClient.prototype._getCachedOrFetch = function (url, opts, cb) {

@@ -120,3 +153,2 @@ var client = this;

var cacheHit = cached && cached.item && (cached.item.body || cached.item.error);
var cachedError;

@@ -127,7 +159,3 @@ if (cacheHit) {

if (cached.item.error) {
cachedError = cached.item.error;
err = new Error(cachedError.message);
err.statusCode = cachedError.statusCode;
err.body = cachedError.body;
err.headers = cachedError.headers;
err = createErrorFromCache(cached.item.error);
}

@@ -140,3 +168,17 @@

delegate.getWithResponse(url, opts, cb);
delegate.getWithResponse(url, opts, function (err, body, res) {
if (err && client.staleIfError) {
var originalErr = err;
return cache.get(createStaleKeyObject(url, opts, doNotVary), function (err, cached) {
if (err) client._handleCacheError(err);
if (!cached) return cb(originalErr, body, res);
if (delegate.stats) delegate.stats.increment(delegate.name + '.cache.stale');
cb(err, cached.item.body, cached.item.response, true);
});
}
cb(err, body, res);
});
});

@@ -143,0 +185,0 @@ };

2

package.json
{
"name": "flashheart",
"version": "2.7.1",
"version": "2.8.0",
"description": "A fully-featured REST client built for ease-of-use and resilience",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -90,2 +90,17 @@ # flashheart

Optionally, you can enable `staleIfError` which will start listening to the `stale-if-error` directive as well. This stores the response for the duration of the `stale-if-error` directive as well as the `max-age` and will try to retrieve them in this order:
* `max-age` stored version
* fresh version
* `stale-if-error` version
This is enabled simply by passing in the `staleIfError` parameter to `createClient`:
```js
const client = require('flashheart').createClient({
cache: storage,
staleIfError: true
});
```
The cache varies on _all_ request options (and therefore, headers) by default. If you don't want to vary on a particular header, use the `doNotVary` option:

@@ -92,0 +107,0 @@

@@ -19,3 +19,3 @@ var async = require('async');

headers: {
'cache-control': 'max-age=60',
'cache-control': 'max-age=60,stale-if-error=7200',
'content-type': 'application/json'

@@ -30,6 +30,7 @@ },

var client;
var staleClient;
var catbox;
var headers = {
'cache-control': 'max-age=60'
'cache-control': 'max-age=60,stale-if-error=7200'
};

@@ -42,2 +43,8 @@

var expectedStaleKey = {
segment: 'flashheart:' + require('../package').version,
id: url,
stale: true
};
beforeEach(function () {

@@ -66,2 +73,9 @@ nock.cleanAll();

});
staleClient = Client.createClient({
cache: catbox,
stats: stats,
logger: logger,
retries: 0,
staleIfError: true
});
});

@@ -80,2 +94,13 @@

it('caches the stale value if stale-if-error is set', function (done) {
staleClient.get(url, function (err) {
assert.ifError(err);
sinon.assert.calledWith(catbox.set, expectedStaleKey, {
body: responseBody,
response: expectedCachedResponse
}, 7200000);
done();
});
});
it('returns the response from the cache if it exists', function (done) {

@@ -136,2 +161,70 @@ var cachedResponseBody = {

it('attempts to serve stale if error received and staleIfError is enabled', function (done) {
var cachedResponseBody = {
foo: 'baz'
};
var errorResponseCode = 503;
var errorResponseBody = {
error: 'An error'
};
var errorHeaders = {
'cache-control': 'max-age=5',
'content-type': 'application/json',
'www-authenticate': 'Bearer realm="/"'
};
catbox.get.withArgs(expectedStaleKey).yields(null, {
item: {
body: cachedResponseBody,
response: expectedCachedResponse
}
});
nock.cleanAll();
api.get('/').reply(errorResponseCode, errorResponseBody, errorHeaders);
staleClient.get(url, function (err, body, res) {
assert.ifError(err);
assert.deepEqual(body, cachedResponseBody);
assert.deepEqual(res, expectedCachedResponse);
sinon.assert.notCalled(catbox.set);
sinon.assert.calledTwice(catbox.get);
done();
});
});
it('does not store stale cache if staleIfError is not enabled', function (done) {
client.get(url, function (err) {
assert.ifError(err);
sinon.assert.calledOnce(catbox.set);
sinon.assert.calledWith(catbox.set, expectedKey, {
body: responseBody,
response: expectedCachedResponse
}, 60000);
done();
});
});
it('does not read stale cache if staleIfError is not enabled', function (done) {
var errorResponseCode = 503;
var errorResponseBody = {
error: 'An error'
};
var errorHeaders = {
'cache-control': 'max-age=5',
'content-type': 'application/json',
'www-authenticate': 'Bearer realm="/"'
};
nock.cleanAll();
api.get('/').reply(errorResponseCode, errorResponseBody, errorHeaders);
client.get(url, function (err) {
assert.ok(err);
assert.equal(err.statusCode, 503);
sinon.assert.calledOnce(catbox.get);
sinon.assert.calledWith(catbox.get, expectedKey);
done();
});
});
it('returns an error from the cache if it exists', function (done) {

@@ -292,2 +385,28 @@ var errorResponseBody = {

it('stores content for stale duration if staleIfError enabled and max-age value is zero', function (done) {
var headers = {
'cache-control': 'max-age=0,stale-if-error=7200'
};
var expectedCachedResponse = {
statusCode: 200,
headers: {
'cache-control': 'max-age=0,stale-if-error=7200',
'content-type': 'application/json'
},
elapsedTime: nockElapsedTime
};
nock.cleanAll();
api.get('/').reply(200, responseBody, headers);
staleClient.get(url, function (err) {
assert.ifError(err);
sinon.assert.calledOnce(catbox.set);
sinon.assert.calledWith(catbox.set, expectedStaleKey, {
body: responseBody,
response: expectedCachedResponse
}, 7200000);
done();
});
});
it('does not cache the response if the max-age value is invalid', function (done) {

@@ -307,2 +426,28 @@ var headers = {

it('does not store a stale value if stale-if-error missing', function (done) {
var headers = {
'cache-control': 'max-age=60'
};
var expectedCachedResponse = {
statusCode: 200,
headers: {
'cache-control': 'max-age=60',
'content-type': 'application/json'
},
elapsedTime: nockElapsedTime
};
nock.cleanAll();
api.get('/').reply(200, responseBody, headers);
staleClient.get(url, function (err) {
assert.ifError(err);
sinon.assert.calledOnce(catbox.set);
sinon.assert.calledWith(catbox.set, expectedKey, {
body: responseBody,
response: expectedCachedResponse
}, 60000);
done();
});
});
it('respects the doNotVary option when creating a cache key', function (done) {

@@ -427,2 +572,35 @@ var reqheaders = {

it('increments a counter when a stale response is sent', function (done) {
var cachedResponseBody = {
foo: 'baz'
};
var errorResponseCode = 503;
var errorResponseBody = {
error: 'An error'
};
var errorHeaders = {
'cache-control': 'max-age=5',
'content-type': 'application/json',
'www-authenticate': 'Bearer realm="/"'
};
catbox.get.withArgs(expectedStaleKey).yields(null, {
item: {
body: cachedResponseBody,
response: expectedCachedResponse
}
});
nock.cleanAll();
api.get('/').reply(errorResponseCode, errorResponseBody, errorHeaders);
staleClient.get(url, function (err, body, res) {
assert.ifError(err);
assert.deepEqual(body, cachedResponseBody);
assert.deepEqual(res, expectedCachedResponse);
sinon.assert.calledWith(stats.increment, 'http.cache.stale');
done();
});
});
it('increments a counter for each cache miss', function (done) {

@@ -429,0 +607,0 @@ client.get(url, function (err) {

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