WebSocket Pipeline

This page describes the event pipeline architecture in src/websocket/pipeline/. Events are categorized into pipelines by type, providing a framework for validation, rate limiting, idempotency and tracing.

connection-handler.ts does not call routeEventToPipeline today. Payload validation runs in createValidationMiddleware, and handlers call the rate limit stage (enforceGameRateLimit) and idempotency helpers directly.

Overview

Client Event → Zod Validation → Rate Limit Stage → Handler → Response
                    ↑                                ↓
          schemas/client-events.ts            game-events/
                                              lobby-events.ts
                                              state-sync.ts

Pipelines

1. Game Pipeline (game-pipeline.ts)

Handles all player actions at poker tables.

Events:

  • join_table – Player joins a table
  • leave_table – Player leaves a table
  • player_action – Betting actions (fold, check, call, bet, raise, all-in)
  • sit_out – Player marks themselves as sitting out
  • sit_in – Player returns to active play
  • add_chips – Player adds chips to their stack
  • chat_message – Player sends a chat message
  • request_table_state – Player requests current table state

Stages (each wrapped with tracing):

  1. Validation – Verify request data and user authentication
  2. Authorization – Check player is at a table (for table-required events)
  3. Rate limit – Apply per-user limits
  4. Idempotency – Return the cached response for duplicate events
  5. Logging – Log the event for observability
  6. Completion – Record processing time

Rate limiting (RATE_LIMITED_EVENTS) also covers tournament_rebuy, tournament_addon, tournament_reentry, request_lobby_state, watch_table and stop_watching, which are not in EVENT_PIPELINE_MAP.

2. Lobby Pipeline (lobby-pipeline.ts)

Handles lobby subscriptions and state requests.

Events:

  • subscribe_lobby – Client subscribes to lobby updates
  • unsubscribe_lobby – Client unsubscribes from lobby updates
  • request_lobby_state – Client requests current lobby state

Stages:

  1. Validation – Verify user authentication
  2. Logging – Log the event for observability
  3. Completion – Record processing time

3. State Sync Pipeline (state-sync-pipeline.ts)

Handles server-initiated state synchronization broadcasts.

Operations:

  • full_state_broadcast – Send complete table state to all players
  • showdown_broadcast – Reveal cards during showdown
  • player_notification – Send targeted notification to specific player

Stages:

  1. State Filtering – Filter state based on viewer (hide opponent cards)
  2. Delivery – Send to appropriate recipients
  3. Logging – Log the broadcast for observability

Event Context

Every event flowing through a pipeline has an associated EventContext:

interface EventContext {
  correlationId: string;     // Unique ID for tracing (evt_<time>_<random>)
  timestamp: number;         // When event was received
  socket: PokerSocket;       // The socket that sent the event
  userId: string;            // User ID
  username: string;          // Username
  currentTableId?: string;   // Table ID (if at a table)
  metadata: {
    eventName: string;       // The event type
    pipeline: PipelineType;  // Which pipeline is processing
    stages: string[];        // Processing stages completed
    warnings: string[];      // Any warnings
    processingTimeMs?: number; // Total processing time
  };
}

Event Routing

EVENT_PIPELINE_MAP in pipeline/types.ts maps events to pipelines:

// Game events
join_table       → game pipeline
leave_table      → game pipeline
player_action    → game pipeline
sit_out          → game pipeline
sit_in           → game pipeline
add_chips        → game pipeline
chat_message     → game pipeline
request_table_state → game pipeline

// Lobby events
subscribe_lobby  → lobby pipeline
unsubscribe_lobby → lobby pipeline
request_lobby_state → lobby pipeline

Usage

Routing events through a pipeline:

import { createEventContext, routeEventToPipeline, getPipelineForEvent } from './pipeline/index.js';

// In connection handler
socket.on('some_event', async (data, callback) => {
  const pipelineType = getPipelineForEvent('some_event');
  if (!pipelineType) return;

  const context = createEventContext(socket, 'some_event', pipelineType);
  const result = await routeEventToPipeline(context, data);

  if (callback) {
    callback({ success: result.success, error: result.error });
  }
});

Checking event type:

import { isGameEvent, isLobbyEvent, isStateSyncEvent } from './pipeline/index.js';

if (isGameEvent(eventName)) {
  // Handle as game event
}

Logging state sync operations:

import { logStateSyncOperation } from './pipeline/index.js';

logStateSyncOperation(tableId, 'full_state_broadcast', {
  playerCount: 5,
  seq: 42,
});

Architecture Benefits

  1. Consistent Handling – Events routed through a pipeline go through the same stages
  2. Centralized Validation – Validation happens before handler execution
  3. Event Tracing – Correlation IDs allow tracing events through the system
  4. Observability – Structured logging at each pipeline stage
  5. Clean Separation – Game, lobby, and state-sync concerns are separated
  6. Extensibility – New stages can be added without modifying handlers

File Structure

src/websocket/pipeline/
├── index.ts                 # Main exports and pipeline router
├── types.ts                 # Core types (EventContext, Pipeline, etc.)
├── game-pipeline.ts         # Game event pipeline
├── lobby-pipeline.ts        # Lobby event pipeline
├── state-sync-pipeline.ts   # State sync pipeline
├── rate-limit-stage.ts      # Per-user rate limits
├── idempotency-stage.ts     # Duplicate event handling
├── idempotency-store.ts     # Idempotency key storage
├── tracing-stage.ts         # Event tracing
├── event-trace-store.ts     # Trace storage
├── guaranteed-delivery-stage.ts  # Delivery wrapping and acks
├── delivery-tracker.ts      # Retry tracking
└── README.md

Integration with Existing Code

The pipeline modules work alongside the handlers:

  • Zod Validation (schemas/client-events.ts) – Validates event payloads before pipeline
  • Event Handlers (game-events/, lobby-events.ts) – Execute business logic
  • State Sync (state-sync.ts) – Handles state synchronization
  • Table Manager (table-manager.ts) – Manages table instances

The pipelines provide the framework; handlers provide the implementation.

Try the live demo Pricing

Have questions about Poker Engine? We reply fast.