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

@sedlak.r/mq

v2.0.0

Published

Message queue for events

Readme

EventEmitter

Info

Message queue for events. Is used for sending events, requests, notify information and binding events on dom elements. It is a minimalistic library (< 8kB min file) and is really simple to use it.

How to install

Install Node.js 22 or 24 (LTS lines - jsdom, used by the test suite, does not support odd-numbered releases). The package manager is pnpm, pinned by the packageManager field, so let Corepack provide it rather than installing pnpm yourself:

corepack enable
pnpm install

Scripts

| Command | What it does | | ------------------------ | ------------------------------------------------------ | | pnpm run dev | Serves index.html with the sources loaded as modules | | pnpm test | Runs the spec suite (Vitest + jsdom) | | pnpm run test:watch | Same, in watch mode | | pnpm run test:coverage | Spec suite with a V8 coverage report | | pnpm run bench | Benchmarks MQ.Store removal cost | | pnpm run lint | ESLint | | pnpm run format | Prettier, in place | | pnpm run build | Writes dist/mq.js and dist/mq.min.js |

How to release

  • pnpm install
  • commit changes
  • bump the version in package.json and add a CHANGELOG.md entry
  • pnpm run build
  • pnpm publish in the root directory

prepublishOnly re-runs lint, tests and the build, so a broken tree cannot be published.

Unlike npm publish, pnpm publish refuses to run with uncommitted changes or from a branch other than the publish branch. Releasing a prerelease from a working branch therefore needs the checks turned off explicitly:

pnpm publish --tag rc --no-git-checks

Methods

.create(context)

It's method for creating new emitter with given context. Context can be any object od any function. It is use for manipulation with handlers. More information in section "How to use it"

.event(name, params)

Call event with given name and send through given params. This function is call immediately after you call it.

.notify(name, params)

Call notify with given name and send through given params. This function is same like .event() but it can be called after same time. It's only notifier and you cannot determine when it's called, because there can be timeout due to other events, requests or notify.

.request(name, params)

Call request with given name and send through given params and get return from this call. This is similar to .event() but this function return value. This is a really special method and EventEmitter check if it's right called. If .request() has not any handler, than fail because without handler you can not get return value. Call also fail if there are more handlers than one, because you can not get return value from more functions.

.ctxRequest(name, params)

Same as .request above, but looks up for event with same context as callee

.demand(name, params)

Call request with given name and send through given params and get return from this call. This is similar to .request() but this function return value and event return undefined. If .demand() has not any handler, than do not fail and return undefined. Call also fail if there are more handlers than one, because you can not get return value from more functions.

.subscribe()

This method is used for subscribing for events, that are triggered by .event(), .notify() or .request(). You can use it for your custom events or bind it to dom element. More information in section "How to use it"

.unsubscribe()

This method is used for stop listening for events, that are triggered by .event(), .notify() or .request(). More information in section "How to use it"

Called with no arguments it drops everything registered by that emitter's context - both named events and DOM element bindings. Bindings made by other contexts on the same element are left alone.

Called with only an event name it drops that event's handlers for the context. Pass the handler too - unsubscribe(name, handler) - to remove one specific subscription rather than every handler the context has for that event.

Note that on the default context - the global EventEmitter, or an emitter that was never given a context - remove-by-name ignores both the context and the handler and drops every handler registered under that name, whichever context registered it. This is long-standing behaviour of the default context, not specific to the name-only form. Use EventEmitter.create(context) when you need removal scoped to your own subscriptions.

.interrupt(event, stopProp, cancelDef)

This function is used to stop browser event. There are parameters for stop propagation and cancel default action. It's helper function.

.watching(name)

This function is used for getting number of listener, who use .subscribe() method. If function return 0, nobody listen on event and is not necessary to call it.

.ctxWatching(name)

Same as .watching above, but looks up for event with same context as callee

.debugMode(state, filters)

