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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@transitive-sdk/datacache

v0.14.1

Published

A class for storing data in a JSON object with change detection and change notifications. Ideal for building data-syncs.

Readme

DataCache

A class for storing data in a JSON object with change detection and change notifications. Ideal for building data-syncs and for triggering reactive updates in React (or similar front-end framework) when this synced data is changed on the back-end.

> const {DataCache} = require('@transitive-sdk/datacache')
> d = new DataCache()
> d.subscribe((change) => console.log('d has changed', change));
> d.subscribeTopic('/+first/c', (value, path, match) => console.log('/+first/c has changed to', value, `with first being ${match.first}`));

> d.update(['a','b'], 1234)
d has changed { '/a/b': 1234 }

> d.update(['a','c'], 123)
d has changed { '/a/c': 123 }
/+first/c has changed to 123 with first being a

> d.get()
{ a: { b: 1234, c: 123 } }

With this it is terribly easy to implement a data-sync over any connection that allows you to send strings:

const data = new DataCache();

const client = new SomeCommunicationProtocol();
client.connect('...to some peer over some protocol');

// parse messages we receive from peer, apply to local DataCache
client.on('message', (message) => {
  const change = JSON.parse(message.toString());
  if (change) {
    _.forEach(change, (value, key) =>
      data.update(key, value, {external: true}));
  }
});

// subscribe to local changes and publish them to the peer
data.subscribe((change, tags) => {
  if (tags?.external)
    // this is a change that we've received from another party, don't re-publish
    return;

  // notify the peer of these changes
  client.send(JSON.stringify(change));
});

Documentation

Table of Contents

DataCache

A class implementing a local data cache, used as a local data store with deduplication detection and update events. While this class is very handy you probably won't need to create instances of it directly. Instead use the mqttSync.data instance which holds the locally stored data subscribed/published from/to MQTTSync. For example on the robot:

// update/publish our status:
mqttSync.data.update('status', {changed: Date.now(), msg: 'OK'});
// subscribe to new user requests (e.g., from UI):
mqttSync.data.subscribePath('+user/request', (request, key, {user}) => {
  log.debug(`user ${user} made request`, request);
});

In the cloud or in a web component you would need to use the full topic including org, device, scope, cap-name, and version.

Parameters

  • data (optional, default {})

filter

Filter the object using path with wildcards

Parameters

  • path

filterByTopic

Filter the object using topic with wildcards

Parameters

  • topic

forMatch

For each topic match, invoke the callback with the value, path, and match just like subscribePath, but on the current data rather than future changes.

Parameters

  • topic
  • callback

forPathMatch

For each path match, invoke the callback with the value, path, and match just like subscribePath

Parameters

  • path
  • callback

get

Get sub-value at path, or entire object if none given

Parameters

  • path (optional, default [])

getByTopic

Get sub-value specified by topic

Parameters

  • topic

subscribe

Add a callback for all change events.

Parameters

  • callback

subscribePath

Subscribe to a specific path (array) only. Callback receives value, key, matched, tags.

Parameters

  • path
  • callback

subscribePathFlat

Same as subscribePath but always get all changes in flat form

Parameters

  • topic
  • callback

subscribeTopic

Subscribe to a specific topic only. Callback receives value, key, matched, tags.

Parameters

  • topic
  • callback

unsubscribe

Remove a callback previously registered using subscribe.

Parameters

  • callback

update

Update the value at the given path (array or dot separated string)

Parameters

  • path
  • value
  • tags

updateFromArray

Update the object with the given value at the given path, remove empty; return the flat changes (see toFlatObject). Add tags to updates to mark them somehow based on the context, e.g., so that some subscriptions can choose to ignore updates with a certain tag.

Parameters

  • path
  • value
  • tags (optional, default {})

updateFromModifier

Update data from a modifier object where keys are topic names to be interpreted as paths, and values are the values to set

Parameters

  • modifier
  • tags

updateFromTopic

Set value from the given topic (with or without leading or trailing slash)

Parameters

  • topic
  • value
  • tags

dropWildcardIds

reduce wildcards with Ids, such as +sessionId, to just +

Parameters

  • x

forMatchIterator

Iterate through the object and invoke callback for each match of path (with named wildcards)

Parameters

  • obj
  • path
  • callback
  • pathSoFar (optional, default [])
  • matchSoFar (optional, default {})

isPrefixOf

prefixArray is a prefix of the array

Parameters

  • prefixArray
  • array

isSubTopicOf

sub is a strict sub-topic of parent, and in particular not equal

Parameters

  • sub
  • parent

pathToTopic

convert a path array to mqtt topic; reduces +id identifiers to +

Parameters

  • pathArray

selectFromObject

Given an object and a path with wildcards (* and +), modify the object to only contain elements matched by the path, e.g., {a: {b: 1, c: 2}, d: 2} and ['a','+'] would give {a: {b: 1, c: 2}}

Parameters

  • obj object The object to select from
  • path array An array specifying the path to select, potentially containing mqtt wildcards ('+').

setFromPath

Like _.set but without arrays. This allows using numbers as keys.

Parameters

  • obj
  • path
  • value

toFlatObject

Given an object, return a new flat object of topic+value pairs, e.g.:

{a: {b: 1, c: 2}, d: 3}   →   {'/a/b': 1, '/a/c': 2, '/d': 3}

Note: not idempotent!

{'/a/b': 1, '/a/c': 2, d: 3}  →  {'%2Fa%2Fb': 1, '%2Fa%2Fc': 2, '/d': 3}

Parameters

  • obj
  • prefix (optional, default [])
  • rtv (optional, default {})

topicMatch

Match a slash-separated topic or path array with a selector using +XYZ for (named) wildcards. Return the matching result.

Parameters

  • selector
  • topic

topicToPath

convert topic to path array

Parameters

  • topic

unset

Unset the topic in that obj, and clean up parent if empty, recursively. Return the path to the removed node.

Parameters

  • obj
  • path

updateObject

Given a modifier {"a/b/c": "xyz"} update the object obj such that obj.a.b.c = "xyz".

Parameters

  • obj
  • modifier