/** Social card URLs and their version hashes; shared by page heads (client and server) and the /og handler. */
/** Bump when a card layout changes so every cached card URL changes with it. */
export const OG_RENDERER_VERSION = "1";
export const OG_WIDTH = 1200;
export const OG_HEIGHT = 630;
export const OG_PREFIX = "/og/";
export const SITE_OG_PATH = "/og/site.png";
export const SITE_DESCRIPTION =
"gitfor hosts Git repositories with pull requests, Actions-style CI, issues, security scanning and sites. Open source under 0BSD, and you can run your own instance.";
export const SITE_OG_ALT = "gitfor: open-source Git hosting, code review and CI";
/** FNV-1a 32-bit over the joined fields: cheap, sync and stable on both sides; it only needs to change, not resist collisions. */
export function ogVersion(fields: ReadonlyArray<string | number | null | undefined>): string {
const input = [
OG_RENDERER_VERSION,
...fields.map((field) => (field === null || field === undefined ? "" : String(field))),
].join("\u0000");
let hash = 0x811c9dc5;
for (let index = 0; index < input.length; index++) {
hash ^= input.charCodeAt(index);
hash = Math.imul(hash, 0x01000193);
}
return (hash >>> 0).toString(16).padStart(8, "0");
}
export type RepoCardData = {
owner: string;
name: string;
description: string | null;
stars: number;
forks: number;
openIssues: number;
openPulls: number;
avatarKey: string | null;
latestRelease: string | null;
};
export type AccountCardData = {
name: string;