@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/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
- if (!cfg.apiToken) {
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
- Authorization: `Bearer ${cfg.apiToken}`,
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);