@xtr-dev/rondevu-client 0.10.2 → 0.11.0
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 +8 -2
- package/dist/api.d.ts +11 -2
- package/dist/rondevu-service.d.ts +4 -2
- package/dist/rondevu-service.js +3 -3
- package/dist/rondevu-signaler.js +15 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,10 +17,12 @@ TypeScript/JavaScript client for Rondevu, providing easy-to-use WebRTC connectio
|
|
|
17
17
|
|
|
18
18
|
- **High-Level Wrappers**: ServiceHost and ServiceClient eliminate WebRTC boilerplate
|
|
19
19
|
- **Username-Based Discovery**: Connect to peers by username, not complex offer/answer exchange
|
|
20
|
+
- **Semver-Compatible Matching**: Requesting chat@1.0.0 matches any compatible 1.x.x version
|
|
21
|
+
- **Privacy-First Design**: Services are hidden by default - no enumeration possible
|
|
20
22
|
- **Automatic Reconnection**: Built-in retry logic with exponential backoff
|
|
21
23
|
- **Message Queuing**: Messages sent while disconnected are queued and flushed on reconnect
|
|
22
24
|
- **Cryptographic Username Claiming**: Secure ownership with Ed25519 signatures
|
|
23
|
-
- **Service Publishing**: Package-style naming (chat.app@1.0.0)
|
|
25
|
+
- **Service Publishing**: Package-style naming (chat.app@1.0.0) with multiple simultaneous offers
|
|
24
26
|
- **TypeScript**: Full type safety and autocomplete
|
|
25
27
|
- **Configurable Polling**: Exponential backoff with jitter to reduce server load
|
|
26
28
|
|
|
@@ -373,7 +375,7 @@ await conn.queueMessage('This will be sent when connected', {
|
|
|
373
375
|
|
|
374
376
|
## Migration from v0.9.x
|
|
375
377
|
|
|
376
|
-
v0.11.0 introduces high-level wrappers
|
|
378
|
+
v0.11.0+ introduces high-level wrappers, RESTful API changes, and semver-compatible discovery:
|
|
377
379
|
|
|
378
380
|
**API Changes:**
|
|
379
381
|
- Server endpoints restructured (`/usernames/*` → `/users/*`)
|
|
@@ -381,6 +383,10 @@ v0.11.0 introduces high-level wrappers and RESTful API changes:
|
|
|
381
383
|
- Message queue fully implemented
|
|
382
384
|
- Configurable polling with exponential backoff
|
|
383
385
|
- Removed deprecated `cleanup()` methods (use `dispose()`)
|
|
386
|
+
- **v0.11.0+**: Services use `offers` array instead of single `sdp`
|
|
387
|
+
- **v0.11.0+**: Semver-compatible service discovery (chat@1.0.0 matches 1.x.x)
|
|
388
|
+
- **v0.11.0+**: All services are hidden - no listing endpoint
|
|
389
|
+
- **v0.11.0+**: Services support multiple simultaneous offers for connection pooling
|
|
384
390
|
|
|
385
391
|
**Migration Guide:**
|
|
386
392
|
|
package/dist/api.d.ts
CHANGED
|
@@ -25,20 +25,29 @@ export interface Offer {
|
|
|
25
25
|
expiresAt: number;
|
|
26
26
|
answererPeerId?: string;
|
|
27
27
|
}
|
|
28
|
+
export interface OfferRequest {
|
|
29
|
+
sdp: string;
|
|
30
|
+
}
|
|
28
31
|
export interface ServiceRequest {
|
|
29
32
|
username: string;
|
|
30
33
|
serviceFqn: string;
|
|
31
|
-
|
|
34
|
+
offers: OfferRequest[];
|
|
32
35
|
ttl?: number;
|
|
33
36
|
isPublic?: boolean;
|
|
34
37
|
metadata?: Record<string, any>;
|
|
35
38
|
signature: string;
|
|
36
39
|
message: string;
|
|
37
40
|
}
|
|
41
|
+
export interface ServiceOffer {
|
|
42
|
+
offerId: string;
|
|
43
|
+
sdp: string;
|
|
44
|
+
createdAt: number;
|
|
45
|
+
expiresAt: number;
|
|
46
|
+
}
|
|
38
47
|
export interface Service {
|
|
39
48
|
serviceId: string;
|
|
40
49
|
uuid: string;
|
|
41
|
-
|
|
50
|
+
offers: ServiceOffer[];
|
|
42
51
|
username: string;
|
|
43
52
|
serviceFqn: string;
|
|
44
53
|
isPublic: boolean;
|
|
@@ -7,7 +7,9 @@ export interface RondevuServiceOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export interface PublishServiceOptions {
|
|
9
9
|
serviceFqn: string;
|
|
10
|
-
|
|
10
|
+
offers: Array<{
|
|
11
|
+
sdp: string;
|
|
12
|
+
}>;
|
|
11
13
|
ttl?: number;
|
|
12
14
|
isPublic?: boolean;
|
|
13
15
|
metadata?: Record<string, any>;
|
|
@@ -36,7 +38,7 @@ export interface PublishServiceOptions {
|
|
|
36
38
|
* // Publish a service
|
|
37
39
|
* const publishedService = await service.publishService({
|
|
38
40
|
* serviceFqn: 'chat.app@1.0.0',
|
|
39
|
-
* sdp: offerSdp,
|
|
41
|
+
* offers: [{ sdp: offerSdp }],
|
|
40
42
|
* ttl: 300000,
|
|
41
43
|
* isPublic: true,
|
|
42
44
|
* })
|
package/dist/rondevu-service.js
CHANGED
|
@@ -23,7 +23,7 @@ import { RondevuAPI } from './api.js';
|
|
|
23
23
|
* // Publish a service
|
|
24
24
|
* const publishedService = await service.publishService({
|
|
25
25
|
* serviceFqn: 'chat.app@1.0.0',
|
|
26
|
-
* sdp: offerSdp,
|
|
26
|
+
* offers: [{ sdp: offerSdp }],
|
|
27
27
|
* ttl: 300000,
|
|
28
28
|
* isPublic: true,
|
|
29
29
|
* })
|
|
@@ -86,7 +86,7 @@ export class RondevuService {
|
|
|
86
86
|
if (!this.usernameClaimed) {
|
|
87
87
|
throw new Error('Username not claimed. Call claimUsername() first or the server will reject the service.');
|
|
88
88
|
}
|
|
89
|
-
const { serviceFqn,
|
|
89
|
+
const { serviceFqn, offers, ttl, isPublic, metadata } = options;
|
|
90
90
|
// Generate signature for service publication
|
|
91
91
|
const message = `publish:${this.username}:${serviceFqn}:${Date.now()}`;
|
|
92
92
|
const signature = await RondevuAPI.signMessage(message, this.keypair.privateKey);
|
|
@@ -94,7 +94,7 @@ export class RondevuService {
|
|
|
94
94
|
const serviceRequest = {
|
|
95
95
|
username: this.username,
|
|
96
96
|
serviceFqn,
|
|
97
|
-
|
|
97
|
+
offers,
|
|
98
98
|
signature,
|
|
99
99
|
message,
|
|
100
100
|
ttl,
|
package/dist/rondevu-signaler.js
CHANGED
|
@@ -62,11 +62,15 @@ export class RondevuSignaler {
|
|
|
62
62
|
// Publish service with the offer SDP
|
|
63
63
|
const publishedService = await this.rondevu.publishService({
|
|
64
64
|
serviceFqn: this.service,
|
|
65
|
-
sdp: offer.sdp,
|
|
65
|
+
offers: [{ sdp: offer.sdp }],
|
|
66
66
|
ttl: 300000, // 5 minutes
|
|
67
67
|
isPublic: true,
|
|
68
68
|
});
|
|
69
|
-
|
|
69
|
+
// Get the first offer from the published service
|
|
70
|
+
if (!publishedService.offers || publishedService.offers.length === 0) {
|
|
71
|
+
throw new Error('No offers returned from service publication');
|
|
72
|
+
}
|
|
73
|
+
this.offerId = publishedService.offers[0].offerId;
|
|
70
74
|
this.serviceUuid = publishedService.uuid;
|
|
71
75
|
// Start polling for answer
|
|
72
76
|
this.startAnswerPolling();
|
|
@@ -173,12 +177,19 @@ export class RondevuSignaler {
|
|
|
173
177
|
}
|
|
174
178
|
// Get the first available service (already has full details from searchServices)
|
|
175
179
|
const service = services[0];
|
|
176
|
-
|
|
180
|
+
// Get the first available offer from the service
|
|
181
|
+
if (!service.offers || service.offers.length === 0) {
|
|
182
|
+
console.warn(`No offers available for service ${this.host}/${this.service}`);
|
|
183
|
+
this.isPolling = false;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const firstOffer = service.offers[0];
|
|
187
|
+
this.offerId = firstOffer.offerId;
|
|
177
188
|
this.serviceUuid = service.uuid;
|
|
178
189
|
// Notify offer listeners
|
|
179
190
|
const offer = {
|
|
180
191
|
type: 'offer',
|
|
181
|
-
sdp:
|
|
192
|
+
sdp: firstOffer.sdp,
|
|
182
193
|
};
|
|
183
194
|
this.offerListeners.forEach(listener => {
|
|
184
195
|
try {
|
package/package.json
CHANGED