Convert the players page and related components from DaisyUI to the
custom neon design system, matching the landing page and matches page
visual style. Adds decorative blur orbs, neon glow effects, and
consistent color semantics across PlayerCard, RecentPlayers, and
TrackPlayerModal components.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Convert matches page from DaisyUI to neon esports design system
- Add colored left borders to cards for instant win/loss/tie scanning
- Add player count badges and demo status icons to match cards
- Implement filter state preservation across navigation
- Add staggered card animations and skeleton loading states
- Add slide transition for filter panel
- Make cards compact with horizontal layout for better density
- Update grid to 4 columns on xl screens
- Style DataTable, ShareCodeInput with neon theme
- Add external link support to NeonButton
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract SearchModal component from SearchBar for root-level rendering
- Add isModalOpen state to search store with open/close methods
- Simplify SearchBar to trigger button only
- Update Modal with proper overflow handling and scroll-to-close
- Fix layout background to use void color
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Delete ThemeToggle.svelte component
- Remove theme toggle from Header
- Set permanent cs2dark theme in app.html
- Add darkreader-lock meta tag to prevent extension conflicts
- Add color-scheme: dark meta for browser hints
- Update theme-color to void (#0a0a0f)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Apply void dark background with neon-blue border accents
- Add neon text-shadow glow to logo (cyan + gold)
- Update nav links to hover:text-neon-blue with focus-visible states
- Add grid pattern overlay to footer
- Use neon-red for heart icon and donation hover
- Add motion-reduce support and accessible focus rings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create HeroSection with animated search bar and stat counters
- Add LiveMatchTicker with auto-scrolling recent matches
- Build FlashLeaderboard "Wall of Shame" with podium display
- Implement FeatureShowcase with scroll-triggered animations
- Add NeonCTA call-to-action section with trust badges
- Create reusable NeonButton component with glow effects
Accessibility improvements:
- Add aria-labels, aria-hidden for decorative elements
- Implement focus-visible ring styles for keyboard navigation
- Support prefers-reduced-motion across all animations
- Use semantic HTML (article, nav, dl) for screen readers
- Improve color contrast ratios for WCAG compliance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete site rebrand with flash-themed humor throughout:
- Update logo to "team" + "flash.rip" two-color design
- Add flash-themed error pages (404 = "You've Been Full-Blind")
- Revamp homepage hero with "Stop Flashing Your Teammates" tagline
- Update flash statistics page with playful labels ("Friendly Crimes", "Self-Inflicted L")
- Add loading messages store with flash-themed text
- Update all page meta titles and descriptions
- Update sitemap.xml and robots.txt with new domain
- Update package.json name and description
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dynamic MR12/MR15 halftime calculation to RoundTimeline component
- Fix TrackPlayerModal API signature (remove shareCode, change isOpen to open binding)
- Update Player types for string IDs and add ban fields (vac_count, vac_date, game_ban_count, game_ban_date)
- Add target/rel props to Button component for external links
- Enhance homepage with processing matches indicator
- Update preferences store for string player IDs
- Document Phase 5 progress and TypeScript fixes in TODO.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Based on comprehensive research, CS2 implements a bifurcated ranking system:
- Premier Mode: CS Rating (numerical ELO, 0-30,000+) - launched Aug 31, 2023
- Competitive/Wingman: Skill Groups (0-18, Silver I to Global Elite)
- Legacy CS:GO: Skill Groups only (pre-Sept 27, 2023)
Changes:
- Add game_mode field to Match type ('premier' | 'competitive' | 'wingman')
- Create rankingSystem.ts utility with smart detection logic:
* Checks match date (CS:GO legacy vs CS2)
* Checks game_mode (Premier vs Competitive/Wingman)
* Falls back to rating value heuristic (0-18 vs 1000+)
- Update PremierRatingBadge to use new detection logic
- Pass match context from match detail page to badge component
- Update Match and schema documentation with dual-system details
- Add research.md documenting CS2's ranking system architecture
Key dates:
- August 31, 2023: Premier Mode and CS Rating launched
- September 27, 2023: CS2 officially replaced CS:GO
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update Zod schemas to match raw API response formats
- Create transformation layer (rounds, weapons, chat) to convert raw API to structured format
- Add player name mapping in transformers for better UX
- Fix Svelte 5 reactivity issues in chat page (replace $effect with $derived)
- Fix Chart.js compatibility with Svelte 5 state proxies using JSON serialization
- Add economy advantage chart with halftime perspective flip (WIP)
- Remove stray comment from details page
- Update layout to load match data first, then pass to API methods
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Debug logging was added to troubleshoot rank detection logic.
Now that icons are working correctly, removing the console.log.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Set Rating column table cells to fixed height (h-12 = 48px)
- Wrap icons in flex container for vertical centering
- Reduce icon size from 14x14 to 11x11 to fit within row height
- Add max-h-11 constraint to prevent overflow
- Add inline-block and align-middle to icon for proper alignment
This ensures all table rows remain the same height regardless of
whether they show rank icons or Premier rating badges.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- sm: 6x6 → 10x10 (used in scoreboard tables)
- md: 8x8 → 12x12
- lg: 12x12 → 16x16
The icons were too small to see details at 6x6 pixels.
Now properly visible in the Rating column of match scoreboards.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The API returns CS:GO skill groups (0-18) in BOTH rank_old and rank_new
fields for legacy matches. Updated detection logic to:
- Check if rating (rank_new) is in 0-18 range (CS:GO skill groups)
- CS2 ratings are typically 1000-30000, so no overlap
- Use rating value for RankIcon display (contains current skill group)
Debug output showed:
- rating: 15-17 (CS:GO skill groups)
- oldRating: same values (15-17)
- Previous logic failed because rating was not 0
This fix properly detects and displays CS:GO rank icons for legacy matches.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update isLegacyRank check to properly detect CS:GO skill groups (0-18)
- Handle edge case where oldRating could be 0 (unranked)
- Add temporary debug logging to trace rank data values
- Fix detection for matches where rating is outside CS2 range
This will help identify if rank data is being passed correctly from the API.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented rank icon display system for pre-CS2 matches:
New Components:
- RankIcon.svelte: Displays CS:GO skill group icons (0-18)
- Supports sm/md/lg sizes
- Shows appropriate rank icon based on skill group
- Includes hover tooltips with rank names
- Handles all 19 rank tiers (Silver I → Global Elite)
Updated Components:
- PremierRatingBadge: Now intelligently switches between:
- CS:GO rank icons (when rank_old exists, rank_new doesn't)
- Premier rating badge (when rank_new exists)
- "Unranked" text (when neither exists)
Assets:
- Rank icons already present in static/images/rank_icons/
- Weapon icons already present in static/images/weapons/
- All icons in SVG format for crisp display at any size
Display Logic:
- Legacy matches (pre-Sept 2023): Show CS:GO rank icons
- Modern matches (CS2): Show Premier rating with trophy icon
- Automatically detects based on rank_old/rank_new fields
The scoreboard now displays the appropriate ranking visualization
based on match era, matching the original CSGO.WTF design.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Use parseMatchWeaponsSafe instead of parseMatchWeapons
- Use parseMatchChatSafe instead of parseMatchChat
- Throw clear error message when demo not parsed yet
- Prevents Zod validation errors from reaching page loaders
- Matches the pattern already used for rounds endpoint
This fixes Zod errors when navigating to match detail pages where
the demo hasn't been fully parsed yet by the backend.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix toast notification imports: change from showToast to toast.success/error
- Remove hover preloading from app.html and Tabs component
- Fix match rounds API handling with safe parsing for incomplete data
- Fix pagination timestamp calculation (API returns Unix timestamp, not ISO string)
- Refactor matches page state management to fix reactivity issues:
- Replace separate state variables with single matchesState object
- Completely replace state object on updates to trigger reactivity
- Fix infinite loop in intersection observer effect
- Add keyed each blocks for proper list rendering
- Remove client-side filtering (temporarily) to isolate reactivity issues
- Add error state handling with nextPageTime in matches loader
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement localStorage-based player visit tracking with display on home page.
## New Features
### Recently Visited Players Component
- **RecentPlayers.svelte**: Grid display of up to 10 recently visited players
- **Responsive Layout**: 1-4 columns based on screen size
- **Player Cards**: Avatar, name, and time since last visit
- **Remove Functionality**: Individual player removal with X button
- **Auto-show/hide**: Component only renders when players have been visited
### Player Visit Tracking
- **recentPlayers utility**: localStorage management functions
- `getRecentPlayers()`: Retrieve sorted list by most recent
- `addRecentPlayer()`: Add/update player visit with timestamp
- `removeRecentPlayer()`: Remove specific player from list
- `clearRecentPlayers()`: Clear entire history
- **Auto-tracking**: Player profile page automatically records visits on mount
- **Smart deduplication**: Visiting same player updates timestamp, no duplicates
- **Max limit**: Maintains up to 10 most recent players
### Time Display
- Relative time formatting: "Just now", "5m ago", "2h ago", "3d ago"
- Real-time updates when component mounts
- Human-readable timestamps
### UX Features
- **Hover Effects**: Border highlights and shadow on card hover
- **Team Colors**: Player names inherit team colors from profiles
- **Remove on Hover**: X button appears only on hover for clean interface
- **Click Protection**: Remove button prevents navigation when clicked
- **Footer Info**: Shows count of displayed players
## Implementation Details
- **localStorage Key**: `cs2wtf_recent_players`
- **Data Structure**: Array of `{id, name, avatar, visitedAt}` objects
- **Sort Order**: Most recently visited first
- **SSR Safe**: All localStorage operations check for browser environment
- **Error Handling**: Try-catch wraps all storage operations with console errors
## Integration
- Added to home page between hero and featured matches
- Integrates seamlessly with existing layout and styling
- No data fetching required - pure client-side functionality
- Persists across sessions via localStorage
This completes Phase 1 (6/6) - all critical features now implemented!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add per-player VAC and game ban status display in match details scoreboard.
## Changes
- **Types & Schema**: Add vac and game_ban optional boolean fields to MatchPlayer
- **Transformer**: Extract vac and game_ban from legacy player.vac and player.game_ban
- **UI**: Add "Status" column to details table showing VAC/BAN badges
- **Mocks**: Update mock player data with ban status fields
## Implementation Details
The backend API provides per-player ban status in match details via the player
object (player.vac and player.game_ban). These were previously not being extracted
by the transformer.
The new Status column displays:
- Red "VAC" badge if player has VAC ban
- Red "BAN" badge if player has game ban
- Both badges if player has both bans
- "-" if player has no bans
Users can identify banned players at a glance in the scoreboard, improving
transparency and match context.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit completes the first phase of feature parity implementation and
resolves all API integration issues to match the backend API format.
## API Integration Fixes
- Remove all hardcoded default values from transformers (tick_rate, kast, player_count, steam_updated)
- Update TypeScript types to make fields optional where backend doesn't guarantee them
- Update Zod schemas to validate optional fields correctly
- Fix mock data to match real API response format (plain arrays, not wrapped objects)
- Update UI components to handle undefined values with proper fallbacks
- Add comprehensive API documentation for Match and Player endpoints
## Phase 1 Features Implemented (3/6)
### 1. Player Tracking System ✅
- Created TrackPlayerModal.svelte with auth code input
- Integrated track/untrack player API endpoints
- Added UI for providing optional share code
- Displays tracked status on player profiles
- Full validation and error handling
### 2. Share Code Parsing ✅
- Created ShareCodeInput.svelte component
- Added to matches page for easy match submission
- Real-time validation of share code format
- Parse status feedback with loading states
- Auto-redirect to match page on success
### 3. VAC/Game Ban Status ✅
- Added VAC and game ban count/date fields to Player type
- Display status badges on player profile pages
- Show ban count and date when available
- Visual indicators using DaisyUI badge components
## Component Improvements
- Modal.svelte: Added Svelte 5 Snippet types, actions slot support
- ThemeToggle.svelte: Removed deprecated svelte:component usage
- Tooltip.svelte: Fixed type safety with Snippet type
- All new components follow Svelte 5 runes pattern ($state, $derived, $bindable)
## Type Safety & Linting
- Fixed all ESLint errors (any types → proper types)
- Fixed form label accessibility issues
- Replaced error: any with error: unknown + proper type guards
- Added Snippet type imports where needed
- Updated all catch blocks to use instanceof Error checks
## Static Assets
- Migrated all files from public/ to static/ directory per SvelteKit best practices
- Moved 200+ map icons, screenshots, and other assets
- Updated all import paths to use /images/ (served from static/)
## Documentation
- Created IMPLEMENTATION_STATUS.md tracking all 15 missing features
- Updated API.md with optional field annotations
- Created MATCHES_API.md with comprehensive endpoint documentation
- Added inline comments marking optional vs required fields
## Testing
- Updated mock fixtures to remove default values
- Fixed mock handlers to return plain arrays like real API
- Ensured all components handle undefined gracefully
## Remaining Phase 1 Tasks
- [ ] Add VAC status column to match scoreboard
- [ ] Create weapons statistics tab for matches
- [ ] Implement recently visited players on home page
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add LegacyPlayerProfile transformer to handle API response format mismatch
- Transform avatar hashes to full Steam CDN URLs
- Map team IDs correctly (API 1/2 -> Schema 2/3)
- Calculate aggregate stats (avg_kills, avg_deaths, win_rate) from matches
- Reduce featured matches on homepage from 6 to 3
- Show 4 recent matches on player profile instead of 10
- Display recent matches in 4-column grid on desktop (side-by-side)
Fixes "Player not found" error for all player profiles.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Enable SSR for match pages by detecting server vs client context in API client
- Fix 500 errors on economy, chat, and details tabs by adding data loaders
- Handle unparsed matches gracefully with "Match Not Parsed" messages
- Fix dynamic team ID detection instead of hardcoding team IDs 2/3
- Fix DataTable component to properly render HTML in render functions
- Add fixed column widths to tables for visual consistency
- Add meta titles to all tab page loaders
- Fix Svelte 5 $derived syntax errors
- Fix ESLint errors (unused imports, any types, reactive state)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
JavaScript's Number type cannot accurately represent uint64 values exceeding
Number.MAX_SAFE_INTEGER (2^53-1). Converting these IDs to numbers causes
precision loss and API errors.
Root cause found:
- match/[id]/+layout.ts: `Number(params.id)` corrupted match IDs
- player/[id]/+page.ts: `Number(params.id)` corrupted player IDs
Example of the bug:
- URL param: "3638078243082338615" (correct)
- After Number(): 3638078243082339000 (rounded!)
- API response: "Match 3638078243082339000 not found"
Changes:
- Remove Number() conversions in route loaders
- Keep params.id as string throughout the application
- Update API functions to only accept string (not string | number)
- Update MatchesQueryParams.player_id type to string
- Add comprehensive transformers for legacy API responses
- Transform player stats: duo→mk_2, triple→mk_3, steamid64→id
- Build full Steam avatar URLs
- Make share_code optional (not always present)
This ensures uint64 IDs maintain full precision from URL → API → response.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create transformers.ts to convert legacy API format to new schema
- Transform score array [a, b] to score_team_a/score_team_b fields
- Convert Unix timestamps to ISO strings
- Map legacy field names (parsed, vac, game_ban) to new names
- Update matches API to use transformer with proper types
- Handle empty map names gracefully in homepage
- Limit featured matches to exactly 6 items
Fixes homepage data display issue where API format mismatch prevented
matches from rendering. API returns legacy CSGO:WTF format while frontend
expects new CS2.WTF schema.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented comprehensive performance analysis for player profiles with interactive charts
and detailed statistics visualization.
Key Features:
- Performance Trend Chart (K/D and KAST over last 15 matches)
- Map Performance Chart (win rate per map with color coding)
- Utility Effectiveness Stats (flash assists, enemies blinded, HE/flame damage)
- Responsive charts using Chart.js LineChart and BarChart components
Technical Updates:
- Enhanced page loader to fetch 15 detailed matches with player stats
- Fixed DataTable Svelte 5 compatibility and type safety
- Updated MatchCard and PlayerCard to use PlayerMeta properties
- Proper error handling and typed data structures
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented a comprehensive CORS proxy solution that works with both
local and remote backends during development.
## Changes
### Vite Configuration (vite.config.ts)
- Use loadEnv() to properly read VITE_API_BASE_URL from .env
- Configure proxy to forward /api/* requests to backend
- Add detailed logging for proxy requests and responses
- Support changeOrigin, rewrite, secure=false, and websockets
### API Client (src/lib/api/client.ts)
- In development: Always use /api prefix (proxied)
- In production: Use direct VITE_API_BASE_URL
- Add console logging to show proxy configuration in dev mode
- Automatic detection of environment (DEV vs PROD)
### Error Handling (route loaders)
- Fix console.error() calls that caused TypeError with circular refs
- Use error.message instead of logging full error objects
- Affects: +page.ts, matches/+page.ts
### Documentation
- docs/LOCAL_DEVELOPMENT.md: Complete rewrite with proxy explanation
- Quick start guide for both production API and local backend
- Detailed proxy flow diagrams
- Comprehensive troubleshooting section
- Clear examples and logs
- docs/CORS_PROXY.md: Technical deep-dive on proxy implementation
- How the proxy works internally
- Configuration options explained
- Testing procedures
- Common issues and solutions
- .env.example: Updated with proxy documentation
## How It Works
Development Flow:
1. Frontend makes request: /api/matches
2. Vite proxy intercepts and forwards to: ${VITE_API_BASE_URL}/matches
3. Backend responds (no CORS headers needed)
4. Proxy returns response to frontend (same-origin)
Production Flow:
1. Frontend makes request directly to: https://api.csgow.tf/matches
2. Backend responds with CORS headers
3. Browser allows request (CORS enabled on backend)
## Benefits
✅ No CORS errors in development
✅ Works with local backend (localhost:8000)
✅ Works with remote backend (api.csgow.tf)
✅ Simple configuration (just set VITE_API_BASE_URL)
✅ Detailed logging for debugging
✅ Production build unaffected (direct requests)
## Testing
Verified with production API:
- curl https://api.csgow.tf/matches ✓
- Dev server proxy logs show successful forwarding ✓
- Browser Network tab shows /api/* requests ✓
- No CORS errors in console ✓
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace invalid {@const} usage with proper <svelte:component this={...}> syntax.
The {@const} tag must be an immediate child of specific block structures,
not directly inside regular HTML elements.
This commit implements significant portions of Phase 5 (Feature Delivery) including:
Chart Components (src/lib/components/charts/):
- LineChart.svelte: Line charts with Chart.js integration
- BarChart.svelte: Vertical/horizontal bar charts with stacking
- PieChart.svelte: Pie/Doughnut charts with legend
- All charts use Svelte 5 runes ($effect) for reactivity
- Responsive design with customizable options
Data Display Components (src/lib/components/data-display/):
- DataTable.svelte: Generic sortable, filterable table component
- TypeScript generics support for type safety
- Custom formatters and renderers
- Sort indicators and column alignment options
Match Detail Pages:
- Match layout with header, tabs, and score display
- Economy tab: Equipment value charts, buy type classification, round-by-round table
- Details tab: Multi-kill distribution charts, team performance, top performers
- Chat tab: Chronological messages with filtering, search, and round grouping
Additional Components:
- SearchBar, ThemeToggle (layout components)
- MatchCard, PlayerCard (domain components)
- Modal, Skeleton, Tabs, Tooltip (UI components)
- Player profile page with stats and recent matches
Dependencies:
- Installed chart.js for data visualization
- Created Svelte 5 compatible chart wrappers
Phase 4 marked as complete, Phase 5 at 50% completion.
Flashes and Damage tabs deferred for future implementation.
Note: Minor linting warnings to be addressed in follow-up commit.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 4 establishes the core application structure with SvelteKit routing,
data loading, error handling, and state management.
## Routing & Data Loading
- Created root layout load function (+layout.ts) with app version and feature flags
- Implemented comprehensive error boundary (+error.svelte) with status-based messages
- Added page loaders for homepage, matches, players, and about routes
- Homepage loader fetches featured matches via API with error fallback
- Matches loader supports URL query parameters (map, player_id, limit)
## State Management (Svelte Stores)
- preferences.ts: User settings with localStorage persistence
* Theme selection (cs2dark, cs2light, auto)
* Favorite players tracking
* Advanced stats toggle, date format preferences
- search.ts: Search state with recent searches (localStorage)
- toast.ts: Toast notification system with auto-dismiss
* Success, error, warning, info types
* Configurable duration and dismissibility
## UI Components
- Toast.svelte: Individual notification with Lucide icons
- ToastContainer.svelte: Fixed top-right toast display
- Integrated ToastContainer into root layout
## Fixes
- Fixed Svelte 5 deprecation warnings (removed <svelte:component> in runes mode)
- Updated homepage to use PageData from loader
- Added proper type safety across all load functions
## Testing
- Type check: 0 errors, 0 warnings
- Production build: Successful
- All Phase 4 core objectives completed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>