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 🙏

© 2024 – Pkg Stats / Ryan Hefner

mesh-comm

v0.0.5

Published

MeshComm is a lightweight JavaScript library that enables micro-frontends or modules to communicate within a single browser window using messages. Utilizing the `window.postMessage` API as its underlying transport mechanism, MeshComm enables message-based

Downloads

99

Readme

MeshComm

MeshComm is a lightweight JavaScript library that enables micro-frontends or modules to communicate within a single browser window using messages. Utilizing the window.postMessage API as its underlying transport mechanism, MeshComm enables message-based communication without requiring external dependencies. It supports both broadcast-style messages and request-response messaging between nodes, including optional exclusive listener patterns.

Concept Overview

MeshComm provides decentralized networks, each identified by a unique name and always available for direct access. Within each network, endpoints are automatically created when nodes are added at runtime, serving as targets for handling messages.

MeshComm supports two types of communication:

  • Broadcast Messages: Send messages to all nodes or filter them using patterns (e.g., wildcards like *).
  • Request-Response Messages: Send requests to specific nodes and expect a response (for each request, only one node will send a response, even if multiple nodes can handle the message).

Nodes can be marked as exclusive, meaning only one node can occupy a specific endpoint, ensuring no conflicts. In contrast, non-exclusive nodes can share the same endpoint, allowing multiple nodes to coexist at the same endpoints.

Messages can be broadcast, reaching all nodes that match a specific pattern, or sent as request-response pairs, where replies are expected from a particular node. This flexibility makes MeshComm ideal for a wide range of use cases, especially in micro-frontend architectures.

Features

  • Broadcast Messages: Send messages to all nodes or filter them using patterns (e.g., wildcards like *).
  • Request-Response Messages: Send requests to specific nodes and expect a response (for each request, only one node will send a response, even if multiple nodes can handle the message).
  • Exclusive Listeners: Prevent multiple nodes from handling the same endpoint simultaneously.
  • Abortable Requests: Set timeouts or abort requests using AbortController.
  • Singleton Mesh Instances: Access multiple instances of mesh networks, each identified by a unique name.
  • Same-Origin Security: Ensures that communication between the sender and recipient is restricted to the same origin.

Installation

You can install MeshComm via npm:

npm install mesh-comm

or yarn:

yarn add mesh-comm

Basic Usage

Accessing a Mesh Network

MeshComm allows you to have multiple mesh networks simultaneously. Each network is identified by a unique name. Networks exist by default, and you simply retrieve a reference to them.

import MeshComm from 'mesh-comm';

// Get a reference to the mesh instance by name
const mesh = MeshComm('my-mesh');

Adding Nodes

You can add nodes to the mesh that can either handle broadcast messages or participate in request-response patterns.

Example 1: Exclusive Node

// Node 1
mesh.add(
  '/authenticator',
  async (msg: { type: string }) => {
    switch (msg.type) {
      case 'GET_ACCESS_TOKEN':
      // return the access token, if any
      case 'IS_USER_LOGGED_IN':
      // return whether the user is logged in
    }
  },
  { exclusive: true } // No other node can share this endpoint
);

Example 2: Non-Exclusive Nodes

// Node 2
mesh.add('/storage/messages', async (msg: { type: 'GET_UNREAD_MESSAGE_COUNT' } | { type: 'USER_AUTHENTICATED'; authenticated: boolean }) => {
  switch (msg.type) {
    case 'GET_UNREAD_MESSAGE_COUNT': {
      // return unread message count
      break;
    }
    case 'USER_AUTHENTICATED': {
      // probably, clean cache if the user isn't authenticated any longer
      // or, eagerly load the number of unread messages if the user is now logged in
    }
    case 'RESET': {
      // just clean cache
    }
  }
});

// Node 3
mesh.add('/storage/messages', async (msg: { type: 'GET_MESSAGE'; id: number }, options?: RequestOptions) => {
  switch (msg.type) {
    case 'GET_MESSAGE': {
      const token = await mesh.request('/authenticator', { type: 'GET_ACCESS_TOKEN' }); // this is exclusively proccessed by Node 1
      // now let's make a request to the API to get the message
      break;
    }
    case 'USER_AUTHENTICATED': {
      // probably, clean cache if the user isn't authenticated any longer
    }
    case 'RESET': {
      // just clean cache
    }
  }
});

