0dc84c7597
The ride detail and park pages fetched with `next: { revalidate: 60 }`,
which is stale-while-revalidate. After hours of no traffic the Data Cache
held a morning snapshot; the first click served that stale value and only
the second request (e.g. a browser refresh) got the just-revalidated
payload. The endpoint also bundles live state with chart history, so one
stale fetch made the whole page wrong.
Switch the live-data fetches to `cache: "no-store"`. The calendar-month
fetch keeps its 5-min ISR since operating hours change slowly.
48 lines
1.5 KiB
TypeScript
48 lines
1.5 KiB
TypeScript
/**
|
|
* Single source of truth for the backend URL used by Next.js server
|
|
* components. Defaults to localhost in development; throws at *request time*
|
|
* in production if BACKEND_URL isn't set so a misdeployed container fails
|
|
* with a clear message instead of silently pointing at localhost. The check
|
|
* is lazy so Next.js build-time page-data collection doesn't trip it.
|
|
*/
|
|
|
|
let warned = false;
|
|
|
|
export function getBackendUrl(): string {
|
|
const explicit = process.env.BACKEND_URL;
|
|
if (explicit) return explicit;
|
|
if (process.env.NODE_ENV === "production") {
|
|
throw new Error(
|
|
"BACKEND_URL env var is required in production. " +
|
|
"Set it to the backend service URL (e.g. http://backend:3001).",
|
|
);
|
|
}
|
|
if (!warned) {
|
|
warned = true;
|
|
console.warn("[lib/api] BACKEND_URL unset — defaulting to http://localhost:3001 (dev only)");
|
|
}
|
|
return "http://localhost:3001";
|
|
}
|
|
|
|
/**
|
|
* Fetch JSON from the backend with a default revalidate window. Returns
|
|
* `null` on network failure or non-2xx status — callers handle the null
|
|
* to render a graceful fallback instead of crashing the server render.
|
|
*/
|
|
export async function apiFetch<T>(
|
|
path: string,
|
|
options: { revalidate?: number; noStore?: boolean } = {},
|
|
): Promise<T | null> {
|
|
const { revalidate = 60, noStore = false } = options;
|
|
try {
|
|
const res = await fetch(
|
|
`${getBackendUrl()}${path}`,
|
|
noStore ? { cache: "no-store" } : { next: { revalidate } },
|
|
);
|
|
if (!res.ok) return null;
|
|
return (await res.json()) as T;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|