@xtr-dev/rondevu-client 0.21.3 → 0.21.6
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/README.md +21 -25
- package/dist/api/client.d.ts +27 -40
- package/dist/api/client.js +39 -137
- package/dist/connections/answerer.d.ts +7 -5
- package/dist/connections/answerer.js +17 -16
- package/dist/connections/base.d.ts +2 -2
- package/dist/connections/offerer.d.ts +8 -8
- package/dist/connections/offerer.js +15 -15
- package/dist/core/offer-pool.d.ts +15 -4
- package/dist/core/offer-pool.js +30 -5
- package/dist/core/peer.d.ts +9 -9
- package/dist/core/peer.js +17 -16
- package/dist/core/polling-manager.d.ts +2 -1
- package/dist/core/polling-manager.js +2 -1
- package/dist/core/rondevu-types.d.ts +7 -9
- package/dist/core/rondevu.d.ts +26 -18
- package/dist/core/rondevu.js +44 -34
- package/dist/crypto/adapter.d.ts +19 -14
- package/dist/crypto/node.d.ts +14 -15
- package/dist/crypto/node.js +41 -53
- package/dist/crypto/web.d.ts +9 -12
- package/dist/crypto/web.js +36 -50
- package/package.json +2 -1
|
@@ -7,7 +7,7 @@ import { ConnectionConfig } from './config.js';
|
|
|
7
7
|
import { WebRTCAdapter } from '../webrtc/adapter.js';
|
|
8
8
|
export interface OffererOptions {
|
|
9
9
|
api: RondevuAPI;
|
|
10
|
-
|
|
10
|
+
ownerPublicKey: string;
|
|
11
11
|
offerId: string;
|
|
12
12
|
pc: RTCPeerConnection;
|
|
13
13
|
dc?: RTCDataChannel;
|
|
@@ -19,9 +19,9 @@ export interface OffererOptions {
|
|
|
19
19
|
*/
|
|
20
20
|
export declare class OffererConnection extends RondevuConnection {
|
|
21
21
|
private api;
|
|
22
|
-
private
|
|
22
|
+
private ownerPublicKey;
|
|
23
23
|
private offerId;
|
|
24
|
-
private
|
|
24
|
+
private _peerPublicKey;
|
|
25
25
|
private rotationLock;
|
|
26
26
|
private rotating;
|
|
27
27
|
private rotationAttempts;
|
|
@@ -35,7 +35,7 @@ export declare class OffererConnection extends RondevuConnection {
|
|
|
35
35
|
/**
|
|
36
36
|
* Process an answer from the answerer
|
|
37
37
|
*/
|
|
38
|
-
processAnswer(sdp: string,
|
|
38
|
+
processAnswer(sdp: string, answererPublicKey: string): Promise<void>;
|
|
39
39
|
/**
|
|
40
40
|
* Rebind this connection to a new offer (when previous offer failed)
|
|
41
41
|
* Keeps the same connection object alive but with new underlying WebRTC
|
|
@@ -62,9 +62,9 @@ export declare class OffererConnection extends RondevuConnection {
|
|
|
62
62
|
*/
|
|
63
63
|
protected getApi(): any;
|
|
64
64
|
/**
|
|
65
|
-
* Get the owner
|
|
65
|
+
* Get the owner public key
|
|
66
66
|
*/
|
|
67
|
-
protected
|
|
67
|
+
protected getOwnerPublicKey(): string;
|
|
68
68
|
/**
|
|
69
69
|
* Offerers accept all ICE candidates (no filtering)
|
|
70
70
|
*/
|
|
@@ -92,10 +92,10 @@ export declare class OffererConnection extends RondevuConnection {
|
|
|
92
92
|
*/
|
|
93
93
|
getOfferId(): string;
|
|
94
94
|
/**
|
|
95
|
-
* Get the peer
|
|
95
|
+
* Get the peer public key (who answered this offer)
|
|
96
96
|
* Returns null if no answer has been processed yet
|
|
97
97
|
*/
|
|
98
|
-
get
|
|
98
|
+
get peerPublicKey(): string | null;
|
|
99
99
|
/**
|
|
100
100
|
* Handle remote ICE candidates received from polling
|
|
101
101
|
* Called by OfferPool when poll:ice event is received
|
|
@@ -11,7 +11,7 @@ export class OffererConnection extends RondevuConnection {
|
|
|
11
11
|
constructor(options) {
|
|
12
12
|
// Force reconnectEnabled: false for offerer connections (offers are ephemeral)
|
|
13
13
|
super(undefined, { ...options.config, reconnectEnabled: false }, options.webrtcAdapter);
|
|
14
|
-
this.
|
|
14
|
+
this._peerPublicKey = null;
|
|
15
15
|
// Rotation tracking
|
|
16
16
|
this.rotationLock = new AsyncLock();
|
|
17
17
|
this.rotating = false;
|
|
@@ -19,7 +19,7 @@ export class OffererConnection extends RondevuConnection {
|
|
|
19
19
|
// ICE candidate buffering (for candidates received before answer is processed)
|
|
20
20
|
this.pendingIceCandidates = [];
|
|
21
21
|
this.api = options.api;
|
|
22
|
-
this.
|
|
22
|
+
this.ownerPublicKey = options.ownerPublicKey;
|
|
23
23
|
this.offerId = options.offerId;
|
|
24
24
|
// Use the already-created peer connection and data channel
|
|
25
25
|
this.pc = options.pc;
|
|
@@ -49,7 +49,7 @@ export class OffererConnection extends RondevuConnection {
|
|
|
49
49
|
/**
|
|
50
50
|
* Process an answer from the answerer
|
|
51
51
|
*/
|
|
52
|
-
async processAnswer(sdp,
|
|
52
|
+
async processAnswer(sdp, answererPublicKey) {
|
|
53
53
|
if (!this.pc) {
|
|
54
54
|
this.debug('Cannot process answer: peer connection not initialized');
|
|
55
55
|
return;
|
|
@@ -82,10 +82,10 @@ export class OffererConnection extends RondevuConnection {
|
|
|
82
82
|
type: 'answer',
|
|
83
83
|
sdp,
|
|
84
84
|
});
|
|
85
|
-
// Store the peer
|
|
86
|
-
this.
|
|
87
|
-
this.debug(`Answer processed successfully from ${
|
|
88
|
-
this.emit('answer:processed', this.offerId,
|
|
85
|
+
// Store the peer public key
|
|
86
|
+
this._peerPublicKey = answererPublicKey;
|
|
87
|
+
this.debug(`Answer processed successfully from ${answererPublicKey}`);
|
|
88
|
+
this.emit('answer:processed', this.offerId, answererPublicKey);
|
|
89
89
|
// Apply any buffered ICE candidates that arrived before the answer
|
|
90
90
|
if (this.pendingIceCandidates.length > 0) {
|
|
91
91
|
this.debug(`Applying ${this.pendingIceCandidates.length} buffered ICE candidates`);
|
|
@@ -129,10 +129,10 @@ export class OffererConnection extends RondevuConnection {
|
|
|
129
129
|
this.offerId = newOfferId;
|
|
130
130
|
this.pc = newPc;
|
|
131
131
|
this.dc = newDc || null;
|
|
132
|
-
// 3. Reset answer processing flags, peer
|
|
132
|
+
// 3. Reset answer processing flags, peer public key, and pending candidates
|
|
133
133
|
this.answerProcessed = false;
|
|
134
134
|
this.answerSdpFingerprint = null;
|
|
135
|
-
this.
|
|
135
|
+
this._peerPublicKey = null;
|
|
136
136
|
this.pendingIceCandidates = [];
|
|
137
137
|
// 4. Setup event handlers for new peer connection
|
|
138
138
|
this.pc.onicecandidate = event => this.handleIceCandidate(event);
|
|
@@ -217,10 +217,10 @@ export class OffererConnection extends RondevuConnection {
|
|
|
217
217
|
return this.api;
|
|
218
218
|
}
|
|
219
219
|
/**
|
|
220
|
-
* Get the owner
|
|
220
|
+
* Get the owner public key
|
|
221
221
|
*/
|
|
222
|
-
|
|
223
|
-
return this.
|
|
222
|
+
getOwnerPublicKey() {
|
|
223
|
+
return this.ownerPublicKey;
|
|
224
224
|
}
|
|
225
225
|
/**
|
|
226
226
|
* Offerers accept all ICE candidates (no filtering)
|
|
@@ -256,11 +256,11 @@ export class OffererConnection extends RondevuConnection {
|
|
|
256
256
|
return this.offerId;
|
|
257
257
|
}
|
|
258
258
|
/**
|
|
259
|
-
* Get the peer
|
|
259
|
+
* Get the peer public key (who answered this offer)
|
|
260
260
|
* Returns null if no answer has been processed yet
|
|
261
261
|
*/
|
|
262
|
-
get
|
|
263
|
-
return this.
|
|
262
|
+
get peerPublicKey() {
|
|
263
|
+
return this._peerPublicKey;
|
|
264
264
|
}
|
|
265
265
|
/**
|
|
266
266
|
* Handle remote ICE candidates received from polling
|
|
@@ -11,7 +11,7 @@ export type OfferFactory = (pc: RTCPeerConnection) => Promise<{
|
|
|
11
11
|
export interface OfferPoolOptions {
|
|
12
12
|
api: RondevuAPI;
|
|
13
13
|
tags: string[];
|
|
14
|
-
|
|
14
|
+
ownerPublicKey: string;
|
|
15
15
|
maxOffers: number;
|
|
16
16
|
offerFactory: OfferFactory;
|
|
17
17
|
ttl: number;
|
|
@@ -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,8 +34,8 @@ interface OfferPoolEvents {
|
|
|
34
34
|
*/
|
|
35
35
|
export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
|
|
36
36
|
private readonly api;
|
|
37
|
-
private
|
|
38
|
-
private readonly
|
|
37
|
+
private tags;
|
|
38
|
+
private readonly ownerPublicKey;
|
|
39
39
|
private readonly maxOffers;
|
|
40
40
|
private readonly offerFactory;
|
|
41
41
|
private readonly ttl;
|
|
@@ -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
|
*/
|
package/dist/core/offer-pool.js
CHANGED
|
@@ -11,11 +11,12 @@ 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;
|
|
17
18
|
this.tags = options.tags;
|
|
18
|
-
this.
|
|
19
|
+
this.ownerPublicKey = options.ownerPublicKey;
|
|
19
20
|
this.webrtcAdapter = options.webrtcAdapter;
|
|
20
21
|
this.maxOffers = options.maxOffers;
|
|
21
22
|
this.offerFactory = options.offerFactory;
|
|
@@ -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
|
*/
|
|
@@ -179,7 +195,7 @@ export class OfferPool extends EventEmitter {
|
|
|
179
195
|
// Create OffererConnection instance
|
|
180
196
|
const connection = new OffererConnection({
|
|
181
197
|
api: this.api,
|
|
182
|
-
|
|
198
|
+
ownerPublicKey: this.ownerPublicKey,
|
|
183
199
|
offerId,
|
|
184
200
|
pc,
|
|
185
201
|
dc,
|
|
@@ -191,8 +207,13 @@ export class OfferPool extends EventEmitter {
|
|
|
191
207
|
});
|
|
192
208
|
// Setup connection event handlers
|
|
193
209
|
connection.on('connected', () => {
|
|
194
|
-
|
|
195
|
-
|
|
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,8 +266,12 @@ 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
|
-
await connection.processAnswer(data.sdp, data.
|
|
274
|
+
await connection.processAnswer(data.sdp, data.answererPublicKey);
|
|
250
275
|
// Create replacement offer
|
|
251
276
|
this.fillOffers();
|
|
252
277
|
}
|
package/dist/core/peer.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Peer - Clean DX wrapper for peer-to-peer connections
|
|
3
3
|
*
|
|
4
|
-
* Provides a simple interface for connecting to a peer by tags/
|
|
4
|
+
* Provides a simple interface for connecting to a peer by tags/publicKey,
|
|
5
5
|
* with automatic reconnection and message buffering.
|
|
6
6
|
*/
|
|
7
7
|
import { EventEmitter } from 'eventemitter3';
|
|
@@ -37,8 +37,8 @@ export type PeerEventName = keyof PeerEventMap;
|
|
|
37
37
|
export interface PeerOptions {
|
|
38
38
|
/** Tags to match for peer discovery */
|
|
39
39
|
tags: string[];
|
|
40
|
-
/** Optional: connect to specific
|
|
41
|
-
|
|
40
|
+
/** Optional: connect to specific public key */
|
|
41
|
+
publicKey?: string;
|
|
42
42
|
/** Optional: custom RTC configuration */
|
|
43
43
|
rtcConfig?: RTCConfiguration;
|
|
44
44
|
/** Optional: connection behavior configuration */
|
|
@@ -60,12 +60,12 @@ export interface PeerInternalOptions extends PeerOptions {
|
|
|
60
60
|
* @example
|
|
61
61
|
* ```typescript
|
|
62
62
|
* const peer = await rondevu.peer({
|
|
63
|
-
*
|
|
63
|
+
* publicKey: 'abc123...',
|
|
64
64
|
* tags: ['chat']
|
|
65
65
|
* })
|
|
66
66
|
*
|
|
67
67
|
* peer.on('open', () => {
|
|
68
|
-
* console.log('Connected to', peer.
|
|
68
|
+
* console.log('Connected to', peer.peerPublicKey)
|
|
69
69
|
* peer.send('Hello!')
|
|
70
70
|
* })
|
|
71
71
|
*
|
|
@@ -86,14 +86,14 @@ export declare class Peer extends EventEmitter<PeerEventMap> {
|
|
|
86
86
|
private connection;
|
|
87
87
|
private api;
|
|
88
88
|
private tags;
|
|
89
|
-
private
|
|
89
|
+
private targetPublicKey?;
|
|
90
90
|
private iceServers;
|
|
91
91
|
private iceTransportPolicy?;
|
|
92
92
|
private webrtcAdapter?;
|
|
93
93
|
private connectionConfig?;
|
|
94
94
|
private debugEnabled;
|
|
95
95
|
private _state;
|
|
96
|
-
private
|
|
96
|
+
private _peerPublicKey;
|
|
97
97
|
private _offerId;
|
|
98
98
|
constructor(options: PeerInternalOptions);
|
|
99
99
|
/**
|
|
@@ -113,9 +113,9 @@ export declare class Peer extends EventEmitter<PeerEventMap> {
|
|
|
113
113
|
*/
|
|
114
114
|
get state(): PeerState;
|
|
115
115
|
/**
|
|
116
|
-
*
|
|
116
|
+
* Public key of the connected peer
|
|
117
117
|
*/
|
|
118
|
-
get
|
|
118
|
+
get peerPublicKey(): string;
|
|
119
119
|
/**
|
|
120
120
|
* The offer ID being used for this connection
|
|
121
121
|
*/
|
package/dist/core/peer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Peer - Clean DX wrapper for peer-to-peer connections
|
|
3
3
|
*
|
|
4
|
-
* Provides a simple interface for connecting to a peer by tags/
|
|
4
|
+
* Provides a simple interface for connecting to a peer by tags/publicKey,
|
|
5
5
|
* with automatic reconnection and message buffering.
|
|
6
6
|
*/
|
|
7
7
|
import { EventEmitter } from 'eventemitter3';
|
|
@@ -13,12 +13,12 @@ import { ConnectionState } from '../connections/events.js';
|
|
|
13
13
|
* @example
|
|
14
14
|
* ```typescript
|
|
15
15
|
* const peer = await rondevu.peer({
|
|
16
|
-
*
|
|
16
|
+
* publicKey: 'abc123...',
|
|
17
17
|
* tags: ['chat']
|
|
18
18
|
* })
|
|
19
19
|
*
|
|
20
20
|
* peer.on('open', () => {
|
|
21
|
-
* console.log('Connected to', peer.
|
|
21
|
+
* console.log('Connected to', peer.peerPublicKey)
|
|
22
22
|
* peer.send('Hello!')
|
|
23
23
|
* })
|
|
24
24
|
*
|
|
@@ -40,11 +40,11 @@ export class Peer extends EventEmitter {
|
|
|
40
40
|
super();
|
|
41
41
|
this.connection = null;
|
|
42
42
|
this._state = 'connecting';
|
|
43
|
-
this.
|
|
43
|
+
this._peerPublicKey = '';
|
|
44
44
|
this._offerId = '';
|
|
45
45
|
this.api = options.api;
|
|
46
46
|
this.tags = options.tags;
|
|
47
|
-
this.
|
|
47
|
+
this.targetPublicKey = options.publicKey;
|
|
48
48
|
this.iceServers = options.iceServers;
|
|
49
49
|
this.iceTransportPolicy = options.iceTransportPolicy;
|
|
50
50
|
this.webrtcAdapter = options.webrtcAdapter;
|
|
@@ -56,7 +56,7 @@ export class Peer extends EventEmitter {
|
|
|
56
56
|
*/
|
|
57
57
|
async initialize() {
|
|
58
58
|
this.debug('Initializing peer connection');
|
|
59
|
-
this.debug(`Tags: ${this.tags.join(', ')}${this.
|
|
59
|
+
this.debug(`Tags: ${this.tags.join(', ')}${this.targetPublicKey ? `, publicKey: ${this.targetPublicKey}` : ''}`);
|
|
60
60
|
// Discover offers
|
|
61
61
|
const result = (await this.api.discover({
|
|
62
62
|
tags: this.tags,
|
|
@@ -65,23 +65,23 @@ export class Peer extends EventEmitter {
|
|
|
65
65
|
if (!result.offers || result.offers.length === 0) {
|
|
66
66
|
throw new Error(`No peers found for tags: ${this.tags.join(', ')}`);
|
|
67
67
|
}
|
|
68
|
-
// Filter by
|
|
68
|
+
// Filter by publicKey if specified
|
|
69
69
|
let availableOffers = result.offers;
|
|
70
|
-
if (this.
|
|
71
|
-
availableOffers = result.offers.filter((o) => o.
|
|
70
|
+
if (this.targetPublicKey) {
|
|
71
|
+
availableOffers = result.offers.filter((o) => o.publicKey === this.targetPublicKey);
|
|
72
72
|
if (availableOffers.length === 0) {
|
|
73
|
-
throw new Error(`No peers found for tags: ${this.tags.join(', ')} from
|
|
73
|
+
throw new Error(`No peers found for tags: ${this.tags.join(', ')} from ${this.targetPublicKey}`);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
// Pick a random offer
|
|
77
77
|
const offer = availableOffers[Math.floor(Math.random() * availableOffers.length)];
|
|
78
|
-
this.
|
|
78
|
+
this._peerPublicKey = offer.publicKey;
|
|
79
79
|
this._offerId = offer.offerId;
|
|
80
|
-
this.debug(`Selected offer ${offer.offerId} from
|
|
80
|
+
this.debug(`Selected offer ${offer.offerId} from ${offer.publicKey}`);
|
|
81
81
|
// Create the underlying AnswererConnection
|
|
82
82
|
this.connection = new AnswererConnection({
|
|
83
83
|
api: this.api,
|
|
84
|
-
|
|
84
|
+
ownerPublicKey: offer.publicKey,
|
|
85
85
|
tags: offer.tags,
|
|
86
86
|
offerId: offer.offerId,
|
|
87
87
|
offerSdp: offer.sdp,
|
|
@@ -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();
|
|
@@ -179,10 +180,10 @@ export class Peer extends EventEmitter {
|
|
|
179
180
|
return this._state;
|
|
180
181
|
}
|
|
181
182
|
/**
|
|
182
|
-
*
|
|
183
|
+
* Public key of the connected peer
|
|
183
184
|
*/
|
|
184
|
-
get
|
|
185
|
-
return this.
|
|
185
|
+
get peerPublicKey() {
|
|
186
|
+
return this._peerPublicKey;
|
|
186
187
|
}
|
|
187
188
|
/**
|
|
188
189
|
* The offer ID being used for this connection
|
|
@@ -11,9 +11,10 @@ import { EventEmitter } from 'eventemitter3';
|
|
|
11
11
|
import { RondevuAPI, IceCandidate } from '../api/client.js';
|
|
12
12
|
export interface PollAnswerEvent {
|
|
13
13
|
offerId: string;
|
|
14
|
-
|
|
14
|
+
answererPublicKey: string;
|
|
15
15
|
sdp: string;
|
|
16
16
|
answeredAt: number;
|
|
17
|
+
matchedTags?: string[];
|
|
17
18
|
}
|
|
18
19
|
export interface PollIceEvent {
|
|
19
20
|
offerId: string;
|
|
@@ -79,9 +79,10 @@ export class PollingManager extends EventEmitter {
|
|
|
79
79
|
this.debug(`Poll: answer for ${answer.offerId}`);
|
|
80
80
|
this.emit('poll:answer', {
|
|
81
81
|
offerId: answer.offerId,
|
|
82
|
-
|
|
82
|
+
answererPublicKey: answer.answererPublicKey,
|
|
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) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Contains all public interfaces and types for the Rondevu client.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { KeyPair } from '../api/client.js';
|
|
7
7
|
import { CryptoAdapter } from '../crypto/adapter.js';
|
|
8
8
|
import { WebRTCAdapter } from '../webrtc/adapter.js';
|
|
9
9
|
import { ConnectionConfig } from '../connections/config.js';
|
|
@@ -14,10 +14,8 @@ import { IceServerPreset } from './ice-config.js';
|
|
|
14
14
|
export interface RondevuOptions {
|
|
15
15
|
/** API URL (defaults to 'https://api.ronde.vu') */
|
|
16
16
|
apiUrl?: string;
|
|
17
|
-
/** Pre-existing
|
|
18
|
-
|
|
19
|
-
/** Claim specific username (4-32 chars, alphanumeric + dashes + periods) */
|
|
20
|
-
username?: string;
|
|
17
|
+
/** Pre-existing keypair (will generate if not provided) */
|
|
18
|
+
keyPair?: KeyPair;
|
|
21
19
|
/** Crypto adapter (defaults to WebCryptoAdapter) */
|
|
22
20
|
cryptoAdapter?: CryptoAdapter;
|
|
23
21
|
/** WebRTC adapter (defaults to BrowserWebRTCAdapter, use NodeWebRTCAdapter for Node.js) */
|
|
@@ -81,8 +79,8 @@ export interface ConnectionContext {
|
|
|
81
79
|
tags: string[];
|
|
82
80
|
/** The offer ID for this connection */
|
|
83
81
|
offerId: string;
|
|
84
|
-
/**
|
|
85
|
-
|
|
82
|
+
/** Public key of the connected peer */
|
|
83
|
+
peerPublicKey: string;
|
|
86
84
|
}
|
|
87
85
|
/**
|
|
88
86
|
* Options for rondevu.discover() - discovering available offers
|
|
@@ -99,8 +97,8 @@ export interface DiscoverOptions {
|
|
|
99
97
|
export interface DiscoveredOffer {
|
|
100
98
|
/** Unique offer identifier */
|
|
101
99
|
offerId: string;
|
|
102
|
-
/**
|
|
103
|
-
|
|
100
|
+
/** Public key of the offer publisher */
|
|
101
|
+
publicKey: string;
|
|
104
102
|
/** Tags associated with this offer */
|
|
105
103
|
tags: string[];
|
|
106
104
|
/** The WebRTC offer SDP */
|
package/dist/core/rondevu.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { KeyPair, IceCandidate } from '../api/client.js';
|
|
2
2
|
import { WebRTCAdapter } from '../webrtc/adapter.js';
|
|
3
3
|
import { EventEmitter } from 'eventemitter3';
|
|
4
4
|
import { OffererConnection } from '../connections/offerer.js';
|
|
@@ -12,6 +12,7 @@ export type { PollAnswerEvent, PollIceEvent } from './polling-manager.js';
|
|
|
12
12
|
* Rondevu - Complete WebRTC signaling client with durable connections
|
|
13
13
|
*
|
|
14
14
|
* Uses a tags-based discovery system where offers have 1+ tags for matching.
|
|
15
|
+
* Authentication uses Ed25519 public key cryptography - your public key IS your identity.
|
|
15
16
|
*
|
|
16
17
|
* @example
|
|
17
18
|
* ```typescript
|
|
@@ -62,7 +63,7 @@ export declare class Rondevu extends EventEmitter {
|
|
|
62
63
|
private static readonly POLLING_INTERVAL_MS;
|
|
63
64
|
private api;
|
|
64
65
|
private readonly apiUrl;
|
|
65
|
-
private
|
|
66
|
+
private keyPair;
|
|
66
67
|
private cryptoAdapter?;
|
|
67
68
|
private webrtcAdapter;
|
|
68
69
|
private iceServers;
|
|
@@ -91,20 +92,20 @@ export declare class Rondevu extends EventEmitter {
|
|
|
91
92
|
*/
|
|
92
93
|
static connect(options?: RondevuOptions): Promise<Rondevu>;
|
|
93
94
|
/**
|
|
94
|
-
* Get the current
|
|
95
|
+
* Get the current public key (identity)
|
|
95
96
|
*/
|
|
96
|
-
|
|
97
|
+
getPublicKey(): string;
|
|
97
98
|
/**
|
|
98
|
-
* Get the full
|
|
99
|
-
* Use this to persist
|
|
99
|
+
* Get the full keypair (publicKey + privateKey)
|
|
100
|
+
* Use this to persist keypair for future sessions
|
|
100
101
|
*
|
|
101
102
|
* ⚠️ SECURITY WARNING:
|
|
102
|
-
* - The
|
|
103
|
-
* - Store
|
|
104
|
-
* - Never expose
|
|
105
|
-
* - Treat the
|
|
103
|
+
* - The private key grants full access to this identity
|
|
104
|
+
* - Store keypair securely (encrypted storage, never in logs)
|
|
105
|
+
* - Never expose private key in URLs, console output, or error messages
|
|
106
|
+
* - Treat the private key like a password or API key
|
|
106
107
|
*/
|
|
107
|
-
|
|
108
|
+
getKeyPair(): KeyPair;
|
|
108
109
|
/**
|
|
109
110
|
* Get the WebRTC adapter for creating peer connections
|
|
110
111
|
* Used internally by offer pool and connections
|
|
@@ -173,6 +174,13 @@ export declare class Rondevu extends EventEmitter {
|
|
|
173
174
|
* Similar to stopFilling() but doesn't stop the polling/filling process
|
|
174
175
|
*/
|
|
175
176
|
disconnectAll(): void;
|
|
177
|
+
/**
|
|
178
|
+
* Update tags for new offers
|
|
179
|
+
* Existing offers keep their old tags until they expire/rotate
|
|
180
|
+
* New offers created during fill will use the updated tags
|
|
181
|
+
* @param newTags - The new tags to use for future offers
|
|
182
|
+
*/
|
|
183
|
+
updateOfferTags(newTags: string[]): void;
|
|
176
184
|
/**
|
|
177
185
|
* Get the current publishing status
|
|
178
186
|
* @returns Object with publishing state information
|
|
@@ -191,14 +199,14 @@ export declare class Rondevu extends EventEmitter {
|
|
|
191
199
|
* // Connect to any peer matching tags
|
|
192
200
|
* const peer = await rondevu.peer({ tags: ['chat'] })
|
|
193
201
|
*
|
|
194
|
-
* // Connect to specific
|
|
202
|
+
* // Connect to specific peer by public key
|
|
195
203
|
* const peer = await rondevu.peer({
|
|
196
|
-
*
|
|
204
|
+
* publicKey: 'abc123...',
|
|
197
205
|
* tags: ['chat']
|
|
198
206
|
* })
|
|
199
207
|
*
|
|
200
208
|
* peer.on('open', () => {
|
|
201
|
-
* console.log('Connected to', peer.
|
|
209
|
+
* console.log('Connected to', peer.peerPublicKey)
|
|
202
210
|
* peer.send('Hello!')
|
|
203
211
|
* })
|
|
204
212
|
*
|
|
@@ -236,7 +244,7 @@ export declare class Rondevu extends EventEmitter {
|
|
|
236
244
|
*
|
|
237
245
|
* // Access offers
|
|
238
246
|
* for (const offer of result.offers) {
|
|
239
|
-
* console.log(offer.
|
|
247
|
+
* console.log(offer.publicKey, offer.tags)
|
|
240
248
|
* }
|
|
241
249
|
* ```
|
|
242
250
|
*/
|
|
@@ -254,7 +262,7 @@ export declare class Rondevu extends EventEmitter {
|
|
|
254
262
|
getOfferAnswer(offerId: string): Promise<{
|
|
255
263
|
sdp: string;
|
|
256
264
|
offerId: string;
|
|
257
|
-
|
|
265
|
+
answererPublicKey: string;
|
|
258
266
|
answeredAt: number;
|
|
259
267
|
} | null>;
|
|
260
268
|
/**
|
|
@@ -264,14 +272,14 @@ export declare class Rondevu extends EventEmitter {
|
|
|
264
272
|
poll(since?: number): Promise<{
|
|
265
273
|
answers: Array<{
|
|
266
274
|
offerId: string;
|
|
267
|
-
|
|
275
|
+
answererPublicKey: string;
|
|
268
276
|
sdp: string;
|
|
269
277
|
answeredAt: number;
|
|
270
278
|
}>;
|
|
271
279
|
iceCandidates: Record<string, Array<{
|
|
272
280
|
candidate: RTCIceCandidateInit | null;
|
|
273
281
|
role: 'offerer' | 'answerer';
|
|
274
|
-
|
|
282
|
+
peerPublicKey: string;
|
|
275
283
|
createdAt: number;
|
|
276
284
|
}>>;
|
|
277
285
|
}>;
|