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

onestore

v1.1.0

Published

Event Emitter based Store for the browser and node.js

Downloads

8

Readme

onestore

onestore is the one

... store you need in your application

Features

  • it is redux and store-emitter influenced
  • works in the browser and in node.js
  • minimal dependencies: events, inherits.
  • small
  • fast
  • synchronous updates
  • configurable update or clone state TODO
  • dynamic added reducers
  • fluent (chainable) API
  • supports namespaces
  • supports deep nested object trees
  • event bubbling

motivation

I would like to have a store at hand that is similar to redux that works well with nested components.

  • It should allow namespaced listeners
  • It should be possible to define Listeners on specific actions as well as specific objects in the tree.
  • It should only deal with the required part of the tree, not the whole state object.
  • It should support distributed and dynamic added reducers

Note: onestore is not bulletproof. It is possible for one component to overwrite the state of another component that is further down in the object tree.

Therefore you should only add components at the leaves.

install

npm install --save onestore

basic usage

var createStore = require('onestore');
var store = createStore();

store
  .setInitialState([])
  .define({
    'SEND': function (state, action) {
      return [{ message: action }].concat(state);
    },
    'LIKE_LATEST_TWEET': function (state, action) {
      var latest = Object.assign({}, state[0]);
      latest.likes = typeof latest.likes === 'undefined' ? 1 : ++latest.likes;
      state[0] = latest;
      return state;
    }
  });

t.deepEqual(store.getState(), []);

var events = 0;
var tweets = 0;
var likes = 0;
store.on('SEND', s => tweets++);
store.on('LIKE_LATEST_TWEET', s => likes++);
store.on('*', s => events++);

store
  .do('SEND', 'my first tweet')
  .do('LIKE_LATEST_TWEET')
  .do('SEND', 'now I\'m a pro')
  .do('LIKE_LATEST_TWEET')
  .do('LIKE_LATEST_TWEET')
  .do('LIKE_LATEST_TWEET');

var state = store.getState();

t.equal(events, 6);
t.equal(tweets, 2);
t.equal(state.length, 2);
t.deepEqual(state, [{ message: 'now I\'m a pro', likes: 3 }, { message: 'my first tweet', likes: 1 }]);

advanced usage with namespaces


var store = window.store = Store();
var events = 0;

// login.js
store
  .define({
    'user.LOGIN': function (state, action) {
      return { userState: action };
    },
    'user.LOGOUT': function (state, action) {
      return { userState: null };
    }
  });

events = 0;

store.on('user.LOGIN', function (state) {
  t.deepEqual(state.userState, { name: 'its me' });
  events++;
});
store.on('user.LOGOUT', function (state) {
  t.equal(state.userState, null);
  events++;
});
store.on('user', function (state) {
  t.true(state);
  events++;
});
store.on('*', function (state) {
  t.true(state.user);
  events++;
});

store.do('user.LOGIN', { name: 'its me' });
t.deepEqual(store.getState('user'), { userState: { name: 'its me' } });
store.do('user.LOGOUT');
t.deepEqual(store.getState('user'), { userState: null });

t.equal(events, 6);

// bookmarks.js
store
  .define({
    'user.bookmarks.ADD': function (state, action) {
      state = Array.isArray(state) ? state : [];
      console.log('ADD', state, action);
      return state.concat([action]);
    },
    'user.bookmarks.REMOVE': function (state, action) {
      console.log('REMOVE', state, action);
      return state.filter(function (bookmark) {
        return bookmark.name !== action;
      });
    }
  });

store.on('user.bookmark', function (state) {
  console.log('user.bookmarks', state);
  t.true(Array.isArray(state));
  events++;
});

events = 0;

store
  .do('user.bookmarks.ADD', {
    url: 'www.npmjs.org',
    name: 'npm'
  })
  .do('user.bookmarks.ADD', {
    url: 'www.nodejs.org',
    name: 'node.js'
  })
  .do('user.bookmarks.ADD', {
    url: 'www.devdocs.io',
    name: 'devdocs'
  })
  .do('user.bookmarks.REMOVE', 'node.js');

