feat: implement and deploy blind_chess MVP

- pnpm workspace: shared/server/client packages
- Server: Fastify+ws, chess.js, FSM (touch-move + hierarchy),
  per-player view filter, zod validation, rate limiting, grace-window
  disconnect handling
- Client: Svelte 5 + Vite, click-to-move board, moderator panel,
  promotion/draw dialogs
- Shared: protocol types, ModeratorText enum, geometricMoves helper
  (provably zero opponent-info leak)
- 43 tests pass (21 shared, 22 server incl. 4 real-WS integration)
- Deploy: CT 690 on node-241 (192.168.0.245), systemd-managed,
  Caddy block for chess.sethpc.xyz
- Live at https://chess.sethpc.xyz

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude (blind_chess)
2026-04-28 11:20:18 -04:00
parent 9a5ad55f30
commit a6de43edc1
53 changed files with 11970 additions and 5 deletions
+58
View File
@@ -0,0 +1,58 @@
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 };
}
export const RATE_LIMIT = { capacity: 20, refillPerSec: 10 };
export const GRACE_MS = 5 * 60 * 1000;
export const PRUNE_AFTER_FINISHED_MS = 30 * 60 * 1000;