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

reagg

v0.1.3

Published

state management inspired by mongodb aggregation

Downloads

16

Readme

reagg

State management inspired by the Mongodb Aggregation Framework.

This is possibly another saga implementation in the Redux community, but it's my favorite.

The main difference from all other Redux libraries is that you write more declarative than imperative. With reagg, you're not supposed to modify the reducer function. Instead, you enhance the payload on your Actions to inform the reducer how to manage the state. Redux developers will be amused that only a single action type is necessary.

You can gradually integrate reagg with your existing Redux reducer and actions. Over time, I suspect you will write more of your Actions with the payload requirements for reagg than your other reducer implementations.

Install

npm i -S reagg

Usage - Define Redux Actions

tl;dr

{
  type: "STATE_UPDATE",
  stages: [
    {operation, context, payload, target}
  ]
}

Some rules to follow:

  • For Redux compatibility, each action object should have a type field. For the reagg reducer to use the action, a type value of STATE_UPDATE is required.
  • operation and payload fields are required for all stages elements.
  • context and target fields are optional in stages elements, depending on the persistence you are going for.

Here is a working example

// file: myapp/src/actions.js
// you will never need to change the reducer.
// you will only define new actions and describe what is needed by the reducer in `stages`.

import reagg from 'reagg'
const operationTypes = reagg.operations;

// const newData = [
//   {title: 'scary movie', releases: [{country: 'usa', rating: 'PG-13'}]},
//   {title: 'sad movie', releases: [{country: 'usa', rating: 'R'}]}
// ]

export updateMovies = (newData) => {
  return {
    type: reagg.state.actionTypes.STATE_UPDATE, //"STATE_UPDATE",
    stages: [
      // update state object with the new list of movie entities
      {
        context: 'movies.list'.split('.'),  // existing state array to merge with
        payload: newData, // new state to be merged with existing state
        // mini-reducer that merges new and old
        operation: operationTypes.MERGE_ARRAY_ELEMENTS,
        // save the result in the same place the old state existed
        target: 'movies.list'.split('.'),
      },
      // make intermediate structure for next stage of processing
      {
        // context: // use output from above for this stage
        payload: 'releases'.split('.'), // the path to the array to be unwound
        // mini-reducer that expands elements within a nested array to another array where elements also carry info from parent object
        operation: operationTypes.UNWIND_TO_ARRAY,
        // target: // no need to save this form of the data
      },
      // update a specialized state structure
      {
        // context:  // use output from above for this stage
        // now `rating` is a top-level field, and field paths are always specified as an array
        payload: 'rating'.split('.'),
        // mini-reducer that makes an inverted index on the (deeply nested) field specified by `payload`
        operation: operationTypes.INDEX_FROM_ARRAY,
        // save the result where the app can read from for O(1) access time
        target: 'movies.byRating'.split('.'),
      }
    ]
  }
}

Usage - Dispatch Redux Actions

Simply invoke the action creator function you defined previously by passing the data from a network call.

import React from 'react'
import { useDispatch } from 'react-redux'
import Button from './components/Button'
import { updateMovies } from './actions'

const MyComponent = () => {
  const dispatch = useDispatch()
  return (
<Button onClick={() => fetch('/movies').then(data => dispatch(updateMovies(data))}>GET MOVIES</Button>
  )
}

Usage - Setup Redux Store Reducer

import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import reagg from 'reagg'
import App from './App'
import { BrowserRouter as Router } from 'react-router-dom'

// alteratively you can call the reagg reducer from your reducer.
const store = createStore(reagg.state.reduxReducer, {})

ReactDOM.render(
  <Provider store={store}>
    <Router>
      <App />
    </Router>
  </Provider>,
  document.getElementById('root')
);

Operations

Operations must conform to the interface usage:

const next = stage.operation(context, stage.payload);

Custom operations can be used in your actions. Please submit a PR if you have an operation that will be generally useful to the community.

The operations that are currently distributed is found in ./src/operations.js. The following operations are considered part of the interface of reagg:

  • REPLACE_ARRAY_ELEMENT
  • MERGE_ARRAY_ELEMENTS
  • FILTER_ARRAY
  • SORT_ARRAY
  • UNWIND_TO_ARRAY
  • MAP_ARRAY_ITEMS
  • MAP_OBJECT_FROM_KEYS
  • INDEX_FROM_ARRAY
  • ARRAY_FROM_INDEX
  • ARRAY_FROM_KEYS
  • MERGE_OBJECT_SHALLOW_PAYLOAD_CONTEXT
  • MERGE_OBJECT_SHALLOW_CONTEXT_PAYLOAD
  • OVERWRITE