import type { Chess } from 'chess.js'; import type { WebSocket } from 'ws'; import type { Announcement, Color, EndReason, GameId, GameStatus, Mode, PieceType, PlayerToken, PromotionType, Square, } from '@blind-chess/shared'; export interface MoveRecord { ply: number; by: Color; from: Square; to: Square; san: string; capturedPieceType?: PieceType; promotion?: PromotionType; flags: { castle?: 'k' | 'q'; enPassant?: boolean; check?: boolean; mate?: boolean }; at: number; } export interface PlayerSlot { token: PlayerToken; socket: WebSocket | null; joinedAt: number; rateBucket: { tokens: number; last: number }; } export interface Game { id: GameId; mode: Mode; highlightingEnabled: boolean; status: GameStatus; createdAt: number; finishedAt?: number; endReason?: EndReason; winner?: Color | null; chess: Chess; moveHistory: MoveRecord[]; announcements: Announcement[]; players: { w: PlayerSlot | null; b: PlayerSlot | null }; armed: { color: Color; from: Square } | null; drawOffer: { from: Color; at: number } | null; disconnectAt: { w?: number; b?: number }; lastBroadcastIdx: { w: number; b: number }; aiOpponent?: { color: Color; brain: 'casual' | 'recon' }; } export const RATE_LIMIT = { capacity: 20, refillPerSec: 10 }; export const GRACE_MS = 5 * 60 * 1000; export const PRUNE_AFTER_FINISHED_MS = 30 * 60 * 1000;