Files
jackboxpartypack-gamepicker/docs/WEBSOCKET_SUBSCRIPTION_GUIDE.md
cottongin 84398ebdd0 Reorganize project: move docs to docs/ and test scripts to tests/
Moved 9 documentation .md files from root into docs/.
Moved 4 test scripts from root into tests/.
Updated cross-references in README.md and docs to reflect new paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 14:07:39 -05:00

8.0 KiB

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

const ws = new WebSocket('ws://localhost:5000/api/sessions/live');

2. Authenticate

ws.send(JSON.stringify({
  type: 'auth',
  token: 'YOUR_JWT_TOKEN'
}));

3. Wait for Auth Success

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

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

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

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

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
  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