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

@waelio/messaging

v2.3.0

Published

A real-time messaging application with direct & broadcast messages, user lists, and optional MongoDB persistence.

Readme

waelio-messaging

npm version npm downloads CI License: MIT

Real-time messaging hub powered by FeathersJS channels and Socket.io — direct messages, broadcasts, private rooms, user lists, history, and optional MongoDB persistence.

Live Demo: https://waelio-messaging.onrender.com/

What is this?

waelio-messaging gives you:

  • a real-time Socket.io server built on FeathersJS channels (no REST)
  • a ready-to-use chat UI (public/index.html)
  • direct message + broadcast + private rooms + message history
  • optional MongoDB persistence (falls back to in-memory automatically)

The original MessagingHub (raw ws) is kept as a standalone library export. The server now uses a Feathers app layered on top, replacing the hand-rolled broadcast loops with declarative channel routing.

If you just want to run and chat locally, use the 5-minute guide below.

5-minute start (recommended)

1) Install dependencies

npm install

2) Start the app

npm run dev

3) Open the app

Open your browser at:

  • http://localhost:8080

4) Test chat quickly

Open 2 browser tabs to the same URL and:

  • send a direct message
  • click Broadcast for all users
  • click History to load previous messages

How to use the UI

  • Users Online (left): pick a user for direct messages
  • Send: sends to selected user
  • Broadcast: sends to everyone
  • History: loads saved/in-memory message history
  • Room Start/Leave: optional focused room messaging
  • Install (when shown): install the PWA

Background activity indicators

When the tab is in background and a new message arrives, the app shows:

  • unread count in the tab title
  • a favicon badge
  • pulsing activity dot + count in the header

The indicator clears when you return to the tab/window.

PWA (Installable Client)

The bundled UI under public/ is a Progressive Web App:

  • Installable on desktop and mobile (manifest + service worker)
  • Basic offline support (core assets cached, navigation fallback)
  • Install prompt via beforeinstallprompt

Troubleshooting

App doesn’t open

  • Ensure server is running (npm run dev)
  • Ensure port 8080 is free

No messages between tabs

  • Make sure both tabs use the same server URL
  • Hard refresh both tabs after restarting server

MongoDB persistence not working

  • Set MONGO_URI to a valid Mongo connection string
  • Without MONGO_URI, app uses in-memory storage by design

Package install

If you want to use this as a library in your own project:

npm install @waelio/messaging

Library usage (server)

npm run dev       # start in dev (ts-node)
npm run build     # compile TypeScript
npm start         # run compiled server

Web APIs used (client activity indicators)

  • Page Visibility API (document.hidden, visibilitychange)
  • Window focus event (window.addEventListener('focus', ...))
  • Document title updates (document.title)
  • Favicon updates via <link rel="icon"> + Canvas API
  • PWA install events (beforeinstallprompt, appinstalled)

Advanced: create your own server

import http from "http";
import express from "express";
import { createFeathersApp } from "./src/feathers/app.js";

const app = express();
const server = http.createServer(app);

// Socket.io + Feathers channels, no REST
// Optional: pass a MongoDB URI as second argument
await createFeathersApp(server, process.env.MONGO_URI);

server.listen(8080, () => console.log("ready"));

If you prefer the original raw-ws hub as a library:

import http from "http";
import express from "express";
import { MessagingHub } from "@waelio/messaging";

const app = express();
const server = http.createServer(app);

const hub = new MessagingHub(server, { mongoURI: process.env.MONGO_URI });
await hub.ready;

server.listen(8080, () => console.log("ready"));

Web Component

Auto-send on connect:

<waelio-message target="USER_ID" message="hello"></waelio-message>

Broadcast:

<waelio-message message="hello everyone" broadcast></waelio-message>

Manual:

<waelio-message id="msg" send-on="manual" target="USER_ID"></waelio-message>
<script>
  msg.addEventListener("connected", () => msg.send("hi again"));
</script>

Attributes: target, message, broadcast, ws-url, send-on (connect|manual|click), reconnect. Events: connected, disconnected, sent, error.

Architecture

src/
  feathers/
    app.ts          ← Feathers app, Socket.io transport (no REST)
    channels.ts     ← Declarative channel routing rules
    services/
      messages.ts   ← create (send) + find (history)
      rooms.ts      ← create (join private room)
  MessagingHub.ts   ← Original raw-ws hub (library export, unchanged)
  server.ts         ← HTTP server entry point
