@xtr-dev/rondevu-client 0.8.3 → 0.9.1

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.
@@ -1,79 +0,0 @@
1
- import RondevuPeer from './peer/index.js';
2
- import { PooledServiceHandle, PoolStatus } from './service-pool.js';
3
- /**
4
- * Service publish result
5
- */
6
- export interface ServicePublishResult {
7
- serviceId: string;
8
- uuid: string;
9
- offerId: string;
10
- expiresAt: number;
11
- }
12
- /**
13
- * Service publish options
14
- */
15
- export interface PublishServiceOptions {
16
- username: string;
17
- privateKey: string;
18
- serviceFqn: string;
19
- rtcConfig?: RTCConfiguration;
20
- isPublic?: boolean;
21
- metadata?: Record<string, any>;
22
- ttl?: number;
23
- onConnection?: (peer: RondevuPeer) => void;
24
- }
25
- /**
26
- * Service handle for managing an exposed service
27
- */
28
- export interface ServiceHandle {
29
- serviceId: string;
30
- uuid: string;
31
- offerId: string;
32
- unpublish: () => Promise<void>;
33
- }
34
- /**
35
- * Rondevu Services API
36
- * Handles service publishing and management
37
- */
38
- export declare class RondevuServices {
39
- private baseUrl;
40
- private credentials;
41
- private usernameApi;
42
- private offersApi;
43
- constructor(baseUrl: string, credentials: {
44
- peerId: string;
45
- secret: string;
46
- });
47
- /**
48
- * Publishes a service
49
- */
50
- publishService(options: PublishServiceOptions): Promise<ServicePublishResult>;
51
- /**
52
- * Unpublishes a service
53
- */
54
- unpublishService(serviceId: string, username: string): Promise<void>;
55
- /**
56
- * Exposes a service with an automatic connection handler
57
- * This is a convenience method that publishes the service and manages connections
58
- *
59
- * Set poolSize > 1 to enable offer pooling for handling multiple concurrent connections
60
- */
61
- exposeService(options: Omit<PublishServiceOptions, 'onConnection'> & {
62
- handler: (channel: RTCDataChannel, peer: RondevuPeer, connectionId?: string) => void;
63
- poolSize?: number;
64
- pollingInterval?: number;
65
- onPoolStatus?: (status: PoolStatus) => void;
66
- onError?: (error: Error, context: string) => void;
67
- }): Promise<ServiceHandle | PooledServiceHandle>;
68
- /**
69
- * Validates service FQN format
70
- */
71
- private validateServiceFqn;
72
- /**
73
- * Parses a service FQN into name and version
74
- */
75
- parseServiceFqn(fqn: string): {
76
- name: string;
77
- version: string;
78
- };
79
- }
package/dist/services.js DELETED
@@ -1,206 +0,0 @@
1
- import { RondevuUsername } from './usernames.js';
2
- import RondevuPeer from './peer/index.js';
3
- import { RondevuOffers } from './offers.js';
4
- import { ServicePool } from './service-pool.js';
5
- /**
6
- * Rondevu Services API
7
- * Handles service publishing and management
8
- */
9
- export class RondevuServices {
10
- constructor(baseUrl, credentials) {
11
- this.baseUrl = baseUrl;
12
- this.credentials = credentials;
13
- this.usernameApi = new RondevuUsername(baseUrl);
14
- this.offersApi = new RondevuOffers(baseUrl, credentials);
15
- }
16
- /**
17
- * Publishes a service
18
- */
19
- async publishService(options) {
20
- const { username, privateKey, serviceFqn, rtcConfig, isPublic = false, metadata, ttl } = options;
21
- // Validate FQN format
22
- this.validateServiceFqn(serviceFqn);
23
- // Create WebRTC peer connection to generate offer
24
- const pc = new RTCPeerConnection(rtcConfig || {
25
- iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
26
- });
27
- // Add a data channel (required for datachannel-based services)
28
- pc.createDataChannel('rondevu-service');
29
- // Create offer
30
- const offer = await pc.createOffer();
31
- await pc.setLocalDescription(offer);
32
- if (!offer.sdp) {
33
- throw new Error('Failed to generate SDP');
34
- }
35
- // Create signature for username verification
36
- const timestamp = Date.now();
37
- const message = `publish:${username}:${serviceFqn}:${timestamp}`;
38
- const signature = await this.usernameApi.signMessage(message, privateKey);
39
- // Publish service
40
- const response = await fetch(`${this.baseUrl}/services`, {
41
- method: 'POST',
42
- headers: {
43
- 'Content-Type': 'application/json',
44
- 'Authorization': `Bearer ${this.credentials.peerId}:${this.credentials.secret}`
45
- },
46
- body: JSON.stringify({
47
- username,
48
- serviceFqn,
49
- sdp: offer.sdp,
50
- ttl,
51
- isPublic,
52
- metadata,
53
- signature,
54
- message
55
- })
56
- });
57
- if (!response.ok) {
58
- const error = await response.json();
59
- pc.close();
60
- throw new Error(error.error || 'Failed to publish service');
61
- }
62
- const data = await response.json();
63
- // Close the connection for now (would be kept open in a real implementation)
64
- pc.close();
65
- return {
66
- serviceId: data.serviceId,
67
- uuid: data.uuid,
68
- offerId: data.offerId,
69
- expiresAt: data.expiresAt
70
- };
71
- }
72
- /**
73
- * Unpublishes a service
74
- */
75
- async unpublishService(serviceId, username) {
76
- const response = await fetch(`${this.baseUrl}/services/${serviceId}`, {
77
- method: 'DELETE',
78
- headers: {
79
- 'Content-Type': 'application/json',
80
- 'Authorization': `Bearer ${this.credentials.peerId}:${this.credentials.secret}`
81
- },
82
- body: JSON.stringify({ username })
83
- });
84
- if (!response.ok) {
85
- const error = await response.json();
86
- throw new Error(error.error || 'Failed to unpublish service');
87
- }
88
- }
89
- /**
90
- * Exposes a service with an automatic connection handler
91
- * This is a convenience method that publishes the service and manages connections
92
- *
93
- * Set poolSize > 1 to enable offer pooling for handling multiple concurrent connections
94
- */
95
- async exposeService(options) {
96
- const { username, privateKey, serviceFqn, rtcConfig, isPublic, metadata, ttl, handler, poolSize, pollingInterval, onPoolStatus, onError } = options;
97
- // If poolSize > 1, use pooled implementation
98
- if (poolSize && poolSize > 1) {
99
- const pool = new ServicePool(this.baseUrl, this.credentials, {
100
- username,
101
- privateKey,
102
- serviceFqn,
103
- rtcConfig,
104
- isPublic,
105
- metadata,
106
- ttl,
107
- handler: (channel, peer, connectionId) => handler(channel, peer, connectionId),
108
- poolSize,
109
- pollingInterval,
110
- onPoolStatus,
111
- onError
112
- });
113
- return await pool.start();
114
- }
115
- // Otherwise, use existing single-offer logic (UNCHANGED)
116
- // Validate FQN
117
- this.validateServiceFqn(serviceFqn);
118
- // Create peer connection
119
- const pc = new RTCPeerConnection(rtcConfig || {
120
- iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
121
- });
122
- // Create data channel
123
- const channel = pc.createDataChannel('rondevu-service');
124
- // Set up handler
125
- channel.onopen = () => {
126
- const peer = new RondevuPeer(this.offersApi, rtcConfig || {
127
- iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
128
- });
129
- handler(channel, peer);
130
- };
131
- // Create offer
132
- const offer = await pc.createOffer();
133
- await pc.setLocalDescription(offer);
134
- if (!offer.sdp) {
135
- pc.close();
136
- throw new Error('Failed to generate SDP');
137
- }
138
- // Create signature
139
- const timestamp = Date.now();
140
- const message = `publish:${username}:${serviceFqn}:${timestamp}`;
141
- const signature = await this.usernameApi.signMessage(message, privateKey);
142
- // Publish service
143
- const response = await fetch(`${this.baseUrl}/services`, {
144
- method: 'POST',
145
- headers: {
146
- 'Content-Type': 'application/json',
147
- 'Authorization': `Bearer ${this.credentials.peerId}:${this.credentials.secret}`
148
- },
149
- body: JSON.stringify({
150
- username,
151
- serviceFqn,
152
- sdp: offer.sdp,
153
- ttl,
154
- isPublic,
155
- metadata,
156
- signature,
157
- message
158
- })
159
- });
160
- if (!response.ok) {
161
- const error = await response.json();
162
- pc.close();
163
- throw new Error(error.error || 'Failed to expose service');
164
- }
165
- const data = await response.json();
166
- return {
167
- serviceId: data.serviceId,
168
- uuid: data.uuid,
169
- offerId: data.offerId,
170
- unpublish: () => this.unpublishService(data.serviceId, username)
171
- };
172
- }
173
- /**
174
- * Validates service FQN format
175
- */
176
- validateServiceFqn(fqn) {
177
- const parts = fqn.split('@');
178
- if (parts.length !== 2) {
179
- throw new Error('Service FQN must be in format: service-name@version');
180
- }
181
- const [serviceName, version] = parts;
182
- // Validate service name (reverse domain notation)
183
- const serviceNameRegex = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/;
184
- if (!serviceNameRegex.test(serviceName)) {
185
- throw new Error('Service name must be reverse domain notation (e.g., com.example.service)');
186
- }
187
- if (serviceName.length < 3 || serviceName.length > 128) {
188
- throw new Error('Service name must be 3-128 characters');
189
- }
190
- // Validate version (semantic versioning)
191
- const versionRegex = /^[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9.-]+)?$/;
192
- if (!versionRegex.test(version)) {
193
- throw new Error('Version must be semantic versioning (e.g., 1.0.0, 2.1.3-beta)');
194
- }
195
- }
196
- /**
197
- * Parses a service FQN into name and version
198
- */
199
- parseServiceFqn(fqn) {
200
- const parts = fqn.split('@');
201
- if (parts.length !== 2) {
202
- throw new Error('Invalid FQN format');
203
- }
204
- return { name: parts[0], version: parts[1] };
205
- }
206
- }
package/dist/types.d.ts DELETED
@@ -1,157 +0,0 @@
1
- /**
2
- * Session side - identifies which peer in a connection
3
- */
4
- export type Side = 'offerer' | 'answerer';
5
- /**
6
- * Request body for POST /offer
7
- */
8
- export interface CreateOfferRequest {
9
- /** Peer identifier/metadata (max 1024 characters) */
10
- peerId: string;
11
- /** Signaling data for peer connection */
12
- offer: string;
13
- /** Optional custom connection code (if not provided, server generates UUID) */
14
- code?: string;
15
- }
16
- /**
17
- * Response from POST /offer
18
- */
19
- export interface CreateOfferResponse {
20
- /** Unique session identifier (UUID) */
21
- code: string;
22
- }
23
- /**
24
- * Request body for POST /answer
25
- */
26
- export interface AnswerRequest {
27
- /** Session UUID from the offer */
28
- code: string;
29
- /** Response signaling data (required if candidate not provided) */
30
- answer?: string;
31
- /** Additional signaling data (required if answer not provided) */
32
- candidate?: string;
33
- /** Which peer is sending the data */
34
- side: Side;
35
- }
36
- /**
37
- * Response from POST /answer
38
- */
39
- export interface AnswerResponse {
40
- success: boolean;
41
- }
42
- /**
43
- * Request body for POST /poll
44
- */
45
- export interface PollRequest {
46
- /** Session UUID */
47
- code: string;
48
- /** Which side is polling */
49
- side: Side;
50
- }
51
- /**
52
- * Response from POST /poll when side=offerer
53
- */
54
- export interface PollOffererResponse {
55
- /** Answer from answerer (null if not yet received) */
56
- answer: string | null;
57
- /** Additional signaling data from answerer */
58
- answerCandidates: string[];
59
- }
60
- /**
61
- * Response from POST /poll when side=answerer
62
- */
63
- export interface PollAnswererResponse {
64
- /** Offer from offerer */
65
- offer: string;
66
- /** Additional signaling data from offerer */
67
- offerCandidates: string[];
68
- }
69
- /**
70
- * Response from POST /poll (union type)
71
- */
72
- export type PollResponse = PollOffererResponse | PollAnswererResponse;
73
- /**
74
- * Response from GET / - server version information
75
- */
76
- export interface VersionResponse {
77
- /** Git commit hash or version identifier */
78
- version: string;
79
- }
80
- /**
81
- * Response from GET /health
82
- */
83
- export interface HealthResponse {
84
- status: 'ok';
85
- timestamp: number;
86
- version: string;
87
- }
88
- /**
89
- * Error response structure
90
- */
91
- export interface ErrorResponse {
92
- error: string;
93
- }
94
- /**
95
- * Client configuration options
96
- */
97
- export interface RondevuClientOptions {
98
- /** Base URL of the Rondevu server (e.g., 'https://example.com') */
99
- baseUrl: string;
100
- /** Optional fetch implementation (for Node.js environments) */
101
- fetch?: typeof fetch;
102
- }
103
- /**
104
- * WebRTC polyfill for Node.js and other non-browser platforms
105
- */
106
- export interface WebRTCPolyfill {
107
- RTCPeerConnection: typeof RTCPeerConnection;
108
- RTCSessionDescription: typeof RTCSessionDescription;
109
- RTCIceCandidate: typeof RTCIceCandidate;
110
- }
111
- /**
112
- * Configuration options for Rondevu WebRTC client
113
- */
114
- export interface RondevuOptions {
115
- /** Base URL of the Rondevu server (defaults to 'https://api.ronde.vu') */
116
- baseUrl?: string;
117
- /** Peer identifier (optional, auto-generated if not provided) */
118
- peerId?: string;
119
- /** Optional fetch implementation (for Node.js environments) */
120
- fetch?: typeof fetch;
121
- /** WebRTC configuration (ICE servers, etc.) */
122
- rtcConfig?: RTCConfiguration;
123
- /** Polling interval in milliseconds (default: 1000) */
124
- pollingInterval?: number;
125
- /** Connection timeout in milliseconds (default: 30000) */
126
- connectionTimeout?: number;
127
- /** WebRTC polyfill for Node.js (e.g., wrtc or @roamhq/wrtc) */
128
- wrtc?: WebRTCPolyfill;
129
- }
130
- /**
131
- * Connection role - whether this peer is creating or answering
132
- */
133
- export type ConnectionRole = 'offerer' | 'answerer';
134
- /**
135
- * Parameters for creating a RondevuConnection
136
- */
137
- export interface RondevuConnectionParams {
138
- id: string;
139
- topic?: string;
140
- role: ConnectionRole;
141
- pc: RTCPeerConnection;
142
- localPeerId: string;
143
- remotePeerId: string;
144
- pollingInterval: number;
145
- connectionTimeout: number;
146
- wrtc?: WebRTCPolyfill;
147
- }
148
- /**
149
- * Event map for RondevuConnection events
150
- */
151
- export interface RondevuConnectionEvents {
152
- connect: () => void;
153
- disconnect: () => void;
154
- error: (error: Error) => void;
155
- datachannel: (channel: RTCDataChannel) => void;
156
- stream: (stream: MediaStream) => void;
157
- }
package/dist/types.js DELETED
@@ -1,4 +0,0 @@
1
- // ============================================================================
2
- // Signaling Types
3
- // ============================================================================
4
- export {};