uniwrtc 1.0.1 → 1.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
@@ -2,10 +2,12 @@
2
2
 
3
3
  A universal WebRTC signaling service that provides a simple and flexible WebSocket-based signaling server for WebRTC applications.
4
4
 
5
+ Available on npm: https://www.npmjs.com/package/uniwrtc
6
+
5
7
  ## Features
6
8
 
7
9
  - 🚀 **Simple WebSocket-based signaling** - Easy to integrate with any WebRTC application
8
- - 🏠 **Room-based architecture** - Support for multiple rooms with isolated peer groups
10
+ - 🏠 **Session-based architecture** - Support for multiple sessions with isolated peer groups
9
11
  - 🔌 **Flexible client library** - Ready-to-use JavaScript client for browser and Node.js
10
12
  - 📡 **Real-time messaging** - Efficient message routing between peers
11
13
  - 🔄 **Auto-reconnection** - Built-in reconnection logic for reliable connections
@@ -56,9 +58,9 @@ Open `demo.html` in your web browser to try the interactive demo:
56
58
  1. Start the server with `npm start` (local signaling at `ws://localhost:8080`), **or** use the deployed Workers endpoint `wss://signal.peer.ooo`.
57
59
  2. Open `demo.html` in your browser.
58
60
  3. Click "Connect" to connect to the signaling server.
59
- 4. Enter a room ID and click "Join Room".
61
+ 4. Enter a session ID and click "Join Session".
60
62
  5. Open another browser window/tab with the same demo page.
61
- 6. Join the same room to see peer connections in action and P2P data channels open.
63
+ 6. Join the same session to see peer connections in action and P2P data channels open.
62
64
 
63
65
  ## Usage
64
66
 
@@ -68,19 +70,19 @@ The signaling server accepts WebSocket connections and supports the following me
68
70
 
69
71
  #### Client → Server Messages
70
72
 
71
- **Join a room:**
73
+ **Join a session:**
72
74
  ```json
73
75
  {
74
76
  "type": "join",
75
- "roomId": "room-123"
77
+ "sessionId": "session-123"
76
78
  }
77
79
  ```
78
80
 
79
- **Leave a room:**
81
+ **Leave a session:**
80
82
  ```json
81
83
  {
82
84
  "type": "leave",
83
- "roomId": "room-123"
85
+ "sessionId": "session-123"
84
86
  }
85
87
  ```
86
88
 
@@ -90,7 +92,7 @@ The signaling server accepts WebSocket connections and supports the following me
90
92
  "type": "offer",
91
93
  "offer": { /* RTCSessionDescription */ },
92
94
  "targetId": "peer-client-id",
93
- "roomId": "room-123"
95
+ "sessionId": "session-123"
94
96
  }
95
97
  ```
96
98
 
@@ -100,7 +102,7 @@ The signaling server accepts WebSocket connections and supports the following me
100
102
  "type": "answer",
101
103
  "answer": { /* RTCSessionDescription */ },
102
104
  "targetId": "peer-client-id",
103
- "roomId": "room-123"
105
+ "sessionId": "session-123"
104
106
  }
105
107
  ```
106
108
 
@@ -110,7 +112,7 @@ The signaling server accepts WebSocket connections and supports the following me
110
112
  "type": "ice-candidate",
111
113
  "candidate": { /* RTCIceCandidate */ },
112
114
  "targetId": "peer-client-id",
113
- "roomId": "room-123"
115
+ "sessionId": "session-123"
114
116
  }
115
117
  ```
116
118
 
@@ -132,11 +134,11 @@ The signaling server accepts WebSocket connections and supports the following me
132
134
  }
133
135
  ```
134
136
 
135
- **Room joined confirmation:**
137
+ **Session joined confirmation:**
136
138
  ```json
137
139
  {
138
140
  "type": "joined",
139
- "roomId": "room-123",
141
+ "sessionId": "session-123",
140
142
  "clientId": "abc123",
141
143
  "clients": ["xyz789", "def456"]
142
144
  }
@@ -146,8 +148,8 @@ The signaling server accepts WebSocket connections and supports the following me
146
148
  ```json
147
149
  {
148
150
  "type": "peer-joined",
149
- "peerId": "new-peer-id",
150
- "clientId": "new-peer-id"
151
+ "sessionId": "session-123",
152
+ "peerId": "new-peer-id"
151
153
  }
152
154
  ```
153
155
 
@@ -155,8 +157,8 @@ The signaling server accepts WebSocket connections and supports the following me
155
157
  ```json
156
158
  {
157
159
  "type": "peer-left",
158
- "peerId": "departed-peer-id",
159
- "clientId": "departed-peer-id"
160
+ "sessionId": "session-123",
161
+ "peerId": "departed-peer-id"
160
162
  }
161
163
  ```
162
164
 
@@ -166,9 +168,8 @@ Use directly from npm:
166
168
  ```javascript
167
169
  // ESM
168
170
  import { UniWRTCClient } from 'uniwrtc/client-browser.js';
