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>
8.7 KiB
API Proxying with SvelteKit Server Routes
This document explains how API requests are proxied to the backend using SvelteKit server routes.
Why Use Server Routes?
The CS2.WTF frontend uses SvelteKit server routes to proxy API requests to the backend. This approach provides several benefits:
- ✅ Works in all environments: Development, preview, and production
- ✅ No CORS issues: Requests are server-side
- ✅ Single code path: Same behavior everywhere
- ✅ Flexible backend switching: Change one environment variable
- ✅ Future-proof: Can add caching, rate limiting, auth later
- ✅ Better security: Backend URL not exposed to client
Architecture
Request Flow
Browser → /api/matches → SvelteKit Server Route → Backend → Response
Detailed Flow:
1. Browser: GET http://localhost:5173/api/matches?limit=20
↓
2. SvelteKit: Routes to src/routes/api/[...path]/+server.ts
↓
3. Server Handler: Reads VITE_API_BASE_URL environment variable
↓
4. Backend Call: GET https://api.csgow.tf/matches?limit=20
↓
5. Backend: Returns JSON response
↓
6. Server Handler: Forwards response to browser
↓
7. Browser: Receives response (no CORS issues!)
SSR (Server-Side Rendering) Flow:
1. Page Load: +page.ts calls api.matches.getMatches()
↓
2. API Client: Detects import.meta.env.SSR === true
↓
3. Direct Call: GET https://api.csgow.tf/matches?limit=20
↓
4. Backend: Returns JSON response
↓
5. SSR: Renders page with data
Note: SSR bypasses the SvelteKit route and calls the backend directly because relative URLs (/api) don't work during server-side rendering.
Key Components
1. SvelteKit Server Route (src/routes/api/[...path]/+server.ts)
- Catch-all route that matches
/api/* - Forwards requests to backend
- Supports GET, POST, DELETE methods
- Handles errors gracefully
2. API Client (src/lib/api/client.ts)
- Browser: Uses
/apibase URL (routes to SvelteKit) - SSR: Uses
VITE_API_BASE_URLdirectly (bypasses SvelteKit route) - Automatically detects environment with
import.meta.env.SSR
3. Environment Variable (.env)
VITE_API_BASE_URLcontrols which backend to use- Switch between local and production easily
Configuration
Environment Variables
.env:
# Production API (default)
VITE_API_BASE_URL=https://api.csgow.tf
# Local backend (for development)
# VITE_API_BASE_URL=http://localhost:8000
Switching Backends:
# Use production API
echo "VITE_API_BASE_URL=https://api.csgow.tf" > .env
npm run dev
# Use local backend
echo "VITE_API_BASE_URL=http://localhost:8000" > .env
npm run dev
Server Route Implementation
File: src/routes/api/[...path]/+server.ts
import { error, json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.csgow.tf';
export const GET: RequestHandler = async ({ params, url }) => {
const path = params.path; // e.g., "matches"
const queryString = url.search; // e.g., "?limit=20"
const backendUrl = `${API_BASE_URL}/${path}${queryString}`;
try {
const response = await fetch(backendUrl);
const data = await response.json();
return json(data);
} catch (err) {
throw error(503, 'Unable to connect to backend');
}
};
API Client Configuration
File: src/lib/api/client.ts
// Simple, single configuration
const API_BASE_URL = '/api';
// Always routes to SvelteKit server routes
// No environment detection needed
Testing the Setup
1. Check Environment Variable
cat .env
# Should show:
VITE_API_BASE_URL=https://api.csgow.tf
# or
VITE_API_BASE_URL=http://localhost:8000
2. Start Development Server
npm run dev
# Server starts on http://localhost:5173
3. Check Network Requests
Open DevTools → Network tab:
- ✅ Requests go to
/api/matches,/api/player/123, etc. - ✅ Status should be
200 OK - ✅ No CORS errors in console
4. Test Both Backends
Test Production API:
# Set production API
echo "VITE_API_BASE_URL=https://api.csgow.tf" > .env
# Start dev server
npm run dev
# Visit http://localhost:5173/matches
# Should load matches from production API
Test Local Backend:
# Start local backend first
cd ../csgowtfd
go run main.go
# In another terminal, set local API
echo "VITE_API_BASE_URL=http://localhost:8000" > .env
# Start dev server
npm run dev
# Visit http://localhost:5173/matches
# Should load matches from local backend
Common Issues
Issue 1: 503 Service Unavailable
Symptom: API requests return 503 error
Possible Causes:
- Backend is not running
- Wrong
VITE_API_BASE_URLin.env - Network connectivity issues
Fix:
# Check .env file
cat .env
# If using local backend, make sure it's running
curl http://localhost:8000/matches
# If using production API, check connectivity
curl https://api.csgow.tf/matches
# Restart dev server after changing .env
npm run dev
Issue 2: 404 Not Found
Symptom: /api/* routes return 404
Cause: SvelteKit server route file missing or not loaded
Fix:
# Check file exists
ls src/routes/api/[...path]/+server.ts
# If missing, create it
mkdir -p src/routes/api/'[...path]'
# Then create +server.ts file
# Restart dev server
npm run dev
Issue 3: Environment Variable Not Loading
Symptom: Server route uses wrong backend URL
Cause: Changes to .env require server restart
Fix:
# Stop dev server (Ctrl+C)
# Update .env
echo "VITE_API_BASE_URL=http://localhost:8000" > .env
# Start dev server again
npm run dev
Issue 4: CORS Errors Still Appearing
Symptom: Browser console shows CORS errors
Cause: API client is not using /api prefix
Fix:
Check src/lib/api/client.ts:
// Should be:
const API_BASE_URL = '/api';
// Not:
const API_BASE_URL = 'https://api.csgow.tf'; // ❌ Wrong
How It Works Compared to Vite Proxy
Old Approach (Vite Proxy)
Development:
Browser → /api → Vite Proxy → Backend
Production:
Browser → Backend (direct, different code path)
Problems:
- Two different code paths (dev vs prod)
- Proxy only works in development
- SSR has to bypass proxy
- Complex configuration
New Approach (SvelteKit Server Routes)
All Environments:
Browser → /api → SvelteKit Route → Backend
Benefits:
- Single code path
- Works in dev, preview, and production
- Consistent behavior everywhere
- Simpler configuration
Adding Features
Add Request Caching
File: src/routes/api/[...path]/+server.ts
const cache = new Map<string, { data: any; expires: number }>();
export const GET: RequestHandler = async ({ params, url }) => {
const cacheKey = `${params.path}${url.search}`;
// Check cache
const cached = cache.get(cacheKey);
if (cached && Date.now() < cached.expires) {
return json(cached.data);
}
// Fetch from backend
const data = await fetch(`${API_BASE_URL}/${params.path}${url.search}`).then((r) => r.json());
// Cache for 5 minutes
cache.set(cacheKey, {
data,
expires: Date.now() + 5 * 60 * 1000
});
return json(data);
};
Add Rate Limiting
import { rateLimit } from '$lib/server/rateLimit';
export const GET: RequestHandler = async ({ request, params, url }) => {
// Check rate limit
await rateLimit(request);
// Continue with normal flow...
};
Add Authentication
export const GET: RequestHandler = async ({ request, params, url }) => {
// Get auth token from cookie
const token = request.headers.get('cookie')?.includes('auth_token');
// Forward to backend with auth
const response = await fetch(backendUrl, {
headers: {
Authorization: `Bearer ${token}`
}
});
// ...
};
Summary
| Feature | Vite Proxy | SvelteKit Routes |
|---|---|---|
| Works in dev | ✅ | ✅ |
| Works in production | ❌ | ✅ |
| Single code path | ❌ | ✅ |
| Can add caching | ❌ | ✅ |
| Can add rate limiting | ❌ | ✅ |
| Can add auth | ❌ | ✅ |
| SSR compatible | ❌ | ✅ |
SvelteKit server routes provide a production-ready, maintainable solution for API proxying that works in all environments.