/** * WebRTC Globals Initialization * * Single initialization point for WebRTC globals. * Handles both browser and Node.js environments. */ // Track initialization state let isInitialized = false; let initializationPromise: Promise | null = null; /** * Ensures WebRTC globals are available in the current environment. * In browsers, these are already available globally. * In Node.js, we polyfill them from @roamhq/wrtc. * * This function is idempotent - safe to call multiple times. */ export async function ensureWebRTCGlobals(): Promise { // Already initialized if (isInitialized) { return true; } // Already tried and failed if (initializationPromise !== null) { return false; } // Initialization in progress - wait for it if (initializationPromise) { await initializationPromise; return isInitialized; } initializationPromise = doInitialize(); await initializationPromise; return isInitialized; } async function doInitialize(): Promise { // Browser environment - WebRTC is already available if (typeof window !== 'undefined') { if (typeof RTCPeerConnection === 'undefined') { throw new Error('WebRTC is not supported in this browser'); } isInitialized = true; return; } // Node.js environment - need to polyfill try { const wrtc = require('@roamhq/wrtc'); if (typeof global.MediaStream === 'undefined' && wrtc.MediaStream) { global.MediaStream = wrtc.MediaStream; } if (typeof (global as any).RTCDataChannel === 'undefined' && wrtc.RTCDataChannel) { (global as any).RTCDataChannel = wrtc.RTCDataChannel; } if (typeof global.RTCPeerConnection === 'undefined' && wrtc.RTCPeerConnection) { global.RTCPeerConnection = wrtc.RTCPeerConnection; } if (typeof global.RTCSessionDescription === 'undefined' && wrtc.RTCSessionDescription) { global.RTCSessionDescription = wrtc.RTCSessionDescription; } if (typeof global.RTCIceCandidate === 'undefined' && wrtc.RTCIceCandidate) { global.RTCIceCandidate = wrtc.RTCIceCandidate; } if (typeof (global as any).RTCVideoSource === 'undefined' && wrtc.nonstandard?.RTCVideoSource) { (global as any).RTCVideoSource = wrtc.nonstandard.RTCVideoSource; } if (typeof (global as any).RTCAudioSource === 'undefined' && wrtc.nonstandard?.RTCAudioSource) { (global as any).RTCAudioSource = wrtc.nonstandard.RTCAudioSource; } if (typeof (global as any).RTCAudioSink === 'undefined' && wrtc.nonstandard?.RTCAudioSink) { (global as any).RTCAudioSink = wrtc.nonstandard.RTCAudioSink; } isInitialized = true; } catch (error) { // In Bun compiled binaries, native addons like @roamhq/wrtc are not available. // Log warning and continue — WebRTC features will be unavailable but won't crash the process. console.warn(`WebRTC native module (@roamhq/wrtc) not available: ${error}. ` + `WebRTC features will be disabled.`); isInitialized = false; } } /** * Check if WebRTC globals have been initialized. */ export function isWebRTCInitialized(): boolean { return isInitialized; } /** * Check if WebRTC is available in the current environment. * Does not initialize - just checks availability. */ export function isWebRTCAvailable(): boolean { if (typeof window !== 'undefined') { return typeof RTCPeerConnection !== 'undefined'; } // In Node.js, check if already initialized or if wrtc is available if (isInitialized) { return true; } try { require.resolve('@roamhq/wrtc'); return true; } catch { return false; } }