@xtr-dev/rondevu-client 0.7.3 → 0.7.4
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 +195 -73
- package/dist/offers.d.ts +0 -4
- package/dist/offers.js +0 -15
- package/dist/peer/exchanging-ice-state.js +1 -1
- package/dist/peer/index.d.ts +4 -1
- package/dist/peer/index.js +18 -2
- package/dist/peer/state.js +1 -1
- package/dist/rondevu.d.ts +36 -0
- package/dist/rondevu.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
🌐 **Topic-based peer discovery and WebRTC signaling client**
|
|
6
6
|
|
|
7
|
-
TypeScript/JavaScript client for Rondevu, providing topic-based peer discovery, stateless authentication, and complete WebRTC signaling.
|
|
7
|
+
TypeScript/JavaScript client for Rondevu, providing topic-based peer discovery, stateless authentication, and complete WebRTC signaling with trickle ICE support.
|
|
8
8
|
|
|
9
9
|
**Related repositories:**
|
|
10
|
-
- [rondevu-server](https://github.com/xtr-dev/rondevu) - HTTP signaling server
|
|
10
|
+
- [rondevu-server](https://github.com/xtr-dev/rondevu-server) - HTTP signaling server
|
|
11
11
|
- [rondevu-demo](https://rondevu-demo.pages.dev) - Interactive demo
|
|
12
12
|
|
|
13
13
|
---
|
|
@@ -19,6 +19,8 @@ TypeScript/JavaScript client for Rondevu, providing topic-based peer discovery,
|
|
|
19
19
|
- **Bloom Filters**: Efficient peer exclusion for repeated discoveries
|
|
20
20
|
- **Multi-Offer Management**: Create and manage multiple offers per peer
|
|
21
21
|
- **Complete WebRTC Signaling**: Full offer/answer and ICE candidate exchange
|
|
22
|
+
- **Trickle ICE**: Send ICE candidates as they're discovered (faster connections)
|
|
23
|
+
- **State Machine**: Clean state-based connection lifecycle
|
|
22
24
|
- **TypeScript**: Full type safety and autocomplete
|
|
23
25
|
|
|
24
26
|
## Install
|
|
@@ -29,36 +31,42 @@ npm install @xtr-dev/rondevu-client
|
|
|
29
31
|
|
|
30
32
|
## Quick Start
|
|
31
33
|
|
|
32
|
-
The easiest way to use Rondevu is with the high-level `RondevuConnection` class, which handles all WebRTC connection complexity including offer/answer exchange, ICE candidates, and connection lifecycle.
|
|
33
|
-
|
|
34
34
|
### Creating an Offer (Peer A)
|
|
35
35
|
|
|
36
36
|
```typescript
|
|
37
37
|
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
38
38
|
|
|
39
|
+
// Initialize client and register
|
|
39
40
|
const client = new Rondevu({ baseUrl: 'https://api.ronde.vu' });
|
|
40
41
|
await client.register();
|
|
41
42
|
|
|
42
|
-
// Create
|
|
43
|
-
const
|
|
43
|
+
// Create peer connection
|
|
44
|
+
const peer = client.createPeer();
|
|
44
45
|
|
|
45
46
|
// Set up event listeners
|
|
46
|
-
|
|
47
|
-
console.log('
|
|
47
|
+
peer.on('state', (state) => {
|
|
48
|
+
console.log('Peer state:', state);
|
|
49
|
+
// States: idle → creating-offer → waiting-for-answer → exchanging-ice → connected
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
peer.on('connected', () => {
|
|
53
|
+
console.log('✅ Connected to peer!');
|
|
48
54
|
});
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
console.log('Data channel ready');
|
|
56
|
+
peer.on('datachannel', (channel) => {
|
|
57
|
+
console.log('📡 Data channel ready');
|
|
52
58
|
|
|
53
|
-
channel.
|
|
54
|
-
console.log('Received:', event.data);
|
|
55
|
-
};
|
|
59
|
+
channel.addEventListener('message', (event) => {
|
|
60
|
+
console.log('📥 Received:', event.data);
|
|
61
|
+
});
|
|
56
62
|
|
|
57
|
-
channel.
|
|
63
|
+
channel.addEventListener('open', () => {
|
|
64
|
+
channel.send('Hello from peer A!');
|
|
65
|
+
});
|
|
58
66
|
});
|
|
59
67
|
|
|
60
68
|
// Create offer and advertise on topics
|
|
61
|
-
const offerId = await
|
|
69
|
+
const offerId = await peer.createOffer({
|
|
62
70
|
topics: ['my-app', 'room-123'],
|
|
63
71
|
ttl: 300000 // 5 minutes
|
|
64
72
|
});
|
|
@@ -72,6 +80,7 @@ console.log('Share these topics with peers:', ['my-app', 'room-123']);
|
|
|
72
80
|
```typescript
|
|
73
81
|
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
74
82
|
|
|
83
|
+
// Initialize client and register
|
|
75
84
|
const client = new Rondevu({ baseUrl: 'https://api.ronde.vu' });
|
|
76
85
|
await client.register();
|
|
77
86
|
|
|
@@ -81,65 +90,104 @@ const offers = await client.offers.findByTopic('my-app', { limit: 10 });
|
|
|
81
90
|
if (offers.length > 0) {
|
|
82
91
|
const offer = offers[0];
|
|
83
92
|
|
|
84
|
-
// Create connection
|
|
85
|
-
const
|
|
93
|
+
// Create peer connection
|
|
94
|
+
const peer = client.createPeer();
|
|
86
95
|
|
|
87
96
|
// Set up event listeners
|
|
88
|
-
|
|
89
|
-
console.log('
|
|
97
|
+
peer.on('state', (state) => {
|
|
98
|
+
console.log('Peer state:', state);
|
|
99
|
+
// States: idle → answering → exchanging-ice → connected
|
|
90
100
|
});
|
|
91
101
|
|
|
92
|
-
|
|
93
|
-
console.log('Connected!');
|
|
102
|
+
peer.on('connected', () => {
|
|
103
|
+
console.log('✅ Connected!');
|
|
94
104
|
});
|
|
95
105
|
|
|
96
|
-
|
|
97
|
-
console.log('Data channel ready');
|
|
106
|
+
peer.on('datachannel', (channel) => {
|
|
107
|
+
console.log('📡 Data channel ready');
|
|
98
108
|
|
|
99
|
-
channel.
|
|
100
|
-
console.log('Received:', event.data);
|
|
101
|
-
};
|
|
109
|
+
channel.addEventListener('message', (event) => {
|
|
110
|
+
console.log('📥 Received:', event.data);
|
|
111
|
+
});
|
|
102
112
|
|
|
103
|
-
channel.
|
|
113
|
+
channel.addEventListener('open', () => {
|
|
114
|
+
channel.send('Hello from peer B!');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
peer.on('failed', (error) => {
|
|
119
|
+
console.error('❌ Connection failed:', error);
|
|
104
120
|
});
|
|
105
121
|
|
|
106
122
|
// Answer the offer
|
|
107
|
-
await
|
|
123
|
+
await peer.answer(offer.id, offer.sdp, {
|
|
124
|
+
topics: offer.topics
|
|
125
|
+
});
|
|
108
126
|
}
|
|
109
127
|
```
|
|
110
128
|
|
|
111
|
-
|
|
129
|
+
## Connection Lifecycle
|
|
130
|
+
|
|
131
|
+
The `RondevuPeer` uses a state machine for connection management:
|
|
132
|
+
|
|
133
|
+
### Offerer States
|
|
134
|
+
1. **idle** - Initial state
|
|
135
|
+
2. **creating-offer** - Creating WebRTC offer
|
|
136
|
+
3. **waiting-for-answer** - Polling for answer from peer
|
|
137
|
+
4. **exchanging-ice** - Exchanging ICE candidates
|
|
138
|
+
5. **connected** - Successfully connected
|
|
139
|
+
6. **failed** - Connection failed
|
|
140
|
+
7. **closed** - Connection closed
|
|
141
|
+
|
|
142
|
+
### Answerer States
|
|
143
|
+
1. **idle** - Initial state
|
|
144
|
+
2. **answering** - Creating WebRTC answer
|
|
145
|
+
3. **exchanging-ice** - Exchanging ICE candidates
|
|
146
|
+
4. **connected** - Successfully connected
|
|
147
|
+
5. **failed** - Connection failed
|
|
148
|
+
6. **closed** - Connection closed
|
|
149
|
+
|
|
150
|
+
### State Events
|
|
112
151
|
|
|
113
152
|
```typescript
|
|
114
|
-
|
|
115
|
-
|
|
153
|
+
peer.on('state', (stateName) => {
|
|
154
|
+
console.log('Current state:', stateName);
|
|
116
155
|
});
|
|
117
156
|
|
|
118
|
-
|
|
157
|
+
peer.on('connected', () => {
|
|
119
158
|
// Connection established successfully
|
|
120
159
|
});
|
|
121
160
|
|
|
122
|
-
|
|
161
|
+
peer.on('disconnected', () => {
|
|
123
162
|
// Connection lost or closed
|
|
124
163
|
});
|
|
125
164
|
|
|
126
|
-
|
|
127
|
-
//
|
|
165
|
+
peer.on('failed', (error) => {
|
|
166
|
+
// Connection failed
|
|
128
167
|
console.error('Connection error:', error);
|
|
129
168
|
});
|
|
130
169
|
|
|
131
|
-
|
|
132
|
-
// Data channel is ready
|
|
170
|
+
peer.on('datachannel', (channel) => {
|
|
171
|
+
// Data channel is ready (use channel.addEventListener)
|
|
133
172
|
});
|
|
134
173
|
|
|
135
|
-
|
|
174
|
+
peer.on('track', (event) => {
|
|
136
175
|
// Media track received (for audio/video streaming)
|
|
137
176
|
const stream = event.streams[0];
|
|
138
177
|
videoElement.srcObject = stream;
|
|
139
178
|
});
|
|
140
179
|
```
|
|
141
180
|
|
|
142
|
-
|
|
181
|
+
## Trickle ICE
|
|
182
|
+
|
|
183
|
+
This library implements **trickle ICE** for faster connection establishment:
|
|
184
|
+
|
|
185
|
+
- ICE candidates are sent to the server as they're discovered
|
|
186
|
+
- No waiting for all candidates before sending offer/answer
|
|
187
|
+
- Connections establish much faster (milliseconds vs seconds)
|
|
188
|
+
- Proper event listener cleanup to prevent memory leaks
|
|
189
|
+
|
|
190
|
+
## Adding Media Tracks
|
|
143
191
|
|
|
144
192
|
```typescript
|
|
145
193
|
// Get user's camera/microphone
|
|
@@ -148,29 +196,64 @@ const stream = await navigator.mediaDevices.getUserMedia({
|
|
|
148
196
|
audio: true
|
|
149
197
|
});
|
|
150
198
|
|
|
151
|
-
// Add tracks to connection
|
|
199
|
+
// Add tracks to peer connection
|
|
152
200
|
stream.getTracks().forEach(track => {
|
|
153
|
-
|
|
201
|
+
peer.addTrack(track, stream);
|
|
154
202
|
});
|
|
155
203
|
```
|
|
156
204
|
|
|
157
|
-
|
|
205
|
+
## Peer Properties
|
|
158
206
|
|
|
159
207
|
```typescript
|
|
208
|
+
// Get current state name
|
|
209
|
+
console.log(peer.stateName); // 'idle', 'creating-offer', 'connected', etc.
|
|
210
|
+
|
|
160
211
|
// Get connection state
|
|
161
|
-
console.log(
|
|
212
|
+
console.log(peer.connectionState); // RTCPeerConnectionState
|
|
213
|
+
|
|
214
|
+
// Get offer ID (after creating offer or answering)
|
|
215
|
+
console.log(peer.offerId);
|
|
162
216
|
|
|
163
|
-
// Get
|
|
164
|
-
console.log(
|
|
217
|
+
// Get role
|
|
218
|
+
console.log(peer.role); // 'offerer' or 'answerer'
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Closing a Connection
|
|
165
222
|
|
|
166
|
-
|
|
167
|
-
|
|
223
|
+
```typescript
|
|
224
|
+
await peer.close();
|
|
168
225
|
```
|
|
169
226
|
|
|
170
|
-
|
|
227
|
+
## Custom RTCConfiguration
|
|
171
228
|
|
|
172
229
|
```typescript
|
|
173
|
-
|
|
230
|
+
const peer = client.createPeer({
|
|
231
|
+
iceServers: [
|
|
232
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
233
|
+
{
|
|
234
|
+
urls: 'turn:turn.example.com:3478',
|
|
235
|
+
username: 'user',
|
|
236
|
+
credential: 'pass'
|
|
237
|
+
}
|
|
238
|
+
],
|
|
239
|
+
iceTransportPolicy: 'relay' // Force TURN relay (useful for testing)
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Timeouts
|
|
244
|
+
|
|
245
|
+
Configure connection timeouts:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
await peer.createOffer({
|
|
249
|
+
topics: ['my-topic'],
|
|
250
|
+
timeouts: {
|
|
251
|
+
iceGathering: 10000, // ICE gathering timeout (10s)
|
|
252
|
+
waitingForAnswer: 30000, // Waiting for answer timeout (30s)
|
|
253
|
+
creatingAnswer: 10000, // Creating answer timeout (10s)
|
|
254
|
+
iceConnection: 30000 // ICE connection timeout (30s)
|
|
255
|
+
}
|
|
256
|
+
});
|
|
174
257
|
```
|
|
175
258
|
|
|
176
259
|
## Platform-Specific Setup
|
|
@@ -197,6 +280,43 @@ const client = new Rondevu({
|
|
|
197
280
|
});
|
|
198
281
|
```
|
|
199
282
|
|
|
283
|
+
### Node.js with WebRTC (wrtc)
|
|
284
|
+
|
|
285
|
+
For WebRTC functionality in Node.js, you need to provide WebRTC polyfills since Node.js doesn't have native WebRTC support:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
npm install wrtc node-fetch
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
293
|
+
import fetch from 'node-fetch';
|
|
294
|
+
import { RTCPeerConnection, RTCSessionDescription, RTCIceCandidate } from 'wrtc';
|
|
295
|
+
|
|
296
|
+
const client = new Rondevu({
|
|
297
|
+
baseUrl: 'https://api.ronde.vu',
|
|
298
|
+
fetch: fetch as any,
|
|
299
|
+
RTCPeerConnection,
|
|
300
|
+
RTCSessionDescription,
|
|
301
|
+
RTCIceCandidate
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// Now you can use WebRTC features
|
|
305
|
+
await client.register();
|
|
306
|
+
const peer = client.createPeer({
|
|
307
|
+
iceServers: [
|
|
308
|
+
{ urls: 'stun:stun.l.google.com:19302' }
|
|
309
|
+
]
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Create offers, answer, etc.
|
|
313
|
+
const offerId = await peer.createOffer({
|
|
314
|
+
topics: ['my-topic']
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Note:** The `wrtc` package provides WebRTC bindings for Node.js. Alternative packages like `node-webrtc` can also be used - just pass their implementations to the Rondevu constructor.
|
|
319
|
+
|
|
200
320
|
### Deno
|
|
201
321
|
|
|
202
322
|
```typescript
|
|
@@ -230,7 +350,7 @@ export default {
|
|
|
230
350
|
|
|
231
351
|
## Low-Level API Usage
|
|
232
352
|
|
|
233
|
-
For
|
|
353
|
+
For direct control over the signaling process without WebRTC:
|
|
234
354
|
|
|
235
355
|
```typescript
|
|
236
356
|
import { Rondevu, BloomFilter } from '@xtr-dev/rondevu-client';
|
|
@@ -335,13 +455,6 @@ Get all offers owned by the authenticated peer.
|
|
|
335
455
|
const myOffers = await client.offers.getMine();
|
|
336
456
|
```
|
|
337
457
|
|
|
338
|
-
#### `client.offers.heartbeat(offerId)`
|
|
339
|
-
Update last_seen timestamp for an offer.
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
await client.offers.heartbeat(offerId);
|
|
343
|
-
```
|
|
344
|
-
|
|
345
458
|
#### `client.offers.delete(offerId)`
|
|
346
459
|
Delete a specific offer.
|
|
347
460
|
|
|
@@ -370,7 +483,7 @@ Post ICE candidates for an offer.
|
|
|
370
483
|
|
|
371
484
|
```typescript
|
|
372
485
|
await client.offers.addIceCandidates(offerId, [
|
|
373
|
-
'candidate:1 1 UDP...'
|
|
486
|
+
{ candidate: 'candidate:1 1 UDP...', sdpMid: '0', sdpMLineIndex: 0 }
|
|
374
487
|
]);
|
|
375
488
|
```
|
|
376
489
|
|
|
@@ -378,7 +491,7 @@ await client.offers.addIceCandidates(offerId, [
|
|
|
378
491
|
Get ICE candidates from the other peer.
|
|
379
492
|
|
|
380
493
|
```typescript
|
|
381
|
-
const candidates = await client.offers.getIceCandidates(offerId);
|
|
494
|
+
const candidates = await client.offers.getIceCandidates(offerId, since);
|
|
382
495
|
```
|
|
383
496
|
|
|
384
497
|
### Bloom Filter
|
|
@@ -414,8 +527,9 @@ import type {
|
|
|
414
527
|
IceCandidate,
|
|
415
528
|
FetchFunction,
|
|
416
529
|
RondevuOptions,
|
|
417
|
-
|
|
418
|
-
|
|
530
|
+
PeerOptions,
|
|
531
|
+
PeerEvents,
|
|
532
|
+
PeerTimeouts
|
|
419
533
|
} from '@xtr-dev/rondevu-client';
|
|
420
534
|
```
|
|
421
535
|
|
|
@@ -423,28 +537,36 @@ import type {
|
|
|
423
537
|
|
|
424
538
|
The client library is designed to work across different JavaScript runtimes:
|
|
425
539
|
|
|
426
|
-
| Environment | Native Fetch |
|
|
427
|
-
|
|
428
|
-
| Modern Browsers | ✅ Yes | ❌
|
|
429
|
-
| Node.js 18+ | ✅ Yes | ❌ No |
|
|
430
|
-
| Node.js < 18 | ❌ No | ✅
|
|
431
|
-
| Deno | ✅ Yes | ❌
|
|
432
|
-
| Bun | ✅ Yes | ❌ No |
|
|
433
|
-
| Cloudflare Workers | ✅ Yes | ❌ No |
|
|
540
|
+
| Environment | Native Fetch | Native WebRTC | Polyfills Needed |
|
|
541
|
+
|-------------|--------------|---------------|------------------|
|
|
542
|
+
| Modern Browsers | ✅ Yes | ✅ Yes | ❌ None |
|
|
543
|
+
| Node.js 18+ | ✅ Yes | ❌ No | ✅ WebRTC (wrtc) |
|
|
544
|
+
| Node.js < 18 | ❌ No | ❌ No | ✅ Fetch + WebRTC |
|
|
545
|
+
| Deno | ✅ Yes | ⚠️ Partial | ❌ None (signaling only) |
|
|
546
|
+
| Bun | ✅ Yes | ❌ No | ✅ WebRTC (wrtc) |
|
|
547
|
+
| Cloudflare Workers | ✅ Yes | ❌ No | ❌ None (signaling only) |
|
|
548
|
+
|
|
549
|
+
**For signaling-only (no WebRTC peer connections):**
|
|
550
|
+
|
|
551
|
+
Use the low-level API with `client.offers` - no WebRTC polyfills needed.
|
|
434
552
|
|
|
435
|
-
**
|
|
553
|
+
**For full WebRTC support in Node.js:**
|
|
436
554
|
|
|
437
555
|
```bash
|
|
438
|
-
npm install node-fetch
|
|
556
|
+
npm install wrtc node-fetch
|
|
439
557
|
```
|
|
440
558
|
|
|
441
559
|
```typescript
|
|
442
560
|
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
443
561
|
import fetch from 'node-fetch';
|
|
562
|
+
import { RTCPeerConnection, RTCSessionDescription, RTCIceCandidate } from 'wrtc';
|
|
444
563
|
|
|
445
564
|
const client = new Rondevu({
|
|
446
|
-
baseUrl: 'https://
|
|
447
|
-
fetch: fetch as any
|
|
565
|
+
baseUrl: 'https://api.ronde.vu',
|
|
566
|
+
fetch: fetch as any,
|
|
567
|
+
RTCPeerConnection,
|
|
568
|
+
RTCSessionDescription,
|
|
569
|
+
RTCIceCandidate
|
|
448
570
|
});
|
|
449
571
|
```
|
|
450
572
|
|
package/dist/offers.d.ts
CHANGED
package/dist/offers.js
CHANGED
|
@@ -108,21 +108,6 @@ export class RondevuOffers {
|
|
|
108
108
|
const data = await response.json();
|
|
109
109
|
return data.offers;
|
|
110
110
|
}
|
|
111
|
-
/**
|
|
112
|
-
* Update offer heartbeat
|
|
113
|
-
*/
|
|
114
|
-
async heartbeat(offerId) {
|
|
115
|
-
const response = await this.fetchFn(`${this.baseUrl}/offers/${encodeURIComponent(offerId)}/heartbeat`, {
|
|
116
|
-
method: 'PUT',
|
|
117
|
-
headers: {
|
|
118
|
-
Authorization: RondevuAuth.createAuthHeader(this.credentials),
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
if (!response.ok) {
|
|
122
|
-
const error = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
123
|
-
throw new Error(`Failed to update heartbeat: ${error.error || response.statusText}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
111
|
/**
|
|
127
112
|
* Delete an offer
|
|
128
113
|
*/
|
|
@@ -24,7 +24,7 @@ export class ExchangingIceState extends PeerState {
|
|
|
24
24
|
for (const cand of candidates) {
|
|
25
25
|
if (cand.candidate && cand.candidate.candidate && cand.candidate.candidate !== '') {
|
|
26
26
|
try {
|
|
27
|
-
await this.peer.pc.addIceCandidate(new RTCIceCandidate(cand.candidate));
|
|
27
|
+
await this.peer.pc.addIceCandidate(new this.peer.RTCIceCandidate(cand.candidate));
|
|
28
28
|
this.lastIceTimestamp = cand.createdAt;
|
|
29
29
|
}
|
|
30
30
|
catch (err) {
|
package/dist/peer/index.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export default class RondevuPeer extends EventEmitter<PeerEvents> {
|
|
|
12
12
|
offersApi: RondevuOffers;
|
|
13
13
|
offerId?: string;
|
|
14
14
|
role?: 'offerer' | 'answerer';
|
|
15
|
+
RTCPeerConnection: typeof RTCPeerConnection;
|
|
16
|
+
RTCSessionDescription: typeof RTCSessionDescription;
|
|
17
|
+
RTCIceCandidate: typeof RTCIceCandidate;
|
|
15
18
|
private _state;
|
|
16
19
|
private connectionStateChangeHandler?;
|
|
17
20
|
private dataChannelHandler?;
|
|
@@ -29,7 +32,7 @@ export default class RondevuPeer extends EventEmitter<PeerEvents> {
|
|
|
29
32
|
* RTCPeerConnection state
|
|
30
33
|
*/
|
|
31
34
|
get connectionState(): RTCPeerConnectionState;
|
|
32
|
-
constructor(offersApi: RondevuOffers, rtcConfig?: RTCConfiguration);
|
|
35
|
+
constructor(offersApi: RondevuOffers, rtcConfig?: RTCConfiguration, rtcPeerConnection?: typeof RTCPeerConnection, rtcSessionDescription?: typeof RTCSessionDescription, rtcIceCandidate?: typeof RTCIceCandidate);
|
|
33
36
|
/**
|
|
34
37
|
* Set up peer connection event handlers
|
|
35
38
|
*/
|
package/dist/peer/index.js
CHANGED
|
@@ -31,10 +31,26 @@ export default class RondevuPeer extends EventEmitter {
|
|
|
31
31
|
{ urls: 'stun:stun.l.google.com:19302' },
|
|
32
32
|
{ urls: 'stun:stun1.l.google.com:19302' }
|
|
33
33
|
]
|
|
34
|
-
}) {
|
|
34
|
+
}, rtcPeerConnection, rtcSessionDescription, rtcIceCandidate) {
|
|
35
35
|
super();
|
|
36
36
|
this.offersApi = offersApi;
|
|
37
|
-
|
|
37
|
+
// Use provided polyfills or fall back to globals
|
|
38
|
+
this.RTCPeerConnection = rtcPeerConnection || (typeof globalThis.RTCPeerConnection !== 'undefined'
|
|
39
|
+
? globalThis.RTCPeerConnection
|
|
40
|
+
: (() => {
|
|
41
|
+
throw new Error('RTCPeerConnection is not available. Please provide it in the Rondevu constructor options for Node.js environments.');
|
|
42
|
+
}));
|
|
43
|
+
this.RTCSessionDescription = rtcSessionDescription || (typeof globalThis.RTCSessionDescription !== 'undefined'
|
|
44
|
+
? globalThis.RTCSessionDescription
|
|
45
|
+
: (() => {
|
|
46
|
+
throw new Error('RTCSessionDescription is not available. Please provide it in the Rondevu constructor options for Node.js environments.');
|
|
47
|
+
}));
|
|
48
|
+
this.RTCIceCandidate = rtcIceCandidate || (typeof globalThis.RTCIceCandidate !== 'undefined'
|
|
49
|
+
? globalThis.RTCIceCandidate
|
|
50
|
+
: (() => {
|
|
51
|
+
throw new Error('RTCIceCandidate is not available. Please provide it in the Rondevu constructor options for Node.js environments.');
|
|
52
|
+
}));
|
|
53
|
+
this.pc = new this.RTCPeerConnection(rtcConfig);
|
|
38
54
|
this._state = new IdleState(this);
|
|
39
55
|
this.setupPeerConnection();
|
|
40
56
|
}
|
package/dist/peer/state.js
CHANGED
|
@@ -18,7 +18,7 @@ export class PeerState {
|
|
|
18
18
|
async handleIceCandidate(candidate) {
|
|
19
19
|
// ICE candidates can arrive in multiple states, so default is to add them
|
|
20
20
|
if (this.peer.pc.remoteDescription) {
|
|
21
|
-
await this.peer.pc.addIceCandidate(new RTCIceCandidate(candidate));
|
|
21
|
+
await this.peer.pc.addIceCandidate(new this.peer.RTCIceCandidate(candidate));
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
/**
|
package/dist/rondevu.d.ts
CHANGED
|
@@ -22,6 +22,39 @@ export interface RondevuOptions {
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
fetch?: FetchFunction;
|
|
25
|
+
/**
|
|
26
|
+
* Custom RTCPeerConnection implementation for Node.js environments
|
|
27
|
+
* Required when using in Node.js with wrtc or similar polyfills
|
|
28
|
+
*
|
|
29
|
+
* @example Node.js with wrtc
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { RTCPeerConnection } from 'wrtc';
|
|
32
|
+
* const client = new Rondevu({ RTCPeerConnection });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
RTCPeerConnection?: typeof RTCPeerConnection;
|
|
36
|
+
/**
|
|
37
|
+
* Custom RTCSessionDescription implementation for Node.js environments
|
|
38
|
+
* Required when using in Node.js with wrtc or similar polyfills
|
|
39
|
+
*
|
|
40
|
+
* @example Node.js with wrtc
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import { RTCSessionDescription } from 'wrtc';
|
|
43
|
+
* const client = new Rondevu({ RTCSessionDescription });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
RTCSessionDescription?: typeof RTCSessionDescription;
|
|
47
|
+
/**
|
|
48
|
+
* Custom RTCIceCandidate implementation for Node.js environments
|
|
49
|
+
* Required when using in Node.js with wrtc or similar polyfills
|
|
50
|
+
*
|
|
51
|
+
* @example Node.js with wrtc
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { RTCIceCandidate } from 'wrtc';
|
|
54
|
+
* const client = new Rondevu({ RTCIceCandidate });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
RTCIceCandidate?: typeof RTCIceCandidate;
|
|
25
58
|
}
|
|
26
59
|
export declare class Rondevu {
|
|
27
60
|
readonly auth: RondevuAuth;
|
|
@@ -29,6 +62,9 @@ export declare class Rondevu {
|
|
|
29
62
|
private credentials?;
|
|
30
63
|
private baseUrl;
|
|
31
64
|
private fetchFn?;
|
|
65
|
+
private rtcPeerConnection?;
|
|
66
|
+
private rtcSessionDescription?;
|
|
67
|
+
private rtcIceCandidate?;
|
|
32
68
|
constructor(options?: RondevuOptions);
|
|
33
69
|
/**
|
|
34
70
|
* Get offers API (requires authentication)
|
package/dist/rondevu.js
CHANGED
|
@@ -5,6 +5,9 @@ export class Rondevu {
|
|
|
5
5
|
constructor(options = {}) {
|
|
6
6
|
this.baseUrl = options.baseUrl || 'https://api.ronde.vu';
|
|
7
7
|
this.fetchFn = options.fetch;
|
|
8
|
+
this.rtcPeerConnection = options.RTCPeerConnection;
|
|
9
|
+
this.rtcSessionDescription = options.RTCSessionDescription;
|
|
10
|
+
this.rtcIceCandidate = options.RTCIceCandidate;
|
|
8
11
|
this.auth = new RondevuAuth(this.baseUrl, this.fetchFn);
|
|
9
12
|
if (options.credentials) {
|
|
10
13
|
this.credentials = options.credentials;
|
|
@@ -52,6 +55,6 @@ export class Rondevu {
|
|
|
52
55
|
if (!this._offers) {
|
|
53
56
|
throw new Error('Not authenticated. Call register() first or provide credentials.');
|
|
54
57
|
}
|
|
55
|
-
return new RondevuPeer(this._offers, rtcConfig);
|
|
58
|
+
return new RondevuPeer(this._offers, rtcConfig, this.rtcPeerConnection, this.rtcSessionDescription, this.rtcIceCandidate);
|
|
56
59
|
}
|
|
57
60
|
}
|