Documentation
Everything you need to add Dendri to your app — or run the whole stack yourself.
Quickstart
Install the framework-neutral client:
npm install @afterrealism/dendri-client
Create a store and join a room. On the hosted tier, pass your url and apiKey:
import { createDendriStore } from "@afterrealism/dendri-client";
const room = createDendriStore({
url: "wss://signal.dendri.dev",
apiKey: "dk_your_key",
});
room.subscribe(() => {
console.log(room.connectionState, room.peers);
});
room.join("design-review");
room.broadcast({ type: "cursor", x, y });
Configuration
The client takes a single URL plus an optional key. Self-hosters can pass the parts individually instead.
| Option | Type | Notes |
|---|---|---|
url | string | Full server URL, e.g. wss://signal.dendri.dev. |
apiKey | string | Tenant key for the hosted tier. |
host / port / secure / path | string / number / bool / string | Self-host alternative to url. |
signalingTransport | "websocket" | "sse" | "polling" | "auto" | Transport, or auto-fallback. Default websocket. |
enableRelay | bool | Allow encrypted TLS relay when P2P fails. |
Framework bindings
Official bindings ship as subpath exports. The Svelte adapter has no dependency; React and Vue are optional peers.
// React
import { useDendriStore } from "@afterrealism/dendri-client/react";
const { connectionState, peers } = useDendriStore(room);
// Vue
import { useDendriStore } from "@afterrealism/dendri-client/vue";
// Svelte
import { toSvelteStore } from "@afterrealism/dendri-client/svelte";
For collaborative editing, the @afterrealism/dendri-y package bridges a Yjs document over a Dendri room.
Self-hosting
The signaling server is open source (AGPL-3.0) and free to run. Point the SDK at your own host instead of the hosted endpoint — the client API is identical.
const room = createDendriStore({
host: "signal.example.com",
port: 443,
secure: true,
path: "/",
});
Run the Rust server from source, or use the Podman/Quadlet stack in dendri-infrastructure/.
You'll want a TURN server (coturn) alongside it for peers behind strict NATs. See the
server repo for deploy details.
Architecture
Dendri is signaling, not a media relay. It brokers the WebRTC handshake, then gets out of the way so data flows peer-to-peer. When a direct connection isn't possible, it degrades gracefully:
| Tier | Path | When |
|---|---|---|
| 1 | Direct P2P | Same network or open NAT. |
| 2 | STUN | Peers discover public addresses. |
| 3 | TURN | Symmetric NAT — relay through coturn. |
| 4 | TLS relay | Everything else — encrypted relay through the server. |
The signaling server itself is a small Rust (Axum/Tokio) binary backed by Redis-compatible storage, with multi-transport support (WebSocket, HTTP/SSE, long-poll) so it works through hostile proxies.
Licensing
The client SDKs (@afterrealism/dendri-client, @afterrealism/dendri-y) are
Apache-2.0 — use them anywhere. The signaling server is AGPL-3.0, or available under a commercial
licence from Afterrealism for closed-source hosted use.
Need something that isn't here? Open an issue on GitHub.