import { useRef, useEffect, useState } from 'react' import * as Y from 'yjs' import { WebsocketProvider } from 'y-websocket' import type { Awareness } from 'y-protocols/awareness' const COLLAB_WS_URL = import.meta.env.VITE_COLLAB_WS_URL as string || 'ws://localhost:4000' interface UseWebSocketProviderOptions { ydoc: Y.Doc | null roomName: string | null token: string | null userName: string userColor: string } /** * Manages a Y.js WebSocket provider for real-time collaboration. * Connects to the Hocuspocus server. */ export function useWebSocketProvider({ ydoc, roomName, token, userName, userColor, }: UseWebSocketProviderOptions) { const providerRef = useRef(null) const [awareness, setAwareness] = useState(null) const [connected, setConnected] = useState(false) const [peerCount, setPeerCount] = useState(0) useEffect(() => { if (!ydoc || !roomName || !token) { setAwareness(null) setConnected(false) setPeerCount(0) return } const provider = new WebsocketProvider( COLLAB_WS_URL, roomName, ydoc, { params: { token }, connect: true, }, ) providerRef.current = provider // Set local user awareness provider.awareness.setLocalStateField('user', { name: userName, color: userColor, }) setAwareness(provider.awareness) // Track connection status provider.on('status', (event: { status: string }) => { setConnected(event.status === 'connected') }) // Track peer count const updatePeerCount = () => { const states = provider.awareness.getStates() setPeerCount(Math.max(0, states.size - 1)) // Exclude self } provider.awareness.on('change', updatePeerCount) updatePeerCount() return () => { provider.awareness.off('change', updatePeerCount) provider.disconnect() provider.destroy() providerRef.current = null setAwareness(null) setConnected(false) setPeerCount(0) } }, [ydoc, roomName, token, userName, userColor]) return { awareness, connected, peerCount } }