@xtr-dev/rondevu-client 0.18.10 → 0.20.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 (41) hide show
  1. package/README.md +324 -47
  2. package/dist/{api.d.ts → api/client.d.ts} +17 -8
  3. package/dist/{api.js → api/client.js} +114 -81
  4. package/dist/{answerer-connection.d.ts → connections/answerer.d.ts} +13 -5
  5. package/dist/{answerer-connection.js → connections/answerer.js} +17 -32
  6. package/dist/{connection.d.ts → connections/base.d.ts} +26 -5
  7. package/dist/{connection.js → connections/base.js} +45 -4
  8. package/dist/{offerer-connection.d.ts → connections/offerer.d.ts} +30 -5
  9. package/dist/{offerer-connection.js → connections/offerer.js} +93 -32
  10. package/dist/core/index.d.ts +22 -0
  11. package/dist/core/index.js +17 -0
  12. package/dist/core/offer-pool.d.ts +94 -0
  13. package/dist/core/offer-pool.js +267 -0
  14. package/dist/{rondevu.d.ts → core/rondevu.d.ts} +77 -85
  15. package/dist/core/rondevu.js +600 -0
  16. package/dist/{node-crypto-adapter.d.ts → crypto/node.d.ts} +1 -1
  17. package/dist/{web-crypto-adapter.d.ts → crypto/web.d.ts} +1 -1
  18. package/dist/utils/async-lock.d.ts +42 -0
  19. package/dist/utils/async-lock.js +75 -0
  20. package/dist/{message-buffer.d.ts → utils/message-buffer.d.ts} +1 -1
  21. package/package.json +4 -4
  22. package/dist/index.d.ts +0 -13
  23. package/dist/index.js +0 -10
  24. package/dist/rondevu-signaler.d.ts +0 -112
  25. package/dist/rondevu-signaler.js +0 -401
  26. package/dist/rondevu.js +0 -847
  27. /package/dist/{rpc-batcher.d.ts → api/batcher.d.ts} +0 -0
  28. /package/dist/{rpc-batcher.js → api/batcher.js} +0 -0
  29. /package/dist/{connection-config.d.ts → connections/config.d.ts} +0 -0
  30. /package/dist/{connection-config.js → connections/config.js} +0 -0
  31. /package/dist/{connection-events.d.ts → connections/events.d.ts} +0 -0
  32. /package/dist/{connection-events.js → connections/events.js} +0 -0
  33. /package/dist/{types.d.ts → core/types.d.ts} +0 -0
  34. /package/dist/{types.js → core/types.js} +0 -0
  35. /package/dist/{crypto-adapter.d.ts → crypto/adapter.d.ts} +0 -0
  36. /package/dist/{crypto-adapter.js → crypto/adapter.js} +0 -0
  37. /package/dist/{node-crypto-adapter.js → crypto/node.js} +0 -0
  38. /package/dist/{web-crypto-adapter.js → crypto/web.js} +0 -0
  39. /package/dist/{exponential-backoff.d.ts → utils/exponential-backoff.d.ts} +0 -0
  40. /package/dist/{exponential-backoff.js → utils/exponential-backoff.js} +0 -0
  41. /package/dist/{message-buffer.js → utils/message-buffer.js} +0 -0
@@ -1,6 +1,9 @@
1
- import { RondevuAPI, Keypair, IceCandidate, BatcherOptions } from './api.js';
2
- import { CryptoAdapter } from './crypto-adapter.js';
1
+ import { RondevuAPI, Keypair, IceCandidate, BatcherOptions } from '../api/client.js';
2
+ import { CryptoAdapter } from '../crypto/adapter.js';
3
3
  import { EventEmitter } from 'eventemitter3';
4
+ import { OffererConnection } from '../connections/offerer.js';
5
+ import { AnswererConnection } from '../connections/answerer.js';
6
+ import { ConnectionConfig } from '../connections/config.js';
4
7
  export type IceServerPreset = 'ipv4-turn' | 'hostname-turns' | 'google-stun' | 'relay-only';
5
8
  export declare const ICE_SERVER_PRESETS: Record<IceServerPreset, RTCIceServer[]>;
