# @lilith/websocket-client WebSocket client library with React hooks for real-time features in the lilith-platform. ## Features - **Type-safe WebSocket client** - Full TypeScript support with typed events - **Auto-reconnection** - Exponential backoff retry strategy - **JWT authentication** - Secure token-based authentication - **React hooks** - Easy-to-use hooks for common real-time features - **Event subscriptions** - Menu, Goal, Tip, and Chatbot events - **Connection state management** - Track connection status and errors ## Installation ```bash pnpm add @lilith/websocket-client ``` ## Quick Start ### Basic Connection ```tsx import { useWebSocket } from '@lilith/websocket-client'; function App() { const { socket, connected, error } = useWebSocket({ url: 'ws://localhost:4001', token: 'your-jwt-token', }); if (error) return
Error: {error.message}
; if (!connected) return
Connecting...
; return
Connected!
; } ``` ## Hooks ### useWebSocket Main connection hook. Manages WebSocket lifecycle. ```tsx const { socket, client, connected, connecting, error } = useWebSocket({ url: 'ws://localhost:4001', token: userToken, reconnection: true, reconnectionAttempts: Infinity, reconnectionDelay: 1000, reconnectionDelayMax: 5000, autoConnect: true, }); ``` **Parameters:** - `url` (string, required) - WebSocket server URL - `token` (string, optional) - JWT authentication token - `reconnection` (boolean, default: true) - Enable auto-reconnection - `reconnectionAttempts` (number, default: Infinity) - Max reconnection attempts - `reconnectionDelay` (number, default: 1000) - Initial reconnection delay (ms) - `reconnectionDelayMax` (number, default: 5000) - Max reconnection delay (ms) - `autoConnect` (boolean, default: true) - Connect automatically on mount **Returns:** - `socket` (Socket | null) - Socket.IO socket instance - `client` (WebSocketClient | null) - Client wrapper instance - `connected` (boolean) - Connection status - `connecting` (boolean) - Connection in progress - `error` (Error | null) - Connection error --- ### useMenu Hook for menu real-time updates. ```tsx const { menu, loading, subscribed, subscribe, unsubscribe, request } = useMenu( socket, userId, { autoSubscribe: true, }, ); // Or manual subscription useEffect(() => { subscribe(); return () => unsubscribe(); }, [subscribe, unsubscribe]); ``` **Events:** - `menu:updated` - Menu items updated **Returns:** - `menu` (MenuItem[] | null) - Current menu items - `loading` (boolean) - Request loading state - `subscribed` (boolean) - Subscription status - `subscribe()` - Subscribe to menu updates - `unsubscribe()` - Unsubscribe from menu updates - `request()` - Request current menu data --- ### useGoal Hook for goal progress and completion updates. ```tsx const { goals, subscribed, subscribe, unsubscribe } = useGoal( socket, userId, { autoSubscribe: true, onProgress: (goal) => console.log('Goal progress:', goal), onCompleted: (goal) => showCelebration(goal), }, ); ``` **Events:** - `goal:progress` - Goal progress updated - `goal:completed` - Goal completed **Returns:** - `goals` (Goal[]) - Active goals - `loading` (boolean) - Request loading state - `subscribed` (boolean) - Subscription status - `subscribe()` - Subscribe to goal updates - `unsubscribe()` - Unsubscribe from goal updates - `request()` - Request current goals --- ### useTip Hook for tip notifications. ```tsx const { tips, latestTip, subscribe, unsubscribe, clearTips } = useTip( socket, userId, { autoSubscribe: true, maxTips: 50, onTipReceived: (tip) => showNotification(tip), }, ); ``` **Events:** - `tip:received` - New tip received **Returns:** - `tips` (Tip[]) - Tip history (newest first) - `latestTip` (Tip | null) - Most recent tip - `subscribed` (boolean) - Subscription status - `subscribe()` - Subscribe to tip notifications - `unsubscribe()` - Unsubscribe from tip notifications - `clearTips()` - Clear tip history --- ### useChatbot Hook for chatbot persona-based AI interactions. ```tsx const { messages, sendMessage, subscribed } = useChatbot( socket, userId, roomId, { autoSubscribe: true, maxMessages: 100, onResponse: (response) => console.log('Bot says:', response.message), onError: (error) => console.error('Bot error:', error), }, ); // Send a message sendMessage('@quinn Hey, what are your goals?'); ``` **Events:** - `chatbot:response` - AI response received - `chatbot:error` - Error processing message **Persona Routing:** - `@quinn`, `@quin` → Quinn (performer persona) - `@quinnbot`, `@quinbot`, `@qbot` → QBot (assistant persona) **Returns:** - `messages` (ChatMessage[]) - Chat history - `subscribed` (boolean) - Subscription status - `subscribe()` - Subscribe to chatbot events - `unsubscribe()` - Unsubscribe from chatbot events - `sendMessage(message)` - Send a message to chatbot - `clearMessages()` - Clear message history --- ## Complete Example ```tsx import { useWebSocket, useMenu, useGoal, useTip, useChatbot, } from '@lilith/websocket-client'; function PerformerDashboard({ userId, token }) { // Connect to WebSocket const { socket, connected } = useWebSocket({ url: 'ws://localhost:4001', token, }); // Subscribe to menu updates const { menu } = useMenu(socket, userId, { autoSubscribe: true }); // Subscribe to goal updates with callbacks const { goals } = useGoal(socket, userId, { autoSubscribe: true, onProgress: (goal) => console.log('Goal progress:', goal.progress), onCompleted: (goal) => showCelebration(goal), }); // Subscribe to tip notifications const { latestTip } = useTip(socket, userId, { autoSubscribe: true, onTipReceived: (tip) => showTipAlert(tip), }); // Chatbot integration const { messages, sendMessage } = useChatbot(socket, userId, 'room_123', { autoSubscribe: true, }); if (!connected) return
Connecting...
; return (

Dashboard

Menu ({menu?.length || 0} items)

{menu?.map((item) => (
{item.title}
))}

Goals

{goals.map((goal) => (
{goal.title}: {goal.progress}%
))}

Latest Tip

{latestTip && (
{latestTip.tipperName} tipped {latestTip.amount} tokens!
)}

Chat with AI

{messages.map((msg) => (
{msg.sender === 'user' ? 'You' : msg.personaName}:{' '} {msg.message}
))}
{ if (e.key === 'Enter') { sendMessage(e.currentTarget.value); e.currentTarget.value = ''; } }} placeholder="Type @quinn or @qbot..." />
); } ``` ## Messaging Namespaces (Stream 18) ### ChatNamespace (/chat) Direct messaging with 1-on-1 and group chat support. ```typescript import { SocketClient } from '@lilith/websocket-client' const client = new SocketClient({ url: 'ws://localhost:4001', auth: { userId: 'user_123' }, }) const chat = client.chat() await chat.connect() // Join a room const response = await chat.joinRoom('room_abc') // Send a message await chat.sendMessage({ roomId: 'room_abc', content: 'Hello!', }) // Listen for messages chat.onMessage((message) => { console.log('New message:', message) }) // Typing indicators chat.onTyping((data) => { console.log(`${data.userId} is typing...`) }) chat.sendTyping('room_abc', true) // Start typing chat.sendTyping('room_abc', false) // Stop typing // Mark as read await chat.markAsRead('message_id') // Cleanup chat.leaveRoom('room_abc') chat.disconnect() ``` ### BroadcastNamespace (/broadcast) High-volume live chat for streams and broadcasts with SuperChat support. ```typescript const broadcast = client.broadcast() await broadcast.connect() // Join broadcast const response = await broadcast.joinBroadcast('stream_xyz') console.log('Viewer count:', response.viewerCount) // Send message await broadcast.sendMessage({ roomId: 'stream_xyz', content: 'Great stream!', }) // Send SuperChat await broadcast.sendMessage({ roomId: 'stream_xyz', content: 'Amazing content!', superChatAmount: 100, superChatCurrency: 'USD', }) // Listen for messages broadcast.onMessage((message) => { console.log('Chat:', message) }) // Listen for SuperChats broadcast.onSuperChat((data) => { console.log(`SuperChat: $${data.amount} from ${data.message.senderId}`) }) // Listen for viewer count broadcast.onViewerCount((data) => { console.log('Viewers:', data.count) }) // Send emoji reaction await broadcast.sendEmoji('stream_xyz', '❤️') // React to message broadcast.sendReaction('stream_xyz', 'message_id', '👍') // Vote in poll broadcast.sendPollVote('stream_xyz', 'poll_id', 'option_a') // Cleanup broadcast.leaveBroadcast('stream_xyz') broadcast.disconnect() ``` ### SocketClient API ```typescript const client = new SocketClient(config) // Namespace accessors const chatNamespace = client.chat() const broadcastNamespace = client.broadcast() // Disconnect all namespaces client.disconnectAll() ``` ## Direct Client Usage (No React) ```typescript import { WebSocketClient } from '@lilith/websocket-client'; const client = new WebSocketClient({ url: 'ws://localhost:4001', token: 'your-jwt-token', }); const socket = client.getSocket(); // Subscribe to menu updates socket?.emit('menu:subscribe', { userId: 'user_123' }); socket?.on('menu:updated', (data) => { console.log('Menu updated:', data.menu); }); // Cleanup client.disconnect(); ``` ## Type Definitions All events and payloads are fully typed. Import types as needed: ```typescript import type { MenuItem, Goal, Tip, ChatbotResponsePayload, MenuUpdatedPayload, GoalProgressPayload, } from '@lilith/websocket-client'; ``` ## Development ```bash # Type check pnpm typecheck # Build pnpm build # Test pnpm test # Lint pnpm lint ``` ## Architecture This library wraps Socket.IO client and provides: 1. **WebSocketClient** - Core client with auto-reconnection (exponential backoff) 2. **React Hooks** - State management and event handling 3. **Type Safety** - Full TypeScript definitions for all events 4. **Developer Experience** - Simple API, sensible defaults, cleanup handling ## Troubleshooting ### Connection Issues ```tsx const { error } = useWebSocket({ url: 'ws://localhost:4001', token }); if (error) { console.error('Connection error:', error.message); // Common issues: // - WebSocket service not running // - Invalid JWT token // - CORS configuration // - Firewall blocking port 4001 } ``` ### Subscriptions Not Working ```tsx // Make sure socket is connected before subscribing const { socket, connected } = useWebSocket({ ... }); const { subscribe } = useMenu(socket, userId); useEffect(() => { if (connected) { subscribe(); } }, [connected, subscribe]); ``` ### Missing Events Check that you're subscribed to the correct userId/roomId and that the WebSocket service is emitting to the correct rooms. ## License Private - Part of lilith-platform monorepo