@hasna/domains 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +140 -63
  2. package/dist/cli/commands/config.d.ts.map +1 -1
  3. package/dist/cli/commands/domain.d.ts.map +1 -1
  4. package/dist/cli/commands/provider.d.ts.map +1 -1
  5. package/dist/cli/commands/providers.d.ts.map +1 -1
  6. package/dist/cli/commands/storage.d.ts +3 -0
  7. package/dist/cli/commands/storage.d.ts.map +1 -0
  8. package/dist/cli/index.js +2099 -550
  9. package/dist/db/domain-records.d.ts +2 -2
  10. package/dist/db/domain-records.d.ts.map +1 -1
  11. package/dist/db/pg-migrations.d.ts +1 -1
  12. package/dist/db/storage-sync.d.ts +55 -0
  13. package/dist/db/storage-sync.d.ts.map +1 -0
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +863 -157
  17. package/dist/lib/brandsight.d.ts +46 -2
  18. package/dist/lib/brandsight.d.ts.map +1 -1
  19. package/dist/lib/capability.d.ts +5 -3
  20. package/dist/lib/capability.d.ts.map +1 -1
  21. package/dist/lib/cloudflare-auth.d.ts.map +1 -1
  22. package/dist/lib/cloudflare.d.ts +2 -2
  23. package/dist/lib/cloudflare.d.ts.map +1 -1
  24. package/dist/lib/creds-check.d.ts.map +1 -1
  25. package/dist/lib/env-aliases.d.ts +43 -0
  26. package/dist/lib/env-aliases.d.ts.map +1 -0
  27. package/dist/lib/godaddy.d.ts +4 -4
  28. package/dist/lib/namecheap.d.ts +13 -0
  29. package/dist/lib/namecheap.d.ts.map +1 -1
  30. package/dist/lib/registrar.d.ts +49 -5
  31. package/dist/lib/registrar.d.ts.map +1 -1
  32. package/dist/lib/route53.d.ts +2 -0
  33. package/dist/lib/route53.d.ts.map +1 -1
  34. package/dist/lib/sedo.d.ts +7 -0
  35. package/dist/lib/sedo.d.ts.map +1 -1
  36. package/dist/mcp/index.d.ts.map +1 -1
  37. package/dist/mcp/index.js +14266 -15760
  38. package/dist/mcp/storage-tools.d.ts +3 -0
  39. package/dist/mcp/storage-tools.d.ts.map +1 -0
  40. package/dist/storage.d.ts +5 -0
  41. package/dist/storage.d.ts.map +1 -0
  42. package/dist/storage.js +5703 -0
  43. package/package.json +9 -3
  44. package/dist/cli/commands/cloud.d.ts +0 -3
  45. package/dist/cli/commands/cloud.d.ts.map +0 -1
  46. package/dist/db/cloud-sync.d.ts +0 -33
  47. package/dist/db/cloud-sync.d.ts.map +0 -1
  48. package/dist/mcp/cloud-tools.d.ts +0 -3
  49. package/dist/mcp/cloud-tools.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -28633,8 +28633,8 @@ class PgAdapterAsync {
28633
28633
  await this.pool.end();
28634
28634
  }
28635
28635
  }
