mirror of
https://github.com/xtr-dev/rondevu-client.git
synced 2025-12-14 04:43:24 +00:00
eb280e3826e29bad42528cad0d93267326da2406
Handle both browser and Node.js (wrtc) environments when processing ICE candidates. Browsers provide toJSON() method on candidates, but wrtc library candidates are already plain objects. Check for toJSON() existence before calling it. Fixes: TypeError: event.candidate.toJSON is not a function in Node.js
Rondevu Client
🌐 Simple WebRTC signaling client with username-based discovery
TypeScript/JavaScript client for Rondevu, providing WebRTC signaling with username claiming, service publishing/discovery, and efficient batch polling.
Related repositories:
- @xtr-dev/rondevu-client - TypeScript client library (npm)
- @xtr-dev/rondevu-server - HTTP signaling server (npm, live)
- @xtr-dev/rondevu-demo - Interactive demo (live)
Features
- Username Claiming: Secure ownership with Ed25519 signatures
- Anonymous Users: Auto-generated anonymous usernames for quick testing
- Service Publishing: Publish services with multiple offers for connection pooling
- Service Discovery: Direct lookup, random discovery, or paginated search
- Efficient Batch Polling: Single endpoint for answers and ICE candidates (50% fewer requests)
- Semantic Version Matching: Compatible version resolution (chat:1.0.0 matches any 1.x.x)
- TypeScript: Full type safety and autocomplete
- Keypair Management: Generate or reuse Ed25519 keypairs
- Automatic Signatures: All authenticated requests signed automatically
Installation
npm install @xtr-dev/rondevu-client
Quick Start
Publishing a Service (Offerer)
import { Rondevu } from '@xtr-dev/rondevu-client'
// 1. Connect to Rondevu
const rondevu = await Rondevu.connect({
apiUrl: 'https://api.ronde.vu',
username: 'alice', // Or omit for anonymous username
iceServers: 'ipv4-turn' // Preset: 'ipv4-turn', 'hostname-turns', 'google-stun', 'relay-only'
})
// 2. Publish service with automatic offer management
await rondevu.publishService({
service: 'chat:1.0.0',
maxOffers: 5, // Maintain up to 5 concurrent offers
offerFactory: async (rtcConfig) => {
const pc = new RTCPeerConnection(rtcConfig)
const dc = pc.createDataChannel('chat')
dc.addEventListener('open', () => {
console.log('Connection opened!')
dc.send('Hello from Alice!')
})
dc.addEventListener('message', (e) => {
console.log('Received:', e.data)
})
const offer = await pc.createOffer()
await pc.setLocalDescription(offer)
return { pc, dc, offer }
}
})
// 3. Start accepting connections
await rondevu.startFilling()
Connecting to a Service (Answerer)
import { Rondevu } from '@xtr-dev/rondevu-client'
// 1. Connect to Rondevu
const rondevu = await Rondevu.connect({
apiUrl: 'https://api.ronde.vu',
username: 'bob',
iceServers: 'ipv4-turn'
})
// 2. Connect to service (automatic WebRTC setup)
const connection = await rondevu.connectToService({
serviceFqn: 'chat:1.0.0@alice',
onConnection: ({ dc, peerUsername }) => {
console.log('Connected to', peerUsername)
dc.addEventListener('message', (e) => {
console.log('Received:', e.data)
})
dc.addEventListener('open', () => {
dc.send('Hello from Bob!')
})
}
})
// Access connection
connection.dc.send('Another message')
connection.pc.close() // Close when done
Core API
Rondevu.connect()
const rondevu = await Rondevu.connect({
apiUrl: string, // Required: Signaling server URL
username?: string, // Optional: your username (auto-generates anonymous if omitted)
keypair?: Keypair, // Optional: reuse existing keypair
iceServers?: IceServerPreset | RTCIceServer[], // Optional: preset or custom config
debug?: boolean // Optional: enable debug logging (default: false)
})
Service Publishing
await rondevu.publishService({
service: string, // e.g., 'chat:1.0.0' (username auto-appended)
maxOffers: number, // Maximum concurrent offers to maintain
offerFactory?: OfferFactory, // Optional: custom offer creation
ttl?: number // Optional: offer lifetime in ms (default: 300000)
})
await rondevu.startFilling() // Start accepting connections
rondevu.stopFilling() // Stop and close all connections
Service Discovery
// Direct lookup (with username)
await rondevu.getService('chat:1.0.0@alice')
// Random discovery (without username)
await rondevu.discoverService('chat:1.0.0')
// Paginated discovery
await rondevu.discoverServices('chat:1.0.0', limit, offset)
Connecting to Services
const connection = await rondevu.connectToService({
serviceFqn?: string, // Full FQN like 'chat:1.0.0@alice'
service?: string, // Service without username (for discovery)
username?: string, // Target username (combined with service)
onConnection?: (context) => void, // Called when data channel opens
rtcConfig?: RTCConfiguration // Optional: override ICE servers
})
Documentation
📚 ADVANCED.md - Comprehensive guide including:
- Detailed API reference for all methods
- Type definitions and interfaces
- Platform support (Browser & Node.js)
- Advanced usage patterns
- Username rules and service FQN format
- Examples and migration guides
Examples
- React Demo - Full browser UI (live)
License
MIT
Description
Languages
TypeScript
97%
JavaScript
3%