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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@async-kit/eventx

v0.2.0

Published

Typed async event bus with error isolation, concurrency control, middleware, and AbortSignal support for JavaScript/TypeScript

Readme

@async-kit/eventx

Typed publish/subscribe event bus with middleware, concurrency control, once subscriptions, sequential/parallel emit, and AbortSignal support.

Install

npm install @async-kit/eventx

Quick start

import { createBus } from '@async-kit/eventx';

type AppEvents = {
  userCreated: { id: number; email: string };
  orderPaid:   { orderId: string; amount: number };
};

const bus = createBus<AppEvents>();

bus.on('userCreated', async ({ id, email }) => {
  await sendWelcomeEmail(email);
});

await bus.emit('userCreated', { id: 1, email: '[email protected]' });

Features

| Feature | Description | |---|---| | Typed events | Full TypeScript inference — payload types enforced per event | | Parallel / sequential | Choose emit mode per-call or set a global default | | Concurrency control | concurrency: 1 makes a listener process events one at a time | | Once | Auto-unsubscribe after first invocation | | Middleware | Intercept every listener call (logging, auth, tracing) | | AbortSignal | Cancel sequential dispatches mid-flight | | Error handling | Global onError or per-listener ignoreErrors | | Stats | emitted, dispatched, errors, listeners snapshot |

API

createBus<Events>(options?)

const bus = createBus<AppEvents>({
  defaultMode: 'parallel',       // or 'sequential'
  onError: (event, err, ctx) => logger.error({ event, err }),
  middleware: [loggingMiddleware],
});

bus.on(event, listener, options?)

const off = bus.on('userCreated', async (payload, ctx) => {
  console.log(ctx.seq, ctx.emittedAt);
}, { concurrency: 2, ignoreErrors: false });

off(); // unsubscribe

bus.once(event, listener, options?)

Fires once, then auto-removes.

bus.emit(event, payload, options?)

const ac = new AbortController();
await bus.emit('orderPaid', { orderId: 'x', amount: 100 }, {
  mode: 'sequential',
  signal: ac.signal,
});

bus.off(event?)

Remove all listeners for one event, or all events.

bus.listenerCount(event)

bus.stats()

{ emitted: number; dispatched: number; errors: number; listeners: number }

Middleware

import type { Middleware } from '@async-kit/eventx';

const timing: Middleware<AppEvents> = async (event, payload, next) => {
  const start = Date.now();
  await next();
  console.log(event, Date.now() - start, 'ms');
};

const bus = createBus<AppEvents>({ middleware: [timing] });

EventContext

Every listener receives a second ctx argument:

interface EventContext {
  event: string;    // event name
  seq: number;      // monotonically increasing emit sequence
  emittedAt: number; // ms since epoch
  signal: AbortSignal;
}

Examples

Fan-out with concurrency guard

bus.on('orderPaid', processOrder, { concurrency: 1 }); // queue, never parallel

One-time setup listener

bus.once('appReady', () => startHealthChecks());

Sequential audit log

await bus.emit('userDeleted', { id }, { mode: 'sequential' });
// each listener finishes before the next starts

License

MIT