@xtr-dev/rondevu-client 0.20.1 → 0.21.1

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.
Files changed (43) hide show
  1. package/README.md +83 -385
  2. package/dist/api/batcher.d.ts +60 -38
  3. package/dist/api/batcher.js +121 -77
  4. package/dist/api/client.d.ts +104 -61
  5. package/dist/api/client.js +273 -185
  6. package/dist/connections/answerer.d.ts +15 -6
  7. package/dist/connections/answerer.js +56 -19
  8. package/dist/connections/base.d.ts +6 -4
  9. package/dist/connections/base.js +26 -16
  10. package/dist/connections/config.d.ts +30 -0
  11. package/dist/connections/config.js +20 -0
  12. package/dist/connections/events.d.ts +6 -6
  13. package/dist/connections/offerer.d.ts +37 -8
  14. package/dist/connections/offerer.js +92 -24
  15. package/dist/core/ice-config.d.ts +35 -0
  16. package/dist/core/ice-config.js +111 -0
  17. package/dist/core/index.d.ts +18 -18
  18. package/dist/core/index.js +18 -13
  19. package/dist/core/offer-pool.d.ts +30 -11
  20. package/dist/core/offer-pool.js +90 -76
  21. package/dist/core/peer.d.ts +155 -0
  22. package/dist/core/peer.js +252 -0
  23. package/dist/core/polling-manager.d.ts +71 -0
  24. package/dist/core/polling-manager.js +122 -0
  25. package/dist/core/rondevu-errors.d.ts +59 -0
  26. package/dist/core/rondevu-errors.js +75 -0
  27. package/dist/core/rondevu-types.d.ts +125 -0
  28. package/dist/core/rondevu-types.js +6 -0
  29. package/dist/core/rondevu.d.ts +106 -209
  30. package/dist/core/rondevu.js +221 -349
  31. package/dist/crypto/adapter.d.ts +25 -9
  32. package/dist/crypto/node.d.ts +27 -5
  33. package/dist/crypto/node.js +96 -25
  34. package/dist/crypto/web.d.ts +26 -4
  35. package/dist/crypto/web.js +102 -25
  36. package/dist/utils/message-buffer.js +4 -4
  37. package/dist/webrtc/adapter.d.ts +22 -0
  38. package/dist/webrtc/adapter.js +5 -0
  39. package/dist/webrtc/browser.d.ts +12 -0
  40. package/dist/webrtc/browser.js +15 -0
  41. package/dist/webrtc/node.d.ts +32 -0
  42. package/dist/webrtc/node.js +32 -0
  43. package/package.json +17 -6
