mirror of
https://github.com/xtr-dev/rondevu-client.git
synced 2025-12-16 13:53:24 +00:00
Add durable WebRTC connections with auto-reconnect and message buffering (v0.18.8)
- Add connection state machine with proper lifecycle management - Implement automatic reconnection with exponential backoff - Add message buffering during disconnections - Create RondevuConnection base class with state tracking - Create OffererConnection and AnswererConnection classes - Fix ICE polling lifecycle (now stops when connected) - Add fillOffers() semaphore to prevent exceeding maxOffers - Implement answer fingerprinting to prevent duplicate processing - Add dual ICE state monitoring (iceConnectionState + connectionState) - Fix data channel handler timing issues - Add comprehensive event system (20+ events) - Add connection timeouts and proper cleanup Breaking changes: - connectToService() now returns AnswererConnection instead of ConnectionContext - connection:opened event signature changed: (offerId, dc) → (offerId, connection) - Direct DataChannel access replaced with connection wrapper API See MIGRATION.md for upgrade guide. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
102
src/connection-events.ts
Normal file
102
src/connection-events.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* TypeScript event type definitions for RondevuConnection
|
||||
*/
|
||||
|
||||
export enum ConnectionState {
|
||||
INITIALIZING = 'initializing', // Creating peer connection
|
||||
GATHERING = 'gathering', // ICE gathering in progress
|
||||
SIGNALING = 'signaling', // Exchanging offer/answer
|
||||
CHECKING = 'checking', // ICE connectivity checks
|
||||
CONNECTING = 'connecting', // ICE connection attempts
|
||||
CONNECTED = 'connected', // Data channel open, working
|
||||
DISCONNECTED = 'disconnected', // Temporarily disconnected
|
||||
RECONNECTING = 'reconnecting', // Attempting reconnection
|
||||
FAILED = 'failed', // Connection failed
|
||||
CLOSED = 'closed', // Connection closed permanently
|
||||
}
|
||||
|
||||
export interface BufferedMessage {
|
||||
id: string
|
||||
data: string | ArrayBuffer | Blob
|
||||
timestamp: number
|
||||
attempts: number
|
||||
}
|
||||
|
||||
export interface ReconnectInfo {
|
||||
attempt: number
|
||||
delay: number
|
||||
maxAttempts: number
|
||||
}
|
||||
|
||||
export interface StateChangeInfo {
|
||||
oldState: ConnectionState
|
||||
newState: ConnectionState
|
||||
reason?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Event map for RondevuConnection
|
||||
* Maps event names to their payload types
|
||||
*/
|
||||
export interface ConnectionEventMap {
|
||||
// Lifecycle events
|
||||
'state:changed': [StateChangeInfo]
|
||||
'connecting': []
|
||||
'connected': []
|
||||
'disconnected': [reason?: string]
|
||||
'failed': [error: Error]
|
||||
'closed': [reason?: string]
|
||||
|
||||
// Reconnection events
|
||||
'reconnect:scheduled': [ReconnectInfo]
|
||||
'reconnect:attempting': [attempt: number]
|
||||
'reconnect:success': []
|
||||
'reconnect:failed': [error: Error]
|
||||
'reconnect:exhausted': [attempts: number]
|
||||
|
||||
// Message events
|
||||
'message': [data: string | ArrayBuffer | Blob]
|
||||
'message:sent': [data: string | ArrayBuffer | Blob, buffered: boolean]
|
||||
'message:buffered': [data: string | ArrayBuffer | Blob]
|
||||
'message:replayed': [message: BufferedMessage]
|
||||
'message:buffer:overflow': [discardedMessage: BufferedMessage]
|
||||
'message:buffer:expired': [message: BufferedMessage]
|
||||
|
||||
// ICE events
|
||||
'ice:candidate:local': [candidate: RTCIceCandidate | null]
|
||||
'ice:candidate:remote': [candidate: RTCIceCandidate | null]
|
||||
'ice:connection:state': [state: RTCIceConnectionState]
|
||||
'ice:gathering:state': [state: RTCIceGatheringState]
|
||||
'ice:polling:started': []
|
||||
'ice:polling:stopped': []
|
||||
|
||||
// Answer processing events (offerer only)
|
||||
'answer:processed': [offerId: string, answererId: string]
|
||||
'answer:duplicate': [offerId: string]
|
||||
|
||||
// Data channel events
|
||||
'datachannel:open': []
|
||||
'datachannel:close': []
|
||||
'datachannel:error': [error: Event]
|
||||
|
||||
// Cleanup events
|
||||
'cleanup:started': []
|
||||
'cleanup:complete': []
|
||||
|
||||
// Connection events (mirrors RTCPeerConnection.connectionState)
|
||||
'connection:state': [state: RTCPeerConnectionState]
|
||||
|
||||
// Timeout events
|
||||
'connection:timeout': []
|
||||
'ice:gathering:timeout': []
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper type to extract event names from the event map
|
||||
*/
|
||||
export type ConnectionEventName = keyof ConnectionEventMap
|
||||
|
||||
/**
|
||||
* Helper type to extract event arguments for a specific event
|
||||
*/
|
||||
export type ConnectionEventArgs<T extends ConnectionEventName> = ConnectionEventMap[T]
|
||||
Reference in New Issue
Block a user