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

catbox

Package Overview
Dependencies
Maintainers
3
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

catbox - npm Package Compare versions

Comparing version 1.2.0 to 2.1.0

test/import.js

3

examples/policy.js

@@ -44,3 +44,2 @@ // After starting this example load http://localhost:8080 and hit refresh, you will notice that it loads the response from cache for the first 5 seconds and then reloads the cache. Look at the console to see it setting and getting items from cache.

var clientOptions = {
engine: 'redis',
partition: 'examples' // For redis this will store items under keys that start with examples:

@@ -53,3 +52,3 @@ };

var client = new Catbox.Client(clientOptions);
var client = new Catbox.Client(require('../test/import'), clientOptions);
client.start(function () {

@@ -56,0 +55,0 @@

// Load modules
var Hoek = require('hoek');
var Defaults = require('./defaults');
var Memory = require('./memory');
// Mongo, Redis, Riak, and Memcached are loaded below depending on the configuration

@@ -14,38 +11,28 @@

module.exports = internals.Client = function (options) {
internals.defaults = {
partition: 'catbox'
};
Hoek.assert(this.constructor === internals.Client, 'Cache client must be instantiated using new');
this.settings = Defaults.apply(options);
Hoek.assert(this.settings.partition && this.settings.partition.match(/^[\w\-]+$/), 'Invalid partition name:' + this.settings.partition);
// Create internal connection
module.exports = internals.Client = function (engine, options) {
var engine = this.settings.engine;
if (engine === 'extension') {
this.connection = this.settings.extension;
}
else {
var factory = null;
Hoek.assert(this.constructor === internals.Client, 'Cache client must be instantiated using new');
Hoek.assert(engine, 'Missing catbox client engine');
Hoek.assert(typeof engine !== 'object' || !options, 'Cannot specify options with object instance engine config');
if (engine === 'redis') {
factory = require('./redis');
}
else if (engine === 'mongodb') {
factory = require('./mongo');
}
else if (engine === 'memcache') {
factory = require('./memcache');
}
else if (engine === 'riak') {
factory = require('./riak');
}
else if (engine === 'memory') {
factory = Memory;
}
var settings = Hoek.applyToDefaults(internals.defaults, options || {});
Hoek.assert(settings.partition.match(/^[\w\-]+$/), 'Invalid partition name:' + settings.partition);
Hoek.assert(factory, 'Unknown cache engine type');
this.connection = new factory.Connection(this.settings);
if (typeof engine === 'string') {
var Connection = require(engine);
this.connection = new Connection(settings);
}
else if (typeof engine === 'object') {
this.connection = engine;
}
else if (typeof engine === 'function') {
this.connection = new engine(settings);
}
return this;
Hoek.assert(this.connection, 'Invalid engine configuration');
};

@@ -52,0 +39,0 @@

@@ -5,3 +5,2 @@ // Load modules

var Policy = require('./policy');
var Defaults = require('./defaults');

@@ -16,2 +15,1 @@

exports.Policy = exports.policy = Policy;
exports.defaults = Defaults;

@@ -162,3 +162,3 @@ // Load modules

generateFunc(function (err, result, isUncacheable) {
generateFunc.call(null, function (err, value, ttl) {

@@ -168,3 +168,3 @@ // Error

if (err ||
isUncacheable) {
ttl === 0) { // null or undefined means use policy

@@ -177,20 +177,5 @@ if (wasCallbackCalled) {

wasCallbackCalled = true;
return callback(err, result, null, report);
return callback(err, value, null, report);
}
// Valid result
var value = result;
var ttl = null; // Use cache policy
if (value) {
if (value.getTtl && typeof value.getTtl === 'function') {
ttl = value.getTtl();
}
if (value.toCache && typeof value.toCache === 'function') {
value = value.toCache();
}
}
// Check if already sent stale value

@@ -208,3 +193,3 @@

set(value, ttl); // Save to cache (lazy) and continue
return callback(null, result, null, report);
return callback(null, value, null, report);
});

@@ -211,0 +196,0 @@ };

{
"name": "catbox",
"description": "Multi-strategy object caching service",
"version": "1.2.0",
"version": "2.1.0",
"author": "Eran Hammer <eran@hueniverse.com> (http://hueniverse.com)",
"contributors": [
"Doug Pedley",
"Wyatt Preul <wpreul@gmail.com> (http://jsgeek.com)"

@@ -13,11 +12,6 @@ ],

"keywords": [
"cache",
"memory",
"redis",
"mongodb",
"memcache",
"riak"
"cache"
],
"engines": {
"node": ">=0.10.21"
"node": ">=0.10.22"
},

@@ -28,7 +22,3 @@ "dependencies": {

"devDependencies": {
"lab": "1.x.x",
"redis": "0.10.x",
"mongodb": "1.3.x",
"memcached": "0.2.x",
"riakpbc": "1.2.x"
"lab": "1.x.x"
},

@@ -35,0 +25,0 @@ "scripts": {

@@ -5,61 +5,41 @@ <a href="https://github.com/spumko"><img src="https://raw.github.com/spumko/spumko/master/images/from.png" align="right" /></a>

Multi-strategy object caching service
Version: **2.x**
[![Build Status](https://secure.travis-ci.org/spumko/catbox.png)](http://travis-ci.org/spumko/catbox)
**catbox** is a multi-strategy key-value object store. It comes with extensions supporting a memory cache,
[Redis](http://redis.io/), [MongoDB](http://www.mongodb.org/), [Memcached](http://memcached.org/), and [Riak](http://basho.com/riak/).
**catbox** provides two interfaces: a low-level `Client` and a high-level `Policy`.
**catbox** is a multi-strategy key-value object store. It includes support for [Redis](http://redis.io/), [MongoDB](http://www.mongodb.org/),
[Memcached](http://memcached.org/), and a limited memory store (not suitable for production environments). **catbox** provides two interfaces: a low-level `Client` and a high-level
`Policy`.
### Installation
In order to reduce module dependencies, **catbox** does not depend on the [mongodb](https://npmjs.org/package/mongodb) or
[redis](https://npmjs.org/package/redis) modules. To use these strategies, each service must be available on the network and
each module must be manually installed.
In order to reduce module dependencies, **catbox** does not includes the external caching strategies. To use other strategies,
each service must be manually installed via npm or package dependencies manually. The available strategies are:
### Notes
- [Memory](https://github.com/spumko/catbox-memory)
- [Redis](https://github.com/spumko/catbox-redis)
- [MongoDB](https://github.com/spumko/catbox-mongodb)
- [Memcached](https://github.com/spumko/catbox-memcached)
- [Riak](https://github.com/DanielBarnes/catbox-riak)
Since Riak doesn't have ttl built in, a garbage collection function will run periodically to remove expired keys. This function makes a getIndex call, so your riak backend cannot be set to `riak_kv_bitcask_backend`, this call streams the keys that need to be deleted and deletes them as they are received.
In order to prevent siblings we recomend you set `last_write_wins` on the bucket to true.
### `Client`
The `Client` object provides a low-level cache abstraction. The object is constructed using `new Client(options)` where:
The `Client` object provides a low-level cache abstraction. The object is constructed using `new Client(engine, options, loader)` where:
- `options` - is an object with the following keys:
- `engine` - the cache server implementation. Options are:
- `redis`
- `mongodb`
- `memcache`
- `memory`
- `riak`
- an object with **catbox** compatible interface (use the `memory` cache implementation as prototype).
- `engine` - is a string, object, or function detailing the cache strategy implementation details:
- string - the node module name used via `require()`. The required module must export a prototype function with the signature
`function(options)`. **catbox** will call `new require(name)(options)` with the provided `name` string.
- function - a prototype function with the signature `function(options)`. **catbox** will call `new func(options)`.
- object - a pre instantiated client implementation object. Does not support passing `options`.
- `options` - the strategy configuration object. Each strategy defines its own configuration options with the following common options:
- `partition` - the partition name used to isolate the cached results across multiple clients. The partition name is used
as the MongoDB database name, the Riak bucket, or as a key prefix in Redis and Memcached. To share the cache across multiple clients, use the same
partition name.
- additional strategy specific options:
- MongoDB:
- `host` - the MongoDB server hostname. Defaults to `'127.0.0.1'`.
- `port` - the MongoDB server port. Defaults to `27017`.
- `username` - when the mongo server requires authentication. Defaults to no authentication.
- `password` - the authentication password when `username` is configured.
- `poolSize` - number of connections. Defaults to `5`.
- Redis:
- `host` - the Redis server hostname. Defaults to `'127.0.0.1'`.
- `port` - the Redis server port. Defaults to `6379`.
- `password` - the Redis authentication password when required.
- Riak:
- `host` - the Riak server hostname. Defaults to `127.0.0.1`.
- `port` - the Riak PBC port. Defaults to `8087`.
- Memcache:
- `host` - the Memcache server hostname. Defaults to '`127.0.0.1'`. Cannot be used with `location`.
- `port` - the Memcache server port. Defaults to `11211`. Cannot be used with `location`.
- `location` - the Memcache server hostname and port. Defaults to ''127.0.0.1:11211''.
Can be a String, Array, or an Object as per [node-memcached location specification](https://github.com/3rd-Eden/node-memcached#server-locations).
- Memory:
- `maxByteSize` - sets an upper limit on the number of bytes that can be stored in the cached. Once this limit is
reached no additional items will be added to the cache until some expire. The utilized memory calculation is
a rough approximation and must not be relied on. Defaults to `104857600` (100MB).
as the MongoDB database name, the Riak bucket, or as a key prefix in Redis and Memcached. To share the cache across multiple clients,
use the same partition name.
Note that any implementation of client strategies must return deep copies of the stored data as the API assumes that the object returned
from a `get()` is owned by the called and can be safely modified without affecting the cache copy.
#### API

@@ -108,2 +88,3 @@

#### API

@@ -130,3 +111,7 @@

- `id` - the unique item identifier (within the policy segment).
- `generateFunc` - a function with the signature `function(callback = function (err, result))` where `result` is the value to be stored.
- `generateFunc` - the function used to generate a new cache item if one is not found in the cache. The method's signature is
`function(err, value, ttl)` where:
- `err` - an error condition.
- `value` - the new value generated.
- `ttl` - the cache ttl value in milliseconds. Set to `0` to skip storing in the cache. Defaults to the cache global policy.
- `callback` - a function with the signature `function(err, value, cached, report)` where:

@@ -133,0 +118,0 @@ - `err` - any errors encountered.

@@ -23,53 +23,94 @@ // Load modules

it('throws an error if using an unknown engine type', function (done) {
it('uses string engine', function (done) {
var fn = function () {
var client = new Catbox.Client('../test/import');
client.start(function (err) {
var options = {
engine: 'bob'
};
expect(err).to.not.exist;
var client = new Catbox.Client(options);
};
var key = { id: 'x', segment: 'test' };
client.set(key, '123', 1000, function (err) {
expect(fn).to.throw(Error);
done();
expect(err).to.not.exist;
client.get(key, function (err, result) {
expect(err).to.not.exist;
expect(result.item).to.equal('123');
done();
});
});
});
});
it('doesn\'t initialize client when engine is none', function (done) {
it('uses prototype engine', function (done) {
var fn = function () {
var Obj = require('./import');
var client = new Catbox.Client(Obj);
client.start(function (err) {
var client = new Catbox.Client('none');
};
expect(err).to.not.exist;
expect(fn).to.throw(Error);
done();
var key = { id: 'x', segment: 'test' };
client.set(key, '123', 1000, function (err) {
expect(err).to.not.exist;
client.get(key, function (err, result) {
expect(err).to.not.exist;
expect(result.item).to.equal('123');
done();
});
});
});
});
it('returns error when calling get on a bad connection', function (done) {
it('uses object instance engine', function (done) {
var failOn = function (method) {
var Obj = require('./import');
var client = new Catbox.Client(new Obj());
client.start(function (err) {
var err = new Error('FAIL');
var errorEngineImp = {
expect(err).to.not.exist;
start: function (callback) { callback(method === 'start' ? err : null); },
stop: function () { },
isReady: function () { return method !== 'isReady'; },
validateSegmentName: function () { return method === 'validateSegmentName' ? err : null; },
get: function (key, callback) { return callback(method === 'get' ? err : null); },
set: function (key, value, ttl, callback) { return callback(method === 'set' ? err : null); },
drop: function (key, callback) { return callback(method === 'drop' ? err : null); }
};
var key = { id: 'x', segment: 'test' };
client.set(key, '123', 1000, function (err) {
var options = {
engine: errorEngineImp,
partition: 'hapi-cache'
};
expect(err).to.not.exist;
return new Catbox.Client(options);
client.get(key, function (err, result) {
expect(err).to.not.exist;
expect(result.item).to.equal('123');
done();
});
});
});
});
it('throws an error if using an unknown engine type', function (done) {
var fn = function () {
var client = new Catbox.Client('bob');
};
var client = failOn('get');
expect(fn).to.throw(Error);
done();
});
it('errors when calling get on a bad connection', function (done) {
var errorEngine = {
start: function (callback) { callback(null); },
stop: function () { },
isReady: function () { return true; },
validateSegmentName: function () { return null; },
get: function (key, callback) { return callback(new Error('fail')); },
set: function (key, value, ttl, callback) { return callback(new Error('fail')); },
drop: function (key, callback) { return callback(new Error('fail')); }
};
var client = new Catbox.Client(errorEngine);
var key = { id: 'x', segment: 'test' };

@@ -79,3 +120,3 @@ client.get(key, function (err, result) {

expect(err).to.exist;
expect(err.message).to.equal('FAIL');
expect(err.message).to.equal('fail');
done();

@@ -85,167 +126,160 @@ });

describe('Extension', function () {
describe('#start', function () {
it('should allow defaults to be applied multiple times', function (done) {
var options = {
partition: 'test',
engine: {
start: function (callback) {
it('passes an error in the callback when one occurs', function (done) {
callback();
}
var engine = {
start: function (callback) {
callback(new Error());
}
};
var defaultOptions = Catbox.defaults.apply(options);
var client = new Catbox.Client(defaultOptions);
var client = new Catbox.Client(engine);
client.start(function (err) {
expect(err).to.not.exist;
expect(err).to.exist;
done();
});
});
});
describe('#start', function () {
describe('#get', function () {
it('passes an error in the callback when one occurs', function (done) {
it('returns an error when the connection is not ready', function (done) {
var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback(new Error());
}
}
};
callback();
},
isReady: function () {
var client = new Catbox.Client(options);
client.start(function (err) {
return false;
}
};
expect(err).to.exist;
done();
});
var client = new Catbox.Client(engine);
client.get('test', function (err) {
expect(err).to.be.instanceOf(Error);
expect(err.message).to.equal('Disconnected');
done();
});
});
describe('#get', function () {
it('wraps the result with cached details', function (done) {
it('returns an error when the connection is not ready', function (done) {
var engine = {
start: function (callback) {
var options = {
partition: 'test',
engine: {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
get: function (key, callback) {
return false;
}
}
};
var result = {
item: 'test1',
stored: 'test2'
};
var client = new Catbox.Client(options);
client.get('test', function (err) {
callback(null, result);
}
};
expect(err).to.be.instanceOf(Error);
expect(err.message).to.equal('Disconnected');
done();
});
var client = new Catbox.Client(engine);
client.get({ id: 'id', segment: 'segment' }, function (err, cached) {
expect(cached.item).to.equal('test1');
expect(cached.stored).to.equal('test2');
expect(cached.ttl).to.exist;
done();
});
});
it('wraps the result with cached details', function (done) {
it('expires item', function (done) {
var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
get: function (key, callback) {
return true;
},
get: function (key, callback) {
var result = {
item: 'test1',
stored: 'test2'
};
var result = {
item: 'test1',
stored: Date.now() - 100,
ttl: 50
};
callback(null, result);
}
}
};
callback(null, result);
}
};
var client = new Catbox.Client(options);
client.get({ id: 'id', segment: 'segment' }, function (err, cached) {
var client = new Catbox.Client(engine);
client.get({ id: 'id', segment: 'segment' }, function (err, cached) {
expect(cached.item).to.equal('test1');
expect(cached.stored).to.equal('test2');
expect(cached.ttl).to.exist;
done();
});
expect(err).to.equal(null);
expect(cached).to.equal(null);
done();
});
});
});
describe('#set', function () {
describe('#set', function () {
it('returns an error when the connection is not ready', function (done) {
it('returns an error when the connection is not ready', function (done) {
var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return false;
}
}
};
return false;
}
};
var client = new Catbox.Client(options);
client.set('test', 'test', 'test', function (err) {
var client = new Catbox.Client(engine);
client.set('test', 'test', 'test', function (err) {
expect(err).to.be.instanceOf(Error);
expect(err.message).to.equal('Disconnected');
done();
});
expect(err).to.be.instanceOf(Error);
expect(err.message).to.equal('Disconnected');
done();
});
});
});
describe('#drop', function () {
describe('#drop', function () {
it('calls the extension clients drop function', function (done) {
it('calls the extension clients drop function', function (done) {
var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
drop: function (key, callback) {
return true;
},
drop: function (key, callback) {
callback(null, 'success');
}
}
};
callback(null, 'success');
}
};
var client = new Catbox.Client(options);
client.drop({ id: 'id', segment: 'segment' }, function (err, result) {
var client = new Catbox.Client(engine);
client.drop({ id: 'id', segment: 'segment' }, function (err, result) {
expect(result).to.equal('success');
done();
});
expect(result).to.equal('success');
done();
});

@@ -252,0 +286,0 @@ });

@@ -25,3 +25,3 @@ // Load modules

var client = new Catbox.Client('memory');
var client = new Catbox.Client('../test/import');
var cache = new Catbox.Policy({ expiresIn: 1000 }, client, 'test');

@@ -34,2 +34,3 @@

cache.set('x', '123', null, function (err) {
expect(err).to.not.exist;

@@ -49,3 +50,3 @@

var client = new Catbox.Client('memory');
var client = new Catbox.Client('../test/import');
var cache = new Catbox.Policy({}, client, 'test');

@@ -72,3 +73,3 @@

var client = new Catbox.Client('memory');
var client = new Catbox.Client('../test/import');
var cache = new Catbox.Policy({}, client, 'test');

@@ -132,3 +133,3 @@

var client = new Catbox.Client('memory');
var client = new Catbox.Client('../test/import');
client.start(function () {

@@ -156,21 +157,18 @@

var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
get: function (key, callback) {
return true;
},
get: function (key, callback) {
callback(new Error());
},
validateSegmentName: function () {
callback(new Error());
},
validateSegmentName: function () {
return null;
}
return null;
}

@@ -182,3 +180,3 @@ };

var client = new Catbox.Client(options);
var client = new Catbox.Client(engine);
var policy = new Catbox.Policy(policyConfig, client, 'test');

@@ -196,24 +194,21 @@

var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
get: function (key, callback) {
return true;
},
get: function (key, callback) {
callback(null, {
stored: 'stored',
item: 'item'
});
},
validateSegmentName: function () {
callback(null, {
stored: 'stored',
item: 'item'
});
},
validateSegmentName: function () {
return null;
}
return null;
}

@@ -225,3 +220,3 @@ };

var client = new Catbox.Client(options);
var client = new Catbox.Client(engine);
var policy = new Catbox.Policy(policyConfig, client, 'test');

@@ -242,21 +237,18 @@

var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
drop: function (key, callback) {
return true;
},
drop: function (key, callback) {
callback(null, 'success');
},
validateSegmentName: function () {
callback(null, 'success');
},
validateSegmentName: function () {
return null;
}
return null;
}

@@ -269,3 +261,3 @@ };

var client = new Catbox.Client(options);
var client = new Catbox.Client(engine);
var policy = new Catbox.Policy(policyConfig, client, 'test');

@@ -285,17 +277,14 @@

var options = {
partition: 'test',
engine: {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
validateSegmentName: function () {
return true;
},
validateSegmentName: function () {
return null;
}
return null;
}

@@ -308,3 +297,3 @@ };

var client = new Catbox.Client(options);
var client = new Catbox.Client(engine);
var policy = new Catbox.Policy(policyConfig, client, 'test');

@@ -320,3 +309,3 @@

it('doesn\'t try to compile a null config', function (done) {
it('does not try to compile a null config', function (done) {

@@ -349,3 +338,3 @@ var rule = Catbox.policy.compile(null);

var client = new Catbox.Client('memory');
var client = new Catbox.Client('../test/import');
var cache = new Catbox.Policy(config, client);

@@ -836,3 +825,3 @@ };

var client = new Catbox.Client({ engine: 'memory', partition: 'test-partition' });
var client = new Catbox.Client('../test/import', { partition: 'test-partition' });
if (broken) {

@@ -853,11 +842,6 @@ client.get = function (key, callback) { callback(new Error('bad client')); };

var item = {
gen: gen,
toCache: function () { return { gen: gen }; }
gen: gen
};
if (ttl) {
item.getTtl = function () { return ttl; };
}
return callback(null, item);
return callback(null, item, ttl);
}

@@ -886,3 +870,3 @@

setup(rule, 0, false, 0, function (get) {
setup(rule, 0, false, null, function (get) {

@@ -905,3 +889,3 @@ get('test', function (err, value, cached) {

setup(rule, 0, false, 0, function (get) {
setup(rule, 0, false, null, function (get) {

@@ -981,3 +965,3 @@ get('test', function (err, value, cached) {

setup(rule, 6, true, 0, function (get) {
setup(rule, 6, true, null, function (get) {

@@ -1016,3 +1000,3 @@ get('test', function (err, value1, cached) {

setup(rule, 0, false, 0, function (get) {
setup(rule, 0, false, null, function (get) {

@@ -1050,3 +1034,3 @@ get('test', function (err, value1, cached) {

setup(rule, 0, true, 0, function (get) {
setup(rule, 0, true, null, function (get) {

@@ -1069,8 +1053,4 @@ get('test', function (err, value1, cached) {

});
it('uses result toCache() when available', function (done) {
done();
});
});
});
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