169
- // or CommonJS
170
- const { UniWRTCClient } = require('uniwrtc/client-browser.js');
171
- // For Node.js signaling client use 'uniwrtc/client.js'
171
+ // or CommonJS (Node)
172
+ const { UniWRTCClient } = require('uniwrtc/client.js');
172
173
  ```
173
174
 
174
175
  The `client.js` library provides a convenient wrapper for the signaling protocol:
@@ -183,27 +184,27 @@ client.on('connected', (data) => {
183
184
  });
184
185
 
185
186
  client.on('joined', (data) => {
186
- console.log('Joined room:', data.roomId);
187
+ console.log('Joined session:', data.sessionId);
187
188
  console.log('Existing peers:', data.clients);
188
189
  });
189
190
 
190
191
  client.on('peer-joined', (data) => {
191
- console.log('New peer joined:', data.peerId || data.clientId);
192
+ console.log('New peer joined:', data.peerId);
192
193
  // Initiate WebRTC connection with new peer
193
194
  });
194
195
 
195
196
  client.on('offer', (data) => {
196
- console.log('Received offer from:', data.peerId || data.senderId);
197
+ console.log('Received offer from:', data.peerId);
197
198
  // Handle WebRTC offer
198
199
  });
199
200
 
200
201
  client.on('answer', (data) => {
201
- console.log('Received answer from:', data.peerId || data.senderId);
202
+ console.log('Received answer from:', data.peerId);
202
203
  // Handle WebRTC answer
203
204
  });
204
205
 
205
206
  client.on('ice-candidate', (data) => {
206
- console.log('Received ICE candidate from:', data.peerId || data.senderId);
207
+ console.log('Received ICE candidate from:', data.peerId);
207
208
  // Add ICE candidate to peer connection
208
209
  });
209
210
 
@@ -253,7 +254,7 @@ function createPeerConnection(peerId) {
253
254
 
254
255
  // Handle new peer
255
256
  client.on('peer-joined', async (data) => {
256
- const pc = createPeerConnection(data.clientId);
257
+ const pc = createPeerConnection(data.peerId);
257
258
 
258
259
  // Add local tracks
259
260
  const stream = await navigator.mediaDevices.getUserMedia({
@@ -265,22 +266,22 @@ client.on('peer-joined', async (data) => {
265
266
  // Create and send offer
266
267
  const offer = await pc.createOffer();
267
268
  await pc.setLocalDescription(offer);
268
- client.sendOffer(offer, data.clientId);
269
+ client.sendOffer(offer, data.peerId);
269
270
  });
270
271
 
271
272
  // Handle incoming offer
272
273
  client.on('offer', async (data) => {
273
- const pc = createPeerConnection(data.senderId);
274
+ const pc = createPeerConnection(data.peerId);
274
275
 
275
276
  await pc.setRemoteDescription(data.offer);
276
277
  const answer = await pc.createAnswer();
277
278
  await pc.setLocalDescription(answer);
278
- client.sendAnswer(answer, data.senderId);
279
+ client.sendAnswer(answer, data.peerId);
279
280
  });
280
281
 
281
282
  // Handle incoming answer
282
283
  client.on('answer', async (data) => {
283
- const pc = peerConnections.get(data.senderId);
284
+ const pc = peerConnections.get(data.peerId);
284
285
  if (pc) {
285
286
  await pc.setRemoteDescription(data.answer);
286
287
  }
@@ -288,15 +289,15 @@ client.on('answer', async (data) => {
288
289
 
289
290
  // Handle ICE candidates
290
291
  client.on('ice-candidate', async (data) => {
291
- const pc = peerConnections.get(data.senderId);
292
+ const pc = peerConnections.get(data.peerId);
292
293
  if (pc) {
293
294
  await pc.addIceCandidate(data.candidate);
294
295
  }
295
296
  });
296
297
 
297
- // Connect and join room
298
+ // Connect and join session
298
299
  await client.connect();
299
- client.joinRoom('my-video-room');
300
+ client.joinSession('my-video-session');
300
301
  ```
301
302
 
302
303
  ## API Reference
@@ -318,8 +319,8 @@ new UniWRTCClient(serverUrl, options)
318
319
 
319
320
  - `connect()`: Connect to the signaling server (returns Promise)
320
321
  - `disconnect()`: Disconnect from the server
321
- - `joinRoom(roomId)`: Join a specific room
322
- - `leaveRoom()`: Leave the current room
322
+ - `joinSession(sessionId)`: Join a specific session
323
+ - `leaveSession()`: Leave the current session
323
324
  - `sendOffer(offer, targetId)`: Send a WebRTC offer
324
325
  - `sendAnswer(answer, targetId)`: Send a WebRTC answer
325
326
  - `sendIceCandidate(candidate, targetId)`: Send an ICE candidate
@@ -342,7 +343,7 @@ new UniWRTCClient(serverUrl, options)
342
343
 
343
344
  ## Health Check
344
345
 
345
- The server provides an HTTP health check endpoint:
346
+ The server provides an HTTP health check endpoint for monitoring:
346
347
 
