Skip to main content

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โ€‹

  1. Explore the Playground: Test features interactively at /playground
  2. Advanced Features: Learn about spaces and collaboration
  3. Storage Options: Understanding storage providers
  4. Production Setup: Deployment guide
  5. 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! ๐ŸŽ‰