Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions lib/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
interface CacheEntry<T> {
data: T;
expiresAt: number;
}

class InMemoryCache {
private store = new Map<string, CacheEntry<unknown>>();

set<T>(key: string, data: T, ttlMs: number): void {
this.store.set(key, {
data,
expiresAt: Date.now() + ttlMs,
});
}

get<T>(key: string): T | null {
const entry = this.store.get(key) as CacheEntry<T> | undefined;
if (!entry) return null;
if (Date.now() > entry.expiresAt) {
this.store.delete(key);
return null;
}
return entry.data;
}

has(key: string): boolean {
return this.get(key) !== null;
}

delete(key: string): void {
this.store.delete(key);
}

clear(): void {
this.store.clear();
}
}

// Singleton cache instance shared across API requests
export const cache = new InMemoryCache();

export const CACHE_TTL = {
ONE_DAY: 24 * 60 * 60 * 1000,
ONE_HOUR: 60 * 60 * 1000,
FIVE_MINUTES: 5 * 60 * 1000,
};
14 changes: 13 additions & 1 deletion lib/github.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ContributionTotals, GitHubUserData, PullRequestNode, RepoNode } from "@/types/github";
import { graphql } from "@octokit/graphql";
import { cache, CACHE_TTL } from "./cache";

if (!process.env.GITHUB_TOKEN) {
throw new Error("Missing GITHUB_TOKEN");
Expand Down Expand Up @@ -60,15 +61,26 @@ const QUERY = /* GraphQL */ `
export async function fetchGitHubUserData(
username: string
): Promise<GitHubUserData> {
const cacheKey = `github:user:${username.toLowerCase()}`;

const cached = cache.get<GitHubUserData>(cacheKey);
if (cached) {
return cached;
}

const { user } = await client<{ user: any }>(QUERY, { login: username });

if (!user) {
throw new Error("User not found");
}

return {
const data: GitHubUserData = {
repos: user.repositories.nodes as RepoNode[],
pullRequests: user.pullRequests.nodes as PullRequestNode[],
contributions: user.contributionsCollection as ContributionTotals,
};

cache.set(cacheKey, data, CACHE_TTL.ONE_DAY);

return data;
}
Loading