docs: Update README for unified Ed25519 authentication

- Add anonymous username documentation and examples
- Remove Credentials interface from types section
- Update Rondevu constructor to show optional username (auto-generates anonymous)
- Remove register() method references
- Update RondevuAPI constructor (no credentials, requires username + keypair)
- Add automatic signature generation notes
- Update all code examples to show new initialization flow
- Add persistent keypair example with username storage
This commit is contained in:
2025-12-10 22:19:18 +01:00
parent c9a5e0eae6
commit 0fe8e82858

View File

@@ -16,12 +16,14 @@ TypeScript/JavaScript client for Rondevu, providing WebRTC signaling with userna
## Features ## Features
- **Username Claiming**: Secure ownership with Ed25519 signatures - **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 Publishing**: Publish services with multiple offers for connection pooling
- **Service Discovery**: Direct lookup, random discovery, or paginated search - **Service Discovery**: Direct lookup, random discovery, or paginated search
- **Efficient Batch Polling**: Single endpoint for answers and ICE candidates (50% fewer requests) - **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) - **Semantic Version Matching**: Compatible version resolution (chat:1.0.0 matches any 1.x.x)
- **TypeScript**: Full type safety and autocomplete - **TypeScript**: Full type safety and autocomplete
- **Keypair Management**: Generate or reuse Ed25519 keypairs - **Keypair Management**: Generate or reuse Ed25519 keypairs
- **Automatic Signatures**: All authenticated requests signed automatically
## Installation ## Installation
@@ -36,16 +38,18 @@ npm install @xtr-dev/rondevu-client
```typescript ```typescript
import { Rondevu } from '@xtr-dev/rondevu-client' import { Rondevu } from '@xtr-dev/rondevu-client'
// 1. Initialize and claim username // 1. Initialize (with username or anonymous)
const rondevu = new Rondevu({ const rondevu = new Rondevu({
apiUrl: 'https://api.ronde.vu', apiUrl: 'https://api.ronde.vu',
username: 'alice' username: 'alice' // Or omit for anonymous username
}) })
await rondevu.initialize() // Generates keypair automatically await rondevu.initialize() // Generates keypair automatically
// 2. Claim username (optional - anonymous users auto-claim)
await rondevu.claimUsername() await rondevu.claimUsername()
// 2. Create WebRTC offer // 3. Create WebRTC offer
const pc = new RTCPeerConnection({ const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
}) })
@@ -55,7 +59,7 @@ const dc = pc.createDataChannel('chat')
const offer = await pc.createOffer() const offer = await pc.createOffer()
await pc.setLocalDescription(offer) await pc.setLocalDescription(offer)
// 3. Publish service // 4. Publish service
const service = await rondevu.publishService({ const service = await rondevu.publishService({
serviceFqn: 'chat:1.0.0@alice', serviceFqn: 'chat:1.0.0@alice',
offers: [{ sdp: offer.sdp }], offers: [{ sdp: offer.sdp }],
@@ -64,7 +68,7 @@ const service = await rondevu.publishService({
const offerId = service.offers[0].offerId const offerId = service.offers[0].offerId
// 4. Poll for answer and ICE candidates (combined) // 5. Poll for answer and ICE candidates (combined)
let lastPollTimestamp = 0 let lastPollTimestamp = 0
const pollInterval = setInterval(async () => { const pollInterval = setInterval(async () => {
const result = await rondevu.pollOffers(lastPollTimestamp) const result = await rondevu.pollOffers(lastPollTimestamp)
@@ -90,7 +94,7 @@ const pollInterval = setInterval(async () => {
} }
}, 1000) }, 1000)
// 5. Send ICE candidates // 6. Send ICE candidates
pc.onicecandidate = (event) => { pc.onicecandidate = (event) => {
if (event.candidate) { if (event.candidate) {
rondevu.addOfferIceCandidates( rondevu.addOfferIceCandidates(
@@ -101,7 +105,7 @@ pc.onicecandidate = (event) => {
} }
} }
// 6. Handle messages // 7. Handle messages
dc.onmessage = (event) => { dc.onmessage = (event) => {
console.log('Received:', event.data) console.log('Received:', event.data)
} }
@@ -199,16 +203,15 @@ import { Rondevu } from '@xtr-dev/rondevu-client'
const rondevu = new Rondevu({ const rondevu = new Rondevu({
apiUrl: string, // Signaling server URL apiUrl: string, // Signaling server URL
username: string, // Your username username?: string, // Optional: your username (auto-generates anonymous if omitted)
keypair?: Keypair, // Optional: reuse existing keypair keypair?: Keypair // Optional: reuse existing keypair
credentials?: Credentials // Optional: reuse existing credentials
}) })
``` ```
#### Initialization #### Initialization
```typescript ```typescript
// Initialize (generates keypair and credentials if not provided) // Initialize (generates keypair if not provided, auto-claims anonymous usernames)
await rondevu.initialize(): Promise<void> await rondevu.initialize(): Promise<void>
``` ```
@@ -384,15 +387,10 @@ import { RondevuAPI } from '@xtr-dev/rondevu-client'
const api = new RondevuAPI( const api = new RondevuAPI(
baseUrl: string, baseUrl: string,
credentials?: Credentials username: string,
keypair: Keypair
) )
// Set credentials
api.setCredentials(credentials: Credentials): void
// Register peer
await api.register(): Promise<Credentials>
// Check username // Check username
await api.checkUsername(username: string): Promise<{ await api.checkUsername(username: string): Promise<{
available: boolean available: boolean
@@ -440,11 +438,6 @@ interface Keypair {
privateKey: string // Base64-encoded Ed25519 private key privateKey: string // Base64-encoded Ed25519 private key
} }
interface Credentials {
peerId: string
secret: string
}
interface Service { interface Service {
serviceId: string serviceId: string
offers: ServiceOffer[] offers: ServiceOffer[]
@@ -477,10 +470,30 @@ interface PollingConfig {
## Advanced Usage ## Advanced Usage
### Anonymous Username
```typescript
// Auto-generate anonymous username (format: anon-{timestamp}-{random})
const rondevu = new Rondevu({
apiUrl: 'https://api.ronde.vu'
// No username provided - will generate anonymous username
})
await rondevu.initialize() // Auto-claims anonymous username
console.log(rondevu.getUsername()) // e.g., "anon-lx2w34-a3f501"
// Anonymous users behave exactly like regular users
await rondevu.publishService({
serviceFqn: `chat:1.0.0@${rondevu.getUsername()}`,
offers: [{ sdp: offerSdp }]
})
```
### Persistent Keypair ### Persistent Keypair
```typescript ```typescript
// Save keypair to localStorage // Save keypair and username to localStorage
const rondevu = new Rondevu({ const rondevu = new Rondevu({
apiUrl: 'https://api.ronde.vu', apiUrl: 'https://api.ronde.vu',
username: 'alice' username: 'alice'
@@ -490,14 +503,16 @@ await rondevu.initialize()
await rondevu.claimUsername() await rondevu.claimUsername()
// Save for later // Save for later
localStorage.setItem('rondevu-username', rondevu.getUsername())
localStorage.setItem('rondevu-keypair', JSON.stringify(rondevu.getKeypair())) localStorage.setItem('rondevu-keypair', JSON.stringify(rondevu.getKeypair()))
// Load on next session // Load on next session
const savedUsername = localStorage.getItem('rondevu-username')
const savedKeypair = JSON.parse(localStorage.getItem('rondevu-keypair')) const savedKeypair = JSON.parse(localStorage.getItem('rondevu-keypair'))
const rondevu2 = new Rondevu({ const rondevu2 = new Rondevu({
apiUrl: 'https://api.ronde.vu', apiUrl: 'https://api.ronde.vu',
username: 'alice', username: savedUsername,
keypair: savedKeypair keypair: savedKeypair
}) })