Sessions and transports
Transports move bytes
A transport knows how to reach a DID and carry raw frames to it. It doesn't know about identities or messages; authentication happens above it.
| Transport | Import | Use it for |
|---|---|---|
peerjsTransport() | @vaultys/peer-sdk/peerjs | Browsers: WebRTC data channels, introduced by a PeerJS relay |
memoryNetwork().transport() | @vaultys/peer-sdk | Tests, demos, several peers in one page or process |
| Your own | implement Transport | Any channel that carries ordered, reliable frames |
import { peerjsTransport } from "@vaultys/peer-sdk/peerjs";
const peer = await createPeer({
identity,
transport: peerjsTransport({ host: "relay.example.com", secure: true }),
});
With PeerJS, the relay only helps two browsers find each other and set up the WebRTC connection. Data then flows directly between them, or through a TURN server when a direct path isn't possible. The relay sees a hash of your DID and the handshake messages, never message content. See Relays to run your own.
Sessions
A session is one authenticated, encrypted link with one verified DID. Sessions are created for you:
peer.send()and protocol sends open one when needed.peer.connect(did)opens one explicitly, which is useful to show presence.- A contact that dials you creates one on your side.
await peer.connect(bobDid); // throws if Bob is unreachable or refuses
peer.isOnline(bobDid); // true while a session is open
peer.online(); // DIDs with an open session
peer.disconnect(bobDid); // close it
peer.on("connection", ({ did, online }) => {
console.log(did, online ? "online" : "offline");
});
A session exists only after a successful handshake, so "online" in the SDK always means "connected and verified".
Keeping sessions healthy
Sessions send a small keepalive every 15 seconds and close after three silent intervals. That's how a peer that vanished (closed laptop, lost network) is noticed. Tune it with keepaliveMs (0 disables it).
If both peers dial each other at the same moment, they briefly create two sessions. Both sides then keep the same one (the session started by the lexicographically smaller DID) and close the other.
Relay outages
peerjsTransport supervises its registration with the relay. If the signaling connection drops (a sleeping laptop, a network change, a restarted relay), it reconnects with backoff, and checks every 10 seconds and whenever the tab becomes visible again. Open sessions keep working meanwhile, since they don't go through the relay.
Writing a transport
A transport implements two small interfaces:
interface Transport {
listen(did: string, onLink: (link: Link) => void): Promise<void>;
dial(did: string): Promise<Link>;
close(): Promise<void>;
}
interface Link {
send(frame: Uint8Array): void;
onFrame(handler: (frame: Uint8Array) => void): void;
onClose(handler: () => void): void;
close(): void;
readonly closed: boolean;
}
Links must deliver frames reliably and in order. BufferedLink handles buffering frames that arrive before the SDK attaches its handler; most transports wrap their connection in one:
import { BufferedLink } from "@vaultys/peer-sdk";
const link = new BufferedLink(
(frame) => socket.send(frame), // how to send
() => socket.close(), // how to close
);
socket.onmessage = (event) => link.receiveFrame(new Uint8Array(event.data));
socket.onclose = () => link.receiveClose();
When dialing fails because the peer can't be reached, throw a PeerError with code UNREACHABLE; the SDK then queues and retries messages instead of reporting an error.