'use client' import { io, Socket } from 'socket.io-client' let socket: Socket | null = null let currentRoom: string | null = null export type SocketStatus = 'connected' | 'disconnected' | 'reconnecting' type StatusListener = (status: SocketStatus) => void let currentStatus: SocketStatus = 'disconnected' const statusListeners = new Set() function setStatus(status: SocketStatus) { if (status === currentStatus) return currentStatus = status statusListeners.forEach(fn => fn(status)) } /** Subscribe to socket connection status changes. Returns an unsubscribe function. */ export function onSocketStatus(listener: StatusListener): () => void { statusListeners.add(listener) // Immediately notify current status listener(currentStatus) return () => { statusListeners.delete(listener) } } /** Get current socket connection status */ export function getSocketStatus(): SocketStatus { return currentStatus } export function getSocket(): Socket { if (!socket) { socket = io({ path: '/socket.io', transports: ['websocket', 'polling'], upgrade: true, reconnection: true, reconnectionAttempts: Infinity, reconnectionDelay: 1000, reconnectionDelayMax: 5000, timeout: 10000, forceNew: false, }) socket.on('connect', () => { console.log('[Socket.io] Connected:', socket?.id) setStatus('connected') // Re-join project room after reconnect if (currentRoom) { console.log('[Socket.io] Re-joining room:', currentRoom) socket?.emit('join-project', currentRoom) } }) socket.on('disconnect', (reason) => { console.warn('[Socket.io] Disconnected:', reason) setStatus('disconnected') if (reason === 'io server disconnect') { // Server disconnected us, need to manually reconnect socket?.connect() } }) socket.on('connect_error', (err) => { console.warn('[Socket.io] Connection error:', err.message) }) socket.io.on('reconnect', (attempt) => { console.log('[Socket.io] Reconnected after', attempt, 'attempts') setStatus('connected') }) socket.io.on('reconnect_attempt', (attempt) => { console.log('[Socket.io] Reconnect attempt', attempt) setStatus('reconnecting') }) } return socket } /** Track which room the socket should be in (for auto-rejoin on reconnect) */ export function setSocketRoom(projectId: string | null): void { currentRoom = projectId }