import "dotenv/config"; const AUTH_KEY = Bun.env.TBA_AUTH_KEY; if (!AUTH_KEY) { process.exit(); } const authHeaders = new Headers({ "X-TBA-Auth-Key": AUTH_KEY, }); const BASE_URL = "https://www.thebluealliance.com/api/v3"; interface CacheEntry { etag: string; data: string; staleTime: number; } const tbaCache: { [name: string]: CacheEntry } = {}; interface TBAResponse { data: string; status: number; } function updateCache( endpoint: string, etag: string | null, data: string, maxAge: number, ) { if (etag) { tbaCache[endpoint] = { etag, data, staleTime: Date.now() + maxAge }; } } function fetchCache(endpoint: string) { return tbaCache[endpoint]; } async function getTBAEndpoint(endpoint: string): Promise { const time = Date.now(); console.log(tbaCache[endpoint]); if (tbaCache[endpoint] && tbaCache[endpoint].staleTime > time) { console.log("Cache hit... " + endpoint); return { data: fetchCache(endpoint).data, status: 200 }; } console.log("Fetching... " + endpoint); const headers = new Headers(authHeaders); const response = await fetch(BASE_URL + endpoint, { headers }); let data; if (response.status === 200) { data = await response.text(); const maxAge = parseInt( response.headers .get("cache-control") ?.split(",") .filter((d) => d.includes("max-age"))[0] .trim() .split("=")[1] as string, ); updateCache(endpoint, response.headers.get("ETag"), data, maxAge); } else if (response.status === 304) { // Safety: a 304 response indicates out cache is valid based on ETag data = fetchCache(endpoint).data as string; console.log("Unchanged... " + endpoint); } else { data = ""; } return { data, status: response.status, }; } const response = await getTBAEndpoint("/team/frc4043/events/simple"); console.log(response);