@xtr-dev/rondevu-client 0.21.3 → 0.21.5

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.
@@ -153,8 +153,11 @@ export declare class RondevuAPI {
153
153
  }>;
154
154
  /**
155
155
  * Answer an offer
156
+ * @param offerId The offer ID to answer
157
+ * @param sdp The SDP answer
158
+ * @param matchedTags Optional tags that were used to discover this offer
156
159
  */
157
- answerOffer(offerId: string, sdp: string): Promise<void>;
160
+ answerOffer(offerId: string, sdp: string, matchedTags?: string[]): Promise<void>;
158
161
  /**
159
162
  * Get answer for a specific offer (offerer polls this)
160
163
  */
@@ -163,6 +166,7 @@ export declare class RondevuAPI {
163
166
  offerId: string;
164
167
  answererId: string;
165
168
  answeredAt: number;
169
+ matchedTags?: string[];
166
170
  } | null>;
167
171
  /**
168
172
  * Combined polling for answers and ICE candidates
@@ -173,6 +177,7 @@ export declare class RondevuAPI {
173
177
  answererId: string;
174
178
  sdp: string;
175
179
  answeredAt: number;
180
+ matchedTags?: string[];
176
181
  }>;
177
182
  iceCandidates: Record<string, Array<{
178
183
  candidate: RTCIceCandidateInit | null;
@@ -325,11 +325,14 @@ export class RondevuAPI {
325
325
  // ============================================
326
326
  /**
327
327
  * Answer an offer
328
+ * @param offerId The offer ID to answer
329
+ * @param sdp The SDP answer
330
+ * @param matchedTags Optional tags that were used to discover this offer
328
331
  */