347
348
  ```bash
348
349
  curl http://localhost:8080/health
@@ -358,12 +359,12 @@ Response:
358
359
 
359
360
  ## Architecture
360
361
 
361
- ### Room Management
362
+ ### Session Management
362
363
 
363
- - Each room is identified by a unique room ID (string)
364
- - Clients can join/leave rooms dynamically
365
- - Messages can be sent to specific peers or broadcast to all peers in a room
366
- - Empty rooms are automatically cleaned up
364
+ - Each session is identified by a unique session ID (string)
365
+ - Clients can join/leave sessions dynamically
366
+ - Messages can be sent to specific peers or broadcast to all peers in a session
367
+ - Empty sessions are automatically cleaned up
367
368
 
368
369
  ### Message Flow
369
370
 
package/client-browser.js CHANGED
@@ -8,7 +8,7 @@ class UniWRTCClient {
8
8
  this.serverUrl = serverUrl;
9
9
  this.ws = null;
10
10
  this.clientId = null;
11
- this.roomId = null;
11
+ this.sessionId = null;
12
12
  this.peers = new Map();
13
13
  this._connectedOnce = false;
14
14
  this.options = {
@@ -93,24 +93,26 @@ class UniWRTCClient {
93
93
  }
94
94
  }
95
95
 
96
- joinRoom(roomId) {
97
- // Prevent duplicate join calls for the same room
98
- if (this.roomId === roomId) return;
99
- this.roomId = roomId;
96
+ joinSession(sessionId) {
97
+ // Prevent duplicate join calls for the same session
98
+ if (this.sessionId === sessionId) return;
99
+ this.sessionId = sessionId;
100
+
101
+ // Send join message
100
102
  this.send({
101
103
  type: 'join',
102
- roomId: roomId,
104
+ sessionId: sessionId,
103
105
  peerId: this.clientId
104
106
  });
105
107
  }
106
108
 
107
- leaveRoom() {
108
- if (this.roomId) {
109
+ leaveSession() {
110
+ if (this.sessionId) {
109
111
  this.send({
110
112
  type: 'leave',
111
- roomId: this.roomId
113
+ sessionId: this.sessionId
112
114
  });
113
- this.roomId = null;
115
+ this.sessionId = null;
114
116
  }
115
117
  }
116
118
 
@@ -122,30 +124,30 @@ class UniWRTCClient {
122
124
  }
123
125
  }
124
126
 
125
- sendOffer(targetId, offer) {
127
+ sendOffer(offer, targetId) {
126
128
  this.send({
127
129
  type: 'offer',
128
130
  offer: offer,
129
131
  targetId: targetId,
130
- roomId: this.roomId
132
+ sessionId: this.sessionId
131
133
  });
132
134
  }
133
135
 
134
- sendAnswer(targetId, answer) {
136
+ sendAnswer(answer, targetId) {
135
137
  this.send({
136
138
  type: 'answer',
137
139
  answer: answer,
138
140
  targetId: targetId,
139
- roomId: this.roomId
141
+ sessionId: this.sessionId
140
142
  });
141
143
  }
142
144
 
143
- sendIceCandidate(targetId, candidate) {
145
+ sendIceCandidate(candidate, targetId) {
144
146
  this.send({
145
147
  type: 'ice-candidate',
146
148
  candidate: candidate,
147
149
  targetId: targetId,
148
- roomId: this.roomId
150
+ sessionId: this.sessionId
149
151
  });
150
152
  }
151
153
 
@@ -187,9 +189,9 @@ class UniWRTCClient {
187
189
  console.log('[UniWRTC] If this helps, consider donating ❤️ → https://coff.ee/draederg');
188
190
  break;
189
191
  case 'joined':
190
- this.roomId = message.roomId;
192
+ this.sessionId = message.sessionId;
191
193
  this.emit('joined', {
192
- roomId: message.roomId,
194
+ sessionId: message.sessionId,
193
195
  peerId: message.peerId,
194
196
  clientId: message.clientId,
195
197
  clients: message.clients
@@ -197,14 +199,14 @@ class UniWRTCClient {
197
199
  break;
198
200
  case 'peer-joined':
199
201
  this.emit('peer-joined', {
200
- peerId: message.peerId || message.clientId,
201
- clientId: message.clientId
202
+ sessionId: message.sessionId,
203
+ peerId: message.peerId
202
204
  });
203
205
  break;
204
206
  case 'peer-left':
205
207
  this.emit('peer-left', {
206
- peerId: message.peerId || message.clientId,
207
- clientId: message.clientId
208
+ sessionId: message.sessionId,
209
+ peerId: message.peerId
208
210
  });
209
211
  break;
210
212
  case 'offer':
@@ -238,8 +240,8 @@ class UniWRTCClient {
238
240
  case 'chat':
239
241
  this.emit('chat', {
240
242
  text: message.text,
241
- senderId: message.senderId,
242
- roomId: message.roomId
243
+ peerId: message.peerId,
244
+ sessionId: message.sessionId
243
245
  });
244
246
  break;
245
247
  default:
@@ -247,3 +249,8 @@ class UniWRTCClient {
247
249
  }
248
250
  }
249
251
  }
252
+
253
+ // Attach to window for non-module script usage
254
+ if (typeof window !== 'undefined') {
255
+ window.UniWRTCClient = UniWRTCClient;
256
+ }
package/client.js CHANGED
@@ -8,7 +8,7 @@ class UniWRTCClient {
8
8
  this.serverUrl = serverUrl;
9
9
  this.ws = null;
10
10
  this.clientId = null;
11
- this.roomId = null;
11
+ this.sessionId = null;
12
12
  this.peers = new Map();
13
13
  this.options = {
14
14
  autoReconnect: true,
@@ -85,21 +85,21 @@ class UniWRTCClient {
85
85
  }
86
86
  }
87
87
 
88
- joinRoom(roomId) {
89
- this.roomId = roomId;
88
+ joinSession(sessionId) {
89
+ this.sessionId = sessionId;
90
90
  this.send({
91
91
  type: 'join',
92
- roomId: roomId
92
+ sessionId: sessionId
93
93
  });
94
94
  }
95
95
 
96
- leaveRoom() {
97
- if (this.roomId) {
96
+ leaveSession() {
97
+ if (this.sessionId) {
98
98
  this.send({
99
99
  type: 'leave',
100
- roomId: this.roomId
100
+ sessionId: this.sessionId
101
101
  });
102
- this.roomId = null;
102
+ this.sessionId = null;
103
103
  }
104
104
  }
105
105
 
@@ -108,7 +108,7 @@ class UniWRTCClient {
108
108
  type: 'offer',
109
109
  offer: offer,
110
110
  targetId: targetId,
111
- roomId: this.roomId
111
+ sessionId: this.sessionId
112
112
  });
113
113
  }
114
114
 
@@ -117,7 +117,7 @@ class UniWRTCClient {
117
117
  type: 'answer',
118
118
  answer: answer,
119
119
  targetId: targetId,
120
- roomId: this.roomId
120
+ sessionId: this.sessionId
121
121
  });
122
122
  }
123
123
 
@@ -126,7 +126,7 @@ class UniWRTCClient {
126
126
  type: 'ice-candidate',
127
127
  candidate: candidate,
128
128
  targetId: targetId,
129
- roomId: this.roomId
129
+ sessionId: this.sessionId
130
130
  });
131
131
  }
132
132
 
@@ -152,36 +152,38 @@ class UniWRTCClient {
152
152
  break;
153
153
  case 'joined':
154
154
  this.emit('joined', {
155
- roomId: message.roomId,
155
+ sessionId: message.sessionId,
156
156
  clientId: message.clientId,
157
157
  clients: message.clients
158
158
  });
159
159
  break;
160
160
  case 'peer-joined':
161
161
  this.emit('peer-joined', {
162
- clientId: message.clientId
162
+ sessionId: message.sessionId,
163
+ peerId: message.peerId
163
164
  });
164
165
  break;
165
166
  case 'peer-left':
166
167
  this.emit('peer-left', {
167
- clientId: message.clientId
168
+ sessionId: message.sessionId,
169
+ peerId: message.peerId
168
170
  });
169
171
  break;
170
172
  case 'offer':
171
173
  this.emit('offer', {
172
- senderId: message.senderId,
174
+ peerId: message.peerId,
173
175
  offer: message.offer
174
176
  });
175
177
  break;
176
178
  case 'answer':
177
179
  this.emit('answer', {
178
- senderId: message.senderId,
180
+ peerId: message.peerId,
179
181
  answer: message.answer
180
182
  });
181
183
  break;
182
184
  case 'ice-candidate':
183
185
  this.emit('ice-candidate', {
184
- senderId: message.senderId,
186
+ peerId: message.peerId,
185
187
  candidate: message.candidate
186
188
  });
187
189
  break;
package/demo.html CHANGED
@@ -282,11 +282,11 @@
282
282
  </div>
283
283
 
284
284
  <div class="card">
285
- <h2>Room Status</h2>
285
+ <h2>Room / Session</h2>
286
286
 
287
287
  <div class="connection-controls" style="margin-bottom: 15px;">
288
- <input type="text" id="roomId" placeholder="Enter room ID" value="demo-room">
289
- <button class="btn-primary" id="joinBtn" onclick="joinRoom()" disabled>Join Room</button>
288
+ <input type="text" id="roomId" placeholder="Enter room/session ID" value="demo-room">
289
+ <button class="btn-primary" id="joinBtn" onclick="joinSession()" disabled>Join</button>
290
290
  </div>
291
291
 
292
292
  <div id="roomInfo">
@@ -430,18 +430,26 @@
430
430
  log('Connecting to signaling server...', 'info');
431
431
 
432
432
  const customPeerId = document.getElementById('customPeerId').value.trim();
433
- client = new UniWRTCClient(serverUrl, { customPeerId: customPeerId || null });
433
+
434
+ // For Cloudflare (signal.peer.ooo), append room param to URL
435
+ let finalUrl = serverUrl;
436
+ const roomId = document.getElementById('roomId').value;
437
+ if (serverUrl.includes('signal.peer.ooo') && roomId) {
438
+ finalUrl = serverUrl + (serverUrl.includes('?') ? '&' : '?') + `room=${roomId}`;
439
+ }
440
+
441
+ client = new UniWRTCClient(finalUrl, { customPeerId: customPeerId || null });
434
442
 
435
443
  client.on('connected', (data) => {
436
444
  log(`Connected with ID: ${data.clientId}`, 'success');
437
445
  updateStatus(true);
438
446
 
439
- // Auto-join room after connecting
447
+ // Auto-join session after connecting
440
448
  const roomId = document.getElementById('roomId').value;
441
449
  if (roomId) {
442
450
  setTimeout(() => {
443
- log(`Auto-joining room: ${roomId}...`, 'info');
444
- client.joinRoom(roomId);
451
+ log(`Auto-joining session: ${roomId}...`, 'info');
452
+ client.joinSession(roomId);
445
453
  }, 500);
446
454
  }
447
455
  });
@@ -455,15 +463,21 @@
455
463
  let knownPeers = [];
456
464
 
457
465
  client.on('joined', (data) => {
458
- log(`Joined room: ${data.roomId}`, 'success');
466
+ log(`Joined session: ${data.sessionId}`, 'success');
459
467
  knownPeers = data.clients || [];
460
468
  updatePeersList(knownPeers);
461
469
 
462
- // Update room info with dynamic peer count
463
- updateRoomInfo(data.roomId, data.peerId || client.clientId);
470
+ // Update session info with dynamic peer count
471
+ updateRoomInfo(data.sessionId, client.clientId);
464
472
  });
465
473
 
466
474
  client.on('peer-joined', (data) => {
475
+ // Only connect to peers in the same session (if we have one set)
476
+ if (client.sessionId && data.sessionId !== client.sessionId) {
477
+ log(`Ignoring peer from different session: ${data.peerId}`, 'warning');
478
+ return;
479
+ }
480
+
467
481
  log(`Peer joined: ${data.peerId}`, 'success');
468
482
  // Add to known peers if not already there
469
483
  if (data.peerId && !knownPeers.includes(data.peerId)) {
@@ -471,8 +485,8 @@
471
485
  updatePeersList(knownPeers);
472
486
  }
473
487
 
474
- // Update room info with new peer count
475
- updateRoomInfo(client.roomId, client.clientId);
488
+ // Update session info with new peer count
489
+ updateRoomInfo(data.sessionId, client.clientId);
476
490
 
477
491
  // Auto-initiate P2P connection
478
492
  setTimeout(() => {
@@ -481,14 +495,19 @@
481
495
  });
482
496
 
483
497
  client.on('peer-left', (data) => {
484
- const peerId = data.peerId || data.clientId;
498
+ // Only process if from current session (if we have one set)
499
+ if (client.sessionId && data.sessionId !== client.sessionId) {
500
+ return;
501
+ }
502
+
503
+ const peerId = data.peerId;
485
504
  log(`Peer left: ${peerId}`, 'warning');
486
505
  // Remove from known peers
487
506
  knownPeers = knownPeers.filter(id => id !== peerId);
488
507
  updatePeersList(knownPeers);
489
508
 
490
- // Update room info with new peer count
491
- updateRoomInfo(client.roomId, client.clientId);
509
+ // Update session info with new peer count
510
+ updateRoomInfo(data.sessionId, client.clientId);
492
511
 
493
512
  // Close peer connection
494
513
  const pc = peerConnections.get(peerId);
@@ -511,7 +530,7 @@
511
530
  await pc.setLocalDescription(answer);
512
531
 
513
532
  // Send answer back
514
- client.sendAnswer(data.peerId, answer);
533
+ client.sendAnswer(answer, data.peerId);
515
534
  } catch (e) {
516
535
  log(`Offer error: ${e.message}`, 'error');
517
536
  }
@@ -552,8 +571,8 @@
552
571
  });
553
572
 
554
573
  client.on('chat', (data) => {
555
- displayChatMessage(data.text, `${data.senderId.substring(0, 6)}...`, false);
556
- log(`Chat from ${data.senderId}: ${data.text}`, 'info');
574
+ displayChatMessage(data.text, `${data.peerId.substring(0, 6)}...`, false);
575
+ log(`Chat from ${data.peerId}: ${data.text}`, 'info');
557
576
  });
558
577
 
559
578
  await client.connect();
@@ -580,8 +599,8 @@
580
599
  return;
581
600
  }
582
601
 
583
- if (!client || !client.roomId) {
584
- log('Not connected to a room', 'error');
602
+ if (!client || !client.sessionId) {
603
+ log('Not connected to a session', 'error');
585
604
  return;
586
605
  }
587
606
 
@@ -590,10 +609,10 @@
590
609
  document.getElementById('manualPeerId').value = '';
591
610
  }
592
611
 
593
- function joinRoom() {
594
- const roomId = document.getElementById('roomId').value;
612
+ function joinSession() {
613
+ const sessionId = document.getElementById('roomId').value;
595
614
 
596
- if (!roomId) {
615
+ if (!sessionId) {
597
616
  log('Please enter a room ID', 'error');
598
617
  return;
599
618
  }
@@ -603,8 +622,8 @@
603
622
  return;
604
623
  }
605
624
 
606
- log(`Joining room: ${roomId}...`, 'info');
607
- client.joinRoom(roomId);
625
+ log(`Joining session: ${sessionId}...`, 'info');
626
+ client.joinSession(sessionId);
608
627
  }
609
628
 
610
629
  function listRooms() {
@@ -619,12 +638,15 @@
619
638
 
620
639
  async function createPeerConnection(peerId, initiator = false) {
621
640
  if (peerConnections.has(peerId)) {
641
+ log(`Peer connection already exists for ${peerId.substring(0, 6)}`, 'info');
622
642
  return peerConnections.get(peerId);
623
643
  }
624
644
 
625
645
  // Determine who should initiate based on peer IDs (lexicographic comparison)
626
646
  // Only the peer with smaller ID creates the offer
627
647
  const shouldInitiate = client.clientId < peerId;
648
+
649
+ log(`Creating peer connection with ${peerId.substring(0, 6)} (shouldInitiate: ${shouldInitiate})`, 'info');
628
650
 
629
651
  const pc = new RTCPeerConnection({
630
652
  iceServers: [
@@ -635,11 +657,12 @@
635
657
  pc.onicecandidate = (event) => {
636
658
  if (event.candidate) {
637
659
  log(`Sending ICE candidate to ${peerId.substring(0, 6)}...`, 'info');
638
- client.sendIceCandidate(peerId, event.candidate);
660
+ client.sendIceCandidate(event.candidate, peerId);
639
661
  }
640
662
  };
641
663
 
642
664
  pc.ondatachannel = (event) => {
665
+ log(`Received data channel from ${peerId.substring(0, 6)}`, 'info');
643
666
  setupDataChannel(peerId, event.channel);
644
667
  };
645
668
 
@@ -649,8 +672,10 @@
649
672
 
650
673
  const offer = await pc.createOffer();
651
674
  await pc.setLocalDescription(offer);
652
- client.sendOffer(peerId, offer);
675
+ client.sendOffer(offer, peerId);
653
676
  log(`Sent offer to ${peerId.substring(0, 6)}...`, 'success');
677
+ } else {
678
+ log(`Waiting for offer from ${peerId.substring(0, 6)}...`, 'info');
654
679
  }
655
680
 
656
681
  peerConnections.set(peerId, pc);
@@ -660,7 +685,6 @@
660
685
  function setupDataChannel(peerId, dataChannel) {
661
686
  dataChannel.onopen = () => {
662
687
  log(`Data channel open with ${peerId.substring(0, 6)}...`, 'success');
663
- dataChannels.set(peerId, dataChannel);
664
688
  };
665
689
 
666
690
  dataChannel.onmessage = (event) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uniwrtc",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A universal WebRTC signaling service",
5
5
  "main": "server.js",
6
6
  "scripts": {
package/server.js CHANGED
@@ -54,9 +54,12 @@ function log(message, data = '') {
54
54
  console.log(`[${timestamp}] ${message}`, data);
55
55
  }
56
56
 
57
- function broadcastToRoom(roomId, message, excludeClient = null) {
58
- const room = rooms.get(roomId);
59
- if (!room) return;
57
+ function broadcastToRoom(sessionId, message, excludeClient = null) {
58
+ const room = rooms.get(sessionId);
59
+ if (!room) {
60
+ log(`WARNING: Attempted to broadcast to non-existent session: ${sessionId}`);
61
+ return;
62
+ }
60
63
 
61
64
  room.clients.forEach(client => {
62
65
  if (client !== excludeClient && client.readyState === WebSocket.OPEN) {
@@ -164,33 +167,33 @@ function handleSetId(ws, message) {
164
167
  }
165
168
 
166
169
  function handleJoin(ws, message) {
167
- const { roomId } = message;
170
+ const { sessionId } = message;
168
171
 
169
- if (!roomId) {
170
- sendToClient(ws, { type: 'error', message: 'Room ID is required' });
172
+ if (!sessionId) {
173
+ sendToClient(ws, { type: 'error', message: 'Session ID is required' });
171
174
  return;
172
175
  }
173
176
 
174
- // Leave current room if in one
177
+ // Leave current session if in one
175
178
  if (ws.room) {
176
- handleLeave(ws, { roomId: ws.room });
179
+ handleLeave(ws, { sessionId: ws.room });
177
180
  }
178
181
 
179
- // Create room if it doesn't exist
180
- if (!rooms.has(roomId)) {
181
- rooms.set(roomId, {
182
- id: roomId,
182
+ // Create session if it doesn't exist
183
+ if (!rooms.has(sessionId)) {
184
+ rooms.set(sessionId, {
185
+ id: sessionId,
183
186
  clients: new Set(),
184
187
  createdAt: Date.now()
185
188
  });
186
- log('Room created:', roomId);
189
+ log('Session created:', sessionId);
187
190
  }
188
191
 
189
- const room = rooms.get(roomId);
192
+ const room = rooms.get(sessionId);
190
193
  room.clients.add(ws);
191
- ws.room = roomId;
194
+ ws.room = sessionId;
192
195
 
193
- log(`Client ${ws.clientId} joined room ${roomId}`);
196
+ log(`Client ${ws.clientId} joined session ${sessionId}`);
194
197
 
195
198
  // Get list of existing clients in the room
196
199
  const existingClients = Array.from(room.clients)
@@ -200,51 +203,52 @@ function handleJoin(ws, message) {
200
203
  // Notify the joining client
201
204
  sendToClient(ws, {
202
205
  type: 'joined',
203
- roomId: roomId,
206
+ sessionId: sessionId,
204
207
  clientId: ws.clientId,
205
208
  clients: existingClients
206
209
  });
207
210
 
208
- // Notify other clients in the room
209
- broadcastToRoom(roomId, {
211
+ // Notify other clients in the session
212
+ broadcastToRoom(sessionId, {
210
213
  type: 'peer-joined',
211
- peerId: ws.clientId,
212
- clientId: ws.clientId
214
+ sessionId: sessionId,
215
+ peerId: ws.clientId
213
216
  }, ws);
214
217
  }
215
218
 
216
219
  function handleLeave(ws, message) {
217
- const { roomId } = message;
220
+ const { sessionId } = message;
218
221
 
219
- if (!roomId || !rooms.has(roomId)) {
222
+ if (!sessionId || !rooms.has(sessionId)) {
220
223
  return;
221
224
  }
222
225
 
223
- const room = rooms.get(roomId);
226
+ const room = rooms.get(sessionId);
224
227
  room.clients.delete(ws);
225
228
 
226
- log(`Client ${ws.clientId} left room ${roomId}`);
229
+ log(`Client ${ws.clientId} left session ${sessionId}`);
227
230
 
228
231
  // Notify other clients
229
- broadcastToRoom(roomId, {
232
+ broadcastToRoom(sessionId, {
230
233
  type: 'peer-left',
231
- clientId: ws.clientId
234
+ sessionId: sessionId,
235
+ peerId: ws.clientId
232
236
  });
233
237
 
234
- // Clean up empty rooms
238
+ // Clean up empty sessions
235
239
  if (room.clients.size === 0) {
236
- rooms.delete(roomId);
237
- log('Room deleted:', roomId);
240
+ rooms.delete(sessionId);
241
+ log('Session deleted:', sessionId);
238
242
  }
239
243
 
240
244
  ws.room = null;
241
245
  }
242
246
 
243
247
  function handleSignaling(ws, message) {
244
- const { targetId, roomId } = message;
248
+ const { targetId, sessionId } = message;
245
249
 
246
250
  if (!ws.room) {
247
- sendToClient(ws, { type: 'error', message: 'Not in a room' });
251
+ sendToClient(ws, { type: 'error', message: 'Not in a session' });
248
252
  return;
249
253
  }
250
254
 
@@ -273,29 +277,29 @@ function handleSignaling(ws, message) {
273
277
  }
274
278
 
275
279
  function handleChat(ws, message) {
276
- const { roomId, text } = message;
280
+ const { sessionId, text } = message;
277
281
 
278
- if (!roomId || !text) {
279
- sendToClient(ws, { type: 'error', message: 'Room ID and text are required' });
282
+ if (!sessionId || !text) {
283
+ sendToClient(ws, { type: 'error', message: 'Session ID and text are required' });
280
284
  return;
281
285
  }
282
286
 
283
- log(`Chat message in room ${roomId}: ${text.substring(0, 50)}`);
287
+ log(`Chat message in session ${sessionId}: ${text.substring(0, 50)}`);
284
288
 
285
- const room = rooms.get(roomId);
289
+ const room = rooms.get(sessionId);
286
290
  if (!room) {
287
- sendToClient(ws, { type: 'error', message: 'Room not found' });
291
+ sendToClient(ws, { type: 'error', message: 'Session not found' });
288
292
  return;
289
293
  }
290
294
 
291
- // Broadcast chat to ALL clients in the room (including sender)
295
+ // Broadcast chat to ALL clients in the session (including sender)
292
296
  room.clients.forEach(client => {
293
297
  if (client.readyState === WebSocket.OPEN) {
294
298
  client.send(JSON.stringify({
295
299
  type: 'chat',
296
300
  text: text,
297
- senderId: ws.clientId,
298
- roomId: roomId
301
+ peerId: ws.clientId,
302
+ sessionId: sessionId
299
303
  }));
300
304
  }
301
305
  });
@@ -109,14 +109,14 @@ class UniWRTCClient {
109
109
  }
110
110
  }
111
111
 
112
- joinRoom(roomId) {
113
- this.roomId = roomId;
114
- // Durable Objects handle room joining automatically via room parameter
112
+ joinSession(sessionId) {
113
+ this.sessionId = sessionId;
114
+ // Durable Objects handle session joining automatically via room parameter
115
115
  }
116
116
 
117
- leaveRoom() {
118
- if (this.roomId) {
119
- this.roomId = null;
117
+ leaveSession() {
118
+ if (this.sessionId) {
119
+ this.sessionId = null;
120
120
  }
121
121
  }
122
122
 
@@ -128,7 +128,7 @@ class UniWRTCClient {
128
128
  }
129
129
  }
130
130
 
131
- sendOffer(targetId, offer) {
131
+ sendOffer(offer, targetId) {
132
132
  this.send({
133
133
  type: 'offer',
134
134
  offer: offer,
@@ -136,7 +136,7 @@ class UniWRTCClient {
136
136
  });
137
137
  }
138
138
 
139
- sendAnswer(targetId, answer) {
139
+ sendAnswer(answer, targetId) {
140
140
  this.send({
141
141
  type: 'answer',
142
142
  answer: answer,
@@ -144,7 +144,7 @@ class UniWRTCClient {
144
144
  });
145
145
  }
146
146
 
147
- sendIceCandidate(targetId, candidate) {
147
+ sendIceCandidate(candidate, targetId) {
148
148
  this.send({
149
149
  type: 'ice-candidate',
150
150
  candidate: candidate,
@@ -188,21 +188,23 @@ class UniWRTCClient {
188
188
  console.log('[UniWRTC] If this helps, consider donating ❤️ → https://coff.ee/draederg');
189
189
  break;
190
190
  case 'joined':
191
- this.roomId = message.roomId;
191
+ this.sessionId = message.sessionId;
192
192
  this.emit('joined', {
193
- roomId: message.roomId,
193
+ sessionId: message.sessionId,
194
194
  clientId: message.clientId,
195
195
  clients: message.clients
196
196
  });
197
197
  break;
198
198
  case 'peer-joined':
199
199
  this.emit('peer-joined', {
200
- clientId: message.clientId
200
+ sessionId: message.sessionId,
201
+ peerId: message.peerId
201
202
  });
202
203
  break;
203
204
  case 'peer-left':
204
205
  this.emit('peer-left', {
205
- clientId: message.clientId
206
+ sessionId: message.sessionId,
207
+ peerId: message.peerId
206
208
  });
207
209
  break;
208
210
  case 'offer':
@@ -236,8 +238,8 @@ class UniWRTCClient {
236
238
  case 'chat':
237
239
  this.emit('chat', {
238
240
  text: message.text,
239
- senderId: message.senderId,
240
- roomId: message.roomId
241
+ peerId: message.peerId,
242
+ sessionId: message.sessionId
241
243
  });
242
244
  break;
243
245
  default:
package/src/room.js CHANGED
@@ -17,7 +17,7 @@ export class Room {
17
17
  const clientId = crypto.randomUUID().substring(0, 9);
18
18
  this.clients.set(clientId, server);
19
19
 
20
- console.log(`[Room] Client ${clientId} joined (total: ${this.clients.size})`);
20
+ console.log(`[Room] Client ${clientId} connected (total: ${this.clients.size})`);
21
21
 
22
22
  // Send welcome message
23
23
  server.send(JSON.stringify({
@@ -26,11 +26,7 @@ export class Room {
26
26
  message: 'Connected to UniWRTC signaling room'
27
27
  }));
28
28
 
29
- // Notify existing clients
30
- this.broadcast({
31
- type: 'peer-joined',
32
- clientId: clientId
33
- }, clientId);
29
+ // NOTE: peer-joined is sent when client explicitly joins via 'join' message
34
30
 
35
31
  server.onmessage = async (event) => {
36
32
  try {
@@ -45,10 +41,10 @@ export class Room {
45
41
  server.onclose = () => {
46
42
  console.log(`[Room] Client ${clientId} left`);
47
43
  this.clients.delete(clientId);
44
+ // Note: sessionId should be tracked per client if needed
48
45
  this.broadcast({
49
46
  type: 'peer-left',
50
- peerId: clientId,
51
- clientId: clientId
47
+ peerId: clientId
52
48
  });
53
49
  };
54
50
 
@@ -81,7 +77,7 @@ export class Room {
81
77
  }
82
78
 
83
79
  async handleJoin(clientId, message) {
84
- const { roomId, peerId } = message;
80
+ const { sessionId, peerId } = message;
85
81
 
86
82
  // Get list of other peers
87
83
  const peers = Array.from(this.clients.keys())
@@ -89,11 +85,11 @@ export class Room {
89
85
 
90
86
  const client = this.clients.get(clientId);
91
87
  if (client && client.readyState === WebSocket.OPEN) {
92
- // Send joined confirmation
88
+ // Send joined confirmation (align with server schema)
93
89
  client.send(JSON.stringify({
94
90
  type: 'joined',
95
- roomId: roomId,
96
- peerId: peerId || clientId,
91
+ sessionId: sessionId,
92
+ clientId: clientId,
97
93
  clients: peers
98
94
  }));
99
95
  }
@@ -101,8 +97,8 @@ export class Room {
101
97
  // Notify other peers
102
98
  this.broadcast({
103
99
  type: 'peer-joined',
104
- peerId: peerId || clientId,
105
- clientId: clientId
100
+ sessionId: sessionId,
101
+ peerId: clientId
106
102
  }, clientId);
107
103
  }
108
104