Session 25: Fix all data rendering — proxy routes, Tank01 normalizer, box-score bridge, inline streaks (1579 tests)

This commit is contained in:
Kev
2026-06-12 17:58:55 -04:00
parent 433e827103
commit 956cdb863a
15 changed files with 602 additions and 39 deletions
@@ -0,0 +1,27 @@
import { NextRequest, NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
/**
* Game-lines proxy (Session 25). Thin forwarder to Express
* `/api/gamelines/:sport` (Tank01 book-by-book moneylines / spreads /
* totals). See the schedule proxy for why these were missing.
*/
export async function GET(req: NextRequest, { params }: { params: Promise<{ sport: string }> }) {
const { sport } = await params;
const sportLc = String(sport || '').toLowerCase();
const qs = req.nextUrl.search;
try {
const upstream = await fetch(`${BACKEND_URL}/api/gamelines/${encodeURIComponent(sportLc)}${qs}`, {
method: 'GET',
headers: { Accept: 'application/json' },
});
const data = await upstream.json().catch(() => ({}));
if (!upstream.ok) return NextResponse.json(data, { status: upstream.status });
return NextResponse.json(data);
} catch {
return NextResponse.json({ sport: sportLc, games: {}, source: 'tank01' });
}
}
+27
View File
@@ -0,0 +1,27 @@
import { NextRequest, NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
/**
* Hot-list proxy (Session 25). Forwards to Express `/api/hotlist/:sport`,
* preserving the `?stat=` filter. Computed from cached game logs — no
* odds-api credits. See the schedule proxy for why these were missing.
*/
export async function GET(req: NextRequest, { params }: { params: Promise<{ sport: string }> }) {
const { sport } = await params;
const sportLc = String(sport || '').toLowerCase();
const qs = req.nextUrl.search;
try {
const upstream = await fetch(`${BACKEND_URL}/api/hotlist/${encodeURIComponent(sportLc)}${qs}`, {
method: 'GET',
headers: { Accept: 'application/json' },
});
const data = await upstream.json().catch(() => ({}));
if (!upstream.ok) return NextResponse.json(data, { status: upstream.status });
return NextResponse.json(data);
} catch {
return NextResponse.json({ sport: sportLc, players: [], source: 'computed' });
}
}
+34
View File
@@ -0,0 +1,34 @@
import { NextRequest, NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
/**
* Schedule proxy (Session 25).
*
* The all-day intelligence endpoints (schedule / gamelines / streaks /
* hotlist) were built on the Express backend in Sessions 23-24 but had
* NO Next.js proxy route — so the browser's `fetch('/api/schedule/mlb')`
* 404'd on the Next origin and the slate showed zero games even though
* the backend was serving 8+. This thin forwarder fixes that, mirroring
* the existing `/api/odds/*` proxies.
*/
export async function GET(req: NextRequest, { params }: { params: Promise<{ sport: string }> }) {
const { sport } = await params;
const sportLc = String(sport || '').toLowerCase();
const qs = req.nextUrl.search;
try {
const upstream = await fetch(`${BACKEND_URL}/api/schedule/${encodeURIComponent(sportLc)}${qs}`, {
method: 'GET',
headers: { Accept: 'application/json' },
});
const data = await upstream.json().catch(() => ({}));
if (!upstream.ok) return NextResponse.json(data, { status: upstream.status });
return NextResponse.json(data);
} catch {
// Schedule is the foundation layer — never blow up the page. Return an
// empty-but-valid slate so the UI degrades to "no games" gracefully.
return NextResponse.json({ sport: sportLc, games: [], source: 'espn' });
}
}
+27
View File
@@ -0,0 +1,27 @@
import { NextRequest, NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
/**
* Streaks proxy (Session 25). Forwards to Express `/api/streaks/:sport`,
* preserving the `?stat=` filter. Computed from cached game logs — no
* odds-api credits. See the schedule proxy for why these were missing.
*/
export async function GET(req: NextRequest, { params }: { params: Promise<{ sport: string }> }) {
const { sport } = await params;
const sportLc = String(sport || '').toLowerCase();
const qs = req.nextUrl.search;
try {
const upstream = await fetch(`${BACKEND_URL}/api/streaks/${encodeURIComponent(sportLc)}${qs}`, {
method: 'GET',
headers: { Accept: 'application/json' },
});
const data = await upstream.json().catch(() => ({}));
if (!upstream.ok) return NextResponse.json(data, { status: upstream.status });
return NextResponse.json(data);
} catch {
return NextResponse.json({ sport: sportLc, streaks: [], source: 'computed' });
}
}