const http = require('http'); const PORT = Number(process.env.PORT || 3000); const baseCors = { 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS', }; function nowIso() { return new Date().toISOString(); } function parseCookies(cookieHeader) { if (!cookieHeader) return {}; const out = {}; const parts = String(cookieHeader).split(';'); for (const part of parts) { const [rawKey, ...rest] = part.trim().split('='); if (!rawKey) continue; const rawValue = rest.join('='); out[rawKey] = decodeURIComponent(rawValue || ''); } return out; } function getDemoMode(req) { const cookies = parseCookies(req.headers.cookie); const raw = cookies.gridpilot_demo_mode || 'none'; if (raw === 'admin' || raw === 'driver' || raw === 'sponsor' || raw === 'none') return raw; return 'none'; } function getFaultMode(req) { const cookies = parseCookies(req.headers.cookie); const raw = cookies.gridpilot_fault_mode || ''; if (raw === 'null-array' || raw === 'missing-field' || raw === 'invalid-date') return raw; return null; } function getSessionDriftMode(req) { const cookies = parseCookies(req.headers.cookie); const raw = cookies.gridpilot_session_drift || ''; if (raw === 'invalid-cookie' || raw === 'expired' || raw === 'missing-sponsor-id') return raw; return null; } function sendJson(res, code, obj) { res.statusCode = code; res.setHeader('content-type', 'application/json'); res.end(JSON.stringify(obj)); } function sendNull(res) { res.statusCode = 200; res.setHeader('content-type', 'application/json'); res.end('null'); } function normalizeArrayFields(obj, fields) { if (!obj || typeof obj !== 'object') return obj; const out = { ...obj }; for (const field of fields) { if (out[field] == null) { out[field] = []; continue; } if (!Array.isArray(out[field])) { out[field] = []; } } return out; } const ONE_BY_ONE_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO0pS0kAAAAASUVORK5CYII='; function sendPng(res, code = 200) { res.statusCode = code; res.setHeader('content-type', 'image/png'); res.end(Buffer.from(ONE_BY_ONE_PNG_BASE64, 'base64')); } function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } function matchPathname(pathname, template) { const re = new RegExp(`^${template.split('/').map(escapeRegExp).join('/')}$`); return re.test(pathname); } function getPathParam(pathname, matcher) { const match = pathname.match(matcher); return match ? match[1] : null; } function getSessionForMode(mode, req) { if (mode === 'none') return null; const cookies = parseCookies(req.headers.cookie); const sponsorId = cookies.gridpilot_sponsor_id || 'demo-sponsor-1'; if (mode === 'admin') { return { token: 'test-token-admin', user: { userId: 'user-admin', email: 'admin@gridpilot.test', displayName: 'Demo Admin', primaryDriverId: 'driver-admin', }, }; } if (mode === 'sponsor') { return { token: 'test-token-sponsor', user: { userId: 'user-sponsor', email: 'sponsor@gridpilot.test', displayName: 'Demo Sponsor User', primaryDriverId: 'driver-sponsor', sponsorId, }, }; } return { token: 'test-token-driver', user: { userId: 'user-driver', email: 'driver@gridpilot.test', displayName: 'Demo Driver', primaryDriverId: 'driver-1', }, }; } const DEMO = { leagueId: 'league-1', teamId: 'team-1', raceId: 'race-1', protestId: 'protest-1', seasonId: 'season-1', sponsorId: 'demo-sponsor-1', }; function buildLeagueList() { return { leagues: [ { id: DEMO.leagueId, name: 'Demo League', description: 'Demo league for docker smoke tests', ownerId: 'driver-admin', createdAt: nowIso(), usedSlots: 2, timingSummary: 'Weekly', settings: { maxDrivers: 50 }, scoring: { scoringPresetName: 'Demo rules', scoringPatternSummary: 'Standard', }, }, ], totalCount: 1, }; } function buildTeamsList() { return { teams: [ { id: DEMO.teamId, name: 'Demo Team', ownerId: 'driver-admin', createdAt: nowIso(), memberCount: 2, }, ], totalCount: 1, }; } function buildRaceSchedule(seasonId) { const date = nowIso(); return { seasonId, published: true, races: [ { id: DEMO.raceId, name: 'Demo Race', date, scheduledAt: date, track: 'Demo Track', car: 'Demo Car', sessionType: 'race', status: 'scheduled', isRegistered: false, }, ], }; } function buildStandings() { return { standings: [ { driverId: 'driver-1', points: 100, position: 1 }, { driverId: 'driver-admin', points: 90, position: 2 }, ], }; } function buildMemberships() { return { members: [ { driverId: 'driver-admin', role: 'owner', joinedAt: nowIso() }, { driverId: 'driver-1', role: 'member', joinedAt: nowIso() }, { driverId: 'driver-sponsor', role: 'member', joinedAt: nowIso() }, ], }; } function buildDriver(driverId) { return { currentDriver: { id: driverId, name: driverId === 'driver-admin' ? 'Demo Admin Driver' : 'Demo Driver', country: 'DE', createdAt: nowIso(), }, }; } function buildDriverProfile(driverId) { return { currentDriver: { id: driverId, name: driverId === 'driver-admin' ? 'Demo Admin Driver' : 'Demo Driver', country: 'DE', avatarUrl: '/images/avatars/neutral-default-avatar.jpeg', iracingId: driverId === 'driver-admin' ? '1002' : '1001', joinedAt: nowIso(), rating: 2500, globalRank: 42, consistency: 78, bio: '', totalDrivers: 1000, }, stats: { totalRaces: 12, wins: 2, podiums: 5, dnfs: 1, avgFinish: 6.3, bestFinish: 1, worstFinish: 18, finishRate: 91.7, winRate: 16.7, podiumRate: 41.7, percentile: 42, rating: 2500, consistency: 78, overallRank: 42, }, finishDistribution: { totalRaces: 12, wins: 2, podiums: 5, topTen: 8, dnfs: 1, other: 3, }, teamMemberships: [], socialSummary: { friendsCount: 1, friends: [ { id: 'driver-admin', name: 'Demo Admin Driver', country: 'DE', avatarUrl: '/images/avatars/male-default-avatar.jpg', }, ], }, extendedProfile: { socialHandles: [], achievements: [], racingStyle: 'Balanced', favoriteTrack: 'Spa', favoriteCar: 'Porsche 992 Cup', timezone: 'Europe/Berlin', availableHours: 'Evenings', lookingForTeam: false, openToRequests: true, }, }; } function buildTeamDetails(teamId) { return { team: { id: teamId, name: 'Demo Team', ownerId: 'driver-admin', createdAt: nowIso(), description: '', }, }; } function buildTeamMembers(teamId) { return { teamId, members: [ { driverId: 'driver-admin', role: 'owner', joinedAt: nowIso(), driver: { id: 'driver-admin', name: 'Demo Admin Driver' } }, { driverId: 'driver-1', role: 'member', joinedAt: nowIso(), driver: { id: 'driver-1', name: 'Demo Driver' } }, ], }; } function buildRacePageData() { const date = nowIso(); return { races: [ { id: DEMO.raceId, name: 'Demo Race', date, scheduledAt: date, leagueId: DEMO.leagueId, leagueName: 'Demo League', track: 'Demo Track', car: 'Demo Car', status: 'scheduled', strengthOfField: null, }, ], }; } function buildRaceDetail(raceId) { const date = nowIso(); return { race: { id: raceId, name: 'Demo Race', date, track: 'Demo Track', car: 'Demo Car', status: 'scheduled', leagueId: DEMO.leagueId, }, league: { id: DEMO.leagueId, name: 'Demo League' }, entryList: [], registration: { isRegistered: false }, userResult: null, }; } function buildRaceResults(raceId) { return { raceId, results: [], }; } function buildSponsorDashboard(sponsorId) { return { sponsorId, sponsor: { id: sponsorId, name: 'Demo Sponsor', logoUrl: '', websiteUrl: '' }, stats: { impressions: 0, clicks: 0 }, activeSponsorships: [], recentCampaigns: [], }; } function buildSponsorSponsorships(sponsorId) { return { sponsorId, sponsorships: [], }; } function buildSponsorSettings(sponsorId) { return { profile: { sponsorId, name: 'Demo Sponsor', websiteUrl: '', logoUrl: '' }, notifications: {}, privacy: {}, }; } function buildPendingSponsorshipRequests() { return { requests: [], }; } function buildDashboardOverview() { const scheduledAt = nowIso(); return { currentDriver: { id: 'driver-1', name: 'Demo Driver', country: 'DE', avatarUrl: '/images/avatars/neutral-default-avatar.jpeg', rating: 2500, globalRank: 42, totalRaces: 12, wins: 2, podiums: 5, consistency: 78, }, myUpcomingRaces: [ { id: DEMO.raceId, leagueId: DEMO.leagueId, leagueName: 'Demo League', track: 'Spa', car: 'Porsche 992 Cup', scheduledAt, status: 'scheduled', isMyLeague: true, }, ], otherUpcomingRaces: [], upcomingRaces: [ { id: DEMO.raceId, leagueId: DEMO.leagueId, leagueName: 'Demo League', track: 'Spa', car: 'Porsche 992 Cup', scheduledAt, status: 'scheduled', isMyLeague: true, }, ], activeLeaguesCount: 1, nextRace: { id: DEMO.raceId, leagueId: DEMO.leagueId, leagueName: 'Demo League', track: 'Spa', car: 'Porsche 992 Cup', scheduledAt, status: 'scheduled', isMyLeague: true, }, recentResults: [], leagueStandingsSummaries: [ { leagueId: DEMO.leagueId, leagueName: 'Demo League', position: 1, totalDrivers: 10, points: 100 }, ], feedSummary: { items: [ { id: 'feed-1', type: 'info', headline: 'Welcome to GridPilot', body: 'Demo data from the docker test API.', timestamp: nowIso(), ctaLabel: 'Browse leagues', ctaHref: '/leagues', }, ], }, friends: [ { id: 'driver-admin', name: 'Demo Admin Driver', avatarUrl: '/images/avatars/male-default-avatar.jpg', country: 'DE', }, ], }; } const server = http.createServer((req, res) => { const origin = req.headers.origin || 'http://localhost:3100'; res.setHeader('Access-Control-Allow-Origin', origin); res.setHeader('Vary', 'Origin'); for (const [k, v] of Object.entries(baseCors)) res.setHeader(k, v); if (req.method === 'OPTIONS') { res.statusCode = 204; return res.end(); } const url = new URL(req.url, 'http://localhost'); const { pathname: rawPathname, searchParams } = url; // Normalize trailing slashes so `/foo` and `/foo/` behave the same in mocks. // This prevents false-negative 404s caused by minor URL formatting differences. const pathname = rawPathname !== '/' ? rawPathname.replace(/\/+$/, '') || '/' : rawPathname; const demoMode = getDemoMode(req); const faultMode = getFaultMode(req); const sessionDriftMode = getSessionDriftMode(req); const send = (code, obj) => sendJson(res, code, obj); if (pathname === '/health') return send(200, { status: 'ok' }); if (pathname === '/policy/snapshot') { return send(200, { policyVersion: 1, operationalMode: 'test', maintenanceAllowlist: { view: [], mutate: [] }, capabilities: {}, loadedFrom: 'defaults', loadedAtIso: nowIso(), }); } if (pathname === '/auth/session') { const session = getSessionForMode(demoMode, req); // Test-mock behavior: "public" mode returns 200 with a null session so the browser // does not emit noisy "Failed to load resource 401/403" console errors. if (!session) return sendNull(res); // Drift injection is only enabled when explicitly requested via cookie. if (sessionDriftMode === 'expired') { return sendNull(res); } if (sessionDriftMode === 'invalid-cookie') { return send(200, { token: 'invalid', user: session.user }); } if (sessionDriftMode === 'missing-sponsor-id') { if (session.user && typeof session.user === 'object' && 'sponsorId' in session.user) { const { sponsorId: _omit, ...restUser } = session.user; return send(200, { token: session.token, user: restUser }); } return send(200, session); } return send(200, session); } const avatarPath = getPathParam(pathname, /^\/media\/avatar\/([^/]+)$/); if (avatarPath) return sendPng(res, 200); const leagueMedia = pathname.match(/^\/media\/leagues\/([^/]+)\/(cover|logo)$/); if (leagueMedia) return sendPng(res, 200); const teamMedia = pathname.match(/^\/media\/teams\/([^/]+)\/logo$/); if (teamMedia) return sendPng(res, 200); const sponsorMedia = pathname.match(/^\/media\/sponsors\/([^/]+)\/logo$/); if (sponsorMedia) return sendPng(res, 200); if (pathname === '/leagues/all-with-capacity') { const payload = normalizeArrayFields(buildLeagueList(), ['leagues']); if (faultMode === 'null-array') payload.leagues = null; return send(200, payload); } if (pathname === '/leagues/all-with-capacity-and-scoring') { const payload = normalizeArrayFields(buildLeagueList(), ['leagues']); if (faultMode === 'null-array') payload.leagues = null; return send(200, payload); } if (pathname === '/teams/all') { const payload = normalizeArrayFields(buildTeamsList(), ['teams']); if (faultMode === 'null-array') payload.teams = null; return send(200, payload); } if (pathname === '/leagues/scoring-presets') { return send(200, { presets: [ { id: 'preset-1', name: 'Demo Scoring', description: 'Demo scoring preset for docker smoke tests', primaryChampionshipType: 'driver', sessionSummary: 'Main race', bonusSummary: '', dropPolicySummary: 'All results count', defaultTimings: { practiceMinutes: 15, qualifyingMinutes: 10, sprintRaceMinutes: 0, mainRaceMinutes: 30, sessionCount: 1, }, }, ], }); } if (pathname === '/dashboard/overview') { const payload = buildDashboardOverview(); if (faultMode === 'null-array') { if (payload.feedSummary && payload.feedSummary.items) payload.feedSummary.items = null; if (payload.friends) payload.friends = null; if (payload.leagueStandingsSummaries) payload.leagueStandingsSummaries = null; if (payload.myUpcomingRaces) payload.myUpcomingRaces = null; if (payload.otherUpcomingRaces) payload.otherUpcomingRaces = null; if (payload.upcomingRaces) payload.upcomingRaces = null; } if (faultMode === 'invalid-date') { if (payload.nextRace && payload.nextRace.scheduledAt) payload.nextRace.scheduledAt = 'not-a-date'; if (Array.isArray(payload.upcomingRaces) && payload.upcomingRaces[0]?.scheduledAt) payload.upcomingRaces[0].scheduledAt = 'not-a-date'; if (Array.isArray(payload.myUpcomingRaces) && payload.myUpcomingRaces[0]?.scheduledAt) payload.myUpcomingRaces[0].scheduledAt = 'not-a-date'; } return send(200, payload); } if (pathname === '/drivers/leaderboard') return send(200, { drivers: [] }); if (pathname === '/drivers/current') return send(200, buildDriver(getSessionForMode(demoMode, req)?.user?.primaryDriverId || 'driver-1')); if (pathname === '/races/page-data') { const payload = normalizeArrayFields(buildRacePageData(), ['races']); if (faultMode === 'null-array') payload.races = null; if (faultMode === 'invalid-date' && Array.isArray(payload.races) && payload.races[0]) { payload.races[0].date = 'not-a-date'; payload.races[0].scheduledAt = 'not-a-date'; } return send(200, payload); } if (pathname === '/races/reference/penalty-types') { return send(200, { penaltyTypes: [ { type: 'time_penalty', requiresValue: true, valueKind: 'seconds' }, { type: 'grid_penalty', requiresValue: true, valueKind: 'grid_positions' }, { type: 'points_deduction', requiresValue: true, valueKind: 'points' }, { type: 'disqualification', requiresValue: false, valueKind: 'none' }, { type: 'warning', requiresValue: false, valueKind: 'none' }, { type: 'license_points', requiresValue: true, valueKind: 'points' }, ], defaultReasons: { upheld: 'Protest upheld based on steward review.', dismissed: 'Protest dismissed due to insufficient evidence.', }, }); } const leagueProtestsMatch = pathname.match(/^\/leagues\/([^/]+)\/protests(?:\/([^/]+))?$/); if (leagueProtestsMatch) { const leagueId = leagueProtestsMatch[1]; const protestId = leagueProtestsMatch[2] || DEMO.protestId; return send(200, { protests: [ { id: protestId, leagueId, raceId: DEMO.raceId, protestingDriverId: 'driver-1', accusedDriverId: 'driver-admin', submittedAt: nowIso(), description: 'Demo protest for docker smoke tests', status: 'pending', }, ], racesById: { [DEMO.raceId]: { id: DEMO.raceId, name: 'Demo Race', date: nowIso(), leagueName: 'Demo League', }, }, driversById: { 'driver-1': { id: 'driver-1', iracingId: '1001', name: 'Demo Driver', country: 'DE', joinedAt: nowIso(), }, 'driver-admin': { id: 'driver-admin', iracingId: '1002', name: 'Demo Admin Driver', country: 'DE', joinedAt: nowIso(), }, }, }); } const raceIdProtests = getPathParam(pathname, /^\/races\/([^/]+)\/protests$/); if (raceIdProtests) { return send(200, { protests: [ { id: DEMO.protestId, protestingDriverId: 'driver-1', accusedDriverId: 'driver-admin', incident: { type: 'contact' }, lap: 1, description: 'Demo incident', status: 'pending', filedAt: nowIso(), }, ], driverMap: { 'driver-1': 'Demo Driver', 'driver-admin': 'Demo Admin Driver', }, }); } const raceIdPenalties = getPathParam(pathname, /^\/races\/([^/]+)\/penalties$/); if (raceIdPenalties) { return send(200, { penalties: [], driverMap: {}, }); } const leagueIdFromMemberships = getPathParam(pathname, /^\/leagues\/([^/]+)\/memberships$/); if (leagueIdFromMemberships) { if (leagueIdFromMemberships !== DEMO.leagueId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); const payload = normalizeArrayFields(buildMemberships(), ['members']); if (faultMode === 'null-array') payload.members = null; return send(200, payload); } const leagueIdFromStandings = getPathParam(pathname, /^\/leagues\/([^/]+)\/standings$/); if (leagueIdFromStandings) { if (leagueIdFromStandings !== DEMO.leagueId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); const payload = normalizeArrayFields(buildStandings(), ['standings']); if (faultMode === 'null-array') payload.standings = null; return send(200, payload); } const leagueIdFromSchedule = getPathParam(pathname, /^\/leagues\/([^/]+)\/schedule$/); if (leagueIdFromSchedule) { if (leagueIdFromSchedule !== DEMO.leagueId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); const seasonId = searchParams.get('seasonId') || DEMO.seasonId; const payload = normalizeArrayFields(buildRaceSchedule(seasonId), ['races']); if (faultMode === 'null-array') payload.races = null; if (faultMode === 'invalid-date' && Array.isArray(payload.races) && payload.races[0]) { payload.races[0].date = 'not-a-date'; payload.races[0].scheduledAt = 'not-a-date'; } if (faultMode === 'missing-field' && Array.isArray(payload.races) && payload.races[0]) { delete payload.races[0].track; } return send(200, payload); } const leagueIdFromWallet = getPathParam(pathname, /^\/leagues\/([^/]+)\/wallet$/); if (leagueIdFromWallet) { if (leagueIdFromWallet !== DEMO.leagueId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); const date = nowIso(); const payload = { balance: 2880, currency: 'USD', totalRevenue: 3200, totalFees: 320, totalWithdrawals: 0, pendingPayouts: 0, canWithdraw: true, transactions: [ { id: 'wallet-tx-1', type: 'sponsorship', description: 'Demo sponsorship revenue', amount: 1600, fee: 160, netAmount: 1440, date, status: 'completed', reference: 'sponsorship-1', }, ], }; if (faultMode === 'null-array') payload.transactions = null; if (faultMode === 'invalid-date' && Array.isArray(payload.transactions) && payload.transactions[0]) { payload.transactions[0].date = 'not-a-date'; } return send(200, payload); } const leagueIdFromWalletWithdraw = getPathParam(pathname, /^\/leagues\/([^/]+)\/wallet\/withdraw$/); if (leagueIdFromWalletWithdraw && req.method === 'POST') { if (leagueIdFromWalletWithdraw !== DEMO.leagueId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); return send(200, { success: true }); } const leagueIdFromRaces = getPathParam(pathname, /^\/leagues\/([^/]+)\/races$/); if (leagueIdFromRaces) { if (leagueIdFromRaces !== DEMO.leagueId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); return send(200, { races: [buildRaceDetail(DEMO.raceId).race] }); } const leagueIdFromSeasons = getPathParam(pathname, /^\/leagues\/([^/]+)\/seasons$/); if (leagueIdFromSeasons) { if (leagueIdFromSeasons !== DEMO.leagueId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); return send(200, [ { seasonId: DEMO.seasonId, name: 'Season 1', status: 'active', startDate: nowIso(), endDate: nowIso() }, ]); } const leagueIdFromRosterMembers = getPathParam(pathname, /^\/leagues\/([^/]+)\/admin\/roster\/members$/); if (leagueIdFromRosterMembers) { return send(200, [ { driverId: 'driver-admin', role: 'owner', joinedAt: nowIso(), driver: { id: 'driver-admin', name: 'Demo Admin Driver' }, }, { driverId: 'driver-1', role: 'member', joinedAt: nowIso(), driver: { id: 'driver-1', name: 'Demo Driver' }, }, ]); } const leagueIdFromJoinRequests = getPathParam(pathname, /^\/leagues\/([^/]+)\/admin\/roster\/join-requests$/); if (leagueIdFromJoinRequests) { return send(200, [ { id: 'join-request-1', leagueId: leagueIdFromJoinRequests, driverId: 'driver-sponsor', requestedAt: nowIso(), message: 'Please approve my join request', driver: { id: 'driver-sponsor', name: 'Demo Sponsor Driver' }, }, ]); } const seasonIdFromSponsorships = getPathParam(pathname, /^\/leagues\/seasons\/([^/]+)\/sponsorships$/); if (seasonIdFromSponsorships) { return send(200, { sponsorships: [ { id: 'sponsorship-1', seasonId: seasonIdFromSponsorships, sponsorId: DEMO.sponsorId, tier: 'main', status: 'active' }, ], }); } const driverId = getPathParam(pathname, /^\/drivers\/([^/]+)$/); if (driverId) return send(200, buildDriver(driverId)); const driverIdProfile = getPathParam(pathname, /^\/drivers\/([^/]+)\/profile$/); if (driverIdProfile) return send(200, buildDriverProfile(driverIdProfile)); const teamIdDetails = getPathParam(pathname, /^\/teams\/([^/]+)$/); if (teamIdDetails) return send(200, buildTeamDetails(teamIdDetails)); const teamIdMembers = getPathParam(pathname, /^\/teams\/([^/]+)\/members$/); if (teamIdMembers) return send(200, buildTeamMembers(teamIdMembers)); const teamIdMembership = getPathParam(pathname, /^\/teams\/([^/]+)\/members\/([^/]+)$/); if (teamIdMembership) { const parts = pathname.split('/'); const teamId = parts[2]; const memberDriverId = parts[4]; return send(200, { teamId, driverId: memberDriverId, role: memberDriverId === 'driver-admin' ? 'owner' : 'member' }); } const raceIdDetail = getPathParam(pathname, /^\/races\/([^/]+)$/); if (raceIdDetail) { if (raceIdDetail !== DEMO.raceId) return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); const driverIdForRace = searchParams.get('driverId') || (getSessionForMode(demoMode, req)?.user?.primaryDriverId || 'driver-1'); void driverIdForRace; const payload = buildRaceDetail(raceIdDetail); if (faultMode === 'invalid-date' && payload.race) { payload.race.date = 'not-a-date'; } if (faultMode === 'null-array') { payload.entryList = null; } return send(200, payload); } const raceIdSof = getPathParam(pathname, /^\/races\/([^/]+)\/sof$/); if (raceIdSof) return send(200, { raceId: raceIdSof, strengthOfField: 2500 }); const raceIdResults = getPathParam(pathname, /^\/races\/([^/]+)\/results$/); if (raceIdResults) return send(200, buildRaceResults(raceIdResults)); const sponsorDashboard = getPathParam(pathname, /^\/sponsors\/dashboard\/([^/]+)$/); if (sponsorDashboard) { const payload = buildSponsorDashboard(sponsorDashboard); if (faultMode === 'null-array') { payload.activeSponsorships = null; payload.recentCampaigns = null; } if (faultMode === 'missing-field' && payload.sponsor) { delete payload.sponsor.name; } return send(200, payload); } const sponsorSponsorships = getPathParam(pathname, /^\/sponsors\/([^/]+)\/sponsorships$/); if (sponsorSponsorships) { const payload = buildSponsorSponsorships(sponsorSponsorships); if (faultMode === 'null-array') payload.sponsorships = null; return send(200, payload); } const sponsorGet = getPathParam(pathname, /^\/sponsors\/([^/]+)$/); if (sponsorGet) return send(200, { sponsor: { id: sponsorGet, name: 'Demo Sponsor', logoUrl: '', websiteUrl: '' } }); if (matchPathname(pathname, '/sponsors/pricing')) return send(200, { pricing: [] }); if (matchPathname(pathname, '/sponsors')) return send(200, { sponsors: [{ id: DEMO.sponsorId, name: 'Demo Sponsor', logoUrl: '', websiteUrl: '' }] }); if (pathname === '/sponsors/requests') return send(200, buildPendingSponsorshipRequests()); const sponsorBilling = getPathParam(pathname, /^\/sponsors\/billing\/([^/]+)$/); if (sponsorBilling) { const today = new Date(); const invoiceDate = new Date(today.getFullYear(), today.getMonth(), 1).toISOString(); const dueDate = new Date(today.getFullYear(), today.getMonth(), 15).toISOString(); const nextPaymentDate = new Date(today.getFullYear(), today.getMonth() + 1, 1).toISOString(); return send(200, { paymentMethods: [ { id: 'pm-1', type: 'card', last4: '4242', brand: 'Visa', isDefault: true, expiryMonth: 12, expiryYear: 2030, }, ], invoices: [ { id: 'inv-1', invoiceNumber: 'GP-0001', date: invoiceDate, dueDate, amount: 100, vatAmount: 20, totalAmount: 120, status: 'paid', description: 'Demo sponsorship invoice', sponsorshipType: 'league', pdfUrl: '/billing/invoices/inv-1.pdf', }, ], stats: { totalSpent: 120, pendingAmount: 0, nextPaymentDate, nextPaymentAmount: 0, activeSponsorships: 0, averageMonthlySpend: 20, }, }); } const sponsorSettings = getPathParam(pathname, /^\/sponsors\/settings\/([^/]+)$/); if (sponsorSettings) return send(200, buildSponsorSettings(sponsorSettings)); const sponsorLeagueAvailable = pathname === '/sponsors/leagues/available'; if (sponsorLeagueAvailable) { return send(200, [ { id: DEMO.leagueId, name: 'Demo League', game: 'iRacing', drivers: 24, avgViewsPerRace: 3200, mainSponsorSlot: { available: true, price: 1500 }, secondarySlots: { available: 2, total: 4, price: 500 }, rating: 4.6, tier: 'standard', nextRace: 'Sunday 19:00', seasonStatus: 'active', description: 'Demo league available for sponsorship (docker smoke tests).', }, ]); } const sponsorLeagueDetail = getPathParam(pathname, /^\/sponsors\/leagues\/([^/]+)\/detail$/); if (sponsorLeagueDetail) { return send(200, { league: { id: sponsorLeagueDetail, name: 'Demo League', game: 'iRacing', tier: 'standard', season: '2025 S1', description: 'Demo league detail for sponsor pages (docker smoke tests).', drivers: 24, races: 10, completedRaces: 2, totalImpressions: 42000, avgViewsPerRace: 3200, engagement: 78, rating: 4.6, seasonStatus: 'active', seasonDates: { start: nowIso(), end: nowIso() }, nextRace: { name: 'Demo Race 3', date: nowIso() }, sponsorSlots: { main: { available: true, price: 1500, benefits: ['Logo on broadcast overlay', 'Mentioned in race intro'], }, secondary: { available: 2, total: 4, price: 500, benefits: ['Logo on results page', 'Listed on sponsor board'], }, }, }, drivers: [ { id: 'driver-1', name: 'Demo Driver', country: 'DE', position: 1, races: 2, impressions: 6400, team: 'Demo Team', }, ], races: [ { id: DEMO.raceId, name: 'Demo Race', date: nowIso(), views: 3200, status: 'completed', }, { id: 'race-2', name: 'Demo Race 2', date: nowIso(), views: 0, status: 'upcoming', }, ], }); } return send(404, { message: 'Not Found', path: pathname, rawPath: rawPathname }); }); server.listen(PORT, () => { // eslint-disable-next-line no-console console.log(`[api-mock] listening on ${PORT}`); });