import { env } from '$env/dynamic/private'; import type { Sponsor } from '$lib/types'; import { cache } from './cache'; const SPONSORS_LOGIN = 'fatfingers23'; type SponsorNode = { login: string; name: string | null; avatarUrl: string; url: string; }; const SPONSORS_QUERY = ` query ($login: String!) { user(login: $login) { sponsorshipsAsMaintainer(first: 100, includePrivate: false, activeOnly: true) { nodes { sponsorEntity { ... on User { login name avatarUrl(size: 160) url } ... on Organization { login name avatarUrl(size: 160) url } } } } } } `; export async function fetchSponsors(fetch: typeof globalThis.fetch): Promise { const cached = cache.get('sponsors'); if (cached) { return cached as Sponsor[]; } const token = env.GITHUB_TOKEN; if (!token) { console.warn('GITHUB_TOKEN is not set — Sponsors section will be hidden.'); return []; } try { const res = await fetch('https://api.github.com/graphql', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ query: SPONSORS_QUERY, variables: { login: SPONSORS_LOGIN } }) }); if (!res.ok) { console.warn(`GitHub Sponsors request failed: ${res.status} ${res.statusText}`); return []; } const json = await res.json(); if (json.errors) { console.warn('GitHub Sponsors GraphQL errors:', json.errors); return []; } const nodes: { sponsorEntity: SponsorNode | null }[] = json.data?.user?.sponsorshipsAsMaintainer?.nodes ?? []; const sponsors: Sponsor[] = nodes .map((node) => node.sponsorEntity) .filter((entity): entity is SponsorNode => Boolean(entity?.login)) .map((entity) => ({ login: entity.login, name: entity.name ?? entity.login, avatarUrl: entity.avatarUrl ?? `https://github.com/${entity.login}.png`, url: entity.url })); cache.set('sponsors', sponsors); return sponsors; } catch (error) { console.warn('Failed to fetch GitHub Sponsors:', error); return []; } }