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

device-storage-sharable-records

v1.0.1

Published

Device stored collection of sharable records.

Readme

device-storage sharable records

A local collection of records, stored in the device (browser), where any record can be shared as a URL.

As an example of usage, this module can be used to store personal preference settings, like a view setup (e.g. dashboard), but also be able to share this setup with someone else, and when doing so the receiver will get a copy of the setup stored in his/her local collection and own that piece of data in his/her device/browser.

Use this when:

  • You're OK with letting the users own and handle certain settings instead of storing it centrally in a server.
  • You don't control the backend but need to persist some (non-critical) dynamic dataset at the user.

To create a device storage sharable records manager, or local collection, it is recommended to input some settings like such:

const recordSchema = { title: '', items: [] };
const shallowProjection = ['title'];
const recordPrefix = 'ITEM.';

const localCollection = createLocalCollection({
  recordSchema,
  shallowProjection,
  recordPrefix,
});
  • recordSchema: This is used when creating new records. (id is added internaly)
  • shallowProjection: The properties that are needed to present the collection of possible records to the user. (Read about records part of the manager state, below)
  • recordPrefix: This prefix makes it possible to have several separate local collections. (Since localStorage is shared among all websites on the same domain, this can ensure that each site uses a unique prefix)

The object that is returned from createLocalCollection contains first and foremost:

  • useLocalCollection: The main hook for the (zustand) internal state. See below for what the internal state contains.
  • useCurrentRecord: A helper hook for the current record.
  • useRecords: A helper hook for the shallow records array.

Also, for non-React environments or integrations, some util functions are returned. Look below.

The internal (zustand) state contains:

  • current: The entire record currently selected.
  • records: Array of all records in storage, with only properties id plus what's in shallowProjection.
  • dUrl: The generated URL from current record.

And the actions available are:

  • init: Must be run, e.g. at application startup. Reads the persistant local storage and populates current & records. Give this function a URL (or only the search/arguments part of it) to import an exported record.
  • updateCurrent: Takes a record object and updates the current record.
  • createRecord: Creates a new record and sets it as current.
  • switchRecord: Give this function an id and it will search for it in the storage and set it as current. If it is given the NEW_RECORD_KEY exported from this module, it will instead create a new record (same as createRecord).
  • deleteRecord: Given an id this will remove that record (from storage and records) and if that record is the current it will select a random record as current, or create a new one if no other exists.
  • exportToUrl: Export the current record to a URL, that will be put in dUrl.

API

Options input

See description about these above.

  • recordSchema: object
  • shallowProjection: array
  • recordPrefix: string

It is also possible to replace the default localStorage use, by providing storageFns as option:

  • storageFns: An object with
    • storageGet: (key: string) => string
    • storageSet: (key: string, value: string) => bool
    • storageRemove: (key: string) => bool
    • storageGetAll: () => object

And lastly, if globalThis.location?.href.split('?')[0] is not the way to get the base URL for your environment (if you want to use the share feature), add this to options:

  • getBaseUrl: () => string,

createLocalCollection return

See description about these above.

  • useLocalCollection: (selector: function) => any (See zustand docs for details).
  • useCurrentRecord: () => object
  • useRecords: () => records

For non-React environments or integrations, some util functions are returned:

  • getStore: () => useLocalCollection.getState()
  • setState: (updater) => useLocalCollection.setState(updater)
  • subscribe: useLocalCollection.subscribe
  • destroy: useLocalCollection.destroy
  • getNewRecord: reducer.getNewRecord
  • getSelectedRecordId: reducer.getSelectedRecordId

To integrate this into other state managers, you could use some listener. Here is an example for binding to an XState (v5+) machine:

import { createLocalCollection } from 'device-storage-sharable-records';

export const localCollection = createLocalCollection(/* As above */);

const localCollectionListener = fromCallback(({ sendBack }) => {
  localCollection.subscribe(({ current = {}, dUrl } = {}, prevState = {}) => {
    console.log('localCollectionListener event:', current.id, dUrl);
    // A record is imported:
    if (current.id !== prevState.current?.id) return sendBack({ type: 'init', output: current });
    // A record is exported:
    if (dUrl && dUrl !== prevState.dUrl) return (globalThis.location = dUrl);
    return undefined;
  });
  localCollection.getStore().init(globalThis.location.search);
  return localCollection.destroy;
});

Licence

MIT