@xtr-dev/rondevu-client 0.0.2 → 0.0.3
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 +534 -128
- package/dist/client.d.ts +4 -4
- package/dist/client.js +5 -9
- package/dist/connection.d.ts +75 -0
- package/dist/connection.js +260 -0
- package/dist/event-emitter.d.ts +31 -0
- package/dist/event-emitter.js +78 -0
- package/dist/index.d.ts +5 -27
- package/dist/index.js +8 -46
- package/dist/rondevu.d.ts +58 -0
- package/dist/rondevu.js +204 -0
- package/dist/types.d.ts +62 -2
- package/dist/types.js +4 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# @xtr-dev/rondevu-client
|
|
2
2
|
|
|
3
|
-
TypeScript client for
|
|
3
|
+
TypeScript/JavaScript client for WebRTC peer-to-peer connections with automatic signaling and connection management.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✨ **Simple API** - Three methods to establish connections: `create()`, `connect()`, `join()`
|
|
8
|
+
- 🔄 **Automatic Everything** - Handles signaling, ICE candidates, and connection lifecycle
|
|
9
|
+
- 📡 **Event-Driven** - Clean event-based API for connection state and data
|
|
10
|
+
- 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
|
|
11
|
+
- 🌐 **Universal** - Works in browsers and Node.js
|
|
12
|
+
- 🚀 **Zero Dependencies** - Lightweight with no runtime dependencies
|
|
4
13
|
|
|
5
14
|
## Installation
|
|
6
15
|
|
|
@@ -8,227 +17,624 @@ TypeScript client for interacting with the Rondevu peer signaling and discovery
|
|
|
8
17
|
npm install @xtr-dev/rondevu-client
|
|
9
18
|
```
|
|
10
19
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
### Basic Setup
|
|
20
|
+
## Quick Start
|
|
14
21
|
|
|
15
22
|
```typescript
|
|
16
|
-
import {
|
|
23
|
+
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
24
|
+
|
|
25
|
+
// Initialize once
|
|
26
|
+
const rdv = new Rondevu({
|
|
27
|
+
baseUrl: 'https://your-rondevu-server.com',
|
|
28
|
+
rtcConfig: {
|
|
29
|
+
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
|
30
|
+
}
|
|
31
|
+
});
|
|
17
32
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
33
|
+
// Peer A: Create a connection
|
|
34
|
+
const connA = await rdv.create('meeting-123', 'meetings');
|
|
35
|
+
connA.on('connect', () => {
|
|
36
|
+
const channel = connA.dataChannel('chat');
|
|
37
|
+
channel.send('Hello!');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Peer B: Connect to the connection
|
|
41
|
+
const connB = await rdv.connect('meeting-123');
|
|
42
|
+
connB.on('datachannel', (channel) => {
|
|
43
|
+
channel.onmessage = (e) => console.log('Received:', e.data);
|
|
22
44
|
});
|
|
23
45
|
```
|
|
24
46
|
|
|
25
|
-
|
|
47
|
+
## API Documentation
|
|
48
|
+
|
|
49
|
+
### Rondevu Class
|
|
26
50
|
|
|
27
|
-
|
|
51
|
+
The main class for WebRTC connection management with automatic signaling.
|
|
52
|
+
|
|
53
|
+
#### Constructor
|
|
28
54
|
|
|
29
55
|
```typescript
|
|
30
|
-
|
|
31
|
-
|
|
56
|
+
const rdv = new Rondevu(options: RondevuOptions);
|
|
57
|
+
```
|
|
32
58
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
59
|
+
**Options:**
|
|
60
|
+
```typescript
|
|
61
|
+
interface RondevuOptions {
|
|
62
|
+
baseUrl: string; // Rondevu server URL (required)
|
|
63
|
+
peerId?: string; // Custom peer ID (auto-generated if not provided)
|
|
64
|
+
origin?: string; // Origin for session isolation
|
|
65
|
+
fetch?: typeof fetch; // Custom fetch (for Node.js)
|
|
66
|
+
rtcConfig?: RTCConfiguration; // WebRTC configuration (ICE servers, etc.)
|
|
67
|
+
pollingInterval?: number; // Polling interval in ms (default: 1000)
|
|
68
|
+
connectionTimeout?: number; // Connection timeout in ms (default: 30000)
|
|
69
|
+
}
|
|
36
70
|
```
|
|
37
71
|
|
|
38
|
-
####
|
|
72
|
+
#### Properties
|
|
73
|
+
|
|
74
|
+
- `peerId: string` - The current peer identifier (read-only)
|
|
75
|
+
|
|
76
|
+
#### Methods
|
|
77
|
+
|
|
78
|
+
##### `create(id: string, topic: string): Promise<RondevuConnection>`
|
|
79
|
+
|
|
80
|
+
Creates a new connection (offerer role) and waits for a peer to join.
|
|
39
81
|
|
|
40
82
|
```typescript
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
83
|
+
const connection = await rdv.create('my-connection-id', 'my-topic');
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Parameters:**
|
|
87
|
+
- `id` - Connection identifier (can be any string)
|
|
88
|
+
- `topic` - Topic name for grouping connections (max 1024 chars)
|
|
89
|
+
|
|
90
|
+
**Returns:** `RondevuConnection` object
|
|
91
|
+
|
|
92
|
+
**Use case:** When you want to create a new connection and share its ID with others.
|
|
46
93
|
|
|
47
|
-
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
##### `connect(id: string): Promise<RondevuConnection>`
|
|
97
|
+
|
|
98
|
+
Connects to an existing connection by ID (answerer role).
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const connection = await rdv.connect('my-connection-id');
|
|
48
102
|
```
|
|
49
103
|
|
|
50
|
-
|
|
104
|
+
**Parameters:**
|
|
105
|
+
- `id` - The connection ID to join
|
|
106
|
+
|
|
107
|
+
**Returns:** `RondevuConnection` object
|
|
108
|
+
|
|
109
|
+
**Use case:** When you have a specific connection ID (e.g., from a QR code, link, or shared message).
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
##### `join(topic: string, options?: JoinOptions): Promise<RondevuConnection>`
|
|
114
|
+
|
|
115
|
+
Joins a topic and automatically connects to the first available peer (answerer role).
|
|
51
116
|
|
|
52
117
|
```typescript
|
|
53
|
-
|
|
54
|
-
|
|
118
|
+
const connection = await rdv.join('my-topic');
|
|
119
|
+
```
|
|
55
120
|
|
|
56
|
-
|
|
57
|
-
|
|
121
|
+
**Parameters:**
|
|
122
|
+
- `topic` - Topic name to join
|
|
123
|
+
- `options` - Optional join options
|
|
58
124
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
125
|
+
```typescript
|
|
126
|
+
interface JoinOptions {
|
|
127
|
+
filter?: (session: { code: string; peerId: string }) => boolean;
|
|
128
|
+
select?: 'first' | 'newest' | 'oldest' | 'random';
|
|
62
129
|
}
|
|
63
130
|
```
|
|
64
131
|
|
|
65
|
-
|
|
132
|
+
**Returns:** `RondevuConnection` object
|
|
66
133
|
|
|
134
|
+
**Use case:** When you want automatic peer discovery and connection.
|
|
135
|
+
|
|
136
|
+
**Example with options:**
|
|
67
137
|
```typescript
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
answer: webrtcAnswerData,
|
|
72
|
-
side: 'answerer'
|
|
138
|
+
const connection = await rdv.join('game-room', {
|
|
139
|
+
filter: (session) => session.peerId.startsWith('player-'),
|
|
140
|
+
select: 'random'
|
|
73
141
|
});
|
|
74
142
|
```
|
|
75
143
|
|
|
76
|
-
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
##### `updatePeerId(newPeerId: string): void`
|
|
147
|
+
|
|
148
|
+
Updates the peer ID (useful when user identity changes).
|
|
77
149
|
|
|
78
150
|
```typescript
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (offererData.answer) {
|
|
82
|
-
console.log('Received answer from peer');
|
|
83
|
-
}
|
|
151
|
+
rdv.updatePeerId('new-peer-id');
|
|
152
|
+
```
|
|
84
153
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### RondevuConnection Class
|
|
157
|
+
|
|
158
|
+
Represents a WebRTC connection with event-driven API.
|
|
159
|
+
|
|
160
|
+
#### Properties
|
|
161
|
+
|
|
162
|
+
- `id: string` - Connection identifier (read-only)
|
|
163
|
+
- `topic: string` - Topic name (read-only)
|
|
164
|
+
- `role: 'offerer' | 'answerer'` - Connection role (read-only)
|
|
165
|
+
- `remotePeerId: string` - Remote peer's ID (read-only)
|
|
166
|
+
|
|
167
|
+
#### Methods
|
|
168
|
+
|
|
169
|
+
##### `dataChannel(label: string, options?: RTCDataChannelInit): RTCDataChannel`
|
|
170
|
+
|
|
171
|
+
Gets or creates a data channel.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const channel = connection.dataChannel('chat');
|
|
175
|
+
channel.onopen = () => channel.send('Hello!');
|
|
88
176
|
```
|
|
89
177
|
|
|
90
|
-
|
|
178
|
+
**Parameters:**
|
|
179
|
+
- `label` - Data channel label/name
|
|
180
|
+
- `options` - Optional RTCDataChannel configuration
|
|
181
|
+
|
|
182
|
+
**Returns:** `RTCDataChannel` object
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
##### `addStream(stream: MediaStream): void`
|
|
187
|
+
|
|
188
|
+
Adds a local media stream (audio/video) to the connection.
|
|
91
189
|
|
|
92
190
|
```typescript
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
candidate: iceCandidate,
|
|
97
|
-
side: 'offerer' // or 'answerer'
|
|
191
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
192
|
+
video: true,
|
|
193
|
+
audio: true
|
|
98
194
|
});
|
|
195
|
+
connection.addStream(stream);
|
|
99
196
|
```
|
|
100
197
|
|
|
101
|
-
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
##### `getPeerConnection(): RTCPeerConnection`
|
|
201
|
+
|
|
202
|
+
Gets the underlying `RTCPeerConnection` for advanced use cases.
|
|
102
203
|
|
|
103
204
|
```typescript
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
console.log('Timestamp:', health.timestamp);
|
|
205
|
+
const pc = connection.getPeerConnection();
|
|
206
|
+
const stats = await pc.getStats();
|
|
107
207
|
```
|
|
108
208
|
|
|
109
|
-
|
|
209
|
+
**Use case:** Accessing WebRTC stats, adding custom tracks, or other advanced WebRTC features.
|
|
110
210
|
|
|
111
|
-
|
|
211
|
+
---
|
|
112
212
|
|
|
113
|
-
|
|
213
|
+
##### `close(): void`
|
|
214
|
+
|
|
215
|
+
Closes the connection and cleans up resources.
|
|
114
216
|
|
|
115
217
|
```typescript
|
|
116
|
-
|
|
218
|
+
connection.close();
|
|
117
219
|
```
|
|
118
220
|
|
|
119
|
-
|
|
120
|
-
- `baseUrl` (string, required): Base URL of the Rondevu server
|
|
121
|
-
- `origin` (string, optional): Origin header for session isolation (defaults to baseUrl origin)
|
|
122
|
-
- `fetch` (function, optional): Custom fetch implementation (for Node.js)
|
|
221
|
+
---
|
|
123
222
|
|
|
124
|
-
####
|
|
223
|
+
#### Events
|
|
125
224
|
|
|
126
|
-
|
|
225
|
+
Listen to connection events using the `.on()` method:
|
|
127
226
|
|
|
128
|
-
|
|
227
|
+
##### `'connect'`
|
|
129
228
|
|
|
130
|
-
|
|
131
|
-
- `page` (number, optional): Page number, default 1
|
|
132
|
-
- `limit` (number, optional): Results per page, default 100, max 1000
|
|
229
|
+
Emitted when the WebRTC connection is established.
|
|
133
230
|
|
|
134
|
-
|
|
231
|
+
```typescript
|
|
232
|
+
connection.on('connect', () => {
|
|
233
|
+
console.log('Connected!');
|
|
234
|
+
});
|
|
235
|
+
```
|
|
135
236
|
|
|
136
|
-
|
|
237
|
+
---
|
|
137
238
|
|
|
138
|
-
|
|
239
|
+
##### `'disconnect'`
|
|
139
240
|
|
|
140
|
-
|
|
141
|
-
- `topic` (string): Topic identifier
|
|
241
|
+
Emitted when the connection is closed or lost.
|
|
142
242
|
|
|
143
|
-
|
|
243
|
+
```typescript
|
|
244
|
+
connection.on('disconnect', () => {
|
|
245
|
+
console.log('Disconnected');
|
|
246
|
+
});
|
|
247
|
+
```
|
|
144
248
|
|
|
145
|
-
|
|
249
|
+
---
|
|
146
250
|
|
|
147
|
-
|
|
251
|
+
##### `'error'`
|
|
148
252
|
|
|
149
|
-
|
|
150
|
-
- `topic` (string): Topic identifier (max 256 characters)
|
|
151
|
-
- `request` (CreateOfferRequest):
|
|
152
|
-
- `info` (string): Peer identifier/metadata (max 1024 characters)
|
|
153
|
-
- `offer` (string): WebRTC signaling data
|
|
253
|
+
Emitted when an error occurs.
|
|
154
254
|
|
|
155
|
-
|
|
255
|
+
```typescript
|
|
256
|
+
connection.on('error', (error: Error) => {
|
|
257
|
+
console.error('Connection error:', error.message);
|
|
258
|
+
});
|
|
259
|
+
```
|
|
156
260
|
|
|
157
|
-
|
|
261
|
+
---
|
|
158
262
|
|
|
159
|
-
|
|
263
|
+
##### `'datachannel'`
|
|
160
264
|
|
|
161
|
-
|
|
162
|
-
- `request` (AnswerRequest):
|
|
163
|
-
- `code` (string): Session UUID
|
|
164
|
-
- `answer` (string, optional): Answer signaling data
|
|
165
|
-
- `candidate` (string, optional): ICE candidate data
|
|
166
|
-
- `side` ('offerer' | 'answerer'): Which peer is sending
|
|
265
|
+
Emitted when a remote peer creates a data channel.
|
|
167
266
|
|
|
168
|
-
|
|
267
|
+
```typescript
|
|
268
|
+
connection.on('datachannel', (channel: RTCDataChannel) => {
|
|
269
|
+
console.log('Received channel:', channel.label);
|
|
270
|
+
channel.onmessage = (e) => console.log(e.data);
|
|
271
|
+
});
|
|
272
|
+
```
|
|
169
273
|
|
|
170
|
-
|
|
274
|
+
---
|
|
171
275
|
|
|
172
|
-
|
|
276
|
+
##### `'stream'`
|
|
173
277
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
278
|
+
Emitted when a remote media stream is received.
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
connection.on('stream', (stream: MediaStream) => {
|
|
282
|
+
videoElement.srcObject = stream;
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
177
287
|
|
|
178
|
-
|
|
288
|
+
## Usage Examples
|
|
179
289
|
|
|
180
|
-
|
|
290
|
+
### Example 1: Simple Chat Application
|
|
181
291
|
|
|
182
|
-
|
|
292
|
+
```typescript
|
|
293
|
+
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
294
|
+
|
|
295
|
+
const rdv = new Rondevu({
|
|
296
|
+
baseUrl: 'https://your-server.com',
|
|
297
|
+
rtcConfig: {
|
|
298
|
+
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Peer A: Create connection
|
|
303
|
+
const connectionA = await rdv.create('chat-room-123', 'chat-rooms');
|
|
183
304
|
|
|
184
|
-
|
|
305
|
+
connectionA.on('connect', () => {
|
|
306
|
+
const chat = connectionA.dataChannel('messages');
|
|
307
|
+
chat.send(JSON.stringify({ user: 'Alice', text: 'Hello!' }));
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
connectionA.on('datachannel', (channel) => {
|
|
311
|
+
if (channel.label === 'messages') {
|
|
312
|
+
channel.onmessage = (e) => {
|
|
313
|
+
const msg = JSON.parse(e.data);
|
|
314
|
+
console.log(`${msg.user}: ${msg.text}`);
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
});
|
|
185
318
|
|
|
186
|
-
|
|
319
|
+
// Share 'chat-room-123' with Peer B
|
|
187
320
|
|
|
188
|
-
|
|
321
|
+
// Peer B: Join connection
|
|
322
|
+
const connectionB = await rdv.connect('chat-room-123');
|
|
323
|
+
|
|
324
|
+
connectionB.on('connect', () => {
|
|
325
|
+
const chat = connectionB.dataChannel('messages');
|
|
326
|
+
chat.send(JSON.stringify({ user: 'Bob', text: 'Hi Alice!' }));
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
### Example 2: Video Chat
|
|
189
333
|
|
|
190
334
|
```typescript
|
|
191
|
-
import {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
335
|
+
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
336
|
+
|
|
337
|
+
const rdv = new Rondevu({
|
|
338
|
+
baseUrl: 'https://your-server.com',
|
|
339
|
+
rtcConfig: {
|
|
340
|
+
iceServers: [
|
|
341
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
342
|
+
{
|
|
343
|
+
urls: 'turn:your-turn-server.com:3478',
|
|
344
|
+
username: 'user',
|
|
345
|
+
credential: 'pass'
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// Get local video stream
|
|
352
|
+
const localStream = await navigator.mediaDevices.getUserMedia({
|
|
353
|
+
video: true,
|
|
354
|
+
audio: true
|
|
355
|
+
});
|
|
356
|
+
document.getElementById('local-video').srcObject = localStream;
|
|
357
|
+
|
|
358
|
+
// Create connection and add stream
|
|
359
|
+
const connection = await rdv.create('video-call-456', 'video-calls');
|
|
360
|
+
connection.addStream(localStream);
|
|
361
|
+
|
|
362
|
+
// Handle remote stream
|
|
363
|
+
connection.on('stream', (remoteStream) => {
|
|
364
|
+
document.getElementById('remote-video').srcObject = remoteStream;
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
connection.on('connect', () => {
|
|
368
|
+
console.log('Video call connected!');
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Other peer joins
|
|
372
|
+
// const connection = await rdv.connect('video-call-456');
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
### Example 3: Topic-Based Discovery
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
381
|
+
|
|
382
|
+
const rdv = new Rondevu({
|
|
383
|
+
baseUrl: 'https://your-server.com',
|
|
384
|
+
peerId: 'player-123' // Custom peer ID
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Create a game session
|
|
388
|
+
const host = await rdv.create('game-session-1', 'multiplayer-games');
|
|
389
|
+
|
|
390
|
+
host.on('connect', () => {
|
|
391
|
+
console.log('Player joined:', host.remotePeerId);
|
|
392
|
+
|
|
393
|
+
const game = host.dataChannel('game-state');
|
|
394
|
+
game.send(JSON.stringify({ type: 'start', level: 1 }));
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Another player discovers and joins
|
|
398
|
+
const player = await rdv.join('multiplayer-games', {
|
|
399
|
+
filter: (session) => session.peerId !== rdv.peerId, // Avoid self
|
|
400
|
+
select: 'first' // Join first available game
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
player.on('connect', () => {
|
|
404
|
+
console.log('Joined game with:', player.remotePeerId);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
player.on('datachannel', (channel) => {
|
|
408
|
+
channel.onmessage = (e) => {
|
|
409
|
+
const data = JSON.parse(e.data);
|
|
410
|
+
console.log('Game event:', data);
|
|
411
|
+
};
|
|
412
|
+
});
|
|
201
413
|
```
|
|
202
414
|
|
|
203
|
-
|
|
415
|
+
---
|
|
204
416
|
|
|
205
|
-
|
|
417
|
+
### Example 4: Connection Stats Monitoring
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
421
|
+
|
|
422
|
+
const rdv = new Rondevu({ baseUrl: 'https://your-server.com' });
|
|
423
|
+
const connection = await rdv.connect('meeting-123');
|
|
424
|
+
|
|
425
|
+
connection.on('connect', () => {
|
|
426
|
+
// Access underlying RTCPeerConnection for stats
|
|
427
|
+
const pc = connection.getPeerConnection();
|
|
428
|
+
|
|
429
|
+
setInterval(async () => {
|
|
430
|
+
const stats = await pc.getStats();
|
|
431
|
+
|
|
432
|
+
stats.forEach(report => {
|
|
433
|
+
if (report.type === 'candidate-pair' && report.state === 'succeeded') {
|
|
434
|
+
console.log('RTT:', report.currentRoundTripTime * 1000, 'ms');
|
|
435
|
+
console.log('Bytes sent:', report.bytesSent);
|
|
436
|
+
console.log('Bytes received:', report.bytesReceived);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
}, 2000);
|
|
440
|
+
});
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Low-Level API (Advanced)
|
|
446
|
+
|
|
447
|
+
For advanced use cases, you can use the low-level `RondevuClient` for manual signaling:
|
|
206
448
|
|
|
207
449
|
```typescript
|
|
208
|
-
import fetch from 'node-fetch';
|
|
209
450
|
import { RondevuClient } from '@xtr-dev/rondevu-client';
|
|
210
451
|
|
|
211
452
|
const client = new RondevuClient({
|
|
212
|
-
baseUrl: 'https://
|
|
213
|
-
|
|
453
|
+
baseUrl: 'https://your-server.com'
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// List topics
|
|
457
|
+
const { topics } = await client.listTopics();
|
|
458
|
+
|
|
459
|
+
// List sessions in a topic
|
|
460
|
+
const { sessions } = await client.listSessions('my-topic');
|
|
461
|
+
|
|
462
|
+
// Create offer manually
|
|
463
|
+
const { code } = await client.createOffer('my-topic', {
|
|
464
|
+
peerId: 'my-peer-id',
|
|
465
|
+
offer: sdpOffer,
|
|
466
|
+
code: 'custom-session-id' // Optional
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// Send answer
|
|
470
|
+
await client.sendAnswer({
|
|
471
|
+
code: sessionCode,
|
|
472
|
+
answer: sdpAnswer,
|
|
473
|
+
side: 'answerer'
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// Poll for remote data
|
|
477
|
+
const data = await client.poll(sessionCode, 'offerer');
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
See the original README for full low-level API documentation.
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## Configuration
|
|
485
|
+
|
|
486
|
+
### ICE Servers
|
|
487
|
+
|
|
488
|
+
Configure STUN/TURN servers for NAT traversal:
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
const rdv = new Rondevu({
|
|
492
|
+
baseUrl: 'https://your-server.com',
|
|
493
|
+
rtcConfig: {
|
|
494
|
+
iceServers: [
|
|
495
|
+
// Public STUN servers
|
|
496
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
497
|
+
{ urls: 'stun:stun1.l.google.com:19302' },
|
|
498
|
+
|
|
499
|
+
// Private TURN server (recommended for production)
|
|
500
|
+
{
|
|
501
|
+
urls: 'turn:your-turn-server.com:3478',
|
|
502
|
+
username: 'username',
|
|
503
|
+
credential: 'password'
|
|
504
|
+
}
|
|
505
|
+
],
|
|
506
|
+
iceTransportPolicy: 'all' // 'relay' to force TURN
|
|
507
|
+
}
|
|
214
508
|
});
|
|
215
509
|
```
|
|
216
510
|
|
|
511
|
+
### Polling and Timeouts
|
|
512
|
+
|
|
513
|
+
Customize polling interval and connection timeout:
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
const rdv = new Rondevu({
|
|
517
|
+
baseUrl: 'https://your-server.com',
|
|
518
|
+
pollingInterval: 500, // Poll every 500ms (default: 1000)
|
|
519
|
+
connectionTimeout: 60000 // 60 second timeout (default: 30000)
|
|
520
|
+
});
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Custom Peer ID
|
|
524
|
+
|
|
525
|
+
Provide a custom peer identifier:
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
const rdv = new Rondevu({
|
|
529
|
+
baseUrl: 'https://your-server.com',
|
|
530
|
+
peerId: 'user-alice-session-xyz'
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
console.log(rdv.peerId); // 'user-alice-session-xyz'
|
|
534
|
+
|
|
535
|
+
// Update later if needed
|
|
536
|
+
rdv.updatePeerId('user-alice-new-session');
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
217
541
|
## Error Handling
|
|
218
542
|
|
|
219
|
-
|
|
543
|
+
Always handle connection errors:
|
|
220
544
|
|
|
221
545
|
```typescript
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
546
|
+
const connection = await rdv.create('session-1', 'topic-1');
|
|
547
|
+
|
|
548
|
+
connection.on('error', (error) => {
|
|
549
|
+
console.error('Connection error:', error.message);
|
|
550
|
+
|
|
551
|
+
if (error.message.includes('timeout')) {
|
|
552
|
+
// Handle timeout
|
|
553
|
+
} else if (error.message.includes('not found')) {
|
|
554
|
+
// Handle session not found
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
connection.on('disconnect', () => {
|
|
559
|
+
console.log('Connection closed');
|
|
560
|
+
// Cleanup UI, attempt reconnection, etc.
|
|
561
|
+
});
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## TypeScript Support
|
|
567
|
+
|
|
568
|
+
The library is written in TypeScript and includes comprehensive type definitions:
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import {
|
|
572
|
+
Rondevu,
|
|
573
|
+
RondevuConnection,
|
|
574
|
+
RondevuOptions,
|
|
575
|
+
JoinOptions,
|
|
576
|
+
ConnectionRole
|
|
577
|
+
} from '@xtr-dev/rondevu-client';
|
|
578
|
+
|
|
579
|
+
const options: RondevuOptions = {
|
|
580
|
+
baseUrl: 'https://your-server.com',
|
|
581
|
+
rtcConfig: {
|
|
582
|
+
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
const rdv: Rondevu = new Rondevu(options);
|
|
587
|
+
const connection: RondevuConnection = await rdv.create('id', 'topic');
|
|
588
|
+
|
|
589
|
+
console.log(connection.role); // Type: 'offerer' | 'answerer'
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## Node.js Support
|
|
595
|
+
|
|
596
|
+
The library works in Node.js with a WebRTC polyfill:
|
|
597
|
+
|
|
598
|
+
```bash
|
|
599
|
+
npm install wrtc
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
604
|
+
import wrtc from 'wrtc';
|
|
605
|
+
|
|
606
|
+
// Polyfill WebRTC globals
|
|
607
|
+
global.RTCPeerConnection = wrtc.RTCPeerConnection;
|
|
608
|
+
global.RTCSessionDescription = wrtc.RTCSessionDescription;
|
|
609
|
+
global.RTCIceCandidate = wrtc.RTCIceCandidate;
|
|
610
|
+
|
|
611
|
+
const rdv = new Rondevu({
|
|
612
|
+
baseUrl: 'https://your-server.com',
|
|
613
|
+
fetch: fetch // Use node-fetch if needed
|
|
614
|
+
});
|
|
230
615
|
```
|
|
231
616
|
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## Browser Compatibility
|
|
620
|
+
|
|
621
|
+
- Chrome/Edge 56+
|
|
622
|
+
- Firefox 44+
|
|
623
|
+
- Safari 11+
|
|
624
|
+
- Opera 43+
|
|
625
|
+
|
|
626
|
+
Requires WebRTC support (`RTCPeerConnection`, `RTCDataChannel`).
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
232
630
|
## License
|
|
233
631
|
|
|
234
632
|
MIT
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## Links
|
|
637
|
+
|
|
638
|
+
- [GitHub Repository](https://github.com/xtr-dev/rondevu)
|
|
639
|
+
- [Server Documentation](https://github.com/xtr-dev/rondevu/tree/main/server)
|
|
640
|
+
- [Demo Application](https://github.com/xtr-dev/rondevu/tree/main/demo)
|