npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details


  • User packages



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.


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




Wrap handlers to use pull-stream




choo-pull stability

npm version build status test coverage downloads js-standard-style

Wrap handlers to use pull-stream in a choo plugin. This is intended to go beyond basic choo usage, and tread into the domain of managing asynchronous complexity using streams / FRP.

While streams code takes longer to write up front, resulting code is generally stateless, pretty damn fast and surprisingly reusable. pull-streams are a minimal version of streams that weigh 200 bytes and handle backpressure phenomenally.


const pull = require('choo-pull')
const choo = require('choo')

const app = choo()

const tree = app.start()

Now each handler in a model expects a valid through pull-stream to be returned synchronously. Initial data will be passed as the source, errors handling and done() calls are appended in the sink:

const through = require('pull-through')
const ws = require('pull-ws')
const xhr = require('xhr')

module.exports = {
  namespace: 'my-model',
  state: {
    count: 0
  reducers: {
    increment: (data, state) => ({ count: state.count + data }),
    decrement: (data, state) => ({ count: state.count - data }),
  subscriptions: {
    getDataFromSocket: (Send$) => {
      const ws$ = Ws$('wss://')
      return pull(ws$, Deserialize$(), Send$('performXhr'))
  effects: {
    performXhr: (state, Send$) => pull(Xhr$(), Deserialize$())

function Xhr$ () {
  return through((data, cb) => {
    xhr('/foo/bar', { data: data }, (err, res) => {
      if (err) return cb(err)
      cb(null, res)

function Deserialize$ () {
  return through((data, cb) {
    try {
      cb(null, JSON.parse(data))
    } catch (e) {

function Ws$ (url) {
  return ws(new window.WebSocket(url))

Using send()

Like all other API methods, so too does the send() method become a pull-stream. More specifically it becomes a through stream that takes the action name as the sole arugment, and pushes any results into any a connecting through or sink stream:

const through = require('pull-through')

module.exports = {
  state: {
    count: 0
  reducers: {
    bar: (state) => ({ state.count + data })
  effects: {
    callBar: (state, prev, Send$) => Send$('bar'),
    callFoo: (state, prev, Send$) => Send$('foo')

// send('callFoo', 1)
// => state.count = 1


hooks = pull(opts)

Create an object of hooks that can be passed to app.use(). Internally ties into the following hooks:

  • wrapSubscriptions: changes the API of subscriptions to be (Send$)
  • wrapEffects: changes the API of effects to be (state, Send$)

The following options can be passed:

  • opts.subscriptions: default: true. Determine if subscriptions should be wrapped
  • opts.effects: default: true. Determine if effects should be wrapped

Incrementally enabling options can be useful when incrementally upgrading from a CSP-style codebase to a reactive / streaming one.


Wrap a single subscription. Useful to incrementally upgrade a CSP-style codebase to a reactive / streaming one.


Wrap a single effect. Useful to incrementally upgrade a CSP-style codebase to a reactive / streaming one.


Why aren't reducers wrapped in pull-streams?

In choo@3 the internal workings demand that data always be returned synchronously. Because pull-stream returns data in a callback, reducers cannot be wrapped. Perhaps at some point we'll allow for a hybrid API, but at this point it's frankly not possible.


$ npm install choo-pull