@xtr-dev/rondevu-client 0.11.0 → 0.12.0
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/dist/api.d.ts +16 -8
- package/dist/api.js +27 -17
- package/dist/rondevu-signaler.js +28 -15
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -99,27 +99,35 @@ export declare class RondevuAPI {
|
|
|
99
99
|
*/
|
|
100
100
|
getOffer(offerId: string): Promise<Offer>;
|
|
101
101
|
/**
|
|
102
|
-
* Answer
|
|
102
|
+
* Answer a service
|
|
103
103
|
*/
|
|
104
|
-
|
|
104
|
+
answerService(serviceUuid: string, sdp: string): Promise<{
|
|
105
|
+
offerId: string;
|
|
106
|
+
}>;
|
|
105
107
|
/**
|
|
106
|
-
* Get answer for
|
|
108
|
+
* Get answer for a service (offerer polls this)
|
|
107
109
|
*/
|
|
108
|
-
|
|
110
|
+
getServiceAnswer(serviceUuid: string): Promise<{
|
|
109
111
|
sdp: string;
|
|
112
|
+
offerId: string;
|
|
110
113
|
} | null>;
|
|
111
114
|
/**
|
|
112
115
|
* Search offers by topic
|
|
113
116
|
*/
|
|
114
117
|
searchOffers(topic: string): Promise<Offer[]>;
|
|
115
118
|
/**
|
|
116
|
-
* Add ICE candidates to
|
|
119
|
+
* Add ICE candidates to a service
|
|
117
120
|
*/
|
|
118
|
-
|
|
121
|
+
addServiceIceCandidates(serviceUuid: string, candidates: RTCIceCandidateInit[], offerId?: string): Promise<{
|
|
122
|
+
offerId: string;
|
|
123
|
+
}>;
|
|
119
124
|
/**
|
|
120
|
-
* Get ICE candidates for
|
|
125
|
+
* Get ICE candidates for a service (with polling support)
|
|
121
126
|
*/
|
|
122
|
-
|
|
127
|
+
getServiceIceCandidates(serviceUuid: string, since?: number, offerId?: string): Promise<{
|
|
128
|
+
candidates: IceCandidate[];
|
|
129
|
+
offerId: string;
|
|
130
|
+
}>;
|
|
123
131
|
/**
|
|
124
132
|
* Publish a service
|
|
125
133
|
*/
|
package/dist/api.js
CHANGED
|
@@ -131,27 +131,28 @@ export class RondevuAPI {
|
|
|
131
131
|
return await response.json();
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
|
-
* Answer
|
|
134
|
+
* Answer a service
|
|
135
135
|
*/
|
|
136
|
-
async
|
|
137
|
-
const response = await fetch(`${this.baseUrl}/
|
|
136
|
+
async answerService(serviceUuid, sdp) {
|
|
137
|
+
const response = await fetch(`${this.baseUrl}/services/${serviceUuid}/answer`, {
|
|
138
138
|
method: 'POST',
|
|
139
139
|
headers: {
|
|
140
140
|
'Content-Type': 'application/json',
|
|
141
141
|
...this.getAuthHeader(),
|
|
142
142
|
},
|
|
143
|
-
body: JSON.stringify({ sdp
|
|
143
|
+
body: JSON.stringify({ sdp }),
|
|
144
144
|
});
|
|
145
145
|
if (!response.ok) {
|
|
146
146
|
const error = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
147
|
-
throw new Error(`Failed to answer
|
|
147
|
+
throw new Error(`Failed to answer service: ${error.error || response.statusText}`);
|
|
148
148
|
}
|
|
149
|
+
return await response.json();
|
|
149
150
|
}
|
|
150
151
|
/**
|
|
151
|
-
* Get answer for
|
|
152
|
+
* Get answer for a service (offerer polls this)
|
|
152
153
|
*/
|
|
153
|
-
async
|
|
154
|
-
const response = await fetch(`${this.baseUrl}/
|
|
154
|
+
async getServiceAnswer(serviceUuid) {
|
|
155
|
+
const response = await fetch(`${this.baseUrl}/services/${serviceUuid}/answer`, {
|
|
155
156
|
headers: this.getAuthHeader(),
|
|
156
157
|
});
|
|
157
158
|
if (!response.ok) {
|
|
@@ -163,7 +164,7 @@ export class RondevuAPI {
|
|
|
163
164
|
throw new Error(`Failed to get answer: ${error.error || response.statusText}`);
|
|
164
165
|
}
|
|
165
166
|
const data = await response.json();
|
|
166
|
-
return { sdp: data.sdp };
|
|
167
|
+
return { sdp: data.sdp, offerId: data.offerId };
|
|
167
168
|
}
|
|
168
169
|
/**
|
|
169
170
|
* Search offers by topic
|
|
@@ -182,33 +183,42 @@ export class RondevuAPI {
|
|
|
182
183
|
// ICE Candidates
|
|
183
184
|
// ============================================
|
|
184
185
|
/**
|
|
185
|
-
* Add ICE candidates to
|
|
186
|
+
* Add ICE candidates to a service
|
|
186
187
|
*/
|
|
187
|
-
async
|
|
188
|
-
const response = await fetch(`${this.baseUrl}/
|
|
188
|
+
async addServiceIceCandidates(serviceUuid, candidates, offerId) {
|
|
189
|
+
const response = await fetch(`${this.baseUrl}/services/${serviceUuid}/ice-candidates`, {
|
|
189
190
|
method: 'POST',
|
|
190
191
|
headers: {
|
|
191
192
|
'Content-Type': 'application/json',
|
|
192
193
|
...this.getAuthHeader(),
|
|
193
194
|
},
|
|
194
|
-
body: JSON.stringify({ candidates }),
|
|
195
|
+
body: JSON.stringify({ candidates, offerId }),
|
|
195
196
|
});
|
|
196
197
|
if (!response.ok) {
|
|
197
198
|
const error = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
198
199
|
throw new Error(`Failed to add ICE candidates: ${error.error || response.statusText}`);
|
|
199
200
|
}
|
|
201
|
+
return await response.json();
|
|
200
202
|
}
|
|
201
203
|
/**
|
|
202
|
-
* Get ICE candidates for
|
|
204
|
+
* Get ICE candidates for a service (with polling support)
|
|
203
205
|
*/
|
|
204
|
-
async
|
|
205
|
-
const
|
|
206
|
+
async getServiceIceCandidates(serviceUuid, since = 0, offerId) {
|
|
207
|
+
const url = new URL(`${this.baseUrl}/services/${serviceUuid}/ice-candidates`);
|
|
208
|
+
url.searchParams.set('since', since.toString());
|
|
209
|
+
if (offerId) {
|
|
210
|
+
url.searchParams.set('offerId', offerId);
|
|
211
|
+
}
|
|
212
|
+
const response = await fetch(url.toString(), { headers: this.getAuthHeader() });
|
|
206
213
|
if (!response.ok) {
|
|
207
214
|
const error = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
208
215
|
throw new Error(`Failed to get ICE candidates: ${error.error || response.statusText}`);
|
|
209
216
|
}
|
|
210
217
|
const data = await response.json();
|
|
211
|
-
return
|
|
218
|
+
return {
|
|
219
|
+
candidates: data.candidates || [],
|
|
220
|
+
offerId: data.offerId
|
|
221
|
+
};
|
|
212
222
|
}
|
|
213
223
|
// ============================================
|
|
214
224
|
// Services
|
package/dist/rondevu-signaler.js
CHANGED
|
@@ -85,11 +85,12 @@ export class RondevuSignaler {
|
|
|
85
85
|
if (!answer.sdp) {
|
|
86
86
|
throw new Error('Answer SDP is required');
|
|
87
87
|
}
|
|
88
|
-
if (!this.
|
|
89
|
-
throw new Error('No
|
|
88
|
+
if (!this.serviceUuid) {
|
|
89
|
+
throw new Error('No service UUID available. Must receive offer first.');
|
|
90
90
|
}
|
|
91
|
-
// Send answer to the
|
|
92
|
-
await this.rondevu.getAPI().
|
|
91
|
+
// Send answer to the service
|
|
92
|
+
const result = await this.rondevu.getAPI().answerService(this.serviceUuid, answer.sdp);
|
|
93
|
+
this.offerId = result.offerId;
|
|
93
94
|
// Start polling for ICE candidates
|
|
94
95
|
this.startIcePolling();
|
|
95
96
|
}
|
|
@@ -129,8 +130,8 @@ export class RondevuSignaler {
|
|
|
129
130
|
* Send an ICE candidate to the remote peer
|
|
130
131
|
*/
|
|
131
132
|
async addIceCandidate(candidate) {
|
|
132
|
-
if (!this.
|
|
133
|
-
console.warn('Cannot send ICE candidate: no
|
|
133
|
+
if (!this.serviceUuid) {
|
|
134
|
+
console.warn('Cannot send ICE candidate: no service UUID');
|
|
134
135
|
return;
|
|
135
136
|
}
|
|
136
137
|
const candidateData = candidate.toJSON();
|
|
@@ -139,7 +140,11 @@ export class RondevuSignaler {
|
|
|
139
140
|
return;
|
|
140
141
|
}
|
|
141
142
|
try {
|
|
142
|
-
await this.rondevu.getAPI().
|
|
143
|
+
const result = await this.rondevu.getAPI().addServiceIceCandidates(this.serviceUuid, [candidateData], this.offerId || undefined);
|
|
144
|
+
// Store offerId if we didn't have it yet
|
|
145
|
+
if (!this.offerId) {
|
|
146
|
+
this.offerId = result.offerId;
|
|
147
|
+
}
|
|
143
148
|
}
|
|
144
149
|
catch (err) {
|
|
145
150
|
console.error('Failed to send ICE candidate:', err);
|
|
@@ -209,19 +214,23 @@ export class RondevuSignaler {
|
|
|
209
214
|
* Start polling for answer (offerer side) with exponential backoff
|
|
210
215
|
*/
|
|
211
216
|
startAnswerPolling() {
|
|
212
|
-
if (this.answerPollingTimeout || !this.
|
|
217
|
+
if (this.answerPollingTimeout || !this.serviceUuid) {
|
|
213
218
|
return;
|
|
214
219
|
}
|
|
215
220
|
let interval = this.pollingConfig.initialInterval;
|
|
216
221
|
let retries = 0;
|
|
217
222
|
const poll = async () => {
|
|
218
|
-
if (!this.
|
|
223
|
+
if (!this.serviceUuid) {
|
|
219
224
|
this.stopAnswerPolling();
|
|
220
225
|
return;
|
|
221
226
|
}
|
|
222
227
|
try {
|
|
223
|
-
const answer = await this.rondevu.getAPI().
|
|
228
|
+
const answer = await this.rondevu.getAPI().getServiceAnswer(this.serviceUuid);
|
|
224
229
|
if (answer && answer.sdp) {
|
|
230
|
+
// Store offerId if we didn't have it yet
|
|
231
|
+
if (!this.offerId) {
|
|
232
|
+
this.offerId = answer.offerId;
|
|
233
|
+
}
|
|
225
234
|
// Got answer - notify listeners and stop polling
|
|
226
235
|
const answerDesc = {
|
|
227
236
|
type: 'answer',
|
|
@@ -280,21 +289,25 @@ export class RondevuSignaler {
|
|
|
280
289
|
* Start polling for ICE candidates with adaptive backoff
|
|
281
290
|
*/
|
|
282
291
|
startIcePolling() {
|
|
283
|
-
if (this.icePollingTimeout || !this.
|
|
292
|
+
if (this.icePollingTimeout || !this.serviceUuid) {
|
|
284
293
|
return;
|
|
285
294
|
}
|
|
286
295
|
let interval = this.pollingConfig.initialInterval;
|
|
287
296
|
const poll = async () => {
|
|
288
|
-
if (!this.
|
|
297
|
+
if (!this.serviceUuid) {
|
|
289
298
|
this.stopIcePolling();
|
|
290
299
|
return;
|
|
291
300
|
}
|
|
292
301
|
try {
|
|
293
|
-
const
|
|
302
|
+
const result = await this.rondevu
|
|
294
303
|
.getAPI()
|
|
295
|
-
.
|
|
304
|
+
.getServiceIceCandidates(this.serviceUuid, this.lastIceTimestamp, this.offerId || undefined);
|
|
305
|
+
// Store offerId if we didn't have it yet
|
|
306
|
+
if (!this.offerId) {
|
|
307
|
+
this.offerId = result.offerId;
|
|
308
|
+
}
|
|
296
309
|
let foundCandidates = false;
|
|
297
|
-
for (const item of candidates) {
|
|
310
|
+
for (const item of result.candidates) {
|
|
298
311
|
if (item.candidate && item.candidate.candidate && item.candidate.candidate !== '') {
|
|
299
312
|
foundCandidates = true;
|
|
300
313
|
try {
|
package/package.json
CHANGED