Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions src/hooks/use-telnyx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export function useTelnyx(): UseTelnyxReturn {
const callRef = useRef<any>(null)
const durationIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
const callStartTimeRef = useRef<number | null>(null)
const connectStartTimeRef = useRef<number>(0)

const [connectionStatus, setConnectionStatus] = useState<ConnectionStatus>('disconnected')
const [isRegistered, setIsRegistered] = useState(false)
Expand Down Expand Up @@ -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<never>((_, 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')
Expand Down Expand Up @@ -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
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const activeClient = clientRef.current
if (!activeClient) {
Expand Down
Loading