// public-hostname resolver reads filesystem (4th recurrence of
// llm-framing-deterministic).
//
// Reads the same two files that already drive routing:
//   - <configDir>/cloudflared/config.yml — the ingress map cloudflared itself
//     reads to decide where to route a hostname.
//   - <configDir>/alias-domains.json     — the alias list platform/ui/server's
//     isPublicHost() watches via watchFile.
// hasPublicEndpointConfigured() in admin/mcp/src/index.ts already parses both
// with the same regex; this resolver is the read-only twin that returns the
// chosen hostname instead of a boolean.
//
// Graph queries are gone. The previous version returned (none) on
// any account that bootstrapped its tunnel without writing :CloudflareTunnel
// nodes — exactly the laptop Real Agent state that produced this recurrence.
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
const INGRESS_RE = /^\s*-\s*hostname:\s*(\S+)/gm;
function isExcluded(host) {
    return host === "localhost" || host.endsWith(".local");
}
// Apex = single domain (e.g. "realagent.app"), with optional `www.` prefix
// stripped. Subdomain = anything else ("public.realagent.app").
function isApex(host) {
    const stripped = host.startsWith("www.") ? host.slice(4) : host;
    return stripped.split(".").length === 2;
}
function readIngressHostnames(configDir) {
    const path = join(configDir, "cloudflared", "config.yml");
    if (!existsSync(path))
        return [];
    try {
        const yaml = readFileSync(path, "utf-8");
        return [...yaml.matchAll(INGRESS_RE)].map((m) => m[1]).filter((h) => !isExcluded(h));
    }
    catch {
        return [];
    }
}
function readAliasDomains(configDir) {
    const path = join(configDir, "alias-domains.json");
    if (!existsSync(path))
        return [];
    try {
        const parsed = JSON.parse(readFileSync(path, "utf-8"));
        if (!Array.isArray(parsed))
            return [];
        return parsed.filter((h) => typeof h === "string" && h.length > 0 && !isExcluded(h));
    }
    catch {
        return [];
    }
}
// Tiebreak: apex wins over subdomain; otherwise first-in-file.
function pickHostname(candidates) {
    if (candidates.length === 0)
        return null;
    return candidates.find((h) => isApex(h)) ?? candidates[0];
}
export function resolvePublicHostname(configDir) {
    const ingress = readIngressHostnames(configDir);
    const chosen = pickHostname(ingress);
    if (chosen !== null) {
        return { hostname: chosen, isApex: isApex(chosen), source: "cloudflared-config.yml" };
    }
    const alias = readAliasDomains(configDir);
    const aliasChosen = pickHostname(alias);
    if (aliasChosen !== null) {
        return { hostname: aliasChosen, isApex: isApex(aliasChosen), source: "alias-domains.json" };
    }
    return { hostname: null, isApex: null, source: null, reason: "no-tunnel" };
}
//# sourceMappingURL=public-hostname.js.map