var state = store.getState('user.bookmarks');
t.equal(events, 8);
t.equal(state.length, 2);
t.deepEqual(state, [
  {
    url: 'www.npmjs.org',
    name: 'npm'
  },
  {
    url: 'www.devdocs.io',
    name: 'devdocs'
  }]);

API

Glossar

  • fluent API: the functions return this (except the getters), which is the store instance in order to chain the function calls.

  • reducer: reducer function(state, action) which returns the new state based on the previous state and the action type and/or action

  • action: can be anything from Object to primitive.

  • actionType or reducerName: is the name of the reducer function. when you dispatch an action, the reducer function must be registred, otherwise a DoesNotExistError is thrown.

  • bubbling: when dispatching actions with a namespace, an event is emitted for every level up to the root ('*'). e.g. dispatching the action 'user.bookmarks.REMOVE' emits the following events in this order:

    [ 'user.bookmarks.REMOVE', 'user.bookmarks', 'user', '*' ]
  • name: namespace + actionType, where the namespace is optional and can be deeply nested (separated with .).

    the name consists of th the optional namespace and the type of the action.

    [ns1.[ns2.[...nsN.]]]actionType

    The namespace corresponds with the object structure in the store.

Store(reducers, initialState)

Creates a new Store.

reducers and initialState are optional. if you want to provide the initialState, you also have to provide the reducers.

reducers must be an Object with the name of the reducer as key and the reducer function as value. Multiple reducers can be proviced.

methods

setInitialState(initialState)

Lets you set the initialState like in the Constructor. It must NOT be called, after an action took place with dispatch, otherwise a NotAllowedError is thrown.

begin(namespace)

Alias: module, component, ns

Sets the namespace and returns a new module object with the namespace set, so that you don't have to repeat the namespace, but can define it once per module. You can jump out of this namespace with end();

When an action is dispatched on the module, the corresponding events are emitted on the module as well as on the store.

Limitation: module events are only emitted, when the dispatched on the module. In other words if you dispatch e.g. store.dispatch('tweet.SEND') fn is not called when defined like this: store.begin('tweet').on('SEND', **fn**)

end()

Ends the namespace for a component and returns the original store object.

register(reducers) or (name, reducer)

Alias: add, define, reducer, addReducer

It lets you register reducers in the same way as you can register reducers in the Constructor. You can call this function any time. If the reducer function with the given reducerName already exists, it throws AlreadyExistsError.

You can also call the register function with name as String and a reducer function, when you just want to add a single reducer.

update(reducers) or (name, reducer)

Alias: replaceReducer

Same as register, but does not throw an AlreadyExistsError when the reducer with the given name is already registred. Instead it throws an DoesNotExistError, if it does NOT exist.

upsert(reducers) or (name, reducer)

Alias: addOrReplaceReducer

Same as register, but does not throw any Errors (normally :-).

dispatch(name, action)

Alias: do, act

Dispatches the action. The name is the reducerName provided when the reducer function was registered. it must match an already defined reducer function, otherwise a DoesNotExistError is thrown.

getState(namespace)

Alias: get

Returns the state, based on the namespace. If no namespace is provided, the root state object is returned.

getPreviousState(namespace)

Alias: previous, getPrevious

Same as getState, but returns the previous state, based on the namespace. If no namespace is provided, the previous root state object is returned.

events

The events correspond with the node.js event API. The direct use of emit is discouraged, because the Store emits events based on the dispatched actions. Mainly useful are the parts of the API are: on, once and removeListener.

on(name, state)

called every time the action is dispatched.

once(name, state)

called only the first time, the action is dispatched.

removeListener(eventName, listener)

Lets you remove an event listener.

license

MIT

related