import { createHash, createPublicKey } from "node:crypto";
import { delimiter as pathDelimiter, isAbsolute as pathIsAbsolute, resolve as normalizePath, } from "node:path";
export const SEED_DOMAIN_IDS = [
    "runs",
    "runtimeEvents",
    "proofEvidence",
    "permissionActivity",
    "repositories",
    "onboarding",
    "settings",
    "reviewQueue",
];
export const SEED_FAILURE_REASONS = {
    seedConfigJsonInvalid: "seed-config-json-invalid",
    seedConfigUnknownDomain: "seed-config-unknown-domain",
    seedConfigDomainValueInvalid: "seed-config-domain-value-invalid",
};
export const SYNC_DEPTHS = ["off", "summary", "detail"];
export const SYNC_FAILURE_REASONS = {
    endpointMissing: "sync-endpoint-missing",
    endpointInvalid: "sync-endpoint-invalid",
    endpointInsecure: "sync-endpoint-insecure",
    enabledInvalid: "sync-enabled-invalid",
    domainValueInvalid: "sync-domain-value-invalid",
    signingKeyMissing: "sync-signing-key-missing",
    signingKeyInvalid: "sync-signing-key-invalid",
    keyIdInvalid: "sync-key-id-invalid",
    retryBudgetInvalid: "sync-retry-budget-invalid",
    timeoutInvalid: "sync-timeout-invalid",
    intervalInvalid: "sync-interval-invalid",
};
export const BRIDGE_MODE_FAILURE_REASONS = {
    bridgeModeMissing: "bridge-mode-missing",
    bridgeModeInvalid: "bridge-mode-invalid",
    nonLoopbackBindingRejected: "bridge-non-loopback-binding-rejected",
};
export const DEV_RUN_INTENT_RECEIPT_TRUST = {
    keyId: "pt-test-receipt-key-2026-05",
    issuer: "patchtrail-api-test",
    audience: "patchtrail-local-bridge-test",
    publicKeySpkiBase64: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZN2hg8XOHctTaq0PSK07j54WU3gldqx5/a0J/s93WI6YWgnU6QBik01k4Mgi1bGp6vtyQU9q1ut2/GlD2OSXoQ==",
};
export const RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS = {
    trustedPublicKeysMissing: "run-intent-receipt-trusted-public-keys-missing",
    trustedPublicKeyInvalid: "run-intent-receipt-trusted-public-key-invalid",
    trustedPublicKeyDevOnly: "run-intent-receipt-trusted-public-key-dev-only",
    keyIdMissing: "run-intent-receipt-key-id-missing",
    keyIdInvalid: "run-intent-receipt-key-id-invalid",
    keyIdDuplicate: "run-intent-receipt-key-id-duplicate",
    issuerMissing: "run-intent-receipt-issuer-missing",
    issuerInvalid: "run-intent-receipt-issuer-invalid",
    audienceMissing: "run-intent-receipt-audience-missing",
    audienceInvalid: "run-intent-receipt-audience-invalid",
};
const TRUST_METADATA_MAX_LENGTH = 80;
function parsePort(value, fallback) {
    if (!value)
        return fallback;
    if (!/^\d+$/.test(value)) {
        throw new Error(`Invalid PATCHTRAIL_BRIDGE_PORT: ${value}`);
    }
    const parsed = Number(value);
    if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65_535) {
        throw new Error(`Invalid PATCHTRAIL_BRIDGE_PORT: ${value}`);
    }
    return parsed;
}
export function parseBridgeMode(value) {
    if (value === "production" || value === "test" || value === "development") {
        return value;
    }
    if (!value)
        throw new Error(BRIDGE_MODE_FAILURE_REASONS.bridgeModeMissing);
    throw new Error(BRIDGE_MODE_FAILURE_REASONS.bridgeModeInvalid);
}
export function loadBridgeConfig(env = process.env) {
    const mode = parseBridgeMode(env.NODE_ENV);
    return {
        host: env.PATCHTRAIL_BRIDGE_HOST ?? "127.0.0.1",
        port: parsePort(env.PATCHTRAIL_BRIDGE_PORT, 47_839),
        mode,
        allowNonLoopback: env.PATCHTRAIL_ALLOW_NON_LOOPBACK === "1",
        runIntentReceiptTrust: loadRunIntentReceiptTrustConfig(env, mode),
        seed: loadSeedConfig(env, mode),
        sync: loadSyncConfig(env, mode),
        repoAllowedRoots: parseRepoAllowedRoots(env.PATCHTRAIL_REPO_ALLOWED_ROOTS),
    };
}
/**
 * Parse the repo allow-list from a delimiter-separated path list. Accepts the
 * OS path delimiter (`:` POSIX / `;` Windows) and additionally always splits on
 * a newline so a multi-line config value works on either OS. Blank and
 * non-absolute entries are dropped; absolutes are normalized + de-duplicated.
 */
