@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 CHANGED
@@ -99,27 +99,35 @@ export declare class RondevuAPI {
99
99
  */
100
100
  getOffer(offerId: string): Promise<Offer>;
101
101
  /**
102
- * Answer an offer
102
+ * Answer a service
103
103
  */
104
- answerOffer(offerId: string, sdp: string, secret?: string): Promise<void>;
104
+ answerService(serviceUuid: string, sdp: string): Promise<{
105
+ offerId: string;
106
+ }>;
105
107
  /**
106
- * Get answer for an offer (offerer polls this)
108
+ * Get answer for a service (offerer polls this)
107
109
  */
108
- getAnswer(offerId: string): Promise<{
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 an offer
119
+ * Add ICE candidates to a service
117
120
  */
118
- addIceCandidates(offerId: string, candidates: RTCIceCandidateInit[]): Promise<void>;
121
+ addServiceIceCandidates(serviceUuid: string, candidates: RTCIceCandidateInit[], offerId?: string): Promise<{
122
+ offerId: string;
123
+ }>;
119
124
  /**
120
- * Get ICE candidates for an offer (with polling support)
125
+ * Get ICE candidates for a service (with polling support)
121
126
  */
122
- getIceCandidates(offerId: string, since?: number): Promise<IceCandidate[]>;
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 an offer
134
+ * Answer a service
135
135
  */
136
- async answerOffer(offerId, sdp, secret) {
137
- const response = await fetch(`${this.baseUrl}/offers/${offerId}/answer`, {
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, secret }),
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 offer: ${error.error || response.statusText}`);
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 an offer (offerer polls this)
152
+ * Get answer for a service (offerer polls this)
152
153
  */
153
- async getAnswer(offerId) {
154
- const response = await fetch(`${this.baseUrl}/offers/${offerId}/answer`, {
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 an offer
186
+ * Add ICE candidates to a service
186
187
  */
187
- async addIceCandidates(offerId, candidates) {
188
- const response = await fetch(`${this.baseUrl}/offers/${offerId}/ice-candidates`, {
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 an offer (with polling support)
204
+ * Get ICE candidates for a service (with polling support)
203
205
  */
204
- async getIceCandidates(offerId, since = 0) {
205
- const response = await fetch(`${this.baseUrl}/offers/${offerId}/ice-candidates?since=${since}`, { headers: this.getAuthHeader() });
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 data.candidates || [];
218
+ return {
219
+ candidates: data.candidates || [],
220
+ offerId: data.offerId
221
+ };
212
222
  }
213
223
  // ============================================
214
224
  // Services
@@ -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.offerId) {
89
- throw new Error('No offer ID available. Must receive offer first.');
88
+ if (!this.serviceUuid) {
89
+ throw new Error('No service UUID available. Must receive offer first.');
90
90
  }
91
- // Send answer to the offer
92
- await this.rondevu.getAPI().answerOffer(this.offerId, answer.sdp);
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.offerId) {
133
- console.warn('Cannot send ICE candidate: no offer ID');
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().addIceCandidates(this.offerId, [candidateData]);
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.offerId) {
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.offerId) {
223
+ if (!this.serviceUuid) {
219
224
  this.stopAnswerPolling();
220
225
  return;
221
226
  }
222
227
  try {
223
- const answer = await this.rondevu.getAPI().getAnswer(this.offerId);
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.offerId) {
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.offerId) {
297
+ if (!this.serviceUuid) {
289
298
  this.stopIcePolling();
290
299
  return;
291
300
  }
292
301
  try {
293
- const candidates = await this.rondevu
302
+ const result = await this.rondevu
294
303
  .getAPI()
295
- .getIceCandidates(this.offerId, this.lastIceTimestamp);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtr-dev/rondevu-client",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",