@xtr-dev/rondevu-client 0.3.1 → 0.3.2
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 +36 -46
- package/dist/client.d.ts +23 -51
- package/dist/client.js +23 -63
- package/dist/connection.d.ts +0 -1
- package/dist/connection.js +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/rondevu.d.ts +16 -20
- package/dist/rondevu.js +48 -65
- package/dist/types.d.ts +4 -67
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Rondevu
|
|
2
2
|
|
|
3
|
-
🎯 **Simple WebRTC peer signaling
|
|
3
|
+
🎯 **Simple WebRTC peer signaling**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Connect peers directly by ID with automatic WebRTC negotiation.
|
|
6
6
|
|
|
7
7
|
**Related repositories:**
|
|
8
8
|
- [rondevu-server](https://github.com/xtr-dev/rondevu-server) - HTTP signaling server
|
|
@@ -30,68 +30,57 @@ npm install @xtr-dev/rondevu-client
|
|
|
30
30
|
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
31
31
|
|
|
32
32
|
const rdv = new Rondevu({
|
|
33
|
-
baseUrl: 'https://
|
|
33
|
+
baseUrl: 'https://api.ronde.vu',
|
|
34
34
|
rtcConfig: {
|
|
35
35
|
iceServers: [
|
|
36
|
-
// your ICE servers here
|
|
37
36
|
{ urls: 'stun:stun.l.google.com:19302' },
|
|
38
|
-
{ urls: 'stun:stun1.l.google.com:19302' }
|
|
39
|
-
{
|
|
40
|
-
urls: 'turn:relay1.example.com:3480',
|
|
41
|
-
username: 'example',
|
|
42
|
-
credential: 'example'
|
|
43
|
-
}
|
|
37
|
+
{ urls: 'stun:stun1.l.google.com:19302' }
|
|
44
38
|
]
|
|
45
39
|
}
|
|
46
40
|
});
|
|
47
41
|
|
|
48
|
-
//
|
|
49
|
-
const
|
|
42
|
+
// Create a connection with custom ID
|
|
43
|
+
const connection = await rdv.create('my-room-123');
|
|
50
44
|
|
|
51
|
-
// Or connect
|
|
52
|
-
const
|
|
45
|
+
// Or connect to an existing connection
|
|
46
|
+
const connection = await rdv.connect('my-room-123');
|
|
53
47
|
|
|
54
|
-
// Use
|
|
55
|
-
|
|
56
|
-
const channel =
|
|
48
|
+
// Use data channels
|
|
49
|
+
connection.on('connect', () => {
|
|
50
|
+
const channel = connection.dataChannel('chat');
|
|
57
51
|
channel.send('Hello!');
|
|
58
52
|
});
|
|
53
|
+
|
|
54
|
+
connection.on('datachannel', (channel) => {
|
|
55
|
+
if (channel.label === 'chat') {
|
|
56
|
+
channel.onmessage = (event) => {
|
|
57
|
+
console.log('Received:', event.data);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
});
|
|
59
61
|
```
|
|
60
62
|
|
|
61
63
|
#### Node.js
|
|
62
64
|
|
|
63
|
-
In Node.js, you need to provide a WebRTC polyfill since WebRTC APIs are not natively available:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
npm install @roamhq/wrtc
|
|
67
|
-
# or
|
|
68
|
-
npm install wrtc
|
|
69
|
-
```
|
|
70
|
-
|
|
71
65
|
```typescript
|
|
72
66
|
import { Rondevu } from '@xtr-dev/rondevu-client';
|
|
73
67
|
import wrtc from '@roamhq/wrtc';
|
|
74
68
|
import fetch from 'node-fetch';
|
|
75
69
|
|
|
76
70
|
const rdv = new Rondevu({
|
|
77
|
-
baseUrl: 'https://
|
|
71
|
+
baseUrl: 'https://api.ronde.vu',
|
|
78
72
|
fetch: fetch as any,
|
|
79
73
|
wrtc: {
|
|
80
74
|
RTCPeerConnection: wrtc.RTCPeerConnection,
|
|
81
75
|
RTCSessionDescription: wrtc.RTCSessionDescription,
|
|
82
76
|
RTCIceCandidate: wrtc.RTCIceCandidate,
|
|
83
|
-
},
|
|
84
|
-
rtcConfig: {
|
|
85
|
-
iceServers: [
|
|
86
|
-
{ urls: 'stun:stun.l.google.com:19302' }
|
|
87
|
-
]
|
|
88
77
|
}
|
|
89
78
|
});
|
|
90
79
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const channel =
|
|
80
|
+
const connection = await rdv.create('my-room-123');
|
|
81
|
+
|
|
82
|
+
connection.on('connect', () => {
|
|
83
|
+
const channel = connection.dataChannel('chat');
|
|
95
84
|
channel.send('Hello from Node.js!');
|
|
96
85
|
});
|
|
97
86
|
```
|
|
@@ -99,23 +88,24 @@ conn.on('connect', () => {
|
|
|
99
88
|
### API
|
|
100
89
|
|
|
101
90
|
**Main Methods:**
|
|
102
|
-
- `rdv.
|
|
103
|
-
- `rdv.
|
|
104
|
-
- `rdv.create(id, topic)` - Create connection for others to join
|
|
105
|
-
- `rdv.connect(id)` - Join connection by ID
|
|
91
|
+
- `rdv.create(id)` - Create connection with custom ID
|
|
92
|
+
- `rdv.connect(id)` - Connect to existing connection by ID
|
|
106
93
|
|
|
107
94
|
**Connection Events:**
|
|
108
95
|
- `connect` - Connection established
|
|
109
96
|
- `disconnect` - Connection closed
|
|
110
|
-
- `
|
|
111
|
-
- `
|
|
112
|
-
- `
|
|
97
|
+
- `error` - Connection error
|
|
98
|
+
- `datachannel` - New data channel received
|
|
99
|
+
- `stream` - Media stream received
|
|
113
100
|
|
|
114
101
|
**Connection Methods:**
|
|
115
|
-
- `
|
|
116
|
-
- `
|
|
117
|
-
- `
|
|
118
|
-
|
|
102
|
+
- `connection.dataChannel(label)` - Get or create data channel
|
|
103
|
+
- `connection.addStream(stream)` - Add media stream
|
|
104
|
+
- `connection.close()` - Close connection
|
|
105
|
+
|
|
106
|
+
### Version Compatibility
|
|
107
|
+
|
|
108
|
+
The client automatically checks server compatibility via the `/health` endpoint. If the server version is incompatible, an error will be thrown during initialization.
|
|
119
109
|
|
|
120
110
|
### License
|
|
121
111
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { RondevuClientOptions,
|
|
1
|
+
import { RondevuClientOptions, CreateOfferRequest, CreateOfferResponse, AnswerRequest, AnswerResponse, PollOffererResponse, PollAnswererResponse, VersionResponse, HealthResponse, Side } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* HTTP API client for Rondevu peer signaling
|
|
3
|
+
* HTTP API client for Rondevu peer signaling server
|
|
4
4
|
*/
|
|
5
5
|
export declare class RondevuAPI {
|
|
6
6
|
private readonly baseUrl;
|
|
@@ -17,7 +17,7 @@ export declare class RondevuAPI {
|
|
|
17
17
|
/**
|
|
18
18
|
* Gets server version information
|
|
19
19
|
*
|
|
20
|
-
* @returns Server version
|
|
20
|
+
* @returns Server version
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* ```typescript
|
|
@@ -28,56 +28,27 @@ export declare class RondevuAPI {
|
|
|
28
28
|
*/
|
|
29
29
|
getVersion(): Promise<VersionResponse>;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* Creates a new offer
|
|
32
32
|
*
|
|
33
|
-
* @param
|
|
34
|
-
* @
|
|
35
|
-
* @returns List of topics with pagination info
|
|
33
|
+
* @param request - Offer details including peer ID, signaling data, and optional custom code
|
|
34
|
+
* @returns Unique offer code (UUID or custom code)
|
|
36
35
|
*
|
|
37
36
|
* @example
|
|
38
37
|
* ```typescript
|
|
39
38
|
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
40
|
-
* const {
|
|
41
|
-
* console.log(`Found ${topics.length} topics`);
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
listTopics(page?: number, limit?: number): Promise<ListTopicsResponse>;
|
|
45
|
-
/**
|
|
46
|
-
* Discovers available peers for a given topic
|
|
47
|
-
*
|
|
48
|
-
* @param topic - Topic identifier
|
|
49
|
-
* @returns List of available sessions
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* ```typescript
|
|
53
|
-
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
54
|
-
* const { sessions } = await api.listSessions('my-room');
|
|
55
|
-
* const otherPeers = sessions.filter(s => s.peerId !== myPeerId);
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
listSessions(topic: string): Promise<ListSessionsResponse>;
|
|
59
|
-
/**
|
|
60
|
-
* Announces peer availability and creates a new session
|
|
61
|
-
*
|
|
62
|
-
* @param topic - Topic identifier for grouping peers (max 1024 characters)
|
|
63
|
-
* @param request - Offer details including peer ID and signaling data
|
|
64
|
-
* @returns Unique session code (UUID)
|
|
65
|
-
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```typescript
|
|
68
|
-
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
69
|
-
* const { code } = await api.createOffer('my-room', {
|
|
39
|
+
* const { code } = await api.createOffer({
|
|
70
40
|
* peerId: 'peer-123',
|
|
71
|
-
* offer: signalingData
|
|
41
|
+
* offer: signalingData,
|
|
42
|
+
* code: 'my-custom-code' // optional
|
|
72
43
|
* });
|
|
73
|
-
* console.log('
|
|
44
|
+
* console.log('Offer code:', code);
|
|
74
45
|
* ```
|
|
75
46
|
*/
|
|
76
|
-
createOffer(
|
|
47
|
+
createOffer(request: CreateOfferRequest): Promise<CreateOfferResponse>;
|
|
77
48
|
/**
|
|
78
|
-
* Sends an answer or candidate to an existing
|
|
49
|
+
* Sends an answer or candidate to an existing offer
|
|
79
50
|
*
|
|
80
|
-
* @param request - Answer details including
|
|
51
|
+
* @param request - Answer details including offer code and signaling data
|
|
81
52
|
* @returns Success confirmation
|
|
82
53
|
*
|
|
83
54
|
* @example
|
|
@@ -86,14 +57,14 @@ export declare class RondevuAPI {
|
|
|
86
57
|
*
|
|
87
58
|
* // Send answer
|
|
88
59
|
* await api.sendAnswer({
|
|
89
|
-
* code:
|
|
60
|
+
* code: offerCode,
|
|
90
61
|
* answer: answerData,
|
|
91
62
|
* side: 'answerer'
|
|
92
63
|
* });
|
|
93
64
|
*
|
|
94
65
|
* // Send candidate
|
|
95
66
|
* await api.sendAnswer({
|
|
96
|
-
* code:
|
|
67
|
+
* code: offerCode,
|
|
97
68
|
* candidate: candidateData,
|
|
98
69
|
* side: 'offerer'
|
|
99
70
|
* });
|
|
@@ -101,38 +72,39 @@ export declare class RondevuAPI {
|
|
|
101
72
|
*/
|
|
102
73
|
sendAnswer(request: AnswerRequest): Promise<AnswerResponse>;
|
|
103
74
|
/**
|
|
104
|
-
* Polls for
|
|
75
|
+
* Polls for offer data from the other peer
|
|
105
76
|
*
|
|
106
|
-
* @param code -
|
|
77
|
+
* @param code - Offer code
|
|
107
78
|
* @param side - Which side is polling ('offerer' or 'answerer')
|
|
108
|
-
* @returns
|
|
79
|
+
* @returns Offer data including offers, answers, and candidates
|
|
109
80
|
*
|
|
110
81
|
* @example
|
|
111
82
|
* ```typescript
|
|
112
83
|
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
113
84
|
*
|
|
114
85
|
* // Offerer polls for answer
|
|
115
|
-
* const offererData = await api.poll(
|
|
86
|
+
* const offererData = await api.poll(offerCode, 'offerer');
|
|
116
87
|
* if (offererData.answer) {
|
|
117
88
|
* console.log('Received answer:', offererData.answer);
|
|
118
89
|
* }
|
|
119
90
|
*
|
|
120
91
|
* // Answerer polls for offer
|
|
121
|
-
* const answererData = await api.poll(
|
|
92
|
+
* const answererData = await api.poll(offerCode, 'answerer');
|
|
122
93
|
* console.log('Received offer:', answererData.offer);
|
|
123
94
|
* ```
|
|
124
95
|
*/
|
|
125
96
|
poll(code: string, side: Side): Promise<PollOffererResponse | PollAnswererResponse>;
|
|
126
97
|
/**
|
|
127
|
-
* Checks server health
|
|
98
|
+
* Checks server health and version
|
|
128
99
|
*
|
|
129
|
-
* @returns Health status and
|
|
100
|
+
* @returns Health status, timestamp, and version
|
|
130
101
|
*
|
|
131
102
|
* @example
|
|
132
103
|
* ```typescript
|
|
133
104
|
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
134
105
|
* const health = await api.health();
|
|
135
106
|
* console.log('Server status:', health.status);
|
|
107
|
+
* console.log('Server version:', health.version);
|
|
136
108
|
* ```
|
|
137
109
|
*/
|
|
138
110
|
health(): Promise<HealthResponse>;
|
package/dist/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HTTP API client for Rondevu peer signaling
|
|
2
|
+
* HTTP API client for Rondevu peer signaling server
|
|
3
3
|
*/
|
|
4
4
|
export class RondevuAPI {
|
|
5
5
|
/**
|
|
@@ -35,7 +35,7 @@ export class RondevuAPI {
|
|
|
35
35
|
/**
|
|
36
36
|
* Gets server version information
|
|
37
37
|
*
|
|
38
|
-
* @returns Server version
|
|
38
|
+
* @returns Server version
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```typescript
|
|
@@ -50,73 +50,32 @@ export class RondevuAPI {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* Creates a new offer
|
|
54
54
|
*
|
|
55
|
-
* @param
|
|
56
|
-
* @
|
|
57
|
-
* @returns List of topics with pagination info
|
|
55
|
+
* @param request - Offer details including peer ID, signaling data, and optional custom code
|
|
56
|
+
* @returns Unique offer code (UUID or custom code)
|
|
58
57
|
*
|
|
59
58
|
* @example
|
|
60
59
|
* ```typescript
|
|
61
60
|
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
62
|
-
* const {
|
|
63
|
-
* console.log(`Found ${topics.length} topics`);
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
async listTopics(page = 1, limit = 100) {
|
|
67
|
-
const params = new URLSearchParams({
|
|
68
|
-
page: page.toString(),
|
|
69
|
-
limit: limit.toString(),
|
|
70
|
-
});
|
|
71
|
-
return this.request(`/topics?${params}`, {
|
|
72
|
-
method: 'GET',
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Discovers available peers for a given topic
|
|
77
|
-
*
|
|
78
|
-
* @param topic - Topic identifier
|
|
79
|
-
* @returns List of available sessions
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* ```typescript
|
|
83
|
-
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
84
|
-
* const { sessions } = await api.listSessions('my-room');
|
|
85
|
-
* const otherPeers = sessions.filter(s => s.peerId !== myPeerId);
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
async listSessions(topic) {
|
|
89
|
-
return this.request(`/${encodeURIComponent(topic)}/sessions`, {
|
|
90
|
-
method: 'GET',
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Announces peer availability and creates a new session
|
|
95
|
-
*
|
|
96
|
-
* @param topic - Topic identifier for grouping peers (max 1024 characters)
|
|
97
|
-
* @param request - Offer details including peer ID and signaling data
|
|
98
|
-
* @returns Unique session code (UUID)
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```typescript
|
|
102
|
-
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
103
|
-
* const { code } = await api.createOffer('my-room', {
|
|
61
|
+
* const { code } = await api.createOffer({
|
|
104
62
|
* peerId: 'peer-123',
|
|
105
|
-
* offer: signalingData
|
|
63
|
+
* offer: signalingData,
|
|
64
|
+
* code: 'my-custom-code' // optional
|
|
106
65
|
* });
|
|
107
|
-
* console.log('
|
|
66
|
+
* console.log('Offer code:', code);
|
|
108
67
|
* ```
|
|
109
68
|
*/
|
|
110
|
-
async createOffer(
|
|
111
|
-
return this.request(
|
|
69
|
+
async createOffer(request) {
|
|
70
|
+
return this.request('/offer', {
|
|
112
71
|
method: 'POST',
|
|
113
72
|
body: JSON.stringify(request),
|
|
114
73
|
});
|
|
115
74
|
}
|
|
116
75
|
/**
|
|
117
|
-
* Sends an answer or candidate to an existing
|
|
76
|
+
* Sends an answer or candidate to an existing offer
|
|
118
77
|
*
|
|
119
|
-
* @param request - Answer details including
|
|
78
|
+
* @param request - Answer details including offer code and signaling data
|
|
120
79
|
* @returns Success confirmation
|
|
121
80
|
*
|
|
122
81
|
* @example
|
|
@@ -125,14 +84,14 @@ export class RondevuAPI {
|
|
|
125
84
|
*
|
|
126
85
|
* // Send answer
|
|
127
86
|
* await api.sendAnswer({
|
|
128
|
-
* code:
|
|
87
|
+
* code: offerCode,
|
|
129
88
|
* answer: answerData,
|
|
130
89
|
* side: 'answerer'
|
|
131
90
|
* });
|
|
132
91
|
*
|
|
133
92
|
* // Send candidate
|
|
134
93
|
* await api.sendAnswer({
|
|
135
|
-
* code:
|
|
94
|
+
* code: offerCode,
|
|
136
95
|
* candidate: candidateData,
|
|
137
96
|
* side: 'offerer'
|
|
138
97
|
* });
|
|
@@ -145,24 +104,24 @@ export class RondevuAPI {
|
|
|
145
104
|
});
|
|
146
105
|
}
|
|
147
106
|
/**
|
|
148
|
-
* Polls for
|
|
107
|
+
* Polls for offer data from the other peer
|
|
149
108
|
*
|
|
150
|
-
* @param code -
|
|
109
|
+
* @param code - Offer code
|
|
151
110
|
* @param side - Which side is polling ('offerer' or 'answerer')
|
|
152
|
-
* @returns
|
|
111
|
+
* @returns Offer data including offers, answers, and candidates
|
|
153
112
|
*
|
|
154
113
|
* @example
|
|
155
114
|
* ```typescript
|
|
156
115
|
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
157
116
|
*
|
|
158
117
|
* // Offerer polls for answer
|
|
159
|
-
* const offererData = await api.poll(
|
|
118
|
+
* const offererData = await api.poll(offerCode, 'offerer');
|
|
160
119
|
* if (offererData.answer) {
|
|
161
120
|
* console.log('Received answer:', offererData.answer);
|
|
162
121
|
* }
|
|
163
122
|
*
|
|
164
123
|
* // Answerer polls for offer
|
|
165
|
-
* const answererData = await api.poll(
|
|
124
|
+
* const answererData = await api.poll(offerCode, 'answerer');
|
|
166
125
|
* console.log('Received offer:', answererData.offer);
|
|
167
126
|
* ```
|
|
168
127
|
*/
|
|
@@ -174,15 +133,16 @@ export class RondevuAPI {
|
|
|
174
133
|
});
|
|
175
134
|
}
|
|
176
135
|
/**
|
|
177
|
-
* Checks server health
|
|
136
|
+
* Checks server health and version
|
|
178
137
|
*
|
|
179
|
-
* @returns Health status and
|
|
138
|
+
* @returns Health status, timestamp, and version
|
|
180
139
|
*
|
|
181
140
|
* @example
|
|
182
141
|
* ```typescript
|
|
183
142
|
* const api = new RondevuAPI({ baseUrl: 'https://example.com' });
|
|
184
143
|
* const health = await api.health();
|
|
185
144
|
* console.log('Server status:', health.status);
|
|
145
|
+
* console.log('Server version:', health.version);
|
|
186
146
|
* ```
|
|
187
147
|
*/
|
|
188
148
|
async health() {
|
package/dist/connection.d.ts
CHANGED
package/dist/connection.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
export { Rondevu } from './rondevu.js';
|
|
6
6
|
export { RondevuConnection } from './connection.js';
|
|
7
7
|
export { RondevuAPI } from './client.js';
|
|
8
|
-
export type { RondevuOptions,
|
|
8
|
+
export type { RondevuOptions, ConnectionRole, RondevuConnectionParams, RondevuConnectionEvents, WebRTCPolyfill, Side, CreateOfferRequest, CreateOfferResponse, AnswerRequest, AnswerResponse, PollRequest, PollOffererResponse, PollAnswererResponse, PollResponse, VersionResponse, HealthResponse, ErrorResponse, RondevuClientOptions, } from './types.js';
|
package/dist/rondevu.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RondevuAPI } from './client.js';
|
|
2
2
|
import { RondevuConnection } from './connection.js';
|
|
3
|
-
import { RondevuOptions
|
|
3
|
+
import { RondevuOptions } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Main Rondevu WebRTC client with automatic connection management
|
|
6
6
|
*/
|
|
@@ -20,6 +20,15 @@ export declare class Rondevu {
|
|
|
20
20
|
* @param options - Client configuration options
|
|
21
21
|
*/
|
|
22
22
|
constructor(options?: RondevuOptions);
|
|
23
|
+
/**
|
|
24
|
+
* Check server version compatibility
|
|
25
|
+
*/
|
|
26
|
+
private checkServerVersion;
|
|
27
|
+
/**
|
|
28
|
+
* Check if client and server versions are compatible
|
|
29
|
+
* For now, just check major version compatibility
|
|
30
|
+
*/
|
|
31
|
+
private isVersionCompatible;
|
|
23
32
|
/**
|
|
24
33
|
* Generate a unique peer ID
|
|
25
34
|
*/
|
|
@@ -30,35 +39,22 @@ export declare class Rondevu {
|
|
|
30
39
|
updatePeerId(newPeerId: string): void;
|
|
31
40
|
/**
|
|
32
41
|
* Create a new connection (offerer role)
|
|
33
|
-
* @param id - Connection identifier
|
|
34
|
-
* @param topic - Topic name for grouping connections
|
|
42
|
+
* @param id - Connection identifier (custom code)
|
|
35
43
|
* @returns Promise that resolves to RondevuConnection
|
|
36
44
|
*/
|
|
37
|
-
create(id: string
|
|
45
|
+
create(id: string): Promise<RondevuConnection>;
|
|
38
46
|
/**
|
|
39
|
-
* Connect to an existing
|
|
40
|
-
* @param id -
|
|
47
|
+
* Connect to an existing offer by ID (answerer role)
|
|
48
|
+
* @param id - Offer code
|
|
41
49
|
* @returns Promise that resolves to RondevuConnection
|
|
42
50
|
*/
|
|
43
51
|
connect(id: string): Promise<RondevuConnection>;
|
|
44
|
-
/**
|
|
45
|
-
* Join a topic and discover available peers (answerer role)
|
|
46
|
-
* @param topic - Topic name
|
|
47
|
-
* @param options - Optional join options for filtering and selection
|
|
48
|
-
* @returns Promise that resolves to RondevuConnection
|
|
49
|
-
*/
|
|
50
|
-
join(topic: string, options?: JoinOptions): Promise<RondevuConnection>;
|
|
51
|
-
/**
|
|
52
|
-
* Select a session based on strategy
|
|
53
|
-
*/
|
|
54
|
-
private selectSession;
|
|
55
52
|
/**
|
|
56
53
|
* Wait for ICE gathering to complete
|
|
57
54
|
*/
|
|
58
55
|
private waitForIceGathering;
|
|
59
56
|
/**
|
|
60
|
-
* Find
|
|
61
|
-
* This requires polling since we don't know which topic it's in
|
|
57
|
+
* Find an offer by code
|
|
62
58
|
*/
|
|
63
|
-
private
|
|
59
|
+
private findOfferById;
|
|
64
60
|
}
|
package/dist/rondevu.js
CHANGED
|
@@ -29,6 +29,37 @@ export class Rondevu {
|
|
|
29
29
|
'In Node.js, provide a WebRTC polyfill via the wrtc option. ' +
|
|
30
30
|
'Install: npm install @roamhq/wrtc or npm install wrtc');
|
|
31
31
|
}
|
|
32
|
+
// Check server version compatibility (async, don't block constructor)
|
|
33
|
+
this.checkServerVersion().catch(() => {
|
|
34
|
+
// Silently fail version check - connection will work even if version check fails
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check server version compatibility
|
|
39
|
+
*/
|
|
40
|
+
async checkServerVersion() {
|
|
41
|
+
try {
|
|
42
|
+
const { version: serverVersion } = await this.api.health();
|
|
43
|
+
const clientVersion = '0.3.2'; // Should match package.json
|
|
44
|
+
if (!this.isVersionCompatible(clientVersion, serverVersion)) {
|
|
45
|
+
console.warn(`[Rondevu] Version mismatch: client v${clientVersion}, server v${serverVersion}. ` +
|
|
46
|
+
'This may cause compatibility issues.');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// Version check failed - server might not support /health endpoint
|
|
51
|
+
console.debug('[Rondevu] Could not check server version');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if client and server versions are compatible
|
|
56
|
+
* For now, just check major version compatibility
|
|
57
|
+
*/
|
|
58
|
+
isVersionCompatible(clientVersion, serverVersion) {
|
|
59
|
+
const clientMajor = parseInt(clientVersion.split('.')[0]);
|
|
60
|
+
const serverMajor = parseInt(serverVersion.split('.')[0]);
|
|
61
|
+
// Major versions must match
|
|
62
|
+
return clientMajor === serverMajor;
|
|
32
63
|
}
|
|
33
64
|
/**
|
|
34
65
|
* Generate a unique peer ID
|
|
@@ -44,11 +75,10 @@ export class Rondevu {
|
|
|
44
75
|
}
|
|
45
76
|
/**
|
|
46
77
|
* Create a new connection (offerer role)
|
|
47
|
-
* @param id - Connection identifier
|
|
48
|
-
* @param topic - Topic name for grouping connections
|
|
78
|
+
* @param id - Connection identifier (custom code)
|
|
49
79
|
* @returns Promise that resolves to RondevuConnection
|
|
50
80
|
*/
|
|
51
|
-
async create(id
|
|
81
|
+
async create(id) {
|
|
52
82
|
// Create peer connection
|
|
53
83
|
const pc = new this.RTCPeerConnection(this.rtcConfig);
|
|
54
84
|
// Create initial data channel for negotiation (required for offer creation)
|
|
@@ -58,8 +88,8 @@ export class Rondevu {
|
|
|
58
88
|
await pc.setLocalDescription(offer);
|
|
59
89
|
// Wait for ICE gathering to complete
|
|
60
90
|
await this.waitForIceGathering(pc);
|
|
61
|
-
// Create
|
|
62
|
-
await this.api.createOffer(
|
|
91
|
+
// Create offer on server with custom code
|
|
92
|
+
await this.api.createOffer({
|
|
63
93
|
peerId: this.peerId,
|
|
64
94
|
offer: pc.localDescription.sdp,
|
|
65
95
|
code: id,
|
|
@@ -67,7 +97,6 @@ export class Rondevu {
|
|
|
67
97
|
// Create connection object
|
|
68
98
|
const connectionParams = {
|
|
69
99
|
id,
|
|
70
|
-
topic,
|
|
71
100
|
role: 'offerer',
|
|
72
101
|
pc,
|
|
73
102
|
localPeerId: this.peerId,
|
|
@@ -82,22 +111,22 @@ export class Rondevu {
|
|
|
82
111
|
return connection;
|
|
83
112
|
}
|
|
84
113
|
/**
|
|
85
|
-
* Connect to an existing
|
|
86
|
-
* @param id -
|
|
114
|
+
* Connect to an existing offer by ID (answerer role)
|
|
115
|
+
* @param id - Offer code
|
|
87
116
|
* @returns Promise that resolves to RondevuConnection
|
|
88
117
|
*/
|
|
89
118
|
async connect(id) {
|
|
90
|
-
// Poll server to get
|
|
91
|
-
const
|
|
92
|
-
if (!
|
|
93
|
-
throw new Error(`
|
|
119
|
+
// Poll server to get offer by ID
|
|
120
|
+
const offerData = await this.findOfferById(id);
|
|
121
|
+
if (!offerData) {
|
|
122
|
+
throw new Error(`Offer ${id} not found or expired`);
|
|
94
123
|
}
|
|
95
124
|
// Create peer connection
|
|
96
125
|
const pc = new this.RTCPeerConnection(this.rtcConfig);
|
|
97
126
|
// Set remote offer
|
|
98
127
|
await pc.setRemoteDescription({
|
|
99
128
|
type: 'offer',
|
|
100
|
-
sdp:
|
|
129
|
+
sdp: offerData.offer,
|
|
101
130
|
});
|
|
102
131
|
// Generate answer
|
|
103
132
|
const answer = await pc.createAnswer();
|
|
@@ -113,11 +142,10 @@ export class Rondevu {
|
|
|
113
142
|
// Create connection object
|
|
114
143
|
const connectionParams = {
|
|
115
144
|
id,
|
|
116
|
-
topic: sessionData.topic || 'unknown',
|
|
117
145
|
role: 'answerer',
|
|
118
146
|
pc,
|
|
119
147
|
localPeerId: this.peerId,
|
|
120
|
-
remotePeerId:
|
|
148
|
+
remotePeerId: '', // Will be determined from peerId in offer
|
|
121
149
|
pollingInterval: this.pollingInterval,
|
|
122
150
|
connectionTimeout: this.connectionTimeout,
|
|
123
151
|
wrtc: this.wrtc,
|
|
@@ -127,46 +155,6 @@ export class Rondevu {
|
|
|
127
155
|
connection.startPolling();
|
|
128
156
|
return connection;
|
|
129
157
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Join a topic and discover available peers (answerer role)
|
|
132
|
-
* @param topic - Topic name
|
|
133
|
-
* @param options - Optional join options for filtering and selection
|
|
134
|
-
* @returns Promise that resolves to RondevuConnection
|
|
135
|
-
*/
|
|
136
|
-
async join(topic, options) {
|
|
137
|
-
// List sessions in topic
|
|
138
|
-
const { sessions } = await this.api.listSessions(topic);
|
|
139
|
-
// Filter out self (sessions with our peer ID)
|
|
140
|
-
let availableSessions = sessions.filter(session => session.peerId !== this.peerId);
|
|
141
|
-
// Apply custom filter if provided
|
|
142
|
-
if (options?.filter) {
|
|
143
|
-
availableSessions = availableSessions.filter(options.filter);
|
|
144
|
-
}
|
|
145
|
-
if (availableSessions.length === 0) {
|
|
146
|
-
throw new Error(`No available peers in topic: ${topic}`);
|
|
147
|
-
}
|
|
148
|
-
// Select session based on strategy
|
|
149
|
-
const selectedSession = this.selectSession(availableSessions, options?.select || 'first');
|
|
150
|
-
// Connect to selected session
|
|
151
|
-
return this.connect(selectedSession.code);
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Select a session based on strategy
|
|
155
|
-
*/
|
|
156
|
-
selectSession(sessions, strategy) {
|
|
157
|
-
switch (strategy) {
|
|
158
|
-
case 'first':
|
|
159
|
-
return sessions[0];
|
|
160
|
-
case 'newest':
|
|
161
|
-
return sessions.reduce((newest, session) => session.createdAt > newest.createdAt ? session : newest);
|
|
162
|
-
case 'oldest':
|
|
163
|
-
return sessions.reduce((oldest, session) => session.createdAt < oldest.createdAt ? session : oldest);
|
|
164
|
-
case 'random':
|
|
165
|
-
return sessions[Math.floor(Math.random() * sessions.length)];
|
|
166
|
-
default:
|
|
167
|
-
return sessions[0];
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
158
|
/**
|
|
171
159
|
* Wait for ICE gathering to complete
|
|
172
160
|
*/
|
|
@@ -190,27 +178,22 @@ export class Rondevu {
|
|
|
190
178
|
});
|
|
191
179
|
}
|
|
192
180
|
/**
|
|
193
|
-
* Find
|
|
194
|
-
* This requires polling since we don't know which topic it's in
|
|
181
|
+
* Find an offer by code
|
|
195
182
|
*/
|
|
196
|
-
async
|
|
183
|
+
async findOfferById(id) {
|
|
197
184
|
try {
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
const response = await client.poll(id, 'answerer');
|
|
185
|
+
// Poll for the offer directly
|
|
186
|
+
const response = await this.api.poll(id, 'answerer');
|
|
201
187
|
const answererResponse = response;
|
|
202
188
|
if (answererResponse.offer) {
|
|
203
189
|
return {
|
|
204
|
-
code: id,
|
|
205
|
-
peerId: '', // Will be populated from session data
|
|
206
190
|
offer: answererResponse.offer,
|
|
207
|
-
topic: undefined,
|
|
208
191
|
};
|
|
209
192
|
}
|
|
210
193
|
return null;
|
|
211
194
|
}
|
|
212
195
|
catch (err) {
|
|
213
|
-
throw new Error(`Failed to find
|
|
196
|
+
throw new Error(`Failed to find offer ${id}: ${err.message}`);
|
|
214
197
|
}
|
|
215
198
|
}
|
|
216
199
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,59 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type Side = 'offerer' | 'answerer';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
export interface Session {
|
|
9
|
-
/** Unique session identifier (UUID) */
|
|
10
|
-
code: string;
|
|
11
|
-
/** Peer identifier/metadata */
|
|
12
|
-
peerId: string;
|
|
13
|
-
/** Signaling data for peer connection */
|
|
14
|
-
offer: string;
|
|
15
|
-
/** Additional signaling data from offerer */
|
|
16
|
-
offerCandidates: string[];
|
|
17
|
-
/** Unix timestamp when session was created */
|
|
18
|
-
createdAt: number;
|
|
19
|
-
/** Unix timestamp when session expires */
|
|
20
|
-
expiresAt: number;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Topic information with peer count
|
|
24
|
-
*/
|
|
25
|
-
export interface TopicInfo {
|
|
26
|
-
/** Topic identifier */
|
|
27
|
-
topic: string;
|
|
28
|
-
/** Number of available peers in this topic */
|
|
29
|
-
count: number;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Pagination information
|
|
33
|
-
*/
|
|
34
|
-
export interface Pagination {
|
|
35
|
-
/** Current page number */
|
|
36
|
-
page: number;
|
|
37
|
-
/** Results per page */
|
|
38
|
-
limit: number;
|
|
39
|
-
/** Total number of results */
|
|
40
|
-
total: number;
|
|
41
|
-
/** Whether there are more results available */
|
|
42
|
-
hasMore: boolean;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Response from GET / - list all topics
|
|
46
|
-
*/
|
|
47
|
-
export interface ListTopicsResponse {
|
|
48
|
-
topics: TopicInfo[];
|
|
49
|
-
pagination: Pagination;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Response from GET /:topic/sessions - list sessions in a topic
|
|
53
|
-
*/
|
|
54
|
-
export interface ListSessionsResponse {
|
|
55
|
-
sessions: Session[];
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Request body for POST /:topic/offer
|
|
6
|
+
* Request body for POST /offer
|
|
59
7
|
*/
|
|
60
8
|
export interface CreateOfferRequest {
|
|
61
9
|
/** Peer identifier/metadata (max 1024 characters) */
|
|
@@ -66,7 +14,7 @@ export interface CreateOfferRequest {
|
|
|
66
14
|
code?: string;
|
|
67
15
|
}
|
|
68
16
|
/**
|
|
69
|
-
* Response from POST
|
|
17
|
+
* Response from POST /offer
|
|
70
18
|
*/
|
|
71
19
|
export interface CreateOfferResponse {
|
|
72
20
|
/** Unique session identifier (UUID) */
|
|
@@ -135,6 +83,7 @@ export interface VersionResponse {
|
|
|
135
83
|
export interface HealthResponse {
|
|
136
84
|
status: 'ok';
|
|
137
85
|
timestamp: number;
|
|
86
|
+
version: string;
|
|
138
87
|
}
|
|
139
88
|
/**
|
|
140
89
|
* Error response structure
|
|
@@ -178,18 +127,6 @@ export interface RondevuOptions {
|
|
|
178
127
|
/** WebRTC polyfill for Node.js (e.g., wrtc or @roamhq/wrtc) */
|
|
179
128
|
wrtc?: WebRTCPolyfill;
|
|
180
129
|
}
|
|
181
|
-
/**
|
|
182
|
-
* Options for joining a topic
|
|
183
|
-
*/
|
|
184
|
-
export interface JoinOptions {
|
|
185
|
-
/** Filter function to select specific sessions */
|
|
186
|
-
filter?: (session: {
|
|
187
|
-
code: string;
|
|
188
|
-
peerId: string;
|
|
189
|
-
}) => boolean;
|
|
190
|
-
/** Selection strategy for choosing a session */
|
|
191
|
-
select?: 'first' | 'newest' | 'oldest' | 'random';
|
|
192
|
-
}
|
|
193
130
|
/**
|
|
194
131
|
* Connection role - whether this peer is creating or answering
|
|
195
132
|
*/
|
|
@@ -199,7 +136,7 @@ export type ConnectionRole = 'offerer' | 'answerer';
|
|
|
199
136
|
*/
|
|
200
137
|
export interface RondevuConnectionParams {
|
|
201
138
|
id: string;
|
|
202
|
-
topic
|
|
139
|
+
topic?: string;
|
|
203
140
|
role: ConnectionRole;
|
|
204
141
|
pc: RTCPeerConnection;
|
|
205
142
|
localPeerId: string;
|