You can turn on debug mode and filter some specific events. Other events will be writen into browser console with all parameters.

How to use it

You can use this library in global way. There is global variable EventEmitter.

Since 1.6 the same API is also importable, and the package ships its own types:

// installs globalThis.MQ and globalThis.EventEmitter, and exports them
import { EventEmitter, Emitter, Store, Timer } from "@sedlak.r/mq";

// identical API, but nothing is written to globalThis
import { EventEmitter } from "@sedlak.r/mq/pure";

Both entries share one registry, so an event sent through the imported emitter reaches handlers subscribed through the global one. require() works too, and dist/mq.min.js is still the file to drop into a <script src> tag.

The two styles mix freely. A library can bundle its own copy and install the global, an application can import { EventEmitter } from its own copy, and both still talk to each other:

import { EventEmitter } from "@sedlak.r/mq";

class Editor {
	constructor() {
		this.emitter = EventEmitter.create(this);
		this.emitter.subscribe("Document.changed", (data) => this.redraw(data));
	}
	destroy() {
		this.emitter.unsubscribe();
	}
}

That works because the first copy to load publishes its classes and its single emitter under Symbol.for("@sedlak.r/mq"), and every later copy adopts them instead of building a second Store. Without it, duplicate copies each get their own bus and events silently fail to cross - no error, just handlers that never fire. If the copies are different versions the older one wins, and a warning names both so the duplicate can be deduplicated.

Example 1

EventEmitter.subscribe("MyEvent", function (data) {
	console.log("You handler for event");
});
EventEmitter.event("MyEvent");
EventEmitter.event("MyEvent", [true, "param2"]);

In this example you can see basic usages of emitter. You can subscribe for event and call event with or without parameters. But there are two main problems. You can not destroy this handler for MyEvent, because you don't have original handler and also you don't have context, so in handler is invalid pointer on this. We can make modification for first problem.

Example 1 - first problem solve

var handler = function (data) {
	console.log("You handler for event");
};
EventEmitter.subscribe("MyEvent", handler);
EventEmitter.event("MyEvent");
EventEmitter.event("MyEvent", [true, "param2"]);
EventEmitter.unsubscribe("MyEvent", handler);

So now we can unsubscribe our event. Now we must solve the second problem. Context.

Example 1 - second problem solve

var emitter,
	context = {},
	handler = function (data) {
		console.log("You handler for event with context from 'context' variable.");
	};
emitter = EventEmitter.create(context);
emitter.subscribe("MyEvent", handler);
emitter.event("MyEvent");
emitter.event("MyEvent", [true, "param2"]);
emitter.unsubscribe("MyEvent", handler);

Now we have solve second problem. This is the recommended use of EventEmitter. In every file create new instance with this as a context. If you implemented destroy on object, you can call emitter.unsubscribe() and all handlers for context will be destroyed. So we can update last example for complete clean all events.

Example 2

var emitter,
	context = {},
	handler = function (data) {
		console.log("You handler for event wit context from 'context' variable.");
	};
emitter = EventEmitter.create(context);
emitter.subscribe("MyEvent", handler);
emitter.subscribe("MyEventSecond", handler);
emitter.event("MyEvent");
emitter.event("MyEvent", [true, "param2"]);
emitter.unsubscribe();

And last part is binding to DOM elements. It's easy like others thing before.

Example 3

var emitter,
	context = {},
	handler = function (data) {
		console.log("Clicked on body and destroy.");
		emitter.unsubscribe();
	};
emitter = EventEmitter.create(context);
emitter.subscribe(document.body, "click", handler);

The bare emitter.unsubscribe() above really does detach the click listener. Before 2.0 it did not, and the binding had to be removed explicitly with emitter.unsubscribe(document.body, "click", handler).

Licence

MIT License

Copyright (c) 2022 Radek Sedlák
Copyright (c) 2015 Stanislav Hacker

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

The Software shall be used for Good, not Evil.