Build your first P2P app in 15 minutes with real cryptographic identity and WebRTC mesh networking.
Toolkit-P2P v0.4 "Orbit" • Production-ready • 268+ tests • Zero servers
Optional packages: @toolkit-p2p/sync, @toolkit-p2p/bulletin, @toolkit-p2p/mailbox
Build a real-time shared cursor that works over WebRTC mesh networks.
import { loadOrCreateIdentity } from '@toolkit-p2p/identity';
// Creates Ed25519 keypair, stored in IndexedDB
const identity = await loadOrCreateIdentity();
console.log(identity.did);
// Output: "did:zeta:5HqJw2..." (base58-encoded public key)Your DID (Decentralized Identifier) is your cryptographic identity. Private key never leaves your device.
import { createTransport } from '@toolkit-p2p/transport';
// Create WebRTC mesh transport
const transport = createTransport({
identity,
signalingUrl: 'ws://localhost:8080', // Or your signaling server
roomCode: 'ABC123',
});
// Listen for peer connections
transport.onPeerJoined((peerId) => {
console.log('Peer joined:', peerId);
});
transport.onPeerLeft((peerId) => {
console.log('Peer left:', peerId);
});Room codes enable discovery. All peers in the same room connect via WebRTC DataChannels.
// Broadcast cursor position to all peers
document.addEventListener('mousemove', (e) => {
const data = {
type: 'cursor',
x: e.clientX,
y: e.clientY,
};
const encoded = new TextEncoder().encode(JSON.stringify(data));
transport.broadcast(encoded);
});
// Receive cursor updates from peers
transport.onMessage((peerId, data) => {
const decoded = JSON.parse(new TextDecoder().decode(data));
if (decoded.type === 'cursor') {
updatePeerCursor(peerId, decoded.x, decoded.y);
}
});That's it! You now have real-time cursor sync over a serverless mesh network.
Add Bulletin (presence) and Mailbox (encrypted messaging) to build a full P2P chat.
import { Bulletin } from '@toolkit-p2p/bulletin';
// Create shared CRDT state
const bulletin = new Bulletin();
// Set your status (automatically syncs via LWW-Map CRDT)
bulletin.set('status', 'online', { ttlSec: 3600 });
// Listen for remote status changes
bulletin.onChange((field, value) => {
console.log(`Field ${field} updated:`, value);
});
// Sync with peers (merge remote state)
transport.onMessage((peerId, data) => {
const message = JSON.parse(new TextDecoder().decode(data));
if (message.type === 'bulletin-sync') {
bulletin.merge(message.snapshot);
}
});import { MailboxQueue, deriveSessionKey, encrypt } from '@toolkit-p2p/mailbox';
// Derive session key from room code (PBKDF2-SHA256)
const sessionKey = await deriveSessionKey(identity, 'ABC123');
// Encrypt message (AES-256-GCM)
const message = { text: 'Hello, P2P world!' };
const encoded = new TextEncoder().encode(JSON.stringify(message));
const encrypted = await encrypt(encoded, sessionKey);
// Send to specific peer
await transport.send(targetPeerId, encrypted);AES-256-GCM encryption ensures only room participants can read messages.
Add persistence with a headless peer that never sleeps:
import { HeadlessNode } from '@toolkit-p2p/headless';
const lighthouse = new HeadlessNode({
storagePath: '~/.lighthouse',
port: 3000,
});
await lighthouse.start();
// Lighthouse now provides store-and-forward for offline peersDeploy on a Raspberry Pi for 24/7 network continuity. See deployment guide.
Each device generates its own did:zeta:<publicKey> using Ed25519 signatures.
Private keys stored in IndexedDB. Trust tickets enable mutual auto-connect. Blocklist for security.
Direct P2P connections via WebRTC DataChannels. WebSocket signaling for initial offer/answer exchange.
Optional STUN/TURN servers. Connection health monitoring. Automatic reconnection. Flow control.
Conflict-free data types ensure eventual consistency. Vector clocks track causality. LWW-Map for state.
Merkle trees for efficient sync. G-Counter for metrics. Works offline, syncs when reconnected.
Complete documentation of all 9 packages and 268+ APIs
Deep dive into CRDTs, vector clocks, trust mesh, and Lighthouse pattern
Build P2P games, social networks, marketplaces, and more
Clone frog7, stark7, doom7, and 6 more working examples