- 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>
87 lines
2.3 KiB
TypeScript
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,
|
|
}
|
|
}
|