@xtr-dev/rondevu-client 0.7.11 → 0.8.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 +459 -404
- package/dist/auth.d.ts +3 -3
- package/dist/auth.js +4 -8
- package/dist/discovery.d.ts +93 -0
- package/dist/discovery.js +164 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -2
- package/dist/offer-pool.d.ts +74 -0
- package/dist/offer-pool.js +119 -0
- package/dist/rondevu.d.ts +18 -3
- package/dist/rondevu.js +32 -5
- package/dist/service-pool.d.ts +115 -0
- package/dist/service-pool.js +339 -0
- package/dist/services.d.ts +79 -0
- package/dist/services.js +206 -0
- package/dist/usernames.d.ts +79 -0
- package/dist/usernames.js +147 -0
- package/package.json +3 -3
package/dist/auth.d.ts
CHANGED
|
@@ -9,10 +9,10 @@ export declare class RondevuAuth {
|
|
|
9
9
|
constructor(baseUrl: string, fetchFn?: FetchFunction);
|
|
10
10
|
/**
|
|
11
11
|
* Register a new peer and receive credentials
|
|
12
|
-
*
|
|
13
|
-
* @throws Error if registration fails
|
|
12
|
+
* Generates a cryptographically random peer ID (128-bit)
|
|
13
|
+
* @throws Error if registration fails
|
|
14
14
|
*/
|
|
15
|
-
register(
|
|
15
|
+
register(): Promise<Credentials>;
|
|
16
16
|
/**
|
|
17
17
|
* Create Authorization header value
|
|
18
18
|
*/
|
package/dist/auth.js
CHANGED
|
@@ -11,20 +11,16 @@ export class RondevuAuth {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Register a new peer and receive credentials
|
|
14
|
-
*
|
|
15
|
-
* @throws Error if registration fails
|
|
14
|
+
* Generates a cryptographically random peer ID (128-bit)
|
|
15
|
+
* @throws Error if registration fails
|
|
16
16
|
*/
|
|
17
|
-
async register(
|
|
18
|
-
const body = {};
|
|
19
|
-
if (customPeerId !== undefined) {
|
|
20
|
-
body.peerId = customPeerId;
|
|
21
|
-
}
|
|
17
|
+
async register() {
|
|
22
18
|
const response = await this.fetchFn(`${this.baseUrl}/register`, {
|
|
23
19
|
method: 'POST',
|
|
24
20
|
headers: {
|
|
25
21
|
'Content-Type': 'application/json',
|
|
26
22
|
},
|
|
27
|
-
body: JSON.stringify(
|
|
23
|
+
body: JSON.stringify({}),
|
|
28
24
|
});
|
|
29
25
|
if (!response.ok) {
|
|
30
26
|
const error = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import RondevuPeer from './peer/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Service info from discovery
|
|
4
|
+
*/
|
|
5
|
+
export interface ServiceInfo {
|
|
6
|
+
uuid: string;
|
|
7
|
+
isPublic: boolean;
|
|
8
|
+
serviceFqn?: string;
|
|
9
|
+
metadata?: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Service list result
|
|
13
|
+
*/
|
|
14
|
+
export interface ServiceListResult {
|
|
15
|
+
username: string;
|
|
16
|
+
services: ServiceInfo[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Service query result
|
|
20
|
+
*/
|
|
21
|
+
export interface ServiceQueryResult {
|
|
22
|
+
uuid: string;
|
|
23
|
+
allowed: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Service details
|
|
27
|
+
*/
|
|
28
|
+
export interface ServiceDetails {
|
|
29
|
+
serviceId: string;
|
|
30
|
+
username: string;
|
|
31
|
+
serviceFqn: string;
|
|
32
|
+
offerId: string;
|
|
33
|
+
sdp: string;
|
|
34
|
+
isPublic: boolean;
|
|
35
|
+
metadata?: Record<string, any>;
|
|
36
|
+
createdAt: number;
|
|
37
|
+
expiresAt: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Connect result
|
|
41
|
+
*/
|
|
42
|
+
export interface ConnectResult {
|
|
43
|
+
peer: RondevuPeer;
|
|
44
|
+
channel: RTCDataChannel;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Rondevu Discovery API
|
|
48
|
+
* Handles service discovery and connections
|
|
49
|
+
*/
|
|
50
|
+
export declare class RondevuDiscovery {
|
|
51
|
+
private baseUrl;
|
|
52
|
+
private credentials;
|
|
53
|
+
private offersApi;
|
|
54
|
+
constructor(baseUrl: string, credentials: {
|
|
55
|
+
peerId: string;
|
|
56
|
+
secret: string;
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* Lists all services for a username
|
|
60
|
+
* Returns UUIDs only for private services, full details for public
|
|
61
|
+
*/
|
|
62
|
+
listServices(username: string): Promise<ServiceListResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Queries a service by FQN
|
|
65
|
+
* Returns UUID if service exists and is allowed
|
|
66
|
+
*/
|
|
67
|
+
queryService(username: string, serviceFqn: string): Promise<ServiceQueryResult>;
|
|
68
|
+
/**
|
|
69
|
+
* Gets service details by UUID
|
|
70
|
+
*/
|
|
71
|
+
getServiceDetails(uuid: string): Promise<ServiceDetails>;
|
|
72
|
+
/**
|
|
73
|
+
* Connects to a service by UUID
|
|
74
|
+
*/
|
|
75
|
+
connectToService(uuid: string, options?: {
|
|
76
|
+
rtcConfig?: RTCConfiguration;
|
|
77
|
+
onConnected?: () => void;
|
|
78
|
+
onData?: (data: any) => void;
|
|
79
|
+
}): Promise<RondevuPeer>;
|
|
80
|
+
/**
|
|
81
|
+
* Convenience method: Query and connect in one call
|
|
82
|
+
* Returns both peer and data channel
|
|
83
|
+
*/
|
|
84
|
+
connect(username: string, serviceFqn: string, options?: {
|
|
85
|
+
rtcConfig?: RTCConfiguration;
|
|
86
|
+
}): Promise<ConnectResult>;
|
|
87
|
+
/**
|
|
88
|
+
* Convenience method: Connect to service by UUID with channel
|
|
89
|
+
*/
|
|
90
|
+
connectByUuid(uuid: string, options?: {
|
|
91
|
+
rtcConfig?: RTCConfiguration;
|
|
92
|
+
}): Promise<ConnectResult>;
|
|
93
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import RondevuPeer from './peer/index.js';
|
|
2
|
+
import { RondevuOffers } from './offers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rondevu Discovery API
|
|
5
|
+
* Handles service discovery and connections
|
|
6
|
+
*/
|
|
7
|
+
export class RondevuDiscovery {
|
|
8
|
+
constructor(baseUrl, credentials) {
|
|
9
|
+
this.baseUrl = baseUrl;
|
|
10
|
+
this.credentials = credentials;
|
|
11
|
+
this.offersApi = new RondevuOffers(baseUrl, credentials);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Lists all services for a username
|
|
15
|
+
* Returns UUIDs only for private services, full details for public
|
|
16
|
+
*/
|
|
17
|
+
async listServices(username) {
|
|
18
|
+
const response = await fetch(`${this.baseUrl}/usernames/${username}/services`);
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
throw new Error('Failed to list services');
|
|
21
|
+
}
|
|
22
|
+
const data = await response.json();
|
|
23
|
+
return {
|
|
24
|
+
username: data.username,
|
|
25
|
+
services: data.services
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Queries a service by FQN
|
|
30
|
+
* Returns UUID if service exists and is allowed
|
|
31
|
+
*/
|
|
32
|
+
async queryService(username, serviceFqn) {
|
|
33
|
+
const response = await fetch(`${this.baseUrl}/index/${username}/query`, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: { 'Content-Type': 'application/json' },
|
|
36
|
+
body: JSON.stringify({ serviceFqn })
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
const error = await response.json();
|
|
40
|
+
throw new Error(error.error || 'Service not found');
|
|
41
|
+
}
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
return {
|
|
44
|
+
uuid: data.uuid,
|
|
45
|
+
allowed: data.allowed
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Gets service details by UUID
|
|
50
|
+
*/
|
|
51
|
+
async getServiceDetails(uuid) {
|
|
52
|
+
const response = await fetch(`${this.baseUrl}/services/${uuid}`);
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const error = await response.json();
|
|
55
|
+
throw new Error(error.error || 'Service not found');
|
|
56
|
+
}
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
return {
|
|
59
|
+
serviceId: data.serviceId,
|
|
60
|
+
username: data.username,
|
|
61
|
+
serviceFqn: data.serviceFqn,
|
|
62
|
+
offerId: data.offerId,
|
|
63
|
+
sdp: data.sdp,
|
|
64
|
+
isPublic: data.isPublic,
|
|
65
|
+
metadata: data.metadata,
|
|
66
|
+
createdAt: data.createdAt,
|
|
67
|
+
expiresAt: data.expiresAt
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Connects to a service by UUID
|
|
72
|
+
*/
|
|
73
|
+
async connectToService(uuid, options) {
|
|
74
|
+
// Get service details
|
|
75
|
+
const service = await this.getServiceDetails(uuid);
|
|
76
|
+
// Create peer with the offer
|
|
77
|
+
const peer = new RondevuPeer(this.offersApi, options?.rtcConfig || {
|
|
78
|
+
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
|
79
|
+
});
|
|
80
|
+
// Set up event handlers
|
|
81
|
+
if (options?.onConnected) {
|
|
82
|
+
peer.on('connected', options.onConnected);
|
|
83
|
+
}
|
|
84
|
+
if (options?.onData) {
|
|
85
|
+
peer.on('datachannel', (channel) => {
|
|
86
|
+
channel.onmessage = (e) => options.onData(e.data);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// Answer the offer
|
|
90
|
+
await peer.answer(service.offerId, service.sdp, {
|
|
91
|
+
topics: [], // V2 doesn't use topics
|
|
92
|
+
rtcConfig: options?.rtcConfig
|
|
93
|
+
});
|
|
94
|
+
return peer;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Convenience method: Query and connect in one call
|
|
98
|
+
* Returns both peer and data channel
|
|
99
|
+
*/
|
|
100
|
+
async connect(username, serviceFqn, options) {
|
|
101
|
+
// Query service
|
|
102
|
+
const query = await this.queryService(username, serviceFqn);
|
|
103
|
+
if (!query.allowed) {
|
|
104
|
+
throw new Error('Service access denied');
|
|
105
|
+
}
|
|
106
|
+
// Get service details
|
|
107
|
+
const service = await this.getServiceDetails(query.uuid);
|
|
108
|
+
// Create peer
|
|
109
|
+
const peer = new RondevuPeer(this.offersApi, options?.rtcConfig || {
|
|
110
|
+
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
|
111
|
+
});
|
|
112
|
+
// Answer the offer
|
|
113
|
+
await peer.answer(service.offerId, service.sdp, {
|
|
114
|
+
topics: [], // V2 doesn't use topics
|
|
115
|
+
rtcConfig: options?.rtcConfig
|
|
116
|
+
});
|
|
117
|
+
// Wait for data channel
|
|
118
|
+
const channel = await new Promise((resolve, reject) => {
|
|
119
|
+
const timeout = setTimeout(() => {
|
|
120
|
+
reject(new Error('Timeout waiting for data channel'));
|
|
121
|
+
}, 30000);
|
|
122
|
+
peer.on('datachannel', (ch) => {
|
|
123
|
+
clearTimeout(timeout);
|
|
124
|
+
resolve(ch);
|
|
125
|
+
});
|
|
126
|
+
peer.on('failed', (error) => {
|
|
127
|
+
clearTimeout(timeout);
|
|
128
|
+
reject(error);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
return { peer, channel };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Convenience method: Connect to service by UUID with channel
|
|
135
|
+
*/
|
|
136
|
+
async connectByUuid(uuid, options) {
|
|
137
|
+
// Get service details
|
|
138
|
+
const service = await this.getServiceDetails(uuid);
|
|
139
|
+
// Create peer
|
|
140
|
+
const peer = new RondevuPeer(this.offersApi, options?.rtcConfig || {
|
|
141
|
+
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
|
142
|
+
});
|
|
143
|
+
// Answer the offer
|
|
144
|
+
await peer.answer(service.offerId, service.sdp, {
|
|
145
|
+
topics: [], // V2 doesn't use topics
|
|
146
|
+
rtcConfig: options?.rtcConfig
|
|
147
|
+
});
|
|
148
|
+
// Wait for data channel
|
|
149
|
+
const channel = await new Promise((resolve, reject) => {
|
|
150
|
+
const timeout = setTimeout(() => {
|
|
151
|
+
reject(new Error('Timeout waiting for data channel'));
|
|
152
|
+
}, 30000);
|
|
153
|
+
peer.on('datachannel', (ch) => {
|
|
154
|
+
clearTimeout(timeout);
|
|
155
|
+
resolve(ch);
|
|
156
|
+
});
|
|
157
|
+
peer.on('failed', (error) => {
|
|
158
|
+
clearTimeout(timeout);
|
|
159
|
+
reject(error);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
return { peer, channel };
|
|
163
|
+
}
|
|
164
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,5 @@ export { RondevuAuth } from './auth.js';
|
|
|
8
8
|
export type { Credentials, FetchFunction } from './auth.js';
|
|
9
9
|
export { RondevuOffers } from './offers.js';
|
|
10
10
|
export type { CreateOfferRequest, Offer, IceCandidate, TopicInfo } from './offers.js';
|
|
11
|
-
export { BloomFilter } from './bloom.js';
|
|
12
11
|
export { default as RondevuPeer } from './peer/index.js';
|
|
13
12
|
export type { PeerOptions, PeerEvents, PeerTimeouts } from './peer/index.js';
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,5 @@ export { Rondevu } from './rondevu.js';
|
|
|
8
8
|
export { RondevuAuth } from './auth.js';
|
|
9
9
|
// Export offers API
|
|
10
10
|
export { RondevuOffers } from './offers.js';
|
|
11
|
-
// Export bloom filter
|
|
12
|
-
export { BloomFilter } from './bloom.js';
|
|
13
11
|
// Export peer manager
|
|
14
12
|
export { default as RondevuPeer } from './peer/index.js';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { RondevuOffers, Offer } from './offers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Represents an offer that has been answered
|
|
4
|
+
*/
|
|
5
|
+
export interface AnsweredOffer {
|
|
6
|
+
offerId: string;
|
|
7
|
+
answererId: string;
|
|
8
|
+
sdp: string;
|
|
9
|
+
answeredAt: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Configuration options for the offer pool
|
|
13
|
+
*/
|
|
14
|
+
export interface OfferPoolOptions {
|
|
15
|
+
/** Number of simultaneous open offers to maintain */
|
|
16
|
+
poolSize: number;
|
|
17
|
+
/** Polling interval in milliseconds (default: 2000ms) */
|
|
18
|
+
pollingInterval?: number;
|
|
19
|
+
/** Callback invoked when an offer is answered */
|
|
20
|
+
onAnswered: (answer: AnsweredOffer) => Promise<void>;
|
|
21
|
+
/** Callback to create new offers when refilling the pool */
|
|
22
|
+
onRefill: (count: number) => Promise<Offer[]>;
|
|
23
|
+
/** Error handler for pool operations */
|
|
24
|
+
onError: (error: Error, context: string) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Manages a pool of offers with automatic polling and refill
|
|
28
|
+
*
|
|
29
|
+
* The OfferPool maintains a configurable number of simultaneous offers,
|
|
30
|
+
* polls for answers periodically, and automatically refills the pool
|
|
31
|
+
* when offers are consumed.
|
|
32
|
+
*/
|
|
33
|
+
export declare class OfferPool {
|
|
34
|
+
private offersApi;
|
|
35
|
+
private options;
|
|
36
|
+
private offers;
|
|
37
|
+
private polling;
|
|
38
|
+
private pollingTimer?;
|
|
39
|
+
private lastPollTime;
|
|
40
|
+
private readonly pollingInterval;
|
|
41
|
+
constructor(offersApi: RondevuOffers, options: OfferPoolOptions);
|
|
42
|
+
/**
|
|
43
|
+
* Add offers to the pool
|
|
44
|
+
*/
|
|
45
|
+
addOffers(offers: Offer[]): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Start polling for answers
|
|
48
|
+
*/
|
|
49
|
+
start(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Stop polling for answers
|
|
52
|
+
*/
|
|
53
|
+
stop(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Poll for answers and refill the pool if needed
|
|
56
|
+
*/
|
|
57
|
+
private poll;
|
|
58
|
+
/**
|
|
59
|
+
* Get the current number of active offers in the pool
|
|
60
|
+
*/
|
|
61
|
+
getActiveOfferCount(): number;
|
|
62
|
+
/**
|
|
63
|
+
* Get all active offer IDs
|
|
64
|
+
*/
|
|
65
|
+
getActiveOfferIds(): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Get the last poll timestamp
|
|
68
|
+
*/
|
|
69
|
+
getLastPollTime(): number;
|
|
70
|
+
/**
|
|
71
|
+
* Check if the pool is currently polling
|
|
72
|
+
*/
|
|
73
|
+
isPolling(): boolean;
|
|
74
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages a pool of offers with automatic polling and refill
|
|
3
|
+
*
|
|
4
|
+
* The OfferPool maintains a configurable number of simultaneous offers,
|
|
5
|
+
* polls for answers periodically, and automatically refills the pool
|
|
6
|
+
* when offers are consumed.
|
|
7
|
+
*/
|
|
8
|
+
export class OfferPool {
|
|
9
|
+
constructor(offersApi, options) {
|
|
10
|
+
this.offersApi = offersApi;
|
|
11
|
+
this.options = options;
|
|
12
|
+
this.offers = new Map();
|
|
13
|
+
this.polling = false;
|
|
14
|
+
this.lastPollTime = 0;
|
|
15
|
+
this.pollingInterval = options.pollingInterval || 2000;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Add offers to the pool
|
|
19
|
+
*/
|
|
20
|
+
async addOffers(offers) {
|
|
21
|
+
for (const offer of offers) {
|
|
22
|
+
this.offers.set(offer.id, offer);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Start polling for answers
|
|
27
|
+
*/
|
|
28
|
+
async start() {
|
|
29
|
+
if (this.polling) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.polling = true;
|
|
33
|
+
// Do an immediate poll
|
|
34
|
+
await this.poll().catch((error) => {
|
|
35
|
+
this.options.onError(error, 'initial-poll');
|
|
36
|
+
});
|
|
37
|
+
// Start polling interval
|
|
38
|
+
this.pollingTimer = setInterval(async () => {
|
|
39
|
+
if (this.polling) {
|
|
40
|
+
await this.poll().catch((error) => {
|
|
41
|
+
this.options.onError(error, 'poll');
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}, this.pollingInterval);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Stop polling for answers
|
|
48
|
+
*/
|
|
49
|
+
async stop() {
|
|
50
|
+
this.polling = false;
|
|
51
|
+
if (this.pollingTimer) {
|
|
52
|
+
clearInterval(this.pollingTimer);
|
|
53
|
+
this.pollingTimer = undefined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Poll for answers and refill the pool if needed
|
|
58
|
+
*/
|
|
59
|
+
async poll() {
|
|
60
|
+
try {
|
|
61
|
+
// Get all answers from server
|
|
62
|
+
const answers = await this.offersApi.getAnswers();
|
|
63
|
+
// Filter for our pool's offers
|
|
64
|
+
const myAnswers = answers.filter(a => this.offers.has(a.offerId));
|
|
65
|
+
// Process each answer
|
|
66
|
+
for (const answer of myAnswers) {
|
|
67
|
+
// Notify ServicePool
|
|
68
|
+
await this.options.onAnswered({
|
|
69
|
+
offerId: answer.offerId,
|
|
70
|
+
answererId: answer.answererId,
|
|
71
|
+
sdp: answer.sdp,
|
|
72
|
+
answeredAt: answer.answeredAt
|
|
73
|
+
});
|
|
74
|
+
// Remove consumed offer from pool
|
|
75
|
+
this.offers.delete(answer.offerId);
|
|
76
|
+
}
|
|
77
|
+
// Immediate refill if below pool size
|
|
78
|
+
if (this.offers.size < this.options.poolSize) {
|
|
79
|
+
const needed = this.options.poolSize - this.offers.size;
|
|
80
|
+
try {
|
|
81
|
+
const newOffers = await this.options.onRefill(needed);
|
|
82
|
+
await this.addOffers(newOffers);
|
|
83
|
+
}
|
|
84
|
+
catch (refillError) {
|
|
85
|
+
this.options.onError(refillError, 'refill');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
this.lastPollTime = Date.now();
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// Don't crash the pool on errors - let error handler deal with it
|
|
92
|
+
this.options.onError(error, 'poll');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get the current number of active offers in the pool
|
|
97
|
+
*/
|
|
98
|
+
getActiveOfferCount() {
|
|
99
|
+
return this.offers.size;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get all active offer IDs
|
|
103
|
+
*/
|
|
104
|
+
getActiveOfferIds() {
|
|
105
|
+
return Array.from(this.offers.keys());
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get the last poll timestamp
|
|
109
|
+
*/
|
|
110
|
+
getLastPollTime() {
|
|
111
|
+
return this.lastPollTime;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if the pool is currently polling
|
|
115
|
+
*/
|
|
116
|
+
isPolling() {
|
|
117
|
+
return this.polling;
|
|
118
|
+
}
|
|
119
|
+
}
|
package/dist/rondevu.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { RondevuAuth, Credentials, FetchFunction } from './auth.js';
|
|
2
2
|
import { RondevuOffers } from './offers.js';
|
|
3
|
+
import { RondevuUsername } from './usernames.js';
|
|
4
|
+
import { RondevuServices } from './services.js';
|
|
5
|
+
import { RondevuDiscovery } from './discovery.js';
|
|
3
6
|
import RondevuPeer from './peer/index.js';
|
|
4
7
|
export interface RondevuOptions {
|
|
5
8
|
/**
|
|
@@ -58,7 +61,10 @@ export interface RondevuOptions {
|
|
|
58
61
|
}
|
|
59
62
|
export declare class Rondevu {
|
|
60
63
|
readonly auth: RondevuAuth;
|
|
64
|
+
readonly usernames: RondevuUsername;
|
|
61
65
|
private _offers?;
|
|
66
|
+
private _services?;
|
|
67
|
+
private _discovery?;
|
|
62
68
|
private credentials?;
|
|
63
69
|
private baseUrl;
|
|
64
70
|
private fetchFn?;
|
|
@@ -67,14 +73,23 @@ export declare class Rondevu {
|
|
|
67
73
|
private rtcIceCandidate?;
|
|
68
74
|
constructor(options?: RondevuOptions);
|
|
69
75
|
/**
|
|
70
|
-
* Get offers API (requires authentication)
|
|
76
|
+
* Get offers API (low-level access, requires authentication)
|
|
77
|
+
* For most use cases, use services and discovery APIs instead
|
|
71
78
|
*/
|
|
72
79
|
get offers(): RondevuOffers;
|
|
80
|
+
/**
|
|
81
|
+
* Get services API (requires authentication)
|
|
82
|
+
*/
|
|
83
|
+
get services(): RondevuServices;
|
|
84
|
+
/**
|
|
85
|
+
* Get discovery API (requires authentication)
|
|
86
|
+
*/
|
|
87
|
+
get discovery(): RondevuDiscovery;
|
|
73
88
|
/**
|
|
74
89
|
* Register and initialize authenticated client
|
|
75
|
-
*
|
|
90
|
+
* Generates a cryptographically random peer ID (128-bit)
|
|
76
91
|
*/
|
|
77
|
-
register(
|
|
92
|
+
register(): Promise<Credentials>;
|
|
78
93
|
/**
|
|
79
94
|
* Check if client is authenticated
|
|
80
95
|
*/
|
package/dist/rondevu.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { RondevuAuth } from './auth.js';
|
|
2
2
|
import { RondevuOffers } from './offers.js';
|
|
3
|
+
import { RondevuUsername } from './usernames.js';
|
|
4
|
+
import { RondevuServices } from './services.js';
|
|
5
|
+
import { RondevuDiscovery } from './discovery.js';
|
|
3
6
|
import RondevuPeer from './peer/index.js';
|
|
4
7
|
export class Rondevu {
|
|
5
8
|
constructor(options = {}) {
|
|
@@ -9,13 +12,17 @@ export class Rondevu {
|
|
|
9
12
|
this.rtcSessionDescription = options.RTCSessionDescription;
|
|
10
13
|
this.rtcIceCandidate = options.RTCIceCandidate;
|
|
11
14
|
this.auth = new RondevuAuth(this.baseUrl, this.fetchFn);
|
|
15
|
+
this.usernames = new RondevuUsername(this.baseUrl);
|
|
12
16
|
if (options.credentials) {
|
|
13
17
|
this.credentials = options.credentials;
|
|
14
18
|
this._offers = new RondevuOffers(this.baseUrl, this.credentials, this.fetchFn);
|
|
19
|
+
this._services = new RondevuServices(this.baseUrl, this.credentials);
|
|
20
|
+
this._discovery = new RondevuDiscovery(this.baseUrl, this.credentials);
|
|
15
21
|
}
|
|
16
22
|
}
|
|
17
23
|
/**
|
|
18
|
-
* Get offers API (requires authentication)
|
|
24
|
+
* Get offers API (low-level access, requires authentication)
|
|
25
|
+
* For most use cases, use services and discovery APIs instead
|
|
19
26
|
*/
|
|
20
27
|
get offers() {
|
|
21
28
|
if (!this._offers) {
|
|
@@ -23,14 +30,34 @@ export class Rondevu {
|
|
|
23
30
|
}
|
|
24
31
|
return this._offers;
|
|
25
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Get services API (requires authentication)
|
|
35
|
+
*/
|
|
36
|
+
get services() {
|
|
37
|
+
if (!this._services) {
|
|
38
|
+
throw new Error('Not authenticated. Call register() first or provide credentials.');
|
|
39
|
+
}
|
|
40
|
+
return this._services;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get discovery API (requires authentication)
|
|
44
|
+
*/
|
|
45
|
+
get discovery() {
|
|
46
|
+
if (!this._discovery) {
|
|
47
|
+
throw new Error('Not authenticated. Call register() first or provide credentials.');
|
|
48
|
+
}
|
|
49
|
+
return this._discovery;
|
|
50
|
+
}
|
|
26
51
|
/**
|
|
27
52
|
* Register and initialize authenticated client
|
|
28
|
-
*
|
|
53
|
+
* Generates a cryptographically random peer ID (128-bit)
|
|
29
54
|
*/
|
|
30
|
-
async register(
|
|
31
|
-
this.credentials = await this.auth.register(
|
|
32
|
-
// Create
|
|
55
|
+
async register() {
|
|
56
|
+
this.credentials = await this.auth.register();
|
|
57
|
+
// Create API instances
|
|
33
58
|
this._offers = new RondevuOffers(this.baseUrl, this.credentials, this.fetchFn);
|
|
59
|
+
this._services = new RondevuServices(this.baseUrl, this.credentials);
|
|
60
|
+
this._discovery = new RondevuDiscovery(this.baseUrl, this.credentials);
|
|
34
61
|
return this.credentials;
|
|
35
62
|
}
|
|
36
63
|
/**
|