'use strict'; /** * injuryService — the real injury wire (Session 64 / A1-S5). * * FREE ESPN injuries feed per sport → per-player status chips: * OUT / GTD (day-to-day, questionable) / PROB. Day 1 is ACCURATE CHIPS on * player pages + prop rows; cascade auto-regrades are a future board. * Cache 15 min. Pure parser + injectable fetch → unit-tested offline. */ const { nameKey } = require('../utils/playerName'); const TTL = 900; const HTTP_TIMEOUT_MS = 10_000; const FEEDS = { mlb: 'https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/injuries', wnba: 'https://site.api.espn.com/apis/site/v2/sports/basketball/wnba/injuries', nba: 'https://site.api.espn.com/apis/site/v2/sports/basketball/nba/injuries', }; /** ESPN status text → the three honest chips (unknown → null, never guessed). */ function chipFor(statusText) { const s = String(statusText || '').toLowerCase(); if (!s) return null; if (s.includes('out') || s.includes('injured list') || s.includes('il-') || s === 'suspension') return 'OUT'; if (s.includes('day-to-day') || s.includes('questionable') || s.includes('doubtful') || s === 'gtd') return 'GTD'; if (s.includes('probable')) return 'PROB'; return null; } /** Pure: ESPN injuries JSON → { nameKey: { status, detail, team } } */ function parseInjuries(json) { const byPlayer = {}; for (const teamBlock of (json && json.injuries) || []) { const team = teamBlock.displayName || null; for (const inj of teamBlock.injuries || []) { const athlete = inj.athlete || {}; const name = athlete.displayName || athlete.fullName; if (!name) continue; const chip = chipFor(inj.status); if (!chip) continue; byPlayer[nameKey(name)] = { status: chip, detail: (inj.details && inj.details.type) || inj.shortComment || null, team, }; } } return byPlayer; } async function fetchInjuries(sport, opts = {}) { const sp = String(sport || '').toLowerCase(); const url = FEEDS[sp]; if (!url) return {}; const cacheGet = opts.cacheGet || require('../utils/redis').cacheGet; const cacheSet = opts.cacheSet || require('../utils/redis').cacheSet; const key = `injuries:${sp}`; const cached = await cacheGet(key); if (cached) return cached; const axios = opts.axios || require('axios'); try { const res = await axios.get(url, { timeout: HTTP_TIMEOUT_MS }); const parsed = parseInjuries(res.data); await cacheSet(key, parsed, TTL); return parsed; } catch (e) { console.warn(`[injuries] ${sp} fetch failed:`, e.message); return {}; } } module.exports = { fetchInjuries, parseInjuries, chipFor, __internals: { TTL, FEEDS } };