329
- async answerOffer(offerId, sdp) {
332
+ async answerOffer(offerId, sdp, matchedTags) {
330
333
  const request = {
331
334
  method: 'answerOffer',
332
- params: { offerId, sdp },
335
+ params: { offerId, sdp, matchedTags },
333
336
  };
334
337
  const authHeaders = await this.generateAuthHeaders(request);
335
338
  await this.rpc(request, authHeaders);
@@ -14,6 +14,7 @@ export interface AnswererOptions {
14
14
  rtcConfig?: RTCConfiguration;
15
15
  webrtcAdapter?: WebRTCAdapter;
16
16
  config?: Partial<ConnectionConfig>;
17
+ matchedTags?: string[];
17
18
  }
18
19
  /**
19
20
  * Answerer connection - processes offers and creates answers
@@ -24,6 +25,7 @@ export declare class AnswererConnection extends RondevuConnection {
24
25
  private tags;
25
26
  private offerId;
26
27
  private offerSdp;
28
+ private matchedTags?;
27
29
  constructor(options: AnswererOptions);
28
30
  /**
29
31
  * Initialize the connection by processing offer and creating answer
@@ -14,6 +14,7 @@ export class AnswererConnection extends RondevuConnection {
14
14
  this.tags = options.tags;
15
15
  this.offerId = options.offerId;
16
16
  this.offerSdp = options.offerSdp;
17
+ this.matchedTags = options.matchedTags;
17
18
  }
18
19
  /**
19
20
  * Initialize the connection by processing offer and creating answer
@@ -43,8 +44,8 @@ export class AnswererConnection extends RondevuConnection {
43
44
  const answer = await this.pc.createAnswer();
44
45
  await this.pc.setLocalDescription(answer);
45
46
  this.debug('Answer created, sending to server');
46
- // Send answer to server
47
- await this.api.answerOffer(this.offerId, answer.sdp);
47
+ // Send answer to server (including matched tags so offerer knows which tags we searched for)
48
+ await this.api.answerOffer(this.offerId, answer.sdp, this.matchedTags);
48
49
  // Note: ICE candidate polling is handled by PollingManager
49
50
  // Candidates are received via handleRemoteIceCandidates()
50
51
  this.debug('Answer sent successfully');
@@ -22,7 +22,7 @@ export interface OfferPoolOptions {
22
22
  debugEnabled?: boolean;
23
23
  }
24
24
  interface OfferPoolEvents {
25
- 'connection:opened': (offerId: string, connection: OffererConnection) => void;
25
+ 'connection:opened': (offerId: string, connection: OffererConnection, matchedTags?: string[]) => void;
26
26
  'offer:created': (offerId: string, tags: string[]) => void;
27
27
  'offer:failed': (offerId: string, error: Error) => void;
28
28
  'connection:rotated': (oldOfferId: string, newOfferId: string, connection: OffererConnection) => void;
@@ -34,7 +34,7 @@ interface OfferPoolEvents {
34
34
  */
35
35
  export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
36
36
  private readonly api;
37
- private readonly tags;
37
+ private tags;
38
38
  private readonly ownerUsername;
39
39
  private readonly maxOffers;
40
40
  private readonly offerFactory;
@@ -45,6 +45,7 @@ export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
45
45
  private readonly connectionConfig?;
46
46
  private readonly debugEnabled;
47
47
  private readonly activeConnections;
48
+ private readonly matchedTagsByOffer;
48
49
  private readonly fillLock;
49
50
  private running;
50
51
  constructor(options: OfferPoolOptions);
@@ -62,6 +63,16 @@ export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
62
63
  * Get count of active offers
63
64
  */
64
65
  getOfferCount(): number;
66
+ /**
67
+ * Update tags for new offers
68
+ * Existing offers keep their old tags until they expire/rotate
69
+ * New offers created during fill will use the updated tags
70
+ */
71
+ updateTags(newTags: string[]): void;
72
+ /**
73
+ * Get current tags
74
+ */
75
+ getTags(): string[];
65
76
  /**
66
77
  * Get all active connections
67
78
  */
@@ -11,6 +11,7 @@ export class OfferPool extends EventEmitter {
11
11
  super();
12
12
  // State
13
13
  this.activeConnections = new Map();
14
+ this.matchedTagsByOffer = new Map(); // Track matchedTags from answers
14
15
  this.fillLock = new AsyncLock();
15
16
  this.running = false;
16
17
  this.api = options.api;
@@ -62,6 +63,21 @@ export class OfferPool extends EventEmitter {
62
63
  getOfferCount() {
63
64
  return this.activeConnections.size;
64
65
  }
66
+ /**
67
+ * Update tags for new offers
68
+ * Existing offers keep their old tags until they expire/rotate
69
+ * New offers created during fill will use the updated tags
70
+ */
71
+ updateTags(newTags) {
72
+ this.debug(`Updating tags: ${newTags.join(', ')}`);
73
+ this.tags = newTags;
74
+ }
75
+ /**
76
+ * Get current tags
77
+ */
78
+ getTags() {
79
+ return [...this.tags];
80
+ }
65
81
  /**
66
82
  * Get all active connections
67
83
  */
@@ -191,8 +207,13 @@ export class OfferPool extends EventEmitter {
191
207
  });
192
208
  // Setup connection event handlers
193
209
  connection.on('connected', () => {
194
- this.debug(`Connection established for offer ${offerId}`);
195
- this.emit('connection:opened', offerId, connection);
210
+ // Use getOfferId() to get current ID after potential rotations
211
+ const currentOfferId = connection.getOfferId();
212
+ this.debug(`Connection established for offer ${currentOfferId}`);
213
+ // Get and clean up matchedTags
214
+ const matchedTags = this.matchedTagsByOffer.get(currentOfferId);
215
+ this.matchedTagsByOffer.delete(currentOfferId);
216
+ this.emit('connection:opened', currentOfferId, connection, matchedTags);
196
217
  });
197
218
  connection.on('failed', async (error) => {
198
219
  const currentOfferId = connection.getOfferId();
@@ -245,6 +266,10 @@ export class OfferPool extends EventEmitter {
245
266
  const connection = this.activeConnections.get(data.offerId);
246
267
  if (connection) {
247
268
  this.debug(`Processing answer for offer ${data.offerId}`);
269
+ // Store matchedTags for when connection opens
270
+ if (data.matchedTags) {
271
+ this.matchedTagsByOffer.set(data.offerId, data.matchedTags);
272
+ }
248
273
  try {
249
274
  await connection.processAnswer(data.sdp, data.answererId);
250
275
  // Create replacement offer
package/dist/core/peer.js CHANGED
@@ -94,6 +94,7 @@ export class Peer extends EventEmitter {
94
94
  ...this.connectionConfig,
95
95
  debug: this.debugEnabled,
96
96
  },
97
+ matchedTags: this.tags, // Pass the tags we used to discover this offer
97
98
  });
98
99
  // Wire up events
99
100
  this.setupEventHandlers();
@@ -14,6 +14,7 @@ export interface PollAnswerEvent {
14
14
  answererId: string;
15
15
  sdp: string;
16
16
  answeredAt: number;
17
+ matchedTags?: string[];
17
18
  }
18
19
  export interface PollIceEvent {
19
20
  offerId: string;
@@ -82,6 +82,7 @@ export class PollingManager extends EventEmitter {
82
82
  answererId: answer.answererId,
83
83
  sdp: answer.sdp,
84
84
  answeredAt: answer.answeredAt,
85
+ matchedTags: answer.matchedTags,
85
86
  });
86
87
  // Update last poll timestamp
87
88
  if (answer.answeredAt > this.lastPollTimestamp) {
@@ -173,6 +173,13 @@ export declare class Rondevu extends EventEmitter {
173
173
  * Similar to stopFilling() but doesn't stop the polling/filling process
174
174
  */
175
175
  disconnectAll(): void;
176
+ /**
177
+ * Update tags for new offers
178
+ * Existing offers keep their old tags until they expire/rotate
179
+ * New offers created during fill will use the updated tags
180
+ * @param newTags - The new tags to use for future offers
181
+ */
182
+ updateOfferTags(newTags: string[]): void;
176
183
  /**
177
184
  * Get the current publishing status
178
185
  * @returns Object with publishing state information
@@ -222,8 +222,8 @@ export class Rondevu extends EventEmitter {
222
222
  debugEnabled: this.debugEnabled,
223
223
  });
224
224
  // Forward events from OfferPool
225
- this.offerPool.on('connection:opened', (offerId, connection) => {
226
- this.emit('connection:opened', offerId, connection);
225
+ this.offerPool.on('connection:opened', (offerId, connection, matchedTags) => {
226
+ this.emit('connection:opened', offerId, connection, matchedTags);
227
227
  });
228
228
  this.offerPool.on('offer:created', (offerId, tags) => {
229
229
  this.emit('offer:created', offerId, tags);
@@ -314,6 +314,17 @@ export class Rondevu extends EventEmitter {
314
314
  this.debug('Disconnecting all offers');
315
315
  this.offerPool?.disconnectAll();
316
316
  }
317
+ /**
318
+ * Update tags for new offers
319
+ * Existing offers keep their old tags until they expire/rotate
320
+ * New offers created during fill will use the updated tags
321
+ * @param newTags - The new tags to use for future offers
322
+ */
323
+ updateOfferTags(newTags) {
324
+ this.debug(`Updating offer tags: ${newTags.join(', ')}`);
325
+ this.currentTags = newTags;
326
+ this.offerPool?.updateTags(newTags);
327
+ }
317
328
  /**
318
329
  * Get the current publishing status
319
330
  * @returns Object with publishing state information
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtr-dev/rondevu-client",
3
- "version": "0.21.3",
3
+ "version": "0.21.5",
4
4
  "description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing",
5
5
  "type": "module",
6
6
  "main": "dist/core/index.js",