Quick Start Guide
Get up and running with Vaultys P2P features in just a few minutes! This guide will walk you through creating your first peer-to-peer application with real examples from our playground.
๐ 5-Minute Setupโ
Step 1: Install the SDKโ
npm install @vaultys/peer-sdk @vaultys/id
Step 2: Create Your First Identityโ
Every peer in the Vaultys network needs a unique decentralized identity (DID). You can create one using either a software key or a passkey (WebAuthn):
import { VaultysId } from '@vaultys/id';
// Option 1: Software-based identity (works everywhere)
const vaultysId = await VaultysId.generatePerson();
// Option 2: Hardware-based identity using passkey (more secure)
const vaultysId = await VaultysId.createWebauthn(true);
console.log('My DID:', vaultysId.did);
// Example: did:vaultys:5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
Step 3: Set Up P2P Connectionโ
import { setupVaultysPeerSDK, BrowserStorageProvider } from '@vaultys/peer-sdk';
const peerService = setupVaultysPeerSDK({
vaultysId,
storageProvider: new BrowserStorageProvider(),
relay: {
host: 'peerjs.92k.de',
secure: true
}
});
// Listen for connection events
peerService.on('relay-connected', () => {
console.log('Connected to P2P network! โ
');
});
// Initialize the connection
await peerService.initialize();
๐ฌ Building a P2P Chat (Complete Example)โ
Here's a fully functional P2P chat application based on our playground implementation:
import { setupVaultysPeerSDK, BrowserStorageProvider } from '@vaultys/peer-sdk';
import { VaultysId } from '@vaultys/id';
class P2PChat {
constructor() {
this.peerService = null;
this.myDid = null;
this.contacts = new Map();
this.messages = [];
}
async initialize() {
// Create or load identity
let vaultysId = await this.loadOrCreateIdentity();
this.myDid = vaultysId.did;
// Set up peer service
this.peerService = setupVaultysPeerSDK({
vaultysId,
storageProvider: new BrowserStorageProvider(),
relay: {
host: 'peerjs.92k.de',
secure: true
}
});
// Set up event listeners
this.setupEventListeners();
// Initialize connection
await this.peerService.initialize();
console.log('Chat ready! Your DID:', this.myDid);
}
async loadOrCreateIdentity() {
// Check for stored identity
const stored = localStorage.getItem('vaultysIdentity');
if (stored) {
const { secret } = JSON.parse(stored);
return VaultysId.fromSecret(secret);
}
// Create new identity
const vaultysId = await VaultysId.generatePerson();
localStorage.setItem('vaultysIdentity', JSON.stringify({
did: vaultysId.did,
secret: vaultysId.getSecret(),
createdAt: new Date().toISOString()
}));
return vaultysId;
}
setupEventListeners() {
// Message received
this.peerService.on('message-received', (message) => {
console.log('New message:', message);
this.messages.push({
id: message.id,
from: message.from,
content: message.content,
timestamp: message.timestamp,
type: message.type || 'text'
});
this.onMessageReceived?.(message);
});
// Contact comes online
this.peerService.on('contact-online', (did) => {
console.log('Contact online:', did);
const contact = this.contacts.get(did);
if (contact) {
contact.online = true;
this.onContactStatusChanged?.(did, true);
}
});
// Contact goes offline
this.peerService.on('contact-offline', (did) => {
console.log('Contact offline:', did);
const contact = this.contacts.get(did);
if (contact) {
contact.online = false;
this.onContactStatusChanged?.(did, false);
}
});
// File received
this.peerService.on('file-received', (fileMessage) => {
console.log('File received:', fileMessage.fileData.name);
this.onFileReceived?.(fileMessage);
});
}
async addContact(did, nickname) {
const contact = await this.peerService.addContact(did, { nickname });
this.contacts.set(did, {
did,
nickname: nickname || did.slice(0, 10),
online: false,
addedAt: new Date().toISOString()
});
return contact;
}
async sendMessage(contactDid, content) {
const message = {
id: Date.now().toString(),
from: this.myDid,
to: contactDid,
content,
timestamp: Date.now(),
type: 'text'
};
await this.peerService.sendMessage(contactDid, content);
this.messages.push(message);
return message;
}
async sendFile(contactDid, file) {
const buffer = await file.arrayBuffer();
const fileData = {
name: file.name,
size: file.size,
type: file.type,
data: new Uint8Array(buffer)
};
await this.peerService.sendMessage(
contactDid,
`Sent file: ${file.name}`,
'file',
fileData
);
}
getConversation(contactDid) {
return this.messages.filter(
m => m.from === contactDid || m.to === contactDid
).sort((a, b) => a.timestamp - b.timestamp);
}
}
// Usage
const chat = new P2PChat();
await chat.initialize();
// Add a contact
await chat.addContact('did:vaultys:...', 'Alice');
// Send a message
await chat.sendMessage('did:vaultys:...', 'Hello Alice! ๐');
// Send a file
const file = document.getElementById('fileInput').files[0];
await chat.sendFile('did:vaultys:...', file);
๐จ Building Collaborative Featuresโ
Create real-time collaborative applications with shared state:
import { VaultysSpace } from '@vaultys/peer-sdk';
class CollaborativeCanvas {
constructor() {
this.space = null;
this.canvasArray = null;
}
async initialize(roomName, vaultysId) {
const peerService = setupVaultysPeerSDK({
vaultysId,
storageProvider: new BrowserStorageProvider()
});
// Create or join a collaborative space
this.space = await peerService.createOrJoinSpace(roomName, {
ownerDid: vaultysId.did,
useAwareness: true,
autoSaveInterval: 5000
});
// Create shared canvas array
this.canvasArray = this.space.getArray('canvas');
// Listen for remote updates
this.canvasArray.observe((event) => {
this.redrawCanvas();
});
// Set up awareness for live cursors
this.space.awareness.setLocalState({
name: 'User',
color: this.getRandomColor(),
cursor: null
});
// Track other users' cursors
this.space.awareness.on('change', () => {
const states = this.space.awareness.getStates();
this.updateCursors(states);
});
}
addStroke(stroke) {
// Add stroke to shared array
this.canvasArray.push([stroke]);
}
clearCanvas() {
// Clear shared canvas
this.canvasArray.delete(0, this.canvasArray.length);
}
updateCursor(x, y) {
// Share cursor position
this.space.awareness.setLocalState({
...this.space.awareness.getLocalState(),
cursor: { x, y }
});
}
}
๐ง React Component Exampleโ
Here's how to integrate P2P features into a React app:
import React, { useState, useEffect, useRef } from 'react';
import { setupVaultysPeerSDK, BrowserStorageProvider } from '@vaultys/peer-sdk';
import { VaultysId } from '@vaultys/id';
function P2PChat() {
const [isConnected, setIsConnected] = useState(false);
const [myDid, setMyDid] = useState('');
const [contacts, setContacts] = useState([]);
const [messages, setMessages] = useState([]);
const [inputMessage, setInputMessage] = useState('');
const peerServiceRef = useRef(null);
useEffect(() => {
initializePeer();
}, []);
const initializePeer = async () => {
// Create identity
const vaultysId = await VaultysId.generatePerson();
setMyDid(vaultysId.did);
// Set up peer service
const peerService = setupVaultysPeerSDK({
vaultysId,
storageProvider: new BrowserStorageProvider()
});
// Event listeners
peerService.on('relay-connected', () => {
setIsConnected(true);
});
peerService.on('message-received', (message) => {
setMessages(prev => [...prev, message]);
});
peerService.on('contact-online', (did) => {
setContacts(prev => prev.map(c =>
c.did === did ? {...c, online: true} : c
));
});
// Initialize
await peerService.initialize();
peerServiceRef.current = peerService;
};
const addContact = async (did) => {
const contact = await peerServiceRef.current.addContact(did);
setContacts(prev => [...prev, {
did,
nickname: did.slice(0, 10),
online: false
}]);
};
const sendMessage = async (contactDid) => {
if (!inputMessage.trim()) return;
await peerServiceRef.current.sendMessage(contactDid, inputMessage);
setMessages(prev => [...prev, {
from: myDid,
to: contactDid,
content: inputMessage,
timestamp: Date.now()
}]);
setInputMessage('');
};
return (
<div className="p2p-chat">
<div className="status">
{isConnected ? '๐ข Connected' : '๐ด Connecting...'}
</div>
<div className="my-did">
My DID: {myDid}
</div>
<div className="contacts">
{contacts.map(contact => (
<div key={contact.did} className="contact">
{contact.online ? '๐ข' : 'โซ'} {contact.nickname}
</div>
))}
</div>
<div className="messages">
{messages.map((msg, i) => (
<div key={i} className="message">
<strong>{msg.from === myDid ? 'You' : msg.from}:</strong>
{msg.content}
</div>
))}
</div>
<input
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
placeholder="Type a message..."
/>
</div>
);
}
๐ฏ Key Concepts Explainedโ
Identity Managementโ
// Store identity securely
const storeIdentity = (vaultysId) => {
const identity = {
did: vaultysId.did,
secret: vaultysId.getSecret(),
type: 'software', // or 'webauthn'
createdAt: new Date().toISOString()
};
localStorage.setItem('vaultysIdentity', JSON.stringify(identity));
};
// Load existing identity
const loadIdentity = () => {
const stored = localStorage.getItem('vaultysIdentity');
if (stored) {
const { secret } = JSON.parse(stored);
return VaultysId.fromSecret(secret);
}
return null;
};
Event-Driven Architectureโ
// Core events you should handle
peerService.on('relay-connected', () => {
// Connected to signaling server
});
peerService.on('relay-disconnected', () => {
// Disconnected from signaling server
});
peerService.on('message-received', (message) => {
// Handle incoming messages
});
peerService.on('file-received', (fileMessage) => {
// Handle incoming files
});
peerService.on('contact-online', (did) => {
// Contact came online
});
peerService.on('contact-offline', (did) => {
// Contact went offline
});
peerService.on('peer-status', (did, status) => {
// Peer connection status changed
});
File Sharingโ
// Send file
const sendFile = async (file, contactDid) => {
const buffer = await file.arrayBuffer();
await peerService.sendMessage(
contactDid,
`Sending ${file.name}`,
'file',
{
name: file.name,
size: file.size,
type: file.type,
data: new Uint8Array(buffer)
}
);
};
// Receive and save file
peerService.on('file-received', async (message) => {
const blob = new Blob([message.fileData.data], {
type: message.fileData.type
});
// Create download link
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = message.fileData.name;
a.click();
URL.revokeObjectURL(url);
});
๐ Try It Liveโ
Want to see these examples in action? Check out our Interactive Playground where you can:
- Create and manage identities
- Test P2P chat with file sharing
- Try collaborative canvas drawing
- Experiment with real-time document editing
๐ Next Stepsโ
- Explore the Playground: Test features interactively at /playground
- Advanced Features: Learn about spaces and collaboration
- Storage Options: Understanding storage providers
- Production Setup: Deployment guide
- API Reference: Complete API documentation
๐ก Pro Tipsโ
- Identity Persistence: Always store identities securely for returning users
- Error Handling: Implement proper error handlers for network issues
- Message Queuing: Messages are automatically queued when peers are offline
- File Size: For large files (>10MB), consider chunking or using a separate transfer method
- WebRTC Fallback: Configure TURN servers for users behind strict firewalls
Ready to build something amazing? Start with our playground to see everything in action! ๐