b5d3fd14bb
MLB statsapi + WNBA ESPN live boxscores -> per-player current values
(live:{sport}:{date} TTL 90s, /api/live/:sport + Next proxy). Pure
propState math (HIT / ON PACE / NEEDS N / HOLDS / LINE PASSED — never
red in-progress), attachLiveProgress strip join on nameKey+statType,
proximity-to-hit slate float, StatStrip LiveTracker in the ROW-GRAMMAR
outcome slot (spec amended + lock test updated). Grades never change
in-game — tracking, labeled as such. 2698 -> 2757 tests, web build 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
45 lines
1.6 KiB
JavaScript
45 lines
1.6 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* GET /api/live/:sport — LIVE TRACKING read (A1 board, Session 11).
|
|
*
|
|
* Public, rate-limited 60/min. Cache-aside via liveTrackingService:
|
|
* reads `live:{sport}:{date}` (TTL 90s); on a miss it consults the day's
|
|
* schedule and fetches boxscores ONLY when games are actually live — so the
|
|
* total upstream cost is 1 schedule call + N-live-games boxscore calls per
|
|
* 90s window across ALL users, and zero boxscore calls when nothing is live
|
|
* (specs/LIVE-TRACKING.md POLLING RULE).
|
|
*
|
|
* This is TRACKING, not re-grading — grades are locked pre-game and this
|
|
* endpoint never touches them.
|
|
*/
|
|
|
|
const express = require('express');
|
|
const { createRateLimit } = require('../middleware/rateLimit');
|
|
const { getLiveTracking } = require('../services/liveTrackingService');
|
|
|
|
const router = express.Router();
|
|
router.use(createRateLimit({ windowMs: 60_000, max: 60 }));
|
|
|
|
const LIVE_SPORTS = new Set(['mlb', 'wnba']);
|
|
|
|
router.get('/:sport', async (req, res) => {
|
|
const sport = String(req.params.sport || '').toLowerCase();
|
|
if (!LIVE_SPORTS.has(sport)) {
|
|
// Honest empty for sports without a free live box feed — never an error.
|
|
return res.json({ sport, hasLive: false, games: [] });
|
|
}
|
|
try {
|
|
const data = await getLiveTracking(sport);
|
|
// Short CDN/browser cache — matches the 90s shared window without
|
|
// holding a live slate stale for long.
|
|
res.set('Cache-Control', 'public, max-age=30');
|
|
return res.json(data);
|
|
} catch (err) {
|
|
console.error('[live]', err.message);
|
|
return res.status(200).json({ sport, hasLive: false, games: [] });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|