public/
  index.html        ← p5.js canvas UI using socket.io-client

How Feathers channels replace the old broadcast loops

| Scenario | Channel used | | ---------------------- | --------------------------------------------- | | Direct message | direct/<recipientId> | | Broadcast | all (filtered to exclude sender) | | Room message | rooms/<roomId> (filtered to exclude sender) | | Room join notification | direct/<userId> + direct/<partnerId> |

Each connected socket is placed in all and direct/<id> on connect. When two clients join a room their sockets are also added to rooms/<roomId>. Feathers service.publish() in channels.ts decides which channel receives each service event — no manual looping required.

Protocol (Summary)

Client → Server (Socket.io emit)

| Old ws message type | New Feathers call | | --------------------- | ------------------------------------------------------------------- | | route | socket.emit('messages::create', { type:'route', to, payload }) | | broadcast | socket.emit('messages::create', { type:'broadcast', payload }) | | get-history | socket.emit('messages::find', {}, callback) | | join-room | socket.emit('rooms::create', { with: partnerId }) | | room-message | socket.emit('messages::create', { type:'room-message', payload }) | | start-typing | socket.emit('start-typing') | | stop-typing | socket.emit('stop-typing') |

Server → Client (Socket.io events)

  • register-success { id } — your assigned client ID
  • user-list { users[] } — full list of connected IDs
  • user-joined { id, ts } / user-left { id, ts }
  • user-typing { id } / user-stopped-typing { id }
  • messages created { senderId, recipientId, payload, isBroadcast, roomId, timestamp } — Feathers service event
  • rooms created { roomId, userId, partnerId } — Feathers service event

Persistence (Optional)

Pass a MongoDB URI to createFeathersApp (or MessagingHub) to persist messages across restarts. Without it, an in-memory store is used automatically (last 100 messages).

await createFeathersApp(server, process.env.MONGO_URI);

GitHub webhook sync

The server can synchronize portalRequests records from GitHub webhook events through:

  • POST /api/github/webhook
  • HMAC verification via GITHUB_WEBHOOK_SECRET and GitHub's X-Hub-Signature-256 header

Supported event types:

  • issues
  • pull_request
  • repository_dispatch

How a GitHub event finds a portal request

For issues and pull_request events, include the request ID in either:

  • the issue/PR body as Portal-Request-Id: <requestId>
  • a label such as portal-request:<requestId>

Optional metadata can also be supplied:

  • Session-Code: <code> in the body, or a label like session:<code>
  • labels like started or in-progress to promote the request status to started

Status mapping:

  • issuesimported by default, or started when a started-style label is present
  • pull_requeststarted
  • repository_dispatch → explicit client_payload.status

Explicit sync via repository_dispatch

Send a repository_dispatch payload with:

{
  "action": "portal-request-sync",
  "client_payload": {
    "requestId": "<requestId>",
    "status": "imported",
    "hostDisplayName": "octocat",
    "sessionCode": "ROOM-42"
  }
}

This is handy when you want GitHub Actions to drive the sync directly instead of inferring it from labels or issue bodies.

Built-in GitHub Actions helper

This repository now includes .github/workflows/portal-request-sync.yml.

It can help in two ways:

  • Manual sync from the GitHub Actions UI with requestId, status, hostDisplayName, and sessionCode
  • Automatic sync dispatch for matching issues and pull_request activity by emitting a repository_dispatch event on the same repo

Recommended setup modes:

  1. Direct webhook mode
  • Configure your GitHub webhook to send issues and pull_request directly to /api/github/webhook
  • Use this when you want the fewest moving parts
  1. Workflow-assisted mode
  • Enable the included Portal Request Sync workflow
  • Configure your GitHub webhook to send repository_dispatch to /api/github/webhook
  • Use this when you want GitHub Actions to normalize issue/PR activity before your server receives it

To avoid duplicate updates, pick one mode per repository instead of enabling both issue/PR webhooks and workflow-generated repository_dispatch events for the same sync flow.

Release Scripts

Patch / Minor / Major then publish:

npm run release:patch && npm run release:publish
npm run release:minor && npm run release:publish
npm run release:major && npm run release:publish

License

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