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

@quazardous/quarkernel

v2.4.0

Published

Micro Custom Events Kernel with dependency ordering, shared context, and composite events

Readme

QuarKernel

npm version bundle size license

Event orchestration: dependency ordering, shared context and composite events.

TypeScript-first. Zero dependencies. ~4.8 kB gzipped for the kernel, state machines in a separate entry (sizes).

Try QK Studio Try FSM Studio


Why QuarKernel?

// Other event libs: fire and pray
emitter.emit('user:login', data);

// QuarKernel: orchestrate with confidence
qk.on('user:login', fetchUser, { id: 'fetch' });
qk.on('user:login', logAnalytics, { after: ['fetch'] }); // Guaranteed order
qk.on('user:login', (e) => greet(e.context.user));       // Shared context

What makes it different:

mitt and eventemitter3 are simple synchronous event buses, and much smaller. emittery adds async listeners. QuarKernel is for when listeners must be orchestrated: run in a given order, share data, and react to combinations of events.

| Feature | mitt | eventemitter3 | emittery | QuarKernel | |---------|:----:|:-------------:|:--------:|:--------------:| | Awaitable emit() (async listeners) | - | - | Yes | Yes | | Serial emit | - | - | Yes | Yes | | Promise-based once() | - | - | Yes | Yes | | Catch-all listener | Yes (*) | - | Yes (onAny) | Yes | | Wildcard patterns (user:*) | - | - | - | Yes | | Listener priority | - | - | - | Yes | | Dependency ordering (after) | - | - | - | Yes | | Shared context per emit | - | - | - | Yes | | Composite events | - | - | - | Yes | | State machines | - | - | - | Yes (/fsm) | | TypeScript types | Yes | Yes | Yes | Yes | | Size (min + gzip) | 0.2 kB | 1.3 kB | 2.2 kB | 4.8 kB (createKernel) |

Sizes measured with esbuild (minified ESM) + gzip: mitt 3.0.1, eventemitter3 5.0.4, emittery 1.2.0, QuarKernel 2.4.0.


Install

npm install @quazardous/quarkernel
<!-- CDN -->
<script src="https://unpkg.com/@quazardous/quarkernel@2/dist/index.umd.js"></script>

Requirements

  • Node.js 18+, or any modern browser (the code uses ES2022 syntax)
  • ES modules (import), CommonJS (require), and a QuarKernel global from the UMD build for <script> tags
  • TypeScript types included
  • Release notes in the CHANGELOG

Size

Minified + gzipped, measured with esbuild on 2.4.0. The publish workflow enforces a budget per entry point (npm run size --workspace=packages/quarkernel).

| Import | min + gzip | |--------|-----------:| | @quazardous/quarkernel, createKernel only | 4.8 kB | | @quazardous/quarkernel, whole entry | 7.6 kB | | @quazardous/quarkernel/fsm | 6.1 kB (includes the kernel, shared with the core entry) | | @quazardous/quarkernel/xstate | 1.1 kB |

The ES module entries share a single copy of the kernel, so importing both the core and /fsm adds nothing on top of /fsm. The CommonJS builds (require) are self-contained: requiring both loads the kernel twice.

Latest published version: core size core, fsm size fsm


Quick Start

import { createKernel } from '@quazardous/quarkernel';

const qk = createKernel();

// 1. Dependency ordering - control execution sequence
qk.on('checkout', async (e) => {
  e.context.inventory = await checkStock(e.data.items);
}, { id: 'stock' });

qk.on('checkout', async (e) => {
  // Runs AFTER stock check - guaranteed
  await processPayment(e.data.card, e.context.inventory);
}, { after: ['stock'] });

await qk.emit('checkout', { items: ['sku-123'], card: 'tok_visa' });
// 2. Composite events - react to event combinations
const checkout = qk.when(['cart:ready', 'payment:confirmed']);

checkout.onComposed(() => {
  console.log('Both events fired - proceed to shipping!');
});

// Promise form: await checkout.once(), then checkout.dispose() when done
// Across several kernels: new Composition([[kernelA, 'a'], [kernelB, 'b']])
// 3. Wildcards - catch event patterns
qk.on('user:*', (e) => console.log('User action:', e.name));
// Matches: user:login, user:logout, user:signup...

Semantics

