S11 (a1): live tracking — the read locked, the game watched
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>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
'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;
|
||||
Reference in New Issue
Block a user