Add Projects page backed by the Forgejo API, with caching

This commit is contained in:
badblocks 2026-07-20 12:10:32 -07:00
parent 5d5fb93647
commit 8466324a59
Signed by: badblocks
SSH key fingerprint: SHA256:hEcM6BP4hKm9F7WsomNuXSBpPn2BSDnFzPSl3y1NerQ
5 changed files with 269 additions and 1 deletions

52
src/lib/ForgejoClient.ts Normal file
View file

@ -0,0 +1,52 @@
import httpFetchClient from "@lib/HttpFetchClient";
const FORGEJO_BASE = "https://git.badblocks.dev";
const API = `${FORGEJO_BASE}/api/v1`;
const HEADERS = { Accept: "application/json" };
export interface ForgejoRepoDto {
name: string;
full_name: string;
description: string;
topics: string[];
stars_count: number;
forks_count: number;
updated_at: string;
language: string;
html_url: string;
archived: boolean;
default_branch: string;
}
export interface LastCommit { date: string; sha: string; message: string }
export const toIsoSeconds = (ts: string) =>
new Date(ts).toISOString().replace(/\.\d{3}Z$/, "");
const forgejoClient = {
searchByTopic: async (topic: string): Promise<ForgejoRepoDto[]> => {
const res = await httpFetchClient.get(
`${API}/repos/search?topic=true&q=${encodeURIComponent(topic)}&limit=50`, HEADERS);
if (!res?.ok) throw new Error("Forgejo search returned not-ok");
return res.data as ForgejoRepoDto[];
},
getLanguages: async (fullName: string): Promise<Record<string, number>> =>
httpFetchClient.get(`${API}/repos/${fullName}/languages`, HEADERS),
getLastCommit: async (fullName: string, branch: string): Promise<LastCommit | null> => {
try {
const res = await httpFetchClient.get(
`${API}/repos/${fullName}/branches/${encodeURIComponent(branch)}`, HEADERS);
const c = res?.commit;
if (!c?.timestamp) return null;
return {
date: toIsoSeconds(c.timestamp),
sha: String(c.id ?? "").slice(0, 7),
message: String(c.message ?? "").split("\n")[0].trim(),
};
} catch (error: any) {
if (error?.status === 404 || error?.statusCode === 404) return null;
throw error;
}
},
};
export default forgejoClient;