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>
This commit is contained in:
138
src/lib/types/Match.ts
Normal file
138
src/lib/types/Match.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Match data model
|
||||
* Represents a complete CS2 match with metadata and optional player stats
|
||||
*/
|
||||
export interface Match {
|
||||
/** Unique match identifier (uint64) */
|
||||
match_id: number;
|
||||
|
||||
/** CS:GO/CS2 share code */
|
||||
share_code: string;
|
||||
|
||||
/** Map name (e.g., "de_inferno") */
|
||||
map: string;
|
||||
|
||||
/** Match date and time (ISO 8601) */
|
||||
date: string;
|
||||
|
||||
/** Final score for team A (T/CT side) */
|
||||
score_team_a: number;
|
||||
|
||||
/** Final score for team B (CT/T side) */
|
||||
score_team_b: number;
|
||||
|
||||
/** Match duration in seconds */
|
||||
duration: number;
|
||||
|
||||
/** Match result: 0 = tie, 1 = team_a win, 2 = team_b win */
|
||||
match_result: number;
|
||||
|
||||
/** Maximum rounds (24 for MR12, 30 for MR15) */
|
||||
max_rounds: number;
|
||||
|
||||
/** Whether the demo has been successfully parsed */
|
||||
demo_parsed: boolean;
|
||||
|
||||
/** Whether any player has a VAC ban */
|
||||
vac_present: boolean;
|
||||
|
||||
/** Whether any player has a game ban */
|
||||
gameban_present: boolean;
|
||||
|
||||
/** Server tick rate (64 or 128) */
|
||||
tick_rate: number;
|
||||
|
||||
/** Array of player statistics (optional, included in detailed match view) */
|
||||
players?: MatchPlayer[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal match information for lists
|
||||
*/
|
||||
export interface MatchListItem {
|
||||
match_id: number;
|
||||
map: string;
|
||||
date: string;
|
||||
score_team_a: number;
|
||||
score_team_b: number;
|
||||
duration: number;
|
||||
demo_parsed: boolean;
|
||||
player_count: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match player statistics
|
||||
* Player performance data for a specific match
|
||||
*/
|
||||
export interface MatchPlayer {
|
||||
/** Player Steam ID */
|
||||
id: number;
|
||||
|
||||
/** Player display name */
|
||||
name: string;
|
||||
|
||||
/** Steam avatar URL */
|
||||
avatar: string;
|
||||
|
||||
/** Team ID: 2 = T side, 3 = CT side */
|
||||
team_id: number;
|
||||
|
||||
// Performance metrics
|
||||
kills: number;
|
||||
deaths: number;
|
||||
assists: number;
|
||||
|
||||
/** Headshot kills */
|
||||
headshot: number;
|
||||
|
||||
/** MVP stars earned */
|
||||
mvp: number;
|
||||
|
||||
/** In-game score */
|
||||
score: number;
|
||||
|
||||
/** KAST percentage (0-100): Kill/Assist/Survive/Trade */
|
||||
kast: number;
|
||||
|
||||
// Rank tracking (CS2 Premier rating: 0-30000)
|
||||
rank_old?: number;
|
||||
rank_new?: number;
|
||||
|
||||
// Damage statistics
|
||||
dmg_enemy?: number;
|
||||
dmg_team?: number;
|
||||
|
||||
// Multi-kill counts
|
||||
mk_2?: number; // Double kills
|
||||
mk_3?: number; // Triple kills
|
||||
mk_4?: number; // Quad kills
|
||||
mk_5?: number; // Aces
|
||||
|
||||
// Utility damage
|
||||
ud_he?: number; // HE grenade damage
|
||||
ud_flames?: number; // Molotov/Incendiary damage
|
||||
ud_flash?: number; // Flash grenades used
|
||||
ud_smoke?: number; // Smoke grenades used
|
||||
ud_decoy?: number; // Decoy grenades used
|
||||
|
||||
// Flash statistics
|
||||
flash_assists?: number;
|
||||
flash_duration_enemy?: number; // Total enemy blind time
|
||||
flash_duration_team?: number; // Total team blind time
|
||||
flash_duration_self?: number; // Self-flash time
|
||||
flash_total_enemy?: number; // Enemies flashed count
|
||||
flash_total_team?: number; // Teammates flashed count
|
||||
flash_total_self?: number; // Self-flash count
|
||||
|
||||
// Other
|
||||
crosshair?: string;
|
||||
color?: 'green' | 'yellow' | 'purple' | 'blue' | 'orange' | 'grey';
|
||||
avg_ping?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match with extended player details (full scoreboard)
|
||||
*/
|
||||
export type MatchWithPlayers = Match & {
|
||||
players: MatchPlayer[];
|
||||
};
|
||||
78
src/lib/types/Message.ts
Normal file
78
src/lib/types/Message.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Chat message data model
|
||||
* In-game chat messages from match demos
|
||||
*/
|
||||
export interface Message {
|
||||
/** Chat message text content */
|
||||
message: string;
|
||||
|
||||
/** true = all chat (both teams), false = team chat only */
|
||||
all_chat: boolean;
|
||||
|
||||
/** Game tick when message was sent */
|
||||
tick: number;
|
||||
|
||||
/** Reference to MatchPlayer ID */
|
||||
match_player_id?: number;
|
||||
|
||||
/** Player ID who sent the message */
|
||||
player_id?: number;
|
||||
|
||||
/** Player name (included in API response) */
|
||||
player_name?: string;
|
||||
|
||||
/** Round number when message was sent */
|
||||
round?: number;
|
||||
|
||||
/** Message timestamp (ISO 8601) */
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match chat response
|
||||
*/
|
||||
export interface MatchChatResponse {
|
||||
match_id: number;
|
||||
messages: Message[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat message with enhanced player data
|
||||
*/
|
||||
export interface EnrichedMessage extends Message {
|
||||
player_name: string;
|
||||
player_avatar?: string;
|
||||
team_id?: number;
|
||||
round: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat filter options
|
||||
*/
|
||||
export interface ChatFilter {
|
||||
/** Filter by player ID */
|
||||
player_id?: number;
|
||||
|
||||
/** Filter by chat type */
|
||||
chat_type?: 'all' | 'team' | 'all_chat';
|
||||
|
||||
/** Filter by round number */
|
||||
round?: number;
|
||||
|
||||
/** Search message content */
|
||||
search?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat statistics
|
||||
*/
|
||||
export interface ChatStats {
|
||||
total_messages: number;
|
||||
team_chat_count: number;
|
||||
all_chat_count: number;
|
||||
messages_per_player: Record<number, number>;
|
||||
most_active_player: {
|
||||
player_id: number;
|
||||
message_count: number;
|
||||
};
|
||||
}
|
||||
107
src/lib/types/Player.ts
Normal file
107
src/lib/types/Player.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import type { Match, MatchPlayer } from './Match';
|
||||
|
||||
/**
|
||||
* Player profile data model
|
||||
* Represents a Steam user with CS2 statistics
|
||||
*/
|
||||
export interface Player {
|
||||
/** Steam ID (uint64) */
|
||||
id: number;
|
||||
|
||||
/** Steam display name */
|
||||
name: string;
|
||||
|
||||
/** Steam avatar URL */
|
||||
avatar: string;
|
||||
|
||||
/** Custom Steam profile URL */
|
||||
vanity_url?: string;
|
||||
|
||||
/** Actual vanity URL (may differ from vanity_url) */
|
||||
vanity_url_real?: string;
|
||||
|
||||
/** Last time Steam profile was updated (ISO 8601) */
|
||||
steam_updated: string;
|
||||
|
||||
/** Steam account creation date (ISO 8601) */
|
||||
profile_created?: string;
|
||||
|
||||
/** Total competitive wins */
|
||||
wins?: number;
|
||||
|
||||
/**
|
||||
* Total competitive losses
|
||||
* Note: Backend has typo "looses", we map it to "losses"
|
||||
*/
|
||||
losses?: number;
|
||||
|
||||
/** Total ties */
|
||||
ties?: number;
|
||||
|
||||
/** Number of VAC bans on record */
|
||||
vac_count?: number;
|
||||
|
||||
/** Date of last VAC ban (ISO 8601) */
|
||||
vac_date?: string | null;
|
||||
|
||||
/** Number of game bans on record */
|
||||
game_ban_count?: number;
|
||||
|
||||
/** Date of last game ban (ISO 8601) */
|
||||
game_ban_date?: string | null;
|
||||
|
||||
/** Oldest match share code seen for this player */
|
||||
oldest_sharecode_seen?: string;
|
||||
|
||||
/** Recent matches with player statistics */
|
||||
matches?: PlayerMatch[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Player match entry (includes match + player stats)
|
||||
*/
|
||||
export interface PlayerMatch extends Match {
|
||||
/** Player's statistics for this match */
|
||||
stats: MatchPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lightweight player metadata for quick previews
|
||||
*/
|
||||
export interface PlayerMeta {
|
||||
id: number;
|
||||
name: string;
|
||||
avatar: string;
|
||||
recent_matches: number;
|
||||
last_match_date: string;
|
||||
avg_kills: number;
|
||||
avg_deaths: number;
|
||||
avg_kast: number;
|
||||
win_rate: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Player profile with calculated aggregate statistics
|
||||
*/
|
||||
export interface PlayerProfile extends Player {
|
||||
/** Total matches played */
|
||||
total_matches: number;
|
||||
|
||||
/** Overall K/D ratio */
|
||||
kd_ratio: number;
|
||||
|
||||
/** Overall win rate percentage */
|
||||
win_rate: number;
|
||||
|
||||
/** Average headshot percentage */
|
||||
avg_headshot_pct: number;
|
||||
|
||||
/** Average KAST percentage */
|
||||
avg_kast: number;
|
||||
|
||||
/** Current CS2 Premier rating (0-30000) */
|
||||
current_rating?: number;
|
||||
|
||||
/** Peak CS2 Premier rating */
|
||||
peak_rating?: number;
|
||||
}
|
||||
85
src/lib/types/RoundStats.ts
Normal file
85
src/lib/types/RoundStats.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Round statistics data model
|
||||
* Economy and performance data for a single round
|
||||
*/
|
||||
export interface RoundStats {
|
||||
/** Round number (1-24 for MR12, 1-30 for MR15) */
|
||||
round: number;
|
||||
|
||||
/** Money available at round start */
|
||||
bank: number;
|
||||
|
||||
/** Value of equipment purchased/held */
|
||||
equipment: number;
|
||||
|
||||
/** Total money spent this round */
|
||||
spent: number;
|
||||
|
||||
/** Kills achieved in this round */
|
||||
kills_in_round?: number;
|
||||
|
||||
/** Damage dealt in this round */
|
||||
damage_in_round?: number;
|
||||
|
||||
/** Reference to MatchPlayer ID */
|
||||
match_player_id?: number;
|
||||
|
||||
/** Player ID for this round data */
|
||||
player_id?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Team round statistics
|
||||
* Aggregated economy data for a team in a round
|
||||
*/
|
||||
export interface TeamRoundStats {
|
||||
round: number;
|
||||
team_id: number; // 2 = T, 3 = CT
|
||||
|
||||
/** Total team money at round start */
|
||||
total_bank: number;
|
||||
|
||||
/** Total equipment value */
|
||||
total_equipment: number;
|
||||
|
||||
/** Average equipment value per player */
|
||||
avg_equipment: number;
|
||||
|
||||
/** Total money spent */
|
||||
total_spent: number;
|
||||
|
||||
/** Round winner (2 = T, 3 = CT) */
|
||||
winner?: number;
|
||||
|
||||
/** Win reason */
|
||||
win_reason?: 'elimination' | 'bomb_defused' | 'bomb_exploded' | 'time' | 'target_saved';
|
||||
|
||||
/** Buy type classification */
|
||||
buy_type?: 'eco' | 'semi-eco' | 'force' | 'full';
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete match rounds data
|
||||
*/
|
||||
export interface MatchRoundsData {
|
||||
match_id: number;
|
||||
rounds: RoundStats[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Round details with player breakdown
|
||||
*/
|
||||
export interface RoundDetail {
|
||||
round: number;
|
||||
winner: number;
|
||||
win_reason: string;
|
||||
players: RoundStats[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete match rounds response
|
||||
*/
|
||||
export interface MatchRoundsResponse {
|
||||
match_id: number;
|
||||
rounds: RoundDetail[];
|
||||
}
|
||||
147
src/lib/types/Weapon.ts
Normal file
147
src/lib/types/Weapon.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Weapon statistics data model
|
||||
* Tracks weapon usage, damage, and hit locations
|
||||
*/
|
||||
export interface Weapon {
|
||||
/** Player ID of the victim who was hit/killed */
|
||||
victim: number;
|
||||
|
||||
/** Damage dealt with this hit */
|
||||
dmg: number;
|
||||
|
||||
/** Weapon equipment type ID */
|
||||
eq_type: number;
|
||||
|
||||
/** Hit location group (1=head, 2=chest, 3=stomach, 4=left_arm, 5=right_arm, 6=left_leg, 7=right_leg) */
|
||||
hit_group: number;
|
||||
|
||||
/** Reference to MatchPlayer ID */
|
||||
match_player_id?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Weapon performance statistics for a player
|
||||
*/
|
||||
export interface WeaponStats {
|
||||
/** Weapon equipment type ID */
|
||||
eq_type: number;
|
||||
|
||||
/** Weapon display name */
|
||||
weapon_name: string;
|
||||
|
||||
/** Total kills with this weapon */
|
||||
kills: number;
|
||||
|
||||
/** Total damage dealt */
|
||||
damage: number;
|
||||
|
||||
/** Total hits landed */
|
||||
hits: number;
|
||||
|
||||
/** Hit group distribution */
|
||||
hit_groups: {
|
||||
head: number;
|
||||
chest: number;
|
||||
stomach: number;
|
||||
left_arm: number;
|
||||
right_arm: number;
|
||||
left_leg: number;
|
||||
right_leg: number;
|
||||
};
|
||||
|
||||
/** Headshot percentage */
|
||||
headshot_pct?: number;
|
||||
|
||||
/** Accuracy percentage (hits / shots) if available */
|
||||
accuracy?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Player weapon statistics
|
||||
*/
|
||||
export interface PlayerWeaponStats {
|
||||
player_id: number;
|
||||
weapon_stats: WeaponStats[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Match weapons response
|
||||
*/
|
||||
export interface MatchWeaponsResponse {
|
||||
match_id: number;
|
||||
weapons: PlayerWeaponStats[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hit group enumeration
|
||||
*/
|
||||
export enum HitGroup {
|
||||
Generic = 0,
|
||||
Head = 1,
|
||||
Chest = 2,
|
||||
Stomach = 3,
|
||||
LeftArm = 4,
|
||||
RightArm = 5,
|
||||
LeftLeg = 6,
|
||||
RightLeg = 7
|
||||
}
|
||||
|
||||
/**
|
||||
* Weapon type enumeration
|
||||
* Equipment type IDs from CS2
|
||||
*/
|
||||
export enum WeaponType {
|
||||
// Pistols
|
||||
Glock = 1,
|
||||
USP = 2,
|
||||
P2000 = 3,
|
||||
P250 = 4,
|
||||
Deagle = 5,
|
||||
FiveSeven = 6,
|
||||
Tec9 = 7,
|
||||
CZ75 = 8,
|
||||
DualBerettas = 9,
|
||||
|
||||
// SMGs
|
||||
MP9 = 10,
|
||||
MAC10 = 11,
|
||||
MP7 = 12,
|
||||
UMP45 = 13,
|
||||
P90 = 14,
|
||||
PPBizon = 15,
|
||||
MP5SD = 16,
|
||||
|
||||
// Rifles
|
||||
AK47 = 17,
|
||||
M4A4 = 18,
|
||||
M4A1S = 19,
|
||||
Galil = 20,
|
||||
Famas = 21,
|
||||
AUG = 22,
|
||||
SG553 = 23,
|
||||
|
||||
// Sniper Rifles
|
||||
AWP = 24,
|
||||
SSG08 = 25,
|
||||
SCAR20 = 26,
|
||||
G3SG1 = 27,
|
||||
|
||||
// Heavy
|
||||
Nova = 28,
|
||||
XM1014 = 29,
|
||||
Mag7 = 30,
|
||||
SawedOff = 31,
|
||||
M249 = 32,
|
||||
Negev = 33,
|
||||
|
||||
// Equipment
|
||||
Zeus = 34,
|
||||
Knife = 35,
|
||||
HEGrenade = 36,
|
||||
Flashbang = 37,
|
||||
Smoke = 38,
|
||||
Molotov = 39,
|
||||
Decoy = 40,
|
||||
Incendiary = 41,
|
||||
C4 = 42
|
||||
}
|
||||
161
src/lib/types/api.ts
Normal file
161
src/lib/types/api.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* API response types and error handling
|
||||
*/
|
||||
|
||||
import type { Match, MatchListItem } from './Match';
|
||||
import type { Player, PlayerMeta } from './Player';
|
||||
|
||||
/**
|
||||
* Standard API error response
|
||||
*/
|
||||
export interface APIError {
|
||||
error: string;
|
||||
message: string;
|
||||
status_code: number;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic API response wrapper
|
||||
*/
|
||||
export interface APIResponse<T> {
|
||||
data: T;
|
||||
success: boolean;
|
||||
error?: APIError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match parse response
|
||||
*/
|
||||
export interface MatchParseResponse {
|
||||
match_id: number;
|
||||
status: 'parsing' | 'queued' | 'completed' | 'error';
|
||||
message: string;
|
||||
estimated_time?: number; // seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Match parse status
|
||||
*/
|
||||
export interface MatchParseStatus {
|
||||
match_id: number;
|
||||
status: 'pending' | 'parsing' | 'completed' | 'error';
|
||||
progress?: number; // 0-100
|
||||
error_message?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches list response with pagination
|
||||
*/
|
||||
export interface MatchesListResponse {
|
||||
matches: MatchListItem[];
|
||||
next_page_time?: number; // Unix timestamp
|
||||
has_more: boolean;
|
||||
total_count?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match list query parameters
|
||||
*/
|
||||
export interface MatchesQueryParams {
|
||||
limit?: number; // 1-100
|
||||
map?: string;
|
||||
player_id?: number;
|
||||
before_time?: number; // Unix timestamp for pagination
|
||||
}
|
||||
|
||||
/**
|
||||
* Player track/untrack response
|
||||
*/
|
||||
export interface TrackPlayerResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Player profile response
|
||||
*/
|
||||
export type PlayerProfileResponse = Player;
|
||||
|
||||
/**
|
||||
* Player metadata response
|
||||
*/
|
||||
export type PlayerMetaResponse = PlayerMeta;
|
||||
|
||||
/**
|
||||
* Match details response
|
||||
*/
|
||||
export type MatchDetailsResponse = Match;
|
||||
|
||||
/**
|
||||
* Error types for better error handling
|
||||
*/
|
||||
export enum APIErrorType {
|
||||
NetworkError = 'NETWORK_ERROR',
|
||||
ServerError = 'SERVER_ERROR',
|
||||
NotFound = 'NOT_FOUND',
|
||||
BadRequest = 'BAD_REQUEST',
|
||||
Unauthorized = 'UNAUTHORIZED',
|
||||
Timeout = 'TIMEOUT',
|
||||
ValidationError = 'VALIDATION_ERROR',
|
||||
UnknownError = 'UNKNOWN_ERROR'
|
||||
}
|
||||
|
||||
/**
|
||||
* Typed API error class
|
||||
*/
|
||||
export class APIException extends Error {
|
||||
constructor(
|
||||
public type: APIErrorType,
|
||||
public message: string,
|
||||
public statusCode?: number,
|
||||
public details?: unknown
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'APIException';
|
||||
}
|
||||
|
||||
static fromResponse(statusCode: number, data?: unknown): APIException {
|
||||
let type: APIErrorType;
|
||||
let message: string;
|
||||
|
||||
switch (statusCode) {
|
||||
case 400:
|
||||
type = APIErrorType.BadRequest;
|
||||
message = 'Invalid request parameters';
|
||||
break;
|
||||
case 401:
|
||||
type = APIErrorType.Unauthorized;
|
||||
message = 'Unauthorized access';
|
||||
break;
|
||||
case 404:
|
||||
type = APIErrorType.NotFound;
|
||||
message = 'Resource not found';
|
||||
break;
|
||||
case 500:
|
||||
case 502:
|
||||
case 503:
|
||||
type = APIErrorType.ServerError;
|
||||
message = 'Server error occurred';
|
||||
break;
|
||||
default:
|
||||
type = APIErrorType.UnknownError;
|
||||
message = 'An unknown error occurred';
|
||||
}
|
||||
|
||||
// Extract message from response data if available
|
||||
if (data && typeof data === 'object' && 'message' in data) {
|
||||
message = String(data.message);
|
||||
}
|
||||
|
||||
return new APIException(type, message, statusCode, data);
|
||||
}
|
||||
|
||||
static networkError(message = 'Network connection failed'): APIException {
|
||||
return new APIException(APIErrorType.NetworkError, message);
|
||||
}
|
||||
|
||||
static timeout(message = 'Request timed out'): APIException {
|
||||
return new APIException(APIErrorType.Timeout, message);
|
||||
}
|
||||
}
|
||||
42
src/lib/types/index.ts
Normal file
42
src/lib/types/index.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Central export for all CS2.WTF type definitions
|
||||
*/
|
||||
|
||||
// Match types
|
||||
export type { Match, MatchListItem, MatchPlayer, MatchWithPlayers } from './Match';
|
||||
|
||||
// Player types
|
||||
export type { Player, PlayerMatch, PlayerMeta, PlayerProfile } from './Player';
|
||||
|
||||
// Round statistics types
|
||||
export type {
|
||||
RoundStats,
|
||||
TeamRoundStats,
|
||||
MatchRoundsData,
|
||||
RoundDetail,
|
||||
MatchRoundsResponse
|
||||
} from './RoundStats';
|
||||
|
||||
// Weapon types
|
||||
export type { Weapon, WeaponStats, PlayerWeaponStats, MatchWeaponsResponse } from './Weapon';
|
||||
|
||||
export { HitGroup, WeaponType } from './Weapon';
|
||||
|
||||
// Message/Chat types
|
||||
export type { Message, MatchChatResponse, EnrichedMessage, ChatFilter, ChatStats } from './Message';
|
||||
|
||||
// API response types
|
||||
export type {
|
||||
APIError,
|
||||
APIResponse,
|
||||
MatchParseResponse,
|
||||
MatchParseStatus,
|
||||
MatchesListResponse,
|
||||
MatchesQueryParams,
|
||||
TrackPlayerResponse,
|
||||
PlayerProfileResponse,
|
||||
PlayerMetaResponse,
|
||||
MatchDetailsResponse
|
||||
} from './api';
|
||||
|
||||
export { APIErrorType, APIException } from './api';
|
||||
Reference in New Issue
Block a user