import {
  Route53Client
} from "./chunk-32e7ya18.js";
import {
  AWSClient
} from "./chunk-zqtpg06c.js";
// src/dns/porkbun.ts
var PORKBUN_API_URL = "https://api.porkbun.com/api/json/v3";
var PORKBUN_MAX_ATTEMPTS = 8;
var PORKBUN_REQUEST_TIMEOUT_MS = 15000;
function isRetryablePorkbunResponse(status, message = "") {
  return status === 408 || status === 409 || status === 425 || status === 429 || status >= 500 || /rate limit|temporar|timed? ?out|try again/i.test(message);
}
async function waitForPorkbunRetry(attempt, response) {
  const retryAfter = response?.headers.get("retry-after");
  const retryAfterMs = retryAfter === null || retryAfter === undefined ? undefined : Number(retryAfter) * 1000;
  const delay = Number.isFinite(retryAfterMs) ? Math.max(0, retryAfterMs) : Math.min(1000 * 2 ** (attempt - 1), 30000);
  await new Promise((resolve) => setTimeout(resolve, delay));
}

class PorkbunProvider {
  name = "porkbun";
  apiKey;
  secretKey;
  requestTimeoutMs;
  constructor(apiKey, secretKey, requestTimeoutMs = PORKBUN_REQUEST_TIMEOUT_MS) {
    this.apiKey = apiKey;
    this.secretKey = secretKey;
    this.requestTimeoutMs = requestTimeoutMs;
  }
  async request(endpoint, additionalBody = {}) {
    let lastError;
    for (let attempt = 1;attempt <= PORKBUN_MAX_ATTEMPTS; attempt += 1) {
      let response;
      const controller = new AbortController;
      const timeout = setTimeout(() => {
        controller.abort(new Error(`Porkbun API request timed out after ${this.requestTimeoutMs}ms`));
      }, this.requestTimeoutMs);
      try {
        response = await fetch(`${PORKBUN_API_URL}${endpoint}`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify({
            apikey: this.apiKey,
            secretapikey: this.secretKey,
            ...additionalBody
          }),
          signal: controller.signal
        });
      } catch (error) {
        lastError = error;
        if (attempt === PORKBUN_MAX_ATTEMPTS)
          throw error;
        await waitForPorkbunRetry(attempt);
        continue;
      } finally {
        clearTimeout(timeout);
      }
      if (!response.ok) {
        lastError = new Error(`Porkbun API error: ${response.status} ${response.statusText}`);
        if (!isRetryablePorkbunResponse(response.status) || attempt === PORKBUN_MAX_ATTEMPTS)
          throw lastError;
        await waitForPorkbunRetry(attempt, response);
        continue;
      }
      const data = await response.json();
      if (data.status === "ERROR") {
        lastError = new Error(`Porkbun API error: ${data.message || "Unknown error"}`);
        if (!isRetryablePorkbunResponse(0, data.message) || attempt === PORKBUN_MAX_ATTEMPTS)
          throw lastError;
        await waitForPorkbunRetry(attempt, response);
        continue;
      }
      return data;
    }
    throw lastError;
  }
  getSubdomain(recordName, domain) {
    const cleanName = recordName.replace(/\.$/, "");
    const cleanDomain = domain.replace(/\.$/, "");
    if (cleanName === cleanDomain) {
      return "";
    }
    if (cleanName.endsWith(`.${cleanDomain}`)) {
      return cleanName.slice(0, -(cleanDomain.length + 1));
    }
    return cleanName;
  }
  getRootDomain(domain) {
    const parts = domain.replace(/\.$/, "").split(".");
    if (parts.length >= 2) {
      return parts.slice(-2).join(".");
    }
    return domain;
  }
  static ADDRESS_TYPES = new Set(["A", "AAAA"]);
  async clearConflictingAliases(domain, record) {
    if (!PorkbunProvider.ADDRESS_TYPES.has(record.type))
      return [];
    const rootDomain = this.getRootDomain(domain);
    const subdomain = this.getSubdomain(record.name, rootDomain);
    const listed = await this.listRecords(domain);
    if (!listed.success)
      return [`could not list records to clear ALIAS/CNAME conflicts: ${listed.message ?? "unknown provider error"}`];
    const warnings = [];
    for (const existing of listed.records) {
      if (existing.type !== "ALIAS" && existing.type !== "CNAME")
        continue;
      if (this.getSubdomain(existing.name, rootDomain) !== subdomain)
        continue;
      const removed = await this.deleteRecord(domain, existing);
      if (!removed.success)
        warnings.push(`could not remove conflicting ${existing.type} on ${existing.name}: ${removed.message ?? "unknown provider error"}`);
    }
    return warnings;
  }
  async addressRecordExists(domain, record) {
    const rootDomain = this.getRootDomain(domain);
    const subdomain = this.getSubdomain(record.name, rootDomain);
    const listed = await this.listRecords(domain);
    if (!listed.success)
      return true;
    return listed.records.some((r) => r.type === record.type && this.getSubdomain(r.name, rootDomain) === subdomain && r.content === record.content);
  }
  async createRecord(domain, record) {
    try {
      const rootDomain = this.getRootDomain(domain);
      const subdomain = this.getSubdomain(record.name, rootDomain);
      const body = {
        type: record.type,
        content: record.content,
        ttl: String(record.ttl || 600)
      };
      if (subdomain) {
        body.name = subdomain;
      }
      if ((record.type === "MX" || record.type === "SRV") && record.priority !== undefined) {
        body.prio = String(record.priority);
      }
      if (record.type === "SRV" && record.weight !== undefined && record.port !== undefined) {
        body.content = `${record.weight} ${record.port} ${record.content}`;
      }
      const conflicts = await this.clearConflictingAliases(domain, record);
      const response = await this.request(`/dns/create/${rootDomain}`, body);
      if (PorkbunProvider.ADDRESS_TYPES.has(record.type) && !await this.addressRecordExists(domain, record)) {
        return {
          success: false,
          message: `Porkbun reported success but no ${record.type} record for ${record.name} exists${conflicts.length > 0 ? ` (${conflicts.join("; ")})` : ""}. A conflicting ALIAS/CNAME on the same name silently voids the write.`
        };
      }
      return {
        success: true,
        id: response.id?.toString(),
        message: "Record created successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async upsertRecord(domain, record) {
    try {
      const rootDomain = this.getRootDomain(domain);
      const subdomain = this.getSubdomain(record.name, rootDomain);
      const existing = await this.listRecords(domain, record.type);
      if (existing.success) {
        const matchingRecord = existing.records.find((r) => {
          const existingSubdomain = this.getSubdomain(r.name, rootDomain);
          return existingSubdomain === subdomain && r.type === record.type;
        });
        if (matchingRecord?.id) {
          const body = {
            type: record.type,
            content: record.content,
            ttl: String(record.ttl || 600)
          };
          if (subdomain) {
            body.name = subdomain;
          }
          if ((record.type === "MX" || record.type === "SRV") && record.priority !== undefined) {
            body.prio = String(record.priority);
          }
          if (record.type === "SRV" && record.weight !== undefined && record.port !== undefined) {
            body.content = `${record.weight} ${record.port} ${record.content}`;
          }
          await this.request(`/dns/edit/${rootDomain}/${matchingRecord.id}`, body);
          return {
            success: true,
            id: matchingRecord.id,
            message: "Record updated successfully"
          };
        }
      }
      return this.createRecord(domain, record);
    } catch (error) {
      return this.createRecord(domain, record);
    }
  }
  async deleteRecord(domain, record) {
    try {
      const rootDomain = this.getRootDomain(domain);
      if ("id" in record && record.id) {
        await this.request(`/dns/delete/${rootDomain}/${record.id}`);
        return {
          success: true,
          message: "Record deleted successfully"
        };
      }
      const subdomain = this.getSubdomain(record.name, rootDomain);
      const existing = await this.listRecords(domain);
      if (!existing.success) {
        return {
          success: false,
          message: "Failed to list records"
        };
      }
      const matchingRecord = existing.records.find((r) => {
        const existingSubdomain = this.getSubdomain(r.name, rootDomain);
        return existingSubdomain === subdomain && r.type === record.type && r.content === record.content;
      });
      if (!matchingRecord?.id) {
        return {
          success: false,
          message: "Record not found"
        };
      }
      await this.request(`/dns/delete/${rootDomain}/${matchingRecord.id}`);
      return {
        success: true,
        message: "Record deleted successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async listRecords(domain, type) {
    try {
      const rootDomain = this.getRootDomain(domain);
      let endpoint = `/dns/retrieve/${rootDomain}`;
      if (type) {
        endpoint = `/dns/retrieveByNameType/${rootDomain}/${type}`;
      }
      const response = await this.request(endpoint);
      const records = (response.records || []).map((r) => ({
        id: r.id,
        name: r.name || rootDomain,
        type: r.type,
        content: r.content,
        ttl: Number.parseInt(r.ttl, 10),
        priority: r.prio ? Number.parseInt(r.prio, 10) : undefined
      }));
      return {
        success: true,
        records
      };
    } catch (error) {
      return {
        success: false,
        records: [],
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async canManageDomain(domain) {
    try {
      const rootDomain = this.getRootDomain(domain);
      await this.request(`/dns/retrieve/${rootDomain}`);
      return true;
    } catch {
      return false;
    }
  }
  async listDomains() {
    try {
      const response = await this.request("/domain/listAll");
      return (response.domains || []).map((d) => d.domain);
    } catch {
      return [];
    }
  }
  async getNameServers(domain) {
    try {
      const rootDomain = this.getRootDomain(domain);
      const response = await this.request(`/dns/getNS/${rootDomain}`);
      return response.ns || [];
    } catch {
      return [];
    }
  }
  async updateNameServers(domain, nameservers) {
    try {
      const rootDomain = this.getRootDomain(domain);
      await this.request(`/dns/updateNS/${rootDomain}`, {
        ns: nameservers
      });
      return true;
    } catch {
      return false;
    }
  }
}
// src/dns/godaddy.ts
var GODADDY_API_URL = "https://api.godaddy.com";
var GODADDY_OTE_API_URL = "https://api.ote-godaddy.com";

class GoDaddyProvider {
  name = "godaddy";
  apiKey;
  apiSecret;
  baseUrl;
  constructor(apiKey, apiSecret, environment = "production") {
    this.apiKey = apiKey;
    this.apiSecret = apiSecret;
    this.baseUrl = environment === "ote" ? GODADDY_OTE_API_URL : GODADDY_API_URL;
  }
  async request(method, endpoint, body) {
    const url = `${this.baseUrl}${endpoint}`;
    const headers = {
      Authorization: `sso-key ${this.apiKey}:${this.apiSecret}`,
      "Content-Type": "application/json",
      Accept: "application/json"
    };
    const options = {
      method,
      headers
    };
    if (body) {
      options.body = JSON.stringify(body);
    }
    const response = await fetch(url, options);
    if (response.status === 204) {
      return {};
    }
    if (response.ok) {
      const text = await response.text();
      if (text) {
        return JSON.parse(text);
      }
      return {};
    }
    let errorMessage = `GoDaddy API error: ${response.status} ${response.statusText}`;
    try {
      const errorData = await response.json();
      if (errorData.message) {
        errorMessage = `GoDaddy API error: ${errorData.message}`;
      }
      if (errorData.fields) {
        errorMessage += ` - Fields: ${JSON.stringify(errorData.fields)}`;
      }
    } catch {}
    throw new Error(errorMessage);
  }
  getSubdomain(recordName, domain) {
    const cleanName = recordName.replace(/\.$/, "");
    const cleanDomain = domain.replace(/\.$/, "");
    if (cleanName === cleanDomain) {
      return "@";
    }
    if (cleanName.endsWith(`.${cleanDomain}`)) {
      return cleanName.slice(0, -(cleanDomain.length + 1));
    }
    return cleanName;
  }
  getRootDomain(domain) {
    const parts = domain.replace(/\.$/, "").split(".");
    if (parts.length >= 2) {
      return parts.slice(-2).join(".");
    }
    return domain;
  }
  toGoDaddyRecord(record, domain) {
    const rootDomain = this.getRootDomain(domain);
    const subdomain = this.getSubdomain(record.name, rootDomain);
    const gdRecord = {
      type: record.type,
      name: subdomain,
      data: record.content,
      ttl: record.ttl || 600
    };
    if (record.type === "MX" && record.priority !== undefined) {
      gdRecord.priority = record.priority;
    }
    return gdRecord;
  }
  fromGoDaddyRecord(record, domain) {
    const rootDomain = this.getRootDomain(domain);
    let name = record.name;
    if (name === "@") {
      name = rootDomain;
    } else if (!name.endsWith(rootDomain)) {
      name = `${name}.${rootDomain}`;
    }
    return {
      name,
      type: record.type,
      content: record.data,
      ttl: record.ttl,
      priority: record.priority
    };
  }
  async createRecord(domain, record) {
    try {
      const rootDomain = this.getRootDomain(domain);
      const gdRecord = this.toGoDaddyRecord(record, domain);
      await this.request("PATCH", `/v1/domains/${rootDomain}/records`, [gdRecord]);
      return {
        success: true,
        message: "Record created successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async upsertRecord(domain, record) {
    try {
      const rootDomain = this.getRootDomain(domain);
      const gdRecord = this.toGoDaddyRecord(record, domain);
      await this.request("PUT", `/v1/domains/${rootDomain}/records/${record.type}/${gdRecord.name}`, [gdRecord]);
      return {
        success: true,
        message: "Record upserted successfully"
      };
    } catch (error) {
      return this.createRecord(domain, record);
    }
  }
  async deleteRecord(domain, record) {
    try {
      const rootDomain = this.getRootDomain(domain);
      const subdomain = this.getSubdomain(record.name, rootDomain);
      const existingRecords = await this.request("GET", `/v1/domains/${rootDomain}/records/${record.type}/${subdomain}`);
      const remainingRecords = existingRecords.filter((r) => r.data !== record.content);
      if (remainingRecords.length === existingRecords.length) {
        return {
          success: false,
          message: "Record not found"
        };
      }
      if (remainingRecords.length === 0) {
        try {
          await this.request("DELETE", `/v1/domains/${rootDomain}/records/${record.type}/${subdomain}`);
        } catch {}
      } else {
        await this.request("PUT", `/v1/domains/${rootDomain}/records/${record.type}/${subdomain}`, remainingRecords);
      }
      return {
        success: true,
        message: "Record deleted successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async listRecords(domain, type) {
    try {
      const rootDomain = this.getRootDomain(domain);
      let endpoint = `/v1/domains/${rootDomain}/records`;
      if (type) {
        endpoint = `/v1/domains/${rootDomain}/records/${type}`;
      }
      const records = await this.request("GET", endpoint);
      return {
        success: true,
        records: records.map((r) => this.fromGoDaddyRecord(r, domain))
      };
    } catch (error) {
      return {
        success: false,
        records: [],
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async canManageDomain(domain) {
    try {
      const rootDomain = this.getRootDomain(domain);
      await this.request("GET", `/v1/domains/${rootDomain}`);
      return true;
    } catch {
      return false;
    }
  }
  async listDomains() {
    try {
      const response = await this.request("GET", "/v1/domains");
      return response.map((d) => d.domain);
    } catch {
      return [];
    }
  }
  async getDomainDetails(domain) {
    try {
      const rootDomain = this.getRootDomain(domain);
      const details = await this.request("GET", `/v1/domains/${rootDomain}`);
      return {
        domain: details.domain,
        status: details.status,
        nameServers: details.nameServers,
        expires: details.expires
      };
    } catch {
      return null;
    }
  }
  async updateNameServers(domain, nameservers) {
    try {
      const rootDomain = this.getRootDomain(domain);
      await this.request("PUT", `/v1/domains/${rootDomain}/records/NS`, nameservers.map((ns) => ({
        type: "NS",
        name: "@",
        data: ns,
        ttl: 3600
      })));
      return true;
    } catch {
      return false;
    }
  }
  async checkDomainAvailability(domain) {
    try {
      const result = await this.request("GET", `/v1/domains/available?domain=${encodeURIComponent(domain)}`);
      return {
        available: result.available,
        price: result.price,
        currency: result.currency
      };
    } catch {
      return { available: false };
    }
  }
}
// src/dns/cloudflare.ts
var CLOUDFLARE_API_URL = "https://api.cloudflare.com/client/v4";

class CloudflareProvider {
  name = "cloudflare";
  apiToken;
  zoneCache = new Map;
  constructor(apiToken) {
    this.apiToken = apiToken;
  }
  async request(method, endpoint, body) {
    const url = `${CLOUDFLARE_API_URL}${endpoint}`;
    const headers = {
      Authorization: `Bearer ${this.apiToken}`,
      "Content-Type": "application/json"
    };
    const options = {
      method,
      headers
    };
    if (body) {
      options.body = JSON.stringify(body);
    }
    const response = await fetch(url, options);
    const data = await response.json();
    if (!data.success) {
      const errorMessages = data.errors.map((e) => e.message).join(", ");
      throw new Error(`Cloudflare API error: ${errorMessages}`);
    }
    return data;
  }
  getRootDomain(domain) {
    const parts = domain.replace(/\.$/, "").split(".");
    if (parts.length >= 2) {
      return parts.slice(-2).join(".");
    }
    return domain;
  }
  async getZoneId(domain) {
    const rootDomain = this.getRootDomain(domain);
    const cached = this.zoneCache.get(rootDomain);
    if (cached) {
      return cached;
    }
    const response = await this.request("GET", `/zones?name=${encodeURIComponent(rootDomain)}`);
    if (!response.result || response.result.length === 0) {
      throw new Error(`Zone not found for domain: ${rootDomain}`);
    }
    const zoneId = response.result[0].id;
    this.zoneCache.set(rootDomain, zoneId);
    return zoneId;
  }
  getFullRecordName(name, domain) {
    const rootDomain = this.getRootDomain(domain);
    const cleanName = name.replace(/\.$/, "");
    if (!cleanName || cleanName === rootDomain || cleanName === "@") {
      return rootDomain;
    }
    if (cleanName.endsWith(`.${rootDomain}`)) {
      return cleanName;
    }
    return `${cleanName}.${rootDomain}`;
  }
  toCloudflareRecord(record, domain) {
    const cfRecord = {
      type: record.type,
      name: this.getFullRecordName(record.name, domain),
      content: record.content || record.value || "",
      ttl: record.ttl || 1
    };
    if (record.type === "MX" && record.priority !== undefined) {
      cfRecord.priority = record.priority;
    }
    if (record.type === "SRV") {
      if (record.priority !== undefined) {
        cfRecord.priority = record.priority;
      }
    }
    return cfRecord;
  }
  fromCloudflareRecord(record) {
    return {
      id: record.id,
      name: record.name,
      type: record.type,
      content: record.content,
      ttl: record.ttl,
      priority: record.priority
    };
  }
  async createRecord(domain, record) {
    try {
      const zoneId = await this.getZoneId(domain);
      const cfRecord = this.toCloudflareRecord(record, domain);
      const response = await this.request("POST", `/zones/${zoneId}/dns_records`, cfRecord);
      return {
        success: true,
        id: response.result.id,
        message: "Record created successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async upsertRecord(domain, record) {
    try {
      const zoneId = await this.getZoneId(domain);
      const fullName = this.getFullRecordName(record.name, domain);
      const existingResponse = await this.request("GET", `/zones/${zoneId}/dns_records?type=${record.type}&name=${encodeURIComponent(fullName)}`);
      const cfRecord = this.toCloudflareRecord(record, domain);
      if (existingResponse.result && existingResponse.result.length > 0) {
        const existingId = existingResponse.result[0].id;
        const response2 = await this.request("PUT", `/zones/${zoneId}/dns_records/${existingId}`, cfRecord);
        return {
          success: true,
          id: response2.result.id,
          message: "Record updated successfully"
        };
      }
      const response = await this.request("POST", `/zones/${zoneId}/dns_records`, cfRecord);
      return {
        success: true,
        id: response.result.id,
        message: "Record created successfully"
      };
    } catch (error) {
      return this.createRecord(domain, record);
    }
  }
  async deleteRecord(domain, record) {
    try {
      const zoneId = await this.getZoneId(domain);
      const fullName = this.getFullRecordName(record.name, domain);
      const existingResponse = await this.request("GET", `/zones/${zoneId}/dns_records?type=${record.type}&name=${encodeURIComponent(fullName)}`);
      if (!existingResponse.result || existingResponse.result.length === 0) {
        return {
          success: false,
          message: "Record not found"
        };
      }
      const matchingRecord = existingResponse.result.find((r) => r.content === record.content);
      if (!matchingRecord) {
        return {
          success: false,
          message: "Record with matching content not found"
        };
      }
      await this.request("DELETE", `/zones/${zoneId}/dns_records/${matchingRecord.id}`);
      return {
        success: true,
        message: "Record deleted successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async listRecords(domain, type) {
    try {
      const zoneId = await this.getZoneId(domain);
      let endpoint = `/zones/${zoneId}/dns_records?per_page=100`;
      if (type) {
        endpoint += `&type=${type}`;
      }
      const allRecords = [];
      let page = 1;
      let hasMore = true;
      while (hasMore) {
        const response = await this.request("GET", `${endpoint}&page=${page}`);
        allRecords.push(...response.result || []);
        if (response.result_info) {
          hasMore = page < response.result_info.total_pages;
          page++;
        } else {
          hasMore = false;
        }
      }
      return {
        success: true,
        records: allRecords.map((r) => this.fromCloudflareRecord(r))
      };
    } catch (error) {
      return {
        success: false,
        records: [],
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async canManageDomain(domain) {
    try {
      await this.getZoneId(domain);
      return true;
    } catch {
      return false;
    }
  }
  async listDomains() {
    try {
      const allZones = [];
      let page = 1;
      let hasMore = true;
      while (hasMore) {
        const response = await this.request("GET", `/zones?per_page=50&page=${page}`);
        allZones.push(...response.result || []);
        if (response.result_info) {
          hasMore = page < response.result_info.total_pages;
          page++;
        } else {
          hasMore = false;
        }
      }
      return allZones.map((z) => z.name);
    } catch {
      return [];
    }
  }
  async getZoneDetails(domain) {
    try {
      const zoneId = await this.getZoneId(domain);
      const response = await this.request("GET", `/zones/${zoneId}`);
      return {
        id: response.result.id,
        name: response.result.name,
        status: response.result.status,
        nameServers: response.result.name_servers,
        paused: response.result.paused
      };
    } catch {
      return null;
    }
  }
  async purgeCache(domain, options) {
    try {
      const zoneId = await this.getZoneId(domain);
      const body = {};
      if (options?.purgeEverything) {
        body.purge_everything = true;
      } else {
        if (options?.files)
          body.files = options.files;
        if (options?.tags)
          body.tags = options.tags;
        if (options?.hosts)
          body.hosts = options.hosts;
      }
      if (Object.keys(body).length === 0) {
        body.purge_everything = true;
      }
      await this.request("POST", `/zones/${zoneId}/purge_cache`, body);
      return true;
    } catch {
      return false;
    }
  }
  async getRecordProxyStatus(domain, record) {
    try {
      const zoneId = await this.getZoneId(domain);
      const fullName = this.getFullRecordName(record.name, domain);
      const response = await this.request("GET", `/zones/${zoneId}/dns_records?type=${record.type}&name=${encodeURIComponent(fullName)}`);
      if (response.result && response.result.length > 0) {
        const matchingRecord = response.result.find((r) => r.content === record.content);
        return matchingRecord?.proxied ?? null;
      }
      return null;
    } catch {
      return null;
    }
  }
  async setRecordProxyStatus(domain, record, proxied) {
    try {
      const zoneId = await this.getZoneId(domain);
      const fullName = this.getFullRecordName(record.name, domain);
      const response = await this.request("GET", `/zones/${zoneId}/dns_records?type=${record.type}&name=${encodeURIComponent(fullName)}`);
      if (!response.result || response.result.length === 0) {
        return false;
      }
      const matchingRecord = response.result.find((r) => r.content === record.content);
      if (!matchingRecord) {
        return false;
      }
      await this.request("PATCH", `/zones/${zoneId}/dns_records/${matchingRecord.id}`, { proxied });
      return true;
    } catch {
      return false;
    }
  }
}
// src/dns/route53-adapter.ts
class Route53Provider {
  name = "route53";
  client;
  hostedZoneCache = new Map;
  providedHostedZoneId;
  constructor(region = "us-east-1", hostedZoneId) {
    this.client = new Route53Client(region);
    this.providedHostedZoneId = hostedZoneId;
  }
  getRootDomain(domain) {
    const parts = domain.replace(/\.$/, "").split(".");
    if (parts.length >= 2) {
      return parts.slice(-2).join(".");
    }
    return domain;
  }
  async getHostedZoneId(domain) {
    if (this.providedHostedZoneId) {
      return this.providedHostedZoneId;
    }
    const rootDomain = this.getRootDomain(domain);
    const cached = this.hostedZoneCache.get(rootDomain);
    if (cached) {
      return cached;
    }
    const zone = await this.client.findHostedZoneForDomain(domain);
    if (zone) {
      const zoneId = zone.Id.replace("/hostedzone/", "");
      this.hostedZoneCache.set(rootDomain, zoneId);
      return zoneId;
    }
    return null;
  }
  normalizeName(name) {
    return name.endsWith(".") ? name : `${name}.`;
  }
  async createRecord(domain, record) {
    try {
      const hostedZoneId = await this.getHostedZoneId(domain);
      if (!hostedZoneId) {
        return {
          success: false,
          message: `No hosted zone found for domain: ${domain}`
        };
      }
      const recordName = this.normalizeName(record.name);
      let recordValue = record.content;
      if (record.type === "TXT" && !recordValue.startsWith('"')) {
        recordValue = `"${recordValue}"`;
      }
      if (record.type === "MX" && record.priority !== undefined) {
        recordValue = `${record.priority} ${recordValue}`;
      }
      const result = await this.client.changeResourceRecordSets({
        HostedZoneId: hostedZoneId,
        ChangeBatch: {
          Comment: `Created by ts-cloud DNS provider`,
          Changes: [
            {
              Action: "CREATE",
              ResourceRecordSet: {
                Name: recordName,
                Type: record.type,
                TTL: record.ttl || 300,
                ResourceRecords: [{ Value: recordValue }]
              }
            }
          ]
        }
      });
      return {
        success: true,
        id: result.ChangeInfo?.Id,
        message: "Record created successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async upsertRecord(domain, record) {
    try {
      const hostedZoneId = await this.getHostedZoneId(domain);
      if (!hostedZoneId) {
        return {
          success: false,
          message: `No hosted zone found for domain: ${domain}`
        };
      }
      const recordName = this.normalizeName(record.name);
      let recordValue = record.content;
      if (record.type === "TXT" && !recordValue.startsWith('"')) {
        recordValue = `"${recordValue}"`;
      }
      if (record.type === "MX" && record.priority !== undefined) {
        recordValue = `${record.priority} ${recordValue}`;
      }
      const result = await this.client.changeResourceRecordSets({
        HostedZoneId: hostedZoneId,
        ChangeBatch: {
          Comment: `Upserted by ts-cloud DNS provider`,
          Changes: [
            {
              Action: "UPSERT",
              ResourceRecordSet: {
                Name: recordName,
                Type: record.type,
                TTL: record.ttl || 300,
                ResourceRecords: [{ Value: recordValue }]
              }
            }
          ]
        }
      });
      return {
        success: true,
        id: result.ChangeInfo?.Id,
        message: "Record upserted successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async deleteRecord(domain, record) {
    try {
      const hostedZoneId = await this.getHostedZoneId(domain);
      if (!hostedZoneId) {
        return {
          success: false,
          message: `No hosted zone found for domain: ${domain}`
        };
      }
      const recordName = this.normalizeName(record.name);
      let recordValue = record.content;
      if (record.type === "TXT" && !recordValue.startsWith('"')) {
        recordValue = `"${recordValue}"`;
      }
      if (record.type === "MX" && record.priority !== undefined) {
        recordValue = `${record.priority} ${recordValue}`;
      }
      await this.client.changeResourceRecordSets({
        HostedZoneId: hostedZoneId,
        ChangeBatch: {
          Comment: `Deleted by ts-cloud DNS provider`,
          Changes: [
            {
              Action: "DELETE",
              ResourceRecordSet: {
                Name: recordName,
                Type: record.type,
                TTL: record.ttl || 300,
                ResourceRecords: [{ Value: recordValue }]
              }
            }
          ]
        }
      });
      return {
        success: true,
        message: "Record deleted successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async listRecords(domain, type) {
    try {
      const hostedZoneId = await this.getHostedZoneId(domain);
      if (!hostedZoneId) {
        return {
          success: false,
          records: [],
          message: `No hosted zone found for domain: ${domain}`
        };
      }
      const result = await this.client.listResourceRecordSets({
        HostedZoneId: hostedZoneId,
        StartRecordType: type
      });
      const records = [];
      for (const rs of result.ResourceRecordSets) {
        if (type && rs.Type !== type) {
          continue;
        }
        if (rs.AliasTarget) {
          continue;
        }
        for (const rr of rs.ResourceRecords || []) {
          let content = rr.Value;
          let priority;
          if (rs.Type === "MX") {
            const parts = content.split(" ");
            if (parts.length >= 2) {
              priority = Number.parseInt(parts[0], 10);
              content = parts.slice(1).join(" ");
            }
          }
          if (rs.Type === "TXT" && content.startsWith('"') && content.endsWith('"')) {
            content = content.slice(1, -1);
          }
          records.push({
            name: rs.Name.replace(/\.$/, ""),
            type: rs.Type,
            content,
            ttl: rs.TTL,
            priority
          });
        }
      }
      return {
        success: true,
        records
      };
    } catch (error) {
      return {
        success: false,
        records: [],
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async canManageDomain(domain) {
    const hostedZoneId = await this.getHostedZoneId(domain);
    return hostedZoneId !== null;
  }
  async listDomains() {
    try {
      const result = await this.client.listHostedZones();
      return result.HostedZones.map((z) => z.Name.replace(/\.$/, ""));
    } catch {
      return [];
    }
  }
  getRoute53Client() {
    return this.client;
  }
  async createAliasRecord(params) {
    try {
      const hostedZoneId = await this.getHostedZoneId(params.domain);
      if (!hostedZoneId) {
        return {
          success: false,
          message: `No hosted zone found for domain: ${params.domain}`
        };
      }
      const result = await this.client.createAliasRecord({
        HostedZoneId: hostedZoneId,
        Name: this.normalizeName(params.name),
        TargetHostedZoneId: params.targetHostedZoneId,
        TargetDNSName: params.targetDnsName,
        EvaluateTargetHealth: params.evaluateTargetHealth,
        Type: params.type
      });
      return {
        success: true,
        id: result.ChangeInfo?.Id,
        message: "Alias record created successfully"
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
  async createCloudFrontAlias(params) {
    return this.createAliasRecord({
      domain: params.domain,
      name: params.name,
      targetHostedZoneId: Route53Client.CloudFrontHostedZoneId,
      targetDnsName: params.cloudFrontDomainName,
      evaluateTargetHealth: false
    });
  }
  async createAlbAlias(params) {
    const hostedZoneId = Route53Client.ALBHostedZoneIds[params.region];
    if (!hostedZoneId) {
      return {
        success: false,
        message: `Unknown region for ALB: ${params.region}`
      };
    }
    return this.createAliasRecord({
      domain: params.domain,
      name: params.name,
      targetHostedZoneId: hostedZoneId,
      targetDnsName: params.albDnsName,
      evaluateTargetHealth: true
    });
  }
}
// src/aws/acm.ts
class ACMClient {
  client;
  region;
  constructor(region = "us-east-1") {
    this.client = new AWSClient;
    this.region = region;
  }
  async requestCertificate(params) {
    const requestBody = {
      DomainName: params.DomainName,
      ValidationMethod: params.ValidationMethod || "DNS"
    };
    if (params.SubjectAlternativeNames) {
      requestBody.SubjectAlternativeNames = params.SubjectAlternativeNames;
    }
    const result = await this.client.request({
      service: "acm",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "content-type": "application/x-amz-json-1.1",
        "x-amz-target": "CertificateManager.RequestCertificate"
      },
      body: JSON.stringify(requestBody)
    });
    return {
      CertificateArn: result.CertificateArn || ""
    };
  }
  async describeCertificate(params) {
    const result = await this.client.request({
      service: "acm",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "content-type": "application/x-amz-json-1.1",
        "x-amz-target": "CertificateManager.DescribeCertificate"
      },
      body: JSON.stringify({
        CertificateArn: params.CertificateArn
      })
    });
    const cert = result.Certificate || {};
    return {
      CertificateArn: cert.CertificateArn || "",
      DomainName: cert.DomainName || "",
      SubjectAlternativeNames: cert.SubjectAlternativeNames,
      Status: cert.Status || "PENDING_VALIDATION",
      Type: cert.Type,
      DomainValidationOptions: cert.DomainValidationOptions?.map((opt) => ({
        DomainName: opt.DomainName,
        ValidationDomain: opt.ValidationDomain,
        ValidationStatus: opt.ValidationStatus,
        ResourceRecord: opt.ResourceRecord ? {
          Name: opt.ResourceRecord.Name,
          Type: opt.ResourceRecord.Type,
          Value: opt.ResourceRecord.Value
        } : undefined,
        ValidationMethod: opt.ValidationMethod
      })),
      CreatedAt: cert.CreatedAt,
      IssuedAt: cert.IssuedAt,
      NotBefore: cert.NotBefore,
      NotAfter: cert.NotAfter
    };
  }
  async listCertificates(params) {
    const requestBody = {};
    if (params?.CertificateStatuses) {
      requestBody.CertificateStatuses = params.CertificateStatuses;
    }
    if (params?.MaxItems) {
      requestBody.MaxItems = params.MaxItems;
    }
    if (params?.NextToken) {
      requestBody.NextToken = params.NextToken;
    }
    const result = await this.client.request({
      service: "acm",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "content-type": "application/x-amz-json-1.1",
        "x-amz-target": "CertificateManager.ListCertificates"
      },
      body: JSON.stringify(requestBody)
    });
    return {
      CertificateSummaryList: (result.CertificateSummaryList || []).map((cert) => ({
        CertificateArn: cert.CertificateArn,
        DomainName: cert.DomainName
      })),
      NextToken: result.NextToken
    };
  }
  async deleteCertificate(params) {
    await this.client.request({
      service: "acm",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "content-type": "application/x-amz-json-1.1",
        "x-amz-target": "CertificateManager.DeleteCertificate"
      },
      body: JSON.stringify({
        CertificateArn: params.CertificateArn
      })
    });
  }
  async listTagsForCertificate(params) {
    const result = await this.client.request({
      service: "acm",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "content-type": "application/x-amz-json-1.1",
        "x-amz-target": "CertificateManager.ListTagsForCertificate"
      },
      body: JSON.stringify({
        CertificateArn: params.CertificateArn
      })
    });
    return {
      Tags: result.Tags || []
    };
  }
  async addTagsToCertificate(params) {
    await this.client.request({
      service: "acm",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "content-type": "application/x-amz-json-1.1",
        "x-amz-target": "CertificateManager.AddTagsToCertificate"
      },
      body: JSON.stringify({
        CertificateArn: params.CertificateArn,
        Tags: params.Tags
      })
    });
  }
  async resendValidationEmail(params) {
    await this.client.request({
      service: "acm",
      region: this.region,
      method: "POST",
      path: "/",
      headers: {
        "content-type": "application/x-amz-json-1.1",
        "x-amz-target": "CertificateManager.ResendValidationEmail"
      },
      body: JSON.stringify({
        CertificateArn: params.CertificateArn,
        Domain: params.Domain,
        ValidationDomain: params.ValidationDomain
      })
    });
  }
  async findCertificateByDomain(domainName) {
    const result = await this.listCertificates({
      CertificateStatuses: ["ISSUED"]
    });
    const summary = result.CertificateSummaryList.find((c) => c.DomainName === domainName || c.DomainName === `*.${domainName.split(".").slice(1).join(".")}`);
    if (!summary) {
      return null;
    }
    return this.describeCertificate({ CertificateArn: summary.CertificateArn });
  }
  async waitForCertificateValidation(certificateArn, maxAttempts = 60, delayMs = 30000) {
    for (let i = 0;i < maxAttempts; i++) {
      const cert = await this.describeCertificate({ CertificateArn: certificateArn });
      if (cert.Status === "ISSUED") {
        return cert;
      }
      if (cert.Status === "FAILED" || cert.Status === "VALIDATION_TIMED_OUT") {
        return null;
      }
      await new Promise((resolve) => setTimeout(resolve, delayMs));
    }
    return null;
  }
  async getDnsValidationRecords(certificateArn) {
    const cert = await this.describeCertificate({ CertificateArn: certificateArn });
    if (!cert.DomainValidationOptions) {
      return [];
    }
    return cert.DomainValidationOptions.filter((opt) => opt.ResourceRecord && opt.ValidationMethod === "DNS").map((opt) => ({
      domainName: opt.DomainName,
      recordName: opt.ResourceRecord.Name,
      recordType: opt.ResourceRecord.Type,
      recordValue: opt.ResourceRecord.Value
    }));
  }
  async requestCertificateWithSans(params) {
    const sans = new Set;
    sans.add(params.DomainName);
    if (params.IncludeWww !== false) {
      sans.add(`www.${params.DomainName}`);
    }
    if (params.IncludeWildcard) {
      sans.add(`*.${params.DomainName}`);
    }
    if (params.AdditionalSans) {
      for (const san of params.AdditionalSans) {
        sans.add(san);
      }
    }
    return this.requestCertificate({
      DomainName: params.DomainName,
      SubjectAlternativeNames: Array.from(sans),
      ValidationMethod: "DNS"
    });
  }
  async isCertificateValidForDomain(certificateArn, domainName) {
    const cert = await this.describeCertificate({ CertificateArn: certificateArn });
    if (cert.Status !== "ISSUED") {
      return false;
    }
    if (cert.DomainName === domainName) {
      return true;
    }
    if (cert.DomainName?.startsWith("*.")) {
      const baseDomain = cert.DomainName.slice(2);
      const domainParts = domainName.split(".");
      const baseParts = baseDomain.split(".");
      if (domainParts.slice(-baseParts.length).join(".") === baseDomain) {
        return true;
      }
    }
    if (cert.SubjectAlternativeNames) {
      for (const san of cert.SubjectAlternativeNames) {
        if (san === domainName) {
          return true;
        }
        if (san.startsWith("*.")) {
          const baseDomain = san.slice(2);
          const domainParts = domainName.split(".");
          const baseParts = baseDomain.split(".");
          if (domainParts.slice(-baseParts.length).join(".") === baseDomain) {
            return true;
          }
        }
      }
    }
    return false;
  }
}

class ACMDnsValidator {
  acm;
  route53;
  dnsProvider;
  constructor(region = "us-east-1", dnsProviderConfig) {
    this.acm = new ACMClient(region);
    this.route53 = new Route53Client;
    if (dnsProviderConfig && dnsProviderConfig.provider !== "route53") {
      this.dnsProvider = createDnsProvider(dnsProviderConfig);
    }
  }
  async requestAndValidate(params) {
    const {
      domainName,
      hostedZoneId,
      subjectAlternativeNames = [],
      waitForValidation = false,
      maxWaitMinutes = 30
    } = params;
    if (!this.dnsProvider && !hostedZoneId) {
      throw new Error("Either hostedZoneId or external DNS provider configuration is required");
    }
    const { CertificateArn } = await this.acm.requestCertificate({
      DomainName: domainName,
      SubjectAlternativeNames: subjectAlternativeNames.length > 0 ? [domainName, ...subjectAlternativeNames] : undefined,
      ValidationMethod: "DNS"
    });
    await this.waitForValidationOptions(CertificateArn);
    const validationRecords = await this.acm.getDnsValidationRecords(CertificateArn);
    if (this.dnsProvider) {
      for (const record of validationRecords) {
        const result = await this.dnsProvider.upsertRecord(domainName, {
          name: record.recordName,
          type: record.recordType,
          content: record.recordValue,
          ttl: 300
        });
        if (!result.success) {
          console.warn(`Failed to create validation record for ${record.domainName}: ${result.message}`);
        }
      }
    } else if (hostedZoneId) {
      for (const record of validationRecords) {
        await this.route53.changeResourceRecordSets({
          HostedZoneId: hostedZoneId,
          ChangeBatch: {
            Comment: `ACM DNS validation for ${record.domainName}`,
            Changes: [
              {
                Action: "UPSERT",
                ResourceRecordSet: {
                  Name: record.recordName,
                  Type: record.recordType,
                  TTL: 300,
                  ResourceRecords: [{ Value: record.recordValue }]
                }
              }
            ]
          }
        });
      }
    }
    if (waitForValidation) {
      const cert = await this.acm.waitForCertificateValidation(CertificateArn, maxWaitMinutes * 2, 30000);
      if (!cert) {
        throw new Error(`Certificate validation timed out after ${maxWaitMinutes} minutes`);
      }
    }
    return {
      certificateArn: CertificateArn,
      validationRecords
    };
  }
  async waitForValidationOptions(certificateArn, maxAttempts = 30) {
    for (let i = 0;i < maxAttempts; i++) {
      const cert = await this.acm.describeCertificate({ CertificateArn: certificateArn });
      if (cert.DomainValidationOptions && cert.DomainValidationOptions.length > 0 && cert.DomainValidationOptions[0].ResourceRecord) {
        return;
      }
      await new Promise((resolve) => setTimeout(resolve, 2000));
    }
    throw new Error("Timeout waiting for DNS validation options");
  }
  async createValidationRecords(params) {
    const { certificateArn, hostedZoneId, domain } = params;
    if (!this.dnsProvider && !hostedZoneId) {
      throw new Error("Either hostedZoneId or external DNS provider configuration is required");
    }
    const validationRecords = await this.acm.getDnsValidationRecords(certificateArn);
    const results = [];
    if (this.dnsProvider) {
      const targetDomain = domain || validationRecords[0]?.domainName;
      for (const record of validationRecords) {
        const result = await this.dnsProvider.upsertRecord(targetDomain, {
          name: record.recordName,
          type: record.recordType,
          content: record.recordValue,
          ttl: 300
        });
        results.push({
          ...record,
          changeId: result.success ? result.id : undefined
        });
      }
    } else if (hostedZoneId) {
      for (const record of validationRecords) {
        const result = await this.route53.changeResourceRecordSets({
          HostedZoneId: hostedZoneId,
          ChangeBatch: {
            Comment: `ACM DNS validation for ${record.domainName}`,
            Changes: [
              {
                Action: "UPSERT",
                ResourceRecordSet: {
                  Name: record.recordName,
                  Type: record.recordType,
                  TTL: 300,
                  ResourceRecords: [{ Value: record.recordValue }]
                }
              }
            ]
          }
        });
        results.push({
          ...record,
          changeId: result.ChangeInfo?.Id
        });
      }
    }
    return results;
  }
  async deleteValidationRecords(params) {
    const { certificateArn, hostedZoneId, domain } = params;
    const validationRecords = await this.acm.getDnsValidationRecords(certificateArn);
    if (this.dnsProvider) {
      const targetDomain = domain || validationRecords[0]?.domainName;
      for (const record of validationRecords) {
        try {
          await this.dnsProvider.deleteRecord(targetDomain, {
            name: record.recordName,
            type: record.recordType,
            content: record.recordValue
          });
        } catch {}
      }
    } else if (hostedZoneId) {
      for (const record of validationRecords) {
        try {
          await this.route53.changeResourceRecordSets({
            HostedZoneId: hostedZoneId,
            ChangeBatch: {
              Comment: `Cleanup ACM DNS validation for ${record.domainName}`,
              Changes: [
                {
                  Action: "DELETE",
                  ResourceRecordSet: {
                    Name: record.recordName,
                    Type: record.recordType,
                    TTL: 300,
                    ResourceRecords: [{ Value: record.recordValue }]
                  }
                }
              ]
            }
          });
        } catch {}
      }
    }
  }
  async findOrCreateCertificate(params) {
    const { domainName, hostedZoneId, subjectAlternativeNames, waitForValidation = true } = params;
    if (!this.dnsProvider && !hostedZoneId) {
      throw new Error("Either hostedZoneId or external DNS provider configuration is required");
    }
    const existing = await this.acm.findCertificateByDomain(domainName);
    if (existing && existing.Status === "ISSUED") {
      return {
        certificateArn: existing.CertificateArn,
        isNew: false
      };
    }
    const { certificateArn } = await this.requestAndValidate({
      domainName,
      hostedZoneId,
      subjectAlternativeNames,
      waitForValidation
    });
    return {
      certificateArn,
      isNew: true
    };
  }
  hasExternalDnsProvider() {
    return this.dnsProvider !== undefined;
  }
  getDnsProviderName() {
    return this.dnsProvider?.name || "route53";
  }
}

// src/dns/validator.ts
class UnifiedDnsValidator {
  acm;
  dnsProvider;
  constructor(dnsProvider, acmRegion = "us-east-1") {
    this.acm = new ACMClient(acmRegion);
    if ("provider" in dnsProvider) {
      this.dnsProvider = createDnsProvider(dnsProvider);
    } else {
      this.dnsProvider = dnsProvider;
    }
  }
  getProvider() {
    return this.dnsProvider;
  }
  async requestAndValidate(params) {
    const { domainName, subjectAlternativeNames = [], waitForValidation = false, maxWaitMinutes = 30 } = params;
    const { CertificateArn } = await this.acm.requestCertificate({
      DomainName: domainName,
      SubjectAlternativeNames: subjectAlternativeNames.length > 0 ? [domainName, ...subjectAlternativeNames] : undefined,
      ValidationMethod: "DNS"
    });
    await this.waitForValidationOptions(CertificateArn);
    const validationRecords = await this.acm.getDnsValidationRecords(CertificateArn);
    for (const record of validationRecords) {
      const result = await this.dnsProvider.upsertRecord(domainName, {
        name: record.recordName,
        type: record.recordType,
        content: record.recordValue,
        ttl: 300
      });
      if (!result.success) {
        console.warn(`Failed to create validation record for ${record.domainName}: ${result.message}`);
      }
    }
    let status = "pending";
    if (waitForValidation) {
      const cert = await this.acm.waitForCertificateValidation(CertificateArn, maxWaitMinutes * 2, 30000);
      status = cert?.Status === "ISSUED" ? "issued" : "failed";
    }
    return {
      certificateArn: CertificateArn,
      validationRecords: validationRecords.map((r) => ({
        domainName: r.domainName,
        recordName: r.recordName,
        recordType: r.recordType,
        recordValue: r.recordValue
      })),
      isNew: true,
      status
    };
  }
  async createValidationRecords(params) {
    const { certificateArn, domain } = params;
    const errors = [];
    const validationRecords = await this.acm.getDnsValidationRecords(certificateArn);
    for (const record of validationRecords) {
      const result = await this.dnsProvider.upsertRecord(domain, {
        name: record.recordName,
        type: record.recordType,
        content: record.recordValue,
        ttl: 300
      });
      if (!result.success) {
        errors.push(`Failed to create record for ${record.domainName}: ${result.message}`);
      }
    }
    return {
      success: errors.length === 0,
      records: validationRecords.map((r) => ({
        domainName: r.domainName,
        recordName: r.recordName,
        recordType: r.recordType,
        recordValue: r.recordValue
      })),
      errors
    };
  }
  async deleteValidationRecords(params) {
    const { certificateArn, domain } = params;
    const errors = [];
    const validationRecords = await this.acm.getDnsValidationRecords(certificateArn);
    for (const record of validationRecords) {
      const result = await this.dnsProvider.deleteRecord(domain, {
        name: record.recordName,
        type: record.recordType,
        content: record.recordValue
      });
      if (!result.success) {
        errors.push(`Failed to delete record for ${record.domainName}: ${result.message}`);
      }
    }
    return {
      success: errors.length === 0,
      errors
    };
  }
  async findOrCreateCertificate(params) {
    const { domainName, subjectAlternativeNames = [], waitForValidation = true, maxWaitMinutes } = params;
    const existing = await this.acm.findCertificateByDomain(domainName);
    if (existing && existing.Status === "ISSUED") {
      const existingSans = existing.SubjectAlternativeNames || [existing.DomainName];
      const hasWildcard = existingSans.some((san) => san === `*.${domainName}`);
      const allSansCovered = subjectAlternativeNames.every((san) => existingSans.includes(san) || hasWildcard);
      if (allSansCovered) {
        return {
          certificateArn: existing.CertificateArn,
          validationRecords: [],
          isNew: false,
          status: "issued"
        };
      }
      console.log(`Existing certificate doesn't cover all required SANs, requesting new certificate...`);
    }
    return this.requestAndValidate({
      domainName,
      subjectAlternativeNames,
      waitForValidation,
      maxWaitMinutes
    });
  }
  async requestCertificateWithCommonSans(params) {
    const {
      domainName,
      includeWww = true,
      includeWildcard = false,
      additionalSans = [],
      waitForValidation = false
    } = params;
    const sans = [];
    if (includeWww) {
      sans.push(`www.${domainName}`);
    }
    if (includeWildcard) {
      sans.push(`*.${domainName}`);
    }
    sans.push(...additionalSans);
    return this.requestAndValidate({
      domainName,
      subjectAlternativeNames: sans,
      waitForValidation
    });
  }
  async waitForValidationOptions(certificateArn, maxAttempts = 30) {
    for (let i = 0;i < maxAttempts; i++) {
      const cert = await this.acm.describeCertificate({ CertificateArn: certificateArn });
      if (cert.DomainValidationOptions && cert.DomainValidationOptions.length > 0 && cert.DomainValidationOptions[0].ResourceRecord) {
        return;
      }
      await new Promise((resolve) => setTimeout(resolve, 2000));
    }
    throw new Error("Timeout waiting for DNS validation options");
  }
  async getCertificateStatus(certificateArn) {
    const cert = await this.acm.describeCertificate({ CertificateArn: certificateArn });
    return {
      status: cert.Status,
      domainValidations: (cert.DomainValidationOptions || []).map((opt) => ({
        domain: opt.DomainName,
        status: opt.ValidationStatus || "UNKNOWN"
      }))
    };
  }
}
function createPorkbunValidator(apiKey, secretKey, acmRegion) {
  return new UnifiedDnsValidator({ provider: "porkbun", apiKey, secretKey }, acmRegion);
}
function createGoDaddyValidator(apiKey, apiSecret, acmRegion, environment) {
  return new UnifiedDnsValidator({ provider: "godaddy", apiKey, apiSecret, environment }, acmRegion);
}
function createRoute53Validator(region, hostedZoneId, acmRegion) {
  return new UnifiedDnsValidator({ provider: "route53", region, hostedZoneId }, acmRegion || region);
}
// src/dns/index.ts
function createDnsProvider(config) {
  switch (config.provider) {
    case "route53":
      return new Route53Provider(config.region, config.hostedZoneId);
    case "porkbun":
      return new PorkbunProvider(config.apiKey, config.secretKey);
    case "godaddy":
      return new GoDaddyProvider(config.apiKey, config.apiSecret, config.environment);
    case "cloudflare":
      return new CloudflareProvider(config.apiToken);
    default:
      throw new Error(`Unknown DNS provider: ${config.provider}`);
  }
}
async function detectDnsProvider(domain, configs) {
  for (const config of configs) {
    const provider = createDnsProvider(config);
    if (await provider.canManageDomain(domain)) {
      return provider;
    }
  }
  return null;
}

class DnsProviderFactory {
  providers = new Map;
  configs = [];
  addConfig(config) {
    this.configs.push(config);
    return this;
  }
  addRoute53(region, hostedZoneId) {
    this.configs.push({
      provider: "route53",
      region,
      hostedZoneId
    });
    return this;
  }
  addPorkbun(apiKey, secretKey) {
    this.configs.push({
      provider: "porkbun",
      apiKey,
      secretKey
    });
    return this;
  }
  addGoDaddy(apiKey, apiSecret, environment) {
    this.configs.push({
      provider: "godaddy",
      apiKey,
      apiSecret,
      environment
    });
    return this;
  }
  addCloudflare(apiToken) {
    this.configs.push({
      provider: "cloudflare",
      apiToken
    });
    return this;
  }
  loadFromEnv() {
    if (process.env.AWS_ACCESS_KEY_ID || process.env.AWS_REGION) {
      this.addRoute53(process.env.AWS_REGION);
    }
    const porkbunApiKey = process.env.PORKBUN_API_KEY;
    const porkbunSecretKey = process.env.PORKBUN_SECRET_KEY;
    if (porkbunApiKey && porkbunSecretKey) {
      this.addPorkbun(porkbunApiKey, porkbunSecretKey);
    }
    const godaddyApiKey = process.env.GODADDY_API_KEY;
    const godaddyApiSecret = process.env.GODADDY_API_SECRET;
    if (godaddyApiKey && godaddyApiSecret) {
      const env = process.env.GODADDY_ENVIRONMENT;
      this.addGoDaddy(godaddyApiKey, godaddyApiSecret, env);
    }
    const cloudflareApiToken = process.env.CLOUDFLARE_API_TOKEN;
    if (cloudflareApiToken) {
      this.addCloudflare(cloudflareApiToken);
    }
    return this;
  }
  getProvider(name) {
    const cached = this.providers.get(name);
    if (cached) {
      return cached;
    }
    const config = this.configs.find((c) => c.provider === name);
    if (!config) {
      return null;
    }
    const provider = createDnsProvider(config);
    this.providers.set(name, provider);
    return provider;
  }
  async getProviderForDomain(domain) {
    for (const config of this.configs) {
      const provider = createDnsProvider(config);
      if (await provider.canManageDomain(domain)) {
        return provider;
      }
    }
    return null;
  }
  getAllProviders() {
    return this.configs.map((config) => createDnsProvider(config));
  }
}
var dnsProviders = new DnsProviderFactory;

export { PorkbunProvider, GoDaddyProvider, CloudflareProvider, Route53Provider, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, ACMClient, ACMDnsValidator };
