71 lines · 3.3 KB
import { env } from "cloudflare:workers";
import { all } from "../db";
import { repoDb } from "../scoped-db";
import { ownerSiteScopes } from "./store";
import { sitesDomain } from "./config";

const API = "https://api.cloudflare.com/client/v4";
const HOSTS_PER_CALL = 30;
const SITE_LABELS_MAX = 500;

/** The account's Sites: labels (production, previews, PR aliases) under `SITES_DOMAIN`, and their custom domains. */
export async function accountSitesHosts(accountId: string): Promise<{ labels: string[]; custom: string[] }> {
  // A site counts when the account owns it or its repository; repository scopes are already the account's.
  const repos = new Set(
    (await all<{ id: string }>("SELECT id FROM repos WHERE owner_id = ?", accountId)).map((repo) => repo.id),
  );
  const rows: Array<{ host: string; custom: number }> = [];
  for (const scope of await ownerSiteScopes(accountId)) {
    if (rows.length >= SITE_LABELS_MAX) break;
    const owned = repos.has(scope) ? "SELECT id FROM sites" : "SELECT id FROM sites WHERE owner_id = ?1";
    rows.push(
      ...(await repoDb(scope).all<{ host: string; custom: number }>(
        `SELECT label AS host, 0 AS custom FROM sites WHERE id IN (${owned})
     UNION SELECT label, 0 FROM site_deployments WHERE site_id IN (${owned})
     UNION SELECT label, 0 FROM site_pr_aliases WHERE site_id IN (${owned})
     UNION SELECT custom_domain, 1 FROM sites WHERE id IN (${owned}) AND custom_domain IS NOT NULL
     LIMIT ${SITE_LABELS_MAX}`,
        accountId,
      )),
    );
  }
  const domain = sitesDomain();
  const labels = domain
    ? rows.filter((row) => row.custom === 0).map((row) => `${row.host.toLowerCase()}.${domain}`)
    : [];
  const custom = rows.filter((row) => row.custom === 1).map((row) => row.host.toLowerCase());
  return { labels: [...new Set(labels)], custom: [...new Set(custom)] };
}

async function purgeHosts(zoneId: string, hosts: string[], accountId: string): Promise<number> {