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

@mnjs/radio

v5.0.0-beta.6

Published

Channels and request/reply messaging for Marionette

Readme

@mnjs/radio

Named channels for events and request/reply, usable without Marionette core or a DOM.

npm install @mnjs/[email protected]
import { Radio, createRadio } from '@mnjs/radio';

const channel = Radio.channel('app');
channel.reply('title', () => 'Hello');
channel.on('refresh', () => console.log('Refreshing'));
channel.request('title');
channel.trigger('refresh');

const isolatedRadio = createRadio();

Radio is the default instance also exported by marionette. Within the same module format and package installation, either import reaches the same channels. createRadio() creates an independent channel registry. Each createMarionette() runtime also owns its own Radio instance; use that runtime's Radio when binding its objects and applications.

The package depends on @mnjs/utils, which supplies Events and shared helpers. It does not depend on core. ESM and CommonJS exports include Radio, createRadio, Channel, Requests, and their public types. ESM and CommonJS each have their own default instance; do not mix the two formats to share a channel registry.

Radio, utils, data, adapters, and core are versioned and released together.

Standalone messaging

import { Channel, Requests } from '@mnjs/radio';

const local = new Channel('editor');
local.on('save', () => console.log('Saved'));
local.reply('title', 'Untitled');

const service = Object.assign({}, Requests);
service.reply('ready', true);

new Channel(name) creates an independent Events-and-Requests object. It is not registered with Radio; call its reset() to remove its handlers and owned listeners. Two standalone channels with the same name are still separate objects. Radio.reset() only covers channels obtained through Radio.channel(name).

The named Channel export is Radio.Channel. Use new isolatedRadio.Channel(name) when a standalone channel should share a particular Radio instance's logging configuration. Requests adds only request/reply methods to its receiver; it uses the default Radio's warning configuration.

Logging

Assign radio.log(channelName, eventName, ...args) to receive activity from tuneIn(), and radio.debugLog(warning, eventName, channelName) to receive diagnostics. The defaults write to the console.

const radio = createRadio();
radio.log = (channel, event, ...args) => console.log({ channel, event, args });
radio.debugLog = (warning, event, channel) => console.warn({ warning, event, channel });
radio.setDebug();
radio.tuneIn('app');

Each Radio instance owns its hooks. They run with that Radio as this, and existing channels use the current hook, even when it is replaced after tuneIn(). setDebug(false) suppresses warning delivery to custom hooks too. Standalone channels use their constructor's Radio configuration; the shared default Requests mixin uses the default Radio. Hook exceptions propagate to the caller.