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

@afterrealism/dendri-client

v2.6.0

Published

Dendri client WebRTC P2P signaling library

Readme

@afterrealism/dendri-client

Framework-neutral TypeScript client SDK for Dendri WebRTC P2P signaling. Works in the browser and Node.js.

Install

npm install @afterrealism/dendri-client

Connect To Your Server

Pass the signaling server your app should use as a single URL:

import { Dendri } from "@afterrealism/dendri-client";

const peer = new Dendri({
	url: "wss://signal.example.com",
	apiKey: "your-api-key", // only needed for hosted / multi-tenant deployments
});

url is shorthand for host/port/secure/path — pass those individually if you prefer; explicitly passed fields win over url-derived ones.

You can also pass an explicit peer id as the first argument: new Dendri("my-peer-id", { ... }).

Local development usually looks like:

const peer = new Dendri({ url: "ws://localhost:9876" });

Quick Start

// Connect to another peer
const conn = peer.connect("other-peer-id");

conn.on("open", () => {
	conn.send("hello");
});

conn.on("data", (data) => {
	console.log("Received:", data);
});

// Receive connections
peer.on("connection", (conn) => {
	conn.on("data", (data) => {
		console.log("Received:", data);
	});
});

Room Store

Use createDendriStore() when integrating with UI frameworks:

import { createDendriStore } from "@afterrealism/dendri-client";

const store = createDendriStore({ url: "wss://signal.example.com" });

const unsubscribe = store.subscribe(() => {
	console.log(store.connectionState, store.peers);
});

store.join("my-room");

Framework Adapters

Ready-made bindings ship as subpath exports (react and vue are optional peer dependencies; the Svelte adapter is dependency-free):

// React — re-renders on store changes (useSyncExternalStore under the hood)
import { useDendriStore } from "@afterrealism/dendri-client/react";
const { connectionState, peers } = useDendriStore(store);
// Vue — shallowRef that tracks the store, auto-unsubscribes with the component
import { useDendriStore } from "@afterrealism/dendri-client/vue";
const snapshot = useDendriStore(store); // snapshot.value.connectionState
<!-- Svelte — standard store contract, works with $ auto-subscription (Svelte 4 + 5) -->
<script>
	import { toSvelteStore } from "@afterrealism/dendri-client/svelte";
	const snapshot = toSvelteStore(store);
</script>
{$snapshot.connectionState}

Any other framework can wrap store.subscribe and store.getSnapshot() the same way.

Features

  • P2P Data Channels - Send data directly between browsers
  • Media Calls - Video and audio streaming via WebRTC
  • Rooms - Group peers into rooms with automatic peer discovery
  • Presence - Track online status and custom metadata across peers
  • Topics - Pub/sub messaging with named topics
  • RPC - Request/response pattern over data channels
  • Host Migration - Automatic leader election when the host disconnects
  • Hybrid Connections - Seamless fallback between data channel and relay
  • Relay Encryption - End-to-end encryption for relayed messages
  • Store - Shared synchronized state across peers
  • Auto Reconnect - Exponential backoff with jitter
  • MsgPack Serializer - Binary serialization for smaller payloads

Multi-Tab Reconnection

When two browser tabs use the same peer_id to connect to the same signaling server:

  • Same peer_id, same token — Treated as a reconnection. The server replaces the old WebSocket with the new one. Room memberships and queued messages are preserved. The first tab eventually receives a disconnect event via heartbeat timeout.
  • Same peer_id, different token — Rejected with an ID_TAKEN error. Prevents accidental or malicious ID hijacking.

For multi-tab apps, use BroadcastChannel or localStorage to coordinate a single Dendri connection across tabs, or let each tab create its own instance with distinct peer_id values and communicate through rooms.

MsgPack Serializer

For binary serialization instead of JSON:

import { MsgPackDendri } from "@afterrealism/dendri-client";

const peer = new MsgPackDendri("my-peer-id", {
	host: "signal.example.com",
	secure: true,
});

SSR

Importing the package is safe in SSR code, but creating peers and joining rooms should happen only in browser/client lifecycle code because WebRTC and WebSocket connections are browser/runtime side effects.

Browser Global Build

The package ships browser global (IIFE) assets for CDN/script-tag workflows:

<script src="https://unpkg.com/@afterrealism/dendri-client"></script>
<script>
	const peer = new dendri.Dendri({ host: "signal.example.com", port: 443, secure: true, path: "/" });
</script>
  • dist/dendri.min.global.js (minified, served by unpkg/jsdelivr by default)
  • dist/dendri.browser.global.js (unminified, for debugging)

The global build exposes Dendri and util on window.dendri. Prefer npm imports for framework apps.

License

Apache-2.0