Files
awoooi/apps/web/src/hooks/useApprovalSSE.ts
OG T 5ee139749a chore(lint): 清理 7 項 ESLint 警告
- useApprovalSSE.ts: 標記未使用的 fallbackToPolling
- useErrors.ts: 移除未使用的 ErrorListResponse import
- dashboard.store.ts: 標記 SSE event 參數
- agent.store.ts: 加註 SSE 串流迴圈說明
- approval.store.ts: 改用正規 type import
- terminal.store.ts: 改用 inline type import
- OmniTerminal.tsx: 改用 type import

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-29 16:40:19 +08:00

87 lines
2.3 KiB
TypeScript

'use client'
/**
* useApprovalSSE - Approval SSE 連線 Hook
* ========================================
* Phase 15: Polling → SSE
*
* 自動管理 SSE 連線生命週期:
* - 組件掛載時自動連線
* - 組件卸載時自動斷線
* - 支援 SSE 失敗後降級到 Polling
*/
import { useEffect, useRef, useCallback } from 'react'
import { useApprovalStore } from '@/stores/approval.store'
interface UseApprovalSSEOptions {
/** 自動連線 (預設 true) */
autoConnect?: boolean
/** SSE 失敗後是否降級到 Polling (預設 true) */
fallbackToPolling?: boolean
}
interface UseApprovalSSEReturn {
/** SSE 連線狀態 */
status: 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error'
/** 是否已連線 */
isConnected: boolean
/** 是否重連中 */
isReconnecting: boolean
/** 錯誤訊息 */
error: string | null
/** 手動連線 */
connect: () => void
/** 手動斷線 */
disconnect: () => void
}
export function useApprovalSSE(options: UseApprovalSSEOptions = {}): UseApprovalSSEReturn {
const { autoConnect = true, fallbackToPolling: _fallbackToPolling = true } = options
const connectSSE = useApprovalStore((s) => s.connectSSE)
const disconnectSSE = useApprovalStore((s) => s.disconnectSSE)
const stopPolling = useApprovalStore((s) => s.stopPolling)
const sseStatus = useApprovalStore((s) => s.sseStatus)
const error = useApprovalStore((s) => s.error)
const mountedRef = useRef(true)
const handleConnect = useCallback(() => {
if (!mountedRef.current) return
console.log('[useApprovalSSE] Connecting...')
connectSSE()
}, [connectSSE])
const handleDisconnect = useCallback(() => {
console.log('[useApprovalSSE] Disconnecting...')
disconnectSSE()
stopPolling()
}, [disconnectSSE, stopPolling])
useEffect(() => {
mountedRef.current = true
if (autoConnect) {
console.log('[useApprovalSSE] Auto-connecting...')
handleConnect()
}
// Cleanup: 防止殭屍連線
return () => {
console.log('[useApprovalSSE] Cleanup')
mountedRef.current = false
handleDisconnect()
}
}, [autoConnect, handleConnect, handleDisconnect])
return {
status: sseStatus,
isConnected: sseStatus === 'connected',
isReconnecting: sseStatus === 'reconnecting',
error,
connect: handleConnect,
disconnect: handleDisconnect,
}
}