@telnyx/webrtc
Version:
Telnyx WebRTC Client
1 lines • 239 kB
JavaScript
function e(e,t){var i={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(i[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var s=0;for(n=Object.getOwnPropertySymbols(e);s<n.length;s++)t.indexOf(n[s])<0&&Object.prototype.propertyIsEnumerable.call(e,n[s])&&(i[n[s]]=e[n[s]])}return i}function t(e,t,i,n){return new(i||(i=Promise))((function(s,o){function r(e){try{c(n.next(e))}catch(e){o(e)}}function a(e){try{c(n.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(r,a)}c((n=n.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;var i="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto),n=new Uint8Array(16);function s(){if(!i)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return i(n)}for(var o=[],r=0;r<256;++r)o[r]=(r+256).toString(16).substr(1);function a(e,t,i){var n=t&&i||0;"string"==typeof e&&(t="binary"===e?new Array(16):null,e=null);var r=(e=e||{}).random||(e.rng||s)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,t)for(var a=0;a<16;++a)t[n+a]=r[a];return t||function(e,t){var i=t||0,n=o;return[n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]]].join("")}(r)}const c={SDP_CREATE_OFFER_FAILED:40001,SDP_CREATE_ANSWER_FAILED:40002,SDP_SET_LOCAL_DESCRIPTION_FAILED:40003,SDP_SET_REMOTE_DESCRIPTION_FAILED:40004,SDP_SEND_FAILED:40005,MEDIA_MICROPHONE_PERMISSION_DENIED:42001,MEDIA_DEVICE_NOT_FOUND:42002,MEDIA_GET_USER_MEDIA_FAILED:42003,HOLD_FAILED:44001,INVALID_CALL_PARAMETERS:44002,BYE_SEND_FAILED:44003,SUBSCRIBE_FAILED:44004,PEER_CLOSED_DURING_INIT:44005,WEBSOCKET_CONNECTION_FAILED:45001,WEBSOCKET_ERROR:45002,RECONNECTION_EXHAUSTED:45003,GATEWAY_FAILED:45004,LOGIN_FAILED:46001,INVALID_CREDENTIALS:46002,AUTHENTICATION_REQUIRED:46003,ICE_RESTART_FAILED:47001,NETWORK_OFFLINE:48001,SESSION_NOT_REATTACHED:48501,UNEXPECTED_ERROR:49001},l={HIGH_RTT:31001,HIGH_JITTER:31002,HIGH_PACKET_LOSS:31003,LOW_MOS:31004,LOW_LOCAL_AUDIO:31005,LOW_INBOUND_AUDIO:31006,LOW_BYTES_RECEIVED:32001,LOW_BYTES_SENT:32002,RECORDING_UNAVAILABLE:32003,RECORDING_BUFFER_OVERFLOW:32004,ICE_CONNECTIVITY_LOST:33001,ICE_GATHERING_TIMEOUT:33002,ICE_GATHERING_EMPTY:33003,PEER_CONNECTION_FAILED:33004,ONLY_HOST_ICE_CANDIDATES:33005,ANSWER_WHILE_PEER_ACTIVE:33006,ICE_CANDIDATE_PAIR_CHANGED:33008,AUDIO_INPUT_DEVICE_CHANGE_SKIPPED:33009,MULTIPLE_ACTIVE_CALLS_DETECTED:33010,DUPLICATE_INBOUND_ANSWER:33007,SHARED_REMOTE_ELEMENT_OVERWRITE:33011,TOKEN_EXPIRING_SOON:34001,UNKNOWN_REATTACHED_SESSION:35002,SIGNALING_RECOVERY_REQUIRED:36003,MEDIA_RECOVERY_REQUIRED:36004,RECONNECTION_FAILED_WITH_NO_AUTO_RECONNECT:36005},{SDP_CREATE_OFFER_FAILED:d,SDP_CREATE_ANSWER_FAILED:h,SDP_SET_LOCAL_DESCRIPTION_FAILED:u,SDP_SET_REMOTE_DESCRIPTION_FAILED:p,SDP_SEND_FAILED:g,MEDIA_MICROPHONE_PERMISSION_DENIED:v,MEDIA_DEVICE_NOT_FOUND:m,MEDIA_GET_USER_MEDIA_FAILED:f,HOLD_FAILED:_,INVALID_CALL_PARAMETERS:y,BYE_SEND_FAILED:b,SUBSCRIBE_FAILED:S,PEER_CLOSED_DURING_INIT:I,WEBSOCKET_CONNECTION_FAILED:C,WEBSOCKET_ERROR:E,RECONNECTION_EXHAUSTED:w,GATEWAY_FAILED:k,LOGIN_FAILED:T,INVALID_CREDENTIALS:R,AUTHENTICATION_REQUIRED:A,ICE_RESTART_FAILED:O,NETWORK_OFFLINE:D,SESSION_NOT_REATTACHED:N,UNEXPECTED_ERROR:L}=c,{HIGH_RTT:M,HIGH_JITTER:P,HIGH_PACKET_LOSS:x,LOW_MOS:U,LOW_LOCAL_AUDIO:F,LOW_INBOUND_AUDIO:$,LOW_BYTES_RECEIVED:j,LOW_BYTES_SENT:B,RECORDING_UNAVAILABLE:W,RECORDING_BUFFER_OVERFLOW:H,ICE_CONNECTIVITY_LOST:G,ICE_GATHERING_TIMEOUT:V,ICE_GATHERING_EMPTY:q,PEER_CONNECTION_FAILED:Y,ONLY_HOST_ICE_CANDIDATES:K,ANSWER_WHILE_PEER_ACTIVE:J,ICE_CANDIDATE_PAIR_CHANGED:z,AUDIO_INPUT_DEVICE_CHANGE_SKIPPED:Q,MULTIPLE_ACTIVE_CALLS_DETECTED:X,DUPLICATE_INBOUND_ANSWER:Z,SHARED_REMOTE_ELEMENT_OVERWRITE:ee,TOKEN_EXPIRING_SOON:te,UNKNOWN_REATTACHED_SESSION:ie,SIGNALING_RECOVERY_REQUIRED:ne,MEDIA_RECOVERY_REQUIRED:se,RECONNECTION_FAILED_WITH_NO_AUTO_RECONNECT:oe}=l,re=/^a=candidate:.+typ (srflx|prflx|relay)/m,ae="wss://rtc.telnyx.com",ce={NORMAL_CLOSURE:1e3,GOING_AWAY:1001,PROTOCOL_ERROR:1002,UNSUPPORTED_DATA:1003,NO_STATUS_RECEIVED:1005,ABNORMAL_CLOSURE:1006,INVALID_FRAME_PAYLOAD:1007,POLICY_VIOLATION:1008,MESSAGE_TOO_BIG:1009,INTERNAL_ERROR:1011},le={urls:"stun:stun.l.google.com:19302"},de={urls:"stun:stun.telnyx.com:3478"},he={urls:"turn:turn.telnyx.com:3478?transport=udp",username:"testuser",credential:"testpassword"},ue={urls:"turn:turn.telnyx.com:3478?transport=tcp",username:"testuser",credential:"testpassword"},pe={urls:"turns:turn2.telnyx.com:443",username:"testuser",credential:"testpassword"},ge=[de,le,...[he,ue],pe],ve=[{urls:"stun:stundev.telnyx.com:3478"},le,{urls:"turn:turndev.telnyx.com:3478?transport=udp",username:"testuser",credential:"testpassword"},{urls:"turn:turndev.telnyx.com:3478?transport=tcp",username:"testuser",credential:"testpassword"},{urls:"turns:turndev.telnyx.com:443",username:"testuser",credential:"testpassword"}],me={GOOGLE_STUN:le,TELNYX_STUN:de,TELNYX_TURN_UDP_3478:he,TELNYX_TURN_TCP_3478:ue,TELNYX_TURNS_TCP_443:pe};var fe;!function(e){e.SocketOpen="telnyx.socket.open",e.SocketClose="telnyx.socket.close",e.SocketError="telnyx.socket.error",e.SocketMessage="telnyx.socket.message",e.SpeedTest="telnyx.internal.speedtest",e.SocketActivity="telnyx.internal.socketActivity",e.Ready="telnyx.ready",e.Error="telnyx.error",e.Warning="telnyx.warning",e.Notification="telnyx.notification",e.StatsFrame="telnyx.stats.frame",e.StatsReport="telnyx.stats.report",e.Messages="telnyx.messages",e.Calls="telnyx.calls",e.MediaError="telnyx.rtc.mediaError",e.PeerConnectionFailureError="telnyx.rtc.peerConnectionFailureError",e.PeerConnectionSignalingStateClosed="telnyx.rtc.peerConnectionSignalingStateClosed",e.AIConversationMessage="telnyx.ai.conversation"}(fe||(fe={}));const _e={40001:{name:"SDP_CREATE_OFFER_FAILED",message:"Failed to create call offer",description:"The browser was unable to generate a local SDP offer. This typically indicates a WebRTC API error or invalid media constraints.",causes:["Browser WebRTC API error","Missing or invalid media constraints"],solutions:["Check getUserMedia permissions","Verify ICE server configuration"],fatal:!0},40002:{name:"SDP_CREATE_ANSWER_FAILED",message:"Failed to answer the call",description:"The browser was unable to generate a local SDP answer. The remote offer may be invalid or the browser state inconsistent.",causes:["Browser WebRTC API error","Invalid remote SDP offer"],solutions:["Retry the call","Check browser WebRTC compatibility"],fatal:!0},40003:{name:"SDP_SET_LOCAL_DESCRIPTION_FAILED",message:"Failed to apply local call settings",description:"setLocalDescription() was rejected by the browser. The generated SDP may be malformed or the browser state may be inconsistent.",causes:["Malformed SDP","Browser state inconsistency"],solutions:["Retry the call"],fatal:!0},40004:{name:"SDP_SET_REMOTE_DESCRIPTION_FAILED",message:"Failed to apply remote call settings",description:"setRemoteDescription() was rejected by the browser. The remote SDP may be malformed or contain unsupported codecs.",causes:["Malformed remote SDP","Browser codec mismatch"],solutions:["Retry the call","Check codec configuration"],fatal:!0},40005:{name:"SDP_SEND_FAILED",message:"Failed to send call data to server",description:"The Invite or Answer message could not be delivered via the signaling WebSocket. The connection may have been lost.",causes:["WebSocket connection lost","Server error"],solutions:["Check network connectivity","Retry the call"],fatal:!0},42001:{name:"MEDIA_MICROPHONE_PERMISSION_DENIED",message:"Microphone access denied",description:"The user or operating system denied microphone permission. The browser permission prompt was dismissed or OS-level access is disabled.",causes:["User denied browser permission prompt","OS-level microphone access disabled"],solutions:["Ask user to grant microphone permission in browser settings"],fatal:!0},42002:{name:"MEDIA_DEVICE_NOT_FOUND",message:"No microphone found",description:"The requested audio input device is not available. No microphone is connected, the device was disconnected, or an invalid deviceId was specified.",causes:["No microphone connected","Device was disconnected","Invalid deviceId"],solutions:["Check that a microphone is connected","Select a valid audio input device"],fatal:!0},42003:{name:"MEDIA_GET_USER_MEDIA_FAILED",message:"Failed to access microphone",description:"getUserMedia() was rejected for an unexpected reason. The device may be in use by another application or the browser encountered an internal error.",causes:["Browser error","Device in use by another application"],solutions:["Close other applications using the microphone","Retry"],fatal:!0},44001:{name:"HOLD_FAILED",message:"Failed to hold the call",description:"The server rejected or did not respond to the hold request. The WebSocket connection may have been lost during the operation.",causes:["Server error","WebSocket connection lost during hold"],solutions:["Retry the hold operation","Check network connectivity"],fatal:!1},44002:{name:"INVALID_CALL_PARAMETERS",message:"Invalid call parameters",description:"The call could not be initiated because required parameters are missing or invalid. For example, no destination number was provided to newCall().",causes:["Missing destinationNumber in call options","Invalid or empty call parameters"],solutions:["Provide a valid destinationNumber when calling newCall()","Check the call options object for required fields"],fatal:!0},44003:{name:"BYE_SEND_FAILED",message:"Failed to hang up cleanly",description:"The hangup signal could not be delivered to the server. The call was terminated locally but the server may not be aware.",causes:["WebSocket connection lost before BYE sent"],solutions:["No action needed — call is terminated locally","Check network connectivity"],fatal:!1},44004:{name:"SUBSCRIBE_FAILED",message:"Failed to subscribe to call events",description:"The Verto subscribe request for the call channel failed. This may prevent receiving call state updates from the server.",causes:["WebSocket connection lost during subscribe","Server rejected the subscription request"],solutions:["Check network connectivity","Retry the call"],fatal:!1},44005:{name:"PEER_CLOSED_DURING_INIT",message:"Call was closed during setup",description:"The PeerConnection was closed (e.g. by hangup()) while peer.init() was still running. This is a race condition: an async operation such as setRemoteDescription, getUserMedia, or the media recovery flow yielded control, and close() ran during that gap. The init() cannot continue because the underlying RTCPeerConnection has been destroyed.",causes:["call.hangup() or call.close() was called while the call was still setting up","A WebSocket Bye message arrived during getUserMedia prompt or SDP negotiation","User clicked hangup/decline before media permissions were granted"],solutions:["This is expected if the user intentionally hung up during setup — no action needed","If this happens frequently without user action, check for automatic hangup triggers that may fire too early"],fatal:!0},45001:{name:"WEBSOCKET_CONNECTION_FAILED",message:"Unable to connect to server",description:"The WebSocket connection to the signaling server could not be established. The server may be unreachable, the URL may be incorrect, or a firewall may be blocking the connection.",causes:["Server unreachable","Incorrect WebSocket URL","Firewall blocking WebSocket connections","Network interruption"],solutions:["Check network connectivity","Verify the signaling server URL","Ensure WebSocket connections are not blocked by a firewall"],fatal:!0},45002:{name:"WEBSOCKET_ERROR",message:"Connection to server lost",description:"An error occurred on the WebSocket connection after it was established. The connection may have been dropped due to network issues or server-side closure.",causes:["Network interruption","Server closed the connection","Idle timeout"],solutions:["Check network connectivity","SDK will attempt automatic reconnection if configured"],fatal:!1},45003:{name:"RECONNECTION_EXHAUSTED",message:"Unable to reconnect to server",description:"All automatic reconnection attempts have been exhausted. The SDK tried to re-establish the WebSocket connection multiple times but failed on every attempt.",causes:["Prolonged network outage","Server unreachable","Firewall or proxy blocking reconnection"],solutions:["Check network connectivity","Call client.disconnect() and client.connect() to manually retry","Notify the user that the connection was lost"],fatal:!0},45004:{name:"GATEWAY_FAILED",message:"Gateway connection failed",description:"The upstream gateway reported a FAILED, FAIL_WAIT, or TIMEOUT state. The signaling server could not establish or maintain a connection to the gateway. When autoReconnect is disabled, this is immediately fatal. When enabled, the SDK will retry until RECONNECTION_EXHAUSTED.",causes:["Gateway down or unreachable","Server-side infrastructure issue","Network partition between signaling server and gateway"],solutions:["Wait for automatic reconnection (if autoReconnect is enabled)","Call client.disconnect() and client.connect() to manually retry","Check Telnyx service status"],fatal:!1},46001:{name:"LOGIN_FAILED",message:"Authentication failed",description:"The login request was rejected by the server. The credentials may be invalid, expired, or the account may be suspended.",causes:["Invalid credentials (username/password or token)","Expired authentication token","Account suspended or disabled"],solutions:["Verify credentials","Generate a new authentication token","Check account status"],fatal:!0},46002:{name:"INVALID_CREDENTIALS",message:"Invalid credential parameters",description:"The SDK rejected the login options before sending any request to the server. This is an internal client-side validation guard — the credentials object is missing required fields or has an invalid structure. No network request was made.",causes:["Missing login and password fields","Missing or malformed authentication token","Invalid combination of credential fields in the options object"],solutions:["Provide valid login/password or a valid authentication token","Check the TelnyxRTC constructor options against the documentation","Ensure the credential object matches one of the supported auth modes (credentials, token, or anonymous)"],fatal:!0},46003:{name:"AUTHENTICATION_REQUIRED",message:"Authentication required",description:"The server rejected a request because the session is not authenticated. This can happen when the client sends a message (e.g. Invite, Subscribe, or Ping) before login completes, after a token expires mid-session, or after the server drops the authenticated state for any reason.",causes:["Message sent before login completed","Authentication token expired during the session","Server-side session was invalidated","WebSocket reconnected but re-authentication did not complete"],solutions:["Ensure the client is fully logged in before sending messages","Re-authenticate using client.login() with fresh credentials","Listen for telnyx.ready before making calls or sending requests"],fatal:!1},47001:{name:"ICE_RESTART_FAILED",message:"ICE restart failed",description:"The ICE restart Modify request could not be sent or the server returned an error. The media path could not be recovered via ICE restart.",causes:["WebSocket connection lost during ICE restart","Server rejected the Modify request","Timeout waiting for server response"],solutions:["The call may recover via WebSocket reconnect + Attach","If the call does not recover, hang up and retry"],fatal:!1},48001:{name:"NETWORK_OFFLINE",message:"Device is offline",description:"The browser reported that the device has lost network connectivity (navigator.onLine === false). All WebSocket and media connections will fail until the network is restored.",causes:["Wi-Fi or ethernet disconnected","Airplane mode enabled","Network interface went down"],solutions:["Check network connectivity","Reconnect to Wi-Fi or ethernet","Disable airplane mode"],fatal:!1},48501:{name:"SESSION_NOT_REATTACHED",message:"Active call lost after reconnect",description:"The WebSocket reconnected successfully but the server did not reattach the active call session. The server no longer knows about the call, so any subsequent call-control operation (hangup, hold, etc.) will fail with CALL_DOES_NOT_EXIST. The call is unrecoverable and must be terminated locally.",causes:["Server-side session expired during the disconnection window","Reconnect token was invalidated","Backend restarted or lost in-memory call state"],solutions:["Terminate the local call and notify the user","Start a new call","Investigate why the session was not preserved on the server"],fatal:!0},49001:{name:"UNEXPECTED_ERROR",message:"An unexpected error occurred",description:"An error was thrown that does not match any known SDK error category. This is a catch-all for unclassified failures.",causes:["Unknown or unhandled error condition"],solutions:["Check the originalError property for the underlying cause","Report the issue if it persists"],fatal:!0}},ye={31001:{name:"HIGH_RTT",message:"High network latency detected",description:"Round-trip time (RTT) exceeded the threshold for multiple consecutive samples. High latency causes perceptible audio delays.",causes:["Poor network connection","Geographic distance to media server","Network congestion"],solutions:["Check network connectivity","Use a wired connection instead of Wi-Fi","Close bandwidth-heavy applications"]},31002:{name:"HIGH_JITTER",message:"High jitter detected",description:"Jitter (variability in packet arrival time) exceeded the threshold for multiple consecutive samples. High jitter causes crackling and choppy audio.",causes:["Network congestion","Unstable Wi-Fi connection","Overloaded network equipment"],solutions:["Use a wired connection instead of Wi-Fi","Close bandwidth-heavy applications","Check network equipment"]},31003:{name:"HIGH_PACKET_LOSS",message:"High packet loss detected",description:"Packet loss exceeded the threshold for multiple consecutive samples. High packet loss causes choppy audio or dropped calls.",causes:["Network congestion","Unstable connection","Firewall or QoS misconfiguration"],solutions:["Check network connectivity","Use a wired connection","Contact network administrator"]},31004:{name:"LOW_MOS",message:"Low call quality score",description:"Mean Opinion Score (MOS) dropped below the acceptable threshold for multiple consecutive samples. This is a composite indicator of overall call quality.",causes:["Combination of high latency, jitter, and/or packet loss","Poor network conditions"],solutions:["Check network connectivity","Use a wired connection","Close bandwidth-heavy applications"]},31005:{name:"LOW_LOCAL_AUDIO",message:"Low local microphone audio detected",description:"Local outbound audio level stayed below the acceptable threshold before the microphone produced real audio, or stayed silent for a long continuous window after audio was confirmed. This may indicate that the microphone is not capturing enough audio even while RTP is being sent.",causes:["Microphone input level is too low","Wrong microphone selected","Microphone is obstructed or too far from the speaker","Operating system input gain is muted or very low"],solutions:["Check the selected microphone","Increase microphone input gain","Move closer to the microphone","Verify the microphone is not muted at the operating system or hardware level"]},31006:{name:"LOW_INBOUND_AUDIO",message:"Low inbound audio detected",description:"Inbound (remote) audio level stayed below the acceptable threshold for multiple consecutive stats intervals while RTP packets continued to flow. This may indicate the remote party is sending silence or comfort-noise (e.g. one-way audio caused by a media bridge issue), as opposed to LOW_BYTES_RECEIVED which fires when no bytes arrive at all.",causes:["Remote party microphone is muted or capturing very low audio","Media bridge or PBX is injecting comfort-noise/silence instead of forwarding real audio","One-way audio where RTP flows but content is silent (server-side media issue)","Remote party is on hold or not speaking"],solutions:["Verify the remote party is not muted and is actively speaking","Check the media bridge / PBX for comfort-noise injection or transcoding issues","Inspect PCAP RTP payload uniqueness to distinguish real audio from comfort-noise","If the issue persists, report the call for server-side media investigation"]},32001:{name:"LOW_BYTES_RECEIVED",message:"No audio data received",description:"No bytes have been received from the remote party for multiple consecutive seconds. This may indicate a network interruption or remote-side issue.",causes:["Network interruption","Remote party microphone issue","Firewall blocking inbound media"],solutions:["Check network connectivity","Ask remote party to check their microphone","Check firewall rules for media ports"]},32002:{name:"LOW_BYTES_SENT",message:"No audio data being sent",description:"No bytes have been sent for multiple consecutive seconds. This may indicate a local microphone issue or network interruption.",causes:["Microphone muted or disconnected","Network interruption","Local media track ended"],solutions:["Check that the microphone is not muted","Verify the microphone is still connected","Check network connectivity"]},32003:{name:"RECORDING_UNAVAILABLE",message:"Call recording is not available in this browser",description:"Call recording was enabled (enableCallRecording is true), but the browser does not support MediaStreamTrackProcessor (required to capture raw audio PCM). Recording is disabled for this call; the call proceeds normally. Currently affects Firefox and older Chromium (< 94).",causes:["Browser does not implement MediaStreamTrackProcessor (Firefox, Safari)","Chromium version older than 94","Recording enabled on an unsupported platform"],solutions:["Use a recent Chromium-based browser (Chrome 94+, Edge 94+) to capture recordings","Disable enableCallRecording if recording is not required for this deployment","See the enableCallRecording JSDoc for platform support details"]},32004:{name:"RECORDING_BUFFER_OVERFLOW",message:"Call recording buffer overflow — oldest packets dropped",description:"The in-memory call recording buffer reached its maxBufferBytes cap before the next scheduled flush. The oldest captured RTP packets were dropped to keep memory bounded. This indicates the flush interval is too long for the call audio rate, or the upload endpoint is slow/unreachable. The recording continues with the remaining (newer) packets.",causes:["Flush interval (callRecordingFlushIntervalMs) is larger than the buffer can hold at the current audio rate","Upload endpoint (/call_recording) is slow or unreachable, so intermediate flushes back up","A very long call with high sample rate filling the buffer between flushes"],solutions:["Reduce callRecordingFlushIntervalMs so flushes happen more frequently","Increase callRecordingMaxBufferBytes if memory headroom allows","Check the /call_recording endpoint health and network path to voice-sdk-proxy"]},33001:{name:"ICE_CONNECTIVITY_LOST",message:"Connection interrupted",description:"The ICE connection transitioned to the disconnected state. The previously selected connection path was lost and renegotiation may be required. The connection may recover automatically.",causes:["Temporary network interruption","Network interface change (e.g. Wi-Fi to cellular)","NAT rebinding"],solutions:["Wait for automatic recovery","Check network connectivity"]},33002:{name:"ICE_GATHERING_TIMEOUT",message:"ICE gathering timed out",description:"ICE candidate gathering did not complete within the safety timeout. This is typically caused by network restrictions blocking STUN/TURN. The call may still succeed if candidates arrive late.",causes:["Firewall blocking STUN/TURN","Network unreachable","STUN/TURN server not responding"],solutions:["Check STUN/TURN server reachability","Ensure UDP traffic is not blocked","Try forceRelayCandidate option"]},33003:{name:"ICE_GATHERING_EMPTY",message:"No ICE candidates gathered",description:"No ICE candidates were gathered after sending the initial SDP. This may indicate a firewall blocking all STUN/TURN traffic or no available network interface.",causes:["Firewall blocking all STUN/TURN traffic","No network interface available","VPN blocking UDP"],solutions:["Check STUN/TURN server reachability","Ensure UDP traffic is not blocked","Use forceRelayCandidate option"]},33004:{name:"PEER_CONNECTION_FAILED",message:"Connection failed",description:"RTCPeerConnection entered the failed state. This is a recoverable condition — the SDK may attempt ICE restart or the connection may recover. If it does not recover, the call will eventually be terminated.",causes:["ICE failure","DTLS handshake failure","Prolonged network interruption"],solutions:["Wait for automatic recovery","Check network connectivity","Verify TURN server credentials"]},33005:{name:"ONLY_HOST_ICE_CANDIDATES",message:"Only local network candidates available",description:"ICE gathering completed but only host (local network) candidates were collected — no server-reflexive (srflx) or relay (turn) candidates were found. This typically means the STUN/TURN servers are unreachable, which will prevent connections outside the local network.",causes:["STUN/TURN servers unreachable","Firewall blocking UDP traffic to STUN/TURN servers","Incorrect TURN server configuration or credentials","Restrictive corporate network or VPN"],solutions:["Verify STUN/TURN server URLs and credentials","Ensure UDP traffic to STUN/TURN ports is not blocked","Check firewall or VPN settings","Try using TCP-based TURN as a fallback"]},33006:{name:"ANSWER_WHILE_PEER_ACTIVE",message:"Call answer ignored because a peer connection is already active",description:"answer() was called on a call that already has an active or connecting peer connection. Creating a second peer connection for the same call would duplicate media negotiation, confuse the remote party, and break call reporting. This is typically caused by application code invoking answer() multiple times (e.g. from multiple event handlers).",causes:["Application called answer() twice on the same call object","Multiple click handlers or event listeners triggering answer()"],solutions:["Ensure answer() is called only once per call","Disable the answer button after the first click","Check that answer() is not invoked from multiple event handlers"]},33008:{name:"ICE_CANDIDATE_PAIR_CHANGED",message:"ICE candidate pair changed mid-call",description:"The selected ICE candidate pair changed during an active call. This indicates a network path shift — for example, a Wi-Fi to cellular handoff, a NAT rebinding, or a relay fallback. The call may continue normally, but the path change can briefly affect audio quality.",causes:["Network interface change (e.g. Wi-Fi to cellular)","NAT rebinding or IP address change","Previous candidate pair failed and ICE selected an alternative","Network topology change"],solutions:["Monitor for audio quality degradation after the path change","Check network stability if changes are frequent","Verify TURN server configuration for relay fallback"]},33007:{name:"DUPLICATE_INBOUND_ANSWER",message:"Call answer ignored because another inbound call is already being answered",description:"answer() was called on an inbound call while another inbound call is already answering or active in this JavaScript runtime. Answering both legs can trigger SIP 486 USER_BUSY / LOSE_RACE when duplicate WebSocket registrations receive the same incoming call.",causes:["Multiple TelnyxRTC instances in the same page","Application code recreating a client without disconnecting the previous instance","Duplicate inbound call notifications produced by duplicate WebSocket registrations"],solutions:["Keep a single active TelnyxRTC instance for inbound call handling","Call disconnect() before replacing an SDK client instance","Only call answer() for one inbound call notification at a time"]},34001:{name:"TOKEN_EXPIRING_SOON",message:"Authentication token expiring soon",description:"The authentication token is approaching its expiration time. If the token expires the connection will be lost and calls will fail. A new token should be generated before expiration.",causes:["Token was issued with a limited lifetime"],solutions:["Generate a new authentication token","Reconnect with fresh credentials before the token expires"]},36003:{name:"SIGNALING_RECOVERY_REQUIRED",message:"Signaling recovery required",description:"The signaling (WebSocket) path has been detected as unhealthy and the SDK will force-close the socket and reconnect. The source field in the warning payload indicates what triggered the recovery (probe, request, peer_failure, or no_rtp). Active calls will be recovered via reattach after reconnection.",causes:["WebSocket probe timed out with no response","Critical signaling request timed out","Peer/media failure detected while signaling is also unhealthy"],solutions:["The SDK will automatically reconnect and recover the call","Check for network interface changes or interruptions","Verify firewall/NAT timeout settings"]},36004:{name:"MEDIA_RECOVERY_REQUIRED",message:"Media recovery required",description:"The peer connection or media flow has been detected as unhealthy while signaling is healthy. The SDK will attempt ICE restart to recover the media path. No socket reconnection is needed.",causes:["ICE connection state changed to failed","RTCPeerConnection state changed to failed","No RTP packets/bytes received while media should be active"],solutions:["The SDK will automatically attempt ICE restart","Check network connectivity and ICE candidate availability","Verify TURN server configuration"]},36005:{name:"RECONNECTION_FAILED_WITH_NO_AUTO_RECONNECT",message:"Reconnection failed — auto-reconnect disabled",description:"The WebSocket was closed and auto-reconnect is disabled, so the SDK will not attempt to reconnect. This typically occurs after the user called disconnect() or after reconnection attempts were exhausted.",causes:["Auto-reconnect was disabled by the application","Reconnection attempts were previously exhausted","The session was intentionally disconnected"],solutions:["Call connect() manually to re-establish the session","Check if disconnect() was called intentionally","Review maxReconnectAttempts configuration"]},33009:{name:"AUDIO_INPUT_DEVICE_CHANGE_SKIPPED",message:"Audio input device change skipped",description:"The SDK could not change the microphone because the active peer connection has no audio RTP sender to replace. The existing local media and mute state were left unchanged.",causes:["The call was created without an audio sender","The peer connection was not ready when setAudioInDevice was called","The call is already ending or the local media sender was removed"],solutions:["Retry after the call is active and local media is attached","Verify the call was started with audio enabled","Inspect call state and peer connection sender availability"]},33010:{name:"MULTIPLE_ACTIVE_CALLS_DETECTED",message:"Multiple active calls detected in one SDK session",description:"A new call was created or received while another call is still active (ringing, answering, active, held, or recovering) in the same SDK session. This may be intentional for some applications (e.g. call waiting, transfer) but is often abnormal and makes call reports and application behavior harder to reason about. The new call proceeds normally — this warning is diagnostic only.",causes:["Application created an outbound call while another call is active","An inbound call arrived while another call is already active","Application did not hang up the previous call before starting a new one","Call waiting or multi-call scenario (may be intentional)"],solutions:["Verify this is the expected behavior for your application","Ensure the previous call is hung up before creating a new one if only one call is expected","Use call.hold() before starting a new call if needed","Check the warning payload for call IDs to correlate which calls are involved"]},33011:{name:"SHARED_REMOTE_ELEMENT_OVERWRITE",message:"Remote media element overwritten by another call",description:"A new MediaStream was attached to an HTML media element (audio/video) that already held a different MediaStream from another active call. The SDK overwrote the existing stream (last-writer-wins), which disrupts the other call remote media playout. This happens when two concurrent calls share a single remoteElement instead of each having its own. Use a per-call remoteElement (client.newCall({ remoteElement }) or call.answer({ remoteElement })) so each call owns a distinct element.",causes:["Two concurrent calls share one remoteElement (legacy single-element app)","Application did not pass a per-call remoteElement to newCall() or answer()","A second inbound call rang into a session using one session-level remoteElement"],solutions:["Pass a distinct remoteElement per call via client.newCall({ remoteElement })","For inbound calls, override at answer time via call.answer({ remoteElement })","Give each call its own <audio>/<video> element so attach/detach lifecycles are independent"]},35002:{name:"UNKNOWN_REATTACHED_SESSION",message:"Unknown reattach session after reconnect",description:"The WebSocket reconnected successfully and the server sent an Attach message for a session that does not match any active SDK call. The unknown Attach is ACK'd and ignored.",causes:["Server sent an Attach for a call that no longer exists in the SDK","Multiple Attach messages arrived and only the first was recovered","Race condition between reconnection and new inbound call"],solutions:["Check application logic for multiple simultaneous calls","Inspect the Attach callID in the warning payload for details","If a call should be active, start a new call manually"]}};function be(e,t){const i=ye[e];return{code:e,name:i.name,message:t||i.message,description:i.description,causes:[...i.causes],solutions:[...i.solutions]}}class Se extends Error{constructor(e){super(e.message||`[${e.code}] ${e.name}`),this.name=e.name,this.code=e.code,this.description=e.description,this.causes=e.causes,this.solutions=e.solutions,this.originalError=e.originalError,this.fatal=e.fatal,Object.setPrototypeOf(this,Se.prototype)}toJSON(){return{code:this.code,name:this.name,description:this.description,message:this.message,causes:this.causes,solutions:this.solutions,originalError:this.originalError,fatal:this.fatal}}}function Ie(e){return!0===e.recoverable}function Ce(e){if(e instanceof DOMException){if("NotAllowedError"===e.name)return v;if("NotFoundError"===e.name||"OverconstrainedError"===e.name)return m}return f}function Ee(e,t,i,n){const s=_e[e],o=t instanceof Error?t:void 0!==t?new Error(String(t)):void 0;return new Se({code:e,name:s.name,description:s.description,message:i||s.message,causes:[...s.causes],solutions:[...s.solutions],originalError:o,fatal:null!=n?n:s.fatal})}class we extends Error{constructor(e,t,i=""){super(`Signaling request timed out (id=${e}, method=${i||"unknown"}, timeout=${t}ms)`),this.name="RequestTimeoutError",this.requestId=e,this.timeoutMs=t,this.method=i}}class ke extends Error{constructor(e,t,i){super(`Stale request cancelled (id=${e}, gen=${t}, current=${i})`),this.name="StaleRequestError",this.requestId=e,this.staleGeneration=t,this.currentGeneration=i}}var Te="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function Re(e,t){return e(t={exports:{}},t.exports),t.exports}var Ae=Re((function(e){var t,i;t=Te,i=function(){var e=function(){},t="undefined",i=typeof window!==t&&typeof window.navigator!==t&&/Trident\/|MSIE /.test(window.navigator.userAgent),n=["trace","debug","info","warn","error"];function s(e,t){var i=e[t];if("function"==typeof i.bind)return i.bind(e);try{return Function.prototype.bind.call(i,e)}catch(t){return function(){return Function.prototype.apply.apply(i,[e,arguments])}}}function o(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function r(t,i){for(var s=0;s<n.length;s++){var o=n[s];this[o]=s<t?e:this.methodFactory(o,t,i)}this.log=this.debug}function a(e,i,n){return function(){typeof console!==t&&(r.call(this,i,n),this[e].apply(this,arguments))}}function c(n,r,c){return function(n){return"debug"===n&&(n="log"),typeof console!==t&&("trace"===n&&i?o:void 0!==console[n]?s(console,n):void 0!==console.log?s(console,"log"):e)}(n)||a.apply(this,arguments)}function l(e,i,s){var o,a=this;i=null==i?"WARN":i;var l="loglevel";function d(){var e;if(typeof window!==t&&l){try{e=window.localStorage[l]}catch(e){}if(typeof e===t)try{var i=window.document.cookie,n=i.indexOf(encodeURIComponent(l)+"=");-1!==n&&(e=/^([^;]+)/.exec(i.slice(n))[1])}catch(e){}return void 0===a.levels[e]&&(e=void 0),e}}"string"==typeof e?l+=":"+e:"symbol"==typeof e&&(l=void 0),a.name=e,a.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},a.methodFactory=s||c,a.getLevel=function(){return o},a.setLevel=function(i,s){if("string"==typeof i&&void 0!==a.levels[i.toUpperCase()]&&(i=a.levels[i.toUpperCase()]),!("number"==typeof i&&i>=0&&i<=a.levels.SILENT))throw"log.setLevel() called with invalid level: "+i;if(o=i,!1!==s&&function(e){var i=(n[e]||"silent").toUpperCase();if(typeof window!==t&&l){try{return void(window.localStorage[l]=i)}catch(e){}try{window.document.cookie=encodeURIComponent(l)+"="+i+";"}catch(e){}}}(i),r.call(a,i,e),typeof console===t&&i<a.levels.SILENT)return"No console available for logging"},a.setDefaultLevel=function(e){i=e,d()||a.setLevel(e,!1)},a.resetLevel=function(){a.setLevel(i,!1),function(){if(typeof window!==t&&l){try{return void window.localStorage.removeItem(l)}catch(e){}try{window.document.cookie=encodeURIComponent(l)+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC"}catch(e){}}}()},a.enableAll=function(e){a.setLevel(a.levels.TRACE,e)},a.disableAll=function(e){a.setLevel(a.levels.SILENT,e)};var h=d();null==h&&(h=i),a.setLevel(h,!1)}var d=new l,h={};d.getLogger=function(e){if("symbol"!=typeof e&&"string"!=typeof e||""===e)throw new TypeError("You must supply a name when creating a logger.");var t=h[e];return t||(t=h[e]=new l(e,d.getLevel(),d.methodFactory)),t};var u=typeof window!==t?window.log:void 0;return d.noConflict=function(){return typeof window!==t&&window.log===d&&(window.log=u),d},d.getLoggers=function(){return h},d.default=d,d},e.exports?e.exports=i():t.log=i()}));const Oe={debug:0,info:1,warn:2,error:3};class De{constructor(e={}){var t,i,n;this.buffer=[],this.isCapturing=!1,this.options={enabled:null!==(t=e.enabled)&&void 0!==t&&t,level:null!==(i=e.level)&&void 0!==i?i:"debug",maxEntries:null!==(n=e.maxEntries)&&void 0!==n?n:1e3}}start(){this.options.enabled&&(this.isCapturing=!0,this.buffer=[])}stop(){this.isCapturing=!1}addEntry(e,t,i){if(!this.isCapturing||!this.options.enabled)return;if(Oe[e]<Oe[this.options.level])return;const n=Object.assign({timestamp:(new Date).toISOString(),level:e,message:t},i&&Object.keys(i).length>0?{context:i}:{});this.buffer.push(n),this.buffer.length>this.options.maxEntries&&this.buffer.shift()}getLogs(){return[...this.buffer]}getLogCount(){return this.buffer.length}drain(){const e=this.buffer;return this.buffer=[],e}clear(){this.buffer=[]}isActive(){return this.isCapturing}isEnabled(){return this.options.enabled}}let Ne=null;const Le=Ae.getLogger("telnyx"),Me={trace:0,debug:1,info:2,warn:3,error:4};let Pe=Me.info;function xe(e){if(null==e)return e;if("object"!=typeof e)return e;try{const t=JSON.stringify(e),i=JSON.parse(t);if("object"==typeof i&&null!==i&&Object.keys(i).length>1)return i}catch(e){}const t={};for(const i in e)try{const n=e[i];if("function"==typeof n)continue;if("object"==typeof n&&null!==n)try{t[i]=JSON.parse(JSON.stringify(n))}catch(e){t[i]=String(n)}else t[i]=n}catch(e){}return Object.keys(t).length>0?t:{value:String(e)}}const Ue=Le.methodFactory;Le.methodFactory=(e,t,i)=>{const n=Ue(e,t,i);return function(...t){if(Me[e]>=Pe){const e=[(new Date).toISOString().replace("T"," ").replace("Z",""),"-"];for(const i of t)e.push(i);n(...e)}const i=Ne;if(null==i?void 0:i.isActive()){const[n,...s]=t,o="string"==typeof n?n:JSON.stringify(n);let r;s.length>0&&(r=1===s.length&&"object"==typeof s[0]&&null!==s[0]?xe(s[0]):{args:s.map(xe)}),i.addEntry(e,o,r)}}},Le.setLevel("debug",!1);const Fe=e=>{const[t,i,n,s,o,r]=e;let a={};try{a=JSON.parse(o.replace(/ID"/g,'Id"'))}catch(e){Le.warn("Verto LA invalid media JSON string:",o)}return{participantId:Number(t),participantNumber:i,participantName:n,codec:s,media:a,participantData:r}},$e=e=>{if("string"!=typeof e)return e;try{return JSON.parse(e)}catch(t){return e}},je=e=>e instanceof Function||"function"==typeof e,Be=e=>"object"==typeof document&&"getElementById"in document?"string"==typeof e?document.getElementById(e)||null:"function"==typeof e?e():e instanceof HTMLMediaElement?e:null:null,We=/^(ws|wss):\/\//,He=(e,t=null)=>{const{result:i={},error:n}=e;if(n)return{error:n};const{result:s=null}=i;if(null===s)return null!==t&&(i.node_id=t),{result:i};const{code:o=null,node_id:r=null,result:a=null}=s;return o&&"200"!==o?{error:s}:a?He(a,r):{result:s}},Ge=({login:e,passwd:t,password:i,login_token:n})=>Boolean(e&&(t||i)||n),Ve=({anonymous_login:e})=>Boolean(e)&&Boolean(e.target_id)&&Boolean(e.target_type),qe=e=>{var t,i,n,s,o,r;let a="",c="";(null===(i=null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.params)||void 0===i?void 0:i.state)&&(a=null===(s=null===(n=null==e?void 0:e.result)||void 0===n?void 0:n.params)||void 0===s?void 0:s.state),(null===(o=null==e?void 0:e.params)||void 0===o?void 0:o.state)&&(c=null===(r=null==e?void 0:e.params)||void 0===r?void 0:r.state);return a||c};function Ye({debounceTime:e}){let t,i;return{promise:new Promise(((n,s)=>{t=e?Ke(n,e):n,i=s})),resolve:t,reject:i}}const Ke=(e,t)=>{let i;return(...n)=>{clearTimeout(i),i=window.setTimeout((()=>{e(...n)}),t)}},Je="telnyx-voice-sdk-id",ze="telnyx-voice-sdk-session-id",Qe="telnyx-voice-sdk-session-id-stored-at",Xe="telnyx-voice-sdk-active-calls",Ze=9e4;function et(e=Date.now()){const t=function(){const e=Number(sessionStorage.getItem(Qe));return Number.isFinite(e)?e:null}();return null!==t&&e-t<=Ze}function tt(){return sessionStorage.getItem(Je)}function it(e,t=Date.now()){sessionStorage.setItem(ze,e),sessionStorage.setItem(Qe,String(t))}function nt(){sessionStorage.removeItem(Je),sessionStorage.removeItem(ze),sessionStorage.removeItem(Qe)}function st(){!function(e){try{sessionStorage.removeItem(e)}catch(t){Le.debug(`safeRemoveItem('${e}') failed: ${t instanceof Error?t.message:String(t)}`)}}(Xe)}function ot(e=Date.now()){const t=function(e){try{return sessionStorage.getItem(e)}catch(t){return Le.debug(`safeGetItem('${e}') failed: ${t instanceof Error?t.message:String(t)}`),null}}(Xe);if(!t)return null;try{const i=JSON.parse(t);if(!i||"object"!=typeof i||!Array.isArray(i.calls))return Le.debug("Active-calls recovery marker payload was malformed — discarded."),st(),null;const n=Number(i.storedAt);return!Number.isFinite(n)||e-n>9e5?(Le.debug("Active-calls recovery marker was stale or had an invalid timestamp — discarded."),st(),null):0===i.calls.length?(Le.debug("Active-calls recovery marker had no call records — discarded."),st(),null):i}catch(e){return Le.debug(`Active-calls recovery marker JSON parse failed — discarded: ${e instanceof Error?e.message:String(e)}`),st(),null}}function rt(e,t,i=Date.now()){if(!Array.isArray(e)||0===e.length)return void st();const n={sessionId:t,calls:e,storedAt:i};!function(e,t){try{sessionStorage.setItem(e,t)}catch(t){Le.info(`safeSetItem('${e}') failed: ${t instanceof Error?t.message:String(t)}`)}}(Xe,JSON.stringify(n))}var at,ct,lt;!function(e){e.Offer="offer",e.Answer="answer"}(at||(at={})),function(e){e.Inbound="inbound",e.Outbound="outbound"}(ct||(ct={})),function(e){e.Invite="telnyx_rtc.invite",e.Attach="telnyx_rtc.attach",e.Answer="telnyx_rtc.answer",e.Info="telnyx_rtc.info",e.Candidate="telnyx_rtc.candidate",e.EndOfCandidates="telnyx_rtc.endOfCandidates",e.Display="telnyx_rtc.display",e.Media="telnyx_rtc.media",e.Event="telnyx_rtc.event",e.Bye="telnyx_rtc.bye",e.Punt="telnyx_rtc.punt",e.Broadcast="telnyx_rtc.broadcast",e.Subscribe="telnyx_rtc.subscribe",e.Unsubscribe="telnyx_rtc.unsubscribe",e.ClientReady="telnyx_rtc.clientReady",e.Modify="telnyx_rtc.modify",e.Ringing="telnyx_rtc.ringing",e.GatewayState="telnyx_rtc.gatewayState",e.Ping="telnyx_rtc.ping",e.Pong="telnyx_rtc.pong"}(lt||(lt={}));const dt={generic:"event",[lt.Display]:"participantData",[lt.Attach]:"participantData",conferenceUpdate:"conferenceUpdate",callUpdate:"callUpdate",vertoClientReady:"vertoClientReady",userMediaError:"userMediaError",peerConnectionFailureError:"peerConnectionFailureError",signalingStateClosed:"signalingStateClosed"},ht={invalidCredentialsOptions:"InvalidCredentialsOptions"},ut=24e4,pt=8e6,gt={destinationNumber:"",remoteCallerName:"Outbound Call",remoteCallerNumber:"",callerName:"",callerNumber:"",audio:!0,useStereo:!1,debug:!1,debugOutput:"socket",attach:!1,screenShare:!1,userVariables:{},mediaSettings:{useSdpASBandwidthKbps:!1,sdpASBandwidthKbps:0},mutedMicOnStart:!1,prefetchIceCandidates:!0};var vt,mt,ft,_t,yt,bt;!function(e){e[e.New=0]="New",e[e.Requesting=1]="Requesting",e[e.Trying=2]="Trying",e[e.Recovering=3]="Recovering",e[e.Ringing=4]="Ringing",e[e.Answering=5]="Answering",e[e.Early=6]="Early",e[e.Active=7]="Active",e[e.Held=8]="Held",e[e.Hangup=9]="Hangup",e[e.Destroy=10]="Destroy",e[e.Purge=11]="Purge"}(vt||(vt={})),function(e){e.Participant="participant",e.Moderator="moderator"}(mt||(mt={})),function(e){e.Join="join",e.Leave="leave",e.Bootstrap="bootstrap",e.Add="add",e.Modify="modify",e.Delete="delete",e.Clear="clear",e.ChatMessage="chatMessage",e.LayerInfo="layerInfo",e.LogoInfo="logoInfo",e.LayoutInfo="layoutInfo",e.LayoutList="layoutList",e.ModCmdResponse="modCommandResponse"}(ft||(ft={})),function(e){e.Video="videoinput",e.AudioIn="audioinput",e.AudioOut="audiooutput"}(_t||(_t={})),function(e){e.REGED="REGED",e.UNREGED="UNREGED",e.NOREG="NOREG",e.FAILED="FAILED",e.FAIL_WAIT="FAIL_WAIT",e.TIMEOUT="TIMEOUT",e.REGISTER="REGISTER",e.TRYING="TRYING",e.EXPIRED="EXPIRED",e.UNREGISTER="UNREGISTER"}(yt||(yt={})),function(e){e.Hold="hold",e.Unhold="unhold",e.ToggleHold="toggleHold",e.UpdateMedia="updateMedia"}(bt||(bt={}));const St="GLOBAL",It={},Ct=(e,t)=>`${e}|${t}`,Et=(e,t=St)=>Ct(e,t)in It,wt=(e,t,i=St)=>{const n=Ct(e,i);n in It||(It[n]=[]),It[n].push(t)},kt=(e,t,i=St)=>{const n=function(s){Tt(e,n,i),t(s)};return n.prototype.targetRef=t,wt(e,n,i)},Tt=(e,t,i=St)=>{if(!Et(e,i))return!1;const n=Ct(e,i);if(je(t)){for(let e=It[n].length-1;e>=0;e--){const i=It[n][e];(t===i||i.prototype&&t===i.prototype.targetRef)&&It[n].splice(e,1)}}else It[n]=[];return 0===It[n].length&&delete It[n],!0},Rt=(e,t,i=St,n=!0)=>{const s=n&&i!==St;if(!Et(e,i))return s&&Rt(e,t),!1;const o=Ct(e,i),r=It[o].length;if(!r)return s&&Rt(e,t),!1;for(let e=r-1;e>=0;e--)It[o][e](t);return s&&Rt(e,t),!0},At=e=>{const t=Ct(e,"");Object.keys(It).filter((e=>0===e.indexOf(t))).forEach((e=>delete It[e]))};let Ot="undefined"!=typeof WebSocket?WebSocket:null;const Dt=0,Nt=1,Lt=2,Mt=3;class Pt{constructor(e){this.session=e,this.previousGatewayState="",this.lastInboundAt=0,this.socketGeneration=0,this._wsClient=null,this._host=ae,this._timers={},this._useCanaryRtcServer=!1,this._hasCanaryBeenUsed=!1,this._safetyTimeoutId=null,this._pendingRequestIds=new Set,this._pendingRequestTimers=new Map,this._pendingRequestRejecters=new Map,this.upDur=null,this.downDur=null;const{host:t,env:i,region:n,useCanaryRtcServer:s}=e.options;Le.debug("Creating new Connection",{host:this._host,env:i,region:n,useCanaryRtcServer:s}),i&&(this._host="development"===i?"wss://rtcdev.telnyx.com":ae),t&&(this._host=(e=>`${We.test(e)?"":"wss://"}${e}`)(t)),n&&(this._host=this._host.replace(/rtc(dev)?/,`${n}.rtc$1`)),s&&(this._useCanaryRtcServer=!0)}get connected(){return!!this._wsClient&&this._wsClient.readyState===Nt}get connecting(){return!!this._wsClient&&this._wsClient.readyState===Dt}get closing(){return!!this._wsClient&&this._wsClient.readyState===Lt}get closed(){return!!this._wsClient&&this._wsClient.readyState===Mt}get isAlive(){return this.connecting||this.connected}get isDead(){return this.closing||this.closed}get host(){return this._host}connect(){Le.debug("Connection.connect() called",{host:this._host,socketGeneration:this.socketGeneration,sessionId:this.session.sessionid});const e=new URL(this._host);let t=tt();this.session.options.rtcIp&&this.session.options.rtcPort&&(t=null,this._useCanaryRtcServer=!1,e.searchParams.set("rtc_ip",this.session.options.rtcIp),e.searchParams.set("rtc_port",this.session.options.rtcPort.toString())),t&&e.searchParams.set("voice_sdk_id",t),this._useCanaryRtcServer&&(e.searchParams.set("canary","true"),t&&!this._hasCanaryBeenUsed&&(e.searchParams.delete("voice_sdk_id"),Le.debug("first canary connection. Refreshing voice_sdk_id")),this._hasCanaryBeenUsed=!0),this.session.callReportVoiceSdkId=e.searchParams.get("voice_sdk_id"),this.session.options.skipLastVoiceSdkId&&e.searchParams.has("voice_sdk_id")&&e.searchParams.set("skip_last_voice_sdk_id","true"),this.session.options.skipTrailing&&e.searchParams.set("skip_trailing","true");try{const t=this.socketGeneration;this._wsClient=new Ot(e.toString()),this.sock