@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
@@ -0,0 +1,71 @@
1
+ /**
2
+ * PollingManager - Centralized polling for WebRTC signaling
3
+ *
4
+ * Provides a single shared polling timer that emits events for:
5
+ * - poll:answer - When an offer receives an answer
6
+ * - poll:ice - When new ICE candidates are available
7
+ *
8
+ * Connections subscribe to these events and filter by offerId in their callbacks.
9
+ */
10
+ import { EventEmitter } from 'eventemitter3';
11
+ import { RondevuAPI, IceCandidate } from '../api/client.js';
12
+ export interface PollAnswerEvent {
13
+ offerId: string;
14
+ answererId: string;
15
+ sdp: string;
16
+ answeredAt: number;
17
+ }
18
+ export interface PollIceEvent {
19
+ offerId: string;
20
+ candidates: IceCandidate[];
21
+ }
22
+ export interface PollingManagerEvents {
23
+ 'poll:answer': (data: PollAnswerEvent) => void;
24
+ 'poll:ice': (data: PollIceEvent) => void;
25
+ 'poll:error': (error: Error) => void;
26
+ 'poll:started': () => void;
27
+ 'poll:stopped': () => void;
28
+ }
29
+ export interface PollingManagerOptions {
30
+ api: RondevuAPI;
31
+ intervalMs?: number;
32
+ debugEnabled?: boolean;
33
+ }
34
+ /**
35
+ * Centralized polling manager that emits global events
36
+ * Connections subscribe to events and filter by offerId
37
+ */
38
+ export declare class PollingManager extends EventEmitter<PollingManagerEvents> {
39
+ private static readonly DEFAULT_INTERVAL_MS;
40
+ private readonly api;
41
+ private readonly intervalMs;
42
+ private readonly debugEnabled;
43
+ private pollingInterval;
44
+ private lastPollTimestamp;
45
+ private running;
46
+ constructor(options: PollingManagerOptions);
47
+ /**
48
+ * Start polling
49
+ */
50
+ start(): void;
51
+ /**
52
+ * Stop polling
53
+ */
54
+ stop(): void;
55
+ /**
56
+ * Check if polling is active
57
+ */
58
+ isRunning(): boolean;
59
+ /**
60
+ * Get the last poll timestamp
61
+ */
62
+ getLastPollTimestamp(): number;
63
+ /**
64
+ * Perform a single poll
65
+ */
66
+ private poll;
67
+ /**
68
+ * Debug logging
69
+ */
70
+ private debug;
71
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * PollingManager - Centralized polling for WebRTC signaling
3
+ *
4
+ * Provides a single shared polling timer that emits events for:
5
+ * - poll:answer - When an offer receives an answer
6
+ * - poll:ice - When new ICE candidates are available
7
+ *
8
+ * Connections subscribe to these events and filter by offerId in their callbacks.
9
+ */
10
+ import { EventEmitter } from 'eventemitter3';
11
+ /**
12
+ * Centralized polling manager that emits global events
13
+ * Connections subscribe to events and filter by offerId
14
+ */
15
+ export class PollingManager extends EventEmitter {
16
+ constructor(options) {
17
+ super();
18
+ this.pollingInterval = null;
19
+ this.lastPollTimestamp = 0;
20
+ this.running = false;
21
+ this.api = options.api;
22
+ this.intervalMs = options.intervalMs ?? PollingManager.DEFAULT_INTERVAL_MS;
23
+ this.debugEnabled = options.debugEnabled ?? false;
24
+ }
25
+ /**
26
+ * Start polling
27
+ */
28
+ start() {
29
+ if (this.running) {
30
+ this.debug('Already running');
31
+ return;
32
+ }
33
+ this.debug('Starting polling manager');
34
+ this.running = true;
35
+ // Poll immediately
36
+ this.poll();
37
+ // Start interval
38
+ this.pollingInterval = setInterval(() => {
39
+ this.poll();
40
+ }, this.intervalMs);
41
+ this.emit('poll:started');
42
+ }
43
+ /**
44
+ * Stop polling
45
+ */
46
+ stop() {
47
+ if (!this.running)
48
+ return;
49
+ this.debug('Stopping polling manager');
50
+ this.running = false;
51
+ if (this.pollingInterval) {
52
+ clearInterval(this.pollingInterval);
53
+ this.pollingInterval = null;
54
+ }
55
+ this.emit('poll:stopped');
56
+ }
57
+ /**
58
+ * Check if polling is active
59
+ */
60
+ isRunning() {
61
+ return this.running;
62
+ }
63
+ /**
64
+ * Get the last poll timestamp
65
+ */
66
+ getLastPollTimestamp() {
67
+ return this.lastPollTimestamp;
68
+ }
69
+ /**
70
+ * Perform a single poll
71
+ */
72
+ async poll() {
73
+ if (!this.running)
74
+ return;
75
+ try {
76
+ const result = await this.api.poll(this.lastPollTimestamp);
77
+ // Emit answer events
78
+ for (const answer of result.answers) {
79
+ this.debug(`Poll: answer for ${answer.offerId}`);
80
+ this.emit('poll:answer', {
81
+ offerId: answer.offerId,
82
+ answererId: answer.answererId,
83
+ sdp: answer.sdp,
84
+ answeredAt: answer.answeredAt,
85
+ });
86
+ // Update last poll timestamp
87
+ if (answer.answeredAt > this.lastPollTimestamp) {
88
+ this.lastPollTimestamp = answer.answeredAt;
89
+ }
90
+ }
91
+ // Emit ICE candidate events (grouped by offerId)
92
+ for (const [offerId, candidates] of Object.entries(result.iceCandidates)) {
93
+ if (candidates.length > 0) {
94
+ this.debug(`Poll: ${candidates.length} ICE candidates for ${offerId}`);
95
+ this.emit('poll:ice', {
96
+ offerId,
97
+ candidates: candidates,
98
+ });
99
+ // Update last poll timestamp from candidates
100
+ for (const candidate of candidates) {
101
+ if (candidate.createdAt > this.lastPollTimestamp) {
102
+ this.lastPollTimestamp = candidate.createdAt;
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ catch (error) {
109
+ this.debug('Poll error:', error);
110
+ this.emit('poll:error', error instanceof Error ? error : new Error(String(error)));
111
+ }
112
+ }
113
+ /**
114
+ * Debug logging
115
+ */
116
+ debug(...args) {
117
+ if (this.debugEnabled) {
118
+ console.log('[PollingManager]', ...args);
119
+ }
120
+ }
121
+ }
122
+ PollingManager.DEFAULT_INTERVAL_MS = 1000;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Rondevu Error Classes
3
+ *
4
+ * Error hierarchy for the Rondevu client:
5
+ * - RondevuError (base)
6
+ * - NetworkError (API/connectivity issues)
7
+ * - ValidationError (invalid input/data)
8
+ * - ConnectionError (WebRTC/ICE issues)
9
+ */
10
+ /**
11
+ * Base error class for all Rondevu errors.
12
+ * Provides optional context object for debugging.
13
+ */
14
+ export declare class RondevuError extends Error {
15
+ context?: Record<string, unknown> | undefined;
16
+ constructor(message: string, context?: Record<string, unknown> | undefined);
17
+ }
18
+ /**
19
+ * Network-related errors (API calls, connectivity)
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * throw new NetworkError('Failed to reach signaling server', {
24
+ * url: 'https://api.ronde.vu',
25
+ * status: 503
26
+ * })
27
+ * ```
28
+ */
29
+ export declare class NetworkError extends RondevuError {
30
+ constructor(message: string, context?: Record<string, unknown>);
31
+ }
32
+ /**
33
+ * Validation errors (invalid input, malformed data)
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * throw new ValidationError('Invalid username format', {
38
+ * username: 'invalid@user',
39
+ * pattern: '^[a-z0-9-]{4,32}$'
40
+ * })
41
+ * ```
42
+ */
43
+ export declare class ValidationError extends RondevuError {
44
+ constructor(message: string, context?: Record<string, unknown>);
45
+ }
46
+ /**
47
+ * WebRTC connection errors (peer connection failures, ICE issues)
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * throw new ConnectionError('ICE connection failed', {
52
+ * iceState: 'failed',
53
+ * offerId: 'abc123'
54
+ * })
55
+ * ```
56
+ */
57
+ export declare class ConnectionError extends RondevuError {
58
+ constructor(message: string, context?: Record<string, unknown>);
59
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Rondevu Error Classes
3
+ *
4
+ * Error hierarchy for the Rondevu client:
5
+ * - RondevuError (base)
6
+ * - NetworkError (API/connectivity issues)
7
+ * - ValidationError (invalid input/data)
8
+ * - ConnectionError (WebRTC/ICE issues)
9
+ */
10
+ /**
11
+ * Base error class for all Rondevu errors.
12
+ * Provides optional context object for debugging.
13
+ */
14
+ export class RondevuError extends Error {
15
+ constructor(message, context) {
16
+ super(message);
17
+ this.context = context;
18
+ this.name = 'RondevuError';
19
+ Object.setPrototypeOf(this, RondevuError.prototype);
20
+ }
21
+ }
22
+ /**
23
+ * Network-related errors (API calls, connectivity)
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * throw new NetworkError('Failed to reach signaling server', {
28
+ * url: 'https://api.ronde.vu',
29
+ * status: 503
30
+ * })
31
+ * ```
32
+ */
33
+ export class NetworkError extends RondevuError {
34
+ constructor(message, context) {
35
+ super(message, context);
36
+ this.name = 'NetworkError';
37
+ Object.setPrototypeOf(this, NetworkError.prototype);
38
+ }
39
+ }
40
+ /**
41
+ * Validation errors (invalid input, malformed data)
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * throw new ValidationError('Invalid username format', {
46
+ * username: 'invalid@user',
47
+ * pattern: '^[a-z0-9-]{4,32}$'
48
+ * })
49
+ * ```
50
+ */
51
+ export class ValidationError extends RondevuError {
52
+ constructor(message, context) {
53
+ super(message, context);
54
+ this.name = 'ValidationError';
55
+ Object.setPrototypeOf(this, ValidationError.prototype);
56
+ }
57
+ }
58
+ /**
59
+ * WebRTC connection errors (peer connection failures, ICE issues)
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * throw new ConnectionError('ICE connection failed', {
64
+ * iceState: 'failed',
65
+ * offerId: 'abc123'
66
+ * })
67
+ * ```
68
+ */
69
+ export class ConnectionError extends RondevuError {
70
+ constructor(message, context) {
71
+ super(message, context);
72
+ this.name = 'ConnectionError';
73
+ Object.setPrototypeOf(this, ConnectionError.prototype);
74
+ }
75
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Rondevu Type Definitions
3
+ *
4
+ * Contains all public interfaces and types for the Rondevu client.
5
+ */
6
+ import { Credential } from '../api/client.js';
7
+ import { CryptoAdapter } from '../crypto/adapter.js';
8
+ import { WebRTCAdapter } from '../webrtc/adapter.js';
9
+ import { ConnectionConfig } from '../connections/config.js';
10
+ import { IceServerPreset } from './ice-config.js';
11
+ /**
12
+ * Options for creating a Rondevu instance via Rondevu.connect()
13
+ */
14
+ export interface RondevuOptions {
15
+ /** API URL (defaults to 'https://api.ronde.vu') */
16
+ apiUrl?: string;
17
+ /** Pre-existing credential (will generate if not provided) */
18
+ credential?: Credential;
19
+ /** Claim specific username (4-32 chars, alphanumeric + dashes + periods) */
20
+ username?: string;
21
+ /** Crypto adapter (defaults to WebCryptoAdapter) */
22
+ cryptoAdapter?: CryptoAdapter;
23
+ /** WebRTC adapter (defaults to BrowserWebRTCAdapter, use NodeWebRTCAdapter for Node.js) */
24
+ webrtcAdapter?: WebRTCAdapter;
25
+ /** ICE server preset name or custom RTCIceServer array */
26
+ iceServers?: IceServerPreset | RTCIceServer[];
27
+ /** Enable debug logging (default: false) */
28
+ debug?: boolean;
29
+ }
30
+ /**
31
+ * Context returned by offer factory functions
32
+ */
33
+ export interface OfferContext {
34
+ /** Optional data channel created for the offer */
35
+ dc?: RTCDataChannel;
36
+ /** The WebRTC offer SDP */
37
+ offer: RTCSessionDescriptionInit;
38
+ }
39
+ /**
40
+ * Factory function for creating WebRTC offers.
41
+ * Rondevu creates the RTCPeerConnection and passes it to the factory,
42
+ * allowing ICE candidate handlers to be set up before setLocalDescription() is called.
43
+ *
44
+ * @param pc - The RTCPeerConnection created by Rondevu (already configured with ICE servers)
45
+ * @returns Promise containing the data channel (optional) and offer SDP
46
+ */
47
+ export type OfferFactory = (pc: RTCPeerConnection) => Promise<OfferContext>;
48
+ /**
49
+ * Options for rondevu.offer() - publishing WebRTC offers
50
+ */
51
+ export interface OfferOptions {
52
+ /** Tags for discovery (e.g., ["chat", "video"]) */
53
+ tags: string[];
54
+ /** Maximum number of concurrent offers to maintain */
55
+ maxOffers: number;
56
+ /** Custom offer creation (defaults to simple data channel) */
57
+ offerFactory?: OfferFactory;
58
+ /** Time-to-live for offers in milliseconds (default: 300000 = 5 minutes) */
59
+ ttl?: number;
60
+ /** Connection durability configuration */
61
+ connectionConfig?: Partial<ConnectionConfig>;
62
+ /** Auto-start filling offers (default: true). Set to false to manually call startFilling() */
63
+ autoStart?: boolean;
64
+ }
65
+ /**
66
+ * Handle returned by rondevu.offer() for controlling the offer lifecycle
67
+ */
68
+ export interface OfferHandle {
69
+ /** Stop filling offers and close all connections */
70
+ cancel: () => void;
71
+ }
72
+ /**
73
+ * Context provided when a connection is established
74
+ */
75
+ export interface ConnectionContext {
76
+ /** The underlying RTCPeerConnection */
77
+ pc: RTCPeerConnection;
78
+ /** The data channel for communication */
79
+ dc: RTCDataChannel;
80
+ /** Tags associated with this connection */
81
+ tags: string[];
82
+ /** The offer ID for this connection */
83
+ offerId: string;
84
+ /** Username of the connected peer */
85
+ peerUsername: string;
86
+ }
87
+ /**
88
+ * Options for rondevu.discover() - discovering available offers
89
+ */
90
+ export interface DiscoverOptions {
91
+ /** Max results (default: 10) */
92
+ limit?: number;
93
+ /** Offset for pagination (default: 0) */
94
+ offset?: number;
95
+ }
96
+ /**
97
+ * A discovered offer from the signaling server
98
+ */
99
+ export interface DiscoveredOffer {
100
+ /** Unique offer identifier */
101
+ offerId: string;
102
+ /** Username of the offer publisher */
103
+ username: string;
104
+ /** Tags associated with this offer */
105
+ tags: string[];
106
+ /** The WebRTC offer SDP */
107
+ sdp: string;
108
+ /** Timestamp when the offer was created */
109
+ createdAt: number;
110
+ /** Timestamp when the offer expires */
111
+ expiresAt: number;
112
+ }
113
+ /**
114
+ * Result of a discover() call
115
+ */
116
+ export interface DiscoverResult {
117
+ /** Array of discovered offers */
118
+ offers: DiscoveredOffer[];
119
+ /** Total count of matching offers */
120
+ count: number;
121
+ /** Limit used in the query */
122
+ limit: number;
123
+ /** Offset used in the query */
124
+ offset: number;
125
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Rondevu Type Definitions
3
+ *
4
+ * Contains all public interfaces and types for the Rondevu client.
5
+ */
6
+ export {};