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




Tiny message bus




nanobus stability

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

Tiny message bus.


var nanobus = require('nanobus')
var bus = nanobus()

bus.on('foo', function (color) {
  console.log('color is', color)

bus.emit('foo', 'blue')


Why not use the Node API?

We had the requirement for a * event to catch all calls, and figured we could improve the file size at the same time. This library is about 1/3rd the size of Node's version. And it was easy to build, so yeah good enough of an excuse hah.

How do I listen for replies?

You can do this by using the .once() listener and establishing a convention around naming schemas.

bus.on('foo', function (color) {
  console.log('foo called')

bus.once('foo:res', function () {
  console.log('response received')

When shouldn't I use this package?

If you're only writing code that runs inside Node and don't need a '*' listener, consider using the built-in event emitter API instead.

Are the emitters asynchronous?

No. If you're interested in doing that, use something like nanotick to batch events and ensure they run asynchronously.


bus = nanobus([name])

Create a new nanobus instance. Optionally takes a name that will be used for tracing in the browser using the performance.mark / performance.measure API.

bus.emit(eventName, [data])

Emit an event. Arbitrary data can optionally be passed as an argument. '*' listeners run after named listeners.

bus.on(eventName, listener([data]))

bus.addListener(eventName, listener([data]))

Listen to an event. If the event name is '*' the listener signature is listener(eventName, [data], [performanceTimingId]).

bus.prependListener(eventName, listener([data]))

Listen to an event, but make sure it's pushed to the start of the listener queue. If the event name is '*' the listener signature is listener(eventName, [data]).

bus.once(eventName, listener([data]))

Listen to an event, and clear it after it's been called once. If the event name is '*' the listener signature is listener(eventName, [data], [performanceTimingId]).

bus.prependOnceListener(eventName, listener([data]))

Listen to an event, and clear it after it's been called once. If the event name is '*' the listener signature is listener(eventName, [data]).

bus.removeListener(eventName, listener)

Remove a specific listener to an event.

listeners = bus.listeners(eventName)

Return all listeners for a given event. '*' listeners are not included in this list. Use bus.listeners('*') to get a list of '*' listeners.


Remove all listeners to an event. If no event name is passed, removes all listeners on the message bus. '*' listeners are not removed unless eventName is * or no event name is passed.


Optional event typing is available in TypeScript by passing an object type with event names as keys and event listener function signatures as values.

// if compilerOptions.esModuleInterop = true
import Nanobus from "nanobus"
// else
import Nanobus = require("nanobus") 

type Events = {
    foo: (color: string) => void
    bar: (count: number) => void

const bus = new Nanobus<Events>()

bus.on("foo", color => {
    // color: string
    console.log("color is", color)

bus.on("bar", count => {
    // count: number
    console.log("count is", count)

bus.on("*", (eventName, data) => {
    // eventName: "foo" | "bar"
    // data: any[]
    if (eventName === "foo") {
        const [color] = data as Parameters<Events["foo"]>
        // color: string
    } else if (eventName === "bar") {
        const [count] = data as Parameters<Events["bar"]>
        // count: number

bus.emit("foo", "blue")  // required arguments: [string]
bus.emit("bar", 100)  // required arguments: [number]