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

@actualwave/messageport-dispatcher

v1.1.10

Published

Cross-domain EventDispatcher for MessagePort interface

Readme

MessagePortDispatcher

MessagePortDispatcher is an extended API for cross-origin communication. It wraps the MessagePort API available on window, Worker, and other targets to send and receive typed custom events across <iframe> boundaries, Web Workers, and any object that implements the MessagePort interface. Internally it uses two EventDispatcher instances — one for incoming events and one for outgoing.

Demo with two <iframe>'s talking to each other

Installation

npm install @actualwave/messageport-dispatcher
yarn add @actualwave/messageport-dispatcher

Usage

Instantiate with any object that implements the MessagePort interface (postMessage, addEventListener, removeEventListener):

const dispatcher = new MessagePortDispatcher(iframe.contentWindow);

Communicating across an iframe boundary

In the outer document, pass the iframe's contentWindow:

import { MessagePortDispatcher } from '@actualwave/messageport-dispatcher';

const frameDispatcher = new MessagePortDispatcher(iframeNode.contentWindow);
frameDispatcher.addEventListener('initialized', () => {
  console.log('Communication channel is open.');
});

Inside the iframe, use getForSelf():

import { getForSelf } from '@actualwave/messageport-dispatcher';

const dispatcher = getForSelf();
dispatcher.dispatchEvent('initialized');

getForSelf(), getForParent(), and getForTop() return cached singletons, so they always return the same instance.

Sending and receiving events

// Send to the other side
dispatcher.dispatchEvent('someEvent', { someData: 'anything here' });

// Receive on the other side
dispatcher.addEventListener('someEvent', (event) => {
  console.log('Data received', event.data);
});

dispatchEvent() serialises the event and calls postMessage() — it does not fire the event locally on receiver. To observe sent events locally, listen on sender:

dispatcher.sender.addEventListener('someEvent', () => {
  console.log('Outgoing event observed');
});
dispatcher.dispatchEvent('someEvent');

Custom adapter target

const target = {
  postMessage: (data, origin) => {
    console.log('Message sent', data);
    window.postMessage(data, origin);
  },
  addEventListener: (eventType, handler) => {
    window.addEventListener(eventType, handler);
  },
  removeEventListener: (eventType, handler) => {
    window.removeEventListener(eventType, handler);
  },
};
const dispatcher = new MessagePortDispatcher(target);

MessagePortTarget

MessagePortTarget is a convenience wrapper for cases where sending and receiving are handled by different objects — for example, an iframe's contentWindow for sending and your own window for receiving:

import { MessagePortDispatcher, MessagePortTarget } from '@actualwave/messageport-dispatcher';

const frameDispatcher = new MessagePortDispatcher(
  new MessagePortTarget(iframeNode.contentWindow, window),
);

It also accepts arrays for broadcasting to or receiving from multiple targets:

const frameDispatcher = new MessagePortDispatcher(
  new MessagePortTarget(
    [iframe1.contentWindow, iframe2.contentWindow, iframe3.contentWindow],
    window,
  ),
);

Data serialisation

Because events cross origin boundaries, only serialisable data can be transferred. Before sending, dispatchEvent checks the event's data value:

  • If the value has a toJSON() method, its return value is sent as-is (structured clone). The developer is responsible for converting nested objects.
  • Otherwise the value is JSON.stringify-d, then parsed back on the receiving side.

Dispatcher ID and echo suppression

Each MessagePortDispatcher instance generates a unique dispatcherId. When a sent event is echoed back (which happens with window.postMessage), the dispatcher detects its own ID and routes the echo to the sender EventDispatcher instead of receiver, preventing false local dispatch.

API

MessagePortDispatcher constructor

| Parameter | Type | Description | |---|---|---| | target | MessagePortLike \| null | Object with postMessage and addEventListener. Defaults to self. | | customPostMessageHandler | Function \| null | Replaces the default target.postMessage() call. | | receiverEventPreprocessor | EventProcessor \| null | Transforms incoming events before listeners are called. | | senderEventPreprocessor | EventProcessor \| null | Transforms outgoing events before postMessage is called. |

MessagePortDispatcher instance members

| Member | Type | Description | |---|---|---| | dispatcherId | string | Unique ID for this instance. | | targetOrigin | string | Passed to postMessage as the target origin. Defaults to '*'. | | target | MessagePortLike | The underlying message port object. | | sender | IEventDispatcher | Fires outgoing events (echoes of sent messages). | | receiver | IEventDispatcher | Fires incoming events received from the other side. | | addEventListener(type, listener, priority?) | void | Delegates to receiver.addEventListener. | | hasEventListener(type) | boolean | Delegates to receiver.hasEventListener. | | removeEventListener(type, listener) | void | Delegates to receiver.removeEventListener. | | removeAllEventListeners(type) | void | Delegates to receiver.removeAllEventListeners. | | dispatchEvent(eventType, data?, transferList?) | void | Serialises and sends the event via postMessage. |

Factory functions

| Function | Description | |---|---| | getForSelf() | Cached dispatcher for self (current window / worker). | | getForParent() | Cached dispatcher for parent window. | | getForTop() | Cached dispatcher for top window. | | createMessagePortDispatcher(target?, ...) | Creates a new MessagePortDispatcher instance. |

MessagePortTarget

| Member | Description | |---|---| | constructor(sender?, receiver?) | Accepts single objects or arrays of objects for each role. | | postMessage(...args) | Calls postMessage on all senders. | | addEventListener(type, handler) | Calls addEventListener on all receivers. | | removeEventListener(type, handler) | Calls removeEventListener on all receivers. |

TypeScript

The package ships with TypeScript declarations. Types from @actualwave/event-dispatcher are also available for event typing:

import {
  MessagePortDispatcher,
  MessagePortTarget,
  MessagePortEvent,
  createMessagePortDispatcher,
  getForSelf,
  getForParent,
  getForTop,
} from '@actualwave/messageport-dispatcher';

import type { EventListener, EventProcessor } from '@actualwave/event-dispatcher';

const preprocessor: EventProcessor = (event) => {
  return { ...event, data: { ...(event.data as object), timestamp: Date.now() } };
};

const dispatcher = new MessagePortDispatcher(iframe.contentWindow, null, preprocessor);

const handler: EventListener = (event) => {
  console.log(event.type, event.data);
};

dispatcher.addEventListener('myEvent', handler);
dispatcher.dispatchEvent('myEvent', { payload: 42 });