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 🙏

© 2024 – Pkg Stats / Ryan Hefner

nestore

v0.0.47

Published

Event based state management

Downloads

6

Readme

Getting Started

Installation

Install using your preferred package manager, or import from a cdn:

yarn add nestore
<script src="https://unpkg.com/nestore"></script>

Usage

Import (or require) nestore and create a store with values, setters and listeners all in one place

// store.js
import nestore from 'nestore'

const nst = nestore({
    logged_in: false,
    user: null,
    messages: [],
    login: (NST, [name, password]) => {
        NST.set('logged_in', true)
        NST.store.user = name
    }
})

export default nst

Then import your store, register listeners on any path, and interact with the store

// app.js
import nst from './store.js'

nst.on('user', ({ key, path, value }) => {
    console.log(`Logged in as ${value}`)
})

nst.login('Alice', '1234')
nst.set('messages')

Nestore will automatically infer the types from the values in the initialStore, or you can provide a custom type definition for more type-safety

export type MyStore = {
    user: null | MyUser;
    messages: MyMessage[]
}

export type MyUser = {
    id: number;
    name: string;
}

export type MyMessage =  {
    time: number;
    text: string;
    media?: string[];
}

const myStore = nestore<MyStore>({
    user: null,
    messages: [],
})

Store Actions

Create a Store

Import nestore and create a store. The store is an object that contains the current values of the state. The store can hold any values, nested at any depth, that can be accessed from anywhere. The store always maintains the same reference allowing for a single-source-of-truth.

Import nestore, create your store, and export it.

import nestore from 'nestore'

const nst = nestore({ 
    logged_in: false,
    user_name: null,
    time: Date.now()
    1: 'one',
})

export default nst

Access the Store

All values are available through the store except in-store-mutators. Use the get method for easy or programmatic access to paths, or access the values directly through the store. Later we will react to changes with events.

The store is a mutable object with persistent references. Any direct access to nst.store.<path> will return that value with its current reference. Be cautious of unintended updates to store values by reference.

import nst from './myStore.js'

let loggedIn = nst.get('logged_in')
let user = nst.store.user_name

Update the Store

You can manually update/create values/keys externally using the set method or by updating the value directly. You can also update the entire store using either of these methods. Setting the value to null or undefined will not remove the key from the store.

import nst from './myStore.js'

nst.logged_in = false
nst.set('user_name', null)

Remove from the Store

To completely remove a key from the store 'object' - use the remove method. This will emit an event for the provided path.

nst.remove('user_name')

Reset the Store

Nestore keeps a copy (deep-clone) of the original store and provides a reset method.

import nst from './myStore.js'

nst.logged_in = false
nst.set('user_name', null)

Store Events

All actions and events within the store emit events that can be used to trigger external behavior when the data changes. Many storage mediums use the pub/sub pattern to react to real-time changes to data.

Listen to Changes

Nestore provides a method for registering an event listener that subscribes to a specific path, provided as the first argument to the nst.on method, and a callback to handle logic as the second argument. The callback will be always be invoked with an object of type NSTEmit.

nst.on('/', ({ value }) => {
    // react to the entire store (path and key are '/')
})
nst.on('path', ({ path, key, value }) => {
    // react to any changes to 'path'
})

Thanks to eventemitter2 we can listen to nested paths in objects and arrays. See more emitter methods and examples in Common Emitter Methods

nst.on('users.*.logged_in', ({ path, key, value }) => {
    // react to any users `logged_in` status
})

or we can use some convenience/utility methods provided by ee2 like:

// invoke the callback, then remove the lsitener
nst.once('path', () => {})
// invoke the callback n times, then remove the lsitener
nst.many('path', 5, () => {})
// invoke a callback on any change to the store
nst.onAny('path', () => {})

Emit Changes

Any update to the store using the set method will emit events for all paths/keys that were modified by the update

Events will only be emitted if the values are different (shallow equality) when preventRepeatUpdates is true, and when the emit flag is omitted or set to 'emit' or 'all'. See the Full API section

Manual Emit

You can also manually emit events to force update a listener. The value provided to the emit method should be an object with the type T_NSTEmit, but any values / types provided will be emitted.

Common Emitter Methods

Nestore extends the event-emitter-2 class. Visit the ee2 npm page to view the full documentation of every method included with the event emitter.

emit

Execute each of the listeners that may be listening for the specified event name in order with the list of arguments. emitter.

emitter.emit(event | eventNS, [arg1], [arg2], [...])

on / off

Execute each of the listeners that may be listening for the specified event name in order with the list of arguments.

Same as addListener and removeListener

emitter.emit(event | eventNS, [arg1], [arg2], [...])

Full API

Types

NSTOptions
NSTEmit
...

Nestore Async Generator

Nestore Options

delimiter
adapters See Adapters

Properties

maxListeners
delimiter

Methods

In Store Listeners

In Store Mutators

Manage all store logic in a single place with custom in-store mutator functions.

These can be any type of function (async/sync) and return any value. Just set the state when the values are ready.

const myStore = nestore({
    user_name: null,
    user_data: null,

    fetchUserData: async (nst, [name]) => {
        const { data } = await axios.get(`/api/users/${name}`)
        nst.set('user_data', data)
        return data
    }
})

// just run the function
myStore.fetchUserData('Johnny68')

// wait for the return value
let userData = await myStore.fetchUserData('Johnny68')

Adapters

About

An exploration of event based datastore management for JavaScript/TypeScript applications. Initially created to manage state and update the display of long-running nodejs CLI programs

Inspired by Zustand - API inspired by the vanilla implementation of Zustand

Contributing

This state-management solutions still requires at least:

  • more / advanced test cases
  • performance imporovements
  • footprint reduction
  • better documentation

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change and make sure all tests pass locally before making a pull request.

Please make sure to update tests as appropriate, or suggest new test cases.

GitHub Repository

GitHub Issues

NPM Package


License

MIT