Sending Messages

You can send broadcast messages to all nodes or select specific patterns.

Broadcast to All Nodes

mesh.send('/*', { type: 'USER_AUTHENTICATED', authenticated: true }); // this will be delivered to all 3 nodes
mesh.send('/storage/*', { type: 'RESET' }); // this will be delivered to Node 2 and Node 3 only

Request-Response

Request a response from a specific node. You can also provide an abort signal or timeout.

const message = await mesh.request('/storage/messages', { type: 'GET_MESSAGE', id: 123 }); // though this is delivered to both Node 2 and Node 3, only Node 3 will process and respond.

Handling Timeouts

Sending broadcast messages, we aren't concerned whether there is any node. However, when it comes to sending request-response messages, there are cases when the node(s) is(are) not added yet to the endpoint. This is addressed with a timeout, which default value is 5000ms, which works this way:

// one of the nodes attempts to send a request-response message:
try {
  const message = await mesh.request('/storage/messages', { type: 'GET_MESSAGE', id: 123 }, { timeout: 5_000 });

  // The following process occurs behind the scenes:
  //
  // 1. The mesh checks if any nodes are registered at the target endpoint:
  //   - If yes, the message is sent to those nodes (note: this does not guarantee that any node is interested in this request).
  //   - If no, It waits for up to 5000ms for a node to register at the endpoint.

  // 2. If a response is received within 5000ms, the promise resolves successfully.

  // 3. If no response is received within 5000ms, the promise is rejected. This could happen for two reasons:
  //   - (a) There are nodes at the endpoint, but none are able to process the request.
  //   - (b) Processing the request is taking longer than 5000ms.

  // 4. If no nodes are added to the endpoint within 5000ms, the promise is also rejected.
} catch (error) {
  if (error instanceof MeshTimeoutError /* or, alternatively, error.name === 'MeshTimeoutError' */) {
    // Processing the request took longer than 5000ms or no node, at the target endpoint, could process it (3)
  }
  if (error instanceof MeshNoNodeError /* or, alternatively, error.name === 'MeshNoNodeError' */) {
    // No node registered at the target endpoint within 5000ms
  }
}

Handling Abort

Abortable Requests are particularly useful in user-driven interfaces where operations may need to be canceled due to timeouts or user action (this highlights a practical use case). You can use AbortController to abort requests.

const abortCtrl = new AbortController();

// Abort request if the user clicks button
const onButtonClick = () => {
  abortCtrl.abort();
};

try {
  const user = await mesh.request('/storage/users', { type: 'GET_USER', id: 123 }, { signal: abortCtrl.signal, timeout: 5_000 });
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request aborted');
  }
  if (error.name === 'MeshTimeoutError') {
    console.error('Request timed out');
  }
}

Debugging

If you need to debug communications between nodes, mesh-comm provides an easy way to see all message exchanges in the console.

To enable logging, simply add into your script:

MeshComm.logger.enable();

This will echo all communication between nodes to the console, which can be useful for tracking messages, requests, and responses during development.

Security Considerations

MeshComm leverages the window.postMessage API for communication, which ensures that messages can only be transmitted within the same window object. Currently, the library does not support communication across multiple window instances or between different iframes. All message sending and receiving is confined to the same window context.

Additionally, MeshComm enforces same-origin policies to ensure secure communication. This means that both the sender and the recipient of a message must be from the same origin (i.e., they share the same protocol, domain, and port). This built-in security feature ensures that malicious scripts or unauthorized third parties cannot intercept or send messages between different origins, providing an extra layer of security.

Key Points:

  • Communication is restricted to within a single window instance.
  • No support for cross-window or cross-iframe messaging.
  • Enforces same-origin communication to prevent unauthorized message interception or sending.

Playground

Please see packages/example

License

This project is licensed under the MIT License. See the LICENSE file for details.