Session 7d: Audit fixes - rate limiting, error leak, parallel parlays, analyze cache, bundle analyzer
This commit is contained in:
+33
-2
@@ -1,8 +1,39 @@
|
||||
const express = require('express');
|
||||
const { analyzeProp } = require('../services/propAnalyzer');
|
||||
const { cacheGet, cacheSet } = require('../utils/redis');
|
||||
const { createRateLimit } = require('../middleware/rateLimit');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// SEC-1 (Session 7d): /prop and /batch are public — both proxy to the
|
||||
// prop analyzer which makes upstream API calls. Cap to 10 requests per
|
||||
// IP per minute so a single bad actor can't burn analyzer credits.
|
||||
const analyzeLimit = createRateLimit({ windowMs: 60_000, max: 10 });
|
||||
router.use(analyzeLimit);
|
||||
|
||||
// PERF-1 (Session 7d): cache analyzeProp results in Redis. Same prop hit
|
||||
// twice within 60s reuses the previous analysis instead of re-doing the
|
||||
// upstream chain. 60s is short enough that line moves still surface.
|
||||
const ANALYZE_TTL_SECONDS = 60;
|
||||
function analyzeCacheKey(prop) {
|
||||
const sport = (prop.sport || 'nba').toLowerCase();
|
||||
const player = String(prop.player || '').trim().toLowerCase();
|
||||
const stat = String(prop.stat_type || '').trim().toLowerCase();
|
||||
const line = Number(prop.line);
|
||||
const direction = String(prop.direction || '').toLowerCase();
|
||||
return `analyze:${sport}:${player}:${stat}:${line}:${direction}`;
|
||||
}
|
||||
async function cachedAnalyze(prop) {
|
||||
const key = analyzeCacheKey(prop);
|
||||
const cached = await cacheGet(key);
|
||||
if (cached) return { ...cached, _cache: 'HIT' };
|
||||
const result = await analyzeProp(prop);
|
||||
// cacheSet swallows failures (degraded Redis) — analysis still flows
|
||||
// even when the cache is down.
|
||||
await cacheSet(key, result, ANALYZE_TTL_SECONDS);
|
||||
return { ...result, _cache: 'MISS' };
|
||||
}
|
||||
|
||||
const VALID_STAT_TYPES = new Set([
|
||||
'points', 'rebounds', 'assists', 'threes', 'blocks',
|
||||
'steals', 'pra', 'turnovers',
|
||||
@@ -32,7 +63,7 @@ router.post('/prop', async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await analyzeProp(req.body);
|
||||
const result = await cachedAnalyze(req.body);
|
||||
return res.json(result);
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status === 404) {
|
||||
@@ -61,7 +92,7 @@ router.post('/batch', async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await analyzeProp(prop);
|
||||
const result = await cachedAnalyze(prop);
|
||||
results.push(result);
|
||||
} catch (err) {
|
||||
results.push({
|
||||
|
||||
Reference in New Issue
Block a user