@xtr-dev/rondevu-client 0.13.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -381
- package/dist/api.d.ts +67 -116
- package/dist/api.js +201 -244
- package/dist/crypto-adapter.d.ts +37 -0
- package/dist/crypto-adapter.js +4 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -1
- package/dist/node-crypto-adapter.d.ts +35 -0
- package/dist/node-crypto-adapter.js +80 -0
- package/dist/rondevu-signaler.d.ts +10 -7
- package/dist/rondevu-signaler.js +96 -64
- package/dist/rondevu.d.ts +199 -37
- package/dist/rondevu.js +519 -103
- package/dist/rpc-batcher.d.ts +61 -0
- package/dist/rpc-batcher.js +111 -0
- package/dist/web-crypto-adapter.d.ts +16 -0
- package/dist/web-crypto-adapter.js +52 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@xtr-dev/rondevu-client)
|
|
4
4
|
|
|
5
|
-
🌐 **Simple
|
|
5
|
+
🌐 **Simple WebRTC signaling client with username-based discovery**
|
|
6
6
|
|
|
7
|
-
TypeScript/JavaScript client for Rondevu, providing
|
|
7
|
+
TypeScript/JavaScript client for Rondevu, providing WebRTC signaling with username claiming, service publishing/discovery, and efficient batch polling.
|
|
8
8
|
|
|
9
9
|
**Related repositories:**
|
|
10
10
|
- [@xtr-dev/rondevu-client](https://github.com/xtr-dev/rondevu-client) - TypeScript client library ([npm](https://www.npmjs.com/package/@xtr-dev/rondevu-client))
|
|
@@ -15,18 +15,17 @@ TypeScript/JavaScript client for Rondevu, providing easy-to-use WebRTC connectio
|
|
|
15
15
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **Cryptographic Username Claiming**: Secure ownership with Ed25519 signatures
|
|
25
|
-
- **Service Publishing**: Package-style naming (chat.app@1.0.0) with multiple simultaneous offers
|
|
18
|
+
- **Username Claiming**: Secure ownership with Ed25519 signatures
|
|
19
|
+
- **Anonymous Users**: Auto-generated anonymous usernames for quick testing
|
|
20
|
+
- **Service Publishing**: Publish services with multiple offers for connection pooling
|
|
21
|
+
- **Service Discovery**: Direct lookup, random discovery, or paginated search
|
|
22
|
+
- **Efficient Batch Polling**: Single endpoint for answers and ICE candidates (50% fewer requests)
|
|
23
|
+
- **Semantic Version Matching**: Compatible version resolution (chat:1.0.0 matches any 1.x.x)
|
|
26
24
|
- **TypeScript**: Full type safety and autocomplete
|
|
27
|
-
- **
|
|
25
|
+
- **Keypair Management**: Generate or reuse Ed25519 keypairs
|
|
26
|
+
- **Automatic Signatures**: All authenticated requests signed automatically
|
|
28
27
|
|
|
29
|
-
##
|
|
28
|
+
## Installation
|
|
30
29
|
|
|
31
30
|
```bash
|
|
32
31
|
npm install @xtr-dev/rondevu-client
|
|
@@ -34,424 +33,144 @@ npm install @xtr-dev/rondevu-client
|
|
|
34
33
|
|
|
35
34
|
## Quick Start
|
|
36
35
|
|
|
37
|
-
###
|
|
36
|
+
### Publishing a Service (Offerer)
|
|
38
37
|
|
|
39
38
|
```typescript
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
host.events.on('connection', (connection) => {
|
|
61
|
-
console.log('✅ New connection!')
|
|
62
|
-
|
|
63
|
-
connection.events.on('message', (msg) => {
|
|
64
|
-
console.log('📨 Received:', msg)
|
|
65
|
-
connection.sendMessage('Hello from Alice!')
|
|
39
|
+
import { Rondevu } from '@xtr-dev/rondevu-client'
|
|
40
|
+
|
|
41
|
+
// 1. Connect to Rondevu
|
|
42
|
+
const rondevu = await Rondevu.connect({
|
|
43
|
+
apiUrl: 'https://api.ronde.vu',
|
|
44
|
+
username: 'alice', // Or omit for anonymous username
|
|
45
|
+
iceServers: 'ipv4-turn' // Preset: 'ipv4-turn', 'hostname-turns', 'google-stun', 'relay-only'
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// 2. Publish service with automatic offer management
|
|
49
|
+
await rondevu.publishService({
|
|
50
|
+
service: 'chat:1.0.0',
|
|
51
|
+
maxOffers: 5, // Maintain up to 5 concurrent offers
|
|
52
|
+
offerFactory: async (rtcConfig) => {
|
|
53
|
+
const pc = new RTCPeerConnection(rtcConfig)
|
|
54
|
+
const dc = pc.createDataChannel('chat')
|
|
55
|
+
|
|
56
|
+
dc.addEventListener('open', () => {
|
|
57
|
+
console.log('Connection opened!')
|
|
58
|
+
dc.send('Hello from Alice!')
|
|
66
59
|
})
|
|
67
60
|
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
dc.addEventListener('message', (e) => {
|
|
62
|
+
console.log('Received:', e.data)
|
|
70
63
|
})
|
|
71
|
-
})
|
|
72
64
|
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
const offer = await pc.createOffer()
|
|
66
|
+
await pc.setLocalDescription(offer)
|
|
67
|
+
return { pc, dc, offer }
|
|
68
|
+
}
|
|
75
69
|
})
|
|
76
70
|
|
|
77
|
-
//
|
|
78
|
-
await
|
|
79
|
-
console.log('Service is now live! Others can connect to @alice')
|
|
80
|
-
|
|
81
|
-
// Later: stop hosting
|
|
82
|
-
host.dispose()
|
|
71
|
+
// 3. Start accepting connections
|
|
72
|
+
await rondevu.startFilling()
|
|
83
73
|
```
|
|
84
74
|
|
|
85
|
-
### Connecting to a Service (
|
|
75
|
+
### Connecting to a Service (Answerer)
|
|
86
76
|
|
|
87
77
|
```typescript
|
|
88
|
-
import {
|
|
89
|
-
|
|
90
|
-
// Step 1: Create and initialize service
|
|
91
|
-
const service = new RondevuService({
|
|
92
|
-
apiUrl: 'https://api.ronde.vu',
|
|
93
|
-
username: 'bob'
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
await service.initialize()
|
|
97
|
-
await service.claimUsername()
|
|
78
|
+
import { Rondevu } from '@xtr-dev/rondevu-client'
|
|
98
79
|
|
|
99
|
-
//
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
autoReconnect: true,
|
|
105
|
-
maxReconnectAttempts: 5
|
|
80
|
+
// 1. Connect to Rondevu
|
|
81
|
+
const rondevu = await Rondevu.connect({
|
|
82
|
+
apiUrl: 'https://api.ronde.vu',
|
|
83
|
+
username: 'bob',
|
|
84
|
+
iceServers: 'ipv4-turn'
|
|
106
85
|
})
|
|
107
86
|
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
87
|
+
// 2. Connect to service (automatic WebRTC setup)
|
|
88
|
+
const connection = await rondevu.connectToService({
|
|
89
|
+
serviceFqn: 'chat:1.0.0@alice',
|
|
90
|
+
onConnection: ({ dc, peerUsername }) => {
|
|
91
|
+
console.log('Connected to', peerUsername)
|
|
111
92
|
|
|
112
|
-
|
|
113
|
-
|
|
93
|
+
dc.addEventListener('message', (e) => {
|
|
94
|
+
console.log('Received:', e.data)
|
|
114
95
|
})
|
|
115
96
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
client.events.on('disconnected', () => {
|
|
121
|
-
console.log('🔌 Disconnected')
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
client.events.on('reconnecting', ({ attempt, maxAttempts }) => {
|
|
125
|
-
console.log(`🔄 Reconnecting (${attempt}/${maxAttempts})...`)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
client.events.on('error', (error) => {
|
|
129
|
-
console.error('❌ Error:', error)
|
|
97
|
+
dc.addEventListener('open', () => {
|
|
98
|
+
dc.send('Hello from Bob!')
|
|
99
|
+
})
|
|
100
|
+
}
|
|
130
101
|
})
|
|
131
102
|
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// Later: disconnect
|
|
136
|
-
client.dispose()
|
|
103
|
+
// Access connection
|
|
104
|
+
connection.dc.send('Another message')
|
|
105
|
+
connection.pc.close() // Close when done
|
|
137
106
|
```
|
|
138
107
|
|
|
139
|
-
## Core
|
|
140
|
-
|
|
141
|
-
### RondevuService
|
|
142
|
-
|
|
143
|
-
Handles authentication and username management:
|
|
144
|
-
- Generates Ed25519 keypair for signing
|
|
145
|
-
- Claims usernames with cryptographic proof
|
|
146
|
-
- Provides API client for signaling server
|
|
147
|
-
|
|
148
|
-
### ServiceHost
|
|
149
|
-
|
|
150
|
-
High-level wrapper for hosting a WebRTC service:
|
|
151
|
-
- Automatically creates and publishes offers
|
|
152
|
-
- Handles incoming connections
|
|
153
|
-
- Manages ICE candidate exchange
|
|
154
|
-
- Supports multiple simultaneous peers
|
|
155
|
-
|
|
156
|
-
### ServiceClient
|
|
108
|
+
## Core API
|
|
157
109
|
|
|
158
|
-
|
|
159
|
-
- Discovers services by username
|
|
160
|
-
- Handles offer/answer exchange automatically
|
|
161
|
-
- Built-in auto-reconnection with exponential backoff
|
|
162
|
-
- Event-driven API
|
|
163
|
-
|
|
164
|
-
### RTCDurableConnection
|
|
165
|
-
|
|
166
|
-
Low-level connection wrapper (used internally):
|
|
167
|
-
- Manages WebRTC PeerConnection lifecycle
|
|
168
|
-
- Handles ICE candidate polling
|
|
169
|
-
- Provides message queue for reliability
|
|
170
|
-
- State management and events
|
|
171
|
-
|
|
172
|
-
## API Reference
|
|
173
|
-
|
|
174
|
-
### RondevuService
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
const service = new RondevuService({
|
|
178
|
-
apiUrl: string, // Signaling server URL
|
|
179
|
-
username: string, // Your username
|
|
180
|
-
keypair?: Keypair // Optional: reuse existing keypair
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
// Initialize service (generates keypair if not provided)
|
|
184
|
-
await service.initialize(): Promise<void>
|
|
185
|
-
|
|
186
|
-
// Claim username with cryptographic signature
|
|
187
|
-
await service.claimUsername(): Promise<void>
|
|
188
|
-
|
|
189
|
-
// Check if username is claimed
|
|
190
|
-
service.isUsernameClaimed(): boolean
|
|
191
|
-
|
|
192
|
-
// Get current username
|
|
193
|
-
service.getUsername(): string
|
|
194
|
-
|
|
195
|
-
// Get keypair
|
|
196
|
-
service.getKeypair(): Keypair
|
|
197
|
-
|
|
198
|
-
// Get API client
|
|
199
|
-
service.getAPI(): RondevuAPI
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### ServiceHost
|
|
110
|
+
### Rondevu.connect()
|
|
203
111
|
|
|
204
112
|
```typescript
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
rtcConfiguration?: RTCConfiguration
|
|
113
|
+
const rondevu = await Rondevu.connect({
|
|
114
|
+
apiUrl: string, // Required: Signaling server URL
|
|
115
|
+
username?: string, // Optional: your username (auto-generates anonymous if omitted)
|
|
116
|
+
keypair?: Keypair, // Optional: reuse existing keypair
|
|
117
|
+
iceServers?: IceServerPreset | RTCIceServer[], // Optional: preset or custom config
|
|
118
|
+
debug?: boolean // Optional: enable debug logging (default: false)
|
|
212
119
|
})
|
|
213
|
-
|
|
214
|
-
// Start hosting
|
|
215
|
-
await host.start(): Promise<void>
|
|
216
|
-
|
|
217
|
-
// Stop hosting and cleanup
|
|
218
|
-
host.dispose(): void
|
|
219
|
-
|
|
220
|
-
// Get all active connections
|
|
221
|
-
host.getConnections(): RTCDurableConnection[]
|
|
222
|
-
|
|
223
|
-
// Events
|
|
224
|
-
host.events.on('connection', (conn: RTCDurableConnection) => {})
|
|
225
|
-
host.events.on('error', (error: Error) => {})
|
|
226
120
|
```
|
|
227
121
|
|
|
228
|
-
###
|
|
122
|
+
### Service Publishing
|
|
229
123
|
|
|
230
124
|
```typescript
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
maxReconnectAttempts?: number, // Default: 5
|
|
237
|
-
rtcConfiguration?: RTCConfiguration
|
|
125
|
+
await rondevu.publishService({
|
|
126
|
+
service: string, // e.g., 'chat:1.0.0' (username auto-appended)
|
|
127
|
+
maxOffers: number, // Maximum concurrent offers to maintain
|
|
128
|
+
offerFactory?: OfferFactory, // Optional: custom offer creation
|
|
129
|
+
ttl?: number // Optional: offer lifetime in ms (default: 300000)
|
|
238
130
|
})
|
|
239
131
|
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
// Disconnect and cleanup
|
|
244
|
-
client.dispose(): void
|
|
245
|
-
|
|
246
|
-
// Get current connection
|
|
247
|
-
client.getConnection(): RTCDurableConnection | null
|
|
248
|
-
|
|
249
|
-
// Events
|
|
250
|
-
client.events.on('connected', (conn: RTCDurableConnection) => {})
|
|
251
|
-
client.events.on('disconnected', () => {})
|
|
252
|
-
client.events.on('reconnecting', (info: { attempt: number, maxAttempts: number }) => {})
|
|
253
|
-
client.events.on('error', (error: Error) => {})
|
|
132
|
+
await rondevu.startFilling() // Start accepting connections
|
|
133
|
+
rondevu.stopFilling() // Stop and close all connections
|
|
254
134
|
```
|
|
255
135
|
|
|
256
|
-
###
|
|
136
|
+
### Service Discovery
|
|
257
137
|
|
|
258
138
|
```typescript
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
// Send message (returns true if sent, false if queued)
|
|
263
|
-
await connection.sendMessage(message: string): Promise<boolean>
|
|
264
|
-
|
|
265
|
-
// Queue message for sending when connected
|
|
266
|
-
await connection.queueMessage(message: string, options?: QueueMessageOptions): Promise<void>
|
|
139
|
+
// Direct lookup (with username)
|
|
140
|
+
await rondevu.getService('chat:1.0.0@alice')
|
|
267
141
|
|
|
268
|
-
//
|
|
269
|
-
|
|
142
|
+
// Random discovery (without username)
|
|
143
|
+
await rondevu.discoverService('chat:1.0.0')
|
|
270
144
|
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
connection.events.on('state-change', (state: ConnectionStates) => {})
|
|
145
|
+
// Paginated discovery
|
|
146
|
+
await rondevu.discoverServices('chat:1.0.0', limit, offset)
|
|
274
147
|
```
|
|
275
148
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
### Polling Configuration
|
|
279
|
-
|
|
280
|
-
The signaling uses configurable polling with exponential backoff:
|
|
149
|
+
### Connecting to Services
|
|
281
150
|
|
|
282
151
|
```typescript
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
jitter: true // Add random 0-100ms to prevent thundering herd
|
|
290
|
-
}
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
This is handled automatically - no configuration needed.
|
|
294
|
-
|
|
295
|
-
### WebRTC Configuration
|
|
296
|
-
|
|
297
|
-
Provide custom STUN/TURN servers:
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
const host = new ServiceHost({
|
|
301
|
-
service: 'chat.app@1.0.0',
|
|
302
|
-
rondevuService: service,
|
|
303
|
-
rtcConfiguration: {
|
|
304
|
-
iceServers: [
|
|
305
|
-
{ urls: 'stun:stun.l.google.com:19302' },
|
|
306
|
-
{
|
|
307
|
-
urls: 'turn:turn.example.com:3478',
|
|
308
|
-
username: 'user',
|
|
309
|
-
credential: 'pass'
|
|
310
|
-
}
|
|
311
|
-
]
|
|
312
|
-
}
|
|
152
|
+
const connection = await rondevu.connectToService({
|
|
153
|
+
serviceFqn?: string, // Full FQN like 'chat:1.0.0@alice'
|
|
154
|
+
service?: string, // Service without username (for discovery)
|
|
155
|
+
username?: string, // Target username (combined with service)
|
|
156
|
+
onConnection?: (context) => void, // Called when data channel opens
|
|
157
|
+
rtcConfig?: RTCConfiguration // Optional: override ICE servers
|
|
313
158
|
})
|
|
314
159
|
```
|
|
315
160
|
|
|
316
|
-
##
|
|
161
|
+
## Documentation
|
|
317
162
|
|
|
318
|
-
|
|
319
|
-
-
|
|
320
|
-
-
|
|
321
|
-
-
|
|
322
|
-
-
|
|
163
|
+
📚 **[ADVANCED.md](./ADVANCED.md)** - Comprehensive guide including:
|
|
164
|
+
- Detailed API reference for all methods
|
|
165
|
+
- Type definitions and interfaces
|
|
166
|
+
- Platform support (Browser & Node.js)
|
|
167
|
+
- Advanced usage patterns
|
|
168
|
+
- Username rules and service FQN format
|
|
169
|
+
- Examples and migration guides
|
|
323
170
|
|
|
324
171
|
## Examples
|
|
325
172
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
See [demo/demo.js](./demo/demo.js) for a complete working example.
|
|
329
|
-
|
|
330
|
-
### Persistent Keypair
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
// Save keypair to localStorage
|
|
334
|
-
const service = new RondevuService({
|
|
335
|
-
apiUrl: 'https://api.ronde.vu',
|
|
336
|
-
username: 'alice'
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
await service.initialize()
|
|
340
|
-
await service.claimUsername()
|
|
341
|
-
|
|
342
|
-
// Save for later
|
|
343
|
-
localStorage.setItem('rondevu-keypair', JSON.stringify(service.getKeypair()))
|
|
344
|
-
localStorage.setItem('rondevu-username', service.getUsername())
|
|
345
|
-
|
|
346
|
-
// Load on next session
|
|
347
|
-
const savedKeypair = JSON.parse(localStorage.getItem('rondevu-keypair'))
|
|
348
|
-
const savedUsername = localStorage.getItem('rondevu-username')
|
|
349
|
-
|
|
350
|
-
const service2 = new RondevuService({
|
|
351
|
-
apiUrl: 'https://api.ronde.vu',
|
|
352
|
-
username: savedUsername,
|
|
353
|
-
keypair: savedKeypair
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
await service2.initialize() // Reuses keypair
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
### Message Queue Example
|
|
360
|
-
|
|
361
|
-
```typescript
|
|
362
|
-
// Messages are automatically queued if not connected yet
|
|
363
|
-
client.events.on('connected', (connection) => {
|
|
364
|
-
// Send immediately
|
|
365
|
-
connection.sendMessage('Hello!')
|
|
366
|
-
})
|
|
367
|
-
|
|
368
|
-
// Or queue for later
|
|
369
|
-
await client.connect()
|
|
370
|
-
const conn = client.getConnection()
|
|
371
|
-
await conn.queueMessage('This will be sent when connected', {
|
|
372
|
-
expiresAt: Date.now() + 60000 // Expire after 1 minute
|
|
373
|
-
})
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
## Migration from v0.9.x
|
|
377
|
-
|
|
378
|
-
v0.11.0+ introduces high-level wrappers, RESTful API changes, and semver-compatible discovery:
|
|
379
|
-
|
|
380
|
-
**API Changes:**
|
|
381
|
-
- Server endpoints restructured (`/usernames/*` → `/users/*`)
|
|
382
|
-
- Added `ServiceHost` and `ServiceClient` wrappers
|
|
383
|
-
- Message queue fully implemented
|
|
384
|
-
- Configurable polling with exponential backoff
|
|
385
|
-
- Removed deprecated `cleanup()` methods (use `dispose()`)
|
|
386
|
-
- **v0.11.0+**: Services use `offers` array instead of single `sdp`
|
|
387
|
-
- **v0.11.0+**: Semver-compatible service discovery (chat@1.0.0 matches 1.x.x)
|
|
388
|
-
- **v0.11.0+**: All services are hidden - no listing endpoint
|
|
389
|
-
- **v0.11.0+**: Services support multiple simultaneous offers for connection pooling
|
|
390
|
-
|
|
391
|
-
**Migration Guide:**
|
|
392
|
-
|
|
393
|
-
```typescript
|
|
394
|
-
// Before (v0.9.x) - Manual WebRTC setup
|
|
395
|
-
const signaler = new RondevuSignaler(service, 'chat@1.0.0')
|
|
396
|
-
const context = new WebRTCContext()
|
|
397
|
-
const pc = context.createPeerConnection()
|
|
398
|
-
// ... 50+ lines of boilerplate
|
|
399
|
-
|
|
400
|
-
// After (v0.11.0) - ServiceHost wrapper
|
|
401
|
-
const host = new ServiceHost({
|
|
402
|
-
service: 'chat@1.0.0',
|
|
403
|
-
rondevuService: service
|
|
404
|
-
})
|
|
405
|
-
await host.start()
|
|
406
|
-
// Done!
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
## Platform Support
|
|
410
|
-
|
|
411
|
-
### Modern Browsers
|
|
412
|
-
Works out of the box - no additional setup needed.
|
|
413
|
-
|
|
414
|
-
### Node.js 18+
|
|
415
|
-
Native fetch is available, but WebRTC requires polyfills:
|
|
416
|
-
|
|
417
|
-
```bash
|
|
418
|
-
npm install wrtc
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
```typescript
|
|
422
|
-
import { WebRTCContext } from '@xtr-dev/rondevu-client'
|
|
423
|
-
import { RTCPeerConnection, RTCSessionDescription, RTCIceCandidate } from 'wrtc'
|
|
424
|
-
|
|
425
|
-
// Configure WebRTC context
|
|
426
|
-
const context = new WebRTCContext({
|
|
427
|
-
RTCPeerConnection,
|
|
428
|
-
RTCSessionDescription,
|
|
429
|
-
RTCIceCandidate
|
|
430
|
-
} as any)
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
## TypeScript
|
|
434
|
-
|
|
435
|
-
All types are exported:
|
|
436
|
-
|
|
437
|
-
```typescript
|
|
438
|
-
import type {
|
|
439
|
-
RondevuServiceOptions,
|
|
440
|
-
ServiceHostOptions,
|
|
441
|
-
ServiceHostEvents,
|
|
442
|
-
ServiceClientOptions,
|
|
443
|
-
ServiceClientEvents,
|
|
444
|
-
ConnectionInterface,
|
|
445
|
-
ConnectionEvents,
|
|
446
|
-
ConnectionStates,
|
|
447
|
-
Message,
|
|
448
|
-
QueueMessageOptions,
|
|
449
|
-
Signaler,
|
|
450
|
-
PollingConfig,
|
|
451
|
-
Credentials,
|
|
452
|
-
Keypair
|
|
453
|
-
} from '@xtr-dev/rondevu-client'
|
|
454
|
-
```
|
|
173
|
+
- [React Demo](https://github.com/xtr-dev/rondevu-demo) - Full browser UI ([live](https://ronde.vu))
|
|
455
174
|
|
|
456
175
|
## License
|
|
457
176
|
|