@hasna/domains 0.0.13 → 0.0.14
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/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/provision.d.ts +3 -0
- package/dist/cli/commands/provision.d.ts.map +1 -0
- package/dist/cli/index.js +391 -251
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +127 -8
- package/dist/lib/brandsight.d.ts +20 -0
- package/dist/lib/brandsight.d.ts.map +1 -1
- package/dist/lib/capability.d.ts +30 -0
- package/dist/lib/capability.d.ts.map +1 -0
- package/dist/lib/cloudflare-auth.d.ts +15 -0
- package/dist/lib/cloudflare-auth.d.ts.map +1 -0
- package/dist/lib/cloudflare.d.ts +13 -4
- package/dist/lib/cloudflare.d.ts.map +1 -1
- package/dist/lib/creds-check.d.ts +13 -0
- package/dist/lib/creds-check.d.ts.map +1 -0
- package/dist/lib/domain-daemon.d.ts +30 -0
- package/dist/lib/domain-daemon.d.ts.map +1 -0
- package/dist/lib/godaddy.d.ts +12 -0
- package/dist/lib/godaddy.d.ts.map +1 -1
- package/dist/lib/ns-drift.d.ts +29 -0
- package/dist/lib/ns-drift.d.ts.map +1 -0
- package/dist/lib/provision-state.d.ts +29 -0
- package/dist/lib/provision-state.d.ts.map +1 -0
- package/dist/lib/registration-poll.d.ts +24 -0
- package/dist/lib/registration-poll.d.ts.map +1 -0
- package/dist/mcp/http.d.ts +2 -1
- package/dist/mcp/http.d.ts.map +1 -1
- package/dist/mcp/index.js +43 -17
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -25599,6 +25599,322 @@ var init_dist_es9 = __esm(() => {
|
|
|
25599
25599
|
init_fromIni();
|
|
25600
25600
|
});
|
|
25601
25601
|
|
|
25602
|
+
// src/lib/cloudflare-auth.ts
|
|
25603
|
+
function resolveCloudflareConfig(env = process.env) {
|
|
25604
|
+
const accountId = env["CLOUDFLARE_ACCOUNT_ID"] || env["HASNAXYZ_CLOUDFLARE_LIVE_ACCOUNT_ID"] || undefined;
|
|
25605
|
+
if (env["CLOUDFLARE_API_TOKEN"]) {
|
|
25606
|
+
return { apiToken: env["CLOUDFLARE_API_TOKEN"], accountId };
|
|
25607
|
+
}
|
|
25608
|
+
if (env["CLOUDFLARE_API_KEY"] && env["CLOUDFLARE_EMAIL"]) {
|
|
25609
|
+
return { apiKey: env["CLOUDFLARE_API_KEY"], email: env["CLOUDFLARE_EMAIL"], accountId };
|
|
25610
|
+
}
|
|
25611
|
+
if (env["HASNAXYZ_CLOUDFLARE_LIVE_API_KEY"] && env["HASNAXYZ_CLOUDFLARE_LIVE_EMAIL"]) {
|
|
25612
|
+
return {
|
|
25613
|
+
apiKey: env["HASNAXYZ_CLOUDFLARE_LIVE_API_KEY"],
|
|
25614
|
+
email: env["HASNAXYZ_CLOUDFLARE_LIVE_EMAIL"],
|
|
25615
|
+
accountId
|
|
25616
|
+
};
|
|
25617
|
+
}
|
|
25618
|
+
return accountId ? { accountId } : {};
|
|
25619
|
+
}
|
|
25620
|
+
function cloudflareAuthHeaders(cfg) {
|
|
25621
|
+
if (cfg.apiToken)
|
|
25622
|
+
return { Authorization: `Bearer ${cfg.apiToken}` };
|
|
25623
|
+
if (cfg.apiKey && cfg.email)
|
|
25624
|
+
return { "X-Auth-Key": cfg.apiKey, "X-Auth-Email": cfg.email };
|
|
25625
|
+
throw new Error("Cloudflare credentials not configured. Set CLOUDFLARE_API_TOKEN, or CLOUDFLARE_API_KEY + CLOUDFLARE_EMAIL.");
|
|
25626
|
+
}
|
|
25627
|
+
|
|
25628
|
+
// src/lib/brandsight.ts
|
|
25629
|
+
function resolveBrandsightConfig(env = process.env) {
|
|
25630
|
+
return {
|
|
25631
|
+
apiKey: env["BRANDSIGHT_API_KEY"] ?? env["HASNAXYZ_BRANDSIGHT_LIVE_API_KEY"] ?? "",
|
|
25632
|
+
apiSecret: env["BRANDSIGHT_API_SECRET"] ?? env["HASNAXYZ_BRANDSIGHT_LIVE_API_SECRET"],
|
|
25633
|
+
customerId: env["BRANDSIGHT_CUSTOMER_ID"] ?? env["HASNAXYZ_BRANDSIGHT_LIVE_CUSTOMER_ID"],
|
|
25634
|
+
shopperId: env["BRANDSIGHT_SHOPPER_ID"] ?? env["HASNAXYZ_BRANDSIGHT_LIVE_SHOPPER_ID"],
|
|
25635
|
+
accountId: env["BRANDSIGHT_ACCOUNT_ID"] ?? env["HASNAXYZ_BRANDSIGHT_LIVE_CUSTOMER_ID"]
|
|
25636
|
+
};
|
|
25637
|
+
}
|
|
25638
|
+
function getApiKey() {
|
|
25639
|
+
const key = process.env["BRANDSIGHT_API_KEY"];
|
|
25640
|
+
if (!key) {
|
|
25641
|
+
throw new BrandsightApiError("BRANDSIGHT_API_KEY environment variable is not set");
|
|
25642
|
+
}
|
|
25643
|
+
return key;
|
|
25644
|
+
}
|
|
25645
|
+
function getConfig4() {
|
|
25646
|
+
return {
|
|
25647
|
+
apiKey: process.env["BRANDSIGHT_API_KEY"] ?? "",
|
|
25648
|
+
accountId: process.env["BRANDSIGHT_ACCOUNT_ID"]
|
|
25649
|
+
};
|
|
25650
|
+
}
|
|
25651
|
+
async function apiRequest3(method, path, apiKey, body, baseUrl = BRANDSIGHT_BASE) {
|
|
25652
|
+
const fetchFn = _fetchFn || globalThis.fetch;
|
|
25653
|
+
const url = `${baseUrl}${path}`;
|
|
25654
|
+
const headers = {
|
|
25655
|
+
Authorization: `Bearer ${apiKey}`,
|
|
25656
|
+
"Content-Type": "application/json",
|
|
25657
|
+
Accept: "application/json",
|
|
25658
|
+
"User-Agent": USER_AGENT
|
|
25659
|
+
};
|
|
25660
|
+
try {
|
|
25661
|
+
const response = await fetchFn(url, {
|
|
25662
|
+
method,
|
|
25663
|
+
headers,
|
|
25664
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
25665
|
+
signal: AbortSignal.timeout(15000)
|
|
25666
|
+
});
|
|
25667
|
+
if (!response.ok) {
|
|
25668
|
+
throw new BrandsightApiError(`Brandsight API ${method} ${path} failed with status ${response.status}`, response.status, await response.text());
|
|
25669
|
+
}
|
|
25670
|
+
const data = await response.json();
|
|
25671
|
+
return { data, stub: false };
|
|
25672
|
+
} catch (error) {
|
|
25673
|
+
if (error instanceof BrandsightApiError)
|
|
25674
|
+
throw error;
|
|
25675
|
+
return { data: null, stub: true };
|
|
25676
|
+
}
|
|
25677
|
+
}
|
|
25678
|
+
async function apiGet(path, apiKey, baseUrl = BRANDSIGHT_BASE) {
|
|
25679
|
+
const fetchFn = _fetchFn || globalThis.fetch;
|
|
25680
|
+
const url = `${baseUrl}${path}`;
|
|
25681
|
+
const headers = {
|
|
25682
|
+
Authorization: `Bearer ${apiKey}`,
|
|
25683
|
+
"Content-Type": "application/json",
|
|
25684
|
+
Accept: "application/json",
|
|
25685
|
+
"User-Agent": USER_AGENT
|
|
25686
|
+
};
|
|
25687
|
+
try {
|
|
25688
|
+
const response = await fetchFn(url, {
|
|
25689
|
+
method: "GET",
|
|
25690
|
+
headers,
|
|
25691
|
+
signal: AbortSignal.timeout(15000)
|
|
25692
|
+
});
|
|
25693
|
+
if (!response.ok) {
|
|
25694
|
+
throw new BrandsightApiError(`Brandsight API GET ${path} failed with status ${response.status}`, response.status, await response.text());
|
|
25695
|
+
}
|
|
25696
|
+
const data = await response.json();
|
|
25697
|
+
return { data, stub: false };
|
|
25698
|
+
} catch (error) {
|
|
25699
|
+
if (error instanceof BrandsightApiError)
|
|
25700
|
+
throw error;
|
|
25701
|
+
return { data: null, stub: true };
|
|
25702
|
+
}
|
|
25703
|
+
}
|
|
25704
|
+
function generateStubAlerts(brandName) {
|
|
25705
|
+
const now = new Date().toISOString();
|
|
25706
|
+
return [
|
|
25707
|
+
{ domain: `${brandName}-deals.com`, type: "keyword", registered_at: now },
|
|
25708
|
+
{ domain: `${brandName.replace(/a/gi, "4").replace(/e/gi, "3")}.com`, type: "homoglyph", registered_at: now },
|
|
25709
|
+
{ domain: `${brandName}s.com`, type: "typosquat", registered_at: now }
|
|
25710
|
+
];
|
|
25711
|
+
}
|
|
25712
|
+
function generateStubSimilarDomains(domain) {
|
|
25713
|
+
const base = domain.replace(/\.[^.]+$/, "");
|
|
25714
|
+
const tld = domain.slice(base.length);
|
|
25715
|
+
return [
|
|
25716
|
+
`${base}-online${tld}`,
|
|
25717
|
+
`${base}s${tld}`,
|
|
25718
|
+
`${base.replace(/a/gi, "4")}${tld}`,
|
|
25719
|
+
`${base}-app${tld}`,
|
|
25720
|
+
`get${base}${tld}`
|
|
25721
|
+
];
|
|
25722
|
+
}
|
|
25723
|
+
function generateStubThreatAssessment(domain) {
|
|
25724
|
+
return {
|
|
25725
|
+
domain,
|
|
25726
|
+
risk_level: "low",
|
|
25727
|
+
threats: [],
|
|
25728
|
+
recommendation: "No immediate threats detected. Continue routine monitoring."
|
|
25729
|
+
};
|
|
25730
|
+
}
|
|
25731
|
+
async function monitorBrand(brandName) {
|
|
25732
|
+
const apiKey = getApiKey();
|
|
25733
|
+
const result = await apiGet(`/brands/${encodeURIComponent(brandName)}/monitor`, apiKey);
|
|
25734
|
+
if (result.stub) {
|
|
25735
|
+
return { brand: brandName, alerts: generateStubAlerts(brandName), stub: true };
|
|
25736
|
+
}
|
|
25737
|
+
return { brand: brandName, alerts: result.data.alerts, stub: false };
|
|
25738
|
+
}
|
|
25739
|
+
async function getSimilarDomains(domain) {
|
|
25740
|
+
const apiKey = getApiKey();
|
|
25741
|
+
const result = await apiGet(`/domains/${encodeURIComponent(domain)}/similar`, apiKey);
|
|
25742
|
+
if (result.stub) {
|
|
25743
|
+
return { domain, similar: generateStubSimilarDomains(domain), stub: true };
|
|
25744
|
+
}
|
|
25745
|
+
return { domain, similar: result.data.similar, stub: false };
|
|
25746
|
+
}
|
|
25747
|
+
async function getThreatAssessment(domain) {
|
|
25748
|
+
const apiKey = getApiKey();
|
|
25749
|
+
const result = await apiGet(`/domains/${encodeURIComponent(domain)}/threats`, apiKey);
|
|
25750
|
+
if (result.stub) {
|
|
25751
|
+
return { ...generateStubThreatAssessment(domain), stub: true };
|
|
25752
|
+
}
|
|
25753
|
+
return { ...result.data, stub: false };
|
|
25754
|
+
}
|
|
25755
|
+
async function listDomains2(config) {
|
|
25756
|
+
const cfg = config ?? getConfig4();
|
|
25757
|
+
const result = await apiGet("/portfolio/domains", cfg.apiKey);
|
|
25758
|
+
if (result.stub)
|
|
25759
|
+
return [];
|
|
25760
|
+
return result.data.domains ?? [];
|
|
25761
|
+
}
|
|
25762
|
+
async function getDomainInfo3(domain, config) {
|
|
25763
|
+
const cfg = config ?? getConfig4();
|
|
25764
|
+
const result = await apiGet(`/portfolio/domains/${encodeURIComponent(domain)}`, cfg.apiKey);
|
|
25765
|
+
if (result.stub)
|
|
25766
|
+
return null;
|
|
25767
|
+
return result.data;
|
|
25768
|
+
}
|
|
25769
|
+
async function checkAvailability4(domain, config) {
|
|
25770
|
+
const cfg = config ?? getConfig4();
|
|
25771
|
+
const result = await apiGet(`/domains/check?domain=${encodeURIComponent(domain)}`, cfg.apiKey);
|
|
25772
|
+
if (result.stub)
|
|
25773
|
+
return { domain, available: false };
|
|
25774
|
+
return result.data;
|
|
25775
|
+
}
|
|
25776
|
+
async function renewDomain3(domain, years = 1, config) {
|
|
25777
|
+
const cfg = config ?? getConfig4();
|
|
25778
|
+
const result = await apiRequest3("POST", `/portfolio/domains/${encodeURIComponent(domain)}/renew`, cfg.apiKey, { years });
|
|
25779
|
+
if (result.stub)
|
|
25780
|
+
return { success: false };
|
|
25781
|
+
return { success: true, orderId: result.data.orderId };
|
|
25782
|
+
}
|
|
25783
|
+
async function syncToLocalDb3(dbFns, config) {
|
|
25784
|
+
const domains = await listDomains2(config);
|
|
25785
|
+
let synced = 0, created = 0, updated = 0;
|
|
25786
|
+
const errors = [];
|
|
25787
|
+
for (const d3 of domains) {
|
|
25788
|
+
try {
|
|
25789
|
+
const existing = dbFns.getDomainByName(d3.domain);
|
|
25790
|
+
if (existing) {
|
|
25791
|
+
dbFns.updateDomain(existing.id, {
|
|
25792
|
+
registrar: "Brandsight",
|
|
25793
|
+
expires_at: d3.expires || undefined,
|
|
25794
|
+
auto_renew: d3.auto_renew,
|
|
25795
|
+
status: "active",
|
|
25796
|
+
nameservers: d3.nameservers
|
|
25797
|
+
});
|
|
25798
|
+
updated++;
|
|
25799
|
+
} else {
|
|
25800
|
+
dbFns.createDomain({
|
|
25801
|
+
name: d3.domain,
|
|
25802
|
+
registrar: "Brandsight",
|
|
25803
|
+
expires_at: d3.expires || undefined,
|
|
25804
|
+
auto_renew: d3.auto_renew,
|
|
25805
|
+
status: "active",
|
|
25806
|
+
nameservers: d3.nameservers
|
|
25807
|
+
});
|
|
25808
|
+
created++;
|
|
25809
|
+
}
|
|
25810
|
+
synced++;
|
|
25811
|
+
} catch (err) {
|
|
25812
|
+
errors.push(`${d3.domain}: ${err instanceof Error ? err.message : String(err)}`);
|
|
25813
|
+
}
|
|
25814
|
+
}
|
|
25815
|
+
return { synced, created, updated, errors };
|
|
25816
|
+
}
|
|
25817
|
+
function createBrandsightProvider(config) {
|
|
25818
|
+
const cfg = config ?? getConfig4();
|
|
25819
|
+
return {
|
|
25820
|
+
name: "brandsight",
|
|
25821
|
+
async listDomains() {
|
|
25822
|
+
const domains = await listDomains2(cfg);
|
|
25823
|
+
return domains.map((d3) => ({
|
|
25824
|
+
domain: d3.domain,
|
|
25825
|
+
registrar: "Brandsight",
|
|
25826
|
+
created: "",
|
|
25827
|
+
expires: d3.expires,
|
|
25828
|
+
nameservers: d3.nameservers,
|
|
25829
|
+
status: d3.status === "ACTIVE" ? "active" : d3.status.toLowerCase(),
|
|
25830
|
+
auto_renew: d3.auto_renew
|
|
25831
|
+
}));
|
|
25832
|
+
},
|
|
25833
|
+
async getDomainInfo(domain) {
|
|
25834
|
+
const d3 = await getDomainInfo3(domain, cfg);
|
|
25835
|
+
if (!d3)
|
|
25836
|
+
throw new Error(`Domain not found in Brandsight: ${domain}`);
|
|
25837
|
+
return {
|
|
25838
|
+
domain: d3.domain,
|
|
25839
|
+
registrar: "Brandsight",
|
|
25840
|
+
created: "",
|
|
25841
|
+
expires: d3.expires,
|
|
25842
|
+
nameservers: d3.nameservers,
|
|
25843
|
+
status: d3.status === "ACTIVE" ? "active" : d3.status.toLowerCase(),
|
|
25844
|
+
auto_renew: d3.auto_renew
|
|
25845
|
+
};
|
|
25846
|
+
},
|
|
25847
|
+
async renewDomain(domain) {
|
|
25848
|
+
const result = await renewDomain3(domain, 1, cfg);
|
|
25849
|
+
return { domain, success: result.success, orderId: result.orderId };
|
|
25850
|
+
},
|
|
25851
|
+
async checkAvailability(domain) {
|
|
25852
|
+
const result = await checkAvailability4(domain, cfg);
|
|
25853
|
+
return {
|
|
25854
|
+
domain: result.domain,
|
|
25855
|
+
available: result.available,
|
|
25856
|
+
standard_price: result.price,
|
|
25857
|
+
currency: result.currency
|
|
25858
|
+
};
|
|
25859
|
+
},
|
|
25860
|
+
async syncToLocalDb(dbFns) {
|
|
25861
|
+
return syncToLocalDb3(dbFns, cfg);
|
|
25862
|
+
}
|
|
25863
|
+
};
|
|
25864
|
+
}
|
|
25865
|
+
var BrandsightApiError, _fetchFn = null, BRANDSIGHT_BASE = "https://api.brandsight.com/v1";
|
|
25866
|
+
var init_brandsight = __esm(() => {
|
|
25867
|
+
init_version();
|
|
25868
|
+
BrandsightApiError = class BrandsightApiError extends Error {
|
|
25869
|
+
statusCode;
|
|
25870
|
+
responseBody;
|
|
25871
|
+
constructor(message, statusCode, responseBody) {
|
|
25872
|
+
super(message);
|
|
25873
|
+
this.statusCode = statusCode;
|
|
25874
|
+
this.responseBody = responseBody;
|
|
25875
|
+
this.name = "BrandsightApiError";
|
|
25876
|
+
}
|
|
25877
|
+
};
|
|
25878
|
+
});
|
|
25879
|
+
|
|
25880
|
+
// src/lib/creds-check.ts
|
|
25881
|
+
var exports_creds_check = {};
|
|
25882
|
+
__export(exports_creds_check, {
|
|
25883
|
+
checkProvisioningCredentials: () => checkProvisioningCredentials
|
|
25884
|
+
});
|
|
25885
|
+
function checkProvisioningCredentials(env = process.env) {
|
|
25886
|
+
const out = [];
|
|
25887
|
+
const hasAws = !!(env["AWS_ACCESS_KEY_ID"] && env["AWS_SECRET_ACCESS_KEY"]) || !!env["AWS_PROFILE"];
|
|
25888
|
+
out.push({
|
|
25889
|
+
provider: "route53",
|
|
25890
|
+
configured: hasAws,
|
|
25891
|
+
mode: env["AWS_PROFILE"] ? `profile:${env["AWS_PROFILE"]}` : hasAws ? "access-keys" : "none",
|
|
25892
|
+
detail: hasAws ? "AWS credentials present (region us-east-1 for Route53 Domains)" : "Set AWS_PROFILE or AWS_ACCESS_KEY_ID/SECRET"
|
|
25893
|
+
});
|
|
25894
|
+
const cf = resolveCloudflareConfig(env);
|
|
25895
|
+
const cfMode = cf.apiToken ? "token" : cf.apiKey && cf.email ? "global-key" : "none";
|
|
25896
|
+
out.push({
|
|
25897
|
+
provider: "cloudflare",
|
|
25898
|
+
configured: cfMode !== "none",
|
|
25899
|
+
mode: cfMode + (cf.accountId ? "+account" : ""),
|
|
25900
|
+
detail: cfMode === "none" ? "Set CLOUDFLARE_API_TOKEN or CLOUDFLARE_API_KEY+CLOUDFLARE_EMAIL" : cf.accountId ? "ok" : "missing CLOUDFLARE_ACCOUNT_ID (needed to create zones)"
|
|
25901
|
+
});
|
|
25902
|
+
const bs = resolveBrandsightConfig(env);
|
|
25903
|
+
const bsConfigured = !!(bs.apiKey && bs.apiSecret && bs.customerId);
|
|
25904
|
+
out.push({
|
|
25905
|
+
provider: "brandsight",
|
|
25906
|
+
configured: bsConfigured,
|
|
25907
|
+
mode: bsConfigured ? "full-creds" : "none",
|
|
25908
|
+
detail: "enterprise/contract-only (gated) \u2014 not used for automated purchase"
|
|
25909
|
+
});
|
|
25910
|
+
const gd = !!(env["GODADDY_API_KEY"] && env["GODADDY_API_SECRET"]);
|
|
25911
|
+
out.push({ provider: "godaddy", configured: gd, mode: gd ? "key+secret" : "none", detail: "retail API gated for purchase/DNS since 2024" });
|
|
25912
|
+
return out;
|
|
25913
|
+
}
|
|
25914
|
+
var init_creds_check = __esm(() => {
|
|
25915
|
+
init_brandsight();
|
|
25916
|
+
});
|
|
25917
|
+
|
|
25602
25918
|
// src/db/domain-history.ts
|
|
25603
25919
|
function rowToDomainHistory(row) {
|
|
25604
25920
|
return {
|
|
@@ -33085,15 +33401,10 @@ function createRoute53Provider(config) {
|
|
|
33085
33401
|
|
|
33086
33402
|
// src/lib/cloudflare.ts
|
|
33087
33403
|
function getConfig3() {
|
|
33088
|
-
return
|
|
33089
|
-
apiToken: process.env["CLOUDFLARE_API_TOKEN"],
|
|
33090
|
-
accountId: process.env["CLOUDFLARE_ACCOUNT_ID"]
|
|
33091
|
-
};
|
|
33404
|
+
return resolveCloudflareConfig();
|
|
33092
33405
|
}
|
|
33093
33406
|
function checkCredentials2(cfg) {
|
|
33094
|
-
|
|
33095
|
-
throw new Error("Cloudflare credentials not configured. Set CLOUDFLARE_API_TOKEN environment variable.");
|
|
33096
|
-
}
|
|
33407
|
+
cloudflareAuthHeaders(cfg);
|
|
33097
33408
|
}
|
|
33098
33409
|
var CF_BASE = "https://api.cloudflare.com/client/v4";
|
|
33099
33410
|
async function cfFetch(path, opts = {}) {
|
|
@@ -33102,7 +33413,7 @@ async function cfFetch(path, opts = {}) {
|
|
|
33102
33413
|
const res = await fetch(`${CF_BASE}${path}`, {
|
|
33103
33414
|
method: opts.method ?? "GET",
|
|
33104
33415
|
headers: {
|
|
33105
|
-
|
|
33416
|
+
...cloudflareAuthHeaders(cfg),
|
|
33106
33417
|
"Content-Type": "application/json"
|
|
33107
33418
|
},
|
|
33108
33419
|
body: opts.body ? JSON.stringify(opts.body) : undefined
|
|
@@ -33209,250 +33520,8 @@ function createCloudflareProvider(config) {
|
|
|
33209
33520
|
};
|
|
33210
33521
|
}
|
|
33211
33522
|
|
|
33212
|
-
// src/lib/brandsight.ts
|
|
33213
|
-
init_version();
|
|
33214
|
-
|
|
33215
|
-
class BrandsightApiError extends Error {
|
|
33216
|
-
statusCode;
|
|
33217
|
-
responseBody;
|
|
33218
|
-
constructor(message, statusCode, responseBody) {
|
|
33219
|
-
super(message);
|
|
33220
|
-
this.statusCode = statusCode;
|
|
33221
|
-
this.responseBody = responseBody;
|
|
33222
|
-
this.name = "BrandsightApiError";
|
|
33223
|
-
}
|
|
33224
|
-
}
|
|
33225
|
-
var _fetchFn = null;
|
|
33226
|
-
function getApiKey() {
|
|
33227
|
-
const key = process.env["BRANDSIGHT_API_KEY"];
|
|
33228
|
-
if (!key) {
|
|
33229
|
-
throw new BrandsightApiError("BRANDSIGHT_API_KEY environment variable is not set");
|
|
33230
|
-
}
|
|
33231
|
-
return key;
|
|
33232
|
-
}
|
|
33233
|
-
function getConfig4() {
|
|
33234
|
-
return {
|
|
33235
|
-
apiKey: process.env["BRANDSIGHT_API_KEY"] ?? "",
|
|
33236
|
-
accountId: process.env["BRANDSIGHT_ACCOUNT_ID"]
|
|
33237
|
-
};
|
|
33238
|
-
}
|
|
33239
|
-
var BRANDSIGHT_BASE = "https://api.brandsight.com/v1";
|
|
33240
|
-
async function apiRequest3(method, path, apiKey, body, baseUrl = BRANDSIGHT_BASE) {
|
|
33241
|
-
const fetchFn = _fetchFn || globalThis.fetch;
|
|
33242
|
-
const url = `${baseUrl}${path}`;
|
|
33243
|
-
const headers = {
|
|
33244
|
-
Authorization: `Bearer ${apiKey}`,
|
|
33245
|
-
"Content-Type": "application/json",
|
|
33246
|
-
Accept: "application/json",
|
|
33247
|
-
"User-Agent": USER_AGENT
|
|
33248
|
-
};
|
|
33249
|
-
try {
|
|
33250
|
-
const response = await fetchFn(url, {
|
|
33251
|
-
method,
|
|
33252
|
-
headers,
|
|
33253
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
33254
|
-
signal: AbortSignal.timeout(15000)
|
|
33255
|
-
});
|
|
33256
|
-
if (!response.ok) {
|
|
33257
|
-
throw new BrandsightApiError(`Brandsight API ${method} ${path} failed with status ${response.status}`, response.status, await response.text());
|
|
33258
|
-
}
|
|
33259
|
-
const data = await response.json();
|
|
33260
|
-
return { data, stub: false };
|
|
33261
|
-
} catch (error) {
|
|
33262
|
-
if (error instanceof BrandsightApiError)
|
|
33263
|
-
throw error;
|
|
33264
|
-
return { data: null, stub: true };
|
|
33265
|
-
}
|
|
33266
|
-
}
|
|
33267
|
-
async function apiGet(path, apiKey, baseUrl = BRANDSIGHT_BASE) {
|
|
33268
|
-
const fetchFn = _fetchFn || globalThis.fetch;
|
|
33269
|
-
const url = `${baseUrl}${path}`;
|
|
33270
|
-
const headers = {
|
|
33271
|
-
Authorization: `Bearer ${apiKey}`,
|
|
33272
|
-
"Content-Type": "application/json",
|
|
33273
|
-
Accept: "application/json",
|
|
33274
|
-
"User-Agent": USER_AGENT
|
|
33275
|
-
};
|
|
33276
|
-
try {
|
|
33277
|
-
const response = await fetchFn(url, {
|
|
33278
|
-
method: "GET",
|
|
33279
|
-
headers,
|
|
33280
|
-
signal: AbortSignal.timeout(15000)
|
|
33281
|
-
});
|
|
33282
|
-
if (!response.ok) {
|
|
33283
|
-
throw new BrandsightApiError(`Brandsight API GET ${path} failed with status ${response.status}`, response.status, await response.text());
|
|
33284
|
-
}
|
|
33285
|
-
const data = await response.json();
|
|
33286
|
-
return { data, stub: false };
|
|
33287
|
-
} catch (error) {
|
|
33288
|
-
if (error instanceof BrandsightApiError)
|
|
33289
|
-
throw error;
|
|
33290
|
-
return { data: null, stub: true };
|
|
33291
|
-
}
|
|
33292
|
-
}
|
|
33293
|
-
function generateStubAlerts(brandName) {
|
|
33294
|
-
const now = new Date().toISOString();
|
|
33295
|
-
return [
|
|
33296
|
-
{ domain: `${brandName}-deals.com`, type: "keyword", registered_at: now },
|
|
33297
|
-
{ domain: `${brandName.replace(/a/gi, "4").replace(/e/gi, "3")}.com`, type: "homoglyph", registered_at: now },
|
|
33298
|
-
{ domain: `${brandName}s.com`, type: "typosquat", registered_at: now }
|
|
33299
|
-
];
|
|
33300
|
-
}
|
|
33301
|
-
function generateStubSimilarDomains(domain) {
|
|
33302
|
-
const base = domain.replace(/\.[^.]+$/, "");
|
|
33303
|
-
const tld = domain.slice(base.length);
|
|
33304
|
-
return [
|
|
33305
|
-
`${base}-online${tld}`,
|
|
33306
|
-
`${base}s${tld}`,
|
|
33307
|
-
`${base.replace(/a/gi, "4")}${tld}`,
|
|
33308
|
-
`${base}-app${tld}`,
|
|
33309
|
-
`get${base}${tld}`
|
|
33310
|
-
];
|
|
33311
|
-
}
|
|
33312
|
-
function generateStubThreatAssessment(domain) {
|
|
33313
|
-
return {
|
|
33314
|
-
domain,
|
|
33315
|
-
risk_level: "low",
|
|
33316
|
-
threats: [],
|
|
33317
|
-
recommendation: "No immediate threats detected. Continue routine monitoring."
|
|
33318
|
-
};
|
|
33319
|
-
}
|
|
33320
|
-
async function monitorBrand(brandName) {
|
|
33321
|
-
const apiKey = getApiKey();
|
|
33322
|
-
const result = await apiGet(`/brands/${encodeURIComponent(brandName)}/monitor`, apiKey);
|
|
33323
|
-
if (result.stub) {
|
|
33324
|
-
return { brand: brandName, alerts: generateStubAlerts(brandName), stub: true };
|
|
33325
|
-
}
|
|
33326
|
-
return { brand: brandName, alerts: result.data.alerts, stub: false };
|
|
33327
|
-
}
|
|
33328
|
-
async function getSimilarDomains(domain) {
|
|
33329
|
-
const apiKey = getApiKey();
|
|
33330
|
-
const result = await apiGet(`/domains/${encodeURIComponent(domain)}/similar`, apiKey);
|
|
33331
|
-
if (result.stub) {
|
|
33332
|
-
return { domain, similar: generateStubSimilarDomains(domain), stub: true };
|
|
33333
|
-
}
|
|
33334
|
-
return { domain, similar: result.data.similar, stub: false };
|
|
33335
|
-
}
|
|
33336
|
-
async function getThreatAssessment(domain) {
|
|
33337
|
-
const apiKey = getApiKey();
|
|
33338
|
-
const result = await apiGet(`/domains/${encodeURIComponent(domain)}/threats`, apiKey);
|
|
33339
|
-
if (result.stub) {
|
|
33340
|
-
return { ...generateStubThreatAssessment(domain), stub: true };
|
|
33341
|
-
}
|
|
33342
|
-
return { ...result.data, stub: false };
|
|
33343
|
-
}
|
|
33344
|
-
async function listDomains2(config) {
|
|
33345
|
-
const cfg = config ?? getConfig4();
|
|
33346
|
-
const result = await apiGet("/portfolio/domains", cfg.apiKey);
|
|
33347
|
-
if (result.stub)
|
|
33348
|
-
return [];
|
|
33349
|
-
return result.data.domains ?? [];
|
|
33350
|
-
}
|
|
33351
|
-
async function getDomainInfo3(domain, config) {
|
|
33352
|
-
const cfg = config ?? getConfig4();
|
|
33353
|
-
const result = await apiGet(`/portfolio/domains/${encodeURIComponent(domain)}`, cfg.apiKey);
|
|
33354
|
-
if (result.stub)
|
|
33355
|
-
return null;
|
|
33356
|
-
return result.data;
|
|
33357
|
-
}
|
|
33358
|
-
async function checkAvailability4(domain, config) {
|
|
33359
|
-
const cfg = config ?? getConfig4();
|
|
33360
|
-
const result = await apiGet(`/domains/check?domain=${encodeURIComponent(domain)}`, cfg.apiKey);
|
|
33361
|
-
if (result.stub)
|
|
33362
|
-
return { domain, available: false };
|
|
33363
|
-
return result.data;
|
|
33364
|
-
}
|
|
33365
|
-
async function renewDomain3(domain, years = 1, config) {
|
|
33366
|
-
const cfg = config ?? getConfig4();
|
|
33367
|
-
const result = await apiRequest3("POST", `/portfolio/domains/${encodeURIComponent(domain)}/renew`, cfg.apiKey, { years });
|
|
33368
|
-
if (result.stub)
|
|
33369
|
-
return { success: false };
|
|
33370
|
-
return { success: true, orderId: result.data.orderId };
|
|
33371
|
-
}
|
|
33372
|
-
async function syncToLocalDb3(dbFns, config) {
|
|
33373
|
-
const domains = await listDomains2(config);
|
|
33374
|
-
let synced = 0, created = 0, updated = 0;
|
|
33375
|
-
const errors = [];
|
|
33376
|
-
for (const d3 of domains) {
|
|
33377
|
-
try {
|
|
33378
|
-
const existing = dbFns.getDomainByName(d3.domain);
|
|
33379
|
-
if (existing) {
|
|
33380
|
-
dbFns.updateDomain(existing.id, {
|
|
33381
|
-
registrar: "Brandsight",
|
|
33382
|
-
expires_at: d3.expires || undefined,
|
|
33383
|
-
auto_renew: d3.auto_renew,
|
|
33384
|
-
status: "active",
|
|
33385
|
-
nameservers: d3.nameservers
|
|
33386
|
-
});
|
|
33387
|
-
updated++;
|
|
33388
|
-
} else {
|
|
33389
|
-
dbFns.createDomain({
|
|
33390
|
-
name: d3.domain,
|
|
33391
|
-
registrar: "Brandsight",
|
|
33392
|
-
expires_at: d3.expires || undefined,
|
|
33393
|
-
auto_renew: d3.auto_renew,
|
|
33394
|
-
status: "active",
|
|
33395
|
-
nameservers: d3.nameservers
|
|
33396
|
-
});
|
|
33397
|
-
created++;
|
|
33398
|
-
}
|
|
33399
|
-
synced++;
|
|
33400
|
-
} catch (err) {
|
|
33401
|
-
errors.push(`${d3.domain}: ${err instanceof Error ? err.message : String(err)}`);
|
|
33402
|
-
}
|
|
33403
|
-
}
|
|
33404
|
-
return { synced, created, updated, errors };
|
|
33405
|
-
}
|
|
33406
|
-
function createBrandsightProvider(config) {
|
|
33407
|
-
const cfg = config ?? getConfig4();
|
|
33408
|
-
return {
|
|
33409
|
-
name: "brandsight",
|
|
33410
|
-
async listDomains() {
|
|
33411
|
-
const domains = await listDomains2(cfg);
|
|
33412
|
-
return domains.map((d3) => ({
|
|
33413
|
-
domain: d3.domain,
|
|
33414
|
-
registrar: "Brandsight",
|
|
33415
|
-
created: "",
|
|
33416
|
-
expires: d3.expires,
|
|
33417
|
-
nameservers: d3.nameservers,
|
|
33418
|
-
status: d3.status === "ACTIVE" ? "active" : d3.status.toLowerCase(),
|
|
33419
|
-
auto_renew: d3.auto_renew
|
|
33420
|
-
}));
|
|
33421
|
-
},
|
|
33422
|
-
async getDomainInfo(domain) {
|
|
33423
|
-
const d3 = await getDomainInfo3(domain, cfg);
|
|
33424
|
-
if (!d3)
|
|
33425
|
-
throw new Error(`Domain not found in Brandsight: ${domain}`);
|
|
33426
|
-
return {
|
|
33427
|
-
domain: d3.domain,
|
|
33428
|
-
registrar: "Brandsight",
|
|
33429
|
-
created: "",
|
|
33430
|
-
expires: d3.expires,
|
|
33431
|
-
nameservers: d3.nameservers,
|
|
33432
|
-
status: d3.status === "ACTIVE" ? "active" : d3.status.toLowerCase(),
|
|
33433
|
-
auto_renew: d3.auto_renew
|
|
33434
|
-
};
|
|
33435
|
-
},
|
|
33436
|
-
async renewDomain(domain) {
|
|
33437
|
-
const result = await renewDomain3(domain, 1, cfg);
|
|
33438
|
-
return { domain, success: result.success, orderId: result.orderId };
|
|
33439
|
-
},
|
|
33440
|
-
async checkAvailability(domain) {
|
|
33441
|
-
const result = await checkAvailability4(domain, cfg);
|
|
33442
|
-
return {
|
|
33443
|
-
domain: result.domain,
|
|
33444
|
-
available: result.available,
|
|
33445
|
-
standard_price: result.price,
|
|
33446
|
-
currency: result.currency
|
|
33447
|
-
};
|
|
33448
|
-
},
|
|
33449
|
-
async syncToLocalDb(dbFns) {
|
|
33450
|
-
return syncToLocalDb3(dbFns, cfg);
|
|
33451
|
-
}
|
|
33452
|
-
};
|
|
33453
|
-
}
|
|
33454
|
-
|
|
33455
33523
|
// src/lib/registrar.ts
|
|
33524
|
+
init_brandsight();
|
|
33456
33525
|
function createNamecheapProvider() {
|
|
33457
33526
|
return {
|
|
33458
33527
|
name: "namecheap",
|
|
@@ -34832,6 +34901,7 @@ function registerAlertCommands(program2) {
|
|
|
34832
34901
|
}
|
|
34833
34902
|
|
|
34834
34903
|
// src/cli/commands/monitor.ts
|
|
34904
|
+
init_brandsight();
|
|
34835
34905
|
function registerMonitorCommand(program2) {
|
|
34836
34906
|
const monitor = program2.command("monitor").description("Brand monitoring and threat detection (Brandsight)");
|
|
34837
34907
|
monitor.command("watch <brand>").description("Monitor a brand for new lookalike domain registrations").option("--json", "Output JSON").action(async (brand, opts) => {
|
|
@@ -35276,6 +35346,14 @@ function registerDoctorCommand(program2) {
|
|
|
35276
35346
|
ok("Registrant contact info complete");
|
|
35277
35347
|
else
|
|
35278
35348
|
fail(`Missing contact fields: ${missingContact.join(", ")}`, "domains config set contact.<field> <value>");
|
|
35349
|
+
section("Provisioning Credentials");
|
|
35350
|
+
const { checkProvisioningCredentials: checkProvisioningCredentials2 } = await Promise.resolve().then(() => (init_creds_check(), exports_creds_check));
|
|
35351
|
+
for (const c3 of checkProvisioningCredentials2()) {
|
|
35352
|
+
if (c3.configured)
|
|
35353
|
+
ok(`${c3.provider}: ${c3.mode} \u2014 ${c3.detail}`);
|
|
35354
|
+
else
|
|
35355
|
+
fail(`${c3.provider}: not configured (${c3.detail})`);
|
|
35356
|
+
}
|
|
35279
35357
|
section("Providers");
|
|
35280
35358
|
const providers = getAvailableProviders().filter((p3) => p3.name !== "brandsight");
|
|
35281
35359
|
for (const p3 of providers) {
|
|
@@ -37333,6 +37411,67 @@ function registerWalletCommand(program2) {
|
|
|
37333
37411
|
});
|
|
37334
37412
|
}
|
|
37335
37413
|
|
|
37414
|
+
// src/lib/provision-state.ts
|
|
37415
|
+
var DOMAIN_FLOW = {
|
|
37416
|
+
requested: { action: "register", next: "registered" },
|
|
37417
|
+
registered: { action: "create_cf_zone", next: "cf_zone_ready" },
|
|
37418
|
+
cf_zone_ready: { action: "delegate_ns", next: "ns_delegated" },
|
|
37419
|
+
ns_delegated: { action: "check_ns_propagation", next: "ns_propagated" },
|
|
37420
|
+
ns_propagated: { action: "verify_dns", next: "dns_managed" },
|
|
37421
|
+
dns_managed: { action: "finalize", next: "ready" }
|
|
37422
|
+
};
|
|
37423
|
+
var TERMINAL = new Set(["ready", "failed"]);
|
|
37424
|
+
function domainHappyPath() {
|
|
37425
|
+
return [...Object.keys(DOMAIN_FLOW), "ready"];
|
|
37426
|
+
}
|
|
37427
|
+
function deriveDomainState(sig) {
|
|
37428
|
+
if (!sig.registered)
|
|
37429
|
+
return "requested";
|
|
37430
|
+
if (!sig.zoneExists)
|
|
37431
|
+
return "registered";
|
|
37432
|
+
if (!sig.registrarNsAreCloudflare)
|
|
37433
|
+
return "cf_zone_ready";
|
|
37434
|
+
if (!sig.publicNsAreCloudflare)
|
|
37435
|
+
return "ns_delegated";
|
|
37436
|
+
if (!sig.zoneActive)
|
|
37437
|
+
return "ns_propagated";
|
|
37438
|
+
return "ready";
|
|
37439
|
+
}
|
|
37440
|
+
|
|
37441
|
+
// src/cli/commands/provision.ts
|
|
37442
|
+
var CF_NS_SUFFIX = ".ns.cloudflare.com";
|
|
37443
|
+
function registerProvisionCommand(program2) {
|
|
37444
|
+
const provision = program2.command("provision").description("Domain provisioning lifecycle");
|
|
37445
|
+
provision.command("status <name>").description("Show the provisioning state of a domain (derived from live signals)").action(async (name) => {
|
|
37446
|
+
const signals = {};
|
|
37447
|
+
try {
|
|
37448
|
+
const detail = await getDomainDetail(name).catch(() => null);
|
|
37449
|
+
signals["registered"] = !!detail;
|
|
37450
|
+
const registrarNs = detail?.nameservers ?? [];
|
|
37451
|
+
signals["registrarNsAreCloudflare"] = registrarNs.length > 0 && registrarNs.every((n3) => n3.includes(CF_NS_SUFFIX));
|
|
37452
|
+
const zone = await getZone(name).catch(() => null);
|
|
37453
|
+
signals["zoneExists"] = !!zone;
|
|
37454
|
+
signals["zoneActive"] = zone?.status === "active";
|
|
37455
|
+
try {
|
|
37456
|
+
const resolved = await (await import("dns")).promises.resolveNs(name).catch(() => []);
|
|
37457
|
+
signals["publicNsAreCloudflare"] = resolved.length > 0 && resolved.every((n3) => n3.includes(CF_NS_SUFFIX));
|
|
37458
|
+
} catch {
|
|
37459
|
+
signals["publicNsAreCloudflare"] = false;
|
|
37460
|
+
}
|
|
37461
|
+
} catch (e3) {
|
|
37462
|
+
console.error(`Error gathering signals: ${e3 instanceof Error ? e3.message : String(e3)}`);
|
|
37463
|
+
}
|
|
37464
|
+
const state = deriveDomainState(signals);
|
|
37465
|
+
console.log(`
|
|
37466
|
+
Domain: ${name}`);
|
|
37467
|
+
console.log(`State: ${state}`);
|
|
37468
|
+
console.log(`Signals: ${JSON.stringify(signals)}`);
|
|
37469
|
+
const path = domainHappyPath();
|
|
37470
|
+
const idx = path.indexOf(state);
|
|
37471
|
+
console.log(`Progress: ${idx >= 0 ? idx + 1 : "?"}/${path.length} [${path.join(" \u2192 ")}]`);
|
|
37472
|
+
});
|
|
37473
|
+
}
|
|
37474
|
+
|
|
37336
37475
|
// src/cli/index.ts
|
|
37337
37476
|
init_version();
|
|
37338
37477
|
var program2 = new Command;
|
|
@@ -37356,4 +37495,5 @@ registerResearchCommand(program2);
|
|
|
37356
37495
|
registerOutreachCommand(program2);
|
|
37357
37496
|
registerSedoCommand(program2);
|
|
37358
37497
|
registerWalletCommand(program2);
|
|
37498
|
+
registerProvisionCommand(program2);
|
|
37359
37499
|
program2.parse(process.argv);
|