diff --git a/docs/lib/contributors.ts b/docs/lib/contributors.ts index 539012f8c..80e65e27e 100644 --- a/docs/lib/contributors.ts +++ b/docs/lib/contributors.ts @@ -6,25 +6,82 @@ export type Contributor = { type?: string; }; -const GITHUB_CONTRIBUTORS_URL = "https://api.github.com/repos/t8y2/dbx/contributors?per_page=48"; +const GITHUB_CONTRIBUTORS_API = "https://api.github.com/repos/t8y2/dbx/contributors"; + +function parseNextLink(linkHeader: string): string | null { + const parts = linkHeader.split(","); + for (const part of parts) { + const [url, rel] = part.split(";").map((s) => s.trim()); + if (rel === 'rel="next"') { + return url.slice(1, -1); // strip < > + } + } + return null; +} + +async function fetchPage(url: string, token?: string): Promise<{ data: Contributor[]; next: string | null }> { + const headers: Record = { + Accept: "application/vnd.github+json", + }; + if (token) { + headers.Authorization = `Bearer ${token}`; + } + + const response = await fetch(url, { + headers, + next: { revalidate: 60 * 60 * 6 }, + }); + + if (!response.ok) return { data: [], next: null }; + + const data = (await response.json()) as Contributor[]; + if (!Array.isArray(data)) return { data: [], next: null }; + + const linkHeader = response.headers.get("Link"); + const next = linkHeader ? parseNextLink(linkHeader) : null; + + return { data, next }; +} function fallbackContributors(): Contributor[] { - return []; + return [ + { login: "t8y2", avatar_url: "https://avatars.githubusercontent.com/u/77960507", html_url: "https://github.com/t8y2", contributions: 1601 }, + { login: "Illuminated2020", avatar_url: "https://avatars.githubusercontent.com/u/53017147", html_url: "https://github.com/Illuminated2020", contributions: 40 }, + { login: "rarnu", avatar_url: "https://avatars.githubusercontent.com/u/28835581", html_url: "https://github.com/rarnu", contributions: 23 }, + { login: "SuLea-IT", avatar_url: "https://avatars.githubusercontent.com/u/105108570", html_url: "https://github.com/SuLea-IT", contributions: 22 }, + { login: "serenez", avatar_url: "https://github.com/serenez.png", html_url: "https://github.com/serenez", contributions: 22 }, + { login: "yavon007", avatar_url: "https://avatars.githubusercontent.com/u/61088461", html_url: "https://github.com/yavon007", contributions: 18 }, + { login: "Bacon2994", avatar_url: "https://avatars.githubusercontent.com/u/108093786", html_url: "https://github.com/Bacon2994", contributions: 11 }, + { login: "Abeautifulsnow", avatar_url: "https://avatars.githubusercontent.com/u/115250255", html_url: "https://github.com/Abeautifulsnow", contributions: 9 }, + { login: "CN-Scars", avatar_url: "https://avatars.githubusercontent.com/u/100192060", html_url: "https://github.com/CN-Scars", contributions: 8 }, + { login: "DengQingNian", avatar_url: "https://avatars.githubusercontent.com/u/117324885", html_url: "https://github.com/DengQingNian", contributions: 7 }, + { login: "xKrah", avatar_url: "https://avatars.githubusercontent.com/u/120772591", html_url: "https://github.com/xKrah", contributions: 7 }, + { login: "agent-43", avatar_url: "https://avatars.githubusercontent.com/u/188405022", html_url: "https://github.com/agent-43", contributions: 6 }, + { login: "eryajf", avatar_url: "https://avatars.githubusercontent.com/u/33259379", html_url: "https://github.com/eryajf", contributions: 5 }, + { login: "wu-clan", avatar_url: "https://avatars.githubusercontent.com/u/114193468", html_url: "https://github.com/wu-clan", contributions: 4 }, + { login: "fraluc06", avatar_url: "https://avatars.githubusercontent.com/u/67560467", html_url: "https://github.com/fraluc06", contributions: 4 }, + { login: "Caisin", avatar_url: "https://avatars.githubusercontent.com/u/62819122", html_url: "https://github.com/Caisin", contributions: 3 }, + { login: "wds824", avatar_url: "https://avatars.githubusercontent.com/u/93659702", html_url: "https://github.com/wds824", contributions: 3 }, + ]; } export async function fetchContributors(): Promise { + const token = process.env.GITHUB_TOKEN; + const firstPage = `${GITHUB_CONTRIBUTORS_API}?per_page=100`; + try { - const response = await fetch(GITHUB_CONTRIBUTORS_URL, { - headers: { Accept: "application/vnd.github+json" }, - next: { revalidate: 60 * 60 * 6 }, - }); + const allContributors: Contributor[] = []; + let url: string | null = firstPage; - if (!response.ok) return fallbackContributors(); + while (url) { + const { data, next } = await fetchPage(url, token); + allContributors.push(...data); + url = next; + } - const data = (await response.json()) as Contributor[]; - if (!Array.isArray(data)) return fallbackContributors(); + if (allContributors.length === 0) return fallbackContributors(); - return data.filter((c) => c.login && c.avatar_url && c.type !== "Bot"); + return allContributors.filter((c) => c.login && c.avatar_url && c.type !== "Bot"); } catch { return fallbackContributors(); }