@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.
- package/README.md +140 -63
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/domain.d.ts.map +1 -1
- package/dist/cli/commands/provider.d.ts.map +1 -1
- package/dist/cli/commands/providers.d.ts.map +1 -1
- package/dist/cli/commands/storage.d.ts +3 -0
- package/dist/cli/commands/storage.d.ts.map +1 -0
- package/dist/cli/index.js +2099 -550
- package/dist/db/domain-records.d.ts +2 -2
- package/dist/db/domain-records.d.ts.map +1 -1
- package/dist/db/pg-migrations.d.ts +1 -1
- package/dist/db/storage-sync.d.ts +55 -0
- package/dist/db/storage-sync.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +863 -157
- package/dist/lib/brandsight.d.ts +46 -2
- package/dist/lib/brandsight.d.ts.map +1 -1
- package/dist/lib/capability.d.ts +5 -3
- package/dist/lib/capability.d.ts.map +1 -1
- package/dist/lib/cloudflare-auth.d.ts.map +1 -1
- package/dist/lib/cloudflare.d.ts +2 -2
- package/dist/lib/cloudflare.d.ts.map +1 -1
- package/dist/lib/creds-check.d.ts.map +1 -1
- package/dist/lib/env-aliases.d.ts +43 -0
- package/dist/lib/env-aliases.d.ts.map +1 -0
- package/dist/lib/godaddy.d.ts +4 -4
- package/dist/lib/namecheap.d.ts +13 -0
- package/dist/lib/namecheap.d.ts.map +1 -1
- package/dist/lib/registrar.d.ts +49 -5
- package/dist/lib/registrar.d.ts.map +1 -1
- package/dist/lib/route53.d.ts +2 -0
- package/dist/lib/route53.d.ts.map +1 -1
- package/dist/lib/sedo.d.ts +7 -0
- package/dist/lib/sedo.d.ts.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +14266 -15760
- package/dist/mcp/storage-tools.d.ts +3 -0
- package/dist/mcp/storage-tools.d.ts.map +1 -0
- package/dist/storage.d.ts +5 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +5703 -0
- package/package.json +9 -3
- package/dist/cli/commands/cloud.d.ts +0 -3
- package/dist/cli/commands/cloud.d.ts.map +0 -1
- package/dist/db/cloud-sync.d.ts +0 -33
- package/dist/db/cloud-sync.d.ts.map +0 -1
- package/dist/mcp/cloud-tools.d.ts +0 -3
- 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/
|
|
28637
|
-
var
|
|
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
|
-
|
|
28658
|
-
|
|
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
|
|
28661
|
-
const url =
|
|
28693
|
+
async function getStoragePg() {
|
|
28694
|
+
const url = getStorageDatabaseUrl();
|
|
28662
28695
|
if (!url) {
|
|
28663
|
-
throw new Error("Missing
|
|
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
|
|
28700
|
+
async function runStorageMigrations(remote) {
|
|
28668
28701
|
for (const sql of PG_MIGRATIONS)
|
|
28669
28702
|
await remote.run(sql);
|
|
28670
28703
|
}
|
|
28671
|
-
async function
|
|
28672
|
-
const remote = await
|
|
28704
|
+
async function storagePush(options) {
|
|
28705
|
+
const remote = await getStoragePg();
|
|
28673
28706
|
const db = getDatabase();
|
|
28674
28707
|
try {
|
|
28675
|
-
await
|
|
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
|
|
28686
|
-
const remote = await
|
|
28718
|
+
async function storagePull(options) {
|
|
28719
|
+
const remote = await getStoragePg();
|
|
28687
28720
|
const db = getDatabase();
|
|
28688
28721
|
try {
|
|
28689
|
-
await
|
|
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
|
|
28700
|
-
const pull = await
|
|
28701
|
-
const push = await
|
|
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
|
|
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 [...
|
|
28712
|
-
const allowed = new Set(
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
36157
|
+
...d3.registrar === "AWS Route 53" ? { registrar: "AWS Route 53" } : {},
|
|
36158
|
+
expires_at: d3.expires || undefined,
|
|
35992
36159
|
auto_renew: d3.auto_renew,
|
|
35993
|
-
|
|
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/
|
|
36008
|
-
function
|
|
36009
|
-
const
|
|
36010
|
-
|
|
36011
|
-
|
|
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
|
-
|
|
36014
|
-
|
|
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
|
|
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
|
-
|
|
36104
|
-
|
|
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
|
-
|
|
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
|
|
36157
|
-
|
|
36158
|
-
const
|
|
36159
|
-
|
|
36160
|
-
|
|
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
|
-
|
|
36185
|
-
|
|
36186
|
-
|
|
36187
|
-
|
|
36188
|
-
|
|
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
|
-
|
|
36194
|
-
|
|
36195
|
-
|
|
36196
|
-
|
|
36197
|
-
|
|
36198
|
-
|
|
36199
|
-
|
|
36200
|
-
|
|
36201
|
-
|
|
36202
|
-
|
|
36203
|
-
|
|
36204
|
-
|
|
36205
|
-
|
|
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
|
|
36212
|
-
const
|
|
36213
|
-
|
|
36214
|
-
|
|
36215
|
-
|
|
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
|
|
36219
|
-
const result = await
|
|
36220
|
-
|
|
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
|
|
36226
|
-
|
|
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
|
|
36233
|
-
const
|
|
36234
|
-
if (
|
|
36235
|
-
|
|
36236
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
36984
|
+
async registerDomain(domain, contact, options = {}) {
|
|
36352
36985
|
const config = getConfig();
|
|
36353
|
-
const result = await
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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: "
|
|
37181
|
+
type: "full",
|
|
36527
37182
|
configured: false,
|
|
36528
|
-
envVars:
|
|
37183
|
+
envVars: providerEnvNames("brandsight")
|
|
36529
37184
|
},
|
|
36530
|
-
|
|
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(
|
|
36534
|
-
return
|
|
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.
|
|
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.
|
|
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 =
|
|
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")
|
|
37267
|
+
if (r3.includes("route 53") || r3.includes("route53"))
|
|
36579
37268
|
return "route53";
|
|
36580
37269
|
if (r3.includes("cloudflare"))
|
|
36581
|
-
return
|
|
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:
|
|
36601
|
-
brandsight: { canBuy: true, canDns: true, gated: true, notes: "GoDaddy Corporate Domains (enterprise/contract-only);
|
|
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
|
-
|
|
37355
|
+
runStorageMigrations,
|
|
36663
37356
|
resolveTables,
|
|
36664
37357
|
resolveCloudflareConfig,
|
|
36665
37358
|
recordDomainPurchase,
|
|
36666
37359
|
upsertRecords as r53UpsertRecords,
|
|
36667
37360
|
upsertRecord as r53UpsertRecord,
|
|
36668
|
-
|
|
36669
|
-
|
|
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
|
-
|
|
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
|
};
|