@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.
Files changed (46) hide show
  1. package/README.md +100 -381
  2. package/dist/api.d.ts +75 -96
  3. package/dist/api.js +202 -243
  4. package/dist/crypto-adapter.d.ts +37 -0
  5. package/dist/crypto-adapter.js +4 -0
  6. package/dist/index.d.ts +8 -15
  7. package/dist/index.js +5 -8
  8. package/dist/node-crypto-adapter.d.ts +35 -0
  9. package/dist/node-crypto-adapter.js +80 -0
  10. package/dist/rondevu-signaler.d.ts +14 -12
  11. package/dist/rondevu-signaler.js +111 -95
  12. package/dist/rondevu.d.ts +329 -0
  13. package/dist/rondevu.js +648 -0
  14. package/dist/rpc-batcher.d.ts +61 -0
  15. package/dist/rpc-batcher.js +111 -0
  16. package/dist/types.d.ts +8 -21
  17. package/dist/types.js +4 -6
  18. package/dist/web-crypto-adapter.d.ts +16 -0
  19. package/dist/web-crypto-adapter.js +52 -0
  20. package/package.json +1 -1
  21. package/dist/bin.d.ts +0 -35
  22. package/dist/bin.js +0 -35
  23. package/dist/connection-manager.d.ts +0 -104
  24. package/dist/connection-manager.js +0 -324
  25. package/dist/connection.d.ts +0 -112
  26. package/dist/connection.js +0 -194
  27. package/dist/durable-connection.d.ts +0 -120
  28. package/dist/durable-connection.js +0 -244
  29. package/dist/event-bus.d.ts +0 -52
  30. package/dist/event-bus.js +0 -84
  31. package/dist/noop-signaler.d.ts +0 -14
  32. package/dist/noop-signaler.js +0 -27
  33. package/dist/quick-start.d.ts +0 -29
  34. package/dist/quick-start.js +0 -44
  35. package/dist/rondevu-context.d.ts +0 -10
  36. package/dist/rondevu-context.js +0 -20
  37. package/dist/rondevu-service.d.ts +0 -87
  38. package/dist/rondevu-service.js +0 -170
  39. package/dist/service-client.d.ts +0 -77
  40. package/dist/service-client.js +0 -158
  41. package/dist/service-host.d.ts +0 -67
  42. package/dist/service-host.js +0 -120
  43. package/dist/signaler.d.ts +0 -25
  44. package/dist/signaler.js +0 -89
  45. package/dist/webrtc-context.d.ts +0 -5
  46. package/dist/webrtc-context.js +0 -35
