const langColorsRes = await fetch("https://cdn.jsdelivr.net/gh/anuraghazra/github-readme-stats@refs/heads/master/src/common/languageColors.json"); const langColors: Record<string, string> = await langColorsRes.json(); type repo = { language: string } type repos = repo[] const fetchOpts: RequestInit = {} if (process.env.AuthorizationHeaderToken) { fetchOpts.headers = { "Authorization": `Bearer ${process.env.AuthorizationHeaderToken}` } } const getTopLangs = async (type: "users" | "orgs", name: string) => { const obj: Record<string, number> = {} const repoResp = await fetch(`https://git.creations.works/api/v1/${type}/${name}/repos?limit=0`, fetchOpts); const repos = await repoResp.json() as repos | { message: string }; if ("message" in repos) { throw new Error(repos.message); } for (const repo of repos) { const lang = repo.language; if (obj[lang] && lang !== "") { obj[lang]++; } else if (lang !== "") { obj[lang] = 1; } } return calculatePercent(obj); } const calculatePercent = (obj: Record<string, number>) => { const totalHits = Object.values(obj).reduce((acc, curr) => acc + curr, 0); const percentages: Record<string, string> = {}; for (const [category, hits] of Object.entries(obj)) { const percent = (hits / totalHits) * 100; percentages[category] = percent.toFixed(2); } return percentages; } const makeSVG = (data: Record<string, string>) => { const svgContent = Object.entries(data) .map(([language, percentage], index) => { const color = langColors[language] || "#111111"; const circleY = 60 + (index * 25); // Adjust Y position for each language return `<circle cx="60" cy="${circleY}" r="10" fill="${color}" /><text x="80" y="${circleY + 5}" fill="#cbd0da">${language}: ${percentage}%</text>`; }) .join(''); return `<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">${svgContent}</svg>`; } Bun.serve({ async fetch(request, server) { const { searchParams } = new URL(request.url); const type = searchParams.get("type") as "users" | "orgs"; const name = searchParams.get("name") as string; if (!type) { return new Response("Please provide a type parameter, users or orgs", { status: 400 }); } if (type !== "users" && type !== "orgs") { return new Response("Type parameter must be either users or orgs", { status: 400 }); } if (!name) { return new Response("Please provide a name parameter", { status: 400 }); } const data = await getTopLangs(type, name); return new Response(makeSVG(data), { headers: { "Content-Type": "image/svg+xml" } }); }, })