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

@meshwhisper/sdk

v0.5.0

Published

Serverless P2P E2EE Messaging SDK

Downloads

557

Readme


The problem with messaging

Building messaging yourself takes months and you'll get the cryptography wrong. Hosted services like Sendbird cost $2,000/month and can read every message your users send.

MeshWhisper is different. You run the backend. It costs €4/month. And it cannot read your users' messages — not as a policy, but by design.


How it works

sequenceDiagram
    autonumber
    participant A as Alice's device
    participant R as Your Node (relay)
    participant B as Bob's device

    Note over A,B: All encryption happens on-device.<br/>The relay only sees ciphertext.

    A->>A: Encrypt with Double Ratchet<br/>(PQXDH session key)
    A->>R: Send {destHash, ciphertext}
    Note right of R: Stores opaque blob.<br/>Cannot decrypt — ever.
    R-->>B: Wake push (no content)
    B->>R: Pull queued blobs
    R->>B: Deliver ciphertext
    B->>B: Decrypt locally
  • Messages are encrypted on-device with the Signal protocol (X3DH + Double Ratchet) before they leave the user's device
  • Your Node sees only encrypted ciphertext. It routes, stores, and delivers — nothing more
  • Push notifications wake the app when a message arrives while it is closed — without the push service seeing message content
  • Sessions, identity, and message history persist automatically across page reloads and restarts
  • Encrypted backup is included — contacts and message history are backed up to your own relay as opaque AES-GCM blobs. No Google Drive, no iCloud, no separate recovery code. Sign in with the same username and password on any device to restore.

What you deploy

flowchart LR
    subgraph Server["Your VPS · ~€4/month"]
        direction TB
        N["meshwhisper-node<br/>relay · store-and-forward<br/>media · key directory"]
        P["meshwhisper-push<br/>APNs · FCM · Web Push"]
        DB[("SQLite")]
        N --- DB
        N <--> P
    end
    subgraph Devices["Your users' devices"]
        direction TB
        A["@meshwhisper/sdk<br/>PWA · React Native · Node.js"]
    end
    A <-->|"wss · ciphertext only"| N
    P -. "content-free wake" .-> A

Two Docker containers alongside whatever is already on your server:

services:
  meshwhisper-node:
    build: ./node
    environment:
      BASE_URL: "https://relay.myapp.com"
      PUSH_WEBHOOK_URL: "http://meshwhisper-push:4000/notify"

  meshwhisper-push:
    build: ./push-service
    environment:
      VAPID_PUBLIC_KEY: "${VAPID_PUBLIC_KEY}"
      VAPID_PRIVATE_KEY: "${VAPID_PRIVATE_KEY}"
      VAPID_SUBJECT: "mailto:[email protected]"
docker compose up -d

That is your entire messaging backend. Relay, store-and-forward, push notifications, media hosting, and key exchange directory — all in one container stack.


What you add to your app

npm install @meshwhisper/sdk
import { MeshWhisper } from '@meshwhisper/sdk';

const mw = await MeshWhisper.init({
  namespace: 'com.example.myapp',
  node: 'wss://relay.myapp.com',
  onMessage: (message) => {
    const text = new TextDecoder().decode(new Uint8Array(message.payload));
    appendToChat(message.senderId, text);
  },
});

// Share this with contacts
const myId = mw.getLocalPeerId();

// Send — X3DH key exchange happens automatically on first contact
await MeshWhisper.send(contactId, new TextEncoder().encode('Hello!'));

The SDK auto-detects the environment. In a browser it uses IndexedDB for storage and the native WebSocket API. In Node.js it uses the filesystem and the ws package. No configuration required.


Learn by reading a real app

Prudence is a complete PWA built on MeshWhisper — direct messages, groups, media, push, multi-device archive sync, conversation history recovery — and is maintained as a living reference for SDK integrators. Every major SDK feature is exercised in the codebase. The annotated map in prudence/REFERENCE.md points each SDK feature to the file and function where it's wired, and calls out the non-obvious patterns (control-message prefixes, archive-sync semantics, identity persistence) that an integrator would only learn by reading the code.

Try it live at prudence.meshwhisper.org or run it locally from prudence/.

For server-side integrations — AI agents, customer-service bots, IoT gateways — see examples/. The first reference is examples/support-bot: a customer-service agent running as a MeshWhisper peer, ~150 lines, with an echo mode (no API key) and an LLM mode (Claude). Same protocol, different deployment shape.


Scaffold in 60 seconds

npx @meshwhisper/cli init

