diff --git a/src/hooks/use-telnyx.ts b/src/hooks/use-telnyx.ts index c62d8307..5c43712e 100644 --- a/src/hooks/use-telnyx.ts +++ b/src/hooks/use-telnyx.ts @@ -82,6 +82,7 @@ export function useTelnyx(): UseTelnyxReturn { const callRef = useRef(null) const durationIntervalRef = useRef | null>(null) const callStartTimeRef = useRef(null) + const connectStartTimeRef = useRef(0) const [connectionStatus, setConnectionStatus] = useState('disconnected') const [isRegistered, setIsRegistered] = useState(false) @@ -622,23 +623,29 @@ export function useTelnyx(): UseTelnyxReturn { }) clientRef.current = client - await client.connect() + connectStartTimeRef.current = Date.now() - // Safety net: if telnyx.ready doesn't fire within REGISTRATION_TIMEOUT_MS, - // reset status from 'connecting' to 'disconnected' so periodic checks - // can retry. Without this, a failed registration leaves status stuck on - // 'connecting' and all ensureRegistered() calls bail early. + // Arm timeout BEFORE awaiting connect to avoid hangs where connect() never resolves. if (registrationTimeoutRef.current) { clearTimeout(registrationTimeoutRef.current) } - registrationTimeoutRef.current = setTimeout(() => { - if (destroyed) return - if (connectionStatusRef.current === 'connecting') { - console.warn('[useTelnyx] Registration timeout - telnyx.ready not received within', REGISTRATION_TIMEOUT_MS, 'ms, resetting to disconnected') + const timeoutPromise = new Promise((_, reject) => { + registrationTimeoutRef.current = setTimeout(() => { + if (destroyed) return + + console.warn( + '[useTelnyx] SIP connect timeout - connect/ready not received within', + REGISTRATION_TIMEOUT_MS, + 'ms' + ) markInitialized() - setConnectionStatus('disconnected') - } - }, REGISTRATION_TIMEOUT_MS) + setConnectionStatus('error') + setRegistrationState(false) + reject(new Error('SIP connect timeout')) + }, REGISTRATION_TIMEOUT_MS) + }) + + await Promise.race([client.connect(), timeoutPromise]) } catch (err) { console.error('[useTelnyx] Failed to initialize:', err) if (!destroyed) setConnectionStatus('error') @@ -734,7 +741,16 @@ export function useTelnyx(): UseTelnyxReturn { async function ensureRegistered(reason: string) { if (destroyed || isInitializingRef.current) return false - if (connectionStatusRef.current === 'connecting') return false + if (connectionStatusRef.current === 'connecting') { + const elapsed = Date.now() - connectStartTimeRef.current + if (connectStartTimeRef.current > 0 && elapsed > REGISTRATION_TIMEOUT_MS) { + console.warn( + `[useTelnyx] ensureRegistered detected stuck connecting (${reason}) after ${elapsed}ms - triggering recovery` + ) + await triggerManualReconnect('connect-timeout') + } + return false + } const activeClient = clientRef.current if (!activeClient) {