random bun scripts that dont fit anywhere else
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add the tba api

+126
+65
tba.ts
··· 1 + import type { TBAApiOptions, TBAEvent, TBATeam } from "./tba.types"; 2 + 3 + export const DEFAULT_TBA_API_URL = "https://www.thebluealliance.com/api/v3"; 4 + 5 + export class TBAApi { 6 + private apiKey: string; 7 + private baseUrl: string; 8 + private cache: Map<string, { etag: string; data: unknown }>; 9 + 10 + constructor(options: TBAApiOptions) { 11 + this.apiKey = options.apiKey; 12 + this.baseUrl = options.baseUrl || DEFAULT_TBA_API_URL; 13 + this.cache = new Map(); 14 + } 15 + 16 + private async fetch<T>(path: string): Promise<T> { 17 + const url = `${this.baseUrl}${path}`; 18 + const cachedResponse = this.cache.get(url); 19 + 20 + const headers: Record<string, string> = { 21 + "X-TBA-Auth-Key": this.apiKey, 22 + }; 23 + 24 + if (cachedResponse?.etag) { 25 + headers["If-None-Match"] = cachedResponse.etag; 26 + } 27 + 28 + const response = await fetch(url, { headers }); 29 + 30 + if (response.status === 304 && cachedResponse) { 31 + return cachedResponse.data as T; 32 + } 33 + 34 + if (!response.ok) { 35 + throw new Error( 36 + `TBA API error: ${response.status} ${response.statusText}`, 37 + ); 38 + } 39 + 40 + const data = await response.json(); 41 + const etag = response.headers.get("ETag"); 42 + 43 + if (etag) { 44 + this.cache.set(url, { etag, data }); 45 + } 46 + 47 + return data as T; 48 + } 49 + 50 + async getEvent(eventKey: string): Promise<TBAEvent> { 51 + return this.fetch(`/event/${eventKey}`); 52 + } 53 + 54 + async getTeamsAtEvent(eventKey: string): Promise<TBATeam[]> { 55 + return this.fetch<TBATeam[]>(`/event/${eventKey}/teams`); 56 + } 57 + 58 + async getTeam(teamKey: string): Promise<TBATeam> { 59 + return this.fetch<TBATeam>(`/team/${teamKey}`); 60 + } 61 + 62 + async getTeamEvents(teamKey: string, year: number): Promise<TBAEvent[]> { 63 + return this.fetch<TBAEvent[]>(`/team/${teamKey}/events/${year}`); 64 + } 65 + }
+61
tba.types.ts
··· 1 + export interface TBAApiOptions { 2 + apiKey: string; 3 + baseUrl?: string; 4 + } 5 + 6 + export interface TBAEvent { 7 + address: string; 8 + city: string; 9 + country: string; 10 + district: null | string; 11 + division_keys: string[]; 12 + end_date: string; 13 + event_code: string; 14 + event_type: number; 15 + event_type_string: string; 16 + first_event_code: string; 17 + first_event_id: null | string; 18 + gmaps_place_id: string; 19 + gmaps_url: string; 20 + key: string; 21 + lat: number; 22 + lng: number; 23 + location_name: string; 24 + name: string; 25 + parent_event_key: null | string; 26 + playoff_type: number; 27 + playoff_type_string: string; 28 + postal_code: string; 29 + short_name: string; 30 + start_date: string; 31 + state_prov: string; 32 + timezone: string; 33 + webcasts: Array<{ 34 + channel: string; 35 + type: string; 36 + }>; 37 + website: null | string; 38 + week: number; 39 + year: number; 40 + } 41 + 42 + export interface TBATeam { 43 + address: string | null; 44 + city: string; 45 + country: string; 46 + gmaps_place_id: string | null; 47 + gmaps_url: string | null; 48 + key: string; 49 + lat: number | null; 50 + lng: number | null; 51 + location_name: string | null; 52 + motto: string | null; 53 + name: string; 54 + nickname: string; 55 + postal_code: string | null; 56 + rookie_year: number; 57 + school_name: string; 58 + state_prov: string; 59 + team_number: number; 60 + website: string | null; 61 + }