6
9
  export interface RondevuOptions {
@@ -32,6 +35,7 @@ export interface PublishServiceOptions {
32
35
  maxOffers: number;
33
36
  offerFactory?: OfferFactory;
34
37
  ttl?: number;
38
+ connectionConfig?: Partial<ConnectionConfig>;
35
39
  }
36
40
  export interface ConnectionContext {
37
41
  pc: RTCPeerConnection;
@@ -44,8 +48,8 @@ export interface ConnectToServiceOptions {
44
48
  serviceFqn?: string;
45
49
  service?: string;
46
50
  username?: string;
47
- onConnection?: (context: ConnectionContext) => void | Promise<void>;
48
51
  rtcConfig?: RTCConfiguration;
52
+ connectionConfig?: Partial<ConnectionConfig>;
49
53
  }
50
54
  export interface ActiveOffer {
51
55
  offerId: string;
@@ -101,14 +105,13 @@ export declare class ConnectionError extends RondevuError {
101
105
  constructor(message: string, context?: Record<string, any>);
102
106
  }
103
107
  /**
104
- * Rondevu - Complete WebRTC signaling client
108
+ * Rondevu - Complete WebRTC signaling client with durable connections
105
109
  *
106
- * Provides a unified API for:
107
- * - Implicit username claiming (auto-claimed on first authenticated request)
108
- * - Service publishing with automatic signature generation
109
- * - Service discovery (direct, random, paginated)
110
- * - WebRTC signaling (offer/answer exchange, ICE relay)
111
- * - Keypair management
110
+ * v1.0.0 introduces breaking changes:
111
+ * - connectToService() now returns AnswererConnection instead of ConnectionContext
112
+ * - Automatic reconnection and message buffering built-in
113
+ * - Connection objects expose .send() method instead of raw DataChannel
114
+ * - Rich event system for connection lifecycle (connected, disconnected, reconnecting, etc.)
112
115
  *
113
116
  * @example
114
117
  * ```typescript
@@ -119,39 +122,39 @@ export declare class ConnectionError extends RondevuError {
119
122
  * iceServers: 'ipv4-turn' // Use preset: 'ipv4-turn', 'hostname-turns', 'google-stun', or 'relay-only'
120
123
  * })
121
124
  *
122
- * // Or use custom ICE servers
123
- * const rondevu2 = await Rondevu.connect({
124
- * apiUrl: 'https://signal.example.com',
125
- * username: 'bob',
126
- * iceServers: [
127
- * { urls: 'stun:stun.l.google.com:19302' },
128
- * { urls: 'turn:turn.example.com:3478', username: 'user', credential: 'pass' }
129
- * ]
130
- * })
131
- *
132
125
  * // Publish a service with automatic offer management
133
126
  * await rondevu.publishService({
134
127
  * service: 'chat:2.0.0',
135
- * maxOffers: 5, // Maintain up to 5 concurrent offers
136
- * offerFactory: async (pc) => {
137
- * // pc is created by Rondevu with ICE handlers already attached
138
- * const dc = pc.createDataChannel('chat')
139
- * const offer = await pc.createOffer()
140
- * await pc.setLocalDescription(offer)
141
- * return { dc, offer }
142
- * }
128
+ * maxOffers: 5 // Maintain up to 5 concurrent offers
143
129
  * })
144
130
  *
145
131
  * // Start accepting connections (auto-fills offers and polls)
146
132
  * await rondevu.startFilling()
147
133
  *
148
- * // Access active connections
149
- * for (const offer of rondevu.getActiveOffers()) {
150
- * offer.dc?.addEventListener('message', (e) => console.log(e.data))
151
- * }
134
+ * // Listen for connections (v1.0.0 API)
135
+ * rondevu.on('connection:opened', (offerId, connection) => {
136
+ * connection.on('connected', () => console.log('Connected!'))
137
+ * connection.on('message', (data) => console.log('Received:', data))
138
+ * connection.send('Hello!')
139
+ * })
140
+ *
141
+ * // Connect to a service (v1.0.0 - returns AnswererConnection)
142
+ * const connection = await rondevu.connectToService({
143
+ * serviceFqn: 'chat:2.0.0@bob'
144
+ * })
145
+ *
146
+ * connection.on('connected', () => {
147
+ * console.log('Connected!')
148
+ * connection.send('Hello!')
149
+ * })
150
+ *
151
+ * connection.on('message', (data) => {
152
+ * console.log('Received:', data)
153
+ * })
152
154
  *
153
- * // Stop when done
154
- * rondevu.stopFilling()
155
+ * connection.on('reconnecting', (attempt) => {
156
+ * console.log(`Reconnecting, attempt ${attempt}`)
157
+ * })
155
158
  * ```
156
159
  */
157
160
  export declare class Rondevu extends EventEmitter {
@@ -169,14 +172,8 @@ export declare class Rondevu extends EventEmitter {
169
172
  private rtcPeerConnection?;
170
173
  private rtcIceCandidate?;
171
174
  private currentService;
172
- private maxOffers;
173
- private offerFactory;
174
- private ttl;
175
- private activeOffers;
176
- private filling;
177
- private pollingInterval;
178
- private lastPollTimestamp;
179
- private isPolling;
175
+ private connectionConfig?;
176
+ private offerPool;
180
177
  private constructor();
181
178
  /**
182
179
  * Internal debug logging - only logs if debug mode is enabled
@@ -215,32 +212,16 @@ export declare class Rondevu extends EventEmitter {
215
212
  * ```typescript
216
213
  * await rondevu.publishService({
217
214
  * service: 'chat:2.0.0',
218
- * maxOffers: 5
215
+ * maxOffers: 5,
216
+ * connectionConfig: {
217
+ * reconnectEnabled: true,
218
+ * bufferEnabled: true
219
+ * }
219
220
  * })
220
221
  * await rondevu.startFilling()
221
222
  * ```
222
223
  */
223
224
  publishService(options: PublishServiceOptions): Promise<void>;
224
- /**
225
- * Set up ICE candidate handler to send candidates to the server
226
- *
227
- * Note: This is used by connectToService() where the offerId is already known.
228
- * For createOffer(), we use inline ICE handling with early candidate queuing
229
- * since the offerId isn't available until after the factory completes.
230
- */
231
- private setupIceCandidateHandler;
232
- /**
233
- * Create a single offer and publish it to the server
234
- */
235
- private createOffer;
236
- /**
237
- * Fill offers to reach maxOffers count
238
- */
239
- private fillOffers;
240
- /**
241
- * Poll for answers and ICE candidates (internal use for automatic offer management)
242
- */
243
- private pollInternal;
244
225
  /**
245
226
  * Start filling offers and polling for answers/ICE
246
227
  * Call this after publishService() to begin accepting connections
@@ -259,14 +240,14 @@ export declare class Rondevu extends EventEmitter {
259
240
  /**
260
241
  * Check if an offer is currently connected
261
242
  * @param offerId - The offer ID to check
262
- * @returns True if the offer exists and has been answered
243
+ * @returns True if the offer exists and is connected
263
244
  */
264
245
  isConnected(offerId: string): boolean;
265
246
  /**
266
247
  * Disconnect all active offers
267
248
  * Similar to stopFilling() but doesn't stop the polling/filling process
268
249
  */
269
- disconnectAll(): Promise<void>;
250
+ disconnectAll(): void;
270
251
  /**
271
252
  * Get the current service status
272
253
  * @returns Object with service state information
@@ -274,8 +255,6 @@ export declare class Rondevu extends EventEmitter {
274
255
  getServiceStatus(): {
275
256
  active: boolean;
276
257
  offerCount: number;
277
- maxOffers: number;
278
- filling: boolean;
279
258
  };
280
259
  /**
281
260
  * Resolve the full service FQN from various input options
@@ -283,41 +262,45 @@ export declare class Rondevu extends EventEmitter {
283
262
  */
284
263
  private resolveServiceFqn;
285
264
  /**
286
- * Start polling for remote ICE candidates
287
- * Returns the polling interval ID
288
- */
289
- private startIcePolling;
290
- /**
291
- * Automatically connect to a service (answerer side)
292
- * Handles the entire connection flow: discovery, WebRTC setup, answer exchange, ICE candidates
265
+ * Connect to a service (answerer side) - v1.0.0 API
266
+ * Returns an AnswererConnection with automatic reconnection and buffering
267
+ *
268
+ * BREAKING CHANGE: This now returns AnswererConnection instead of ConnectionContext
293
269
  *
294
270
  * @example
295
271
  * ```typescript
296
272
  * // Connect to specific user
297
273
  * const connection = await rondevu.connectToService({
298
274
  * serviceFqn: 'chat:2.0.0@alice',
299
- * onConnection: ({ dc, peerUsername }) => {
300
- * console.log('Connected to', peerUsername)
301
- * dc.addEventListener('message', (e) => console.log(e.data))
302
- * dc.addEventListener('open', () => dc.send('Hello!'))
275
+ * connectionConfig: {
276
+ * reconnectEnabled: true,
277
+ * bufferEnabled: true
303
278
  * }
304
279
  * })
305
280
  *
281
+ * connection.on('connected', () => {
282
+ * console.log('Connected!')
283
+ * connection.send('Hello!')
284
+ * })
285
+ *
286
+ * connection.on('message', (data) => {
287
+ * console.log('Received:', data)
288
+ * })
289
+ *
290
+ * connection.on('reconnecting', (attempt) => {
291
+ * console.log(`Reconnecting, attempt ${attempt}`)
292
+ * })
293
+ *
306
294
  * // Discover random service
307
295
  * const connection = await rondevu.connectToService({
308
- * service: 'chat:2.0.0',
309
- * onConnection: ({ dc, peerUsername }) => {
310
- * console.log('Connected to', peerUsername)
311
- * }
296
+ * service: 'chat:2.0.0'
312
297
  * })
313
298
  * ```
314
299
  */
315
- connectToService(options: ConnectToServiceOptions): Promise<ConnectionContext>;
300
+ connectToService(options: ConnectToServiceOptions): Promise<AnswererConnection>;
316
301
  /**
317
302
  * Find a service - unified discovery method
318
303
  *
319
- * Replaces getService(), discoverService(), and discoverServices() with a single method.
320
- *
321
304
  * @param serviceFqn - Service identifier (e.g., 'chat:1.0.0' or 'chat:1.0.0@alice')
322
305
  * @param options - Discovery options
323
306
  *
@@ -399,6 +382,15 @@ export declare class Rondevu extends EventEmitter {
399
382
  * Get the public key
400
383
  */
401
384
  getPublicKey(): string;
385
+ /**
386
+ * Get active connections (for offerer side)
387
+ */
388
+ getActiveConnections(): Map<string, OffererConnection>;
389
+ /**
390
+ * Get all active offers (legacy compatibility)
391
+ * @deprecated Use getActiveConnections() instead
392
+ */
393
+ getActiveOffers(): ActiveOffer[];
402
394
  /**
403
395
  * Access to underlying API for advanced operations
404
396
  * @deprecated Use direct methods on Rondevu instance instead