@@ -10,16 +10,16 @@ import { AsyncLock } from '../utils/async-lock.js';
10
10
  export class OffererConnection extends RondevuConnection {
11
11
  constructor(options) {
12
12
  // Force reconnectEnabled: false for offerer connections (offers are ephemeral)
13
- super(undefined, {
14
- ...options.config,
15
- reconnectEnabled: false
16
- });
13
+ super(undefined, { ...options.config, reconnectEnabled: false }, options.webrtcAdapter);
14
+ this._peerUsername = null;
17
15
  // Rotation tracking
18
16
  this.rotationLock = new AsyncLock();
19
17
  this.rotating = false;
20
18
  this.rotationAttempts = 0;
19
+ // ICE candidate buffering (for candidates received before answer is processed)
20
+ this.pendingIceCandidates = [];
21
21
  this.api = options.api;
22
- this.serviceFqn = options.serviceFqn;
22
+ this.ownerUsername = options.ownerUsername;
23
23
  this.offerId = options.offerId;
24
24
  // Use the already-created peer connection and data channel
25
25
  this.pc = options.pc;
@@ -33,7 +33,7 @@ export class OffererConnection extends RondevuConnection {
33
33
  if (!this.pc)
34
34
  throw new Error('Peer connection not provided');
35
35
  // Setup peer connection event handlers
36
- this.pc.onicecandidate = (event) => this.handleIceCandidate(event);
36
+ this.pc.onicecandidate = event => this.handleIceCandidate(event);
37
37
  this.pc.oniceconnectionstatechange = () => this.handleIceConnectionStateChange();
38
38
  this.pc.onconnectionstatechange = () => this.handleConnectionStateChange();
39
39
  this.pc.onicegatheringstatechange = () => this.handleIceGatheringStateChange();
@@ -67,8 +67,10 @@ export class OffererConnection extends RondevuConnection {
67
67
  throw new Error('Received different answer after already processing one (protocol violation)');
68
68
  }
69
69
  }
70
- // Validate state
71
- if (this.state !== ConnectionState.SIGNALING && this.state !== ConnectionState.CHECKING) {
70
+ // Validate state - allow SIGNALING, CHECKING, and FAILED (for late-arriving answers before rotation)
71
+ if (this.state !== ConnectionState.SIGNALING &&
72
+ this.state !== ConnectionState.CHECKING &&
73
+ this.state !== ConnectionState.FAILED) {
72
74
  this.debug(`Cannot process answer in state ${this.state}`);
73
75
  return;
74
76
  }
@@ -80,8 +82,17 @@ export class OffererConnection extends RondevuConnection {
80
82
  type: 'answer',
81
83
  sdp,
82
84
  });
85
+ // Store the peer username
86
+ this._peerUsername = answererId;
83
87
  this.debug(`Answer processed successfully from ${answererId}`);
84
88
  this.emit('answer:processed', this.offerId, answererId);
89
+ // Apply any buffered ICE candidates that arrived before the answer
90
+ if (this.pendingIceCandidates.length > 0) {
91
+ this.debug(`Applying ${this.pendingIceCandidates.length} buffered ICE candidates`);
92
+ const buffered = this.pendingIceCandidates;
93
+ this.pendingIceCandidates = [];
94
+ this.applyIceCandidates(buffered);
95
+ }
85
96
  }
86
97
  catch (error) {
87
98
  // Reset flags on error so we can try again
@@ -118,11 +129,13 @@ export class OffererConnection extends RondevuConnection {
118
129
  this.offerId = newOfferId;
119
130
  this.pc = newPc;
120
131
  this.dc = newDc || null;
121
- // 3. Reset answer processing flags
132
+ // 3. Reset answer processing flags, peer username, and pending candidates
122
133
  this.answerProcessed = false;
123
134
  this.answerSdpFingerprint = null;
135
+ this._peerUsername = null;
136
+ this.pendingIceCandidates = [];
124
137
  // 4. Setup event handlers for new peer connection
125
- this.pc.onicecandidate = (event) => this.handleIceCandidate(event);
138
+ this.pc.onicecandidate = event => this.handleIceCandidate(event);
126
139
  this.pc.oniceconnectionstatechange = () => this.handleIceConnectionStateChange();
127
140
  this.pc.onconnectionstatechange = () => this.handleConnectionStateChange();
128
141
  this.pc.onicegatheringstatechange = () => this.handleIceGatheringStateChange();
@@ -166,7 +179,7 @@ export class OffererConnection extends RondevuConnection {
166
179
  const data = encoder.encode(sdp);
167
180
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
168
181
  const hashArray = Array.from(new Uint8Array(hashBuffer));
169
- return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
182
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
170
183
  }
171
184
  else {
172
185
  // Fallback: use simple string hash
@@ -186,14 +199,14 @@ export class OffererConnection extends RondevuConnection {
186
199
  this.debug('Generated local ICE candidate');
187
200
  // Send ICE candidate to server
188
201
  this.api
189
- .addOfferIceCandidates(this.serviceFqn, this.offerId, [
202
+ .addOfferIceCandidates(this.offerId, [
190
203
  {
191
204
  candidate: candidate.candidate,
192
205
  sdpMLineIndex: candidate.sdpMLineIndex,
193
206
  sdpMid: candidate.sdpMid,
194
207
  },
195
208
  ])
196
- .catch((error) => {
209
+ .catch(error => {
197
210
  this.debug('Failed to send ICE candidate:', error);
198
211
  });
199
212
  }
@@ -204,10 +217,10 @@ export class OffererConnection extends RondevuConnection {
204
217
  return this.api;
205
218
  }
206
219
  /**
207
- * Get the service FQN
220
+ * Get the owner username
208
221
  */
209
- getServiceFqn() {
210
- return this.serviceFqn;
222
+ getOwnerUsername() {
223
+ return this.ownerUsername;
211
224
  }
212
225
  /**
213
226
  * Offerers accept all ICE candidates (no filtering)
@@ -216,17 +229,25 @@ export class OffererConnection extends RondevuConnection {
216
229
  return null;
217
230
  }
218
231
  /**
219
- * Attempt to reconnect
232
+ * Attempt to reconnect (required by abstract base class)
233
+ *
234
+ * For OffererConnection, traditional reconnection is NOT used.
235
+ * Instead, the OfferPool handles failures via offer rotation:
220
236
  *
221
- * Note: For offerer connections, reconnection is handled by the Rondevu instance
222
- * creating a new offer via fillOffers(). This method is a no-op.
237
+ * 1. When this connection fails, the 'failed' event is emitted
238
+ * 2. OfferPool detects the failure and calls createNewOfferForRotation()
239
+ * 3. The new offer is published to the server
240
+ * 4. This connection is rebound via rebindToOffer()
241
+ *
242
+ * This approach ensures the answerer always gets a fresh offer
243
+ * rather than trying to reconnect to a stale one.
244
+ *
245
+ * @see OfferPool.createNewOfferForRotation() - creates replacement offer
246
+ * @see OffererConnection.rebindToOffer() - rebinds connection to new offer
223
247
  */
224
248
  attemptReconnect() {
225
- this.debug('Reconnection not applicable for offerer - new offer will be created by Rondevu instance');
226
- // Offerer reconnection is handled externally by Rondevu.fillOffers()
227
- // which creates entirely new offers. We don't reconnect the same offer.
228
- // Just emit failure and let the parent handle it.
229
- this.emit('reconnect:failed', new Error('Offerer reconnection handled by parent'));
249
+ this.debug('Reconnection delegated to OfferPool rotation mechanism');
250
+ this.emit('reconnect:failed', new Error('Offerer uses rotation, not reconnection'));
230
251
  }
231
252
  /**
232
253
  * Get the offer ID
@@ -234,5 +255,52 @@ export class OffererConnection extends RondevuConnection {
234
255
  getOfferId() {
235
256
  return this.offerId;
236
257
  }
258
+ /**
259
+ * Get the peer username (who answered this offer)
260
+ * Returns null if no answer has been processed yet
261
+ */
262
+ get peerUsername() {
263
+ return this._peerUsername;
264
+ }
265
+ /**
266
+ * Handle remote ICE candidates received from polling
267
+ * Called by OfferPool when poll:ice event is received
268
+ */
269
+ handleRemoteIceCandidates(candidates) {
270
+ if (!this.pc) {
271
+ this.debug('Cannot add ICE candidates: peer connection not initialized');
272
+ return;
273
+ }
274
+ // If answer hasn't been processed yet, buffer the candidates
275
+ if (!this.answerProcessed) {
276
+ this.debug(`Buffering ${candidates.length} ICE candidates (waiting for answer)`);
277
+ this.pendingIceCandidates.push(...candidates);
278
+ return;
279
+ }
280
+ // Answer is processed, apply candidates immediately
281
+ this.applyIceCandidates(candidates);
282
+ }
283
+ /**
284
+ * Apply ICE candidates to the peer connection
285
+ */
286
+ applyIceCandidates(candidates) {
287
+ if (!this.pc)
288
+ return;
289
+ for (const iceCandidate of candidates) {
290
+ // Offerer accepts answerer's candidates (no role filtering needed here
291
+ // since OfferPool already filters by offerId)
292
+ if (iceCandidate.candidate) {
293
+ const rtcCandidate = this.webrtcAdapter.createIceCandidate(iceCandidate.candidate);
294
+ this.pc
295
+ .addIceCandidate(rtcCandidate)
296
+ .then(() => {
297
+ this.emit('ice:candidate:remote', rtcCandidate);
298
+ })
299
+ .catch(error => {
300
+ this.debug('Failed to add ICE candidate:', error);
301
+ });
302
+ }
303
+ }
304
+ }
237
305
  }
238
306
  OffererConnection.MAX_ROTATION_ATTEMPTS = 5;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ICE Configuration Types and Presets
3
+ *
4
+ * Provides typed ICE server presets for common WebRTC configurations.
5
+ */
6
+ /**
7
+ * Available ICE server preset names
8
+ */
9
+ export type IceServerPreset = 'rondevu' | 'rondevu-relay' | 'rondevu-ipv4' | 'rondevu-ipv4-relay' | 'google-stun' | 'public-stun';
10
+ /**
11
+ * ICE preset configuration containing servers and optional transport policy.
12
+ * The iceTransportPolicy belongs on RTCConfiguration, not RTCIceServer.
13
+ */
14
+ export interface IcePresetConfig {
15
+ iceServers: RTCIceServer[];
16
+ iceTransportPolicy?: RTCIceTransportPolicy;
17
+ }
18
+ /**
19
+ * Pre-configured ICE server presets.
20
+ *
21
+ * - `rondevu`: Official Rondevu TURN/STUN servers (recommended)
22
+ * - `rondevu-relay`: Same as rondevu but forces relay mode (hides client IPs)
23
+ * - `rondevu-ipv4`: Direct IPv4 address (for networks with DNS issues)
24
+ * - `rondevu-ipv4-relay`: IPv4 with forced relay mode
25
+ * - `google-stun`: Google's free STUN servers (no relay, direct connections only)
26
+ * - `public-stun`: Multiple public STUN servers for redundancy
27
+ */
28
+ export declare const ICE_SERVER_PRESETS: Record<IceServerPreset, IcePresetConfig>;
29
+ /**
30
+ * Get the full RTCConfiguration for a preset or custom ICE servers.
31
+ *
32
+ * @param iceServers - Either a preset name or custom ICE servers array
33
+ * @returns Partial RTCConfiguration with iceServers and optional iceTransportPolicy
34
+ */
35
+ export declare function getIceConfiguration(iceServers?: IceServerPreset | RTCIceServer[]): Pick<RTCConfiguration, 'iceServers' | 'iceTransportPolicy'>;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * ICE Configuration Types and Presets
3
+ *
4
+ * Provides typed ICE server presets for common WebRTC configurations.
5
+ */
6
+ /**
7
+ * Pre-configured ICE server presets.
8
+ *
9
+ * - `rondevu`: Official Rondevu TURN/STUN servers (recommended)
10
+ * - `rondevu-relay`: Same as rondevu but forces relay mode (hides client IPs)
11
+ * - `rondevu-ipv4`: Direct IPv4 address (for networks with DNS issues)
12
+ * - `rondevu-ipv4-relay`: IPv4 with forced relay mode
13
+ * - `google-stun`: Google's free STUN servers (no relay, direct connections only)
14
+ * - `public-stun`: Multiple public STUN servers for redundancy
15
+ */
16
+ export const ICE_SERVER_PRESETS = {
17
+ rondevu: {
18
+ iceServers: [
19
+ { urls: 'stun:relay.ronde.vu:3478' },
20
+ {
21
+ urls: [
22
+ 'turns:relay.ronde.vu:5349?transport=tcp',
23
+ 'turn:relay.ronde.vu:3478?transport=tcp',
24
+ 'turn:relay.ronde.vu:3478?transport=udp',
25
+ ],
26
+ username: 'rondevu',
27
+ credential: 'rondevu-public-turn',
28
+ },
29
+ ],
30
+ },
31
+ 'rondevu-relay': {
32
+ iceServers: [
33
+ { urls: 'stun:relay.ronde.vu:3478' },
34
+ {
35
+ urls: [
36
+ 'turns:relay.ronde.vu:5349?transport=tcp',
37
+ 'turn:relay.ronde.vu:3478?transport=tcp',
38
+ 'turn:relay.ronde.vu:3478?transport=udp',
39
+ ],
40
+ username: 'rondevu',
41
+ credential: 'rondevu-public-turn',
42
+ },
43
+ ],
44
+ iceTransportPolicy: 'relay', // Force relay mode - hides client IPs
45
+ },
46
+ 'rondevu-ipv4': {
47
+ iceServers: [
48
+ { urls: 'stun:57.129.61.67:3478' },
49
+ {
50
+ urls: [
51
+ 'turn:57.129.61.67:3478?transport=tcp',
52
+ 'turn:57.129.61.67:3478?transport=udp',
53
+ ],
54
+ username: 'rondevu',
55
+ credential: 'rondevu-public-turn',
56
+ },
57
+ ],
58
+ },
59
+ 'rondevu-ipv4-relay': {
60
+ iceServers: [
61
+ { urls: 'stun:57.129.61.67:3478' },
62
+ {
63
+ urls: [
64
+ 'turn:57.129.61.67:3478?transport=tcp',
65
+ 'turn:57.129.61.67:3478?transport=udp',
66
+ ],
67
+ username: 'rondevu',
68
+ credential: 'rondevu-public-turn',
69
+ },
70
+ ],
71
+ iceTransportPolicy: 'relay',
72
+ },
73
+ 'google-stun': {
74
+ iceServers: [
75
+ { urls: 'stun:stun.l.google.com:19302' },
76
+ { urls: 'stun:stun1.l.google.com:19302' },
77
+ ],
78
+ },
79
+ 'public-stun': {
80
+ iceServers: [
81
+ { urls: 'stun:stun.l.google.com:19302' },
82
+ { urls: 'stun:stun1.l.google.com:19302' },
83
+ { urls: 'stun:stun.cloudflare.com:3478' },
84
+ { urls: 'stun:stun.relay.metered.ca:80' },
85
+ ],
86
+ },
87
+ };
88
+ /**
89
+ * Get the full RTCConfiguration for a preset or custom ICE servers.
90
+ *
91
+ * @param iceServers - Either a preset name or custom ICE servers array
92
+ * @returns Partial RTCConfiguration with iceServers and optional iceTransportPolicy
93
+ */
94
+ export function getIceConfiguration(iceServers) {
95
+ if (typeof iceServers === 'string') {
96
+ const preset = ICE_SERVER_PRESETS[iceServers];
97
+ return {
98
+ iceServers: preset.iceServers,
99
+ iceTransportPolicy: preset.iceTransportPolicy,
100
+ };
101
+ }
102
+ // Default to rondevu preset if no ICE servers specified
103
+ if (!iceServers) {
104
+ const preset = ICE_SERVER_PRESETS.rondevu;
105
+ return {
106
+ iceServers: preset.iceServers,
107
+ iceTransportPolicy: preset.iceTransportPolicy,
108
+ };
109
+ }
110
+ return { iceServers };
111
+ }
@@ -1,22 +1,22 @@
1
1
  /**
2
2
  * @xtr-dev/rondevu-client
3
3
  * WebRTC peer signaling client
4
+ *
5
+ * Simple API:
6
+ * const rondevu = await Rondevu.connect()
7
+ *
8
+ * // Host: publish offers (auto-starts)
9
+ * const offer = await rondevu.offer({ tags: ['chat'], maxOffers: 5 })
10
+ * rondevu.on('connection:opened', (id, conn) => { ... })
11
+ * // Later: offer.cancel()
12
+ *
13
+ * // Guest: connect to a peer
14
+ * const peer = await rondevu.peer({ tags: ['chat'] })
15
+ * peer.on('open', () => peer.send('Hello!'))
4
16
  */
5
- export { Rondevu, RondevuError, NetworkError, ValidationError, ConnectionError } from './rondevu.js';
6
- export { RondevuAPI } from '../api/client.js';
7
- export { RpcBatcher } from '../api/batcher.js';
8
- export { RondevuConnection } from '../connections/base.js';
9
- export { OffererConnection } from '../connections/offerer.js';
10
- export { AnswererConnection } from '../connections/answerer.js';
11
- export { ExponentialBackoff } from '../utils/exponential-backoff.js';
12
- export { MessageBuffer } from '../utils/message-buffer.js';
13
- export { WebCryptoAdapter } from '../crypto/web.js';
14
- export { NodeCryptoAdapter } from '../crypto/node.js';
15
- export type { Signaler, Binnable, } from './types.js';
16
- export type { Keypair, OfferRequest, ServiceRequest, Service, ServiceOffer, IceCandidate, } from '../api/client.js';
17
- export type { RondevuOptions, PublishServiceOptions, ConnectToServiceOptions, ConnectionContext, OfferContext, OfferFactory, ActiveOffer, FindServiceOptions, ServiceResult, PaginatedServiceResult } from './rondevu.js';
18
- export type { CryptoAdapter } from '../crypto/adapter.js';
19
- export type { ConnectionConfig, } from '../connections/config.js';
20
- export type { ConnectionState, BufferedMessage, ReconnectInfo, StateChangeInfo, ConnectionEventMap, ConnectionEventName, ConnectionEventArgs, } from '../connections/events.js';
21
- export type { OffererOptions, } from '../connections/offerer.js';
22
- export type { AnswererOptions, } from '../connections/answerer.js';
17
+ export { Rondevu } from './rondevu.js';
18
+ export { Peer } from './peer.js';
19
+ export { ICE_SERVER_PRESETS } from './ice-config.js';
20
+ export type { RondevuOptions, OfferOptions, OfferHandle, DiscoverOptions, DiscoverResult, } from './rondevu.js';
21
+ export type { PeerState, PeerOptions } from './peer.js';
22
+ export type { IceServerPreset } from './ice-config.js';
@@ -1,17 +1,22 @@
1
1
  /**
2
2
  * @xtr-dev/rondevu-client
3
3
  * WebRTC peer signaling client
4
+ *
5
+ * Simple API:
6
+ * const rondevu = await Rondevu.connect()
7
+ *
8
+ * // Host: publish offers (auto-starts)
9
+ * const offer = await rondevu.offer({ tags: ['chat'], maxOffers: 5 })
10
+ * rondevu.on('connection:opened', (id, conn) => { ... })
11
+ * // Later: offer.cancel()
12
+ *
13
+ * // Guest: connect to a peer
14
+ * const peer = await rondevu.peer({ tags: ['chat'] })
15
+ * peer.on('open', () => peer.send('Hello!'))
4
16
  */
5
- export { Rondevu, RondevuError, NetworkError, ValidationError, ConnectionError } from './rondevu.js';
6
- export { RondevuAPI } from '../api/client.js';
7
- export { RpcBatcher } from '../api/batcher.js';
8
- // Export connection classes
9
- export { RondevuConnection } from '../connections/base.js';
10
- export { OffererConnection } from '../connections/offerer.js';
11
- export { AnswererConnection } from '../connections/answerer.js';
12
- // Export utilities
13
- export { ExponentialBackoff } from '../utils/exponential-backoff.js';
14
- export { MessageBuffer } from '../utils/message-buffer.js';
15
- // Export crypto adapters
16
- export { WebCryptoAdapter } from '../crypto/web.js';
17
- export { NodeCryptoAdapter } from '../crypto/node.js';
17
+ // Main entry point
18
+ export { Rondevu } from './rondevu.js';
19
+ // Simplified peer connection
20
+ export { Peer } from './peer.js';
21
+ // ICE server configuration presets
22
+ export { ICE_SERVER_PRESETS } from './ice-config.js';
@@ -2,53 +2,59 @@ import { EventEmitter } from 'eventemitter3';
2
2
  import { RondevuAPI } from '../api/client.js';
3
3
  import { OffererConnection } from '../connections/offerer.js';
4
4
  import { ConnectionConfig } from '../connections/config.js';
5
+ import { WebRTCAdapter } from '../webrtc/adapter.js';
6
+ import type { PollAnswerEvent, PollIceEvent } from './polling-manager.js';
5
7
  export type OfferFactory = (pc: RTCPeerConnection) => Promise<{
6
8
  dc?: RTCDataChannel;
7
9
  offer: RTCSessionDescriptionInit;
8
10
  }>;
9
11
  export interface OfferPoolOptions {
10
12
  api: RondevuAPI;
11
- serviceFqn: string;
13
+ tags: string[];
14
+ ownerUsername: string;
12
15
  maxOffers: number;
13
16
  offerFactory: OfferFactory;
14
17
  ttl: number;
15
18
  iceServers: RTCIceServer[];
19
+ iceTransportPolicy?: RTCIceTransportPolicy;
20
+ webrtcAdapter: WebRTCAdapter;
16
21
  connectionConfig?: Partial<ConnectionConfig>;
17
22
  debugEnabled?: boolean;
18
23
  }
19
24
  interface OfferPoolEvents {
20
25
  'connection:opened': (offerId: string, connection: OffererConnection) => void;
21
- 'offer:created': (offerId: string, serviceFqn: string) => void;
26
+ 'offer:created': (offerId: string, tags: string[]) => void;
22
27
  'offer:failed': (offerId: string, error: Error) => void;
23
28
  'connection:rotated': (oldOfferId: string, newOfferId: string, connection: OffererConnection) => void;
24
29
  }
25
30
  /**
26
- * OfferPool manages a pool of WebRTC offers for a published service.
31
+ * OfferPool manages a pool of WebRTC offers for published tags.
27
32
  * Maintains a target number of active offers and automatically replaces
28
33
  * offers that fail or get answered.
29
34
  */
30
35
  export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
31
36
  private readonly api;
32
- private readonly serviceFqn;
37
+ private readonly tags;
38
+ private readonly ownerUsername;
33
39
  private readonly maxOffers;
34
40
  private readonly offerFactory;
35
41
  private readonly ttl;
36
42
  private readonly iceServers;
43
+ private readonly iceTransportPolicy?;
44
+ private readonly webrtcAdapter;
37
45
  private readonly connectionConfig?;
38
46
  private readonly debugEnabled;
39
47
  private readonly activeConnections;
40
48
  private readonly fillLock;
41
49
  private running;
42
- private pollingInterval;
43
- private lastPollTimestamp;
44
- private static readonly POLLING_INTERVAL_MS;
45
50
  constructor(options: OfferPoolOptions);
46
51
  /**
47
- * Start filling offers and polling for answers
52
+ * Start filling offers
53
+ * Polling is managed externally by Rondevu's PollingManager
48
54
  */
49
55
  start(): Promise<void>;
50
56
  /**
51
- * Stop filling offers and polling
57
+ * Stop filling offers
52
58
  * Closes all active connections
53
59
  */
54
60
  stop(): void;
@@ -73,6 +79,13 @@ export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
73
79
  * Uses AsyncLock to prevent concurrent fills
74
80
  */
75
81
  private fillOffers;
82
+ /**
83
+ * Create and publish an offer to the server.
84
+ * Shared logic used by both createOffer() and createNewOfferForRotation().
85
+ *
86
+ * @returns The offer ID, RTCPeerConnection, and optional data channel
87
+ */
88
+ private createOfferAndPublish;
76
89
  /**
77
90
  * Create a new offer for rotation (reuses existing creation logic)
78
91
  * Similar to createOffer() but only creates the offer, doesn't create connection
@@ -83,9 +96,15 @@ export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
83
96
  */
84
97
  private createOffer;
85
98
  /**
86
- * Poll for answers and delegate to OffererConnections
99
+ * Handle poll:answer event from PollingManager
100
+ * Called by Rondevu when a poll:answer event is received
101
+ */
102
+ handlePollAnswer(data: PollAnswerEvent): Promise<void>;
103
+ /**
104
+ * Handle poll:ice event from PollingManager
105
+ * Called by Rondevu when a poll:ice event is received
87
106
  */
88
- private pollInternal;
107
+ handlePollIce(data: PollIceEvent): void;
89
108
  /**
90
109
  * Debug logging (only if debug enabled)
91
110
  */