import { env } from "cloudflare:workers";
import type { ReactNode } from "react";
import { featurePage } from "~/lib/marketing/features";
import { accountCardVersion, featureCardVersion, OG_PREFIX, repoCardVersion, siteCardVersion } from "~/lib/og";
import { enforceRateLimit, requestIp } from "../limits";
import { loadRepo } from "../repos";
import { AccountCard, FeatureCard, RepoCard, SiteCard } from "./cards";
import { accountCardData, avatarDataUri, repoCardData, repoCardVisible } from "./data";
/** Versioned URLs change whenever the card would, so they can sit in caches for two weeks. */
export const OG_VERSIONED_CACHE = "public, max-age=1209600";
/** Unversioned or stale URLs, and the generic card every hidden target gets, revalidate hourly. */
export const OG_FALLBACK_CACHE = "public, max-age=3600";
const CACHE_NAME = "og-cards";
type Card = { key: string; version: string; render: () => Promise<ReactNode> };
function host(): string {
return new URL(env.PUBLIC_URL).host;
}
function siteCard(): Card {
return { key: "site", version: siteCardVersion(), render: async () => <SiteCard host={host()} /> };
}
function decode(segment: string): string | null {
try {
return decodeURIComponent(segment);
} catch {
return null;
}
}
/**
* Resolves the card for a path, or null for the generic card. Every lookup reads only public data and never the
* session, and every refusal (private, hidden, taken down, missing, malformed) collapses to the same null.
*/
async function resolveCard(pathname: string): Promise<Card | null> {
const rest = pathname.slice(OG_PREFIX.length);
if (!rest.endsWith(".png")) return null;