2 Commits

Author SHA1 Message Date
8d7075ccc4 0.7.3 2025-11-16 17:51:24 +01:00
db8f0f4ced Fix answerer authorization for ICE candidates
The answerer was getting 403 Forbidden when sending ICE candidates because
the server didn't know who the answerer was yet. ICE gathering starts when
setLocalDescription is called, but we were calling /answer AFTER that.

Fixed by sending the answer to the server BEFORE setLocalDescription:
1. Create answer SDP
2. Send answer to server (registers answererPeerId)
3. Set up ICE handler
4. Set local description (ICE gathering starts)

This ensures the server has answererPeerId set before ICE candidates arrive,
so they're properly authorized.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-16 17:51:04 +01:00
3 changed files with 13 additions and 9 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@xtr-dev/rondevu-client",
"version": "0.7.2",
"version": "0.7.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@xtr-dev/rondevu-client",
"version": "0.7.2",
"version": "0.7.3",
"license": "MIT",
"dependencies": {
"@xtr-dev/rondevu-client": "^0.5.1"

View File

@@ -1,6 +1,6 @@
{
"name": "@xtr-dev/rondevu-client",
"version": "0.7.2",
"version": "0.7.3",
"description": "TypeScript client for Rondevu topic-based peer discovery and signaling server",
"type": "module",
"main": "dist/index.js",

View File

@@ -23,15 +23,19 @@ export class AnsweringState extends PeerState {
sdp: offerSdp
});
// Create answer
const answer = await this.peer.pc.createAnswer();
// Send answer to server BEFORE setLocalDescription
// This registers us as the answerer so ICE candidates will be accepted
await this.peer.offersApi.answer(offerId, answer.sdp!);
// Enable trickle ICE - set up handler before ICE gathering starts
this.setupIceCandidateHandler();
// Create answer
const answer = await this.peer.pc.createAnswer();
await this.peer.pc.setLocalDescription(answer); // ICE gathering starts here
// Send answer to server immediately (don't wait for ICE)
await this.peer.offersApi.answer(offerId, answer.sdp!);
// Set local description - ICE gathering starts here
// Server already knows we're the answerer, so candidates will be accepted
await this.peer.pc.setLocalDescription(answer);
// Transition to exchanging ICE
const { ExchangingIceState } = await import('./exchanging-ice-state.js');