Add RTCConfiguration support to ServiceHost and ServiceClient

- WebRTCContext now accepts optional RTCConfiguration
- ServiceHost and ServiceClient accept optional rtcConfiguration option
- Allows custom STUN/TURN server configuration
- Version bump to 0.10.1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-07 19:43:34 +01:00
parent 54355323d9
commit fbd3be57d4
4 changed files with 42 additions and 31 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "@xtr-dev/rondevu-client", "name": "@xtr-dev/rondevu-client",
"version": "0.10.0", "version": "0.10.1",
"description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing", "description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",

View File

@@ -13,6 +13,7 @@ export interface ServiceClientOptions {
autoReconnect?: boolean autoReconnect?: boolean
reconnectDelay?: number reconnectDelay?: number
maxReconnectAttempts?: number maxReconnectAttempts?: number
rtcConfiguration?: RTCConfiguration
} }
export interface ServiceClientEvents { export interface ServiceClientEvents {
@@ -59,6 +60,7 @@ export class ServiceClient {
private readonly autoReconnect: boolean private readonly autoReconnect: boolean
private readonly reconnectDelay: number private readonly reconnectDelay: number
private readonly maxReconnectAttempts: number private readonly maxReconnectAttempts: number
private readonly rtcConfiguration?: RTCConfiguration
private connection: WebRTCRondevuConnection | null = null private connection: WebRTCRondevuConnection | null = null
private reconnectAttempts = 0 private reconnectAttempts = 0
private reconnectTimeout: ReturnType<typeof setTimeout> | null = null private reconnectTimeout: ReturnType<typeof setTimeout> | null = null
@@ -74,6 +76,7 @@ export class ServiceClient {
this.autoReconnect = options.autoReconnect !== false this.autoReconnect = options.autoReconnect !== false
this.reconnectDelay = options.reconnectDelay || 2000 this.reconnectDelay = options.reconnectDelay || 2000
this.maxReconnectAttempts = options.maxReconnectAttempts || 5 this.maxReconnectAttempts = options.maxReconnectAttempts || 5
this.rtcConfiguration = options.rtcConfiguration
} }
/** /**
@@ -111,7 +114,7 @@ export class ServiceClient {
this.rondevuService.getAPI(), this.rondevuService.getAPI(),
serviceDetails.offerId serviceDetails.offerId
) )
const context = new WebRTCContext(signaler) const context = new WebRTCContext(signaler, this.rtcConfiguration)
// Create connection (answerer role) // Create connection (answerer role)
const conn = new WebRTCRondevuConnection({ const conn = new WebRTCRondevuConnection({

View File

@@ -14,6 +14,7 @@ export interface ServiceHostOptions {
ttl?: number ttl?: number
isPublic?: boolean isPublic?: boolean
metadata?: Record<string, any> metadata?: Record<string, any>
rtcConfiguration?: RTCConfiguration
} }
export interface ServiceHostEvents { export interface ServiceHostEvents {
@@ -62,6 +63,7 @@ export class ServiceHost {
private readonly ttl: number private readonly ttl: number
private readonly isPublic: boolean private readonly isPublic: boolean
private readonly metadata?: Record<string, any> private readonly metadata?: Record<string, any>
private readonly rtcConfiguration?: RTCConfiguration
private readonly bin = createBin() private readonly bin = createBin()
private isStarted = false private isStarted = false
@@ -74,6 +76,7 @@ export class ServiceHost {
this.ttl = options.ttl || 300000 this.ttl = options.ttl || 300000
this.isPublic = options.isPublic !== false this.isPublic = options.isPublic !== false
this.metadata = options.metadata this.metadata = options.metadata
this.rtcConfiguration = options.rtcConfiguration
} }
/** /**
@@ -140,7 +143,7 @@ export class ServiceHost {
private async createOffer(): Promise<void> { private async createOffer(): Promise<void> {
try { try {
// Create temporary context with NoOp signaler // Create temporary context with NoOp signaler
const tempContext = new WebRTCContext(new NoOpSignaler()) const tempContext = new WebRTCContext(new NoOpSignaler(), this.rtcConfiguration)
// Create connection (offerer role) // Create connection (offerer role)
const conn = new WebRTCRondevuConnection({ const conn = new WebRTCRondevuConnection({

View File

@@ -1,35 +1,40 @@
import { Signaler } from './types' import { Signaler } from './types'
const DEFAULT_RTC_CONFIGURATION: RTCConfiguration = {
iceServers: [
{
urls: 'stun:stun.relay.metered.ca:80',
},
{
urls: 'turn:standard.relay.metered.ca:80',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
{
urls: 'turn:standard.relay.metered.ca:80?transport=tcp',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
{
urls: 'turn:standard.relay.metered.ca:443',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
{
urls: 'turns:standard.relay.metered.ca:443?transport=tcp',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
],
}
export class WebRTCContext { export class WebRTCContext {
constructor(public readonly signaler: Signaler) {} constructor(
public readonly signaler: Signaler,
private readonly config?: RTCConfiguration
) {}
createPeerConnection(): RTCPeerConnection { createPeerConnection(): RTCPeerConnection {
return new RTCPeerConnection({ return new RTCPeerConnection(this.config || DEFAULT_RTC_CONFIGURATION)
iceServers: [
{
urls: 'stun:stun.relay.metered.ca:80',
},
{
urls: 'turn:standard.relay.metered.ca:80',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
{
urls: 'turn:standard.relay.metered.ca:80?transport=tcp',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
{
urls: 'turn:standard.relay.metered.ca:443',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
{
urls: 'turns:standard.relay.metered.ca:443?transport=tcp',
username: 'c53a9c971da5e6f3bc959d8d',
credential: 'QaccPqtPPaxyokXp',
},
],
})
} }
} }