77 lines · 3.2 KB
import { env } from "cloudflare:workers";
import { all, first } from "./db";
import { branchSha, listRefs } from "./git/refs";
import { withStore } from "./git/store";
import { renderMarkdown } from "./markdown";
import { REPO_SELECT } from "./repos";
import type { RepoRow } from "~/lib/types";

const DAY_MS = 24 * 60 * 60 * 1000;
const GRAPH_WEEKS = 52;
const WEEK_DAYS = 7;
const README_NAMES = new Set(["readme.md", "readme.markdown"]);
const MAX_README_BYTES = 256 * 1024;
const README_CACHE_TTL_SECONDS = 60 * 60 * 24 * 7;
const decoder = new TextDecoder();

export type ContributionDay = { date: string; count: number };

/** Daily repository activity counts (public repos unless `includePrivate`) for roughly the last year, oldest first, aligned to whole weeks. */
export async function contributionGraph(accountId: string, includePrivate: boolean): Promise<ContributionDay[]> {
  const now = Date.now();
  const today = new Date(now);
  const midnight = Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
  const start = new Date(midnight - (GRAPH_WEEKS * WEEK_DAYS + today.getUTCDay()) * DAY_MS);
  const rows = await all<{ day: string; count: number }>(
    `SELECT strftime('%Y-%m-%d', ac.created_at / 1000, 'unixepoch') AS day, COUNT(*) AS count
     FROM activity ac LEFT JOIN repos r ON r.id = ac.repo_id
     WHERE ac.actor_id = ? AND ac.created_at >= ? AND ac.kind != 'view'
       AND r.id IS NOT NULL AND (? = 1 OR r.visibility = 'public')
     GROUP BY day`,
    accountId,
    start.getTime(),
    includePrivate ? 1 : 0,
  );
  const counts = new Map(rows.map((row) => [row.day, row.count]));
  const days: ContributionDay[] = [];
  for (let time = start.getTime(); time <= now; time += DAY_MS) {
    const date = new Date(time).toISOString().slice(0, 10);
    days.push({ date, count: counts.get(date) ?? 0 });
  }