28636
- // src/db/cloud-sync.ts
28637
- var CLOUD_TABLES = [
28636
+ // src/db/storage-sync.ts
28637
+ var STORAGE_TABLES = [
28638
28638
  "domains",
28639
28639
  "dns_records",
28640
28640
  "alerts",
@@ -28644,6 +28644,7 @@ var CLOUD_TABLES = [
28644
28644
  "domain_history",
28645
28645
  "domain_reputation"
28646
28646
  ];
28647
+ var DOMAINS_STORAGE_TABLES = STORAGE_TABLES;
28647
28648
  var PRIMARY_KEYS = {
28648
28649
  domains: ["id"],
28649
28650
  dns_records: ["id"],
@@ -28654,25 +28655,57 @@ var PRIMARY_KEYS = {
28654
28655
  domain_history: ["id"],
28655
28656
  domain_reputation: ["id"]
28656
28657
  };
28657
- function getCloudDatabaseUrl() {
28658
- return process.env["HASNA_DOMAINS_CLOUD_DATABASE_URL"] ?? process.env["OPEN_DOMAINS_CLOUD_DATABASE_URL"] ?? process.env["DOMAINS_CLOUD_DATABASE_URL"] ?? null;
28658
+ var DOMAINS_STORAGE_ENV = "HASNA_DOMAINS_DATABASE_URL";
28659
+ var DOMAINS_STORAGE_FALLBACK_ENV = "DOMAINS_DATABASE_URL";
28660
+ var DOMAINS_STORAGE_MODE_ENV = "HASNA_DOMAINS_STORAGE_MODE";
28661
+ var DOMAINS_STORAGE_MODE_FALLBACK_ENV = "DOMAINS_STORAGE_MODE";
28662
+ var STORAGE_DATABASE_ENV = [DOMAINS_STORAGE_ENV, DOMAINS_STORAGE_FALLBACK_ENV];
28663
+ var STORAGE_MODE_ENV = [DOMAINS_STORAGE_MODE_ENV, DOMAINS_STORAGE_MODE_FALLBACK_ENV];
28664
+ function firstEnv(names) {
28665
+ for (const name of names) {
28666
+ const value = process.env[name];
28667
+ if (value)
28668
+ return value;
28669
+ }
28670
+ return null;
28671
+ }
28672
+ function normalizeStorageMode(value) {
28673
+ if (!value)
28674
+ return null;
28675
+ const normalized = value.trim().toLowerCase();
28676
+ if (normalized === "local" || normalized === "remote" || normalized === "hybrid")
28677
+ return normalized;
28678
+ return null;
28679
+ }
28680
+ function getStorageDatabaseUrl() {
28681
+ return firstEnv(STORAGE_DATABASE_ENV);
28682
+ }
28683
+ function getStorageDatabaseEnvName() {
28684
+ for (const name of STORAGE_DATABASE_ENV) {
28685
+ if (process.env[name])
28686
+ return name;
28687
+ }
28688
+ return null;
28689
+ }
28690
+ function getStorageMode() {
28691
+ return normalizeStorageMode(firstEnv(STORAGE_MODE_ENV)) ?? (getStorageDatabaseUrl() ? "remote" : "local");
28659
28692
  }
28660
- async function getCloudPg() {
28661
- const url = getCloudDatabaseUrl();
28693
+ async function getStoragePg() {
28694
+ const url = getStorageDatabaseUrl();
28662
28695
  if (!url) {
28663
- throw new Error("Missing HASNA_DOMAINS_CLOUD_DATABASE_URL, OPEN_DOMAINS_CLOUD_DATABASE_URL, or DOMAINS_CLOUD_DATABASE_URL");
28696
+ throw new Error("Missing HASNA_DOMAINS_DATABASE_URL or DOMAINS_DATABASE_URL");
28664
28697
  }
28665
28698
  return new PgAdapterAsync(url);
28666
28699
  }
28667
- async function runCloudMigrations(remote) {
28700
+ async function runStorageMigrations(remote) {
28668
28701
  for (const sql of PG_MIGRATIONS)
28669
28702
  await remote.run(sql);
28670
28703
  }
28671
- async function cloudPush(options) {
28672
- const remote = await getCloudPg();
28704
+ async function storagePush(options) {
28705
+ const remote = await getStoragePg();
28673
28706
  const db = getDatabase();
28674
28707
  try {
28675
- await runCloudMigrations(remote);
28708
+ await runStorageMigrations(remote);
28676
28709
  const results = [];
28677
28710
  for (const table of resolveTables(options?.tables))
28678
28711
  results.push(await pushTable(db, remote, table));
@@ -28682,11 +28715,11 @@ async function cloudPush(options) {
28682
28715
  await remote.close();
28683
28716
  }
28684
28717
  }
28685
- async function cloudPull(options) {
28686
- const remote = await getCloudPg();
28718
+ async function storagePull(options) {
28719
+ const remote = await getStoragePg();
28687
28720
  const db = getDatabase();
28688
28721
  try {
28689
- await runCloudMigrations(remote);
28722
+ await runStorageMigrations(remote);
28690
28723
  const results = [];
28691
28724
  for (const table of resolveTables(options?.tables))
28692
28725
  results.push(await pullTable(remote, db, table));
@@ -28696,20 +28729,33 @@ async function cloudPull(options) {
28696
28729
  await remote.close();
28697
28730
  }
28698
28731
  }
28699
- async function cloudSync(options) {
28700
- const pull = await cloudPull(options);
28701
- const push = await cloudPush(options);
28732
+ async function storageSync(options) {
28733
+ const pull = await storagePull(options);
28734
+ const push = await storagePush(options);
28702
28735
  return { pull, push };
28703
28736
  }
28704
- function getSyncMetaAll() {
28737
+ function getStorageSyncMetaAll() {
28705
28738
  const db = getDatabase();
28706
28739
  ensureSyncMetaTable(db);
28707
28740
  return db.query("SELECT table_name, last_synced_at, direction FROM _domains_sync_meta ORDER BY table_name, direction").all();
28708
28741
  }
28742
+ function getStorageStatus() {
28743
+ return {
28744
+ configured: Boolean(getStorageDatabaseUrl()),
28745
+ env: STORAGE_DATABASE_ENV,
28746
+ mode: getStorageMode(),
28747
+ service: "domains",
28748
+ tables: STORAGE_TABLES,
28749
+ sync: getStorageSyncMetaAll()
28750
+ };
28751
+ }
28752
+ function getSyncMetaAll() {
28753
+ return getStorageSyncMetaAll();
28754
+ }
28709
28755
  function resolveTables(tables) {
28710
28756
  if (!tables || tables.length === 0)
28711
- return [...CLOUD_TABLES];
28712
- const allowed = new Set(CLOUD_TABLES);
28757
+ return [...STORAGE_TABLES];
28758
+ const allowed = new Set(STORAGE_TABLES);
28713
28759
  const requested = tables.map((table) => table.trim()).filter(Boolean);
28714
28760
  const invalid = requested.filter((table) => !allowed.has(table));
28715
28761
  if (invalid.length > 0)
@@ -28943,6 +28989,61 @@ async function renewDomain(domain, years = 1, config) {
28943
28989
  chargedAmount: chargedAmount || undefined
28944
28990
  };
28945
28991
  }
28992
+ function namecheapContactParams(contact) {
28993
+ const organization = contact.organization_name || "NA";
28994
+ const base = {
28995
+ FirstName: contact.first_name,
28996
+ LastName: contact.last_name,
28997
+ OrganizationName: organization,
28998
+ Address1: contact.address_line_1,
28999
+ City: contact.city,
29000
+ StateProvince: contact.state,
29001
+ PostalCode: contact.zip_code,
29002
+ Country: contact.country_code,
29003
+ Phone: contact.phone,
29004
+ EmailAddress: contact.email
29005
+ };
29006
+ const params = {};
29007
+ for (const prefix of ["Registrant", "Tech", "Admin", "AuxBilling"]) {
29008
+ for (const [key, value] of Object.entries(base)) {
29009
+ params[prefix + key] = value;
29010
+ }
29011
+ }
29012
+ return params;
29013
+ }
29014
+ async function registerDomain(domain, contact, options = {}, config) {
29015
+ const cfg = config || getConfig();
29016
+ const params = {
29017
+ DomainName: domain,
29018
+ Years: String(options.years ?? 1),
29019
+ AddFreeWhoisguard: options.whoisGuard === false ? "no" : "yes",
29020
+ WGEnabled: options.whoisGuard === false ? "no" : "yes",
29021
+ ...namecheapContactParams(contact)
29022
+ };
29023
+ if (options.premiumPrice !== undefined) {
29024
+ params.IsPremiumDomain = "true";
29025
+ params.PremiumPrice = String(options.premiumPrice);
29026
+ }
29027
+ const xml = await apiRequest(cfg, "namecheap.domains.create", params);
29028
+ return {
29029
+ domain,
29030
+ success: xml.includes('Status="OK"') || xml.includes('Registered="true"'),
29031
+ orderId: parseXmlValue(xml, "OrderId") || undefined,
29032
+ chargedAmount: parseXmlValue(xml, "ChargedAmount") || undefined
29033
+ };
29034
+ }
29035
+ async function updateNameservers(domain, nameservers, config) {
29036
+ if (nameservers.length === 0)
29037
+ throw new Error("updateNameservers requires at least one nameserver");
29038
+ const cfg = config || getConfig();
29039
+ const { sld, tld } = splitDomain(domain);
29040
+ const xml = await apiRequest(cfg, "namecheap.domains.dns.setCustom", {
29041
+ SLD: sld,
29042
+ TLD: tld,
29043
+ Nameservers: nameservers.join(",")
29044
+ });
29045
+ return xml.includes('Status="OK"') || xml.includes('Updated="true"');
29046
+ }
28946
29047
  async function getDnsRecords(_domain, sld, tld, config) {
28947
29048
  const cfg = config || getConfig();
28948
29049
  const xml = await apiRequest(cfg, "namecheap.domains.dns.getHosts", {
@@ -35616,7 +35717,8 @@ function getConfig2() {
35616
35717
  return {
35617
35718
  region: process.env["AWS_REGION"] || "us-east-1",
35618
35719
  accessKeyId: process.env["AWS_ACCESS_KEY_ID"],
35619
- secretAccessKey: process.env["AWS_SECRET_ACCESS_KEY"]
35720
+ secretAccessKey: process.env["AWS_SECRET_ACCESS_KEY"],
35721
+ sessionToken: process.env["AWS_SESSION_TOKEN"]
35620
35722
  };
35621
35723
  }
35622
35724
  function checkCredentials(cfg) {
@@ -35632,7 +35734,7 @@ function makeClients(config) {
35632
35734
  const cfg = config ?? getConfig2();
35633
35735
  checkCredentials(cfg);
35634
35736
  const region = cfg.region || "us-east-1";
35635
- const credentials = cfg.accessKeyId && cfg.secretAccessKey ? { accessKeyId: cfg.accessKeyId, secretAccessKey: cfg.secretAccessKey } : undefined;
35737
+ const credentials = cfg.accessKeyId && cfg.secretAccessKey ? { accessKeyId: cfg.accessKeyId, secretAccessKey: cfg.secretAccessKey, sessionToken: cfg.sessionToken } : undefined;
35636
35738
  return {
35637
35739
  route53: new Route53Client({ region, credentials }),
35638
35740
  domains: new Route53DomainsClient({ region: "us-east-1", credentials })
@@ -35661,7 +35763,7 @@ async function checkAvailability3(domain, config) {
35661
35763
  } catch {}
35662
35764
  return availability;
35663
35765
  }
35664
- async function registerDomain(domain, contact, durationYears = 1, autoRenew = true, config) {
35766
+ async function registerDomain2(domain, contact, durationYears = 1, autoRenew = true, config) {
35665
35767
  const { domains } = makeClients(config);
35666
35768
  const contactDetail = {
35667
35769
  FirstName: contact.first_name,
@@ -35710,7 +35812,7 @@ async function getDomainDetail(domain, config) {
35710
35812
  nameservers: (result.Nameservers ?? []).map((ns) => ns.Name ?? "").filter(Boolean)
35711
35813
  };
35712
35814
  }
35713
- async function updateNameservers(domain, nameservers, config, client) {
35815
+ async function updateNameservers2(domain, nameservers, config, client) {
35714
35816
  if (!nameservers.length) {
35715
35817
  throw new Error("updateNameservers requires at least one nameserver");
35716
35818
  }
@@ -35772,7 +35874,8 @@ async function listHostedZones(config) {
35772
35874
  id: cleanZoneId(z2.Id ?? ""),
35773
35875
  name: z2.Name ?? "",
35774
35876
  record_count: z2.ResourceRecordSetCount ?? 0,
35775
- comment: z2.Config?.Comment
35877
+ comment: z2.Config?.Comment,
35878
+ private_zone: z2.Config?.PrivateZone
35776
35879
  });
35777
35880
  }
35778
35881
  marker = result.IsTruncated ? result.NextMarker : undefined;
@@ -35787,7 +35890,8 @@ async function getHostedZone(hostedZoneId, config) {
35787
35890
  name: result.HostedZone?.Name ?? "",
35788
35891
  record_count: result.HostedZone?.ResourceRecordSetCount ?? 0,
35789
35892
  comment: result.HostedZone?.Config?.Comment,
35790
- name_servers: result.DelegationSet?.NameServers ?? []
35893
+ name_servers: result.DelegationSet?.NameServers ?? [],
35894
+ private_zone: result.HostedZone?.Config?.PrivateZone
35791
35895
  };
35792
35896
  }
35793
35897
  async function deleteHostedZone(hostedZoneId, config) {
@@ -35797,7 +35901,15 @@ async function deleteHostedZone(hostedZoneId, config) {
35797
35901
  async function findHostedZoneByDomain(domain, config) {
35798
35902
  const zones = await listHostedZones(config);
35799
35903
  const normalized = domain.endsWith(".") ? domain : `${domain}.`;
35800
- return zones.find((z2) => z2.name === normalized) ?? null;
35904
+ const matches = zones.filter((z2) => z2.name === normalized);
35905
+ if (matches.length === 0)
35906
+ return null;
35907
+ const publicMatches = matches.filter((z2) => !z2.private_zone);
35908
+ const candidates = publicMatches.length > 0 ? publicMatches : matches;
35909
+ if (candidates.length > 1) {
35910
+ throw new Error(`Multiple Route 53 hosted zones found for ${domain}; specify hosted zone id`);
35911
+ }
35912
+ return candidates[0] ?? null;
35801
35913
  }
35802
35914
  function rrsToRecord(rrs) {
35803
35915
  if (rrs.AliasTarget) {
@@ -35895,19 +36007,55 @@ async function upsertRecords(hostedZoneId, records, config) {
35895
36007
  }
35896
36008
  function createRoute53Provider(config) {
35897
36009
  const cfg = config ?? getConfig2();
36010
+ const registerWithRoute53 = registerDomain2;
36011
+ const updateRoute53Nameservers = updateNameservers2;
36012
+ async function listDomainInventory() {
36013
+ const byDomain = new Map;
36014
+ try {
36015
+ const registered = await listRegisteredDomains(cfg);
36016
+ for (const d3 of registered) {
36017
+ byDomain.set(d3.domain, {
36018
+ domain: d3.domain,
36019
+ registrar: "AWS Route 53",
36020
+ created: "",
36021
+ expires: d3.expiry,
36022
+ nameservers: [],
36023
+ status: "active",
36024
+ auto_renew: d3.auto_renew
36025
+ });
36026
+ }
36027
+ } catch (error) {
36028
+ const message = error instanceof Error ? error.message : String(error);
36029
+ if (!message.includes("route53domains:ListDomains") && !message.includes("AccessDenied")) {
36030
+ throw error;
36031
+ }
36032
+ }
36033
+ const zones = await listHostedZones(cfg);
36034
+ for (const z2 of zones) {
36035
+ const zone = z2.name_servers?.length ? z2 : await getHostedZone(z2.id, cfg).catch(() => z2);
36036
+ const domain = zone.name.replace(/\.$/, "");
36037
+ const nameservers = zone.name_servers ?? [];
36038
+ const existing = byDomain.get(domain);
36039
+ if (existing) {
36040
+ existing.nameservers = nameservers.length > 0 ? nameservers : existing.nameservers;
36041
+ continue;
36042
+ }
36043
+ byDomain.set(domain, {
36044
+ domain,
36045
+ registrar: "AWS Route 53 DNS",
36046
+ created: "",
36047
+ expires: "",
36048
+ nameservers,
36049
+ status: "active",
36050
+ auto_renew: false
36051
+ });
36052
+ }
36053
+ return Array.from(byDomain.values());
36054
+ }
35898
36055
  return {
35899
36056
  name: "route53",
35900
36057
  async listDomains() {
35901
- const domains = await listRegisteredDomains(cfg);
35902
- return domains.map((d3) => ({
35903
- domain: d3.domain,
35904
- registrar: "AWS Route 53",
35905
- created: "",
35906
- expires: d3.expiry,
35907
- nameservers: [],
35908
- status: "active",
35909
- auto_renew: d3.auto_renew
35910
- }));
36058
+ return listDomainInventory();
35911
36059
  },
35912
36060
  async getDomainInfo(domain) {
35913
36061
  const detail = await getDomainDetail(domain, cfg);
@@ -35921,6 +36069,14 @@ function createRoute53Provider(config) {
35921
36069
  auto_renew: detail.auto_renew
35922
36070
  };
35923
36071
  },
36072
+ async registerDomain(domain, contact, options = {}) {
36073
+ const result = await registerWithRoute53(domain, contact, options.years ?? 1, options.autoRenew ?? true, cfg);
36074
+ return { domain, success: !!result.operationId, operationId: result.operationId };
36075
+ },
36076
+ async updateNameservers(domain, nameservers) {
36077
+ const result = await updateRoute53Nameservers(domain, nameservers, cfg);
36078
+ return { domain, success: !!result.operationId, operationId: result.operationId };
36079
+ },
35924
36080
  async renewDomain(_domain) {
35925
36081
  return { domain: _domain, success: false, orderId: undefined, chargedAmount: undefined };
35926
36082
  },
@@ -35968,7 +36124,7 @@ function createRoute53Provider(config) {
35968
36124
  };
35969
36125
  },
35970
36126
  async syncToLocalDb(dbFns) {
35971
- const domains = await listRegisteredDomains(cfg);
36127
+ const domains = await listDomainInventory();
35972
36128
  let synced = 0;
35973
36129
  let created = 0;
35974
36130
  let updated = 0;
@@ -35977,20 +36133,39 @@ function createRoute53Provider(config) {
35977
36133
  try {
35978
36134
  const existing = dbFns.getDomainByName(d3.domain);
35979
36135
  if (existing) {
36136
+ const existingRoute53 = existing.metadata["route53"];
36137
+ const staleDnsOnlyRegistrar = d3.registrar !== "AWS Route 53" && (existing.registrar === "AWS Route 53 DNS" || existing.registrar === "AWS Route 53" && existingRoute53?.source === "route53:hosted_zones");
35980
36138
  dbFns.updateDomain(existing.id, {
35981
- registrar: "AWS Route 53",
35982
- expires_at: d3.expiry || undefined,
36139
+ ...d3.registrar === "AWS Route 53" ? { registrar: "AWS Route 53" } : {},
36140
+ ...staleDnsOnlyRegistrar ? { registrar: null } : {},
36141
+ expires_at: d3.expires || undefined,
35983
36142
  auto_renew: d3.auto_renew,
36143
+ nameservers: d3.nameservers.length > 0 ? d3.nameservers : existing.nameservers,
36144
+ metadata: {
36145
+ ...existing.metadata,
36146
+ route53: {
36147
+ source: d3.registrar === "AWS Route 53" ? "route53domains+hosted_zones" : "route53:hosted_zones",
36148
+ synced_at: new Date().toISOString()
36149
+ }
36150
+ },
35984
36151
  status: "active"
35985
36152
  });
35986
36153
  updated++;
35987
36154
  } else {
35988
36155
  dbFns.createDomain({
35989
36156
  name: d3.domain,
35990
- registrar: "AWS Route 53",
35991
- expires_at: d3.expiry || undefined,
36157
+ ...d3.registrar === "AWS Route 53" ? { registrar: "AWS Route 53" } : {},
36158
+ expires_at: d3.expires || undefined,
35992
36159
  auto_renew: d3.auto_renew,
35993
- status: "active"
36160
+ nameservers: d3.nameservers,
36161
+ status: "active",
36162
+ notes: d3.registrar === "AWS Route 53 DNS" ? "Discovered from Route 53 hosted zones; registrar ownership was not inferred." : undefined,
36163
+ metadata: {
36164
+ route53: {
36165
+ source: d3.registrar === "AWS Route 53" ? "route53domains+hosted_zones" : "route53:hosted_zones",
36166
+ synced_at: new Date().toISOString()
36167
+ }
36168
+ }
35994
36169
  });
35995
36170
  created++;
35996
36171
  }
@@ -36004,15 +36179,129 @@ function createRoute53Provider(config) {
36004
36179
  };
36005
36180
  }
36006
36181
 
36007
- // src/lib/cloudflare-auth.ts
36008
- function resolveCloudflareConfig(env = process.env) {
36009
- const accountId = env["CLOUDFLARE_ACCOUNT_ID"] || undefined;
36010
- if (env["CLOUDFLARE_API_TOKEN"]) {
36011
- return { apiToken: env["CLOUDFLARE_API_TOKEN"], accountId };
36182
+ // src/lib/env-aliases.ts
36183
+ function firstEnv2(env, names) {
36184
+ for (const key of names) {
36185
+ const value = env[key];
36186
+ if (value)
36187
+ return { key, value };
36188
+ }
36189
+ return;
36190
+ }
36191
+ function hasEveryEnv(env, groups) {
36192
+ return groups.every((names) => !!firstEnv2(env, names));
36193
+ }
36194
+ function flattenEnvNames(groups) {
36195
+ return Array.from(new Set(groups.flatMap((names) => [...names])));
36196
+ }
36197
+ var NAMECHEAP_ENV = {
36198
+ apiKey: ["NAMECHEAP_API_KEY"],
36199
+ username: ["NAMECHEAP_USERNAME"],
36200
+ clientIp: ["NAMECHEAP_CLIENT_IP"]
36201
+ };
36202
+ var GODADDY_ENV = {
36203
+ apiKey: ["GODADDY_API_KEY"],
36204
+ apiSecret: ["GODADDY_API_SECRET"]
36205
+ };
36206
+ var BRANDSIGHT_ENV = {
36207
+ apiKey: [
36208
+ "BRANDSIGHT_API_KEY",
36209
+ "HASNAXYZ_BRANDSIGHT_LIVE_API_KEY",
36210
+ "HASNAXYZ_BRANDSIGHT_SANDBOX_API_KEY"
36211
+ ],
36212
+ apiSecret: [
36213
+ "BRANDSIGHT_API_SECRET",
36214
+ "HASNAXYZ_BRANDSIGHT_LIVE_API_SECRET",
36215
+ "HASNAXYZ_BRANDSIGHT_SANDBOX_API_SECRET"
36216
+ ],
36217
+ customerId: [
36218
+ "BRANDSIGHT_CUSTOMER_ID",
36219
+ "HASNAXYZ_BRANDSIGHT_LIVE_CUSTOMER_ID",
36220
+ "HASNAXYZ_BRANDSIGHT_SANDBOX_CUSTOMER_ID"
36221
+ ],
36222
+ shopperId: [
36223
+ "BRANDSIGHT_SHOPPER_ID",
36224
+ "HASNAXYZ_BRANDSIGHT_LIVE_SHOPPER_ID",
36225
+ "HASNAXYZ_BRANDSIGHT_SANDBOX_SHOPPER_ID"
36226
+ ],
36227
+ accountId: ["BRANDSIGHT_ACCOUNT_ID", "HASNAXYZ_BRANDSIGHT_LIVE_ACCOUNT_ID"]
36228
+ };
36229
+ var SEDO_ENV = {
36230
+ partnerId: ["SEDO_PARTNER_ID", "HASNAXYZ_SEDO_LIVE_PARTNER_ID"],
36231
+ signKey: ["SEDO_API_KEY", "SEDO_SIGN_KEY", "HASNAXYZ_SEDO_LIVE_API_KEY"],
36232
+ username: ["SEDO_USERNAME", "SEDO_EMAIL", "HASNAXYZ_SEDO_LIVE_USERNAME", "HASNAXYZ_SEDO_LIVE_EMAIL"],
36233
+ password: ["SEDO_PASSWORD", "HASNAXYZ_SEDO_LIVE_PASSWORD"]
36234
+ };
36235
+ var CLOUDFLARE_ENV = {
36236
+ apiToken: ["CLOUDFLARE_API_TOKEN", "HASNAXYZ_CLOUDFLARE_LIVE_API_TOKEN"],
36237
+ apiKey: ["CLOUDFLARE_API_KEY", "HASNAXYZ_CLOUDFLARE_LIVE_API_KEY"],
36238
+ email: ["CLOUDFLARE_EMAIL", "HASNAXYZ_CLOUDFLARE_LIVE_EMAIL"],
36239
+ accountId: ["CLOUDFLARE_ACCOUNT_ID", "HASNAXYZ_CLOUDFLARE_LIVE_ACCOUNT_ID"]
36240
+ };
36241
+ var BEEPMEDIA_AWS_ENV = {
36242
+ accessKeyId: ["HASNASTUDIO_BEEPMEDIA_AWS_LIVE_ACCESS_KEY_ID", "BEEPMEDIA_AWS_ACCESS_KEY_ID"],
36243
+ secretAccessKey: ["HASNASTUDIO_BEEPMEDIA_AWS_LIVE_SECRET_ACCESS_KEY", "BEEPMEDIA_AWS_SECRET_ACCESS_KEY"]
36244
+ };
36245
+ function providerEnvNames(provider) {
36246
+ switch (provider.toLowerCase()) {
36247
+ case "namecheap":
36248
+ return flattenEnvNames([NAMECHEAP_ENV.apiKey, NAMECHEAP_ENV.username, NAMECHEAP_ENV.clientIp]);
36249
+ case "godaddy":
36250
+ return flattenEnvNames([GODADDY_ENV.apiKey, GODADDY_ENV.apiSecret]);
36251
+ case "brandsight":
36252
+ return flattenEnvNames([
36253
+ BRANDSIGHT_ENV.apiKey,
36254
+ BRANDSIGHT_ENV.apiSecret,
36255
+ BRANDSIGHT_ENV.customerId,
36256
+ BRANDSIGHT_ENV.shopperId,
36257
+ BRANDSIGHT_ENV.accountId
36258
+ ]);
36259
+ case "sedo":
36260
+ return flattenEnvNames([SEDO_ENV.partnerId, SEDO_ENV.signKey, SEDO_ENV.username, SEDO_ENV.password]);
36261
+ case "cloudflare":
36262
+ return flattenEnvNames([CLOUDFLARE_ENV.apiToken, CLOUDFLARE_ENV.apiKey, CLOUDFLARE_ENV.email, CLOUDFLARE_ENV.accountId]);
36263
+ case "route53":
36264
+ return ["AWS_PROFILE", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"];
36265
+ case "aws:beepmedia":
36266
+ return flattenEnvNames([BEEPMEDIA_AWS_ENV.accessKeyId, BEEPMEDIA_AWS_ENV.secretAccessKey]);
36267
+ default:
36268
+ return [];
36012
36269
  }
36013
- if (env["CLOUDFLARE_API_KEY"] && env["CLOUDFLARE_EMAIL"]) {
36014
- return { apiKey: env["CLOUDFLARE_API_KEY"], email: env["CLOUDFLARE_EMAIL"], accountId };
36270
+ }
36271
+ function hasProviderCredentials(provider, env = process.env) {
36272
+ switch (provider.toLowerCase()) {
36273
+ case "namecheap":
36274
+ return hasEveryEnv(env, [NAMECHEAP_ENV.apiKey, NAMECHEAP_ENV.username, NAMECHEAP_ENV.clientIp]);
36275
+ case "godaddy":
36276
+ return hasEveryEnv(env, [GODADDY_ENV.apiKey, GODADDY_ENV.apiSecret]);
36277
+ case "brandsight":
36278
+ return hasEveryEnv(env, [BRANDSIGHT_ENV.apiKey, BRANDSIGHT_ENV.apiSecret, BRANDSIGHT_ENV.customerId]);
36279
+ case "sedo":
36280
+ return hasEveryEnv(env, [SEDO_ENV.partnerId, SEDO_ENV.signKey, SEDO_ENV.username, SEDO_ENV.password]);
36281
+ case "cloudflare": {
36282
+ const tokenMode = !!firstEnv2(env, CLOUDFLARE_ENV.apiToken);
36283
+ const keyMode = hasEveryEnv(env, [CLOUDFLARE_ENV.apiKey, CLOUDFLARE_ENV.email]);
36284
+ return tokenMode || keyMode;
36285
+ }
36286
+ case "route53":
36287
+ return !!env["AWS_PROFILE"] || hasEveryEnv(env, [["AWS_ACCESS_KEY_ID"], ["AWS_SECRET_ACCESS_KEY"]]);
36288
+ case "aws:beepmedia":
36289
+ return hasEveryEnv(env, [BEEPMEDIA_AWS_ENV.accessKeyId, BEEPMEDIA_AWS_ENV.secretAccessKey]);
36290
+ default:
36291
+ return false;
36015
36292
  }
36293
+ }
36294
+
36295
+ // src/lib/cloudflare-auth.ts
36296
+ function resolveCloudflareConfig(env = process.env) {
36297
+ const accountId = firstEnv2(env, CLOUDFLARE_ENV.accountId)?.value;
36298
+ const apiToken = firstEnv2(env, CLOUDFLARE_ENV.apiToken)?.value;
36299
+ if (apiToken)
36300
+ return { apiToken, accountId };
36301
+ const apiKey = firstEnv2(env, CLOUDFLARE_ENV.apiKey)?.value;
36302
+ const email = firstEnv2(env, CLOUDFLARE_ENV.email)?.value;
36303
+ if (apiKey && email)
36304
+ return { apiKey, email, accountId };
36016
36305
  return accountId ? { accountId } : {};
36017
36306
  }
36018
36307
  function cloudflareAuthHeaders(cfg) {
@@ -36049,6 +36338,22 @@ async function cfFetch(path, opts = {}) {
36049
36338
  }
36050
36339
  return json.result;
36051
36340
  }
36341
+ async function listZones(config) {
36342
+ const zones = [];
36343
+ let page = 1;
36344
+ while (true) {
36345
+ const result = await cfFetch(`/zones?per_page=50&page=${page}`, { config });
36346
+ if (!result || result.length === 0)
36347
+ break;
36348
+ for (const z2 of result) {
36349
+ zones.push({ id: z2.id, name: z2.name, status: z2.status, nameservers: z2.name_servers, original_nameservers: z2.original_name_servers });
36350
+ }
36351
+ if (result.length < 50)
36352
+ break;
36353
+ page++;
36354
+ }
36355
+ return zones;
36356
+ }
36052
36357
  async function getZone(domain, config) {
36053
36358
  const result = await cfFetch(`/zones?name=${encodeURIComponent(domain)}`, { config });
36054
36359
  if (!result || result.length === 0)
@@ -36090,8 +36395,20 @@ async function listRecords2(zoneId, config) {
36090
36395
  }
36091
36396
  return records;
36092
36397
  }
36398
+ async function listRecordsByNameType(zoneId, type, name, config) {
36399
+ const result = await cfFetch(`/zones/${zoneId}/dns_records?type=${encodeURIComponent(type)}&name=${encodeURIComponent(name)}`, { config });
36400
+ return (result ?? []).map((r3) => ({
36401
+ id: r3.id,
36402
+ type: r3.type,
36403
+ name: r3.name,
36404
+ content: r3.content,
36405
+ ttl: r3.ttl,
36406
+ priority: r3.priority,
36407
+ proxied: r3.proxied
36408
+ }));
36409
+ }
36093
36410
  async function upsertRecord2(zoneId, record, config) {
36094
- const existing = await cfFetch(`/zones/${zoneId}/dns_records?type=${record.type}&name=${encodeURIComponent(record.name)}`, { config });
36411
+ const existing = await listRecordsByNameType(zoneId, record.type, record.name, config);
36095
36412
  const body = {
36096
36413
  type: record.type,
36097
36414
  name: record.name,
@@ -36100,16 +36417,106 @@ async function upsertRecord2(zoneId, record, config) {
36100
36417
  priority: record.priority,
36101
36418
  proxied: record.proxied ?? false
36102
36419
  };
36103
- if (existing && existing.length > 0) {
36104
- await cfFetch(`/zones/${zoneId}/dns_records/${existing[0].id}`, { method: "PUT", body, config });
36420
+ const sameRecord = existing.find((r3) => r3.content === record.content && (r3.priority ?? undefined) === (record.priority ?? undefined) && (r3.proxied ?? false) === (record.proxied ?? false));
36421
+ if (sameRecord?.id) {
36422
+ await cfFetch(`/zones/${zoneId}/dns_records/${sameRecord.id}`, { method: "PUT", body, config });
36105
36423
  } else {
36106
36424
  await cfFetch(`/zones/${zoneId}/dns_records`, { method: "POST", body, config });
36107
36425
  }
36108
36426
  }
36427
+ async function replaceRecordsByNameType(zoneId, records, config) {
36428
+ if (records.length === 0)
36429
+ return;
36430
+ const { type, name } = records[0];
36431
+ const existing = await listRecordsByNameType(zoneId, type, name, config);
36432
+ for (const record of existing) {
36433
+ if (record.id)
36434
+ await deleteRecord2(zoneId, record.id, config);
36435
+ }
36436
+ for (const record of records) {
36437
+ await cfFetch(`/zones/${zoneId}/dns_records`, {
36438
+ method: "POST",
36439
+ body: {
36440
+ type: record.type,
36441
+ name: record.name,
36442
+ content: record.content,
36443
+ ttl: record.ttl ?? 1,
36444
+ priority: record.priority,
36445
+ proxied: record.proxied ?? false
36446
+ },
36447
+ config
36448
+ });
36449
+ }
36450
+ }
36451
+ async function deleteRecord2(zoneId, recordId, config) {
36452
+ await cfFetch(`/zones/${zoneId}/dns_records/${recordId}`, { method: "DELETE", config });
36453
+ }
36454
+ function zoneToDomainInfo(zone) {
36455
+ return {
36456
+ domain: zone.name,
36457
+ registrar: "Cloudflare DNS",
36458
+ created: "",
36459
+ expires: "",
36460
+ nameservers: zone.nameservers,
36461
+ status: zone.status === "active" ? "active" : "discovered",
36462
+ auto_renew: false
36463
+ };
36464
+ }
36465
+ function withCloudflareMetadata(existing, zone) {
36466
+ return {
36467
+ ...existing,
36468
+ cloudflare: {
36469
+ zone_id: zone.id,
36470
+ zone_status: zone.status,
36471
+ source: "cloudflare:zones",
36472
+ synced_at: new Date().toISOString()
36473
+ }
36474
+ };
36475
+ }
36109
36476
  function createCloudflareProvider(config) {
36110
36477
  const cfg = config ?? getConfig3();
36111
36478
  return {
36112
36479
  name: "cloudflare",
36480
+ async listDomains() {
36481
+ const zones = await listZones(cfg);
36482
+ return zones.map(zoneToDomainInfo);
36483
+ },
36484
+ async syncToLocalDb(dbFns) {
36485
+ const zones = await listZones(cfg);
36486
+ let synced = 0;
36487
+ let created = 0;
36488
+ let updated = 0;
36489
+ const errors = [];
36490
+ for (const zone of zones) {
36491
+ try {
36492
+ const info = zoneToDomainInfo(zone);
36493
+ const existing = dbFns.getDomainByName(zone.name);
36494
+ if (existing) {
36495
+ dbFns.updateDomain(existing.id, {
36496
+ ...existing.registrar === "Cloudflare DNS" ? { registrar: null } : {},
36497
+ status: existing.status === "discovered" && info.status === "active" ? "active" : existing.status,
36498
+ nameservers: zone.nameservers,
36499
+ metadata: withCloudflareMetadata(existing.metadata, zone)
36500
+ });
36501
+ updated++;
36502
+ } else {
36503
+ dbFns.createDomain({
36504
+ name: zone.name,
36505
+ status: info.status === "active" ? "active" : "discovered",
36506
+ auto_renew: false,
36507
+ nameservers: zone.nameservers,
36508
+ notes: "Discovered from Cloudflare zones; registrar ownership was not inferred.",
36509
+ metadata: withCloudflareMetadata({}, zone)
36510
+ });
36511
+ created++;
36512
+ }
36513
+ synced++;
36514
+ } catch (err) {
36515
+ errors.push(`${zone.name}: ${err instanceof Error ? err.message : String(err)}`);
36516
+ }
36517
+ }
36518
+ return { synced, created, updated, errors };
36519
+ },
36113
36520
  async getDnsRecords(domain) {
36114
36521
  const zone = await getZone(domain, cfg);
36115
36522
  if (!zone)
@@ -36127,8 +36534,15 @@ function createCloudflareProvider(config) {
36127
36534
  const zone = await getZone(domain, cfg);
36128
36535
  if (!zone)
36129
36536
  throw new Error(`No Cloudflare zone found for ${domain}`);
36537
+ const grouped = new Map;
36130
36538
  for (const r3 of records) {
36131
- await upsertRecord2(zone.id, { type: r3.type, name: r3.name, content: r3.value, ttl: r3.ttl || 1, priority: r3.priority }, cfg);
36539
+ const key = `${r3.type}|${r3.name}`;
36540
+ const existing = grouped.get(key) ?? [];
36541
+ existing.push({ type: r3.type, name: r3.name, content: r3.value, ttl: r3.ttl || 1, priority: r3.priority });
36542
+ grouped.set(key, existing);
36543
+ }
36544
+ for (const group of grouped.values()) {
36545
+ await replaceRecordsByNameType(zone.id, group, cfg);
36132
36546
  }
36133
36547
  return true;
36134
36548
  }
@@ -36136,6 +36550,21 @@ function createCloudflareProvider(config) {
36136
36550
  }
36137
36551
 
36138
36552
  // src/lib/brandsight.ts
36553
+ function resolveBrandsightConfig(env = process.env) {
36554
+ const apiKey = firstEnv2(env, BRANDSIGHT_ENV.apiKey)?.value ?? "";
36555
+ const apiSecret = firstEnv2(env, BRANDSIGHT_ENV.apiSecret)?.value;
36556
+ const customerId = firstEnv2(env, BRANDSIGHT_ENV.customerId)?.value;
36557
+ const shopperId = firstEnv2(env, BRANDSIGHT_ENV.shopperId)?.value;
36558
+ const accountId = firstEnv2(env, BRANDSIGHT_ENV.accountId)?.value;
36559
+ return {
36560
+ apiKey,
36561
+ apiSecret,
36562
+ customerId,
36563
+ shopperId,
36564
+ accountId,
36565
+ baseUrl: env["BRANDSIGHT_BASE_URL"]
36566
+ };
36567
+ }
36139
36568
  class BrandsightApiError extends Error {
36140
36569
  statusCode;
36141
36570
  responseBody;
@@ -36148,92 +36577,261 @@ class BrandsightApiError extends Error {
36148
36577
  }
36149
36578
  var _fetchFn = null;
36150
36579
  function getConfig4() {
36151
- return {
36152
- apiKey: process.env["BRANDSIGHT_API_KEY"] ?? "",
36153
- accountId: process.env["BRANDSIGHT_ACCOUNT_ID"]
36154
- };
36580
+ return resolveBrandsightConfig();
36155
36581
  }
36156
- var BRANDSIGHT_BASE = "https://api.brandsight.com/v1";
36157
- async function apiRequest3(method, path, apiKey, body, baseUrl = BRANDSIGHT_BASE) {
36158
- const fetchFn = _fetchFn || globalThis.fetch;
36159
- const url = `${baseUrl}${path}`;
36160
- const headers = {
36161
- Authorization: `Bearer ${apiKey}`,
36162
- "Content-Type": "application/json",
36163
- Accept: "application/json",
36164
- "User-Agent": USER_AGENT
36165
- };
36166
- try {
36167
- const response = await fetchFn(url, {
36168
- method,
36169
- headers,
36170
- body: body ? JSON.stringify(body) : undefined,
36171
- signal: AbortSignal.timeout(15000)
36172
- });
36173
- if (!response.ok) {
36174
- throw new BrandsightApiError(`Brandsight API ${method} ${path} failed with status ${response.status}`, response.status, await response.text());
36175
- }
36176
- const data = await response.json();
36177
- return { data, stub: false };
36178
- } catch (error) {
36179
- if (error instanceof BrandsightApiError)
36180
- throw error;
36181
- return { data: null, stub: true };
36582
+ var BRANDSIGHT_DOMAIN_BASE = "https://api.godaddy.com/v2";
36583
+ function requireDomainConfig(config) {
36584
+ const cfg = config ?? getConfig4();
36585
+ if (!cfg.apiKey || !cfg.apiSecret || !cfg.customerId) {
36586
+ throw new BrandsightApiError("Brandsight Domain API credentials are not configured. Set BRANDSIGHT_API_KEY, BRANDSIGHT_API_SECRET, and BRANDSIGHT_CUSTOMER_ID (or HASNAXYZ_BRANDSIGHT_LIVE_* aliases).");
36182
36587
  }
36588
+ return cfg;
36183
36589
  }
36184
- async function apiGet(path, apiKey, baseUrl = BRANDSIGHT_BASE) {
36185
- const fetchFn = _fetchFn || globalThis.fetch;
36186
- const url = `${baseUrl}${path}`;
36187
- const headers = {
36188
- Authorization: `Bearer ${apiKey}`,
36590
+ function domainBaseUrl(cfg) {
36591
+ return cfg.baseUrl ?? BRANDSIGHT_DOMAIN_BASE;
36592
+ }
36593
+ function domainHeaders(cfg) {
36594
+ return {
36595
+ Authorization: `sso-key ${cfg.apiKey}:${cfg.apiSecret}`,
36189
36596
  "Content-Type": "application/json",
36190
36597
  Accept: "application/json",
36191
36598
  "User-Agent": USER_AGENT
36192
36599
  };
36193
- try {
36194
- const response = await fetchFn(url, {
36195
- method: "GET",
36196
- headers,
36197
- signal: AbortSignal.timeout(15000)
36198
- });
36199
- if (!response.ok) {
36200
- throw new BrandsightApiError(`Brandsight API GET ${path} failed with status ${response.status}`, response.status, await response.text());
36201
- }
36202
- const data = await response.json();
36203
- return { data, stub: false };
36204
- } catch (error) {
36205
- if (error instanceof BrandsightApiError)
36206
- throw error;
36207
- return { data: null, stub: true };
36600
+ }
36601
+ async function domainApiRequest(method, path, config, body) {
36602
+ const cfg = requireDomainConfig(config);
36603
+ const fetchFn = _fetchFn || globalThis.fetch;
36604
+ const response = await fetchFn(`${domainBaseUrl(cfg)}${path}`, {
36605
+ method,
36606
+ headers: domainHeaders(cfg),
36607
+ body: body ? JSON.stringify(body) : undefined,
36608
+ signal: AbortSignal.timeout(30000)
36609
+ });
36610
+ const text = await response.text();
36611
+ if (!response.ok) {
36612
+ throw new BrandsightApiError(`Brandsight Domain API ${method} ${path} failed with status ${response.status}`, response.status, text);
36208
36613
  }
36614
+ if (!text.trim())
36615
+ return {};
36616
+ return JSON.parse(text);
36617
+ }
36618
+ function normalizeBrandsightDomain(raw) {
36619
+ const nameServers = raw.nameServers ?? raw.nameservers ?? [];
36620
+ const expiresAt = raw.expiresAt ?? raw.expires ?? "";
36621
+ const createdAt = raw.createdAt ?? raw.created ?? "";
36622
+ const renewAuto = raw.renewAuto ?? raw.auto_renew ?? false;
36623
+ return {
36624
+ ...raw,
36625
+ domain: String(raw.domain ?? ""),
36626
+ status: String(raw.status ?? "UNKNOWN"),
36627
+ created: createdAt,
36628
+ expires: expiresAt,
36629
+ auto_renew: renewAuto,
36630
+ locked: Boolean(raw.locked),
36631
+ nameservers: nameServers,
36632
+ createdAt,
36633
+ expiresAt,
36634
+ nameServers,
36635
+ renewAuto
36636
+ };
36637
+ }
36638
+ function customerPath(cfg, path) {
36639
+ return `/customers/${encodeURIComponent(cfg.customerId)}${path}`;
36640
+ }
36641
+ function domainTld(domain) {
36642
+ const parts = domain.split(".").filter(Boolean);
36643
+ if (parts.length < 2)
36644
+ throw new BrandsightApiError(`Invalid domain name: ${domain}`);
36645
+ return parts.slice(1).join(".");
36646
+ }
36647
+ function brandsightContact(contact) {
36648
+ return {
36649
+ addressMailing: {
36650
+ address1: contact.address_line_1,
36651
+ city: contact.city,
36652
+ country: contact.country_code,
36653
+ postalCode: contact.zip_code,
36654
+ state: contact.state
36655
+ },
36656
+ email: contact.email,
36657
+ encoding: "ASCII",
36658
+ nameFirst: contact.first_name,
36659
+ nameLast: contact.last_name,
36660
+ organization: contact.organization_name,
36661
+ phone: contact.phone
36662
+ };
36663
+ }
36664
+ async function domainAvailability(domain, cfg, type, period = 1) {
36665
+ const params = new URLSearchParams({
36666
+ domain,
36667
+ period: String(period),
36668
+ type,
36669
+ optimizeFor: "ACCURACY"
36670
+ });
36671
+ const result = await domainApiRequest("GET", `/domains/available?${params.toString()}`, cfg);
36672
+ return {
36673
+ domain: result.domain ?? domain,
36674
+ available: Boolean(result.available),
36675
+ price: result.price,
36676
+ currency: result.currency,
36677
+ registryPremiumPricing: result.registryPremiumPricing
36678
+ };
36209
36679
  }
36210
36680
  async function listDomains2(config) {
36211
- const cfg = config ?? getConfig4();
36212
- const result = await apiGet("/portfolio/domains", cfg.apiKey);
36213
- if (result.stub)
36214
- return [];
36215
- return result.data.domains ?? [];
36681
+ const cfg = requireDomainConfig(config);
36682
+ const domains = [];
36683
+ const seenMarkers = new Set;
36684
+ let marker;
36685
+ while (true) {
36686
+ const params = new URLSearchParams({ limit: "500" });
36687
+ if (marker)
36688
+ params.set("marker", marker);
36689
+ const batch = await domainApiRequest("GET", customerPath(cfg, `/domains?${params.toString()}`), cfg);
36690
+ if (!Array.isArray(batch) || batch.length === 0)
36691
+ break;
36692
+ domains.push(...batch.map(normalizeBrandsightDomain).filter((d3) => d3.domain));
36693
+ if (batch.length < 500)
36694
+ break;
36695
+ const nextMarker = String(batch[batch.length - 1]?.domain ?? "");
36696
+ if (!nextMarker || seenMarkers.has(nextMarker))
36697
+ break;
36698
+ seenMarkers.add(nextMarker);
36699
+ marker = nextMarker;
36700
+ }
36701
+ return domains;
36216
36702
  }
36217
36703
  async function getDomainInfo3(domain, config) {
36218
- const cfg = config ?? getConfig4();
36219
- const result = await apiGet(`/portfolio/domains/${encodeURIComponent(domain)}`, cfg.apiKey);
36220
- if (result.stub)
36221
- return null;
36222
- return result.data;
36704
+ const cfg = requireDomainConfig(config);
36705
+ const result = await domainApiRequest("GET", customerPath(cfg, `/domains/${encodeURIComponent(domain)}`), cfg);
36706
+ return normalizeBrandsightDomain(result);
36223
36707
  }
36224
36708
  async function checkAvailability4(domain, config) {
36225
- const cfg = config ?? getConfig4();
36226
- const result = await apiGet(`/domains/check?domain=${encodeURIComponent(domain)}`, cfg.apiKey);
36227
- if (result.stub)
36228
- return { domain, available: false };
36229
- return result.data;
36709
+ const cfg = requireDomainConfig(config);
36710
+ return domainAvailability(domain, cfg, "REGISTRATION", 1);
36230
36711
  }
36231
36712
  async function renewDomain3(domain, years = 1, config) {
36232
- const cfg = config ?? getConfig4();
36233
- const result = await apiRequest3("POST", `/portfolio/domains/${encodeURIComponent(domain)}/renew`, cfg.apiKey, { years });
36234
- if (result.stub)
36235
- return { success: false };
36236
- return { success: true, orderId: result.data.orderId };
36713
+ const cfg = requireDomainConfig(config);
36714
+ const current = await getDomainInfo3(domain, cfg);
36715
+ if (!current?.expires)
36716
+ throw new BrandsightApiError(`Cannot renew ${domain}: current expiry is unavailable`);
36717
+ const quote = await domainAvailability(domain, cfg, "RENEWAL", years);
36718
+ const price = quote.price ?? current.renewal?.price;
36719
+ const currency = quote.currency ?? current.renewal?.currency;
36720
+ if (price == null || !currency) {
36721
+ throw new BrandsightApiError(`Cannot renew ${domain}: renewal quote did not include an exact price and currency`);
36722
+ }
36723
+ const result = await domainApiRequest("POST", customerPath(cfg, `/domains/${encodeURIComponent(domain)}/renew`), cfg, {
36724
+ consent: {
36725
+ agreedAt: new Date().toISOString(),
36726
+ agreedBy: cfg.shopperId ?? "domains-cli",
36727
+ currency,
36728
+ price,
36729
+ registryPremiumPricing: quote.registryPremiumPricing ?? false
36730
+ },
36731
+ expires: current.expires,
36732
+ period: years
36733
+ });
36734
+ return { success: true, orderId: result.orderId ?? result.id };
36735
+ }
36736
+ async function getLegalAgreements(tld, privacy = false, config) {
36737
+ const cfg = requireDomainConfig(config);
36738
+ const params = new URLSearchParams({
36739
+ privacy: String(privacy),
36740
+ tlds: tld
36741
+ });
36742
+ return domainApiRequest("GET", customerPath(cfg, `/domains/agreements?${params.toString()}`), cfg);
36743
+ }
36744
+ async function getRegistrationSchema(tld, config) {
36745
+ const cfg = requireDomainConfig(config);
36746
+ return domainApiRequest("GET", customerPath(cfg, `/domains/register/schema/${encodeURIComponent(tld)}`), cfg);
36747
+ }
36748
+ async function validateRegistrationRequest(payload, config) {
36749
+ const cfg = requireDomainConfig(config);
36750
+ await domainApiRequest("POST", customerPath(cfg, "/domains/register/validate"), cfg, payload);
36751
+ return true;
36752
+ }
36753
+ async function registerBrandsightDomain(domain, contact, options = {}, config) {
36754
+ const cfg = requireDomainConfig(config);
36755
+ const period = options.years ?? 1;
36756
+ const availability = await domainAvailability(domain, cfg, "REGISTRATION", period);
36757
+ if (!availability.available)
36758
+ throw new BrandsightApiError(`${domain} is not available for registration`);
36759
+ const price = options.premiumPrice ?? availability.price;
36760
+ if (price == null || !availability.currency) {
36761
+ throw new BrandsightApiError(`Cannot register ${domain}: availability quote did not include an exact price and currency`);
36762
+ }
36763
+ const tld = domainTld(domain);
36764
+ const schema = await getRegistrationSchema(tld, cfg);
36765
+ const required = Array.isArray(schema["required"]) ? schema["required"] : [];
36766
+ if (required.includes("metadata") && !options.metadata) {
36767
+ throw new BrandsightApiError(`Cannot register ${domain}: ${tld} requires TLD-specific metadata; pass registration metadata before validation`);
36768
+ }
36769
+ const privacy = options.privacy ?? false;
36770
+ const agreements = await getLegalAgreements(tld, privacy, cfg);
36771
+ const agreementKeys = agreements.map((a3) => a3.agreementKey).filter(Boolean);
36772
+ const c3 = brandsightContact(contact);
36773
+ const payload = {
36774
+ consent: {
36775
+ agreedAt: new Date().toISOString(),
36776
+ agreedBy: contact.email || cfg.shopperId || "domains-cli",
36777
+ agreementKeys,
36778
+ currency: availability.currency,
36779
+ price,
36780
+ registryPremiumPricing: availability.registryPremiumPricing ?? !!options.premiumPrice
36781
+ },
36782
+ contacts: {
36783
+ admin: c3,
36784
+ billing: c3,
36785
+ registrant: c3,
36786
+ tech: c3
36787
+ },
36788
+ domain,
36789
+ metadata: options.metadata ?? {},
36790
+ nameServers: options.nameservers ?? [],
36791
+ period,
36792
+ privacy,
36793
+ renewAuto: options.autoRenew ?? true
36794
+ };
36795
+ await validateRegistrationRequest(payload, cfg);
36796
+ const result = await domainApiRequest("POST", customerPath(cfg, "/domains/register"), cfg, payload);
36797
+ return {
36798
+ success: true,
36799
+ orderId: result.orderId ?? result.id,
36800
+ operationId: result.operationId ?? result.id,
36801
+ chargedAmount: String(price)
36802
+ };
36803
+ }
36804
+ async function updateNameservers3(domain, nameservers, config) {
36805
+ const cfg = requireDomainConfig(config);
36806
+ const result = await domainApiRequest("PUT", customerPath(cfg, `/domains/${encodeURIComponent(domain)}/nameServers`), cfg, { nameServers: nameservers });
36807
+ return { success: true, operationId: result.operationId ?? result.id };
36808
+ }
36809
+ async function getDnsRecords3(domain, config) {
36810
+ const cfg = requireDomainConfig(config);
36811
+ const records = [];
36812
+ let offset = 0;
36813
+ const limit = 1000;
36814
+ while (true) {
36815
+ const batch = await domainApiRequest("GET", customerPath(cfg, `/domains/${encodeURIComponent(domain)}/records?offset=${offset}&limit=${limit}`), cfg);
36816
+ if (!Array.isArray(batch) || batch.length === 0)
36817
+ break;
36818
+ records.push(...batch);
36819
+ if (batch.length < limit)
36820
+ break;
36821
+ offset++;
36822
+ }
36823
+ return records;
36824
+ }
36825
+ function normalizeBrandsightDnsRecord(record) {
36826
+ return {
36827
+ ...record,
36828
+ ttl: Math.max(record.ttl || 600, 600)
36829
+ };
36830
+ }
36831
+ async function setDnsRecords3(domain, records, config) {
36832
+ const cfg = requireDomainConfig(config);
36833
+ await domainApiRequest("PUT", customerPath(cfg, `/domains/${encodeURIComponent(domain)}/records`), cfg, records.map(normalizeBrandsightDnsRecord));
36834
+ return true;
36237
36835
  }
36238
36836
  async function syncToLocalDb3(dbFns, config) {
36239
36837
  const domains = await listDomains2(config);
@@ -36278,7 +36876,7 @@ function createBrandsightProvider(config) {
36278
36876
  return domains.map((d3) => ({
36279
36877
  domain: d3.domain,
36280
36878
  registrar: "Brandsight",
36281
- created: "",
36879
+ created: d3.created ?? "",
36282
36880
  expires: d3.expires,
36283
36881
  nameservers: d3.nameservers,
36284
36882
  status: d3.status === "ACTIVE" ? "active" : d3.status.toLowerCase(),
@@ -36292,23 +36890,58 @@ function createBrandsightProvider(config) {
36292
36890
  return {
36293
36891
  domain: d3.domain,
36294
36892
  registrar: "Brandsight",
36295
- created: "",
36893
+ created: d3.created ?? "",
36296
36894
  expires: d3.expires,
36297
36895
  nameservers: d3.nameservers,
36298
36896
  status: d3.status === "ACTIVE" ? "active" : d3.status.toLowerCase(),
36299
36897
  auto_renew: d3.auto_renew
36300
36898
  };
36301
36899
  },
36302
- async renewDomain(domain) {
36303
- const result = await renewDomain3(domain, 1, cfg);
36900
+ async renewDomain(domain, years = 1) {
36901
+ const result = await renewDomain3(domain, years, cfg);
36304
36902
  return { domain, success: result.success, orderId: result.orderId };
36305
36903
  },
36904
+ async registerDomain(domain, contact, options) {
36905
+ const result = await registerBrandsightDomain(domain, contact, options, cfg);
36906
+ return {
36907
+ domain,
36908
+ success: result.success,
36909
+ orderId: result.orderId,
36910
+ operationId: result.operationId,
36911
+ chargedAmount: result.chargedAmount
36912
+ };
36913
+ },
36914
+ async updateNameservers(domain, nameservers) {
36915
+ const result = await updateNameservers3(domain, nameservers, cfg);
36916
+ return { domain, success: result.success, operationId: result.operationId };
36917
+ },
36918
+ async getDnsRecords(domain) {
36919
+ const records = await getDnsRecords3(domain, cfg);
36920
+ return records.map((r3) => ({
36921
+ type: r3.type,
36922
+ name: r3.name,
36923
+ value: r3.data,
36924
+ ttl: r3.ttl,
36925
+ priority: r3.priority
36926
+ }));
36927
+ },
36928
+ async setDnsRecords(domain, records) {
36929
+ return setDnsRecords3(domain, records.map((r3) => ({
36930
+ type: r3.type,
36931
+ name: r3.name,
36932
+ data: r3.value,
36933
+ ttl: r3.ttl,
36934
+ priority: r3.priority
36935
+ })), cfg);
36936
+ },
36306
36937
  async checkAvailability(domain) {
36307
36938
  const result = await checkAvailability4(domain, cfg);
36308
36939
  return {
36309
36940
  domain: result.domain,
36310
36941
  available: result.available,
36311
- standard_price: result.price,
36942
+ is_premium: result.registryPremiumPricing,
36943
+ premium_price: result.registryPremiumPricing ? result.price : undefined,
36944
+ standard_price: result.registryPremiumPricing ? undefined : result.price,
36312
36945
  currency: result.currency
36313
36946
  };
36314
36947
  },
@@ -36348,9 +36981,27 @@ function createNamecheapProvider() {
36348
36981
  auto_renew: true
36349
36982
  };
36350
36983
  },
36351
- async renewDomain(domain) {
36984
+ async registerDomain(domain, contact, options = {}) {
36352
36985
  const config = getConfig();
36353
- const result = await renewDomain(domain, 1, config);
36986
+ const result = await registerDomain(domain, contact, {
36987
+ years: options.years,
36988
+ premiumPrice: options.premiumPrice
36989
+ }, config);
36990
+ return {
36991
+ domain: result.domain,
36992
+ success: result.success,
36993
+ orderId: result.orderId,
36994
+ chargedAmount: result.chargedAmount
36995
+ };
36996
+ },
36997
+ async updateNameservers(domain, nameservers) {
36998
+ const config = getConfig();
36999
+ const success = await updateNameservers(domain, nameservers, config);
37000
+ return { domain, success };
37001
+ },
37002
+ async renewDomain(domain, years = 1) {
37003
+ const config = getConfig();
37004
+ const result = await renewDomain(domain, years, config);
36354
37005
  return {
36355
37006
  domain: result.domain,
36356
37007
  success: result.success,
@@ -36486,8 +37137,9 @@ var providerRegistry = new Map([
36486
37137
  name: "namecheap",
36487
37138
  type: "full",
36488
37139
  configured: false,
36489
- envVars: ["NAMECHEAP_API_KEY", "NAMECHEAP_USERNAME", "NAMECHEAP_CLIENT_IP"]
37140
+ envVars: providerEnvNames("namecheap")
36490
37141
  },
37142
+ createInventory: createNamecheapProvider,
36491
37143
  createRegistrar: createNamecheapProvider,
36492
37144
  createDns: createNamecheapProvider
36493
37145
  }],
@@ -36496,8 +37148,9 @@ var providerRegistry = new Map([
36496
37148
  name: "godaddy",
36497
37149
  type: "full",
36498
37150
  configured: false,
36499
- envVars: ["GODADDY_API_KEY", "GODADDY_API_SECRET"]
37151
+ envVars: providerEnvNames("godaddy")
36500
37152
  },
37153
+ createInventory: createGoDaddyProvider,
36501
37154
  createRegistrar: createGoDaddyProvider,
36502
37155
  createDns: createGoDaddyProvider
36503
37156
  }],
@@ -36506,8 +37159,9 @@ var providerRegistry = new Map([
36506
37159
  name: "route53",
36507
37160
  type: "full",
36508
37161
  configured: false,
36509
- envVars: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"]
37162
+ envVars: providerEnvNames("route53")
36510
37163
  },
37164
+ createInventory: () => createRoute53Provider(),
36511
37165
  createRegistrar: () => createRoute53Provider(),
36512
37166
  createDns: () => createRoute53Provider()
36513
37167
  }],
@@ -36516,31 +37170,64 @@ var providerRegistry = new Map([
36516
37170
  name: "cloudflare",
36517
37171
  type: "dns",
36518
37172
  configured: false,
36519
- envVars: ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"]
37173
+ envVars: providerEnvNames("cloudflare")
36520
37174
  },
37175
+ createInventory: () => createCloudflareProvider(),
36521
37176
  createDns: createCloudflareProvider
36522
37177
  }],
36523
37178
  ["brandsight", {
36524
37179
  info: {
36525
37180
  name: "brandsight",
36526
- type: "registrar",
37181
+ type: "full",
36527
37182
  configured: false,
36528
- envVars: ["BRANDSIGHT_API_KEY", "BRANDSIGHT_ACCOUNT_ID"]
37183
+ envVars: providerEnvNames("brandsight")
36529
37184
  },
36530
- createRegistrar: createBrandsightProvider
37185
+ createInventory: createBrandsightProvider,
37186
+ createRegistrar: createBrandsightProvider,
37187
+ createDns: createBrandsightProvider
37188
+ }],
37189
+ ["sedo", {
37190
+ info: {
37191
+ name: "sedo",
37192
+ type: "marketplace",
37193
+ configured: false,
37194
+ envVars: providerEnvNames("sedo")
37195
+ }
36531
37196
  }]
36532
37197
  ]);
36533
- function isConfigured(envVars) {
36534
- return envVars.slice(0, 2).every((v3) => !!process.env[v3]);
37198
+ function isConfigured(providerName) {
37199
+ return hasProviderCredentials(providerName);
36535
37200
  }
36536
37201
  function getAvailableProviders() {
36537
37202
  return Array.from(providerRegistry.values()).map((e3) => ({
36538
37203
  ...e3.info,
36539
- configured: isConfigured(e3.info.envVars)
37204
+ configured: isConfigured(e3.info.name),
37205
+ inventory: !!e3.createInventory
36540
37206
  }));
36541
37207
  }
37208
+ function getProviderInfo(name) {
37209
+ const entry = providerRegistry.get(name.toLowerCase());
37210
+ if (!entry)
37211
+ return null;
37212
+ return { ...entry.info, configured: isConfigured(entry.info.name), inventory: !!entry.createInventory };
37213
+ }
37214
+ function providerHasRegistrar(name) {
37215
+ return !!providerRegistry.get(name.toLowerCase())?.createRegistrar;
37216
+ }
37217
+ function providerHasDns(name) {
37218
+ return !!providerRegistry.get(name.toLowerCase())?.createDns;
37219
+ }
37220
+ function providerHasInventory(name) {
37221
+ return !!providerRegistry.get(name.toLowerCase())?.createInventory;
37222
+ }
37223
+ function getDomainInventoryProvider(name) {
37224
+ const entry = providerRegistry.get(name.toLowerCase());
37225
+ if (!entry?.createInventory)
37226
+ throw new Error(`No domain inventory provider: ${name}`);
37227
+ return entry.createInventory();
37228
+ }
36542
37229
  function getRegistrarProvider(name) {
36543
- const entry = providerRegistry.get(name);
37230
+ const entry = providerRegistry.get(name.toLowerCase());
36544
37231
  if (!entry?.createRegistrar)
36545
37232
  throw new Error(`No registrar provider: ${name}`);
36546
37233
  return entry.createRegistrar();
@@ -36549,11 +37236,11 @@ function getProvider(name) {
36549
37236
  return getRegistrarProvider(name);
36550
37237
  }
36551
37238
  async function syncAll(dbFns) {
36552
- const available = getAvailableProviders().filter((p3) => p3.configured && (p3.type === "registrar" || p3.type === "full") && p3.name !== "brandsight");
37239
+ const available = getAvailableProviders().filter((p3) => p3.configured && providerHasInventory(p3.name));
36553
37240
  const result = { providers: [], totalSynced: 0, totalErrors: [] };
36554
37241
  for (const info of available) {
36555
37242
  try {
36556
- const provider = getRegistrarProvider(info.name);
37243
+ const provider = getDomainInventoryProvider(info.name);
36557
37244
  const syncResult = await provider.syncToLocalDb(dbFns);
36558
37245
  result.providers.push({ name: info.name, result: syncResult });
36559
37246
  result.totalSynced += syncResult.synced;
@@ -36571,14 +37258,16 @@ function autoDetectRegistrar(domain, getDomainByName2) {
36571
37258
  if (!dbDomain?.registrar)
36572
37259
  return null;
36573
37260
  const r3 = dbDomain.registrar.toLowerCase();
37261
+ if (r3.includes("cloudflare dns") || r3.includes("route 53 dns") || r3.includes("route53 dns"))
37262
+ return null;
36574
37263
  if (r3.includes("namecheap"))
36575
37264
  return "namecheap";
36576
37265
  if (r3.includes("godaddy"))
36577
37266
  return "godaddy";
36578
- if (r3.includes("route 53") || r3.includes("route53") || r3.includes("aws"))
37267
+ if (r3.includes("route 53") || r3.includes("route53"))
36579
37268
  return "route53";
36580
37269
  if (r3.includes("cloudflare"))
36581
- return "cloudflare";
37270
+ return null;
36582
37271
  if (r3.includes("brandsight"))
36583
37272
  return "brandsight";
36584
37273
  return null;
@@ -36597,8 +37286,9 @@ var PROVIDER_CAPABILITIES = {
36597
37286
  route53: { canBuy: true, canDns: true, gated: false, notes: "Full self-serve buy + hosted zones via AWS API; primary buy path." },
36598
37287
  cloudflare: { canBuy: false, canDns: true, gated: false, notes: "DNS/zone management only; not a registrar. Always our DNS." },
36599
37288
  namecheap: { canBuy: true, canDns: true, gated: false, notes: "Buy + DNS via API; requires API access + whitelisted IP." },
36600
- godaddy: { canBuy: true, canDns: true, gated: true, notes: "Domains API gated behind account thresholds (>=10 / Discount Domain Club) since 2024; purchase + DNS writes unreliable." },
36601
- brandsight: { canBuy: true, canDns: true, gated: true, notes: "GoDaddy Corporate Domains (enterprise/contract-only); credentials issued to onboarded clients, not self-serve." }
37289
+ godaddy: { canBuy: false, canDns: true, gated: true, notes: "Availability remains threshold-gated; this CLI supports sync/renew/DNS records where account access qualifies, but not direct automated purchase." },
37290
+ brandsight: { canBuy: true, canDns: true, gated: true, notes: "GoDaddy Corporate Domains (enterprise/contract-only); this CLI supports portfolio, registration, renewal, nameserver, and DNS operations through the official v2 API when the account contract permits it." },
37291
+ sedo: { canBuy: false, canDns: false, gated: true, notes: "Marketplace API only: search/portfolio/listings and recorded purchases; no registrar DNS or direct registration API in this CLI." }
36602
37292
  };
36603
37293
  var UNKNOWN = { canBuy: false, canDns: false, gated: true, notes: "Unknown provider." };
36604
37294
  function getCapability(name) {
@@ -36656,17 +37346,20 @@ export {
36656
37346
  updateDomain,
36657
37347
  updateDnsRecord,
36658
37348
  syncAll,
37349
+ storageSync,
37350
+ storagePush,
37351
+ storagePull,
36659
37352
  selectDnsProvider,
36660
37353
  selectBuyRegistrar,
36661
37354
  searchDomains,
36662
- runCloudMigrations,
37355
+ runStorageMigrations,
36663
37356
  resolveTables,
36664
37357
  resolveCloudflareConfig,
36665
37358
  recordDomainPurchase,
36666
37359
  upsertRecords as r53UpsertRecords,
36667
37360
  upsertRecord as r53UpsertRecord,
36668
- updateNameservers as r53UpdateNameservers,
36669
- registerDomain as r53RegisterDomain,
37361
+ updateNameservers2 as r53UpdateNameservers,
37362
+ registerDomain2 as r53RegisterDomain,
36670
37363
  listRegisteredDomains as r53ListRegisteredDomains,
36671
37364
  listRecords as r53ListRecords,
36672
37365
  listHostedZones as r53ListHostedZones,
@@ -36678,6 +37371,9 @@ export {
36678
37371
  deleteHostedZone as r53DeleteHostedZone,
36679
37372
  createHostedZone as r53CreateHostedZone,
36680
37373
  checkAvailability3 as r53CheckAvailability,
37374
+ providerHasRegistrar,
37375
+ providerHasInventory,
37376
+ providerHasDns,
36681
37377
  pollRegistrationUntilDone,
36682
37378
  markDomainPremium,
36683
37379
  listSslExpiring,
@@ -36690,9 +37386,17 @@ export {
36690
37386
  linkDomainEmail,
36691
37387
  importZoneFile,
36692
37388
  getSyncMetaAll,
37389
+ getStorageSyncMetaAll,
37390
+ getStorageStatus,
37391
+ getStoragePg,
37392
+ getStorageMode,
37393
+ getStorageDatabaseUrl,
37394
+ getStorageDatabaseEnvName,
37395
+ getProviderInfo,
36693
37396
  getProvider,
36694
37397
  getDomainStats,
36695
37398
  getDomainOffer,
37399
+ getDomainInventoryProvider,
36696
37400
  getDomainEmailLink,
36697
37401
  getDomainDetails,
36698
37402
  getDomainByName,
@@ -36700,8 +37404,6 @@ export {
36700
37404
  getDomain,
36701
37405
  getDnsRecord,
36702
37406
  getDatabase,
36703
- getCloudPg,
36704
- getCloudDatabaseUrl,
36705
37407
  getCapability,
36706
37408
  getByRegistrar,
36707
37409
  getAvailableProviders,
@@ -36720,9 +37422,6 @@ export {
36720
37422
  createAlert,
36721
37423
  countDomains,
36722
37424
  cloudflareAuthHeaders,
36723
- cloudSync,
36724
- cloudPush,
36725
- cloudPull,
36726
37425
  closeDatabase,
36727
37426
  classifyRegistrationStatus,
36728
37427
  checkSsl,
@@ -36734,11 +37433,18 @@ export {
36734
37433
  createZone as cfCreateZone,
36735
37434
  canBuy,
36736
37435
  autoDetectRegistrar,
37436
+ STORAGE_TABLES,
37437
+ STORAGE_MODE_ENV,
37438
+ STORAGE_DATABASE_ENV,
36737
37439
  PgAdapterAsync,
36738
37440
  PROVIDER_CAPABILITIES,
36739
37441
  PG_MIGRATIONS,
36740
37442
  DOMAIN_STATUSES,
36741
37443
  DOMAIN_OFFER_STATUSES,
36742
37444
  DOMAIN_EMAIL_TYPES,
36743
- CLOUD_TABLES
37445
+ DOMAINS_STORAGE_TABLES,
37446
+ DOMAINS_STORAGE_MODE_FALLBACK_ENV,
37447
+ DOMAINS_STORAGE_MODE_ENV,
37448
+ DOMAINS_STORAGE_FALLBACK_ENV,
37449
+ DOMAINS_STORAGE_ENV
36744
37450
  };