import { GITEA_URL, GITEA_USERNAME, GITEA_TOKEN } from './config'; import type { GiteaRepo, GiteaCommit, HeatmapEntry } from './types'; function headers() { const h: Record = { 'Accept': 'application/json' }; if (GITEA_TOKEN) h['Authorization'] = `token ${GITEA_TOKEN}`; return h; } async function get(path: string): Promise { const res = await fetch(`${GITEA_URL}/api/v1${path}`, { headers: headers() }); if (!res.ok) throw new Error(`Gitea API ${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[] = []; results.forEach(r => { 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); } export function calcStats(heatmap: HeatmapEntry[]) { 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(); year.forEach(e => { const d = new Date(e.timestamp * 1000); dateSet.add(d.toISOString().split('T')[0]); }); const today = new Date(); today.setHours(0, 0, 0, 0); let currentStreak = 0; const cur = new Date(today); if (!dateSet.has(cur.toISOString().split('T')[0])) cur.setDate(cur.getDate() - 1); while (dateSet.has(cur.toISOString().split('T')[0])) { currentStreak++; cur.setDate(cur.getDate() - 1); } let longestStreak = 0, streak = 0; const sorted = Array.from(dateSet).sort(); // ← only change for (let i = 0; i < sorted.length; i++) { if (i === 0) { streak = 1; continue; } const prev = new Date(sorted[i - 1]); prev.setDate(prev.getDate() + 1); if (prev.toISOString().split('T')[0] === sorted[i]) { streak++; } else { streak = 1; } if (streak > longestStreak) longestStreak = streak; } if (streak > longestStreak) longestStreak = streak; return { total, currentStreak, longestStreak, activeDays }; }