import { createSignal, createEffect, onSettled } from "solid-js"; import { connectWs } from "./ws"; import type { RoomState, ChatMessage, ClientMessage } from "./types"; /** Auto-clear an error signal after `ms`, unless the `unless` predicate matches the error. */ export function useAutoDismiss( [error, setError]: [() => string | null, (v: string | null) => void], opts: { ms?: number; unless?: (err: string) => boolean } = {}, ): void { createEffect( () => error(), (err) => { if (!err) return; if (opts.unless?.(err)) return; const timer = setTimeout(() => setError(null), opts.ms ?? 5000); return () => clearTimeout(timer); }, ); } /** Manage WebSocket connection lifecycle for a room. */ export function useRoomConnection(roomId: string, userName: string) { const [state, setState] = createSignal(null); const [chats, setChats] = createSignal([]); const [connected, setConnected] = createSignal(false); const [error, setError] = createSignal(null); const [sendFn, setSendFn] = createSignal<((msg: ClientMessage) => void) | null>(null); const initialLoad = { current: true }; const startConnecting = () => { if (sendFn()) return; const send = connectWs(roomId, userName, { onState: (s) => { initialLoad.current = false; setState(s); }, onChat: (msg) => setChats((prev) => { const next = [...prev, msg]; return next.length > 200 ? next.slice(-200) : next; }), onDisconnect: () => { setConnected(false); setSendFn(null); }, onError: (reason) => { setError(reason); }, }); setSendFn(() => send); setConnected(true); setError(null); }; onSettled(() => { startConnecting(); setTimeout(() => { if (initialLoad.current) { setError("Room not found or unavailable"); } }, 8000); }); // Reconnect on disconnect with backoff. createEffect( () => [connected(), sendFn()], ([isConnected, send]) => { if (!isConnected && !send) { const timer = setTimeout(startConnecting, 3000); return () => clearTimeout(timer); } }, ); // Auto-dismiss transient errors, but not "not found". useAutoDismiss([error, setError], { unless: (err) => err.includes("not found") }); const send = (msg: ClientMessage) => sendFn()?.(msg); return { state, chats, connected, error, setError, send }; }