From fbd3be57d46cc2c3028d125152ddf4ac5c8f08c6 Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Sun, 7 Dec 2025 19:43:34 +0100 Subject: [PATCH] Add RTCConfiguration support to ServiceHost and ServiceClient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- package.json | 2 +- src/service-client.ts | 5 +++- src/service-host.ts | 5 +++- src/webrtc-context.ts | 61 +++++++++++++++++++++++-------------------- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index f29759c..3c981d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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", "type": "module", "main": "dist/index.js", diff --git a/src/service-client.ts b/src/service-client.ts index 8eabf96..b5ac6f0 100644 --- a/src/service-client.ts +++ b/src/service-client.ts @@ -13,6 +13,7 @@ export interface ServiceClientOptions { autoReconnect?: boolean reconnectDelay?: number maxReconnectAttempts?: number + rtcConfiguration?: RTCConfiguration } export interface ServiceClientEvents { @@ -59,6 +60,7 @@ export class ServiceClient { private readonly autoReconnect: boolean private readonly reconnectDelay: number private readonly maxReconnectAttempts: number + private readonly rtcConfiguration?: RTCConfiguration private connection: WebRTCRondevuConnection | null = null private reconnectAttempts = 0 private reconnectTimeout: ReturnType | null = null @@ -74,6 +76,7 @@ export class ServiceClient { this.autoReconnect = options.autoReconnect !== false this.reconnectDelay = options.reconnectDelay || 2000 this.maxReconnectAttempts = options.maxReconnectAttempts || 5 + this.rtcConfiguration = options.rtcConfiguration } /** @@ -111,7 +114,7 @@ export class ServiceClient { this.rondevuService.getAPI(), serviceDetails.offerId ) - const context = new WebRTCContext(signaler) + const context = new WebRTCContext(signaler, this.rtcConfiguration) // Create connection (answerer role) const conn = new WebRTCRondevuConnection({ diff --git a/src/service-host.ts b/src/service-host.ts index fb2449f..e25f820 100644 --- a/src/service-host.ts +++ b/src/service-host.ts @@ -14,6 +14,7 @@ export interface ServiceHostOptions { ttl?: number isPublic?: boolean metadata?: Record + rtcConfiguration?: RTCConfiguration } export interface ServiceHostEvents { @@ -62,6 +63,7 @@ export class ServiceHost { private readonly ttl: number private readonly isPublic: boolean private readonly metadata?: Record + private readonly rtcConfiguration?: RTCConfiguration private readonly bin = createBin() private isStarted = false @@ -74,6 +76,7 @@ export class ServiceHost { this.ttl = options.ttl || 300000 this.isPublic = options.isPublic !== false this.metadata = options.metadata + this.rtcConfiguration = options.rtcConfiguration } /** @@ -140,7 +143,7 @@ export class ServiceHost { private async createOffer(): Promise { try { // Create temporary context with NoOp signaler - const tempContext = new WebRTCContext(new NoOpSignaler()) + const tempContext = new WebRTCContext(new NoOpSignaler(), this.rtcConfiguration) // Create connection (offerer role) const conn = new WebRTCRondevuConnection({ diff --git a/src/webrtc-context.ts b/src/webrtc-context.ts index d16687f..b585646 100644 --- a/src/webrtc-context.ts +++ b/src/webrtc-context.ts @@ -1,35 +1,40 @@ 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 { - constructor(public readonly signaler: Signaler) {} + constructor( + public readonly signaler: Signaler, + private readonly config?: RTCConfiguration + ) {} createPeerConnection(): RTCPeerConnection { - return new RTCPeerConnection({ - 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', - }, - ], - }) + return new RTCPeerConnection(this.config || DEFAULT_RTC_CONFIGURATION) } }