npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

resource-store

v0.1.0

Published

Caching/memoization library with multiple storage backends.

Readme

resource-store

resource-store is a Node.js caching/memoization library with multiple storage backends.

npm package Build status Coverage

Usage

Create a ResourceStore object with a generator callback. Then, request values from it by calling the get method and passing JavaScript objects or primitives as keys. If the given key is not already cached, the generator function will be called to generate its value.

The generator function receives keys and generates the values associated with them. For a given key, the value it returns should always be the same.

The optional backend argument determines the type of storage used by the store:

  • Omitted - In-memory storage only, using MemoryBackend.
  • String - File-backed storage starting at the given directory, using FileBackend.
  • Object - An object with methods get, set, delete, and list, see Backends below for details.

The extra parameter passed to the generator function is an object that can be used to store extra data alongside the value generated from the key. See Out-of-Band Data below for more information.

var ResourceStore = require('resource-store');

var store = new ResoureStore(backend, function generator(key, extra, cb) {
    var value;
    // generate value based on key
    // generator callback takes parameters (err, value)
    cb(null, value);
});

Methods

get(key, cb)

Retrieves a value from the store. If the value for the given key has not been generated yet, the generator function will be called, otherwise the stored value will be returned. If multiple calls are made to get for the given key, then the generator function will only be called once and all outstanding calls will return when the generator completes.

The callback to get takes parameters (err, value, extra):

  • err - null unless an error occurred in the generator function or the storage backend.
  • value - the value associated with the requested key.
  • extra - see Out-of-Band Data below.
store.get({ prop1 : 'value1' }, function(err, value, extra) {
    // do stuff with the returned value
});

delete(key, [cb])

Deletes a value from the store. If the value specified by key does not exist then an error will be returned.

store.delete({ prop1 : 'value1' }, function(err) {
    // delete succeeded if err is null
});

list(cbEntry, cbDone)

Lists all values cached in the store.

cbEntry is called once for each entry with parameters err, key, value, extra. See Out-of-Band Data below for more information about the extra parameter.

cbDone is called after all entries have been listed with parameters err, numEntries.

store.list(function cbEntry(err, key, value, extra) {
    // do something with this value
}, function cbDone(err, numEntries) {
    // now go do something else
});

Out-of-Band Data

Some callback functions receive an extra parameter which is the actual value sent to the storage backend (the value associated with the given key is stored at extra.value). The generator function can set properties on extra to store data alongside the cached value. This can be useful for debugging.

The library will also set the following values on extra (all date/time values are millisecond-precision Unix timestamps, the result of +new Date):

  • key - the key object associated with this item. Not very useful to consumers, but needed because a backend may not know its own keys.
  • value - the data value associated with this key.
  • createStarted - available for all functions, but most useful in get and list.
  • createEnded - set when the generator function completes; available for get and list.
  • lastRetrieved - set when a value is generated or retrieved from the storage backend. Available in get and list, but most useful in list to allow deleting old data.
  • wasCached - available in get and set to true if the requested value was already cached (i.e. the generator function was not called).
  • baseFilename - available in all functions if using the FileBackend for storage. This is the data filename where the value will be stored, without the .json extension. This is useful for storing additional binary data alongside the key.

Backends

Storage backends that can be used by this library must store data objects associated with string keys. Note: ResourceStore accepts object keys, but storage backends accept string keys.

Backends must implement the following methods:

  • get - return the value associated with a key, and set and remember value.lastRetrieved, or return false if nothing is stored with that key.
  • set - set the data value associated with a key.
  • delete - clear the data value associated with a key.
  • list - list all data values stored.

Backends can have a shouldCache property. If it is missing or truthy, then ResourceStore will remember values retrieved from the backend when multiple calls to get are made concurrently for the same key. Set backend.shouldCache = false to disable this behavior if retrieving data from the backend is effectively instantaneous.

Pseudocode (to avoid releasing Zalgo, all of these methods should be asynchronous in real implementations):

// cb takes parameters (err, value)
backend.get = function(keyString, cb) {
    // If the key doesn't have anything stored, return false
    if (!(keyString in backend.data)) {
        return cb(null, false);
    }
    // Get the data value associated with the key
    var value = ...;
    // Set lastRetrieved (and persist it somehow)
    value.lastRetrieved = +new Date;
    // err is null unless getting the value failed
    cb(err, value);
};

// cb takes parameters (err)
backend.set = function(keyString, value, cb) {
    // Set the data value associated with the key
    backend.data[keyString] = value;
    // err is null unless setting the value failed
    cb(err);
};

// cb takes parameters (err)
backend.delete = function(keyString, cb) {
    // Clear the data value associated with the key
    // err is null unless deleting the value failed
    cb(err);
};

// cbEntry takes parameters (err, key, value)
// cbDone  takes parameters (err, numEntries)
backend.list = function(cbEntry, cbDone) {
    // Get the list of keys stored
    var keys = Object.keys(backend.data),
        numEntries = 0;
    // Loop and return values
    keys.forEach(function(k) {
        var value = backend.data[k];
        // Skip values that were removed after obtaining the list of keys
        if (typeof value != 'undefined') {
            // Passing the key is optional:  some backends (like FileBackend)
            // don't know their own keys, so pass null instead
            // Set value.lastRetrieved if it isn't already set
            value.lastRetrieved = backend.lastRetrieved[k];
            cbEntry(null, k, value);
            numEntries++;
        }
    });
    cbDone(null, numEntries);
};

Except for the list method, backends do not need to worry about concurrency: ResourceStore will serialize operations for a given key so that only one of get, set, and delete is operating at a time. The list method should store a list of keys first, then loop over them and skip keys that no longer have associated data values.

The library comes with two backends already implemented: ResourceStore.FileBackend and ResourceStore.MemoryBackend.

new FileBackend(dir) stores data in JSON filenames named based on the hash of the requested keys, starting at the directory dir and creating subdirectories as needed.

new MemoryBackend() stores data in memory in a plain old JavaScript object.

Mutability

When using the MemoryBackend, values stored in a ResourceStore are mutable by default. This has the following consequences:

  • The value returned by the generator === the value returned to get() and list() for the same key
  • Object prototype chains, function properties, etc. are preserved
  • The ResourceStore can be used to cache database connections or other complex objects with internal state.

If you'd rather have an immutable data store instead, construct the ResourceStore using a FileBackend, or using an immutable MemoryBackend as follows:

var store = new ResourceStore(
    new ResourceStore.MemoryBackend({ mutable : false }),
    function generator(key, extra, cb) { ... });

With an immutable backend, the ResourceStore will only be able to store values that can be represented in JSON.