Execution order. emit() runs listeners level by level. Listeners without after form the first level; any other listener runs in the level right after its deepest dependency. Listeners of the same level run in parallel and start in priority order (highest first). Each level waits until the previous one has finished, including async work. emitSerial() follows the same order, one listener at a time.

Context. Every emit creates a fresh event.context object. All listeners of that emit share it by reference (it is not cloned), and no other emit sees it, so concurrent emits of the same event never mix their context.

Errors. By default (errorBoundary: true), a failing listener is reported to onError (console.error unless you pass your own) and the other listeners keep running, including the ones that depend on it; emit() resolves with the errors of that emit (also available to listeners as event.errors). With errorBoundary: false, emit() still runs every listener and then rejects with an AggregateError, while emitSerial() stops at the first failure and rejects with that error. Anything a listener wrote to context before throwing stays visible to later listeners. A missing or cyclic after dependency always rejects the emit.

const qk = createKernel({
  errorBoundary: true, // default
  onError: (error, event) => report(error, event.name),
});

const errors = await qk.emit('import:run', file); // [] when every listener succeeded
errors.forEach(({ listenerId, error }) => console.warn(listenerId, error.message));

Concurrency. Emits are not queued: overlapping emits run their listeners interleaved, each with its own context. An emit keeps the listeners it started with; listeners added or removed during an emit only take effect on the next one. event.stopPropagation() skips the listeners that have not started yet.


Cleanup

const off = qk.on('user:login', handler);
off();                              // remove this listener

qk.off('user:login', handler);      // same, by reference
qk.off('user:login');               // every listener of an event
qk.offAll();                        // every listener

// Remove several listeners at once with an AbortSignal
const controller = new AbortController();
qk.on('tick', onTick, { signal: controller.signal });
qk.on('tock', onTock, { signal: controller.signal });
controller.abort();

// From inside a listener
qk.on('job:progress', (e, ctx) => {
  if (e.data.done) ctx.off();
});

// Run only once
qk.on('app:ready', init, { once: true });

Promises

import { createMachine } from '@quazardous/quarkernel/fsm';

// Next occurrence of an event (rejects after the timeout)
const login = await qk.once('user:login', { timeout: 5000 });
console.log(login.data);

// A combination of events
const ready = qk.when(['user:ready', 'config:ready']);
const { data } = await ready.once({ timeout: 5000 });
ready.dispose();

// A state machine reaching a state
const order = createMachine({ /* ... */ });
const { from, context } = await order.waitFor('confirmed', { timeout: 10000 });

State Machines (optional)

Need explicit states on top of events? The optional @quazardous/quarkernel/fsm entry adds finite state machines built on the kernel, using an XState-compatible config. It is a separate import: it adds nothing to your bundle unless you use it.

import { createMachine } from '@quazardous/quarkernel/fsm';

const order = createMachine({
  id: 'order',
  initial: 'draft',
  states: {
    draft: { on: { SUBMIT: 'pending' } },
    pending: { on: { APPROVE: 'confirmed', REJECT: 'draft' } },
    confirmed: {}
  }
});

await order.send('SUBMIT');
console.log(order.state); // 'pending'

Behavior helpers, auto-timers and XState import/export are covered in Async Patterns and Advanced Patterns. Try machines visually in FSM Studio.


Framework Adapters

Official bindings with auto-cleanup on unmount:

| Package | Framework | Docs | |---------|-----------|------| | @quazardous/quarkernel-vue | Vue 3 | README | | @quazardous/quarkernel-react | React 18+ | README | | @quazardous/quarkernel-svelte | Svelte 5 | README |

# Vue
npm install @quazardous/quarkernel @quazardous/quarkernel-vue

# React
npm install @quazardous/quarkernel @quazardous/quarkernel-react

# Svelte
npm install @quazardous/quarkernel @quazardous/quarkernel-svelte

Documentation

Guides:

Packages:

Resources:


Use Cases

Request pipeline - Auth, validate, transform, respond in guaranteed order

Game events - Combo detection with composite events

Form wizards - Step dependencies with shared validation context

Order workflows - State machines for order lifecycle (draft → pending → confirmed → shipped)

Analytics - Wildcard listeners for all track:* events

Microservices - Event choreography with dependency graphs

UI flows - FSM-driven modals, wizards, and multi-step forms


License

MIT - Made by quazardous