import { env } from "cloudflare:workers";
import { repoDb, type ScopedDb } from "../scoped-db";
import { locate } from "../scoped-db/locators";
import { claimHost, siteDb, siteDbById } from "./store";
import { SITE_LIMITS, slotKey } from "./config";
import { commitLabel, pullLabel } from "./naming";
import { isOrphanSite } from "./sync";
import type { SiteDeploymentRow, SiteRow, SlotPointer } from "./config";
type AliasSite = Pick<SiteRow, "id" | "repo_id" | "label" | "commit_previews">;
type AliasDeployment = Pick<SiteDeploymentRow, "id" | "environment" | "branch" | "sha">;
type OpenPull = { number: number };
/** Open pull requests of the site's own repository whose head is `branch`; fork pulls never get an alias. */
async function openPullsFor(site: AliasSite, branch: string): Promise<OpenPull[]> {
if (!site.repo_id) return [];
return repoDb(site.repo_id).all<OpenPull>(
`SELECT i.number FROM pull_requests p JOIN issues i ON i.id = p.issue_id
WHERE p.repo_id = ? AND p.head_repo_id = ? AND p.head_ref = ? AND i.state = 'open' LIMIT ?`,
site.repo_id,
site.repo_id,
branch,
SITE_LIMITS.previewsPerPush,
);
}
/** Writes an alias pointer unless another live site already owns that host. */
async function point(site: AliasSite, label: string, deploymentId: string): Promise<boolean> {
const existing = await env.KV.get<SlotPointer>(slotKey(label), "json");
if (existing && existing.siteId !== site.id && !(await isOrphanSite(existing.siteId))) return false;
const pointer: SlotPointer = { siteId: site.id, deploymentId };
await env.KV.put(slotKey(label), JSON.stringify(pointer));
await claimHost(label, site.id);
return true;
}
async function record(
site: AliasSite,
label: string,