Files
better-auth/docs/lib/community-stats.ts

124 lines
3.2 KiB
TypeScript

import { unstable_cache } from "next/cache";
import staticContributors from "./contributors-data.json";
export interface CommunityStats {
npmDownloads: number;
githubStars: number;
contributors: number;
discordMembers: number;
}
export interface ContributorInfo {
login: string;
avatar_url: string;
html_url: string;
}
export function getContributors(): ContributorInfo[] {
return staticContributors as ContributorInfo[];
}
const staticContributorsCount = staticContributors.length;
// Fetch NPM download stats for the last week
async function fetchNpmDownloads(): Promise<number> {
try {
const response = await fetch(
"https://api.npmjs.org/downloads/point/last-week/better-auth",
{ next: { revalidate: 3600 } }, // Cache for 1 hour
);
if (!response.ok) {
console.error("Failed to fetch NPM downloads:", response.status);
return 2_000_000; // Fallback value
}
const data = await response.json();
return data.downloads || 2_000_000;
} catch (error) {
console.error("Error fetching NPM downloads:", error);
return 2_000_000; // Fallback value
}
}
// Shared headers for GitHub API requests
const githubHeaders = {
Accept: "application/vnd.github.v3+json",
...(process.env.GITHUB_TOKEN && {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
}),
};
// Fetch GitHub repository stats — repo info and contributors in parallel
async function fetchGitHubStats(): Promise<{
stars: number;
contributors: number;
}> {
try {
const [repoResponse, contributorsResponse] = await Promise.all([
fetch("https://api.github.com/repos/better-auth/better-auth", {
next: { revalidate: 3600 },
headers: githubHeaders,
}),
fetch(
"https://api.github.com/repos/better-auth/better-auth/contributors?per_page=1&anon=true",
{
next: { revalidate: 3600 },
headers: githubHeaders,
},
),
]);
let stars = 26000;
if (repoResponse.ok) {
const data = await repoResponse.json();
stars = data.stargazers_count || 26000;
} else {
console.error("Failed to fetch GitHub repo stats:", repoResponse.status);
}
let contributorsCount = staticContributorsCount;
if (contributorsResponse.ok) {
const linkHeader = contributorsResponse.headers.get("Link");
if (linkHeader) {
const match = linkHeader.match(/page=(\d+)>; rel="last"/);
if (match) {
contributorsCount = parseInt(match[1], 10);
}
}
} else {
console.error(
"Failed to fetch contributors:",
contributorsResponse.status,
);
}
return { stars, contributors: contributorsCount };
} catch (error) {
console.error("Error fetching GitHub stats:", error);
return { stars: 26000, contributors: staticContributorsCount };
}
}
// Cached function to get all community stats
export const getCommunityStats = unstable_cache(
async (): Promise<CommunityStats> => {
const [npmDownloads, githubStats] = await Promise.all([
fetchNpmDownloads(),
fetchGitHubStats(),
]);
return {
npmDownloads,
githubStars: githubStats.stars,
contributors: githubStats.contributors,
discordMembers: 10000, // Discord API requires bot token, using static value
};
},
["community-stats"],
{
revalidate: 3600, // Revalidate every hour
tags: ["community-stats"],
},
);