Let people send files
directly to each other.

Move files browser to browser with reliable binary data channels, explicit chunking, and a downloadable blob on the other side.

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

const peer = new Dendri({
  url: "wss://signal.example.com"
});

const conn = peer.connect(remotePeerId, {
  reliable: true
});

if (!conn) {
  throw new Error("Unable to open a peer connection.");
}

conn.on("open", () => {
  conn.send({
    kind: "meta",
    name: file.name,
    size: file.size
  });
});

Your user wants to share.
Not start an upload.

The file is the feature. Storage bills, a detached upload flow, and server-side access to the contents are not.

The file has somewhere to go.

It already belongs with the person on the other side of the room.

Send it there directly.

A reliable WebRTC data connection carries the bytes from one browser to another. On the P2P path, your signaling server never sees the file payload.

A large file needs a steady flow.

Turning the whole file into one message makes progress opaque and memory use harder to manage.

Move it in useful pieces.

Send metadata, stream binary chunks, then signal completion. The example uses 64 KiB chunks and rebuilds a downloadable blob on the receiving side.

The receiver needs a file.

Chunks and progress events are only useful when they become something the person can open.

Rebuild the download at completion.

The receiver keeps metadata and chunks, then creates a Blob with the original MIME type when completion arrives. The demo turns that into a downloadable object URL.

From two peer IDs to one delivered file.

Use the room to find the person, then open a dedicated connection for the transfer.

Read the file-transfer walkthrough →
  1. Find the recipient

    Join a room or use the store to discover the remote peer ID.

    room.join("transfer-room");
  2. Open a reliable connection

    Connect to the selected peer and handle a failed connection explicitly.

    const conn = peer.connect(remotePeerId, { reliable: true });
    if (!conn) throw new Error("Peer connection failed");
  3. Announce, chunk, finish

    Tell the receiver what is coming, stream the file, then offer the reconstructed download.

    conn.send({ kind: "meta", name: file.name, size: file.size });
    conn.send({ kind: "chunk", offset, chunk });
    conn.send({ kind: "done" });

Watch the file cross the room.

Open the demo in two tabs and send something between them.

Dendri is transport.
Not file hosting.

A live transfer needs a participating recipient. If someone must download the file hours or days later, add durable storage and an asynchronous delivery flow. Dendri does not silently turn into a file host.

This raw binary example needs a direct WebRTC path. If that path fails, show the connection error and choose a retry or storage fallback rather than assuming relay delivery.

Let the file stay between them.

Start with one room and give two peers something to share.