Files
csgowtf/src/lib/schemas/roundStats.schema.ts
vikingowl d811efc394 feat: complete Phase 3 - Domain Modeling & Data Layer
Implements comprehensive type system, runtime validation, API client,
and testing infrastructure for CS2.WTF.

TypeScript Interfaces (src/lib/types/):
- Match.ts: Match, MatchPlayer, MatchListItem types
- Player.ts: Player, PlayerMeta, PlayerProfile types
- RoundStats.ts: Round economy and performance data
- Weapon.ts: Weapon statistics with hit groups (HitGroup, WeaponType enums)
- Message.ts: Chat messages with filtering support
- api.ts: API responses, errors, and APIException class
- Complete type safety with strict null checks

Zod Schemas (src/lib/schemas/):
- Runtime validation for all data models
- Schema parsers with safe/unsafe variants
- Special handling for backend typo (looses → losses)
- Share code validation regex
- CS2-specific validations (rank 0-30000, MR12 rounds)

API Client (src/lib/api/):
- client.ts: Axios-based HTTP client with error handling
  - Request cancellation support (AbortController)
  - Automatic retry logic for transient failures
  - Timeout handling (10s default)
  - Typed APIException errors
- players.ts: Player endpoints (profile, meta, track/untrack, search)
- matches.ts: Match endpoints (parse, details, weapons, rounds, chat, search)
- Zod validation on all API responses

MSW Mock Handlers (src/mocks/):
- fixtures.ts: Comprehensive mock data for testing
- handlers/players.ts: Mock player API endpoints
- handlers/matches.ts: Mock match API endpoints
- browser.ts: Browser MSW worker for development
- server.ts: Node MSW server for Vitest tests
- Realistic responses with delays and pagination
- Safe integer IDs to avoid precision loss

Configuration:
- .env.example: Complete environment variable documentation
- src/vite-env.d.ts: Vite environment type definitions
- All strict TypeScript checks passing (0 errors, 0 warnings)

Features:
- Cancellable requests for search (prevent race conditions)
- Data normalization (backend typo handling)
- Comprehensive error types (NetworkError, Timeout, etc.)
- Share code parsing and validation
- Pagination support for players and matches
- Mock data for offline development and testing

Build Status: ✓ Production build successful
Type Check: ✓ 0 errors, 0 warnings
Lint: ✓ All checks passed
Phase 3 Completion: 100%

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 20:31:20 +01:00

63 lines
2.4 KiB
TypeScript

import { z } from 'zod';
/**
* Zod schemas for Round Statistics data models
*/
/** RoundStats schema */
export const roundStatsSchema = z.object({
round: z.number().int().positive(),
bank: z.number().int().nonnegative(),
equipment: z.number().int().nonnegative(),
spent: z.number().int().nonnegative(),
kills_in_round: z.number().int().nonnegative().optional(),
damage_in_round: z.number().int().nonnegative().optional(),
match_player_id: z.number().positive().optional(),
player_id: z.number().positive().optional()
});
/** RoundDetail schema (with player breakdown) */
export const roundDetailSchema = z.object({
round: z.number().int().positive(),
winner: z.number().int().min(2).max(3), // 2 = T, 3 = CT
win_reason: z.string(),
players: z.array(roundStatsSchema)
});
/** MatchRoundsResponse schema */
export const matchRoundsResponseSchema = z.object({
match_id: z.number().positive(),
rounds: z.array(roundDetailSchema)
});
/** TeamRoundStats schema */
export const teamRoundStatsSchema = z.object({
round: z.number().int().positive(),
team_id: z.number().int().min(2).max(3),
total_bank: z.number().int().nonnegative(),
total_equipment: z.number().int().nonnegative(),
avg_equipment: z.number().nonnegative(),
total_spent: z.number().int().nonnegative(),
winner: z.number().int().min(2).max(3).optional(),
win_reason: z
.enum(['elimination', 'bomb_defused', 'bomb_exploded', 'time', 'target_saved'])
.optional(),
buy_type: z.enum(['eco', 'semi-eco', 'force', 'full']).optional()
});
/** Parser functions */
export const parseRoundStats = (data: unknown) => roundStatsSchema.parse(data);
export const parseRoundDetail = (data: unknown) => roundDetailSchema.parse(data);
export const parseMatchRounds = (data: unknown) => matchRoundsResponseSchema.parse(data);
export const parseTeamRoundStats = (data: unknown) => teamRoundStatsSchema.parse(data);
/** Safe parser functions */
export const parseRoundStatsSafe = (data: unknown) => roundStatsSchema.safeParse(data);
export const parseMatchRoundsSafe = (data: unknown) => matchRoundsResponseSchema.safeParse(data);
/** Infer TypeScript types */
export type RoundStatsSchema = z.infer<typeof roundStatsSchema>;
export type RoundDetailSchema = z.infer<typeof roundDetailSchema>;
export type MatchRoundsResponseSchema = z.infer<typeof matchRoundsResponseSchema>;
export type TeamRoundStatsSchema = z.infer<typeof teamRoundStatsSchema>;