import { apiClient } from './client'; import { parsePlayer } from '$lib/schemas'; import type { Player, PlayerMeta, TrackPlayerResponse } from '$lib/types'; import { transformPlayerProfile, type LegacyPlayerProfile } from './transformers'; /** * Player API endpoints */ export const playersAPI = { /** * Get player profile with match history * @param steamId - Steam ID (uint64 as string to preserve precision) * @param beforeTime - Optional Unix timestamp for pagination * @returns Player profile with recent matches */ async getPlayer(steamId: string, beforeTime?: number): Promise { const url = beforeTime ? `/player/${steamId}/next/${beforeTime}` : `/player/${steamId}`; const data = await apiClient.get(url); // Validate with Zod schema return parsePlayer(data); }, /** * Get lightweight player metadata * @param steamId - Steam ID (uint64 as string to preserve precision) * @param limit - Number of recent matches to include (default: 10) * @returns Player metadata */ async getPlayerMeta(steamId: string, limit = 10): Promise { // Use the /player/{id} endpoint which has the data we need const url = `/player/${steamId}`; const legacyData = await apiClient.get(url); // Transform legacy API format to our schema format const transformedData = transformPlayerProfile(legacyData); // Validate the player data // parsePlayer throws on validation failure, so player is always defined if we reach this point const player = parsePlayer(transformedData); // Calculate aggregated stats from matches const matches = player.matches || []; const recentMatches = matches.slice(0, limit); const totalKills = recentMatches.reduce((sum, m) => sum + (m.stats?.kills || 0), 0); const totalDeaths = recentMatches.reduce((sum, m) => sum + (m.stats?.deaths || 0), 0); const totalKast = recentMatches.reduce((sum, _m) => { // KAST is a percentage, we need to calculate it // For now, we'll use a placeholder return sum + 0; }, 0); const wins = recentMatches.filter((m) => { // match_result 1 = win, 2 = loss return m.match_result === 1; }).length; const avgKills = recentMatches.length > 0 ? totalKills / recentMatches.length : 0; const avgDeaths = recentMatches.length > 0 ? totalDeaths / recentMatches.length : 0; const winRate = recentMatches.length > 0 ? wins / recentMatches.length : 0; // Find the most recent match date const lastMatchDate = matches.length > 0 && matches[0] ? matches[0].date : new Date().toISOString(); // Transform to PlayerMeta format const playerMeta: PlayerMeta = { id: parseInt(player.id, 10), name: player.name, avatar: player.avatar, // Already transformed by transformPlayerProfile recent_matches: recentMatches.length, last_match_date: lastMatchDate, avg_kills: avgKills, avg_deaths: avgDeaths, avg_kast: recentMatches.length > 0 ? totalKast / recentMatches.length : 0, // Placeholder KAST calculation win_rate: winRate }; return playerMeta; }, /** * Add player to tracking system * @param steamId - Steam ID (uint64 as string to preserve precision) * @param authCode - Steam authentication code * @returns Success response */ async trackPlayer(steamId: string, authCode: string): Promise { const url = `/player/${steamId}/track`; return apiClient.post(url, { auth_code: authCode }); }, /** * Remove player from tracking system * @param steamId - Steam ID (uint64 as string to preserve precision) * @returns Success response */ async untrackPlayer(steamId: string): Promise { const url = `/player/${steamId}/track`; return apiClient.delete(url); }, /** * Search players by name (cancelable) * @param query - Search query * @param limit - Maximum results * @returns Array of player matches */ async searchPlayers(query: string, limit = 10): Promise { const url = `/players/search`; const data = await apiClient.getCancelable(url, 'player-search', { params: { q: query, limit } }); return data; } }; /** * Player API with default export */ export default playersAPI;