release: bump version to 0.48.0

This commit is contained in:
linkong
2026-05-07 18:06:06 +08:00
parent 421234301a
commit bb9183b8a4
51 changed files with 4609 additions and 400 deletions

View File

@@ -54,6 +54,8 @@ interface UseWebSocketOptions {
interface UseWebSocketReturn {
connected: boolean
connecting: boolean
status: 'connecting' | 'connected' | 'disconnected'
lastMessage: WebSocketMessage | null
sendMessage: (message: Record<string, unknown>) => void
subscribe: (channels: string[]) => void
@@ -65,6 +67,7 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
const {
autoConnect = true,
autoSubscribe = [],
heartbeatInterval = 25000,
onMessage,
onConnect,
onDisconnect,
@@ -75,6 +78,7 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
const wsRef = useRef<WebSocket | null>(null)
const [connected, setConnected] = useState(false)
const [connecting, setConnecting] = useState(false)
const [lastMessage, setLastMessage] = useState<WebSocketMessage | null>(null)
const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const heartbeatTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)
@@ -97,17 +101,21 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
const connect = useCallback(() => {
if (!token) {
setConnected(false)
setConnecting(false)
return
}
intentionalCloseRef.current = false
setConnected(false)
setConnecting(true)
const candidates = buildWebSocketCandidates()
let candidateIndex = 0
let opened = false
const tryConnect = () => {
const baseUrl = candidates[candidateIndex]
const wsUrl = `${baseUrl}?token=${token}`
const wsUrl = `${baseUrl}?token=${encodeURIComponent(token)}`
activeWsUrlRef.current = baseUrl
const ws = new WebSocket(wsUrl)
@@ -119,15 +127,27 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
}
opened = true
setConnected(true)
setConnecting(false)
if (autoSubscribeRef.current.length > 0) {
ws.send(JSON.stringify({ type: 'subscribe', data: { channels: autoSubscribeRef.current } }))
}
if (heartbeatTimerRef.current) {
clearInterval(heartbeatTimerRef.current)
}
heartbeatTimerRef.current = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'heartbeat' }))
}
}, heartbeatInterval)
onConnectRef.current?.()
}
ws.onmessage = (event) => {
try {
const message: WebSocketMessage = JSON.parse(event.data)
if (message.type === 'heartbeat' && message.data?.action === 'ping' && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'heartbeat' }))
}
setLastMessage(message)
onMessageRef.current?.(message)
} catch {
@@ -150,10 +170,13 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
if (!opened && candidateIndex < candidates.length - 1) {
candidateIndex += 1
setConnecting(true)
tryConnect()
return
}
setConnecting(false)
if (intentionalCloseRef.current) {
return
}
@@ -169,6 +192,9 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
ws.onerror = (error) => {
setConnected(false)
if (opened || candidateIndex >= candidates.length - 1) {
setConnecting(false)
}
if (intentionalCloseRef.current || ws.readyState === WebSocket.CLOSING || ws.readyState === WebSocket.CLOSED) {
return
}
@@ -185,6 +211,7 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
tryConnect()
} catch (error) {
setConnected(false)
setConnecting(false)
console.warn('[WebSocket] Failed to initialize connection', { url: activeWsUrlRef.current, error })
if (autoConnect && token) {
reconnectTimeoutRef.current = setTimeout(() => {
@@ -192,7 +219,7 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
}, 3000)
}
}
}, [token, autoConnect])
}, [token, autoConnect, heartbeatInterval])
const disconnect = useCallback(() => {
intentionalCloseRef.current = true
@@ -213,6 +240,7 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
}
}
setConnected(false)
setConnecting(false)
}, [])
const sendMessage = useCallback((message: Record<string, unknown>) => {
@@ -237,6 +265,8 @@ export function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketRet
return {
connected,
connecting,
status: connected ? 'connected' : connecting ? 'connecting' : 'disconnected',
lastMessage,
sendMessage,
subscribe,