@xtr-dev/rondevu-client 0.12.4 → 0.17.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 +100 -381
- package/dist/api.d.ts +75 -96
- package/dist/api.js +202 -243
- package/dist/crypto-adapter.d.ts +37 -0
- package/dist/crypto-adapter.js +4 -0
- package/dist/index.d.ts +8 -15
- package/dist/index.js +5 -8
- package/dist/node-crypto-adapter.d.ts +35 -0
- package/dist/node-crypto-adapter.js +80 -0
- package/dist/rondevu-signaler.d.ts +14 -12
- package/dist/rondevu-signaler.js +111 -95
- package/dist/rondevu.d.ts +329 -0
- package/dist/rondevu.js +648 -0
- package/dist/rpc-batcher.d.ts +61 -0
- package/dist/rpc-batcher.js +111 -0
- package/dist/types.d.ts +8 -21
- package/dist/types.js +4 -6
- package/dist/web-crypto-adapter.d.ts +16 -0
- package/dist/web-crypto-adapter.js +52 -0
- package/package.json +1 -1
- package/dist/bin.d.ts +0 -35
- package/dist/bin.js +0 -35
- package/dist/connection-manager.d.ts +0 -104
- package/dist/connection-manager.js +0 -324
- package/dist/connection.d.ts +0 -112
- package/dist/connection.js +0 -194
- package/dist/durable-connection.d.ts +0 -120
- package/dist/durable-connection.js +0 -244
- package/dist/event-bus.d.ts +0 -52
- package/dist/event-bus.js +0 -84
- package/dist/noop-signaler.d.ts +0 -14
- package/dist/noop-signaler.js +0 -27
- package/dist/quick-start.d.ts +0 -29
- package/dist/quick-start.js +0 -44
- package/dist/rondevu-context.d.ts +0 -10
- package/dist/rondevu-context.js +0 -20
- package/dist/rondevu-service.d.ts +0 -87
- package/dist/rondevu-service.js +0 -170
- package/dist/service-client.d.ts +0 -77
- package/dist/service-client.js +0 -158
- package/dist/service-host.d.ts +0 -67
- package/dist/service-host.js +0 -120
- package/dist/signaler.d.ts +0 -25
- package/dist/signaler.js +0 -89
- package/dist/webrtc-context.d.ts +0 -5
- package/dist/webrtc-context.js +0 -35
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { ConnectionEvents, ConnectionInterface, Message, QueueMessageOptions, Signaler } from './types.js';
|
|
2
|
-
import { EventBus } from './event-bus.js';
|
|
3
|
-
import { WebRTCContext } from './webrtc-context';
|
|
4
|
-
export type WebRTCRondevuConnectionOptions = {
|
|
5
|
-
offer?: RTCSessionDescriptionInit | null;
|
|
6
|
-
context: WebRTCContext;
|
|
7
|
-
signaler: Signaler;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* WebRTCRondevuConnection - WebRTC peer connection wrapper with Rondevu signaling
|
|
11
|
-
*
|
|
12
|
-
* Manages a WebRTC peer connection lifecycle including:
|
|
13
|
-
* - Automatic offer/answer creation based on role
|
|
14
|
-
* - ICE candidate exchange via Rondevu signaling server
|
|
15
|
-
* - Connection state management with type-safe events
|
|
16
|
-
* - Data channel creation and message handling
|
|
17
|
-
*
|
|
18
|
-
* The connection automatically determines its role (offerer or answerer) based on whether
|
|
19
|
-
* an offer is provided in the constructor. The offerer creates the data channel, while
|
|
20
|
-
* the answerer receives it via the 'datachannel' event.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```typescript
|
|
24
|
-
* // Offerer side (creates offer)
|
|
25
|
-
* const connection = new WebRTCRondevuConnection(
|
|
26
|
-
* 'conn-123',
|
|
27
|
-
* 'peer-username',
|
|
28
|
-
* 'chat.service@1.0.0'
|
|
29
|
-
* );
|
|
30
|
-
*
|
|
31
|
-
* await connection.ready; // Wait for local offer
|
|
32
|
-
* const sdp = connection.connection.localDescription!.sdp!;
|
|
33
|
-
* // Send sdp to signaling server...
|
|
34
|
-
*
|
|
35
|
-
* // Answerer side (receives offer)
|
|
36
|
-
* const connection = new WebRTCRondevuConnection(
|
|
37
|
-
* 'conn-123',
|
|
38
|
-
* 'peer-username',
|
|
39
|
-
* 'chat.service@1.0.0',
|
|
40
|
-
* { type: 'offer', sdp: remoteOfferSdp }
|
|
41
|
-
* );
|
|
42
|
-
*
|
|
43
|
-
* await connection.ready; // Wait for local answer
|
|
44
|
-
* const answerSdp = connection.connection.localDescription!.sdp!;
|
|
45
|
-
* // Send answer to signaling server...
|
|
46
|
-
*
|
|
47
|
-
* // Both sides: Set up signaler and listen for state changes
|
|
48
|
-
* connection.setSignaler(signaler);
|
|
49
|
-
* connection.events.on('state-change', (state) => {
|
|
50
|
-
* console.log('Connection state:', state);
|
|
51
|
-
* });
|
|
52
|
-
* ```
|
|
53
|
-
*/
|
|
54
|
-
export declare class RTCDurableConnection implements ConnectionInterface {
|
|
55
|
-
private readonly side;
|
|
56
|
-
readonly expiresAt: number;
|
|
57
|
-
readonly lastActive: number;
|
|
58
|
-
readonly events: EventBus<ConnectionEvents>;
|
|
59
|
-
readonly ready: Promise<void>;
|
|
60
|
-
private iceBin;
|
|
61
|
-
private context;
|
|
62
|
-
private readonly signaler;
|
|
63
|
-
private _conn;
|
|
64
|
-
private _state;
|
|
65
|
-
private _dataChannel;
|
|
66
|
-
private messageQueue;
|
|
67
|
-
constructor({ context, offer, signaler }: WebRTCRondevuConnectionOptions);
|
|
68
|
-
/**
|
|
69
|
-
* Getter method for retrieving the current connection.
|
|
70
|
-
*
|
|
71
|
-
* @return {RTCPeerConnection|null} The current connection instance.
|
|
72
|
-
*/
|
|
73
|
-
get connection(): RTCPeerConnection | null;
|
|
74
|
-
/**
|
|
75
|
-
* Update connection state and emit state-change event
|
|
76
|
-
*/
|
|
77
|
-
private setState;
|
|
78
|
-
/**
|
|
79
|
-
* Start ICE candidate exchange when gathering begins
|
|
80
|
-
*/
|
|
81
|
-
private startIce;
|
|
82
|
-
/**
|
|
83
|
-
* Stop ICE candidate exchange when gathering completes
|
|
84
|
-
*/
|
|
85
|
-
private stopIce;
|
|
86
|
-
/**
|
|
87
|
-
* Disconnects the current connection and cleans up resources.
|
|
88
|
-
* Closes the active connection if it exists, resets the connection instance to null,
|
|
89
|
-
* stops the ICE process, and updates the state to 'disconnected'.
|
|
90
|
-
*
|
|
91
|
-
* @return {void} No return value.
|
|
92
|
-
*/
|
|
93
|
-
disconnect(): void;
|
|
94
|
-
/**
|
|
95
|
-
* Current connection state
|
|
96
|
-
*/
|
|
97
|
-
get state(): "connected" | "disconnected" | "connecting";
|
|
98
|
-
/**
|
|
99
|
-
* Setup data channel event listeners
|
|
100
|
-
*/
|
|
101
|
-
private setupDataChannelListeners;
|
|
102
|
-
/**
|
|
103
|
-
* Flush the message queue
|
|
104
|
-
*/
|
|
105
|
-
private flushQueue;
|
|
106
|
-
/**
|
|
107
|
-
* Queue a message for sending when connection is established
|
|
108
|
-
*
|
|
109
|
-
* @param message - Message to queue (string or ArrayBuffer)
|
|
110
|
-
* @param options - Queue options (e.g., expiration time)
|
|
111
|
-
*/
|
|
112
|
-
queueMessage(message: Message, options?: QueueMessageOptions): Promise<void>;
|
|
113
|
-
/**
|
|
114
|
-
* Send a message immediately
|
|
115
|
-
*
|
|
116
|
-
* @param message - Message to send (string or ArrayBuffer)
|
|
117
|
-
* @returns Promise resolving to true if sent successfully
|
|
118
|
-
*/
|
|
119
|
-
sendMessage(message: Message): Promise<boolean>;
|
|
120
|
-
}
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import { isConnectionState, } from './types.js';
|
|
2
|
-
import { EventBus } from './event-bus.js';
|
|
3
|
-
import { createBin } from './bin.js';
|
|
4
|
-
/**
|
|
5
|
-
* WebRTCRondevuConnection - WebRTC peer connection wrapper with Rondevu signaling
|
|
6
|
-
*
|
|
7
|
-
* Manages a WebRTC peer connection lifecycle including:
|
|
8
|
-
* - Automatic offer/answer creation based on role
|
|
9
|
-
* - ICE candidate exchange via Rondevu signaling server
|
|
10
|
-
* - Connection state management with type-safe events
|
|
11
|
-
* - Data channel creation and message handling
|
|
12
|
-
*
|
|
13
|
-
* The connection automatically determines its role (offerer or answerer) based on whether
|
|
14
|
-
* an offer is provided in the constructor. The offerer creates the data channel, while
|
|
15
|
-
* the answerer receives it via the 'datachannel' event.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* // Offerer side (creates offer)
|
|
20
|
-
* const connection = new WebRTCRondevuConnection(
|
|
21
|
-
* 'conn-123',
|
|
22
|
-
* 'peer-username',
|
|
23
|
-
* 'chat.service@1.0.0'
|
|
24
|
-
* );
|
|
25
|
-
*
|
|
26
|
-
* await connection.ready; // Wait for local offer
|
|
27
|
-
* const sdp = connection.connection.localDescription!.sdp!;
|
|
28
|
-
* // Send sdp to signaling server...
|
|
29
|
-
*
|
|
30
|
-
* // Answerer side (receives offer)
|
|
31
|
-
* const connection = new WebRTCRondevuConnection(
|
|
32
|
-
* 'conn-123',
|
|
33
|
-
* 'peer-username',
|
|
34
|
-
* 'chat.service@1.0.0',
|
|
35
|
-
* { type: 'offer', sdp: remoteOfferSdp }
|
|
36
|
-
* );
|
|
37
|
-
*
|
|
38
|
-
* await connection.ready; // Wait for local answer
|
|
39
|
-
* const answerSdp = connection.connection.localDescription!.sdp!;
|
|
40
|
-
* // Send answer to signaling server...
|
|
41
|
-
*
|
|
42
|
-
* // Both sides: Set up signaler and listen for state changes
|
|
43
|
-
* connection.setSignaler(signaler);
|
|
44
|
-
* connection.events.on('state-change', (state) => {
|
|
45
|
-
* console.log('Connection state:', state);
|
|
46
|
-
* });
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
|
-
export class RTCDurableConnection {
|
|
50
|
-
constructor({ context, offer, signaler }) {
|
|
51
|
-
this.expiresAt = 0;
|
|
52
|
-
this.lastActive = 0;
|
|
53
|
-
this.events = new EventBus();
|
|
54
|
-
this.iceBin = createBin();
|
|
55
|
-
this._conn = null;
|
|
56
|
-
this._state = 'disconnected';
|
|
57
|
-
this._dataChannel = null;
|
|
58
|
-
this.messageQueue = [];
|
|
59
|
-
this.context = context;
|
|
60
|
-
this.signaler = signaler;
|
|
61
|
-
this._conn = context.createPeerConnection();
|
|
62
|
-
this.side = offer ? 'answer' : 'offer';
|
|
63
|
-
// setup data channel
|
|
64
|
-
if (offer) {
|
|
65
|
-
this._conn.addEventListener('datachannel', e => {
|
|
66
|
-
this._dataChannel = e.channel;
|
|
67
|
-
this.setupDataChannelListeners(this._dataChannel);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
this._dataChannel = this._conn.createDataChannel('vu.ronde.protocol');
|
|
72
|
-
this.setupDataChannelListeners(this._dataChannel);
|
|
73
|
-
}
|
|
74
|
-
// setup description exchange
|
|
75
|
-
this.ready = offer
|
|
76
|
-
? this._conn
|
|
77
|
-
.setRemoteDescription(offer)
|
|
78
|
-
.then(() => this._conn?.createAnswer())
|
|
79
|
-
.then(async (answer) => {
|
|
80
|
-
if (!answer || !this._conn)
|
|
81
|
-
throw new Error('Connection disappeared');
|
|
82
|
-
await this._conn.setLocalDescription(answer);
|
|
83
|
-
return await signaler.setAnswer(answer);
|
|
84
|
-
})
|
|
85
|
-
: this._conn.createOffer().then(async (offer) => {
|
|
86
|
-
if (!this._conn)
|
|
87
|
-
throw new Error('Connection disappeared');
|
|
88
|
-
await this._conn.setLocalDescription(offer);
|
|
89
|
-
return await signaler.setOffer(offer);
|
|
90
|
-
});
|
|
91
|
-
// propagate connection state changes
|
|
92
|
-
this._conn.addEventListener('connectionstatechange', () => {
|
|
93
|
-
console.log(this.side, 'connection state changed: ', this._conn.connectionState);
|
|
94
|
-
const state = isConnectionState(this._conn.connectionState)
|
|
95
|
-
? this._conn.connectionState
|
|
96
|
-
: 'disconnected';
|
|
97
|
-
this.setState(state);
|
|
98
|
-
});
|
|
99
|
-
this._conn.addEventListener('iceconnectionstatechange', () => {
|
|
100
|
-
console.log(this.side, 'ice connection state changed: ', this._conn.iceConnectionState);
|
|
101
|
-
});
|
|
102
|
-
// start ICE candidate exchange when gathering begins
|
|
103
|
-
this._conn.addEventListener('icegatheringstatechange', () => {
|
|
104
|
-
if (this._conn.iceGatheringState === 'gathering') {
|
|
105
|
-
this.startIce();
|
|
106
|
-
}
|
|
107
|
-
else if (this._conn.iceGatheringState === 'complete') {
|
|
108
|
-
this.stopIce();
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Getter method for retrieving the current connection.
|
|
114
|
-
*
|
|
115
|
-
* @return {RTCPeerConnection|null} The current connection instance.
|
|
116
|
-
*/
|
|
117
|
-
get connection() {
|
|
118
|
-
return this._conn;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Update connection state and emit state-change event
|
|
122
|
-
*/
|
|
123
|
-
setState(state) {
|
|
124
|
-
this._state = state;
|
|
125
|
-
this.events.emit('state-change', state);
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Start ICE candidate exchange when gathering begins
|
|
129
|
-
*/
|
|
130
|
-
startIce() {
|
|
131
|
-
const listener = ({ candidate }) => {
|
|
132
|
-
if (candidate)
|
|
133
|
-
this.signaler.addIceCandidate(candidate);
|
|
134
|
-
};
|
|
135
|
-
if (!this._conn)
|
|
136
|
-
throw new Error('Connection disappeared');
|
|
137
|
-
this._conn.addEventListener('icecandidate', listener);
|
|
138
|
-
this.iceBin(this.signaler.addListener((candidate) => this._conn?.addIceCandidate(candidate)), () => this._conn?.removeEventListener('icecandidate', listener));
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Stop ICE candidate exchange when gathering completes
|
|
142
|
-
*/
|
|
143
|
-
stopIce() {
|
|
144
|
-
this.iceBin.clean();
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Disconnects the current connection and cleans up resources.
|
|
148
|
-
* Closes the active connection if it exists, resets the connection instance to null,
|
|
149
|
-
* stops the ICE process, and updates the state to 'disconnected'.
|
|
150
|
-
*
|
|
151
|
-
* @return {void} No return value.
|
|
152
|
-
*/
|
|
153
|
-
disconnect() {
|
|
154
|
-
this._conn?.close();
|
|
155
|
-
this._conn = null;
|
|
156
|
-
this.stopIce();
|
|
157
|
-
this.setState('disconnected');
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Current connection state
|
|
161
|
-
*/
|
|
162
|
-
get state() {
|
|
163
|
-
return this._state;
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Setup data channel event listeners
|
|
167
|
-
*/
|
|
168
|
-
setupDataChannelListeners(channel) {
|
|
169
|
-
channel.addEventListener('message', e => {
|
|
170
|
-
this.events.emit('message', e.data);
|
|
171
|
-
});
|
|
172
|
-
channel.addEventListener('open', () => {
|
|
173
|
-
// Channel opened - flush queued messages
|
|
174
|
-
this.flushQueue().catch(err => {
|
|
175
|
-
console.error('Failed to flush message queue:', err);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
channel.addEventListener('error', err => {
|
|
179
|
-
console.error('Data channel error:', err);
|
|
180
|
-
});
|
|
181
|
-
channel.addEventListener('close', () => {
|
|
182
|
-
console.log('Data channel closed');
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Flush the message queue
|
|
187
|
-
*/
|
|
188
|
-
async flushQueue() {
|
|
189
|
-
while (this.messageQueue.length > 0 && this._state === 'connected') {
|
|
190
|
-
const item = this.messageQueue.shift();
|
|
191
|
-
// Check expiration
|
|
192
|
-
if (item.options.expiresAt && Date.now() > item.options.expiresAt) {
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
const success = await this.sendMessage(item.message);
|
|
196
|
-
if (!success) {
|
|
197
|
-
// Re-queue on failure
|
|
198
|
-
this.messageQueue.unshift(item);
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Queue a message for sending when connection is established
|
|
205
|
-
*
|
|
206
|
-
* @param message - Message to queue (string or ArrayBuffer)
|
|
207
|
-
* @param options - Queue options (e.g., expiration time)
|
|
208
|
-
*/
|
|
209
|
-
async queueMessage(message, options = {}) {
|
|
210
|
-
this.messageQueue.push({
|
|
211
|
-
message,
|
|
212
|
-
options,
|
|
213
|
-
timestamp: Date.now()
|
|
214
|
-
});
|
|
215
|
-
// Try immediate send if connected
|
|
216
|
-
if (this._state === 'connected') {
|
|
217
|
-
await this.flushQueue();
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Send a message immediately
|
|
222
|
-
*
|
|
223
|
-
* @param message - Message to send (string or ArrayBuffer)
|
|
224
|
-
* @returns Promise resolving to true if sent successfully
|
|
225
|
-
*/
|
|
226
|
-
async sendMessage(message) {
|
|
227
|
-
if (this._state !== 'connected' || !this._dataChannel) {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
if (this._dataChannel.readyState !== 'open') {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
try {
|
|
234
|
-
// TypeScript has trouble with the union type, so we cast to any
|
|
235
|
-
// Both string and ArrayBuffer are valid for RTCDataChannel.send()
|
|
236
|
-
this._dataChannel.send(message);
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
catch (err) {
|
|
240
|
-
console.error('Send failed:', err);
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
package/dist/event-bus.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type-safe EventBus with event name to payload type mapping
|
|
3
|
-
*/
|
|
4
|
-
type EventHandler<T = any> = (data: T) => void;
|
|
5
|
-
/**
|
|
6
|
-
* EventBus - Type-safe event emitter with inferred event data types
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* interface MyEvents {
|
|
10
|
-
* 'user:connected': { userId: string; timestamp: number };
|
|
11
|
-
* 'user:disconnected': { userId: string };
|
|
12
|
-
* 'message:received': string;
|
|
13
|
-
* }
|
|
14
|
-
*
|
|
15
|
-
* const bus = new EventBus<MyEvents>();
|
|
16
|
-
*
|
|
17
|
-
* // TypeScript knows data is { userId: string; timestamp: number }
|
|
18
|
-
* bus.on('user:connected', (data) => {
|
|
19
|
-
* console.log(data.userId, data.timestamp);
|
|
20
|
-
* });
|
|
21
|
-
*
|
|
22
|
-
* // TypeScript knows data is string
|
|
23
|
-
* bus.on('message:received', (data) => {
|
|
24
|
-
* console.log(data.toUpperCase());
|
|
25
|
-
* });
|
|
26
|
-
*/
|
|
27
|
-
export declare class EventBus<TEvents extends Record<string, any>> {
|
|
28
|
-
private handlers;
|
|
29
|
-
constructor();
|
|
30
|
-
/**
|
|
31
|
-
* Subscribe to an event
|
|
32
|
-
* Returns a cleanup function to unsubscribe
|
|
33
|
-
*/
|
|
34
|
-
on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void;
|
|
35
|
-
/**
|
|
36
|
-
* Subscribe to an event once (auto-unsubscribe after first call)
|
|
37
|
-
*/
|
|
38
|
-
once<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void;
|
|
39
|
-
/**
|
|
40
|
-
* Unsubscribe from an event
|
|
41
|
-
*/
|
|
42
|
-
off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void;
|
|
43
|
-
/**
|
|
44
|
-
* Emit an event with data
|
|
45
|
-
*/
|
|
46
|
-
emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void;
|
|
47
|
-
/**
|
|
48
|
-
* Remove all handlers for a specific event, or all handlers if no event specified
|
|
49
|
-
*/
|
|
50
|
-
clear<K extends keyof TEvents>(event?: K): void;
|
|
51
|
-
}
|
|
52
|
-
export {};
|
package/dist/event-bus.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type-safe EventBus with event name to payload type mapping
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* EventBus - Type-safe event emitter with inferred event data types
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* interface MyEvents {
|
|
9
|
-
* 'user:connected': { userId: string; timestamp: number };
|
|
10
|
-
* 'user:disconnected': { userId: string };
|
|
11
|
-
* 'message:received': string;
|
|
12
|
-
* }
|
|
13
|
-
*
|
|
14
|
-
* const bus = new EventBus<MyEvents>();
|
|
15
|
-
*
|
|
16
|
-
* // TypeScript knows data is { userId: string; timestamp: number }
|
|
17
|
-
* bus.on('user:connected', (data) => {
|
|
18
|
-
* console.log(data.userId, data.timestamp);
|
|
19
|
-
* });
|
|
20
|
-
*
|
|
21
|
-
* // TypeScript knows data is string
|
|
22
|
-
* bus.on('message:received', (data) => {
|
|
23
|
-
* console.log(data.toUpperCase());
|
|
24
|
-
* });
|
|
25
|
-
*/
|
|
26
|
-
export class EventBus {
|
|
27
|
-
constructor() {
|
|
28
|
-
this.handlers = new Map();
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Subscribe to an event
|
|
32
|
-
* Returns a cleanup function to unsubscribe
|
|
33
|
-
*/
|
|
34
|
-
on(event, handler) {
|
|
35
|
-
if (!this.handlers.has(event)) {
|
|
36
|
-
this.handlers.set(event, new Set());
|
|
37
|
-
}
|
|
38
|
-
this.handlers.get(event).add(handler);
|
|
39
|
-
// Return cleanup function
|
|
40
|
-
return () => this.off(event, handler);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Subscribe to an event once (auto-unsubscribe after first call)
|
|
44
|
-
*/
|
|
45
|
-
once(event, handler) {
|
|
46
|
-
const wrappedHandler = (data) => {
|
|
47
|
-
handler(data);
|
|
48
|
-
this.off(event, wrappedHandler);
|
|
49
|
-
};
|
|
50
|
-
this.on(event, wrappedHandler);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Unsubscribe from an event
|
|
54
|
-
*/
|
|
55
|
-
off(event, handler) {
|
|
56
|
-
const eventHandlers = this.handlers.get(event);
|
|
57
|
-
if (eventHandlers) {
|
|
58
|
-
eventHandlers.delete(handler);
|
|
59
|
-
if (eventHandlers.size === 0) {
|
|
60
|
-
this.handlers.delete(event);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Emit an event with data
|
|
66
|
-
*/
|
|
67
|
-
emit(event, data) {
|
|
68
|
-
const eventHandlers = this.handlers.get(event);
|
|
69
|
-
if (eventHandlers) {
|
|
70
|
-
eventHandlers.forEach(handler => handler(data));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Remove all handlers for a specific event, or all handlers if no event specified
|
|
75
|
-
*/
|
|
76
|
-
clear(event) {
|
|
77
|
-
if (event !== undefined) {
|
|
78
|
-
this.handlers.delete(event);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
this.handlers.clear();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
package/dist/noop-signaler.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Signaler } from './types.js';
|
|
2
|
-
import { Binnable } from './bin.js';
|
|
3
|
-
/**
|
|
4
|
-
* NoOpSignaler - A signaler that does nothing
|
|
5
|
-
* Used as a placeholder during connection setup before the real signaler is available
|
|
6
|
-
*/
|
|
7
|
-
export declare class NoOpSignaler implements Signaler {
|
|
8
|
-
addIceCandidate(_candidate: RTCIceCandidate): void;
|
|
9
|
-
addListener(_callback: (candidate: RTCIceCandidate) => void): Binnable;
|
|
10
|
-
addOfferListener(_callback: (offer: RTCSessionDescriptionInit) => void): Binnable;
|
|
11
|
-
addAnswerListener(_callback: (answer: RTCSessionDescriptionInit) => void): Binnable;
|
|
12
|
-
setOffer(_offer: RTCSessionDescriptionInit): Promise<void>;
|
|
13
|
-
setAnswer(_answer: RTCSessionDescriptionInit): Promise<void>;
|
|
14
|
-
}
|
package/dist/noop-signaler.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NoOpSignaler - A signaler that does nothing
|
|
3
|
-
* Used as a placeholder during connection setup before the real signaler is available
|
|
4
|
-
*/
|
|
5
|
-
export class NoOpSignaler {
|
|
6
|
-
addIceCandidate(_candidate) {
|
|
7
|
-
// No-op
|
|
8
|
-
}
|
|
9
|
-
addListener(_callback) {
|
|
10
|
-
// Return no-op cleanup function
|
|
11
|
-
return () => { };
|
|
12
|
-
}
|
|
13
|
-
addOfferListener(_callback) {
|
|
14
|
-
// Return no-op cleanup function
|
|
15
|
-
return () => { };
|
|
16
|
-
}
|
|
17
|
-
addAnswerListener(_callback) {
|
|
18
|
-
// Return no-op cleanup function
|
|
19
|
-
return () => { };
|
|
20
|
-
}
|
|
21
|
-
async setOffer(_offer) {
|
|
22
|
-
// No-op
|
|
23
|
-
}
|
|
24
|
-
async setAnswer(_answer) {
|
|
25
|
-
// No-op
|
|
26
|
-
}
|
|
27
|
-
}
|
package/dist/quick-start.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { RondevuService } from './rondevu-service.js';
|
|
2
|
-
import { Keypair } from './api.js';
|
|
3
|
-
export interface QuickStartOptions {
|
|
4
|
-
apiUrl: string;
|
|
5
|
-
username?: string;
|
|
6
|
-
keypair?: Keypair;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Quick start helper for initializing Rondevu service
|
|
10
|
-
*
|
|
11
|
-
* Simplifies initialization by:
|
|
12
|
-
* - Auto-generating username if not provided
|
|
13
|
-
* - Auto-generating keypair if not provided
|
|
14
|
-
* - Registering with the server
|
|
15
|
-
* - Claiming the username
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* // Simple usage with auto-generated username
|
|
20
|
-
* const service = await quickStart({ apiUrl: 'https://api.ronde.vu' })
|
|
21
|
-
*
|
|
22
|
-
* // With custom username
|
|
23
|
-
* const service = await quickStart({
|
|
24
|
-
* apiUrl: 'https://api.ronde.vu',
|
|
25
|
-
* username: 'my-username'
|
|
26
|
-
* })
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export declare function quickStart(options: QuickStartOptions): Promise<RondevuService>;
|
package/dist/quick-start.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { RondevuService } from './rondevu-service.js';
|
|
2
|
-
/**
|
|
3
|
-
* Quick start helper for initializing Rondevu service
|
|
4
|
-
*
|
|
5
|
-
* Simplifies initialization by:
|
|
6
|
-
* - Auto-generating username if not provided
|
|
7
|
-
* - Auto-generating keypair if not provided
|
|
8
|
-
* - Registering with the server
|
|
9
|
-
* - Claiming the username
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* // Simple usage with auto-generated username
|
|
14
|
-
* const service = await quickStart({ apiUrl: 'https://api.ronde.vu' })
|
|
15
|
-
*
|
|
16
|
-
* // With custom username
|
|
17
|
-
* const service = await quickStart({
|
|
18
|
-
* apiUrl: 'https://api.ronde.vu',
|
|
19
|
-
* username: 'my-username'
|
|
20
|
-
* })
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export async function quickStart(options) {
|
|
24
|
-
// Generate username if not provided
|
|
25
|
-
const username = options.username || `user-${generateId()}`;
|
|
26
|
-
// Create service
|
|
27
|
-
const serviceOptions = {
|
|
28
|
-
apiUrl: options.apiUrl,
|
|
29
|
-
username,
|
|
30
|
-
keypair: options.keypair
|
|
31
|
-
};
|
|
32
|
-
const service = new RondevuService(serviceOptions);
|
|
33
|
-
// Initialize (generates keypair and registers)
|
|
34
|
-
await service.initialize();
|
|
35
|
-
// Claim username
|
|
36
|
-
await service.claimUsername();
|
|
37
|
-
return service;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Generate a random ID
|
|
41
|
-
*/
|
|
42
|
-
function generateId() {
|
|
43
|
-
return Math.random().toString(36).substring(2, 10);
|
|
44
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { RondevuService } from "./rondevu-service";
|
|
2
|
-
import { RTCDurableConnection } from "./durable-connection";
|
|
3
|
-
export declare class RondevuContext {
|
|
4
|
-
readonly rondevu: RondevuService;
|
|
5
|
-
readonly rtcConfig: RTCConfiguration;
|
|
6
|
-
private readonly context;
|
|
7
|
-
private readonly connections;
|
|
8
|
-
constructor(rondevu: RondevuService, rtcConfig: RTCConfiguration);
|
|
9
|
-
createConnection(service: string, host?: string, offer?: RTCSessionDescriptionInit): RTCDurableConnection;
|
|
10
|
-
}
|
package/dist/rondevu-context.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { WebRTCContext } from "./webrtc-context";
|
|
2
|
-
import { RTCDurableConnection } from "./durable-connection";
|
|
3
|
-
import { RondevuSignaler } from "./rondevu-signaler";
|
|
4
|
-
export class RondevuContext {
|
|
5
|
-
constructor(rondevu, rtcConfig) {
|
|
6
|
-
this.rondevu = rondevu;
|
|
7
|
-
this.rtcConfig = rtcConfig;
|
|
8
|
-
this.connections = [];
|
|
9
|
-
this.context = new WebRTCContext(rtcConfig);
|
|
10
|
-
}
|
|
11
|
-
createConnection(service, host, offer) {
|
|
12
|
-
const conn = new RTCDurableConnection({
|
|
13
|
-
context: this.context,
|
|
14
|
-
offer,
|
|
15
|
-
signaler: new RondevuSignaler(this.rondevu, service, host)
|
|
16
|
-
});
|
|
17
|
-
this.connections.push(conn);
|
|
18
|
-
return conn;
|
|
19
|
-
}
|
|
20
|
-
}
|