@xtr-dev/rondevu-client 0.0.1 → 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 CHANGED
@@ -1,6 +1,15 @@
1
1
  # @xtr-dev/rondevu-client
2
2
 
3
- TypeScript client for interacting with the Rondevu peer signaling and discovery server. Provides a simple, type-safe API for WebRTC peer discovery and connection establishment.
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
- ## Usage
12
-
13
- ### Basic Setup
20
+ ## Quick Start
14
21
 
15
22
  ```typescript
16
- import { RondevuClient } from '@xtr-dev/rondevu-client';
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
- const client = new RondevuClient({
19
- baseUrl: 'https://rondevu.example.com',
20
- // Optional: custom origin for session isolation
21
- origin: 'https://myapp.com'
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
- ### Peer Discovery Flow
47
+ ## API Documentation
48
+
49
+ ### Rondevu Class
26
50
 
27
- #### 1. List Available Topics
51
+ The main class for WebRTC connection management with automatic signaling.
52
+
53
+ #### Constructor
28
54
 
29
55
  ```typescript
30
- // Get all topics with peer counts
31
- const { topics, pagination } = await client.listTopics();
56
+ const rdv = new Rondevu(options: RondevuOptions);
57
+ ```
32
58
 
33
- topics.forEach(topic => {
34
- console.log(`${topic.topic}: ${topic.count} peers available`);
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
- #### 2. Create an Offer (Peer A)
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
- // Announce availability in a topic
42
- const { code } = await client.createOffer('my-room', {
43
- info: 'peer-A-unique-id',
44
- offer: webrtcOfferData
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
- console.log('Session code:', code);
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
- #### 3. Discover Peers (Peer B)
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
- // Find available peers in a topic
54
- const { sessions } = await client.listSessions('my-room');
118
+ const connection = await rdv.join('my-topic');
119
+ ```
55
120
 
56
- // Filter out your own sessions
57
- const otherPeers = sessions.filter(s => s.info !== 'my-peer-id');
121
+ **Parameters:**
122
+ - `topic` - Topic name to join
123
+ - `options` - Optional join options
58
124
 
59
- if (otherPeers.length > 0) {
60
- const peer = otherPeers[0];
61
- console.log('Found peer:', peer.info);
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
- #### 4. Send Answer (Peer B)
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
- // Connect to a peer by answering their offer
69
- await client.sendAnswer({
70
- code: peer.code,
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
- #### 5. Poll for Data (Both Peers)
144
+ ---
145
+
146
+ ##### `updatePeerId(newPeerId: string): void`
147
+
148
+ Updates the peer ID (useful when user identity changes).
77
149
 
78
150
  ```typescript
79
- // Offerer polls for answer
80
- const offererData = await client.poll(code, 'offerer');
81
- if (offererData.answer) {
82
- console.log('Received answer from peer');
83
- }
151
+ rdv.updatePeerId('new-peer-id');
152
+ ```
84
153
 
85
- // Answerer polls for offer details
86
- const answererData = await client.poll(code, 'answerer');
87
- console.log('Offer candidates:', answererData.offerCandidates);
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
- #### 6. Exchange ICE Candidates
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
- // Send additional signaling data
94
- await client.sendAnswer({
95
- code: sessionCode,
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
- ### Health Check
198
+ ---
199
+
200
+ ##### `getPeerConnection(): RTCPeerConnection`
201
+
202
+ Gets the underlying `RTCPeerConnection` for advanced use cases.
102
203
 
103
204
  ```typescript
104
- const health = await client.health();
105
- console.log('Server status:', health.status);
106
- console.log('Timestamp:', health.timestamp);
205
+ const pc = connection.getPeerConnection();
206
+ const stats = await pc.getStats();
107
207
  ```
108
208
 
109
- ## API Reference
209
+ **Use case:** Accessing WebRTC stats, adding custom tracks, or other advanced WebRTC features.
110
210
 
111
- ### `RondevuClient`
211
+ ---
112
212
 
113
- #### Constructor
213
+ ##### `close(): void`
214
+
215
+ Closes the connection and cleans up resources.
114
216
 
115
217
  ```typescript
116
- new RondevuClient(options: RondevuClientOptions)
218
+ connection.close();
117
219
  ```
118
220
 
119
- **Options:**
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
- #### Methods
223
+ #### Events
125
224
 
126
- ##### `listTopics(page?, limit?)`
225
+ Listen to connection events using the `.on()` method:
127
226
 
128
- Lists all topics with peer counts.
227
+ ##### `'connect'`
129
228
 
130
- **Parameters:**
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
- **Returns:** `Promise<ListTopicsResponse>`
231
+ ```typescript
232
+ connection.on('connect', () => {
233
+ console.log('Connected!');
234
+ });
235
+ ```
135
236
 
136
- ##### `listSessions(topic)`
237
+ ---
137
238
 
138
- Discovers available peers for a given topic.
239
+ ##### `'disconnect'`
139
240
 
140
- **Parameters:**
141
- - `topic` (string): Topic identifier
241
+ Emitted when the connection is closed or lost.
142
242
 
143
- **Returns:** `Promise<ListSessionsResponse>`
243
+ ```typescript
244
+ connection.on('disconnect', () => {
245
+ console.log('Disconnected');
246
+ });
247
+ ```
144
248
 
145
- ##### `createOffer(topic, request)`
249
+ ---
146
250
 
147
- Announces peer availability and creates a new session.
251
+ ##### `'error'`
148
252
 
149
- **Parameters:**
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
- **Returns:** `Promise<CreateOfferResponse>`
255
+ ```typescript
256
+ connection.on('error', (error: Error) => {
257
+ console.error('Connection error:', error.message);
258
+ });
259
+ ```
156
260
 
157
- ##### `sendAnswer(request)`
261
+ ---
158
262
 
159
- Sends an answer or candidate to an existing session.
263
+ ##### `'datachannel'`
160
264
 
161
- **Parameters:**
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
- **Returns:** `Promise<AnswerResponse>`
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
- ##### `poll(code, side)`
274
+ ---
171
275
 
172
- Polls for session data from the other peer.
276
+ ##### `'stream'`
173
277
 
174
- **Parameters:**
175
- - `code` (string): Session UUID
176
- - `side` ('offerer' | 'answerer'): Which side is polling
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
- **Returns:** `Promise<PollOffererResponse | PollAnswererResponse>`
288
+ ## Usage Examples
179
289
 
180
- ##### `health()`
290
+ ### Example 1: Simple Chat Application
181
291
 
182
- Checks server health.
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
- **Returns:** `Promise<HealthResponse>`
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
- ## TypeScript Types
319
+ // Share 'chat-room-123' with Peer B
187
320
 
188
- All types are exported from the main package:
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
- RondevuClient,
193
- Session,
194
- TopicInfo,
195
- CreateOfferRequest,
196
- AnswerRequest,
197
- PollRequest,
198
- Side,
199
- // ... and more
200
- } from '@xtr-dev/rondevu-client';
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
- ## Node.js Usage
415
+ ---
204
416
 
205
- For Node.js environments (v18+), the built-in fetch is used automatically. For older Node.js versions, provide a fetch implementation:
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://rondevu.example.com',
213
- fetch: fetch as any
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
- All API methods throw errors with descriptive messages:
543
+ Always handle connection errors:
220
544
 
221
545
  ```typescript
222
- try {
223
- await client.createOffer('my-room', {
224
- info: 'peer-id',
225
- offer: data
226
- });
227
- } catch (error) {
228
- console.error('Failed to create offer:', error.message);
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)