pigeonrtc
Version:
Pluggable cross-browser compatible WebRTC library for PeerPigeon
5 lines • 51.1 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/RTCAdapter.js", "../src/BrowserRTCAdapter.js", "../src/NodeRTCAdapter.js", "../src/SignalingClient.js", "../src/MDNSResolver.js", "../src/PeerConnection.js", "../src/PigeonRTC.js", "../src/index.js"],
"sourcesContent": ["/**\n * Base RTCAdapter interface that all WebRTC adapters must implement.\n * This provides a consistent API regardless of the underlying WebRTC implementation.\n */\nexport class RTCAdapter {\n /**\n * Get the RTCPeerConnection class for this adapter\n * @returns {typeof RTCPeerConnection} The RTCPeerConnection class\n */\n getRTCPeerConnection() {\n throw new Error('getRTCPeerConnection must be implemented by adapter');\n }\n\n /**\n * Get the RTCSessionDescription class for this adapter\n * @returns {typeof RTCSessionDescription} The RTCSessionDescription class\n */\n getRTCSessionDescription() {\n throw new Error('getRTCSessionDescription must be implemented by adapter');\n }\n\n /**\n * Get the RTCIceCandidate class for this adapter\n * @returns {typeof RTCIceCandidate} The RTCIceCandidate class\n */\n getRTCIceCandidate() {\n throw new Error('getRTCIceCandidate must be implemented by adapter');\n }\n\n /**\n * Get the MediaStream class for this adapter (if supported)\n * @returns {typeof MediaStream|null} The MediaStream class or null if not supported\n */\n getMediaStream() {\n return null;\n }\n\n /**\n * Check if this adapter supports the current environment\n * @returns {boolean} True if the adapter can work in the current environment\n */\n isSupported() {\n throw new Error('isSupported must be implemented by adapter');\n }\n\n /**\n * Get the name of this adapter\n * @returns {string} The adapter name\n */\n getName() {\n throw new Error('getName must be implemented by adapter');\n }\n\n /**\n * Initialize the adapter (for any setup that needs to happen)\n * @returns {Promise<void>}\n */\n async initialize() {\n // Default implementation does nothing\n }\n\n /**\n * Get user media (if supported)\n * @param {MediaStreamConstraints} _constraints\n * @returns {Promise<MediaStream>}\n */\n async getUserMedia(_constraints) {\n throw new Error('getUserMedia not supported by this adapter');\n }\n\n /**\n * Get display media (if supported)\n * @param {MediaStreamConstraints} _constraints\n * @returns {Promise<MediaStream>}\n */\n async getDisplayMedia(_constraints) {\n throw new Error('getDisplayMedia not supported by this adapter');\n }\n}\n", "import { RTCAdapter } from './RTCAdapter.js';\n\n/**\n * Browser-native WebRTC adapter for use in web browsers.\n * This adapter uses the browser's native WebRTC implementation.\n */\nexport class BrowserRTCAdapter extends RTCAdapter {\n constructor() {\n super();\n this._checkSupport();\n }\n\n _checkSupport() {\n // Check if we're in a browser environment\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\n return;\n }\n\n // Browser environment - check for WebRTC support\n this.hasRTCPeerConnection = !!(\n window.RTCPeerConnection ||\n window.webkitRTCPeerConnection ||\n window.mozRTCPeerConnection\n );\n\n this.hasGetUserMedia = !!(\n navigator.mediaDevices?.getUserMedia ||\n navigator.getUserMedia ||\n navigator.webkitGetUserMedia ||\n navigator.mozGetUserMedia\n );\n\n this.hasGetDisplayMedia = !!(\n navigator.mediaDevices?.getDisplayMedia\n );\n }\n\n getRTCPeerConnection() {\n if (typeof window === 'undefined') {\n throw new Error('BrowserRTCAdapter requires a browser environment');\n }\n\n return window.RTCPeerConnection ||\n window.webkitRTCPeerConnection ||\n window.mozRTCPeerConnection;\n }\n\n getRTCSessionDescription() {\n if (typeof window === 'undefined') {\n throw new Error('BrowserRTCAdapter requires a browser environment');\n }\n\n return window.RTCSessionDescription ||\n window.mozRTCSessionDescription;\n }\n\n getRTCIceCandidate() {\n if (typeof window === 'undefined') {\n throw new Error('BrowserRTCAdapter requires a browser environment');\n }\n\n return window.RTCIceCandidate ||\n window.mozRTCIceCandidate;\n }\n\n getMediaStream() {\n if (typeof window === 'undefined') {\n return null;\n }\n\n return window.MediaStream || window.webkitMediaStream;\n }\n\n isSupported() {\n return typeof window !== 'undefined' && this.hasRTCPeerConnection;\n }\n\n getName() {\n return 'BrowserRTCAdapter';\n }\n\n async getUserMedia(constraints) {\n if (typeof navigator === 'undefined') {\n throw new Error('getUserMedia requires a browser environment');\n }\n\n // Modern API\n if (navigator.mediaDevices?.getUserMedia) {\n return await navigator.mediaDevices.getUserMedia(constraints);\n }\n\n // Legacy API with Promise wrapper\n const getUserMedia = navigator.getUserMedia ||\n navigator.webkitGetUserMedia ||\n navigator.mozGetUserMedia;\n\n if (!getUserMedia) {\n throw new Error('getUserMedia is not supported in this browser');\n }\n\n return new Promise((resolve, reject) => {\n getUserMedia.call(navigator, constraints, resolve, reject);\n });\n }\n\n async getDisplayMedia(constraints) {\n if (typeof navigator === 'undefined') {\n throw new Error('getDisplayMedia requires a browser environment');\n }\n\n if (!navigator.mediaDevices?.getDisplayMedia) {\n throw new Error('getDisplayMedia is not supported in this browser');\n }\n\n return await navigator.mediaDevices.getDisplayMedia(constraints);\n }\n}\n", "import { RTCAdapter } from './RTCAdapter.js';\n\n/**\n * Node.js WebRTC adapter using @koush/wrtc package.\n * This adapter provides WebRTC functionality in Node.js environments.\n */\nexport class NodeRTCAdapter extends RTCAdapter {\n constructor() {\n super();\n this._wrtc = null;\n this._initialized = false;\n }\n\n async initialize() {\n if (this._initialized) {\n return;\n }\n\n try {\n // Dynamically import @koush/wrtc (it's an optional peer dependency)\n const wrtcModule = await import('@koush/wrtc');\n // Handle both default export (ES modules) and named exports (CommonJS)\n this._wrtc = wrtcModule.default || wrtcModule;\n this._initialized = true;\n } catch (error) {\n throw new Error(\n 'NodeRTCAdapter requires @koush/wrtc to be installed. ' +\n 'Install it with: npm install @koush/wrtc'\n );\n }\n }\n\n _ensureInitialized() {\n if (!this._initialized || !this._wrtc) {\n throw new Error(\n 'NodeRTCAdapter not initialized. Call initialize() first.'\n );\n }\n }\n\n getRTCPeerConnection() {\n this._ensureInitialized();\n return this._wrtc.RTCPeerConnection;\n }\n\n getRTCSessionDescription() {\n this._ensureInitialized();\n return this._wrtc.RTCSessionDescription;\n }\n\n getRTCIceCandidate() {\n this._ensureInitialized();\n return this._wrtc.RTCIceCandidate;\n }\n\n getMediaStream() {\n this._ensureInitialized();\n return this._wrtc.MediaStream || null;\n }\n\n isSupported() {\n // Check if we're in a Node.js environment (not browser)\n return typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null &&\n typeof window === 'undefined';\n }\n\n getName() {\n return 'NodeRTCAdapter';\n }\n\n async getUserMedia(_constraints) {\n // Node.js doesn't typically support getUserMedia\n // This would require additional hardware access libraries\n throw new Error('getUserMedia is not supported in Node.js environment');\n }\n\n async getDisplayMedia(_constraints) {\n // Node.js doesn't support getDisplayMedia\n throw new Error('getDisplayMedia is not supported in Node.js environment');\n }\n}\n", "/**\n * WebSocket signaling client for PigeonRTC\n * Handles peer discovery and WebRTC signaling over WebSocket\n */\nexport class SignalingClient extends EventTarget {\n constructor(serverUrl) {\n super();\n this.serverUrl = serverUrl;\n this.ws = null;\n this.clientId = null;\n this.connected = false;\n this.reconnectAttempts = 0;\n this.maxReconnectAttempts = 5;\n this.reconnectDelay = 1000;\n }\n\n /**\n * Connect to the signaling server\n * @returns {Promise<void>}\n */\n connect() {\n return new Promise((resolve, reject) => {\n try {\n this.ws = new WebSocket(this.serverUrl);\n \n this.ws.onopen = () => {\n this.connected = true;\n this.reconnectAttempts = 0;\n this.dispatchEvent(new CustomEvent('connected'));\n resolve();\n };\n \n this.ws.onmessage = (event) => {\n try {\n const message = JSON.parse(event.data);\n this.handleMessage(message);\n } catch (err) {\n console.error('Error parsing message:', err);\n }\n };\n \n this.ws.onerror = (error) => {\n this.dispatchEvent(new CustomEvent('error', { detail: error }));\n reject(error);\n };\n \n this.ws.onclose = () => {\n this.connected = false;\n this.dispatchEvent(new CustomEvent('disconnected'));\n this.attemptReconnect();\n };\n \n } catch (err) {\n reject(err);\n }\n });\n }\n\n /**\n * Handle incoming messages from signaling server\n * @private\n */\n handleMessage(message) {\n switch (message.type) {\n case 'id':\n this.clientId = message.id;\n this.dispatchEvent(new CustomEvent('id', { detail: { id: message.id } }));\n break;\n \n case 'clients':\n this.dispatchEvent(new CustomEvent('clients', { detail: { clients: message.clients } }));\n break;\n \n case 'offer':\n case 'answer':\n case 'ice-candidate':\n this.dispatchEvent(new CustomEvent('signal', { detail: message }));\n break;\n \n default:\n console.warn('Unknown message type:', message.type);\n }\n }\n\n /**\n * Send a message to the signaling server\n * @param {Object} message - Message to send\n */\n send(message) {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(message));\n } else {\n throw new Error('WebSocket not connected');\n }\n }\n\n /**\n * Send an offer to a peer\n * @param {string|number} peerId - Target peer ID\n * @param {RTCSessionDescriptionInit} offer - WebRTC offer\n */\n sendOffer(peerId, offer) {\n this.send({\n type: 'offer',\n to: peerId,\n offer: offer\n });\n }\n\n /**\n * Send an answer to a peer\n * @param {string|number} peerId - Target peer ID\n * @param {RTCSessionDescriptionInit} answer - WebRTC answer\n */\n sendAnswer(peerId, answer) {\n this.send({\n type: 'answer',\n to: peerId,\n answer: answer\n });\n }\n\n /**\n * Send an ICE candidate to a peer\n * @param {string|number} peerId - Target peer ID\n * @param {RTCIceCandidateInit} candidate - ICE candidate\n */\n sendIceCandidate(peerId, candidate) {\n this.send({\n type: 'ice-candidate',\n to: peerId,\n candidate: candidate\n });\n }\n\n /**\n * Attempt to reconnect to the signaling server\n * @private\n */\n attemptReconnect() {\n if (this.reconnectAttempts < this.maxReconnectAttempts) {\n this.reconnectAttempts++;\n setTimeout(() => {\n console.log(`Reconnecting... attempt ${this.reconnectAttempts}`);\n this.connect().catch(err => {\n console.error('Reconnect failed:', err);\n });\n }, this.reconnectDelay * this.reconnectAttempts);\n }\n }\n\n /**\n * Disconnect from the signaling server\n */\n disconnect() {\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n this.connected = false;\n this.clientId = null;\n }\n }\n\n /**\n * Check if connected to signaling server\n * @returns {boolean}\n */\n isConnected() {\n return this.connected && this.ws && this.ws.readyState === WebSocket.OPEN;\n }\n\n /**\n * Get client ID\n * @returns {string|number|null}\n */\n getClientId() {\n return this.clientId;\n }\n}\n", "/**\n * mDNS Resolver for handling .local ICE candidates\n * Uses pigeonns for resolving mDNS hostnames to IP addresses\n * Supports both Node.js (direct mDNS) and Browser (HTTP API) environments\n */\nexport class MDNSResolver {\n constructor(options = {}) {\n this._resolver = null;\n this._initialized = false;\n this._cache = new Map();\n this._cacheTimeout = 60000; // 60 seconds cache TTL\n this._mode = null; // 'node' or 'browser'\n this._serverUrl = options.serverUrl || 'http://localhost:5380'; // pigeonns HTTP server\n }\n\n /**\n * Initialize the mDNS resolver\n * Automatically detects Node.js vs Browser environment\n * @returns {Promise<void>}\n */\n async initialize() {\n if (this._initialized) {\n return;\n }\n\n // Detect environment\n const isNode = typeof process !== 'undefined' && \n process.versions != null && \n process.versions.node != null;\n\n if (isNode) {\n // Node.js: Use direct mDNS resolver\n try {\n const pigeonnsModule = await import('pigeonns');\n const MDNSResolver = pigeonnsModule.default || pigeonnsModule;\n this._resolver = new MDNSResolver({\n timeout: 5000,\n ttl: 60, // Match our cache timeout\n cacheSize: 1000\n });\n this._resolver.start();\n this._mode = 'node';\n this._initialized = true;\n console.log('\u2713 mDNS resolver initialized (Node.js mode)');\n } catch (error) {\n console.warn('Failed to initialize Node.js mDNS resolver:', error.message);\n this._initialized = false;\n }\n } else {\n // Browser: Use HTTP API client\n try {\n // Test if pigeonns server is available\n const response = await fetch(`${this._serverUrl}/health`, {\n method: 'GET',\n signal: AbortSignal.timeout(2000) // 2 second timeout\n });\n \n if (response.ok) {\n this._mode = 'browser';\n this._initialized = true;\n console.log(`\u2713 mDNS resolver initialized (Browser mode) - Server: ${this._serverUrl}`);\n } else {\n console.warn(`pigeonns server not responding at ${this._serverUrl}`);\n this._initialized = false;\n }\n } catch (error) {\n console.warn(`Failed to connect to pigeonns server at ${this._serverUrl}:`, error.message);\n console.warn('mDNS resolution will be disabled. Start pigeonns server with: npx pigeonns serve');\n this._initialized = false;\n }\n }\n }\n\n /**\n * Check if the resolver is available and initialized\n * @returns {boolean}\n */\n isAvailable() {\n return this._initialized && this._resolver !== null;\n }\n\n /**\n * Check if an ICE candidate contains a .local hostname\n * @param {RTCIceCandidateInit} candidate - ICE candidate to check\n * @returns {boolean}\n */\n isLocalCandidate(candidate) {\n if (!candidate || !candidate.candidate) {\n return false;\n }\n\n // Check if the candidate string contains .local\n return candidate.candidate.includes('.local');\n }\n\n /**\n * Extract hostname from ICE candidate string\n * @param {string} candidateString - ICE candidate string\n * @returns {string|null} - Extracted hostname or null\n * @private\n */\n _extractHostname(candidateString) {\n // ICE candidate format: \"candidate:... typ ... ...\"\n // Example: \"candidate:1 1 udp 2113937151 hostname.local 54321 typ host\"\n const parts = candidateString.split(' ');\n \n for (let i = 0; i < parts.length; i++) {\n if (parts[i].endsWith('.local')) {\n return parts[i];\n }\n }\n \n return null;\n }\n\n /**\n * Get cached IP address for hostname\n * @param {string} hostname - Hostname to lookup\n * @returns {string|null}\n * @private\n */\n _getCachedIP(hostname) {\n const cached = this._cache.get(hostname);\n if (cached && Date.now() - cached.timestamp < this._cacheTimeout) {\n return cached.ip;\n }\n return null;\n }\n\n /**\n * Set cached IP address for hostname\n * @param {string} hostname - Hostname to cache\n * @param {string} ip - IP address to cache\n * @private\n */\n _setCachedIP(hostname, ip) {\n this._cache.set(hostname, {\n ip,\n timestamp: Date.now()\n });\n }\n\n /**\n * Resolve a .local hostname to an IP address using mDNS\n * Works in both Node.js (direct mDNS) and Browser (HTTP API) modes\n * @param {string} hostname - Hostname to resolve (e.g., \"myhost.local\")\n * @returns {Promise<string|null>} - Resolved IP address or null if resolution fails\n */\n async resolve(hostname) {\n if (!this.isAvailable()) {\n console.warn('mDNS resolver not available');\n return null;\n }\n\n // Check cache first\n const cachedIP = this._getCachedIP(hostname);\n if (cachedIP) {\n return cachedIP;\n }\n\n try {\n let ip = null;\n\n if (this._mode === 'node') {\n // Node.js: Use direct mDNS resolver\n ip = await this._resolver.resolve(hostname, 'A');\n } else if (this._mode === 'browser') {\n // Browser: Use HTTP API\n const response = await fetch(\n `${this._serverUrl}/resolve?name=${encodeURIComponent(hostname)}&type=A`,\n {\n method: 'GET',\n signal: AbortSignal.timeout(5000) // 5 second timeout\n }\n );\n\n if (response.ok) {\n const data = await response.json();\n ip = data.address;\n } else {\n console.warn(`Failed to resolve ${hostname}: HTTP ${response.status}`);\n }\n }\n \n if (ip) {\n this._setCachedIP(hostname, ip);\n return ip;\n }\n \n return null;\n } catch (error) {\n console.warn(`Failed to resolve ${hostname}:`, error.message);\n return null;\n }\n }\n\n /**\n * Resolve an ICE candidate that contains a .local hostname\n * Returns a new candidate with the hostname replaced by the IP address\n * @param {RTCIceCandidateInit} candidate - ICE candidate to resolve\n * @returns {Promise<RTCIceCandidateInit|null>} - Resolved candidate or null\n */\n async resolveCandidate(candidate) {\n if (!candidate || !candidate.candidate) {\n return null;\n }\n\n if (!this.isLocalCandidate(candidate)) {\n // Not a .local candidate, return as-is\n return candidate;\n }\n\n const hostname = this._extractHostname(candidate.candidate);\n if (!hostname) {\n console.warn('Could not extract hostname from candidate:', candidate.candidate);\n return null;\n }\n\n const ip = await this.resolve(hostname);\n if (!ip) {\n console.warn(`Could not resolve ${hostname} to IP address`);\n return null;\n }\n\n // Create a new candidate with the hostname replaced by the IP\n const resolvedCandidateString = candidate.candidate.replace(hostname, ip);\n \n return {\n ...candidate,\n candidate: resolvedCandidateString,\n address: ip\n };\n }\n\n /**\n * Clear the resolution cache\n */\n clearCache() {\n this._cache.clear();\n }\n\n /**\n * Dispose of the resolver and clean up resources\n */\n dispose() {\n this.clearCache();\n \n // Clean up Node.js resolver if running\n if (this._mode === 'node' && this._resolver) {\n try {\n this._resolver.stop();\n } catch (error) {\n console.warn('Error stopping mDNS resolver:', error.message);\n }\n }\n \n this._resolver = null;\n this._initialized = false;\n this._mode = null;\n }\n}\n", "import { MDNSResolver } from './MDNSResolver.js';\n\n/**\n * Managed peer connection with built-in signaling support\n */\nexport class PeerConnection extends EventTarget {\n constructor(rtcInstance, signalingClient, config = {}) {\n super();\n this.rtc = rtcInstance;\n this.signaling = signalingClient;\n this.config = config;\n this.pc = null;\n this.dataChannels = new Map();\n this.remoteId = null;\n this.isInitiator = false;\n this.mdnsResolver = new MDNSResolver({\n serverUrl: config.mdnsServerUrl || 'http://localhost:5380'\n });\n this._mdnsEnabled = config.enableMDNS !== false; // enabled by default\n }\n\n /**\n * Initialize peer connection\n * @private\n */\n async _init() {\n // Initialize mDNS resolver if enabled\n if (this._mdnsEnabled) {\n await this.mdnsResolver.initialize();\n }\n\n this.pc = this.rtc.createPeerConnection(this.config);\n \n // Handle ICE candidates\n this.pc.onicecandidate = async (event) => {\n if (event.candidate && this.remoteId) {\n let candidateToSend = event.candidate;\n \n // Try to resolve .local candidates if mDNS is enabled\n if (this._mdnsEnabled && this.mdnsResolver.isAvailable() && \n this.mdnsResolver.isLocalCandidate(event.candidate)) {\n const resolvedCandidate = await this.mdnsResolver.resolveCandidate(event.candidate);\n if (resolvedCandidate) {\n candidateToSend = resolvedCandidate;\n console.log('Resolved .local ICE candidate:', event.candidate.candidate, '->', resolvedCandidate.candidate);\n }\n }\n \n this.signaling.sendIceCandidate(this.remoteId, candidateToSend);\n }\n };\n \n // Handle connection state changes\n this.pc.onconnectionstatechange = () => {\n this.dispatchEvent(new CustomEvent('connectionstatechange', {\n detail: this.pc.connectionState\n }));\n \n if (this.pc.connectionState === 'connected') {\n this.dispatchEvent(new CustomEvent('connected'));\n } else if (this.pc.connectionState === 'failed') {\n this.dispatchEvent(new CustomEvent('failed'));\n }\n };\n \n // Handle ICE connection state changes\n this.pc.oniceconnectionstatechange = () => {\n this.dispatchEvent(new CustomEvent('iceconnectionstatechange', {\n detail: this.pc.iceConnectionState\n }));\n };\n \n // Handle remote tracks\n this.pc.ontrack = (event) => {\n this.dispatchEvent(new CustomEvent('track', {\n detail: { track: event.track, streams: event.streams }\n }));\n };\n \n // Handle incoming data channels\n this.pc.ondatachannel = (event) => {\n const channel = event.channel;\n this.dataChannels.set(channel.label, channel);\n this._setupDataChannel(channel);\n \n this.dispatchEvent(new CustomEvent('datachannel', {\n detail: channel\n }));\n };\n }\n\n /**\n * Connect to a remote peer\n * @param {string|number} peerId - Remote peer ID\n * @param {MediaStream} [localStream] - Optional local media stream\n * @returns {Promise<void>}\n */\n async connect(peerId, localStream = null) {\n this.remoteId = peerId;\n this.isInitiator = true;\n await this._init();\n \n // Add local tracks if provided\n if (localStream) {\n localStream.getTracks().forEach(track => {\n this.pc.addTrack(track, localStream);\n });\n }\n \n // Create and send offer\n const offer = await this.pc.createOffer();\n await this.pc.setLocalDescription(offer);\n this.signaling.sendOffer(peerId, offer);\n }\n\n /**\n * Handle incoming offer from remote peer\n * @param {string|number} peerId - Remote peer ID\n * @param {RTCSessionDescriptionInit} offer - WebRTC offer\n * @param {MediaStream} [localStream] - Optional local media stream\n * @returns {Promise<void>}\n */\n async handleOffer(peerId, offer, localStream = null) {\n this.remoteId = peerId;\n this.isInitiator = false;\n await this._init();\n \n // Add local tracks if provided\n if (localStream) {\n localStream.getTracks().forEach(track => {\n this.pc.addTrack(track, localStream);\n });\n }\n \n // Set remote description and create answer\n await this.pc.setRemoteDescription(offer);\n const answer = await this.pc.createAnswer();\n await this.pc.setLocalDescription(answer);\n this.signaling.sendAnswer(peerId, answer);\n }\n\n /**\n * Handle incoming answer from remote peer\n * @param {RTCSessionDescriptionInit} answer - WebRTC answer\n * @returns {Promise<void>}\n */\n async handleAnswer(answer) {\n await this.pc.setRemoteDescription(answer);\n }\n\n /**\n * Handle incoming ICE candidate\n * @param {RTCIceCandidateInit} candidate - ICE candidate\n * @returns {Promise<void>}\n */\n async handleIceCandidate(candidate) {\n if (this.pc) {\n let candidateToAdd = candidate;\n \n // Try to resolve .local candidates if mDNS is enabled\n if (this._mdnsEnabled && this.mdnsResolver.isAvailable() && \n this.mdnsResolver.isLocalCandidate(candidate)) {\n const resolvedCandidate = await this.mdnsResolver.resolveCandidate(candidate);\n if (resolvedCandidate) {\n candidateToAdd = resolvedCandidate;\n console.log('Resolved incoming .local ICE candidate:', candidate.candidate, '->', resolvedCandidate.candidate);\n }\n }\n \n await this.pc.addIceCandidate(candidateToAdd);\n }\n }\n\n /**\n * Create a data channel\n * @param {string} label - Channel label\n * @param {RTCDataChannelInit} [options] - Data channel options\n * @returns {RTCDataChannel}\n */\n createDataChannel(label, options = {}) {\n if (!this.pc) {\n throw new Error('Peer connection not initialized');\n }\n \n const channel = this.pc.createDataChannel(label, options);\n this.dataChannels.set(label, channel);\n this._setupDataChannel(channel);\n return channel;\n }\n\n /**\n * Setup data channel event handlers\n * @private\n */\n _setupDataChannel(channel) {\n channel.onopen = () => {\n this.dispatchEvent(new CustomEvent('channelopen', {\n detail: channel\n }));\n };\n \n channel.onmessage = (event) => {\n this.dispatchEvent(new CustomEvent('message', {\n detail: { channel: channel.label, data: event.data }\n }));\n };\n \n channel.onclose = () => {\n this.dataChannels.delete(channel.label);\n this.dispatchEvent(new CustomEvent('channelclose', {\n detail: channel\n }));\n };\n }\n\n /**\n * Send data on a channel\n * @param {string} channelLabel - Channel label\n * @param {string|ArrayBuffer|Blob} data - Data to send\n */\n send(channelLabel, data) {\n const channel = this.dataChannels.get(channelLabel);\n if (channel && channel.readyState === 'open') {\n channel.send(data);\n } else {\n throw new Error(`Channel ${channelLabel} not open`);\n }\n }\n\n /**\n * Get a data channel by label\n * @param {string} label - Channel label\n * @returns {RTCDataChannel|undefined}\n */\n getDataChannel(label) {\n return this.dataChannels.get(label);\n }\n\n /**\n * Get the underlying RTCPeerConnection\n * @returns {RTCPeerConnection}\n */\n getRTCPeerConnection() {\n return this.pc;\n }\n\n /**\n * Close the peer connection\n */\n close() {\n if (this.pc) {\n this.pc.close();\n this.pc = null;\n }\n this.dataChannels.clear();\n this.remoteId = null;\n \n // Clean up mDNS resolver\n if (this.mdnsResolver) {\n this.mdnsResolver.dispose();\n }\n }\n}\n", "import { BrowserRTCAdapter } from './BrowserRTCAdapter.js';\nimport { NodeRTCAdapter } from './NodeRTCAdapter.js';\nimport { SignalingClient } from './SignalingClient.js';\nimport { PeerConnection } from './PeerConnection.js';\n\n/**\n * Main PigeonRTC class that provides a unified interface for WebRTC\n * across different environments with pluggable adapter support.\n */\nexport class PigeonRTC {\n constructor(options = {}) {\n this.adapter = options.adapter || null;\n this.initialized = false;\n }\n\n /**\n * Initialize PigeonRTC with automatic adapter detection or custom adapter\n * @param {Object} options - Configuration options\n * @param {RTCAdapter} options.adapter - Custom adapter to use (optional)\n * @param {boolean} options.preferNode - Prefer Node adapter even in browser (for testing)\n * @returns {Promise<void>}\n */\n async initialize(options = {}) {\n if (this.initialized) {\n return;\n }\n\n // Use custom adapter if provided\n if (options.adapter) {\n this.adapter = options.adapter;\n }\n\n // Auto-detect adapter if not provided\n if (!this.adapter) {\n this.adapter = await this._detectAdapter(options);\n }\n\n // Initialize the adapter\n await this.adapter.initialize();\n this.initialized = true;\n }\n\n /**\n * Automatically detect and create the appropriate adapter for the current environment\n * @private\n */\n async _detectAdapter(options = {}) {\n // Try Node adapter first if we're in Node.js and preferNode is true or no browser support\n if (options.preferNode || (typeof window === 'undefined' && typeof process !== 'undefined')) {\n const nodeAdapter = new NodeRTCAdapter();\n if (nodeAdapter.isSupported()) {\n try {\n await nodeAdapter.initialize();\n return nodeAdapter;\n } catch (error) {\n // If Node adapter fails, fall through to browser adapter (might be in a hybrid environment)\n console.warn('Node adapter initialization failed, trying browser adapter:', error.message);\n }\n }\n }\n\n // Try browser adapter\n const browserAdapter = new BrowserRTCAdapter();\n if (browserAdapter.isSupported()) {\n return browserAdapter;\n }\n\n // No supported adapter found\n throw new Error(\n 'No supported WebRTC adapter found. ' +\n 'Make sure you are running in a browser with WebRTC support or have @koush/wrtc installed for Node.js.'\n );\n }\n\n /**\n * Ensure PigeonRTC is initialized before use\n * @private\n */\n _ensureInitialized() {\n if (!this.initialized || !this.adapter) {\n throw new Error('PigeonRTC not initialized. Call initialize() first.');\n }\n }\n\n /**\n * Get the RTCPeerConnection class\n * @returns {typeof RTCPeerConnection}\n */\n getRTCPeerConnection() {\n this._ensureInitialized();\n return this.adapter.getRTCPeerConnection();\n }\n\n /**\n * Get the RTCSessionDescription class\n * @returns {typeof RTCSessionDescription}\n */\n getRTCSessionDescription() {\n this._ensureInitialized();\n return this.adapter.getRTCSessionDescription();\n }\n\n /**\n * Get the RTCIceCandidate class\n * @returns {typeof RTCIceCandidate}\n */\n getRTCIceCandidate() {\n this._ensureInitialized();\n return this.adapter.getRTCIceCandidate();\n }\n\n /**\n * Get the MediaStream class (if supported)\n * @returns {typeof MediaStream|null}\n */\n getMediaStream() {\n this._ensureInitialized();\n return this.adapter.getMediaStream();\n }\n\n /**\n * Create a new RTCPeerConnection with the given configuration\n * @param {RTCConfiguration} config - RTCPeerConnection configuration\n * @returns {RTCPeerConnection}\n */\n createPeerConnection(config) {\n this._ensureInitialized();\n const RTCPeerConnection = this.adapter.getRTCPeerConnection();\n return new RTCPeerConnection(config);\n }\n\n /**\n * Create a new RTCSessionDescription\n * @param {RTCSessionDescriptionInit} init - Session description initialization\n * @returns {RTCSessionDescription}\n */\n createSessionDescription(init) {\n this._ensureInitialized();\n const RTCSessionDescription = this.adapter.getRTCSessionDescription();\n return new RTCSessionDescription(init);\n }\n\n /**\n * Create a new RTCIceCandidate\n * @param {RTCIceCandidateInit} init - ICE candidate initialization\n * @returns {RTCIceCandidate}\n */\n createIceCandidate(init) {\n this._ensureInitialized();\n const RTCIceCandidate = this.adapter.getRTCIceCandidate();\n return new RTCIceCandidate(init);\n }\n\n /**\n * Get user media stream (camera/microphone)\n * @param {MediaStreamConstraints} constraints\n * @returns {Promise<MediaStream>}\n */\n async getUserMedia(constraints) {\n this._ensureInitialized();\n return await this.adapter.getUserMedia(constraints);\n }\n\n /**\n * Get display media stream (screen sharing)\n * @param {MediaStreamConstraints} constraints\n * @returns {Promise<MediaStream>}\n */\n async getDisplayMedia(constraints) {\n this._ensureInitialized();\n return await this.adapter.getDisplayMedia(constraints);\n }\n\n /**\n * Check if WebRTC is supported in the current environment\n * @returns {boolean}\n */\n isSupported() {\n return this.adapter ? this.adapter.isSupported() : false;\n }\n\n /**\n * Get the name of the current adapter\n * @returns {string}\n */\n getAdapterName() {\n return this.adapter ? this.adapter.getName() : 'None';\n }\n\n /**\n * Create a signaling client for peer discovery and connection management\n * @param {string} serverUrl - WebSocket server URL (e.g., 'ws://localhost:9090')\n * @returns {SignalingClient}\n */\n createSignalingClient(serverUrl) {\n return new SignalingClient(serverUrl);\n }\n\n /**\n * Create a managed peer connection with built-in signaling\n * @param {SignalingClient} signalingClient - Signaling client instance\n * @param {RTCConfiguration} config - RTCPeerConnection configuration\n * @returns {PeerConnection}\n */\n createManagedPeerConnection(signalingClient, config = {}) {\n this._ensureInitialized();\n return new PeerConnection(this, signalingClient, config);\n }\n}\n\n/**\n * Create and initialize a PigeonRTC instance\n * @param {Object} options - Configuration options\n * @returns {Promise<PigeonRTC>}\n */\nexport async function createPigeonRTC(options = {}) {\n const rtc = new PigeonRTC(options);\n await rtc.initialize(options);\n return rtc;\n}\n\n// Export additional classes\nexport { SignalingClient } from './SignalingClient.js';\nexport { PeerConnection } from './PeerConnection.js';\n", "/**\n * PigeonRTC - Pluggable cross-browser compatible WebRTC library\n * \n * A lightweight, pluggable WebRTC library that provides a consistent API\n * across different environments (browser and Node.js) with support for\n * custom adapters.\n * \n * @module pigeonrtc\n */\n\nexport { PigeonRTC, createPigeonRTC, SignalingClient, PeerConnection } from './PigeonRTC.js';\nexport { RTCAdapter } from './RTCAdapter.js';\nexport { BrowserRTCAdapter } from './BrowserRTCAdapter.js';\nexport { NodeRTCAdapter } from './NodeRTCAdapter.js';\nexport { MDNSResolver } from './MDNSResolver.js';\n\n// Default export for convenience\nimport { createPigeonRTC } from './PigeonRTC.js';\nexport default createPigeonRTC;\n"],
"mappings": "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