@xtr-dev/rondevu-client 0.8.3 → 0.9.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.
@@ -0,0 +1,370 @@
1
+ /**
2
+ * DurableConnection - WebRTC connection with automatic reconnection
3
+ *
4
+ * Manages the WebRTC peer lifecycle and automatically reconnects on
5
+ * connection drops with exponential backoff.
6
+ */
7
+ import { EventEmitter } from '../event-emitter.js';
8
+ import RondevuPeer from '../peer/index.js';
9
+ import { DurableChannel } from './channel.js';
10
+ import { createReconnectionScheduler } from './reconnection.js';
11
+ import { DurableConnectionState } from './types.js';
12
+ /**
13
+ * Default configuration for durable connections
14
+ */
15
+ const DEFAULT_CONFIG = {
16
+ maxReconnectAttempts: 10,
17
+ reconnectBackoffBase: 1000,
18
+ reconnectBackoffMax: 30000,
19
+ reconnectJitter: 0.2,
20
+ connectionTimeout: 30000,
21
+ maxQueueSize: 1000,
22
+ maxMessageAge: 60000,
23
+ rtcConfig: {
24
+ iceServers: [
25
+ { urls: 'stun:stun.l.google.com:19302' },
26
+ { urls: 'stun:stun1.l.google.com:19302' }
27
+ ]
28
+ }
29
+ };
30
+ /**
31
+ * Durable WebRTC connection that automatically reconnects
32
+ *
33
+ * The DurableConnection manages the lifecycle of a WebRTC peer connection
34
+ * and provides:
35
+ * - Automatic reconnection with exponential backoff
36
+ * - Multiple durable channels that survive reconnections
37
+ * - Configurable retry limits and timeouts
38
+ * - High-level connection state events
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const connection = new DurableConnection(
43
+ * offersApi,
44
+ * { username: 'alice', serviceFqn: 'chat@1.0.0' },
45
+ * { maxReconnectAttempts: 5 }
46
+ * );
47
+ *
48
+ * connection.on('connected', () => {
49
+ * console.log('Connected!');
50
+ * });
51
+ *
52
+ * connection.on('reconnecting', (attempt, max, delay) => {
53
+ * console.log(`Reconnecting... (${attempt}/${max}, retry in ${delay}ms)`);
54
+ * });
55
+ *
56
+ * const channel = connection.createChannel('chat');
57
+ * channel.on('message', (data) => {
58
+ * console.log('Received:', data);
59
+ * });
60
+ *
61
+ * await connection.connect();
62
+ * ```
63
+ */
64
+ export class DurableConnection extends EventEmitter {
65
+ constructor(offersApi, connectionInfo, config) {
66
+ super();
67
+ this.offersApi = offersApi;
68
+ this.channels = new Map();
69
+ this.connectionId = `conn-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
70
+ this.config = { ...DEFAULT_CONFIG, ...config };
71
+ this.connectionInfo = connectionInfo;
72
+ this._state = DurableConnectionState.CONNECTING;
73
+ }
74
+ /**
75
+ * Current connection state
76
+ */
77
+ getState() {
78
+ return this._state;
79
+ }
80
+ /**
81
+ * Check if connection is currently connected
82
+ */
83
+ isConnected() {
84
+ return this._state === DurableConnectionState.CONNECTED;
85
+ }
86
+ /**
87
+ * Create a durable channel on this connection
88
+ *
89
+ * The channel will be created on the current peer connection if available,
90
+ * otherwise it will be created when the connection is established.
91
+ *
92
+ * @param label - Channel label
93
+ * @param options - RTCDataChannel init options
94
+ * @returns DurableChannel instance
95
+ */
96
+ createChannel(label, options) {
97
+ // Check if channel already exists
98
+ if (this.channels.has(label)) {
99
+ throw new Error(`Channel with label '${label}' already exists`);
100
+ }
101
+ // Create durable channel
102
+ const durableChannel = new DurableChannel(label, {
103
+ maxQueueSize: this.config.maxQueueSize,
104
+ maxMessageAge: this.config.maxMessageAge,
105
+ ordered: options?.ordered ?? true,
106
+ maxRetransmits: options?.maxRetransmits
107
+ });
108
+ this.channels.set(label, durableChannel);
109
+ // If we have a current peer, attach the channel
110
+ if (this.currentPeer && this._state === DurableConnectionState.CONNECTED) {
111
+ this.createAndAttachChannel(durableChannel, options);
112
+ }
113
+ return durableChannel;
114
+ }
115
+ /**
116
+ * Get an existing channel by label
117
+ */
118
+ getChannel(label) {
119
+ return this.channels.get(label);
120
+ }
121
+ /**
122
+ * Establish the initial connection
123
+ *
124
+ * @returns Promise that resolves when connected
125
+ */
126
+ async connect() {
127
+ if (this._state !== DurableConnectionState.CONNECTING) {
128
+ throw new Error(`Cannot connect from state: ${this._state}`);
129
+ }
130
+ try {
131
+ await this.establishConnection();
132
+ }
133
+ catch (error) {
134
+ this._state = DurableConnectionState.DISCONNECTED;
135
+ await this.handleDisconnection();
136
+ throw error;
137
+ }
138
+ }
139
+ /**
140
+ * Close the connection gracefully
141
+ */
142
+ async close() {
143
+ if (this._state === DurableConnectionState.CLOSED) {
144
+ return;
145
+ }
146
+ const previousState = this._state;
147
+ this._state = DurableConnectionState.CLOSED;
148
+ // Cancel any ongoing reconnection
149
+ if (this.reconnectionScheduler) {
150
+ this.reconnectionScheduler.cancel();
151
+ }
152
+ // Close all channels
153
+ for (const channel of this.channels.values()) {
154
+ channel.close();
155
+ }
156
+ // Close peer connection
157
+ if (this.currentPeer) {
158
+ await this.currentPeer.close();
159
+ this.currentPeer = undefined;
160
+ }
161
+ this.emit('state', this._state, previousState);
162
+ this.emit('closed');
163
+ }
164
+ /**
165
+ * Establish a WebRTC connection
166
+ */
167
+ async establishConnection() {
168
+ // Create new peer
169
+ const peer = new RondevuPeer(this.offersApi, this.config.rtcConfig);
170
+ this.currentPeer = peer;
171
+ // Setup peer event handlers
172
+ this.setupPeerHandlers(peer);
173
+ // Determine connection method based on connection info
174
+ if (this.connectionInfo.uuid) {
175
+ // Connect by UUID
176
+ await this.connectByUuid(peer, this.connectionInfo.uuid);
177
+ }
178
+ else if (this.connectionInfo.username && this.connectionInfo.serviceFqn) {
179
+ // Connect by username and service FQN
180
+ await this.connectByService(peer, this.connectionInfo.username, this.connectionInfo.serviceFqn);
181
+ }
182
+ else {
183
+ throw new Error('Invalid connection info: must provide either uuid or (username + serviceFqn)');
184
+ }
185
+ // Wait for connection with timeout
186
+ await this.waitForConnection(peer);
187
+ // Connection established
188
+ this.transitionToConnected();
189
+ }
190
+ /**
191
+ * Connect to a service by UUID
192
+ */
193
+ async connectByUuid(peer, uuid) {
194
+ // Get service details
195
+ const response = await fetch(`${this.offersApi['baseUrl']}/services/${uuid}`);
196
+ if (!response.ok) {
197
+ throw new Error(`Service not found: ${uuid}`);
198
+ }
199
+ const service = await response.json();
200
+ // Answer the offer
201
+ await peer.answer(service.offerId, service.sdp, {
202
+ secret: this.offersApi['credentials'].secret,
203
+ topics: []
204
+ });
205
+ }
206
+ /**
207
+ * Connect to a service by username and service FQN
208
+ */
209
+ async connectByService(peer, username, serviceFqn) {
210
+ // Query service to get UUID
211
+ const response = await fetch(`${this.offersApi['baseUrl']}/index/${username}/query`, {
212
+ method: 'POST',
213
+ headers: { 'Content-Type': 'application/json' },
214
+ body: JSON.stringify({ serviceFqn })
215
+ });
216
+ if (!response.ok) {
217
+ throw new Error(`Service not found: ${username}/${serviceFqn}`);
218
+ }
219
+ const { uuid } = await response.json();
220
+ // Connect by UUID
221
+ await this.connectByUuid(peer, uuid);
222
+ }
223
+ /**
224
+ * Wait for peer connection to establish
225
+ */
226
+ async waitForConnection(peer) {
227
+ return new Promise((resolve, reject) => {
228
+ const timeout = setTimeout(() => {
229
+ reject(new Error('Connection timeout'));
230
+ }, this.config.connectionTimeout);
231
+ const onConnected = () => {
232
+ clearTimeout(timeout);
233
+ peer.off('connected', onConnected);
234
+ peer.off('failed', onFailed);
235
+ resolve();
236
+ };
237
+ const onFailed = (error) => {
238
+ clearTimeout(timeout);
239
+ peer.off('connected', onConnected);
240
+ peer.off('failed', onFailed);
241
+ reject(error);
242
+ };
243
+ peer.on('connected', onConnected);
244
+ peer.on('failed', onFailed);
245
+ });
246
+ }
247
+ /**
248
+ * Setup event handlers for peer
249
+ */
250
+ setupPeerHandlers(peer) {
251
+ this.peerConnectedHandler = () => {
252
+ // Connection established - will be handled by waitForConnection
253
+ };
254
+ this.peerDisconnectedHandler = () => {
255
+ if (this._state !== DurableConnectionState.CLOSED) {
256
+ this.handleDisconnection();
257
+ }
258
+ };
259
+ this.peerFailedHandler = (error) => {
260
+ if (this._state !== DurableConnectionState.CLOSED) {
261
+ console.error('Peer connection failed:', error);
262
+ this.handleDisconnection();
263
+ }
264
+ };
265
+ this.peerDataChannelHandler = (channel) => {
266
+ // Find or create durable channel
267
+ let durableChannel = this.channels.get(channel.label);
268
+ if (!durableChannel) {
269
+ // Auto-create channel for incoming data channels
270
+ durableChannel = new DurableChannel(channel.label, {
271
+ maxQueueSize: this.config.maxQueueSize,
272
+ maxMessageAge: this.config.maxMessageAge
273
+ });
274
+ this.channels.set(channel.label, durableChannel);
275
+ }
276
+ // Attach the received channel
277
+ durableChannel.attachToChannel(channel);
278
+ };
279
+ peer.on('connected', this.peerConnectedHandler);
280
+ peer.on('disconnected', this.peerDisconnectedHandler);
281
+ peer.on('failed', this.peerFailedHandler);
282
+ peer.on('datachannel', this.peerDataChannelHandler);
283
+ }
284
+ /**
285
+ * Transition to connected state
286
+ */
287
+ transitionToConnected() {
288
+ const previousState = this._state;
289
+ this._state = DurableConnectionState.CONNECTED;
290
+ // Reset reconnection scheduler if it exists
291
+ if (this.reconnectionScheduler) {
292
+ this.reconnectionScheduler.reset();
293
+ }
294
+ // Attach all channels to the new peer connection
295
+ for (const [label, channel] of this.channels) {
296
+ if (this.currentPeer) {
297
+ this.createAndAttachChannel(channel);
298
+ }
299
+ }
300
+ this.emit('state', this._state, previousState);
301
+ this.emit('connected');
302
+ }
303
+ /**
304
+ * Create underlying RTCDataChannel and attach to durable channel
305
+ */
306
+ createAndAttachChannel(durableChannel, options) {
307
+ if (!this.currentPeer) {
308
+ return;
309
+ }
310
+ // Check if peer already has this channel (received via datachannel event)
311
+ // If not, create it
312
+ const senders = this.currentPeer.pc.getSenders?.() || [];
313
+ const existingChannel = Array.from(senders)
314
+ .map((sender) => sender.channel)
315
+ .find(ch => ch && ch.label === durableChannel.label);
316
+ if (existingChannel) {
317
+ durableChannel.attachToChannel(existingChannel);
318
+ }
319
+ else {
320
+ // Create new channel on peer
321
+ const rtcChannel = this.currentPeer.createDataChannel(durableChannel.label, options);
322
+ durableChannel.attachToChannel(rtcChannel);
323
+ }
324
+ }
325
+ /**
326
+ * Handle connection disconnection
327
+ */
328
+ async handleDisconnection() {
329
+ if (this._state === DurableConnectionState.CLOSED ||
330
+ this._state === DurableConnectionState.FAILED) {
331
+ return;
332
+ }
333
+ const previousState = this._state;
334
+ this._state = DurableConnectionState.RECONNECTING;
335
+ this.emit('state', this._state, previousState);
336
+ this.emit('disconnected');
337
+ // Detach all channels (but keep them alive)
338
+ for (const channel of this.channels.values()) {
339
+ channel.detachFromChannel();
340
+ }
341
+ // Close old peer
342
+ if (this.currentPeer) {
343
+ await this.currentPeer.close();
344
+ this.currentPeer = undefined;
345
+ }
346
+ // Create or use existing reconnection scheduler
347
+ if (!this.reconnectionScheduler) {
348
+ this.reconnectionScheduler = createReconnectionScheduler({
349
+ maxAttempts: this.config.maxReconnectAttempts,
350
+ backoffBase: this.config.reconnectBackoffBase,
351
+ backoffMax: this.config.reconnectBackoffMax,
352
+ jitter: this.config.reconnectJitter,
353
+ onReconnect: async () => {
354
+ await this.establishConnection();
355
+ },
356
+ onMaxAttemptsExceeded: (error) => {
357
+ const prevState = this._state;
358
+ this._state = DurableConnectionState.FAILED;
359
+ this.emit('state', this._state, prevState);
360
+ this.emit('failed', error, true);
361
+ },
362
+ onBeforeAttempt: (attempt, max, delay) => {
363
+ this.emit('reconnecting', attempt, max, delay);
364
+ }
365
+ });
366
+ }
367
+ // Schedule reconnection
368
+ this.reconnectionScheduler.schedule();
369
+ }
370
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Reconnection utilities for durable connections
3
+ *
4
+ * This module provides utilities for managing reconnection logic with
5
+ * exponential backoff and jitter.
6
+ */
7
+ /**
8
+ * Calculate exponential backoff delay with jitter
9
+ *
10
+ * @param attempt - Current attempt number (0-indexed)
11
+ * @param base - Base delay in milliseconds
12
+ * @param max - Maximum delay in milliseconds
13
+ * @param jitter - Jitter factor (0-1), e.g., 0.2 for ±20%
14
+ * @returns Delay in milliseconds with jitter applied
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * calculateBackoff(0, 1000, 30000, 0.2) // ~1000ms ± 20%
19
+ * calculateBackoff(1, 1000, 30000, 0.2) // ~2000ms ± 20%
20
+ * calculateBackoff(2, 1000, 30000, 0.2) // ~4000ms ± 20%
21
+ * calculateBackoff(5, 1000, 30000, 0.2) // ~30000ms ± 20% (capped at max)
22
+ * ```
23
+ */
24
+ export declare function calculateBackoff(attempt: number, base: number, max: number, jitter: number): number;
25
+ /**
26
+ * Configuration for reconnection scheduler
27
+ */
28
+ export interface ReconnectionSchedulerConfig {
29
+ /** Maximum number of reconnection attempts */
30
+ maxAttempts: number;
31
+ /** Base delay for exponential backoff */
32
+ backoffBase: number;
33
+ /** Maximum delay between attempts */
34
+ backoffMax: number;
35
+ /** Jitter factor for randomizing delays */
36
+ jitter: number;
37
+ /** Callback invoked for each reconnection attempt */
38
+ onReconnect: () => Promise<void>;
39
+ /** Callback invoked when max attempts exceeded */
40
+ onMaxAttemptsExceeded: (error: Error) => void;
41
+ /** Optional callback invoked before each attempt */
42
+ onBeforeAttempt?: (attempt: number, maxAttempts: number, delay: number) => void;
43
+ }
44
+ /**
45
+ * Reconnection scheduler state
46
+ */
47
+ export interface ReconnectionScheduler {
48
+ /** Current attempt number */
49
+ attempt: number;
50
+ /** Whether scheduler is active */
51
+ active: boolean;
52
+ /** Schedule next reconnection attempt */
53
+ schedule: () => void;
54
+ /** Cancel scheduled reconnection */
55
+ cancel: () => void;
56
+ /** Reset attempt counter */
57
+ reset: () => void;
58
+ }
59
+ /**
60
+ * Create a reconnection scheduler
61
+ *
62
+ * @param config - Scheduler configuration
63
+ * @returns Reconnection scheduler instance
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const scheduler = createReconnectionScheduler({
68
+ * maxAttempts: 10,
69
+ * backoffBase: 1000,
70
+ * backoffMax: 30000,
71
+ * jitter: 0.2,
72
+ * onReconnect: async () => {
73
+ * await connect();
74
+ * },
75
+ * onMaxAttemptsExceeded: (error) => {
76
+ * console.error('Failed to reconnect:', error);
77
+ * },
78
+ * onBeforeAttempt: (attempt, max, delay) => {
79
+ * console.log(`Reconnecting in ${delay}ms (${attempt}/${max})...`);
80
+ * }
81
+ * });
82
+ *
83
+ * // Start reconnection
84
+ * scheduler.schedule();
85
+ *
86
+ * // Cancel reconnection
87
+ * scheduler.cancel();
88
+ * ```
89
+ */
90
+ export declare function createReconnectionScheduler(config: ReconnectionSchedulerConfig): ReconnectionScheduler;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Reconnection utilities for durable connections
3
+ *
4
+ * This module provides utilities for managing reconnection logic with
5
+ * exponential backoff and jitter.
6
+ */
7
+ /**
8
+ * Calculate exponential backoff delay with jitter
9
+ *
10
+ * @param attempt - Current attempt number (0-indexed)
11
+ * @param base - Base delay in milliseconds
12
+ * @param max - Maximum delay in milliseconds
13
+ * @param jitter - Jitter factor (0-1), e.g., 0.2 for ±20%
14
+ * @returns Delay in milliseconds with jitter applied
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * calculateBackoff(0, 1000, 30000, 0.2) // ~1000ms ± 20%
19
+ * calculateBackoff(1, 1000, 30000, 0.2) // ~2000ms ± 20%
20
+ * calculateBackoff(2, 1000, 30000, 0.2) // ~4000ms ± 20%
21
+ * calculateBackoff(5, 1000, 30000, 0.2) // ~30000ms ± 20% (capped at max)
22
+ * ```
23
+ */
24
+ export function calculateBackoff(attempt, base, max, jitter) {
25
+ // Calculate exponential delay: base * 2^attempt
26
+ const exponential = base * Math.pow(2, attempt);
27
+ // Cap at maximum
28
+ const capped = Math.min(exponential, max);
29
+ // Apply jitter: ± (jitter * capped)
30
+ const jitterAmount = capped * jitter;
31
+ const randomJitter = (Math.random() * 2 - 1) * jitterAmount;
32
+ // Return delay with jitter, ensuring it's not negative
33
+ return Math.max(0, capped + randomJitter);
34
+ }
35
+ /**
36
+ * Create a reconnection scheduler
37
+ *
38
+ * @param config - Scheduler configuration
39
+ * @returns Reconnection scheduler instance
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const scheduler = createReconnectionScheduler({
44
+ * maxAttempts: 10,
45
+ * backoffBase: 1000,
46
+ * backoffMax: 30000,
47
+ * jitter: 0.2,
48
+ * onReconnect: async () => {
49
+ * await connect();
50
+ * },
51
+ * onMaxAttemptsExceeded: (error) => {
52
+ * console.error('Failed to reconnect:', error);
53
+ * },
54
+ * onBeforeAttempt: (attempt, max, delay) => {
55
+ * console.log(`Reconnecting in ${delay}ms (${attempt}/${max})...`);
56
+ * }
57
+ * });
58
+ *
59
+ * // Start reconnection
60
+ * scheduler.schedule();
61
+ *
62
+ * // Cancel reconnection
63
+ * scheduler.cancel();
64
+ * ```
65
+ */
66
+ export function createReconnectionScheduler(config) {
67
+ let attempt = 0;
68
+ let active = false;
69
+ let timer;
70
+ const schedule = () => {
71
+ // Cancel any existing timer
72
+ if (timer) {
73
+ clearTimeout(timer);
74
+ timer = undefined;
75
+ }
76
+ // Check if max attempts exceeded
77
+ if (attempt >= config.maxAttempts) {
78
+ active = false;
79
+ config.onMaxAttemptsExceeded(new Error(`Max reconnection attempts exceeded (${config.maxAttempts})`));
80
+ return;
81
+ }
82
+ // Calculate delay
83
+ const delay = calculateBackoff(attempt, config.backoffBase, config.backoffMax, config.jitter);
84
+ // Notify before attempt
85
+ if (config.onBeforeAttempt) {
86
+ config.onBeforeAttempt(attempt + 1, config.maxAttempts, delay);
87
+ }
88
+ // Mark as active
89
+ active = true;
90
+ // Schedule reconnection
91
+ timer = setTimeout(async () => {
92
+ attempt++;
93
+ try {
94
+ await config.onReconnect();
95
+ // Success - reset scheduler
96
+ attempt = 0;
97
+ active = false;
98
+ }
99
+ catch (error) {
100
+ // Failure - schedule next attempt
101
+ schedule();
102
+ }
103
+ }, delay);
104
+ };
105
+ const cancel = () => {
106
+ if (timer) {
107
+ clearTimeout(timer);
108
+ timer = undefined;
109
+ }
110
+ active = false;
111
+ };
112
+ const reset = () => {
113
+ cancel();
114
+ attempt = 0;
115
+ };
116
+ return {
117
+ get attempt() {
118
+ return attempt;
119
+ },
120
+ get active() {
121
+ return active;
122
+ },
123
+ schedule,
124
+ cancel,
125
+ reset
126
+ };
127
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * DurableService - Service with automatic TTL refresh
3
+ *
4
+ * Manages service publishing with automatic reconnection for incoming
5
+ * connections and TTL auto-refresh to prevent expiration.
6
+ */
7
+ import { EventEmitter } from '../event-emitter.js';
8
+ import type { RondevuOffers } from '../offers.js';
9
+ import { DurableChannel } from './channel.js';
10
+ import type { DurableServiceConfig, DurableServiceEvents, ServiceInfo } from './types.js';
11
+ /**
12
+ * Connection handler callback
13
+ */
14
+ export type ConnectionHandler = (channel: DurableChannel, connectionId: string) => void | Promise<void>;
15
+ /**
16
+ * Durable service that automatically refreshes TTL and handles reconnections
17
+ *
18
+ * The DurableService manages service publishing and provides:
19
+ * - Automatic TTL refresh before expiration
20
+ * - Durable connections for incoming peers
21
+ * - Connection pooling for multiple simultaneous connections
22
+ * - High-level connection lifecycle events
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const service = new DurableService(
27
+ * offersApi,
28
+ * (channel, connectionId) => {
29
+ * channel.on('message', (data) => {
30
+ * console.log(`Message from ${connectionId}:`, data);
31
+ * channel.send(`Echo: ${data}`);
32
+ * });
33
+ * },
34
+ * {
35
+ * username: 'alice',
36
+ * privateKey: keypair.privateKey,
37
+ * serviceFqn: 'chat@1.0.0',
38
+ * poolSize: 10
39
+ * }
40
+ * );
41
+ *
42
+ * service.on('published', (serviceId, uuid) => {
43
+ * console.log(`Service published: ${uuid}`);
44
+ * });
45
+ *
46
+ * service.on('connection', (connectionId) => {
47
+ * console.log(`New connection: ${connectionId}`);
48
+ * });
49
+ *
50
+ * await service.start();
51
+ * ```
52
+ */
53
+ export declare class DurableService extends EventEmitter<DurableServiceEvents> {
54
+ private offersApi;
55
+ private baseUrl;
56
+ private credentials;
57
+ private handler;
58
+ readonly config: Required<DurableServiceConfig>;
59
+ private serviceId?;
60
+ private uuid?;
61
+ private expiresAt?;
62
+ private ttlRefreshTimer?;
63
+ private servicePool?;
64
+ private activeChannels;
65
+ constructor(offersApi: RondevuOffers, baseUrl: string, credentials: {
66
+ peerId: string;
67
+ secret: string;
68
+ }, handler: ConnectionHandler, config: DurableServiceConfig);
69
+ /**
70
+ * Start the service
71
+ *
72
+ * Publishes the service and begins accepting connections.
73
+ *
74
+ * @returns Service information
75
+ */
76
+ start(): Promise<ServiceInfo>;
77
+ /**
78
+ * Stop the service
79
+ *
80
+ * Unpublishes the service and closes all active connections.
81
+ */
82
+ stop(): Promise<void>;
83
+ /**
84
+ * Get list of active connection IDs
85
+ */
86
+ getActiveConnections(): string[];
87
+ /**
88
+ * Get service information
89
+ */
90
+ getServiceInfo(): ServiceInfo | null;
91
+ /**
92
+ * Schedule TTL refresh
93
+ */
94
+ private scheduleRefresh;
95
+ /**
96
+ * Refresh service TTL
97
+ */
98
+ private refreshServiceTTL;
99
+ /**
100
+ * Handle new incoming connection
101
+ */
102
+ private handleNewConnection;
103
+ }