Removed all references to the defensive alignment field across frontend codebase after backend removal in Session 1. The alignment field was determined to be unused and was removed from DefensiveDecision model. Changes: - types/websocket.ts: Removed alignment from DefensiveDecisionRequest interface - composables/useGameActions.ts: Removed alignment from submit handler - pages/demo-decisions.vue: Updated demo state and summary text (alignment → depths) - pages/games/[id].vue: Updated decision history text for both defensive and offensive * Defensive: Now shows "infield depth, outfield depth" instead of "alignment, infield" * Offensive: Updated to use new action field with proper labels (swing_away, hit_and_run, etc.) - Test files (3): Updated all test cases to remove alignment references * tests/unit/composables/useGameActions.spec.ts * tests/unit/store/game-decisions.spec.ts * tests/unit/components/Decisions/DefensiveSetup.spec.ts Also updated offensive decision handling to match Session 2 changes (approach/hit_and_run/bunt_attempt → action field). Total: 7 files modified, all alignment references removed Verified: Zero remaining alignment references in .ts/.vue/.js files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
361 lines
7.8 KiB
TypeScript
361 lines
7.8 KiB
TypeScript
/**
|
|
* WebSocket Event Types
|
|
*
|
|
* TypeScript definitions for all Socket.io events between client and server.
|
|
* Ensures type safety for real-time communication.
|
|
*
|
|
* Backend Reference: app/websocket/handlers.py
|
|
*/
|
|
|
|
import type {
|
|
GameState,
|
|
PlayResult,
|
|
DecisionPrompt,
|
|
RollData,
|
|
DefensiveDecision,
|
|
OffensiveDecision,
|
|
ManualOutcomeSubmission,
|
|
} from './game'
|
|
|
|
import type {
|
|
SubstitutionRequest,
|
|
SubstitutionResult,
|
|
SubstitutionError,
|
|
LineupDataResponse,
|
|
} from './player'
|
|
|
|
/**
|
|
* WebSocket connection auth
|
|
*/
|
|
export interface SocketAuth {
|
|
token: string
|
|
}
|
|
|
|
/**
|
|
* Client → Server Events (what client can emit)
|
|
*/
|
|
export interface ClientToServerEvents {
|
|
// Connection management
|
|
join_game: (data: JoinGameRequest) => void
|
|
leave_game: (data: LeaveGameRequest) => void
|
|
heartbeat: () => void
|
|
|
|
// Strategic decisions
|
|
submit_defensive_decision: (data: DefensiveDecisionRequest) => void
|
|
submit_offensive_decision: (data: OffensiveDecisionRequest) => void
|
|
|
|
// Manual outcome workflow
|
|
roll_dice: (data: RollDiceRequest) => void
|
|
submit_manual_outcome: (data: SubmitManualOutcomeRequest) => void
|
|
|
|
// Substitutions
|
|
request_pinch_hitter: (data: PinchHitterRequest) => void
|
|
request_defensive_replacement: (data: DefensiveReplacementRequest) => void
|
|
request_pitching_change: (data: PitchingChangeRequest) => void
|
|
|
|
// Data requests
|
|
get_lineup: (data: GetLineupRequest) => void
|
|
get_box_score: (data: GetBoxScoreRequest) => void
|
|
request_game_state: (data: RequestGameStateRequest) => void
|
|
}
|
|
|
|
/**
|
|
* Server → Client Events (what client can receive)
|
|
*/
|
|
export interface ServerToClientEvents {
|
|
// Connection events
|
|
connected: (data: ConnectedEvent) => void
|
|
game_joined: (data: GameJoinedEvent) => void
|
|
user_connected: (data: UserConnectedEvent) => void
|
|
user_disconnected: (data: UserDisconnectedEvent) => void
|
|
heartbeat_ack: () => void
|
|
|
|
// Decision events
|
|
defensive_decision_submitted: (data: DefensiveDecisionSubmittedEvent) => void
|
|
offensive_decision_submitted: (data: OffensiveDecisionSubmittedEvent) => void
|
|
decision_required: (data: DecisionPrompt) => void
|
|
|
|
// Game state events
|
|
game_state_update: (data: GameState) => void
|
|
game_state_sync: (data: GameStateSyncEvent) => void
|
|
play_completed: (data: PlayResult) => void
|
|
inning_change: (data: InningChangeEvent) => void
|
|
game_ended: (data: GameEndedEvent) => void
|
|
|
|
// Manual workflow events
|
|
dice_rolled: (data: DiceRolledEvent) => void
|
|
outcome_accepted: (data: OutcomeAcceptedEvent) => void
|
|
|
|
// Substitution events
|
|
player_substituted: (data: SubstitutionResult) => void
|
|
substitution_confirmed: (data: SubstitutionConfirmedEvent) => void
|
|
|
|
// Data responses
|
|
lineup_data: (data: LineupDataResponse) => void
|
|
box_score_data: (data: BoxScoreDataEvent) => void
|
|
|
|
// Error events
|
|
error: (data: ErrorEvent) => void
|
|
outcome_rejected: (data: OutcomeRejectedEvent) => void
|
|
substitution_error: (data: SubstitutionError) => void
|
|
invalid_action: (data: InvalidActionEvent) => void
|
|
connection_error: (data: ConnectionErrorEvent) => void
|
|
}
|
|
|
|
// ============================================================================
|
|
// Client → Server Request Types
|
|
// ============================================================================
|
|
|
|
export interface JoinGameRequest {
|
|
game_id: string
|
|
role: 'player' | 'spectator'
|
|
}
|
|
|
|
export interface LeaveGameRequest {
|
|
game_id: string
|
|
}
|
|
|
|
export interface DefensiveDecisionRequest {
|
|
game_id: string
|
|
infield_depth: DefensiveDecision['infield_depth']
|
|
outfield_depth: DefensiveDecision['outfield_depth']
|
|
hold_runners: number[]
|
|
}
|
|
|
|
export interface OffensiveDecisionRequest {
|
|
game_id: string
|
|
action: OffensiveDecision['action']
|
|
steal_attempts: number[]
|
|
}
|
|
|
|
export interface RollDiceRequest {
|
|
game_id: string
|
|
}
|
|
|
|
export interface SubmitManualOutcomeRequest {
|
|
game_id: string
|
|
outcome: string
|
|
hit_location?: string
|
|
}
|
|
|
|
export interface PinchHitterRequest {
|
|
game_id: string
|
|
player_out_lineup_id: number
|
|
player_in_card_id: number
|
|
team_id: number
|
|
}
|
|
|
|
export interface DefensiveReplacementRequest {
|
|
game_id: string
|
|
player_out_lineup_id: number
|
|
player_in_card_id: number
|
|
new_position: string
|
|
team_id: number
|
|
}
|
|
|
|
export interface PitchingChangeRequest {
|
|
game_id: string
|
|
player_out_lineup_id: number
|
|
player_in_card_id: number
|
|
team_id: number
|
|
}
|
|
|
|
export interface GetLineupRequest {
|
|
game_id: string
|
|
team_id: number
|
|
}
|
|
|
|
export interface GetBoxScoreRequest {
|
|
game_id: string
|
|
}
|
|
|
|
export interface RequestGameStateRequest {
|
|
game_id: string
|
|
}
|
|
|
|
// ============================================================================
|
|
// Server → Client Event Types
|
|
// ============================================================================
|
|
|
|
export interface ConnectedEvent {
|
|
user_id: string
|
|
}
|
|
|
|
export interface GameJoinedEvent {
|
|
game_id: string
|
|
role: 'player' | 'spectator'
|
|
}
|
|
|
|
export interface UserConnectedEvent {
|
|
user_id: string
|
|
game_id: string
|
|
}
|
|
|
|
export interface UserDisconnectedEvent {
|
|
user_id: string
|
|
game_id: string
|
|
}
|
|
|
|
export interface DefensiveDecisionSubmittedEvent {
|
|
game_id: string
|
|
decision: DefensiveDecision
|
|
pending_decision: 'offensive' | 'resolution' | null
|
|
}
|
|
|
|
export interface OffensiveDecisionSubmittedEvent {
|
|
game_id: string
|
|
decision: OffensiveDecision
|
|
pending_decision: 'resolution' | null
|
|
}
|
|
|
|
export interface DiceRolledEvent {
|
|
game_id: string
|
|
roll_id: string
|
|
d6_one: number
|
|
d6_two_total: number
|
|
chaos_d20: number
|
|
resolution_d20: number
|
|
check_wild_pitch: boolean
|
|
check_passed_ball: boolean
|
|
timestamp: string
|
|
message: string
|
|
}
|
|
|
|
export interface OutcomeAcceptedEvent {
|
|
outcome: string
|
|
hit_location?: string
|
|
}
|
|
|
|
export interface InningChangeEvent {
|
|
inning: number
|
|
half: 'top' | 'bottom'
|
|
}
|
|
|
|
export interface GameEndedEvent {
|
|
game_id: string
|
|
winner_team_id: number
|
|
final_score: {
|
|
home: number
|
|
away: number
|
|
}
|
|
completed_at: string
|
|
}
|
|
|
|
export interface SubstitutionConfirmedEvent {
|
|
type: string
|
|
new_lineup_id: number
|
|
message: string
|
|
}
|
|
|
|
export interface BoxScoreDataEvent {
|
|
game_id: string
|
|
box_score: {
|
|
game_stats: {
|
|
home_runs: number
|
|
away_runs: number
|
|
home_hits: number
|
|
away_hits: number
|
|
home_errors: number
|
|
away_errors: number
|
|
linescore_home: number[]
|
|
linescore_away: number[]
|
|
}
|
|
batting_stats: BattingStatLine[]
|
|
pitching_stats: PitchingStatLine[]
|
|
}
|
|
}
|
|
|
|
export interface BattingStatLine {
|
|
lineup_id: number
|
|
player_card_id: number
|
|
pa: number
|
|
ab: number
|
|
run: number
|
|
hit: number
|
|
rbi: number
|
|
double: number
|
|
triple: number
|
|
hr: number
|
|
bb: number
|
|
so: number
|
|
hbp: number
|
|
sac: number
|
|
sb: number
|
|
cs: number
|
|
gidp: number
|
|
}
|
|
|
|
export interface PitchingStatLine {
|
|
lineup_id: number
|
|
player_card_id: number
|
|
batters_faced: number
|
|
ip: number
|
|
hit_allowed: number
|
|
run_allowed: number
|
|
erun: number
|
|
bb: number
|
|
so: number
|
|
hbp: number
|
|
hr_allowed: number
|
|
wp: number
|
|
}
|
|
|
|
export interface GameStateSyncEvent {
|
|
state: GameState
|
|
recent_plays: PlayResult[]
|
|
timestamp: string
|
|
}
|
|
|
|
export interface ErrorEvent {
|
|
message: string
|
|
code?: string
|
|
field?: string
|
|
hint?: string
|
|
}
|
|
|
|
export interface OutcomeRejectedEvent {
|
|
message: string
|
|
field: string
|
|
errors?: Array<{
|
|
loc: string[]
|
|
msg: string
|
|
type: string
|
|
}>
|
|
}
|
|
|
|
export interface InvalidActionEvent {
|
|
action: string
|
|
reason: string
|
|
}
|
|
|
|
export interface ConnectionErrorEvent {
|
|
error: string
|
|
details?: string
|
|
}
|
|
|
|
/**
|
|
* Type-safe Socket.io instance
|
|
*/
|
|
export interface TypedSocket {
|
|
on<K extends keyof ServerToClientEvents>(
|
|
event: K,
|
|
listener: ServerToClientEvents[K]
|
|
): void
|
|
|
|
emit<K extends keyof ClientToServerEvents>(
|
|
event: K,
|
|
...args: Parameters<ClientToServerEvents[K]>
|
|
): void
|
|
|
|
off<K extends keyof ServerToClientEvents>(
|
|
event: K,
|
|
listener?: ServerToClientEvents[K]
|
|
): void
|
|
|
|
connect(): void
|
|
disconnect(): void
|
|
|
|
readonly connected: boolean
|
|
readonly id: string
|
|
}
|