@@ -0,0 +1,111 @@
1
+ /**
2
+ * RPC Batcher - Throttles and batches RPC requests to reduce HTTP overhead
3
+ */
4
+ /**
5
+ * Batches and throttles RPC requests to optimize network usage
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const batcher = new RpcBatcher(
10
+ * (requests) => api.rpcBatch(requests),
11
+ * { maxBatchSize: 10, maxWaitTime: 50 }
12
+ * )
13
+ *
14
+ * // These will be batched together if called within maxWaitTime
15
+ * const result1 = await batcher.add(request1)
16
+ * const result2 = await batcher.add(request2)
17
+ * const result3 = await batcher.add(request3)
18
+ * ```
19
+ */
20
+ export class RpcBatcher {
21
+ constructor(sendBatch, options) {
22
+ this.queue = [];
23
+ this.batchTimeout = null;
24
+ this.lastBatchTime = 0;
25
+ this.sendBatch = sendBatch;
26
+ this.options = {
27
+ maxBatchSize: options?.maxBatchSize ?? 10,
28
+ maxWaitTime: options?.maxWaitTime ?? 50,
29
+ throttleInterval: options?.throttleInterval ?? 10,
30
+ };
31
+ }
32
+ /**
33
+ * Add an RPC request to the batch queue
34
+ * Returns a promise that resolves when the request completes
35
+ */
36
+ async add(request) {
37
+ return new Promise((resolve, reject) => {
38
+ this.queue.push({ request, resolve, reject });
39
+ // Send immediately if batch is full
40
+ if (this.queue.length >= this.options.maxBatchSize) {
41
+ this.flush();
42
+ return;
43
+ }
44
+ // Schedule batch if not already scheduled
45
+ if (!this.batchTimeout) {
46
+ this.batchTimeout = setTimeout(() => {
47
+ this.flush();
48
+ }, this.options.maxWaitTime);
49
+ }
50
+ });
51
+ }
52
+ /**
53
+ * Flush the queue immediately
54
+ */
55
+ async flush() {
56
+ // Clear timeout if set
57
+ if (this.batchTimeout) {
58
+ clearTimeout(this.batchTimeout);
59
+ this.batchTimeout = null;
60
+ }
61
+ // Nothing to flush
62
+ if (this.queue.length === 0) {
63
+ return;
64
+ }
65
+ // Throttle: wait if we sent a batch too recently
66
+ const now = Date.now();
67
+ const timeSinceLastBatch = now - this.lastBatchTime;
68
+ if (timeSinceLastBatch < this.options.throttleInterval) {
69
+ const waitTime = this.options.throttleInterval - timeSinceLastBatch;
70
+ await new Promise(resolve => setTimeout(resolve, waitTime));
71
+ }
72
+ // Extract requests from queue
73
+ const batch = this.queue.splice(0, this.options.maxBatchSize);
74
+ const requests = batch.map(item => item.request);
75
+ this.lastBatchTime = Date.now();
76
+ try {
77
+ // Send batch request
78
+ const results = await this.sendBatch(requests);
79
+ // Resolve individual promises
80
+ for (let i = 0; i < batch.length; i++) {
81
+ batch[i].resolve(results[i]);
82
+ }
83
+ }
84
+ catch (error) {
85
+ // Reject all promises in batch
86
+ for (const item of batch) {
87
+ item.reject(error);
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Get current queue size
93
+ */
94
+ getQueueSize() {
95
+ return this.queue.length;
96
+ }
97
+ /**
98
+ * Clear the queue without sending
99
+ */
100
+ clear() {
101
+ if (this.batchTimeout) {
102
+ clearTimeout(this.batchTimeout);
103
+ this.batchTimeout = null;
104
+ }
105
+ // Reject all pending requests
106
+ for (const item of this.queue) {
107
+ item.reject(new Error('Batch queue cleared'));
108
+ }
109
+ this.queue = [];
110
+ }
111
+ }
package/dist/types.d.ts CHANGED
@@ -1,26 +1,13 @@
1
1
  /**
2
- * Core connection types
2
+ * Core signaling types
3
+ */
4
+ /**
5
+ * Cleanup function returned by listener methods
6
+ */
7
+ export type Binnable = () => void;
8
+ /**
9
+ * Signaler interface for WebRTC offer/answer/ICE exchange
3
10
  */
4
- import { EventBus } from './event-bus.js';
5
- import { Binnable } from './bin.js';
6
- export type Message = string | ArrayBuffer;
7
- export interface QueueMessageOptions {
8
- expiresAt?: number;
9
- }
10
- export interface ConnectionEvents {
11
- 'state-change': ConnectionInterface['state'];
12
- message: Message;
13
- }
14
- export declare const ConnectionStates: readonly ["connected", "disconnected", "connecting"];
15
- export declare const isConnectionState: (state: string) => state is (typeof ConnectionStates)[number];
16
- export interface ConnectionInterface {
17
- state: (typeof ConnectionStates)[number];
18
- lastActive: number;
19
- expiresAt?: number;
20
- events: EventBus<ConnectionEvents>;
21
- queueMessage(message: Message, options?: QueueMessageOptions): Promise<void>;
22
- sendMessage(message: Message): Promise<boolean>;
23
- }
24
11
  export interface Signaler {
25
12
  addIceCandidate(candidate: RTCIceCandidate): Promise<void>;
26
13
  addListener(callback: (candidate: RTCIceCandidate) => void): Binnable;
package/dist/types.js CHANGED
@@ -1,6 +1,4 @@
1
- export const ConnectionStates = [
2
- 'connected',
3
- 'disconnected',
4
- 'connecting'
5
- ];
6
- export const isConnectionState = (state) => ConnectionStates.includes(state);
1
+ /**
2
+ * Core signaling types
3
+ */
4
+ export {};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Web Crypto adapter for browser environments
3
+ */
4
+ import { CryptoAdapter, Keypair } from './crypto-adapter.js';
5
+ /**
6
+ * Web Crypto implementation using browser APIs
7
+ * Uses btoa/atob for base64 encoding and crypto.getRandomValues for random bytes
8
+ */
9
+ export declare class WebCryptoAdapter implements CryptoAdapter {
10
+ generateKeypair(): Promise<Keypair>;
11
+ signMessage(message: string, privateKeyBase64: string): Promise<string>;
12
+ verifySignature(message: string, signatureBase64: string, publicKeyBase64: string): Promise<boolean>;
13
+ bytesToBase64(bytes: Uint8Array): string;
14
+ base64ToBytes(base64: string): Uint8Array;
15
+ randomBytes(length: number): Uint8Array;
16
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Web Crypto adapter for browser environments
3
+ */
4
+ import * as ed25519 from '@noble/ed25519';
5
+ // Set SHA-512 hash function for ed25519 (required in @noble/ed25519 v3+)
6
+ ed25519.hashes.sha512Async = async (message) => {
7
+ return new Uint8Array(await crypto.subtle.digest('SHA-512', message));
8
+ };
9
+ /**
10
+ * Web Crypto implementation using browser APIs
11
+ * Uses btoa/atob for base64 encoding and crypto.getRandomValues for random bytes
12
+ */
13
+ export class WebCryptoAdapter {
14
+ async generateKeypair() {
15
+ const privateKey = ed25519.utils.randomSecretKey();
16
+ const publicKey = await ed25519.getPublicKeyAsync(privateKey);
17
+ return {
18
+ publicKey: this.bytesToBase64(publicKey),
19
+ privateKey: this.bytesToBase64(privateKey),
20
+ };
21
+ }
22
+ async signMessage(message, privateKeyBase64) {
23
+ const privateKey = this.base64ToBytes(privateKeyBase64);
24
+ const encoder = new TextEncoder();
25
+ const messageBytes = encoder.encode(message);
26
+ const signature = await ed25519.signAsync(messageBytes, privateKey);
27
+ return this.bytesToBase64(signature);
28
+ }
29
+ async verifySignature(message, signatureBase64, publicKeyBase64) {
30
+ try {
31
+ const signature = this.base64ToBytes(signatureBase64);
32
+ const publicKey = this.base64ToBytes(publicKeyBase64);
33
+ const encoder = new TextEncoder();
34
+ const messageBytes = encoder.encode(message);
35
+ return await ed25519.verifyAsync(signature, messageBytes, publicKey);
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }
41
+ bytesToBase64(bytes) {
42
+ const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join('');
43
+ return btoa(binString);
44
+ }
45
+ base64ToBytes(base64) {
46
+ const binString = atob(base64);
47
+ return Uint8Array.from(binString, char => char.codePointAt(0));
48
+ }
49
+ randomBytes(length) {
50
+ return crypto.getRandomValues(new Uint8Array(length));
51
+ }
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtr-dev/rondevu-client",
3
- "version": "0.12.4",
3
+ "version": "0.17.0",
4
4
  "description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/dist/bin.d.ts DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * Binnable - A cleanup function that can be synchronous or asynchronous
3
- *
4
- * Used to unsubscribe from events, close connections, or perform other cleanup operations.
5
- */
6
- export type Binnable = () => void | Promise<void>;
7
- /**
8
- * Create a cleanup function collector (garbage bin)
9
- *
10
- * Collects cleanup functions and provides a single `clean()` method to execute all of them.
11
- * Useful for managing multiple cleanup operations in a single place.
12
- *
13
- * @returns A function that accepts cleanup functions and has a `clean()` method
14
- *
15
- * @example
16
- * ```typescript
17
- * const bin = createBin();
18
- *
19
- * // Add cleanup functions
20
- * bin(
21
- * () => console.log('Cleanup 1'),
22
- * () => connection.close(),
23
- * () => clearInterval(timer)
24
- * );
25
- *
26
- * // Later, clean everything
27
- * bin.clean(); // Executes all cleanup functions
28
- * ```
29
- */
30
- export declare const createBin: () => ((...rubbish: Binnable[]) => number) & {
31
- /**
32
- * Execute all cleanup functions and clear the bin
33
- */
34
- clean: () => void;
35
- };
package/dist/bin.js DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * Create a cleanup function collector (garbage bin)
3
- *
4
- * Collects cleanup functions and provides a single `clean()` method to execute all of them.
5
- * Useful for managing multiple cleanup operations in a single place.
6
- *
7
- * @returns A function that accepts cleanup functions and has a `clean()` method
8
- *
9
- * @example
10
- * ```typescript
11
- * const bin = createBin();
12
- *
13
- * // Add cleanup functions
14
- * bin(
15
- * () => console.log('Cleanup 1'),
16
- * () => connection.close(),
17
- * () => clearInterval(timer)
18
- * );
19
- *
20
- * // Later, clean everything
21
- * bin.clean(); // Executes all cleanup functions
22
- * ```
23
- */
24
- export const createBin = () => {
25
- const bin = [];
26
- return Object.assign((...rubbish) => bin.push(...rubbish), {
27
- /**
28
- * Execute all cleanup functions and clear the bin
29
- */
30
- clean: () => {
31
- bin.forEach(binnable => binnable());
32
- bin.length = 0;
33
- },
34
- });
35
- };
@@ -1,104 +0,0 @@
1
- import { WebRTCRondevuConnection } from './connection.js';
2
- import { Credentials } from './api.js';
3
- import { ConnectionInterface } from './types.js';
4
- export interface ConnectionManagerOptions {
5
- apiUrl: string;
6
- username: string;
7
- credentials?: Credentials;
8
- autoReconnect?: boolean;
9
- reconnectDelay?: number;
10
- maxReconnectAttempts?: number;
11
- }
12
- export interface HostServiceOptions {
13
- service: string;
14
- ttl?: number;
15
- onConnection?: (connection: ConnectionInterface) => void;
16
- }
17
- export interface ConnectToServiceOptions {
18
- username: string;
19
- service: string;
20
- onConnection?: (connection: ConnectionInterface) => void;
21
- }
22
- /**
23
- * ConnectionManager - High-level connection management
24
- *
25
- * @example
26
- * // Host a service
27
- * const manager = new ConnectionManager({
28
- * apiUrl: 'https://api.ronde.vu',
29
- * credentials: await api.register()
30
- * })
31
- *
32
- * await manager.hostService({
33
- * service: 'chat.app@1.0.0',
34
- * onConnection: (conn) => {
35
- * conn.events.on('message', msg => console.log('Received:', msg))
36
- * }
37
- * })
38
- *
39
- * @example
40
- * // Connect to a service
41
- * const connection = await manager.connectToService({
42
- * username: 'alice',
43
- * service: 'chat.app@1.0.0'
44
- * })
45
- *
46
- * await connection.sendMessage('Hello!')
47
- */
48
- export declare class ConnectionManager {
49
- private readonly api;
50
- private readonly username;
51
- private readonly connections;
52
- private readonly autoReconnect;
53
- private readonly reconnectDelay;
54
- private readonly maxReconnectAttempts;
55
- private readonly bin;
56
- constructor(options: ConnectionManagerOptions);
57
- /**
58
- * Host a service - Creates an offer and publishes it to the signaling server
59
- *
60
- * The service will automatically accept incoming connections and manage them.
61
- * Each new connection triggers the onConnection callback.
62
- *
63
- * @param options - Service hosting options
64
- * @returns Promise that resolves when the service is published
65
- */
66
- hostService(options: HostServiceOptions): Promise<void>;
67
- /**
68
- * Connect to a hosted service
69
- *
70
- * Searches for the service, retrieves the offer, and creates an answering connection.
71
- *
72
- * @param options - Connection options
73
- * @returns The established connection
74
- */
75
- connectToService(options: ConnectToServiceOptions): Promise<WebRTCRondevuConnection>;
76
- /**
77
- * Get a connection by ID
78
- */
79
- getConnection(id: string): WebRTCRondevuConnection | undefined;
80
- /**
81
- * Get all managed connections
82
- */
83
- getAllConnections(): WebRTCRondevuConnection[];
84
- /**
85
- * Remove a connection
86
- */
87
- private removeConnection;
88
- /**
89
- * Schedule reconnection for a failed connection
90
- */
91
- private scheduleReconnect;
92
- /**
93
- * Attempt to reconnect a failed connection
94
- */
95
- private attemptReconnect;
96
- /**
97
- * Create a temporary signaler (used during initial offer creation)
98
- */
99
- private createTempSignaler;
100
- /**
101
- * Clean up all connections and resources
102
- */
103
- destroy(): void;
104
- }