# WebSocket Subscription Guide ## 📋 Overview This guide explains how WebSocket subscriptions work in the Jackbox Game Picker and which events require subscriptions. ## 🔌 Connection & Authentication ### 1. Connect to WebSocket ```javascript const ws = new WebSocket('ws://localhost:5000/api/sessions/live'); ``` ### 2. Authenticate ```javascript ws.send(JSON.stringify({ type: 'auth', token: 'YOUR_JWT_TOKEN' })); ``` ### 3. Wait for Auth Success ```javascript ws.on('message', (data) => { const msg = JSON.parse(data.toString()); if (msg.type === 'auth_success') { console.log('Authenticated!'); // Now you can subscribe to sessions } }); ``` ## 📨 Event Types & Subscription Requirements | Event Type | Requires Subscription? | Broadcast To | When to Subscribe | |------------|------------------------|--------------|-------------------| | `session.started` | ❌ **NO** | All authenticated clients | N/A - Automatic | | `game.added` | ✅ **YES** | Subscribed clients only | After session.started | | `vote.received` | ✅ **YES** | Subscribed clients only | After session.started | | `session.ended` | ✅ **YES** | Subscribed clients only | After session.started | ## 🎯 Subscription Strategy ### Strategy 1: Auto-Subscribe to New Sessions (Recommended for Bots) ```javascript ws.on('message', (data) => { const msg = JSON.parse(data.toString()); // After authentication if (msg.type === 'auth_success') { console.log('✅ Authenticated'); } // Auto-subscribe to new sessions if (msg.type === 'session.started') { const sessionId = msg.data.session.id; console.log(`🎮 New session ${sessionId} started!`); // Subscribe to this session ws.send(JSON.stringify({ type: 'subscribe', sessionId: sessionId })); } // Now you'll receive game.added, vote.received, and session.ended if (msg.type === 'game.added') { console.log(`🎲 Game: ${msg.data.game.title}`); } if (msg.type === 'session.ended') { console.log(`🌙 Session ended! ${msg.data.session.games_played} games played`); } }); ``` ### Strategy 2: Subscribe to Active Session on Connect ```javascript ws.on('message', (data) => { const msg = JSON.parse(data.toString()); if (msg.type === 'auth_success') { console.log('✅ Authenticated'); // Fetch active session from API fetch('http://localhost:5000/api/sessions/active') .then(res => res.json()) .then(session => { if (session && session.id) { // Subscribe to active session ws.send(JSON.stringify({ type: 'subscribe', sessionId: session.id })); } }); } }); ``` ### Strategy 3: Subscribe to Specific Session ```javascript ws.on('message', (data) => { const msg = JSON.parse(data.toString()); if (msg.type === 'auth_success') { console.log('✅ Authenticated'); // Subscribe to specific session const sessionId = 17; ws.send(JSON.stringify({ type: 'subscribe', sessionId: sessionId })); } if (msg.type === 'subscribed') { console.log(`✅ Subscribed to session ${msg.sessionId}`); } }); ``` ## 🔄 Complete Bot Flow ```javascript const WebSocket = require('ws'); class JackboxBot { constructor(token) { this.token = token; this.ws = null; this.currentSessionId = null; } connect() { this.ws = new WebSocket('ws://localhost:5000/api/sessions/live'); this.ws.on('open', () => { console.log('🔌 Connected to WebSocket'); this.authenticate(); }); this.ws.on('message', (data) => { this.handleMessage(JSON.parse(data.toString())); }); } authenticate() { this.ws.send(JSON.stringify({ type: 'auth', token: this.token })); } handleMessage(msg) { switch (msg.type) { case 'auth_success': console.log('✅ Authenticated'); // Don't subscribe yet - wait for session.started break; case 'session.started': this.currentSessionId = msg.data.session.id; console.log(`🎮 Session ${this.currentSessionId} started!`); // Auto-subscribe to this session this.ws.send(JSON.stringify({ type: 'subscribe', sessionId: this.currentSessionId })); // Announce to users this.announce(`Game Night has started! Session #${this.currentSessionId}`); break; case 'subscribed': console.log(`✅ Subscribed to session ${msg.sessionId}`); break; case 'game.added': console.log(`🎲 Game: ${msg.data.game.title}`); this.announce(`Now playing: ${msg.data.game.title}`); break; case 'vote.received': console.log(`🗳️ Vote: ${msg.data.vote.type}`); break; case 'session.ended': console.log(`🌙 Session ${msg.data.session.id} ended`); this.announce(`Game Night ended! ${msg.data.session.games_played} games played`); this.currentSessionId = null; break; } } announce(message) { // Send to IRC/Discord/Kosmi/etc console.log(`📢 ${message}`); } } // Usage const bot = new JackboxBot('YOUR_JWT_TOKEN'); bot.connect(); ``` ## 📊 Subscription Lifecycle ``` 1. Connect to WebSocket ↓ 2. Send auth message ↓ 3. Receive auth_success ↓ 4. Wait for session.started (no subscription needed) ↓ 5. Receive session.started ↓ 6. Send subscribe message with sessionId ↓ 7. Receive subscribed confirmation ↓ 8. Now receive: game.added, vote.received, session.ended ↓ 9. Receive session.ended ↓ 10. Wait for next session.started (repeat from step 4) ``` ## 🔍 Debugging ### Check What You're Subscribed To The WebSocket manager tracks subscriptions. Check backend logs: ``` [WebSocket] Client subscribed to session 17 [WebSocket] Client unsubscribed from session 17 ``` ### Verify Event Reception **session.started** - Should receive immediately after authentication (no subscription needed): ``` [WebSocket] Broadcasted session.started to 2 authenticated client(s) ``` **game.added, vote.received, session.ended** - Only after subscribing: ``` [WebSocket] Broadcasted game.added to 1 client(s) for session 17 ``` ### Common Issues 1. **Not receiving session.started:** - ✅ Are you authenticated? - ✅ Is your WebSocket connection open? - ✅ Check backend logs for broadcast confirmation 2. **Not receiving game.added:** - ✅ Did you subscribe to the session? - ✅ Did you receive `subscribed` confirmation? - ✅ Is the session ID correct? 3. **Not receiving session.ended:** - ✅ Are you still subscribed to the session? - ✅ Did the session actually close? - ✅ Check backend logs ## 🎯 Best Practices 1. **Auto-subscribe to new sessions** when you receive `session.started` 2. **Don't subscribe before session.started** - there's nothing to subscribe to yet 3. **Handle reconnections** - re-authenticate and re-subscribe on reconnect 4. **Use polling as fallback** - poll `/api/sessions/active` every 30s as backup 5. **Unsubscribe when done** - clean up subscriptions when you're done with a session 6. **Validate session IDs** - make sure the session exists before subscribing ## 📝 Summary ### ❌ No Subscription Required - `session.started` - Broadcast to **all authenticated clients** ### ✅ Subscription Required - `game.added` - Only to **subscribed clients** - `vote.received` - Only to **subscribed clients** - `session.ended` - Only to **subscribed clients** ### 🎯 Recommended Flow 1. Authenticate 2. Wait for `session.started` (automatic) 3. Subscribe to the session 4. Receive `game.added`, `vote.received`, `session.ended` 5. Repeat from step 2 for next session ## 🔗 Related Documentation - [SESSION_START_WEBSOCKET.md](SESSION_START_WEBSOCKET.md) - session.started event details - [SESSION_END_WEBSOCKET.md](SESSION_END_WEBSOCKET.md) - session.ended event details - [API_QUICK_REFERENCE.md](API_QUICK_REFERENCE.md) - API reference - [BOT_INTEGRATION.md](BOT_INTEGRATION.md) - Bot integration guide