import { GITEA_USERNAME } from './config'; // keep only safe, non-secret values import type { GiteaRepo, GiteaCommit, HeatmapEntry, CommitStats, } from './types'; const API_PREFIX = '/api/gitea'; async function get(path: string): Promise { const res = await fetch(`${API_PREFIX}${path}`, { headers: { Accept: 'application/json' }, cache: 'no-store', }); if (!res.ok) throw new Error(`Gitea proxy ${path}: HTTP ${res.status}`); return res.json(); } export async function getRepos(limit = 6): Promise { return get( `/users/${GITEA_USERNAME}/repos?limit=${limit}&sort=newest` ); } export async function getHeatmap(): Promise { return get(`/users/${GITEA_USERNAME}/heatmap`); } export async function getRepoCommits( repo: string, limit = 5 ): Promise { return get( `/repos/${GITEA_USERNAME}/${repo}/commits?limit=${limit}` ); } export async function getRecentCommits( repos: GiteaRepo[], perRepo = 4 ): Promise { const results = await Promise.allSettled( repos.slice(0, 4).map((r) => getRepoCommits(r.name, perRepo).then((commits) => commits.map((c) => ({ ...c, _repo: r.name, _repoUrl: r.html_url, })) ) ) ); const all: GiteaCommit[] = []; for (const r of results) { if (r.status === 'fulfilled') all.push(...r.value); } return all .sort( (a, b) => new Date(b.created).getTime() - new Date(a.created).getTime() ) .slice(0, 15); } /** Local date key (avoids UTC shift bugs) */ function dayKey(date: Date): string { const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, '0'); const d = String(date.getDate()).padStart(2, '0'); return `${y}-${m}-${d}`; } export function calcStats(heatmap: HeatmapEntry[]): CommitStats { const yearAgo = Date.now() / 1000 - 365 * 86400; const year = heatmap.filter((e) => e.timestamp > yearAgo); const total = year.reduce((s, e) => s + e.contributions, 0); const activeDays = year.filter((e) => e.contributions > 0).length; const dateSet = new Set(); for (const e of year) { if (e.contributions <= 0) continue; const d = new Date(e.timestamp * 1000); dateSet.add(dayKey(d)); } const today = new Date(); today.setHours(0, 0, 0, 0); // Current streak (backwards from today) let currentStreak = 0; const cur = new Date(today); if (!dateSet.has(dayKey(cur))) { cur.setDate(cur.getDate() - 1); } while (dateSet.has(dayKey(cur))) { currentStreak++; cur.setDate(cur.getDate() - 1); } // Longest streak let longestStreak = 0; let streak = 0; const sorted = Array.from(dateSet).sort(); for (let i = 0; i < sorted.length; i++) { if (i === 0) { streak = 1; longestStreak = 1; continue; } const prev = new Date(sorted[i - 1] + 'T00:00:00'); prev.setDate(prev.getDate() + 1); if (dayKey(prev) === sorted[i]) streak++; else streak = 1; if (streak > longestStreak) longestStreak = streak; } return { total, currentStreak, longestStreak, activeDays }; }