export function parseRepoAllowedRoots(value) {
    if (!value)
        return [];
    const parts = value.split(/[\n;]/u).flatMap((segment) => 
    // Only split POSIX `:` when it is the platform delimiter, so Windows drive
    // letters (C:\...) are not torn apart.
    pathDelimiter === ":" ? segment.split(":") : [segment]);
    const roots = [];
    for (const part of parts) {
        const trimmed = part.trim();
        if (!trimmed || !pathIsAbsolute(trimmed))
            continue;
        const normalized = normalizePath(trimmed);
        if (!roots.includes(normalized))
            roots.push(normalized);
    }
    return roots;
}
export function assertLoopbackBinding(config) {
    const loopbackHosts = new Set(["127.0.0.1", "::1", "localhost"]);
    if (loopbackHosts.has(config.host))
        return;
    if (config.mode !== "production" && config.allowNonLoopback)
        return;
    throw new Error(BRIDGE_MODE_FAILURE_REASONS.nonLoopbackBindingRejected);
}
export function loadRunIntentReceiptTrustConfig(env, mode) {
    const configuredKeys = readConfiguredReceiptTrustedPublicKeys(env);
    const usesDevelopmentFixture = configuredKeys.length === 0;
    const keyInputs = usesDevelopmentFixture
        ? [
            {
                keyId: DEV_RUN_INTENT_RECEIPT_TRUST.keyId,
                publicKeySpkiBase64: DEV_RUN_INTENT_RECEIPT_TRUST.publicKeySpkiBase64,
                source: "development-fixture",
            },
        ]
        : configuredKeys;
    const issuer = env.PATCHTRAIL_RUN_INTENT_RECEIPT_ISSUER ??
        (usesDevelopmentFixture ? DEV_RUN_INTENT_RECEIPT_TRUST.issuer : undefined);
    const audience = env.PATCHTRAIL_RUN_INTENT_RECEIPT_AUDIENCE ??
        (usesDevelopmentFixture
            ? DEV_RUN_INTENT_RECEIPT_TRUST.audience
            : undefined);
    const failures = validateRunIntentReceiptTrustInput({
        issuer,
        audience,
        keys: keyInputs,
        mode,
        usesDevelopmentFixture,
    });
    if (failures.length > 0) {
        throw new Error(`Invalid PatchTrail run-intent receipt trust configuration: ${failures.join(",")}`);
    }
    // Validation above guarantees issuer/audience are present; narrow explicitly
    // rather than asserting non-null so the type system carries the invariant.
    if (issuer === undefined || audience === undefined) {
        throw new Error("Invalid PatchTrail run-intent receipt trust configuration: issuer and audience are required");
    }
    return {
        issuer: issuer.trim(),
        audience: audience.trim(),
        trustedPublicKeys: keyInputs.map((key) => ({
            keyId: key.keyId.trim(),
            publicKey: parseReceiptPublicKey(key.publicKeySpkiBase64),
            source: key.source,
        })),
    };
}
function readConfiguredReceiptTrustedPublicKeys(env) {
    const rawJson = env.PATCHTRAIL_RUN_INTENT_RECEIPT_TRUSTED_PUBLIC_KEYS;
    const singleKey = env.PATCHTRAIL_RUN_INTENT_RECEIPT_PUBLIC_KEY_SPKI_BASE64;
    const singleKeyId = env.PATCHTRAIL_RUN_INTENT_RECEIPT_KEY_ID;
    const keys = [];
    if (rawJson)
        keys.push(...parseReceiptTrustedPublicKeysJson(rawJson));
    if (singleKey || singleKeyId) {
        keys.push({
            keyId: singleKeyId ?? "",
            publicKeySpkiBase64: singleKey ?? "",
            source: "configured",
        });
    }
    return keys;
}
function parseReceiptTrustedPublicKeysJson(rawJson) {
    try {
        const parsed = JSON.parse(rawJson);
        if (Array.isArray(parsed)) {
            return parsed.map((item) => isRecord(item)
                ? {
                    keyId: readString(item.keyId),
                    publicKeySpkiBase64: readString(item.publicKeySpkiBase64),
                    source: "configured",
                }
                : { keyId: "", publicKeySpkiBase64: "", source: "configured" });
        }
        if (isRecord(parsed)) {
            return Object.entries(parsed).map(([keyId, publicKeySpkiBase64]) => ({
                keyId,
                publicKeySpkiBase64: readString(publicKeySpkiBase64),
                source: "configured",
            }));
        }
    }
    catch {
        // Bounded validation below reports a safe reason label only.
    }
    return [{ keyId: "", publicKeySpkiBase64: "", source: "configured" }];
}
function validateRunIntentReceiptTrustInput(input) {
    const failures = [];
    addTrustMetadataFailure(failures, input.issuer, RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.issuerMissing, RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.issuerInvalid);
    addTrustMetadataFailure(failures, input.audience, RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.audienceMissing, RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.audienceInvalid);
    if (input.keys.length === 0) {
        failures.push(RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.trustedPublicKeysMissing);
    }
    const keyIds = new Set();
    for (const key of input.keys) {
        addTrustMetadataFailure(failures, key.keyId, RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.keyIdMissing, RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.keyIdInvalid);
        const normalizedKeyId = key.keyId.trim();
        if (normalizedKeyId) {
            if (keyIds.has(normalizedKeyId)) {
                failures.push(RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.keyIdDuplicate);
            }
            keyIds.add(normalizedKeyId);
        }
        if (!key.publicKeySpkiBase64.trim() ||
            !isValidReceiptPublicKey(key.publicKeySpkiBase64)) {
            failures.push(RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.trustedPublicKeyInvalid);
        }
        else if (input.mode === "production" &&
            isDevelopmentReceiptPublicKey(key.publicKeySpkiBase64)) {
            failures.push(RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.trustedPublicKeyDevOnly);
        }
    }
    if (input.mode === "production" && input.usesDevelopmentFixture) {
        failures.push(RUN_INTENT_RECEIPT_TRUST_FAILURE_REASONS.trustedPublicKeysMissing);
    }
    return uniqueStrings(failures);
}
function addTrustMetadataFailure(failures, value, missingReason, invalidReason) {
    if (!value?.trim()) {
        failures.push(missingReason);
        return;
    }
    if (!isSafeTrustMetadata(value.trim()))
        failures.push(invalidReason);
}
function isSafeTrustMetadata(value) {
    if (value.length < 1 || value.length > TRUST_METADATA_MAX_LENGTH) {
        return false;
    }
    if (!isAsciiLetterOrDigit(value[0]))
        return false;
    return [...value].every((character) => isAsciiLetterOrDigit(character) ||
        character === "." ||
        character === "_" ||
        character === ":" ||
        character === "-");
}
function isValidReceiptPublicKey(publicKeySpkiBase64) {
    try {
        const publicKey = parseReceiptPublicKey(publicKeySpkiBase64);
        return publicKey.asymmetricKeyType === "ec";
    }
    catch {
        return false;
    }
}
function isDevelopmentReceiptPublicKey(publicKeySpkiBase64) {
    try {
        return (fingerprintReceiptPublicKey(publicKeySpkiBase64) ===
            fingerprintReceiptPublicKey(DEV_RUN_INTENT_RECEIPT_TRUST.publicKeySpkiBase64));
    }
    catch {
        return false;
    }
}
function fingerprintReceiptPublicKey(publicKeySpkiBase64) {
    const der = parseReceiptPublicKey(publicKeySpkiBase64).export({
        format: "der",
        type: "spki",
    });
    return createHash("sha256").update(der).digest("base64url");
}
function parseReceiptPublicKey(publicKeySpkiBase64) {
    return createPublicKey({
        key: Buffer.from(publicKeySpkiBase64.trim(), "base64"),
        format: "der",
        type: "spki",
    });
}
function isAsciiLetterOrDigit(character) {
    return Boolean(character &&
        ((character >= "a" && character <= "z") ||
            (character >= "A" && character <= "Z") ||
            (character >= "0" && character <= "9")));
}
function uniqueStrings(values) {
    const seen = new Set();
    const unique = [];
    for (const value of values) {
        if (seen.has(value))
            continue;
        seen.add(value);
        unique.push(value);
    }
    return unique;
}
function readString(value) {
    return typeof value === "string" ? value : "";
}
function isRecord(value) {
    return typeof value === "object" && value !== null && !Array.isArray(value);
}
const SEED_DOMAIN_ID_SET = new Set(SEED_DOMAIN_IDS);
const SEED_DOMAIN_ENV_KEYS = {
    runs: "PATCHTRAIL_BRIDGE_SEED_RUNS",
    runtimeEvents: "PATCHTRAIL_BRIDGE_SEED_RUNTIME_EVENTS",
    proofEvidence: "PATCHTRAIL_BRIDGE_SEED_PROOF_EVIDENCE",
    permissionActivity: "PATCHTRAIL_BRIDGE_SEED_PERMISSION_ACTIVITY",
    repositories: "PATCHTRAIL_BRIDGE_SEED_REPOSITORIES",
    onboarding: "PATCHTRAIL_BRIDGE_SEED_ONBOARDING",
    settings: "PATCHTRAIL_BRIDGE_SEED_SETTINGS",
    reviewQueue: "PATCHTRAIL_BRIDGE_SEED_REVIEW_QUEUE",
};
export function loadSeedConfig(env, mode) {
    const failures = [];
    const domains = buildDefaultSeedDomains();
    const rawJson = env.PATCHTRAIL_BRIDGE_SEED_CONFIG;
    if (rawJson && rawJson.trim().length > 0) {
        applySeedJson(rawJson, domains, failures);
    }
    for (const domainId of SEED_DOMAIN_IDS) {
        const envKey = SEED_DOMAIN_ENV_KEYS[domainId];
        const rawValue = env[envKey];
        if (rawValue === undefined)
            continue;
        const parsed = parseSeedBoolean(rawValue);
        if (parsed === null) {
            failures.push(SEED_FAILURE_REASONS.seedConfigDomainValueInvalid);
            continue;
        }
        domains[domainId] = parsed;
    }
    if (failures.length > 0) {
        throw new Error(`Invalid PatchTrail bridge seed configuration: ${uniqueStrings(failures).join(",")}`);
    }
    const rawEnabledFlag = env.PATCHTRAIL_BRIDGE_SEED_ENABLED;
    const parsedEnabledFlag = rawEnabledFlag === undefined ? null : parseSeedBoolean(rawEnabledFlag);
    if (rawEnabledFlag !== undefined && parsedEnabledFlag === null) {
        throw new Error(`Invalid PatchTrail bridge seed configuration: ${SEED_FAILURE_REASONS.seedConfigDomainValueInvalid}`);
    }
    // Fail closed in production: even if domain flags are set, the seed loader stays off
    // unless a deployer explicitly turns it on via PATCHTRAIL_BRIDGE_SEED_ENABLED=1.
    const anyDomainEnabled = SEED_DOMAIN_IDS.some((id) => domains[id]);
    const enabled = parsedEnabledFlag === true
        ? true
        : parsedEnabledFlag === false
            ? false
            : mode === "production"
                ? false
                : anyDomainEnabled;
    return {
        enabled,
        domains,
    };
}
export function summarizeSeedConfig(config) {
    if (!config.enabled) {
        return { enabled: false, enabledDomains: [] };
    }
    const enabledDomains = SEED_DOMAIN_IDS.filter((id) => config.domains[id]);
    return { enabled: true, enabledDomains };
}
function buildDefaultSeedDomains() {
    const domains = {};
    for (const id of SEED_DOMAIN_IDS) {
        domains[id] = false;
    }
    return domains;
}
function applySeedJson(rawJson, domains, failures) {
    let parsed;
    try {
        parsed = JSON.parse(rawJson);
    }
    catch {
        failures.push(SEED_FAILURE_REASONS.seedConfigJsonInvalid);
        return;
    }
    if (!isRecord(parsed)) {
        failures.push(SEED_FAILURE_REASONS.seedConfigJsonInvalid);
        return;
    }
    const rawDomains = parsed.domains;
    if (rawDomains === undefined)
        return;
    if (!isRecord(rawDomains)) {
        failures.push(SEED_FAILURE_REASONS.seedConfigJsonInvalid);
        return;
    }
    for (const [key, value] of Object.entries(rawDomains)) {
        if (!SEED_DOMAIN_ID_SET.has(key)) {
            failures.push(SEED_FAILURE_REASONS.seedConfigUnknownDomain);
            continue;
        }
        if (typeof value !== "boolean") {
            failures.push(SEED_FAILURE_REASONS.seedConfigDomainValueInvalid);
            continue;
        }
        domains[key] = value;
    }
}
function parseSeedBoolean(value) {
    const normalized = value.trim().toLowerCase();
    if (normalized === "1" || normalized === "true")
        return true;
    if (normalized === "0" || normalized === "false")
        return false;
    return null;
}
const SYNC_DOMAIN_ENV_KEYS = {
    runs: "PATCHTRAIL_BRIDGE_SYNC_RUNS",
    runtimeEvents: "PATCHTRAIL_BRIDGE_SYNC_RUNTIME_EVENTS",
    proofEvidence: "PATCHTRAIL_BRIDGE_SYNC_PROOF_EVIDENCE",
    permissionActivity: "PATCHTRAIL_BRIDGE_SYNC_PERMISSION_ACTIVITY",
    repositories: "PATCHTRAIL_BRIDGE_SYNC_REPOSITORIES",
    onboarding: "PATCHTRAIL_BRIDGE_SYNC_ONBOARDING",
    settings: "PATCHTRAIL_BRIDGE_SYNC_SETTINGS",
    reviewQueue: "PATCHTRAIL_BRIDGE_SYNC_REVIEW_QUEUE",
};
const DEFAULT_SYNC_RETRY_BUDGET = 5;
const DEFAULT_SYNC_TIMEOUT_MS = 10_000;
const DEFAULT_SYNC_INTERVAL_MS = 30_000;
const MIN_SYNC_SIGNING_KEY_LENGTH = 43;
const MAX_SYNC_SIGNING_KEY_LENGTH = 256;
const MIN_SYNC_SIGNING_KEY_DISTINCT_CHARS = 16;
const SYNC_RECEIVER_BASE_PATH = "/api/v1/sync/projections";
function parseSyncEndpoint(value, mode) {
    if (!value)
        return null;
    let url;
    try {
        url = new URL(value);
    }
    catch {
        throw new Error(SYNC_FAILURE_REASONS.endpointInvalid);
    }
    if (mode === "production" && url.protocol !== "https:") {
        throw new Error(SYNC_FAILURE_REASONS.endpointInsecure);
    }
    if (url.protocol !== "https:" && url.protocol !== "http:") {
        throw new Error(SYNC_FAILURE_REASONS.endpointInvalid);
    }
    if (url.username ||
        url.password ||
        url.search ||
        url.hash ||
        url.pathname !== SYNC_RECEIVER_BASE_PATH) {
        throw new Error(SYNC_FAILURE_REASONS.endpointInvalid);
    }
    return `${url.origin}${SYNC_RECEIVER_BASE_PATH}`;
}
function parseRetryBudget(value) {
    if (!value)
        return DEFAULT_SYNC_RETRY_BUDGET;
    if (!/^\d+$/.test(value)) {
        throw new Error(SYNC_FAILURE_REASONS.retryBudgetInvalid);
    }
    const parsed = Number(value);
    if (!Number.isInteger(parsed) || parsed < 0 || parsed > 100) {
        throw new Error(SYNC_FAILURE_REASONS.retryBudgetInvalid);
    }
    return parsed;
}
function parseSyncTimeoutMs(value) {
    if (!value)
        return DEFAULT_SYNC_TIMEOUT_MS;
    if (!/^\d+$/.test(value)) {
        throw new Error(SYNC_FAILURE_REASONS.timeoutInvalid);
    }
    const parsed = Number(value);
    if (!Number.isInteger(parsed) || parsed < 1_000 || parsed > 60_000) {
        throw new Error(SYNC_FAILURE_REASONS.timeoutInvalid);
    }
    return parsed;
}
function parseSyncIntervalMs(value) {
    if (!value)
        return DEFAULT_SYNC_INTERVAL_MS;
    if (!/^\d+$/.test(value)) {
        throw new Error(SYNC_FAILURE_REASONS.intervalInvalid);
    }
    const parsed = Number(value);
    if (!Number.isInteger(parsed) || parsed < 1_000 || parsed > 300_000) {
        throw new Error(SYNC_FAILURE_REASONS.intervalInvalid);
    }
    return parsed;
}
function parseSyncSigningKey(value) {
    if (!value)
        return null;
    const trimmed = value.trim();
    const decoded = decodeBase64Url(trimmed);
    if (trimmed.length < MIN_SYNC_SIGNING_KEY_LENGTH ||
        trimmed.length > MAX_SYNC_SIGNING_KEY_LENGTH ||
        !/^[A-Za-z0-9_-]+$/u.test(trimmed) ||
        new Set(trimmed).size < MIN_SYNC_SIGNING_KEY_DISTINCT_CHARS ||
        !decoded ||
        decoded.length < 32) {
        throw new Error(SYNC_FAILURE_REASONS.signingKeyInvalid);
    }
    return trimmed;
}
function decodeBase64Url(value) {
    if (value.length % 4 === 1)
        return null;
    try {
        const decoded = Buffer.from(value, "base64url");
        if (decoded.toString("base64url") !== value)
            return null;
        return decoded;
    }
    catch {
        return null;
    }
}
function parseSyncKeyId(value) {
    if (!value)
        return null;
    const trimmed = value.trim();
    if (trimmed.length < 1 ||
        trimmed.length > 80 ||
        !/^[A-Za-z0-9_.-]+$/u.test(trimmed)) {
        throw new Error(SYNC_FAILURE_REASONS.keyIdInvalid);
    }
    return trimmed;
}
function syncAudienceFromEndpoint(endpointUrl) {
    if (!endpointUrl)
        return null;
    const url = new URL(endpointUrl);
    return `${url.protocol}//${url.host}`;
}
export function loadSyncConfig(env, mode) {
    const enabledRaw = env.PATCHTRAIL_BRIDGE_SYNC_ENABLED;
    const parsedEnabled = enabledRaw === undefined ? false : parseSeedBoolean(enabledRaw);
    if (parsedEnabled === null) {
        throw new Error(SYNC_FAILURE_REASONS.enabledInvalid);
    }
    const enabledFlag = parsedEnabled === true;
    const endpointUrl = enabledFlag
        ? parseSyncEndpoint(env.PATCHTRAIL_BRIDGE_SYNC_ENDPOINT, mode)
        : null;
    const signingKey = enabledFlag
        ? parseSyncSigningKey(env.PATCHTRAIL_BRIDGE_SYNC_SIGNING_KEY)
        : null;
    const keyId = enabledFlag
        ? parseSyncKeyId(env.PATCHTRAIL_BRIDGE_SYNC_KEY_ID)
        : null;
    const retryBudget = parseRetryBudget(env.PATCHTRAIL_BRIDGE_SYNC_RETRY_BUDGET);
    const timeoutMs = parseSyncTimeoutMs(env.PATCHTRAIL_BRIDGE_SYNC_TIMEOUT_MS);
    const intervalMs = parseSyncIntervalMs(env.PATCHTRAIL_BRIDGE_SYNC_INTERVAL_MS);
    const domains = {
        runs: false,
        runtimeEvents: false,
        proofEvidence: false,
        permissionActivity: false,
        repositories: false,
        onboarding: false,
        settings: false,
        reviewQueue: false,
    };
    for (const id of SEED_DOMAIN_IDS) {
        const envKey = SYNC_DOMAIN_ENV_KEYS[id];
        const raw = env[envKey];
        if (raw !== undefined) {
            const parsed = parseSeedBoolean(raw);
            if (parsed === null) {
                throw new Error(SYNC_FAILURE_REASONS.domainValueInvalid);
            }
            domains[id] = parsed;
        }
    }
    let enabled = enabledFlag;
    if (enabled && !endpointUrl) {
        throw new Error(SYNC_FAILURE_REASONS.endpointMissing);
    }
    if (enabled && !signingKey) {
        throw new Error(SYNC_FAILURE_REASONS.signingKeyMissing);
    }
    if (enabled && !keyId) {
        throw new Error(SYNC_FAILURE_REASONS.keyIdInvalid);
    }
    if (!endpointUrl)
        enabled = false;
    // Default depths: summary for core loop domains, off for auxiliary.
    const defaultDepths = {
        runs: "summary",
        runtimeEvents: "off",
        proofEvidence: "summary",
        permissionActivity: "off",
        repositories: "off",
        onboarding: "off",
        settings: "off",
        reviewQueue: "summary",
    };
    return {
        enabled,
        endpointUrl,
        signingKey,
        keyId,
        audience: syncAudienceFromEndpoint(endpointUrl),
        retryBudget,
        timeoutMs,
        intervalMs,
        domains,
        domainDepths: defaultDepths,
    };
}
export function summarizeSyncConfig(config) {
    const enabledDomains = SEED_DOMAIN_IDS.filter((id) => config.domains[id]);
    return {
        enabled: config.enabled,
        endpointConfigured: Boolean(config.endpointUrl),
        retryBudget: config.retryBudget,
        timeoutMs: config.timeoutMs,
        intervalMs: config.intervalMs,
        enabledDomains,
        domainDepths: config.domainDepths
            ? { ...config.domainDepths }
            : defaultDepths(),
    };
}
function defaultDepths() {
    return {
        runs: "summary",
        runtimeEvents: "off",
        proofEvidence: "summary",
        permissionActivity: "off",
        repositories: "off",
        onboarding: "off",
        settings: "off",
        reviewQueue: "summary",
    };
}
