Self-hosted by default

Realtime collaboration infrastructure you can ship and own.

Dendri gives you a framework-neutral TypeScript SDK and a Rust signaling server for chat, presence, multiplayer state, Yjs documents, and relay-backed WebRTC.

TypeScript SDK Rust signaling React · Vue · Svelte
$ npm install @afterrealism/dendri
$ cd server
$ cargo run -- --host 127.0.0.1 --port 9876 --enable_relay --allow_discovery
Chat Presence Multiplayer state Yjs docs Binary sync Relay fallback
01

Framework-neutral

Use one shared createDendriStore() API across React, Vue, Svelte, and vanilla apps.

02

Self-host first

No hidden hosted defaults. Your app always points to your own signaling server.

03

Collaboration ready

Power chat, presence, multiplayer state, and Yjs CRDT sync from the same room abstractions.

Local setup

Run the full stack in minutes

1) Start signaling server

cd server
cargo run -- --host 127.0.0.1 --port 9876 --enable_relay --allow_discovery

2) Install SDK in your app

npm install @afterrealism/dendri

3) Connect and join a room

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

const store = createDendriStore({
  host: "127.0.0.1",
  port: 9876,
  secure: false,
  path: "/",
});

store.join("project-room");

Task recipes

Use Dendri for common realtime workloads

Realtime chat channels

Publish and subscribe by topic for clean message routing.

const unsubChat = store.subscribe("chat", (data, peerId) => {
  console.log("chat", peerId, data);
});

store.broadcast(
  { type: "chat", text: "hello team" },
  { topic: "chat" },
);

Live presence and cursors

Sync user metadata and read all peers from snapshot state.

store.setPresence({
  name: "Ari",
  cursor: [314, 128],
  color: "#67e8f9",
});

store.subscribe(() => {
  const { presences } = store.getSnapshot();
  console.log("presence map", presences);
});

Collaborative docs with Yjs

Bridge Yjs updates over Dendri topics using @afterrealism/y-dendri.

import { DendriYjsProvider } from "@afterrealism/y-dendri";
import * as Y from "yjs";

const doc = new Y.Doc();
const provider = new DendriYjsProvider({ room: store, doc });

store.join("shared-doc");
// cleanup: provider.destroy(); doc.destroy(); store.destroy();

Binary payload transport

Send chunks for assets or CRDT updates without JSON overhead.

const bytes = new Uint8Array([1, 2, 3, 4]);
store.broadcastBinary(bytes, { topic: "asset-chunk" });

store.subscribe("asset-chunk", (payload) => {
  if (payload instanceof Uint8Array) {
    console.log("binary bytes:", payload.byteLength);
  }
});

Framework integrations

One API, multiple frontend stacks

Vanilla JS integration

Validation and deployment

Test locally before shipping

Cross-framework E2E checks

cd e2e
npm install
npm run test:examples-local

Runs Playwright against Svelte, React, and Vue example apps plus local signaling.

Docker deployment assets

cd deploy
# compose assets for local/VM deployment

Use the deployment folder when you need a packaged service topology.

Infrastructure templates

cd infrastruture/terraform
# Terraform modules for cloud rollout

Start from Terraform modules if you need managed infrastructure provisioning.