Asks for your namespace, where your app should connect (Foundation relay for development, your own server for production), and what kind of app you're building. Writes a working SDK skeleton — and for self-hosted deployments, a complete meshwhisper-node/ directory: Docker Compose, standalone Dockerfiles, generated Web Push keys, and a federation bootstrap so your relay joins the mesh. npx @meshwhisper/cli doctor health-checks any node.


What it costs

| | MeshWhisper | Sendbird | Build it yourself | |---|---|---|---| | Monthly cost | ~€4 (your VPS) | $2,000+ | Your engineers' time | | Can read messages | No — impossible | Yes | Depends on you | | Time to integrate | 2–4 hours | 1–2 days | Minutes | | Push notifications | Included | Add-on | Build separately | | Message history | Included | Included | Build separately | | Delivery receipts | Included | Included | Build separately | | Media sharing | Included | Add-on | Build separately |


What it is good for

MeshWhisper is the right choice when privacy is a feature, not an afterthought:

  • Healthcare — patient-doctor messaging where you genuinely cannot access patient communications
  • Legal — lawyer-client communications where privilege requires confidentiality
  • Finance — advisor-client messaging with regulatory pressure toward E2EE
  • B2B SaaS — telling enterprise customers "we cannot read your data even if subpoenaed"
  • Any app where your users' privacy matters and you want to prove it structurally, not just claim it in a privacy policy

Your node, your users, your namespace

Every MeshWhisper deployment is self-contained. Your node serves your app's namespace. Your users connect to your node. Messages between your users flow through your node. Nothing depends on shared infrastructure, third-party availability, or anyone else's decisions.

Node operators can also choose to peer: relay-to-relay federation is live, and FEDERATION_MODE=open joins the mesh with one bootstrap entry — your node forwards packets for other relays and they for yours. But federation is optional. Your app works in complete isolation from day one.


Packages

| Package | Purpose | |---|---| | @meshwhisper/sdk | Client SDK — browser, Node.js, React Native | | @meshwhisper/cli | npx @meshwhisper/cli init scaffolding | | @meshwhisper/node | Relay server binary | | @meshwhisper/push-service | APNs / FCM / Web Push dispatcher | | @meshwhisper/service-worker | PWA push event handler |


Documentation

  • docs/getting-started.md — complete walkthrough from zero to working PWA
  • docs/api.md — full SDK API reference
  • prudence/REFERENCE.md — Prudence as a living example: which SDK feature lives where in the demo app, and the non-obvious patterns to copy
  • examples/ — Minimal end-to-end integrations. Start with support-bot — a customer-service AI agent as a MeshWhisper peer, ~150 lines. Or local-first — on-site human and machine-to-machine comms that keep working when the relay (or the internet) is gone.
  • docs/identity-patterns.md — Six identity-derivation patterns (username+password, email, phone, OS keychain, Secure Enclave, passkey) — pick what matches your threat model; the SDK is neutral
  • docs/self-hosting.md — server configuration, all environment variables
  • docs/local-networks.md — running on isolated/air-gapped networks; LAN peer-to-peer delivery so conversations survive losing the relay
  • docs/federation.md — relay-to-relay peering protocol (open mode joins the mesh with one env var and one bootstrap entry)
  • docs/p2p-transport.md — opportunistic direct-transport spec; what's shipped (LAN) and what's demand-gated (WebRTC, proximity radio)
  • docs/codebase-overview.md — technical overview for contributors and reviewers
  • docs/direction.md — what MeshWhisper is today, where it's going, what we're deliberately not building
  • docs/adr/ — architecture decision records: the why behind significant choices
  • docs/multi-device.md — strategy for multi-device support (hand-off, hard boot, linked devices)
  • docs/whitepaper.md — full protocol whitepaper (PDF)
  • docs/presentation.pdf — slide deck overview of the protocol and project

Security model

  • Key exchange uses PQXDH — a hybrid of X3DH (X25519) and ML-KEM-768. Sessions are post-quantum secure from the first message.
  • Session encryption uses the Double Ratchet algorithm. Each message uses a fresh key; compromise of one key does not expose past or future messages.
  • Your Node sees only encrypted ciphertext and anonymous destination hashes. It cannot identify senders or read content.
  • Destination hashes rotate every hour, limiting traffic-analysis windows.
  • The push service receives a device token and a destination hash — no message content.
  • Identity keys are generated on-device and never transmitted. Private keys are stored only in the device's configured storage backend.
  • Media is encrypted locally before upload. The Node stores ciphertext. The decryption key travels through the ratchet-encrypted message channel — never through the Node's HTTP API.
  • Safety numbers — both parties can verify a 60-digit code out-of-band to confirm no MITM. Computed from a sorted BLAKE3 hash of both Ed25519 identity keys.

For a detailed technical overview see docs/codebase-overview.md.