@hasna/domains 0.0.36 → 0.0.37
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/alerts.d.ts.map +1 -1
- package/dist/cli/commands/brandsight.d.ts.map +1 -1
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/db.d.ts.map +1 -1
- package/dist/cli/commands/dns.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/domain.d.ts.map +1 -1
- package/dist/cli/commands/history.d.ts.map +1 -1
- package/dist/cli/commands/interactive.d.ts +7 -1
- package/dist/cli/commands/interactive.d.ts.map +1 -1
- package/dist/cli/commands/mcp-install.d.ts.map +1 -1
- package/dist/cli/commands/monitor.d.ts.map +1 -1
- package/dist/cli/commands/outreach.d.ts.map +1 -1
- package/dist/cli/commands/owner.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/provision.d.ts.map +1 -1
- package/dist/cli/commands/reconcile-expiry.d.ts.map +1 -1
- package/dist/cli/commands/research.d.ts.map +1 -1
- package/dist/cli/commands/route53.d.ts.map +1 -1
- package/dist/cli/commands/sedo.d.ts.map +1 -1
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/ssl.d.ts.map +1 -1
- package/dist/cli/commands/wallet.d.ts.map +1 -1
- package/dist/cli/commands/zone.d.ts.map +1 -1
- package/dist/cli/index.js +823 -730
- package/dist/db/dns-tools.d.ts.map +1 -1
- package/dist/index.js +16 -9
- package/dist/lib/stdout.d.ts +54 -0
- package/dist/lib/stdout.d.ts.map +1 -0
- package/dist/mcp/index.js +16 -9
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -16256,6 +16256,9 @@ function normalizeDnsRecordType(value) {
|
|
|
16256
16256
|
}
|
|
16257
16257
|
return recordType3;
|
|
16258
16258
|
}
|
|
16259
|
+
function getVcardPropertyValue(entry) {
|
|
16260
|
+
return entry.length >= 4 ? entry[3] : entry[2];
|
|
16261
|
+
}
|
|
16259
16262
|
async function rdapLookup(domainName) {
|
|
16260
16263
|
const domain = normalizeDomainName(domainName);
|
|
16261
16264
|
const url = `https://rdap.org/domain/${encodeURIComponent(domain)}`;
|
|
@@ -16304,17 +16307,19 @@ function extractRegistrantFromRdap(rdap) {
|
|
|
16304
16307
|
for (const entry of vcard) {
|
|
16305
16308
|
if (!Array.isArray(entry) || entry.length < 3)
|
|
16306
16309
|
continue;
|
|
16307
|
-
const [prop
|
|
16310
|
+
const [prop] = entry;
|
|
16311
|
+
const value = getVcardPropertyValue(entry);
|
|
16308
16312
|
if (prop === "fn")
|
|
16309
|
-
result.name =
|
|
16313
|
+
result.name = typeof value === "string" ? value : null;
|
|
16310
16314
|
else if (prop === "email")
|
|
16311
|
-
result.email =
|
|
16315
|
+
result.email = typeof value === "string" ? value : null;
|
|
16312
16316
|
else if (prop === "tel")
|
|
16313
|
-
result.phone =
|
|
16317
|
+
result.phone = typeof value === "string" ? value : null;
|
|
16314
16318
|
else if (prop === "org") {
|
|
16315
|
-
|
|
16319
|
+
const organization = Array.isArray(value) ? value[0] : value;
|
|
16320
|
+
result.organization = typeof organization === "string" ? organization : null;
|
|
16316
16321
|
} else if (prop === "n" && !result.name) {
|
|
16317
|
-
const parts = Array.isArray(
|
|
16322
|
+
const parts = Array.isArray(value) ? value.filter((part) => typeof part === "string" && part.length > 0) : typeof value === "string" ? [value] : [];
|
|
16318
16323
|
result.name = parts.reverse().join(" ").trim() || null;
|
|
16319
16324
|
}
|
|
16320
16325
|
}
|
|
@@ -16331,8 +16336,10 @@ function extractRegistrarFromRdap(rdap) {
|
|
|
16331
16336
|
if (entity.vcardArray?.[1]) {
|
|
16332
16337
|
const vcard = entity.vcardArray[1];
|
|
16333
16338
|
for (const entry of vcard) {
|
|
16334
|
-
if (Array.isArray(entry) && entry[0] === "fn")
|
|
16335
|
-
|
|
16339
|
+
if (Array.isArray(entry) && entry[0] === "fn") {
|
|
16340
|
+
const value = getVcardPropertyValue(entry);
|
|
16341
|
+
return typeof value === "string" ? value : null;
|
|
16342
|
+
}
|
|
16336
16343
|
}
|
|
16337
16344
|
}
|
|
16338
16345
|
if (entity.remarks) {
|
|
@@ -28939,7 +28946,7 @@ var init_bowser = __esm(() => {
|
|
|
28939
28946
|
|
|
28940
28947
|
// node_modules/@aws-sdk/core/dist-cjs/submodules/client/index.js
|
|
28941
28948
|
var require_client2 = __commonJS((exports) => {
|
|
28942
|
-
var __dirname = "/home/hasna/.hasna/repos/worktrees/open-domains/
|
|
28949
|
+
var __dirname = "/home/hasna/.hasna/repos/worktrees/open-domains/2a0dcf21-d730-4a74-bfc3-12e59e51ecd5/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
|
|
28943
28950
|
var retry = require_retry();
|
|
28944
28951
|
var protocols = require_protocols();
|
|
28945
28952
|
var lambdaInvokeStore = require_invoke_store();
|
|
@@ -51383,6 +51390,65 @@ function compactHint(page, noun, detailHint, options = {}) {
|
|
|
51383
51390
|
}
|
|
51384
51391
|
var DEFAULT_LIST_LIMIT = 20, MAX_LIST_LIMIT = 200;
|
|
51385
51392
|
|
|
51393
|
+
// src/lib/stdout.ts
|
|
51394
|
+
import { writeSync } from "fs";
|
|
51395
|
+
import { format } from "util";
|
|
51396
|
+
function awaitDrain() {
|
|
51397
|
+
Atomics.wait(backpressureWait, 0, 0, BACKPRESSURE_WAIT_MS);
|
|
51398
|
+
}
|
|
51399
|
+
function errorCodeOf(error) {
|
|
51400
|
+
if (typeof error !== "object" || error === null)
|
|
51401
|
+
return null;
|
|
51402
|
+
const code = error.code;
|
|
51403
|
+
return typeof code === "string" ? code : null;
|
|
51404
|
+
}
|
|
51405
|
+
function writeAllBytesSync(bytes, writer) {
|
|
51406
|
+
let offset = 0;
|
|
51407
|
+
while (offset < bytes.length) {
|
|
51408
|
+
let accepted;
|
|
51409
|
+
try {
|
|
51410
|
+
accepted = writer(bytes.subarray(offset));
|
|
51411
|
+
} catch (error) {
|
|
51412
|
+
const code = errorCodeOf(error);
|
|
51413
|
+
if (code === "EAGAIN" || code === "EWOULDBLOCK") {
|
|
51414
|
+
awaitDrain();
|
|
51415
|
+
continue;
|
|
51416
|
+
}
|
|
51417
|
+
if (code === "EPIPE" || code === "ERR_STREAM_DESTROYED")
|
|
51418
|
+
return "reader-closed";
|
|
51419
|
+
throw error;
|
|
51420
|
+
}
|
|
51421
|
+
if (accepted <= 0) {
|
|
51422
|
+
awaitDrain();
|
|
51423
|
+
continue;
|
|
51424
|
+
}
|
|
51425
|
+
offset += accepted;
|
|
51426
|
+
}
|
|
51427
|
+
return "complete";
|
|
51428
|
+
}
|
|
51429
|
+
function writeAllSync(text, writer) {
|
|
51430
|
+
return writeAllBytesSync(Buffer.from(text, "utf8"), writer);
|
|
51431
|
+
}
|
|
51432
|
+
function writeStdout(text, writer = stdoutWriter) {
|
|
51433
|
+
return writeAllSync(text, writer);
|
|
51434
|
+
}
|
|
51435
|
+
function formatLine(...args) {
|
|
51436
|
+
return `${format(...args)}
|
|
51437
|
+
`;
|
|
51438
|
+
}
|
|
51439
|
+
function printLine(...args) {
|
|
51440
|
+
return writeStdout(formatLine(...args));
|
|
51441
|
+
}
|
|
51442
|
+
function printErrorLine(...args) {
|
|
51443
|
+
return writeAllSync(formatLine(...args), stderrWriter);
|
|
51444
|
+
}
|
|
51445
|
+
var BACKPRESSURE_WAIT_MS = 1, backpressureWait, fdWriter = (fd) => (chunk) => writeSync(fd, chunk), stdoutWriter, stderrWriter;
|
|
51446
|
+
var init_stdout = __esm(() => {
|
|
51447
|
+
backpressureWait = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
51448
|
+
stdoutWriter = fdWriter(1);
|
|
51449
|
+
stderrWriter = fdWriter(2);
|
|
51450
|
+
});
|
|
51451
|
+
|
|
51386
51452
|
// src/db/history.ts
|
|
51387
51453
|
function createHistoryEntry2(input) {
|
|
51388
51454
|
return getStore().createHistoryEntry(input);
|
|
@@ -51772,22 +51838,22 @@ function registerMonitorCommand(program2) {
|
|
|
51772
51838
|
try {
|
|
51773
51839
|
const result = await monitorBrand(brand);
|
|
51774
51840
|
if (opts.json) {
|
|
51775
|
-
|
|
51841
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51776
51842
|
return;
|
|
51777
51843
|
}
|
|
51778
51844
|
const page = pageItemsOrExit(result.alerts, { limit: opts.limit, all: opts.all });
|
|
51779
|
-
|
|
51845
|
+
printLine(`Monitor: ${result.brand}${result.stub ? " [stub]" : ""}`);
|
|
51780
51846
|
if (page.items.length === 0) {
|
|
51781
|
-
|
|
51847
|
+
printLine("No alerts.");
|
|
51782
51848
|
return;
|
|
51783
51849
|
}
|
|
51784
51850
|
for (const alert of page.items) {
|
|
51785
|
-
|
|
51851
|
+
printLine(` ${alert.domain} [${alert.type}] registered:${alert.registered_at}`);
|
|
51786
51852
|
}
|
|
51787
|
-
|
|
51853
|
+
printLine(`
|
|
51788
51854
|
${compactHint(page, "alert(s)", "Use --all for every alert or --json for full monitor details.", { paging: "limit" })}`);
|
|
51789
51855
|
} catch (e4) {
|
|
51790
|
-
|
|
51856
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
51791
51857
|
process.exit(1);
|
|
51792
51858
|
}
|
|
51793
51859
|
});
|
|
@@ -51795,21 +51861,21 @@ ${compactHint(page, "alert(s)", "Use --all for every alert or --json for full mo
|
|
|
51795
51861
|
try {
|
|
51796
51862
|
const result = await getSimilarDomains(domain);
|
|
51797
51863
|
if (opts.json) {
|
|
51798
|
-
|
|
51864
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51799
51865
|
return;
|
|
51800
51866
|
}
|
|
51801
51867
|
const page = pageItemsOrExit(result.similar, { limit: opts.limit, all: opts.all });
|
|
51802
|
-
|
|
51868
|
+
printLine(`Similar domains for ${result.domain}${result.stub ? " [stub]" : ""}:`);
|
|
51803
51869
|
if (page.items.length === 0) {
|
|
51804
|
-
|
|
51870
|
+
printLine("No similar domains found.");
|
|
51805
51871
|
return;
|
|
51806
51872
|
}
|
|
51807
51873
|
for (const name of page.items)
|
|
51808
|
-
|
|
51809
|
-
|
|
51874
|
+
printLine(` ${name}`);
|
|
51875
|
+
printLine(`
|
|
51810
51876
|
${compactHint(page, "domain(s)", "Use --all for every result or --json for full response metadata.", { paging: "limit" })}`);
|
|
51811
51877
|
} catch (e4) {
|
|
51812
|
-
|
|
51878
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
51813
51879
|
process.exit(1);
|
|
51814
51880
|
}
|
|
51815
51881
|
});
|
|
@@ -51817,28 +51883,29 @@ ${compactHint(page, "domain(s)", "Use --all for every result or --json for full
|
|
|
51817
51883
|
try {
|
|
51818
51884
|
const result = await getThreatAssessment(domain);
|
|
51819
51885
|
if (opts.json) {
|
|
51820
|
-
|
|
51886
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51821
51887
|
return;
|
|
51822
51888
|
}
|
|
51823
51889
|
const page = pageItemsOrExit(result.threats, { limit: opts.limit, all: opts.all });
|
|
51824
|
-
|
|
51890
|
+
printLine(`Threat assessment for ${result.domain}${result.stub ? " [stub]" : ""}: ${result.risk_level}`);
|
|
51825
51891
|
if (page.items.length === 0) {
|
|
51826
|
-
|
|
51892
|
+
printLine("No immediate threats detected.");
|
|
51827
51893
|
} else {
|
|
51828
51894
|
for (const threat of page.items)
|
|
51829
|
-
|
|
51895
|
+
printLine(` - ${truncateText(threat, 100)}`);
|
|
51830
51896
|
}
|
|
51831
|
-
|
|
51832
|
-
|
|
51897
|
+
printLine(`Recommendation: ${truncateText(result.recommendation, 140)}`);
|
|
51898
|
+
printLine(`
|
|
51833
51899
|
${compactHint(page, "threat(s)", "Use --all for every threat or --json for the full assessment.", { paging: "limit" })}`);
|
|
51834
51900
|
} catch (e4) {
|
|
51835
|
-
|
|
51901
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
51836
51902
|
process.exit(1);
|
|
51837
51903
|
}
|
|
51838
51904
|
});
|
|
51839
51905
|
}
|
|
51840
51906
|
var init_monitor = __esm(() => {
|
|
51841
51907
|
init_brandsight();
|
|
51908
|
+
init_stdout();
|
|
51842
51909
|
});
|
|
51843
51910
|
|
|
51844
51911
|
// src/cli/commands/sedo.ts
|
|
@@ -51851,7 +51918,7 @@ function parseSedoLimit(value, fallback) {
|
|
|
51851
51918
|
return fallback;
|
|
51852
51919
|
const parsed = Number(value);
|
|
51853
51920
|
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
51854
|
-
|
|
51921
|
+
printErrorLine("--limit must be a non-negative integer");
|
|
51855
51922
|
process.exit(1);
|
|
51856
51923
|
}
|
|
51857
51924
|
return parsed;
|
|
@@ -51868,19 +51935,19 @@ function registerSedoCommand(program2) {
|
|
|
51868
51935
|
maxPrice: opts.maxPrice ? parseInt(opts.maxPrice) : undefined
|
|
51869
51936
|
});
|
|
51870
51937
|
if (opts.json) {
|
|
51871
|
-
|
|
51938
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51872
51939
|
} else {
|
|
51873
51940
|
if (result.domains.length === 0) {
|
|
51874
|
-
|
|
51941
|
+
printLine(`No domains found for "${keyword}".`);
|
|
51875
51942
|
return;
|
|
51876
51943
|
}
|
|
51877
|
-
|
|
51944
|
+
printLine(`Sedo marketplace \u2014 "${keyword}" (${result.total} total):`);
|
|
51878
51945
|
for (const d4 of result.domains) {
|
|
51879
51946
|
const price = d4.price ? ` \u2014 ${d4.price.toLocaleString()} ${d4.currency || ""}`.trimEnd() : " \u2014 make offer";
|
|
51880
51947
|
const premium = d4.isPremium ? " [PREMIUM]" : "";
|
|
51881
|
-
|
|
51948
|
+
printLine(` ${d4.domain}${price}${premium}`);
|
|
51882
51949
|
}
|
|
51883
|
-
|
|
51950
|
+
printLine(`
|
|
51884
51951
|
Showing ${result.domains.length}/${result.total} marketplace result(s). Use --limit <n> for more or --json for full fields.`);
|
|
51885
51952
|
}
|
|
51886
51953
|
});
|
|
@@ -51888,12 +51955,12 @@ Showing ${result.domains.length}/${result.total} marketplace result(s). Use --li
|
|
|
51888
51955
|
const { checkSedoStatus: checkSedoStatus2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
|
|
51889
51956
|
const results = await checkSedoStatus2(domains);
|
|
51890
51957
|
if (opts.json) {
|
|
51891
|
-
|
|
51958
|
+
printLine(JSON.stringify(results, null, 2));
|
|
51892
51959
|
} else {
|
|
51893
51960
|
for (const r4 of results) {
|
|
51894
51961
|
const listed = r4.listed ? "listed" : "not listed";
|
|
51895
51962
|
const sale = r4.forSale ? ` for sale (${r4.price || "?"} ${r4.currency || ""})` : "";
|
|
51896
|
-
|
|
51963
|
+
printLine(` ${r4.domain}: ${listed}${sale}`);
|
|
51897
51964
|
}
|
|
51898
51965
|
}
|
|
51899
51966
|
});
|
|
@@ -51902,19 +51969,19 @@ Showing ${result.domains.length}/${result.total} marketplace result(s). Use --li
|
|
|
51902
51969
|
const limit = parseSedoLimit(opts.limit, opts.json || opts.all ? 100 : 20);
|
|
51903
51970
|
const domains = await listSedoPortfolio2({ limit });
|
|
51904
51971
|
if (opts.json) {
|
|
51905
|
-
|
|
51972
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
51906
51973
|
} else {
|
|
51907
51974
|
if (domains.length === 0) {
|
|
51908
|
-
|
|
51975
|
+
printLine("No domains in your Sedo portfolio.");
|
|
51909
51976
|
return;
|
|
51910
51977
|
}
|
|
51911
51978
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
51912
|
-
|
|
51979
|
+
printLine(`Sedo Portfolio:`);
|
|
51913
51980
|
for (const d4 of page.items) {
|
|
51914
51981
|
const sale = d4.forSale ? `[for sale ${d4.price || "?"} ${d4.currency || ""}]` : "";
|
|
51915
|
-
|
|
51982
|
+
printLine(` ${d4.domain} ${sale}`);
|
|
51916
51983
|
}
|
|
51917
|
-
|
|
51984
|
+
printLine(`
|
|
51918
51985
|
${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full marketplace fields.", { paging: "limit" })}`);
|
|
51919
51986
|
}
|
|
51920
51987
|
});
|
|
@@ -51929,9 +51996,9 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51929
51996
|
buyNowPrice: opts.buyNowPrice ? parseInt(opts.buyNowPrice) : undefined
|
|
51930
51997
|
});
|
|
51931
51998
|
if (opts.json) {
|
|
51932
|
-
|
|
51999
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51933
52000
|
} else {
|
|
51934
|
-
|
|
52001
|
+
printLine(`Added ${domain} to Sedo marketplace`);
|
|
51935
52002
|
}
|
|
51936
52003
|
});
|
|
51937
52004
|
sedo.command("edit").description("Update an existing domain on Sedo").argument("<domain>", "Domain name to update").option("--price <n>", "New asking price").option("--currency <currency>", "Currency").option("--buy-now-price <n>", "New buy-it-now price").option("--json", "Output as JSON", false).action(async (domain, opts) => {
|
|
@@ -51943,18 +52010,18 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51943
52010
|
buyNowPrice: opts.buyNowPrice ? parseInt(opts.buyNowPrice) : undefined
|
|
51944
52011
|
});
|
|
51945
52012
|
if (opts.json) {
|
|
51946
|
-
|
|
52013
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51947
52014
|
} else {
|
|
51948
|
-
|
|
52015
|
+
printLine(`Updated ${domain} on Sedo`);
|
|
51949
52016
|
}
|
|
51950
52017
|
});
|
|
51951
52018
|
sedo.command("remove").description("Remove a domain from Sedo marketplace").argument("<domain>", "Domain name to remove").action(async (domain) => {
|
|
51952
52019
|
const { removeDomainFromSedo: removeDomainFromSedo2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
|
|
51953
52020
|
const removed = await removeDomainFromSedo2(domain);
|
|
51954
52021
|
if (removed) {
|
|
51955
|
-
|
|
52022
|
+
printLine(`Removed ${domain} from Sedo marketplace`);
|
|
51956
52023
|
} else {
|
|
51957
|
-
|
|
52024
|
+
printErrorLine(`Failed to remove ${domain} from Sedo`);
|
|
51958
52025
|
process.exit(1);
|
|
51959
52026
|
}
|
|
51960
52027
|
});
|
|
@@ -51962,10 +52029,10 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51962
52029
|
const { checkSedoBlacklist: checkSedoBlacklist2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
|
|
51963
52030
|
const results = await checkSedoBlacklist2(domains);
|
|
51964
52031
|
if (opts.json) {
|
|
51965
|
-
|
|
52032
|
+
printLine(JSON.stringify(results, null, 2));
|
|
51966
52033
|
} else {
|
|
51967
52034
|
for (const r4 of results) {
|
|
51968
|
-
|
|
52035
|
+
printLine(` ${r4.domain}: ${r4.blacklisted ? "BLACKLISTED" : "clean"}`);
|
|
51969
52036
|
}
|
|
51970
52037
|
}
|
|
51971
52038
|
});
|
|
@@ -51974,13 +52041,15 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51974
52041
|
const price = parseInt(opts.price);
|
|
51975
52042
|
const created = recordSedoPurchase2(domain, price, opts.orderId);
|
|
51976
52043
|
if (opts.json) {
|
|
51977
|
-
|
|
52044
|
+
printLine(JSON.stringify(created, null, 2));
|
|
51978
52045
|
} else {
|
|
51979
|
-
|
|
52046
|
+
printLine(`Recorded Sedo purchase: ${domain} for $${price}`);
|
|
51980
52047
|
}
|
|
51981
52048
|
});
|
|
51982
52049
|
}
|
|
51983
|
-
var init_sedo2 = () => {
|
|
52050
|
+
var init_sedo2 = __esm(() => {
|
|
52051
|
+
init_stdout();
|
|
52052
|
+
});
|
|
51984
52053
|
|
|
51985
52054
|
// src/db/owners.ts
|
|
51986
52055
|
function createDomainOwner2(input) {
|
|
@@ -52073,7 +52142,7 @@ __export(exports_owner, {
|
|
|
52073
52142
|
async function requireDomain2(identifier) {
|
|
52074
52143
|
const details = await getDomainDetails2(identifier);
|
|
52075
52144
|
if (!details) {
|
|
52076
|
-
|
|
52145
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52077
52146
|
process.exit(1);
|
|
52078
52147
|
}
|
|
52079
52148
|
return details;
|
|
@@ -52084,21 +52153,21 @@ function registerOwnerCommand(program2) {
|
|
|
52084
52153
|
if (opts.withDomains) {
|
|
52085
52154
|
const results = await listDomainsWithOwners2();
|
|
52086
52155
|
if (opts.json) {
|
|
52087
|
-
|
|
52156
|
+
printLine(JSON.stringify({ owners: results, count: results.length }, null, 2));
|
|
52088
52157
|
return;
|
|
52089
52158
|
}
|
|
52090
52159
|
const page2 = pageItemsOrExit(results, { limit: opts.limit, all: opts.all });
|
|
52091
52160
|
if (page2.items.length === 0) {
|
|
52092
|
-
|
|
52161
|
+
printLine("No premium domain owners found.");
|
|
52093
52162
|
return;
|
|
52094
52163
|
}
|
|
52095
52164
|
for (const r4 of page2.items) {
|
|
52096
52165
|
const verified = r4.verified ? " [verified]" : "";
|
|
52097
52166
|
const org = r4.owner_organization ? ` @ ${r4.owner_organization}` : "";
|
|
52098
52167
|
const email = opts.verbose && r4.owner_email ? ` email:${r4.owner_email}` : "";
|
|
52099
|
-
|
|
52168
|
+
printLine(` ${r4.domain_name} (${r4.domain_status}) \u2014 ${r4.owner_name ?? r4.owner_email ?? "unknown"}${org}${verified}${email}`);
|
|
52100
52169
|
}
|
|
52101
|
-
|
|
52170
|
+
printLine(`
|
|
52102
52171
|
${compactHint(page2, "domain(s) with owner info", "Use --verbose for email details or owner info <domain> for full details.", { paging: "limit" })}`);
|
|
52103
52172
|
return;
|
|
52104
52173
|
}
|
|
@@ -52108,87 +52177,87 @@ ${compactHint(page2, "domain(s) with owner info", "Use --verbose for email detai
|
|
|
52108
52177
|
verified: opts.verifiedOnly ? true : undefined
|
|
52109
52178
|
});
|
|
52110
52179
|
if (opts.json) {
|
|
52111
|
-
|
|
52180
|
+
printLine(JSON.stringify({ owners, count: owners.length }, null, 2));
|
|
52112
52181
|
return;
|
|
52113
52182
|
}
|
|
52114
52183
|
const page = pageItemsOrExit(owners, { limit: opts.limit, all: opts.all });
|
|
52115
52184
|
if (page.items.length === 0) {
|
|
52116
|
-
|
|
52185
|
+
printLine("No owners found.");
|
|
52117
52186
|
return;
|
|
52118
52187
|
}
|
|
52119
52188
|
for (const o2 of page.items) {
|
|
52120
52189
|
const verified = o2.verified ? " [verified]" : "";
|
|
52121
52190
|
const org = o2.owner_organization ? ` @ ${o2.owner_organization}` : "";
|
|
52122
|
-
|
|
52191
|
+
printLine(` ${truncateText(o2.owner_name ?? o2.owner_email ?? "unknown", 48)}${org} [${o2.source}]${verified}`);
|
|
52123
52192
|
if (opts.verbose && o2.owner_email)
|
|
52124
|
-
|
|
52193
|
+
printLine(` email: ${o2.owner_email}`);
|
|
52125
52194
|
if (opts.verbose && o2.owner_phone)
|
|
52126
|
-
|
|
52195
|
+
printLine(` phone: ${o2.owner_phone}`);
|
|
52127
52196
|
}
|
|
52128
|
-
|
|
52197
|
+
printLine(`
|
|
52129
52198
|
${compactHint(page, "owner(s)", "Use --verbose for contact fields or owner get <id> for details.", { paging: "limit" })}`);
|
|
52130
52199
|
});
|
|
52131
52200
|
owner.command("get <ownerId>").description("Get owner details by ID").option("-j, --json", "Output JSON").action(async (ownerId, opts) => {
|
|
52132
52201
|
const o2 = await getDomainOwner2(ownerId);
|
|
52133
52202
|
if (!o2) {
|
|
52134
|
-
|
|
52203
|
+
printErrorLine(`Owner '${ownerId}' not found.`);
|
|
52135
52204
|
process.exit(1);
|
|
52136
52205
|
}
|
|
52137
52206
|
if (opts.json) {
|
|
52138
|
-
|
|
52207
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52139
52208
|
return;
|
|
52140
52209
|
}
|
|
52141
|
-
|
|
52210
|
+
printLine(`
|
|
52142
52211
|
Owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52143
52212
|
if (o2.owner_organization)
|
|
52144
|
-
|
|
52213
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52145
52214
|
if (o2.owner_email)
|
|
52146
|
-
|
|
52215
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52147
52216
|
if (o2.owner_phone)
|
|
52148
|
-
|
|
52149
|
-
|
|
52150
|
-
|
|
52217
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52218
|
+
printLine(` Source: ${o2.source}`);
|
|
52219
|
+
printLine(` Verified: ${o2.verified ? "yes" : "no"}`);
|
|
52151
52220
|
if (o2.contact_id)
|
|
52152
|
-
|
|
52221
|
+
printLine(` Contacts ID: ${o2.contact_id}`);
|
|
52153
52222
|
if (o2.notes)
|
|
52154
|
-
|
|
52155
|
-
|
|
52223
|
+
printLine(` Notes: ${truncateText(o2.notes, 160)}`);
|
|
52224
|
+
printLine();
|
|
52156
52225
|
});
|
|
52157
52226
|
owner.command("info <identifier>").description("Show owner info for a specific domain").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52158
52227
|
const details = await requireDomain2(identifier);
|
|
52159
52228
|
const o2 = await getDomainOwnerByDomain2(details.domain.id);
|
|
52160
52229
|
if (!o2) {
|
|
52161
52230
|
if (opts.json) {
|
|
52162
|
-
|
|
52231
|
+
printLine(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
|
|
52163
52232
|
return;
|
|
52164
52233
|
}
|
|
52165
|
-
|
|
52234
|
+
printLine(`No owner info for ${details.domain.name}.`);
|
|
52166
52235
|
return;
|
|
52167
52236
|
}
|
|
52168
52237
|
const result = { domain: details.domain.name, owner: o2 };
|
|
52169
52238
|
if (opts.json) {
|
|
52170
|
-
|
|
52239
|
+
printLine(JSON.stringify(result, null, 2));
|
|
52171
52240
|
return;
|
|
52172
52241
|
}
|
|
52173
|
-
|
|
52242
|
+
printLine(`
|
|
52174
52243
|
Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
52175
|
-
|
|
52244
|
+
printLine(` Owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52176
52245
|
if (o2.owner_organization)
|
|
52177
|
-
|
|
52246
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52178
52247
|
if (o2.owner_email)
|
|
52179
|
-
|
|
52248
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52180
52249
|
if (o2.owner_phone)
|
|
52181
|
-
|
|
52182
|
-
|
|
52183
|
-
|
|
52250
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52251
|
+
printLine(` Source: ${o2.source}`);
|
|
52252
|
+
printLine(` Verified: ${o2.verified ? "yes" : "no"}`);
|
|
52184
52253
|
if (o2.contact_id)
|
|
52185
|
-
|
|
52186
|
-
|
|
52254
|
+
printLine(` Contacts ID: ${o2.contact_id}`);
|
|
52255
|
+
printLine();
|
|
52187
52256
|
});
|
|
52188
52257
|
owner.command("add <identifier>").description("Add owner info for a domain").option("--name <name>", "Owner name").option("--email <email>", "Owner email").option("--phone <phone>", "Owner phone").option("--organization <org>", "Owner organization").option("--source <source>", "Source (whois/manual/brandsight/import)", "manual").option("--contact-id <id>", "Link to existing open-contacts contact ID").option("--verified", "Mark as verified").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52189
52258
|
const details = await requireDomain2(identifier);
|
|
52190
52259
|
if (!opts.name && !opts.email && !opts.organization && !opts.contactId) {
|
|
52191
|
-
|
|
52260
|
+
printErrorLine("At least one of --name, --email, --organization, or --contact-id is required.");
|
|
52192
52261
|
process.exit(1);
|
|
52193
52262
|
}
|
|
52194
52263
|
const input = {
|
|
@@ -52204,15 +52273,15 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
|
52204
52273
|
};
|
|
52205
52274
|
const o2 = await createDomainOwner2(input);
|
|
52206
52275
|
if (opts.json) {
|
|
52207
|
-
|
|
52276
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52208
52277
|
return;
|
|
52209
52278
|
}
|
|
52210
|
-
|
|
52279
|
+
printLine(`Added owner for ${details.domain.name}: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52211
52280
|
});
|
|
52212
52281
|
owner.command("update <ownerId>").description("Update owner info").option("--name <name>", "Owner name").option("--email <email>", "Owner email").option("--phone <phone>", "Owner phone").option("--organization <org>", "Owner organization").option("--contact-id <id>", "Link to open-contacts contact ID").option("--verified", "Mark as verified").option("--unverify", "Unmark as verified").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (ownerId, opts) => {
|
|
52213
52282
|
const existing = await getDomainOwner2(ownerId);
|
|
52214
52283
|
if (!existing) {
|
|
52215
|
-
|
|
52284
|
+
printErrorLine(`Owner '${ownerId}' not found.`);
|
|
52216
52285
|
process.exit(1);
|
|
52217
52286
|
}
|
|
52218
52287
|
const update = {};
|
|
@@ -52234,72 +52303,72 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
|
52234
52303
|
update.notes = opts.notes;
|
|
52235
52304
|
const o2 = await updateDomainOwner2(ownerId, update);
|
|
52236
52305
|
if (!o2) {
|
|
52237
|
-
|
|
52306
|
+
printErrorLine("Update failed.");
|
|
52238
52307
|
process.exit(1);
|
|
52239
52308
|
}
|
|
52240
52309
|
if (opts.json) {
|
|
52241
|
-
|
|
52310
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52242
52311
|
return;
|
|
52243
52312
|
}
|
|
52244
|
-
|
|
52313
|
+
printLine(`Updated owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52245
52314
|
});
|
|
52246
52315
|
owner.command("delete <ownerId>").description("Delete an owner record").option("-f, --force", "Required confirmation").action(async (ownerId, opts) => {
|
|
52247
52316
|
if (!opts.force) {
|
|
52248
|
-
|
|
52317
|
+
printErrorLine(`Refusing to delete owner '${ownerId}' without --force.`);
|
|
52249
52318
|
process.exit(1);
|
|
52250
52319
|
}
|
|
52251
52320
|
const deleted = await deleteDomainOwner2(ownerId);
|
|
52252
52321
|
if (!deleted) {
|
|
52253
|
-
|
|
52322
|
+
printErrorLine(`Owner '${ownerId}' not found.`);
|
|
52254
52323
|
process.exit(1);
|
|
52255
52324
|
}
|
|
52256
|
-
|
|
52325
|
+
printLine(`Deleted owner ${ownerId}`);
|
|
52257
52326
|
});
|
|
52258
52327
|
owner.command("extract <identifier>").description("Extract owner info from WHOIS lookup").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52259
52328
|
const details = await requireDomain2(identifier);
|
|
52260
52329
|
const whois = await whoisLookup(details.domain.name);
|
|
52261
52330
|
if (!whois.raw) {
|
|
52262
|
-
|
|
52331
|
+
printErrorLine("WHOIS returned no data.");
|
|
52263
52332
|
process.exit(1);
|
|
52264
52333
|
}
|
|
52265
52334
|
const o2 = await extractOwnerFromWhois(details.domain.name, whois.raw);
|
|
52266
52335
|
if (!o2) {
|
|
52267
|
-
|
|
52336
|
+
printLine("No owner information found in WHOIS data.");
|
|
52268
52337
|
return;
|
|
52269
52338
|
}
|
|
52270
52339
|
if (opts.json) {
|
|
52271
|
-
|
|
52340
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52272
52341
|
return;
|
|
52273
52342
|
}
|
|
52274
|
-
|
|
52343
|
+
printLine(`Extracted owner for ${details.domain.name}:`);
|
|
52275
52344
|
if (o2.owner_name)
|
|
52276
|
-
|
|
52345
|
+
printLine(` Name: ${o2.owner_name}`);
|
|
52277
52346
|
if (o2.owner_email)
|
|
52278
|
-
|
|
52347
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52279
52348
|
if (o2.owner_phone)
|
|
52280
|
-
|
|
52349
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52281
52350
|
if (o2.owner_organization)
|
|
52282
|
-
|
|
52283
|
-
|
|
52351
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52352
|
+
printLine();
|
|
52284
52353
|
});
|
|
52285
52354
|
owner.command("link <identifier>").description("Link domain owner to open-contacts contact").option("--contact-id <id>", "Existing contact ID in open-contacts").option("--auto", "Auto-create contact from owner info").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52286
52355
|
const details = await requireDomain2(identifier);
|
|
52287
52356
|
const o2 = await getDomainOwnerByDomain2(details.domain.id);
|
|
52288
52357
|
if (!o2) {
|
|
52289
|
-
|
|
52358
|
+
printErrorLine(`No owner record for ${details.domain.name}. Add one first.`);
|
|
52290
52359
|
process.exit(1);
|
|
52291
52360
|
}
|
|
52292
52361
|
if (opts.contactId) {
|
|
52293
52362
|
const updated = await updateDomainOwner2(o2.id, { contact_id: opts.contactId });
|
|
52294
52363
|
if (!updated) {
|
|
52295
|
-
|
|
52364
|
+
printErrorLine("Link failed.");
|
|
52296
52365
|
process.exit(1);
|
|
52297
52366
|
}
|
|
52298
52367
|
if (opts.json) {
|
|
52299
|
-
|
|
52368
|
+
printLine(JSON.stringify(updated, null, 2));
|
|
52300
52369
|
return;
|
|
52301
52370
|
}
|
|
52302
|
-
|
|
52371
|
+
printLine(`Linked ${details.domain.name} to contact ${opts.contactId}`);
|
|
52303
52372
|
return;
|
|
52304
52373
|
}
|
|
52305
52374
|
if (opts.auto) {
|
|
@@ -52311,64 +52380,65 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
|
52311
52380
|
getContactByEmail: (email) => contacts.getContactByEmail(email)
|
|
52312
52381
|
});
|
|
52313
52382
|
if (!contactId) {
|
|
52314
|
-
|
|
52383
|
+
printErrorLine("Could not create/find contact \u2014 owner has no email.");
|
|
52315
52384
|
process.exit(1);
|
|
52316
52385
|
}
|
|
52317
52386
|
if (opts.json) {
|
|
52318
|
-
|
|
52387
|
+
printLine(JSON.stringify({ domain: details.domain.name, contact_id: contactId }, null, 2));
|
|
52319
52388
|
return;
|
|
52320
52389
|
}
|
|
52321
|
-
|
|
52390
|
+
printLine(`Created/linked contact ${contactId} for ${details.domain.name}`);
|
|
52322
52391
|
} catch (e4) {
|
|
52323
52392
|
const message = e4 instanceof Error ? e4.message : String(e4);
|
|
52324
52393
|
if (typeof e4 === "object" && e4 !== null && "code" in e4 && e4.code === "MODULE_NOT_FOUND" || message.includes("@hasna/contacts")) {
|
|
52325
|
-
|
|
52394
|
+
printErrorLine("@hasna/contacts is not installed. Install it alongside @hasna/domains, or pass --contact-id to link an existing contact ID.");
|
|
52326
52395
|
} else {
|
|
52327
|
-
|
|
52396
|
+
printErrorLine(`Failed to link to open-contacts: ${message}`);
|
|
52328
52397
|
}
|
|
52329
52398
|
process.exit(1);
|
|
52330
52399
|
}
|
|
52331
52400
|
return;
|
|
52332
52401
|
}
|
|
52333
|
-
|
|
52402
|
+
printErrorLine("Use --contact-id <id> or --auto to link.");
|
|
52334
52403
|
process.exit(1);
|
|
52335
52404
|
});
|
|
52336
52405
|
owner.command("whois <identifier>").description("WHOIS lookup and save owner info").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52337
52406
|
const details = await requireDomain2(identifier);
|
|
52338
52407
|
const whois = await whoisLookup(details.domain.name);
|
|
52339
52408
|
if (!whois.raw) {
|
|
52340
|
-
|
|
52409
|
+
printErrorLine("WHOIS returned no data.");
|
|
52341
52410
|
process.exit(1);
|
|
52342
52411
|
}
|
|
52343
52412
|
const o2 = await extractOwnerFromWhois(details.domain.name, whois.raw);
|
|
52344
52413
|
if (!o2) {
|
|
52345
52414
|
if (opts.json) {
|
|
52346
|
-
|
|
52415
|
+
printLine(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
|
|
52347
52416
|
return;
|
|
52348
52417
|
}
|
|
52349
|
-
|
|
52418
|
+
printLine("No owner information found in WHOIS data.");
|
|
52350
52419
|
return;
|
|
52351
52420
|
}
|
|
52352
52421
|
if (opts.json) {
|
|
52353
|
-
|
|
52422
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52354
52423
|
return;
|
|
52355
52424
|
}
|
|
52356
|
-
|
|
52425
|
+
printLine(`WHOIS owner for ${details.domain.name}:`);
|
|
52357
52426
|
if (o2.owner_name)
|
|
52358
|
-
|
|
52427
|
+
printLine(` Name: ${o2.owner_name}`);
|
|
52359
52428
|
if (o2.owner_email)
|
|
52360
|
-
|
|
52429
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52361
52430
|
if (o2.owner_phone)
|
|
52362
|
-
|
|
52431
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52363
52432
|
if (o2.owner_organization)
|
|
52364
|
-
|
|
52365
|
-
|
|
52366
|
-
|
|
52433
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52434
|
+
printLine(` Source: ${o2.source}`);
|
|
52435
|
+
printLine();
|
|
52367
52436
|
});
|
|
52368
52437
|
}
|
|
52369
52438
|
var init_owner = __esm(() => {
|
|
52370
52439
|
init_owners();
|
|
52371
52440
|
init_domains();
|
|
52441
|
+
init_stdout();
|
|
52372
52442
|
});
|
|
52373
52443
|
|
|
52374
52444
|
// src/cli/commands/history.ts
|
|
@@ -52381,7 +52451,7 @@ function registerHistoryCommand(program2) {
|
|
|
52381
52451
|
history.command("list <identifier>").description("List history entries for a domain").option("--type <type>", "Filter by type (whois/rdap/dns/ssl/reputation/exa_research)").option("--limit <n>", "Limit results", "20").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52382
52452
|
const domain = await getDomainDetails2(identifier);
|
|
52383
52453
|
if (!domain) {
|
|
52384
|
-
|
|
52454
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52385
52455
|
process.exit(1);
|
|
52386
52456
|
}
|
|
52387
52457
|
const entries = await getHistoryByDomain2(domain.domain.id, {
|
|
@@ -52389,94 +52459,95 @@ function registerHistoryCommand(program2) {
|
|
|
52389
52459
|
limit: opts.limit ? parseInt(opts.limit) : undefined
|
|
52390
52460
|
});
|
|
52391
52461
|
if (opts.json) {
|
|
52392
|
-
|
|
52462
|
+
printLine(JSON.stringify({ domain: domain.domain.name, history: entries, count: entries.length }, null, 2));
|
|
52393
52463
|
return;
|
|
52394
52464
|
}
|
|
52395
52465
|
if (entries.length === 0) {
|
|
52396
|
-
|
|
52466
|
+
printLine(`No history entries for ${domain.domain.name}.`);
|
|
52397
52467
|
return;
|
|
52398
52468
|
}
|
|
52399
|
-
|
|
52469
|
+
printLine(`History for ${domain.domain.name}:`);
|
|
52400
52470
|
for (const e4 of entries) {
|
|
52401
|
-
|
|
52471
|
+
printLine(` [${e4.created_at}] ${e4.snapshot_type} \u2014 ${e4.registrant_name ?? e4.registrant_email ?? "no owner info"}`);
|
|
52402
52472
|
if (e4.registrar)
|
|
52403
|
-
|
|
52473
|
+
printLine(` Registrar: ${e4.registrar}`);
|
|
52404
52474
|
if (e4.notes)
|
|
52405
|
-
|
|
52475
|
+
printLine(` Notes: ${truncateText(e4.notes, 120)}`);
|
|
52406
52476
|
}
|
|
52407
|
-
|
|
52477
|
+
printLine(`
|
|
52408
52478
|
${entries.length} entry(ies). Use --limit <n> for a different page size or --json for full snapshots.`);
|
|
52409
52479
|
});
|
|
52410
52480
|
history.command("timeline").description("Show all domains with history changes").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all domains with history").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
52411
52481
|
const results = await listDomainsWithHistoryChanges2();
|
|
52412
52482
|
if (opts.json) {
|
|
52413
|
-
|
|
52483
|
+
printLine(JSON.stringify({ domains: results, count: results.length }, null, 2));
|
|
52414
52484
|
return;
|
|
52415
52485
|
}
|
|
52416
52486
|
if (results.length === 0) {
|
|
52417
|
-
|
|
52487
|
+
printLine("No domains with history entries.");
|
|
52418
52488
|
return;
|
|
52419
52489
|
}
|
|
52420
52490
|
const page = pageItemsOrExit(results, { limit: opts.limit, all: opts.all });
|
|
52421
|
-
|
|
52491
|
+
printLine("Domain History Timeline:");
|
|
52422
52492
|
for (const r4 of page.items) {
|
|
52423
|
-
|
|
52493
|
+
printLine(` ${r4.domain_name} \u2014 ${r4.snapshot_count} snapshots, latest: ${r4.latest_snapshot_type} at ${r4.latest_snapshot_at}`);
|
|
52424
52494
|
}
|
|
52425
|
-
|
|
52495
|
+
printLine(`
|
|
52426
52496
|
${compactHint(page, "domain(s) with history", "Use history list <domain> for domain details or --json for full data.", { paging: "limit" })}`);
|
|
52427
52497
|
});
|
|
52428
52498
|
history.command("range").description("List history entries within a date range").requiredOption("--from <date>", "Start date (ISO)").requiredOption("--to <date>", "End date (ISO)").option("--domain <name>", "Filter by domain name").option("--limit <n>", "Limit number of displayed entries").option("--all", "Show all entries in range").option("--verbose", "Show truncated notes and registrar details").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
52429
52499
|
const entries = await getHistoryByDateRange2(opts.from, opts.to, opts.domain);
|
|
52430
52500
|
if (opts.json) {
|
|
52431
|
-
|
|
52501
|
+
printLine(JSON.stringify({ history: entries, count: entries.length }, null, 2));
|
|
52432
52502
|
return;
|
|
52433
52503
|
}
|
|
52434
52504
|
if (entries.length === 0) {
|
|
52435
|
-
|
|
52505
|
+
printLine(`No history entries between ${opts.from} and ${opts.to}.`);
|
|
52436
52506
|
return;
|
|
52437
52507
|
}
|
|
52438
52508
|
const page = pageItemsOrExit(entries, { limit: opts.limit, all: opts.all });
|
|
52439
|
-
|
|
52509
|
+
printLine(`History from ${opts.from} to ${opts.to}:`);
|
|
52440
52510
|
for (const e4 of page.items) {
|
|
52441
52511
|
const extra = opts.verbose ? ` registrar:${truncateText(e4.registrar ?? "-", 40)} notes:${truncateText(e4.notes ?? "-", 80)}` : "";
|
|
52442
|
-
|
|
52512
|
+
printLine(` [${e4.created_at}] ${e4.snapshot_type} \u2014 domain ${e4.domain_id}${extra}`);
|
|
52443
52513
|
}
|
|
52444
|
-
|
|
52514
|
+
printLine(`
|
|
52445
52515
|
${compactHint(page, "entry(s)", "Use --verbose for more columns or --json for full snapshots.", { paging: "limit" })}`);
|
|
52446
52516
|
});
|
|
52447
52517
|
history.command("delete <entryId>").description("Delete a history entry").option("-f, --force", "Required confirmation").action(async (entryId, opts) => {
|
|
52448
52518
|
if (!opts.force) {
|
|
52449
|
-
|
|
52519
|
+
printErrorLine(`Refusing to delete history '${entryId}' without --force.`);
|
|
52450
52520
|
process.exit(1);
|
|
52451
52521
|
}
|
|
52452
52522
|
const deleted = await deleteHistoryEntry2(entryId);
|
|
52453
52523
|
if (!deleted) {
|
|
52454
|
-
|
|
52524
|
+
printErrorLine(`History entry '${entryId}' not found.`);
|
|
52455
52525
|
process.exit(1);
|
|
52456
52526
|
}
|
|
52457
|
-
|
|
52527
|
+
printLine(`Deleted history entry ${entryId}`);
|
|
52458
52528
|
});
|
|
52459
52529
|
history.command("purge <identifier>").description("Delete all history for a domain").option("-f, --force", "Required confirmation").action(async (identifier, opts) => {
|
|
52460
52530
|
if (!opts.force) {
|
|
52461
|
-
|
|
52531
|
+
printErrorLine(`Refusing to purge history for '${identifier}' without --force.`);
|
|
52462
52532
|
process.exit(1);
|
|
52463
52533
|
}
|
|
52464
52534
|
const domain = await getDomainDetails2(identifier);
|
|
52465
52535
|
if (!domain) {
|
|
52466
|
-
|
|
52536
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52467
52537
|
process.exit(1);
|
|
52468
52538
|
}
|
|
52469
52539
|
const deleted = await deleteHistoryByDomain2(domain.domain.id);
|
|
52470
52540
|
if (!deleted) {
|
|
52471
|
-
|
|
52541
|
+
printErrorLine(`No history to purge for ${domain.domain.name}.`);
|
|
52472
52542
|
process.exit(1);
|
|
52473
52543
|
}
|
|
52474
|
-
|
|
52544
|
+
printLine(`Purged all history for ${domain.domain.name}`);
|
|
52475
52545
|
});
|
|
52476
52546
|
}
|
|
52477
52547
|
var init_history2 = __esm(() => {
|
|
52478
52548
|
init_history();
|
|
52479
52549
|
init_domains();
|
|
52550
|
+
init_stdout();
|
|
52480
52551
|
});
|
|
52481
52552
|
|
|
52482
52553
|
// src/db/domain-research.ts
|
|
@@ -52643,13 +52714,13 @@ function registerResearchCommand(program2) {
|
|
|
52643
52714
|
research.command("exa <identifier>").description("Research a domain using Exa AI (ownership, company info, history)").option("--limit <n>", "Limit number of displayed web/company results").option("--all", "Show all returned research results").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52644
52715
|
const domain = await getDomainDetails2(identifier);
|
|
52645
52716
|
if (!domain) {
|
|
52646
|
-
|
|
52717
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52647
52718
|
process.exit(1);
|
|
52648
52719
|
}
|
|
52649
52720
|
try {
|
|
52650
52721
|
const result = await researchDomain(domain.domain.name);
|
|
52651
52722
|
if (opts.json) {
|
|
52652
|
-
|
|
52723
|
+
printLine(JSON.stringify({
|
|
52653
52724
|
domain: result.domain,
|
|
52654
52725
|
summary: result.summary,
|
|
52655
52726
|
results: result.results.map((r4) => ({ title: r4.title, url: r4.url, score: r4.score })),
|
|
@@ -52658,124 +52729,124 @@ function registerResearchCommand(program2) {
|
|
|
52658
52729
|
}, null, 2));
|
|
52659
52730
|
return;
|
|
52660
52731
|
}
|
|
52661
|
-
|
|
52732
|
+
printLine(`Exa Research for ${result.domain}:`);
|
|
52662
52733
|
if (result.summary)
|
|
52663
|
-
|
|
52734
|
+
printLine(`
|
|
52664
52735
|
Summary: ${truncateText(result.summary, 240)}`);
|
|
52665
52736
|
if (result.results.length > 0) {
|
|
52666
52737
|
const page = pageItemsOrExit(result.results, { limit: opts.limit, all: opts.all });
|
|
52667
|
-
|
|
52738
|
+
printLine(`
|
|
52668
52739
|
Web Results:`);
|
|
52669
52740
|
for (const r4 of page.items) {
|
|
52670
|
-
|
|
52671
|
-
|
|
52741
|
+
printLine(` - ${truncateText(r4.title, 100)} (${r4.score.toFixed(2)})`);
|
|
52742
|
+
printLine(` ${r4.url}`);
|
|
52672
52743
|
}
|
|
52673
|
-
|
|
52744
|
+
printLine(` ${compactHint(page, "web result(s)", "Use --all for every result or --json for structured output.", { paging: "limit" })}`);
|
|
52674
52745
|
}
|
|
52675
52746
|
if (result.companies.length > 0) {
|
|
52676
52747
|
const page = pageItemsOrExit(result.companies, { limit: opts.limit, all: opts.all });
|
|
52677
|
-
|
|
52748
|
+
printLine(`
|
|
52678
52749
|
Companies:`);
|
|
52679
52750
|
for (const c4 of page.items) {
|
|
52680
|
-
|
|
52751
|
+
printLine(` - ${c4.name}: ${c4.domain}`);
|
|
52681
52752
|
}
|
|
52682
|
-
|
|
52753
|
+
printLine(` ${compactHint(page, "company result(s)", "Use --all for every company or --json for structured output.", { paging: "limit" })}`);
|
|
52683
52754
|
}
|
|
52684
52755
|
if (result.savedHistory) {
|
|
52685
|
-
|
|
52756
|
+
printLine(`
|
|
52686
52757
|
Saved to history: ${result.savedHistory.id}`);
|
|
52687
52758
|
}
|
|
52688
|
-
|
|
52759
|
+
printLine();
|
|
52689
52760
|
} catch (error) {
|
|
52690
|
-
|
|
52761
|
+
printErrorLine(`Research failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
52691
52762
|
process.exit(1);
|
|
52692
52763
|
}
|
|
52693
52764
|
});
|
|
52694
52765
|
research.command("answer <identifier> <question>").description("Ask a specific question about a domain using Exa AI").option("-j, --json", "Output JSON").action(async (identifier, question, opts) => {
|
|
52695
52766
|
const domain = await getDomainDetails2(identifier);
|
|
52696
52767
|
if (!domain) {
|
|
52697
|
-
|
|
52768
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52698
52769
|
process.exit(1);
|
|
52699
52770
|
}
|
|
52700
52771
|
try {
|
|
52701
52772
|
const answer = await answerAboutDomain(domain.domain.name, question);
|
|
52702
52773
|
if (opts.json) {
|
|
52703
|
-
|
|
52774
|
+
printLine(JSON.stringify({ domain: domain.domain.name, question, answer }, null, 2));
|
|
52704
52775
|
return;
|
|
52705
52776
|
}
|
|
52706
52777
|
if (!answer) {
|
|
52707
|
-
|
|
52778
|
+
printLine("No answer found.");
|
|
52708
52779
|
return;
|
|
52709
52780
|
}
|
|
52710
|
-
|
|
52711
|
-
|
|
52781
|
+
printLine(`Q: ${question}`);
|
|
52782
|
+
printLine(`A: ${answer}`);
|
|
52712
52783
|
} catch (error) {
|
|
52713
|
-
|
|
52784
|
+
printErrorLine(`Answer failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
52714
52785
|
process.exit(1);
|
|
52715
52786
|
}
|
|
52716
52787
|
});
|
|
52717
52788
|
research.command("reputation <identifier>").description("Check domain reputation and blacklist status").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52718
52789
|
const domain = await getDomainDetails2(identifier);
|
|
52719
52790
|
if (!domain) {
|
|
52720
|
-
|
|
52791
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52721
52792
|
process.exit(1);
|
|
52722
52793
|
}
|
|
52723
52794
|
const { reputation, dnsBlacklist } = await checkDomainReputation(domain.domain.name);
|
|
52724
52795
|
if (opts.json) {
|
|
52725
|
-
|
|
52796
|
+
printLine(JSON.stringify({ domain: domain.domain.name, reputation, dnsBlacklist }, null, 2));
|
|
52726
52797
|
return;
|
|
52727
52798
|
}
|
|
52728
|
-
|
|
52799
|
+
printLine(`Reputation for ${domain.domain.name}:`);
|
|
52729
52800
|
if (reputation) {
|
|
52730
|
-
|
|
52801
|
+
printLine(` Blacklisted: ${reputation.is_blacklisted ? "yes" : "no"}`);
|
|
52731
52802
|
if (reputation.threat_score !== null)
|
|
52732
|
-
|
|
52803
|
+
printLine(` Threat Score: ${reputation.threat_score}`);
|
|
52733
52804
|
if (reputation.spam_score !== null)
|
|
52734
|
-
|
|
52735
|
-
|
|
52736
|
-
|
|
52805
|
+
printLine(` Spam Score: ${reputation.spam_score}`);
|
|
52806
|
+
printLine(` Malware: ${reputation.malware_detected ? "detected" : "clean"}`);
|
|
52807
|
+
printLine(` Phishing: ${reputation.phishing_detected ? "detected" : "clean"}`);
|
|
52737
52808
|
if (reputation.last_checked_at)
|
|
52738
|
-
|
|
52809
|
+
printLine(` Last Checked: ${reputation.last_checked_at}`);
|
|
52739
52810
|
} else {
|
|
52740
|
-
|
|
52811
|
+
printLine(" No reputation data yet.");
|
|
52741
52812
|
}
|
|
52742
|
-
|
|
52813
|
+
printLine(` DNS Blacklist: ${dnsBlacklist.listed ? `listed in ${dnsBlacklist.zones.join(", ")}` : "clean"}`);
|
|
52743
52814
|
});
|
|
52744
52815
|
research.command("blacklisted").description("List all blacklisted domains in the database").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all blacklisted domains").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
52745
52816
|
const domains = await listBlacklistedDomains2();
|
|
52746
52817
|
if (opts.json) {
|
|
52747
|
-
|
|
52818
|
+
printLine(JSON.stringify({ domains, count: domains.length }, null, 2));
|
|
52748
52819
|
return;
|
|
52749
52820
|
}
|
|
52750
52821
|
if (domains.length === 0) {
|
|
52751
|
-
|
|
52822
|
+
printLine("No blacklisted domains.");
|
|
52752
52823
|
return;
|
|
52753
52824
|
}
|
|
52754
52825
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
52755
|
-
|
|
52826
|
+
printLine("Blacklisted domains:");
|
|
52756
52827
|
for (const d4 of page.items) {
|
|
52757
|
-
|
|
52828
|
+
printLine(` domain_id: ${d4.domain_id} (sources: ${truncateText(d4.blacklist_sources.join(", "), 100)})`);
|
|
52758
52829
|
}
|
|
52759
|
-
|
|
52830
|
+
printLine(`
|
|
52760
52831
|
${compactHint(page, "blacklisted domain(s)", "Use --all for every domain or --json for full source arrays.", { paging: "limit" })}`);
|
|
52761
52832
|
});
|
|
52762
52833
|
research.command("threats").description("List domains with high threat scores").option("--threshold <n>", "Minimum threat score", "70").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all matching domains").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
52763
52834
|
const threshold = parseInt(opts.threshold ?? "70");
|
|
52764
52835
|
const domains = await listHighThreatDomains2(threshold);
|
|
52765
52836
|
if (opts.json) {
|
|
52766
|
-
|
|
52837
|
+
printLine(JSON.stringify({ domains, threshold, count: domains.length }, null, 2));
|
|
52767
52838
|
return;
|
|
52768
52839
|
}
|
|
52769
52840
|
if (domains.length === 0) {
|
|
52770
|
-
|
|
52841
|
+
printLine(`No domains with threat score >= ${threshold}.`);
|
|
52771
52842
|
return;
|
|
52772
52843
|
}
|
|
52773
52844
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
52774
|
-
|
|
52845
|
+
printLine(`Domains with threat score >= ${threshold}:`);
|
|
52775
52846
|
for (const d4 of page.items) {
|
|
52776
|
-
|
|
52847
|
+
printLine(` domain_id: ${d4.domain_id} \u2014 score: ${d4.threat_score ?? "?"}`);
|
|
52777
52848
|
}
|
|
52778
|
-
|
|
52849
|
+
printLine(`
|
|
52779
52850
|
${compactHint(page, "domain(s)", "Use --all for every domain or --json for full reputation records.", { paging: "limit" })}`);
|
|
52780
52851
|
});
|
|
52781
52852
|
}
|
|
@@ -52783,6 +52854,7 @@ var init_research = __esm(() => {
|
|
|
52783
52854
|
init_domain_research();
|
|
52784
52855
|
init_domains();
|
|
52785
52856
|
init_reputation();
|
|
52857
|
+
init_stdout();
|
|
52786
52858
|
});
|
|
52787
52859
|
|
|
52788
52860
|
// src/cli/commands/outreach.ts
|
|
@@ -52795,7 +52867,7 @@ import { promisify as promisify3 } from "util";
|
|
|
52795
52867
|
async function requireDomainOwner(identifier) {
|
|
52796
52868
|
const owner = await getDomainOwnerByDomainName2(identifier);
|
|
52797
52869
|
if (!owner) {
|
|
52798
|
-
|
|
52870
|
+
printErrorLine(`No owner info found for '${identifier}'.`);
|
|
52799
52871
|
process.exit(1);
|
|
52800
52872
|
}
|
|
52801
52873
|
return owner;
|
|
@@ -52805,7 +52877,7 @@ function registerOutreachCommand(program2) {
|
|
|
52805
52877
|
outreach.command("sms <identifier>").description("Send SMS to a domain owner").requiredOption("--message <text>", "SMS message body").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52806
52878
|
const owner = await requireDomainOwner(identifier);
|
|
52807
52879
|
if (!owner.owner_phone) {
|
|
52808
|
-
|
|
52880
|
+
printErrorLine(`No phone number for '${identifier}'.`);
|
|
52809
52881
|
process.exit(1);
|
|
52810
52882
|
}
|
|
52811
52883
|
try {
|
|
@@ -52821,20 +52893,20 @@ function registerOutreachCommand(program2) {
|
|
|
52821
52893
|
], { encoding: "utf-8" });
|
|
52822
52894
|
const result = JSON.parse(stdout);
|
|
52823
52895
|
if (opts.json) {
|
|
52824
|
-
|
|
52896
|
+
printLine(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
|
|
52825
52897
|
} else {
|
|
52826
|
-
|
|
52898
|
+
printLine(`SMS sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
|
|
52827
52899
|
}
|
|
52828
52900
|
} catch (error) {
|
|
52829
52901
|
const msg = error instanceof Error ? error.message : String(error);
|
|
52830
|
-
|
|
52902
|
+
printErrorLine(`SMS send failed: ${msg}`);
|
|
52831
52903
|
process.exit(1);
|
|
52832
52904
|
}
|
|
52833
52905
|
});
|
|
52834
52906
|
outreach.command("whatsapp <identifier>").description("Send WhatsApp message to a domain owner").requiredOption("--message <text>", "Message body").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52835
52907
|
const owner = await requireDomainOwner(identifier);
|
|
52836
52908
|
if (!owner.owner_phone) {
|
|
52837
|
-
|
|
52909
|
+
printErrorLine(`No phone number for '${identifier}'.`);
|
|
52838
52910
|
process.exit(1);
|
|
52839
52911
|
}
|
|
52840
52912
|
try {
|
|
@@ -52850,20 +52922,20 @@ function registerOutreachCommand(program2) {
|
|
|
52850
52922
|
], { encoding: "utf-8" });
|
|
52851
52923
|
const result = JSON.parse(stdout);
|
|
52852
52924
|
if (opts.json) {
|
|
52853
|
-
|
|
52925
|
+
printLine(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
|
|
52854
52926
|
} else {
|
|
52855
|
-
|
|
52927
|
+
printLine(`WhatsApp sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
|
|
52856
52928
|
}
|
|
52857
52929
|
} catch (error) {
|
|
52858
52930
|
const msg = error instanceof Error ? error.message : String(error);
|
|
52859
|
-
|
|
52931
|
+
printErrorLine(`WhatsApp send failed: ${msg}`);
|
|
52860
52932
|
process.exit(1);
|
|
52861
52933
|
}
|
|
52862
52934
|
});
|
|
52863
52935
|
outreach.command("email <identifier>").description("Send email to a domain owner").requiredOption("--subject <text>", "Email subject").requiredOption("--body <text>", "Email body (plain text)").option("--template <name>", "Use a template by name instead of --body").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52864
52936
|
const owner = await requireDomainOwner(identifier);
|
|
52865
52937
|
if (!owner.owner_email) {
|
|
52866
|
-
|
|
52938
|
+
printErrorLine(`No email for '${identifier}'.`);
|
|
52867
52939
|
process.exit(1);
|
|
52868
52940
|
}
|
|
52869
52941
|
try {
|
|
@@ -52881,13 +52953,13 @@ function registerOutreachCommand(program2) {
|
|
|
52881
52953
|
], { encoding: "utf-8" });
|
|
52882
52954
|
const result = JSON.parse(stdout);
|
|
52883
52955
|
if (opts.json) {
|
|
52884
|
-
|
|
52956
|
+
printLine(JSON.stringify({ domain: identifier, to: owner.owner_email, result }, null, 2));
|
|
52885
52957
|
} else {
|
|
52886
|
-
|
|
52958
|
+
printLine(`Email sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_email}): "${opts.subject}"`);
|
|
52887
52959
|
}
|
|
52888
52960
|
} catch (error) {
|
|
52889
52961
|
const msg = error instanceof Error ? error.message : String(error);
|
|
52890
|
-
|
|
52962
|
+
printErrorLine(`Email send failed: ${msg}`);
|
|
52891
52963
|
process.exit(1);
|
|
52892
52964
|
}
|
|
52893
52965
|
});
|
|
@@ -52895,6 +52967,7 @@ function registerOutreachCommand(program2) {
|
|
|
52895
52967
|
var execFileAsync2;
|
|
52896
52968
|
var init_outreach = __esm(() => {
|
|
52897
52969
|
init_owners();
|
|
52970
|
+
init_stdout();
|
|
52898
52971
|
execFileAsync2 = promisify3(execFile2);
|
|
52899
52972
|
});
|
|
52900
52973
|
|
|
@@ -52934,22 +53007,22 @@ function registerWalletCommand(program2) {
|
|
|
52934
53007
|
try {
|
|
52935
53008
|
const cards = await getAvailableCards();
|
|
52936
53009
|
if (opts.json) {
|
|
52937
|
-
|
|
53010
|
+
printLine(JSON.stringify(cards, null, 2));
|
|
52938
53011
|
} else {
|
|
52939
53012
|
if (cards.length === 0) {
|
|
52940
|
-
|
|
53013
|
+
printLine("No active wallet cards found.");
|
|
52941
53014
|
return;
|
|
52942
53015
|
}
|
|
52943
53016
|
const page = pageItemsOrExit(cards, { limit: opts.limit, all: opts.all });
|
|
52944
|
-
|
|
53017
|
+
printLine("Available wallet cards:");
|
|
52945
53018
|
for (const c4 of page.items) {
|
|
52946
|
-
|
|
53019
|
+
printLine(` ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} \u2014 ${c4.name} (${c4.balance} ${c4.currency})`);
|
|
52947
53020
|
}
|
|
52948
|
-
|
|
53021
|
+
printLine(`
|
|
52949
53022
|
${compactHint(page, "card(s)", "Use --all for every card or --json for full card fields.", { paging: "limit" })}`);
|
|
52950
53023
|
}
|
|
52951
53024
|
} catch (error) {
|
|
52952
|
-
|
|
53025
|
+
printErrorLine(`Failed to list cards: ${error instanceof Error ? error.message : String(error)}`);
|
|
52953
53026
|
process.exit(1);
|
|
52954
53027
|
}
|
|
52955
53028
|
});
|
|
@@ -52961,15 +53034,15 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
52961
53034
|
if (!cardId) {
|
|
52962
53035
|
const cards = await getAvailableCards();
|
|
52963
53036
|
if (cards.length === 0) {
|
|
52964
|
-
|
|
53037
|
+
printErrorLine("No active wallet cards found. Add a card first.");
|
|
52965
53038
|
process.exit(1);
|
|
52966
53039
|
}
|
|
52967
53040
|
if (cards.length === 1) {
|
|
52968
53041
|
cardId = cards[0].external_id;
|
|
52969
53042
|
} else {
|
|
52970
|
-
|
|
53043
|
+
printErrorLine("Multiple cards available. Specify --card-id:");
|
|
52971
53044
|
for (const c4 of cards) {
|
|
52972
|
-
|
|
53045
|
+
printLine(` ${c4.id}: ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} (${c4.balance} ${c4.currency})`);
|
|
52973
53046
|
}
|
|
52974
53047
|
process.exit(1);
|
|
52975
53048
|
}
|
|
@@ -52977,16 +53050,16 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
52977
53050
|
const wallets = getWalletsModule();
|
|
52978
53051
|
const card = wallets.getCard(cardId);
|
|
52979
53052
|
if (!card) {
|
|
52980
|
-
|
|
53053
|
+
printErrorLine(`Card '${cardId}' not found.`);
|
|
52981
53054
|
process.exit(1);
|
|
52982
53055
|
}
|
|
52983
53056
|
if (card.balance < price) {
|
|
52984
|
-
|
|
53057
|
+
printErrorLine(`Insufficient funds: need ${price} ${currency}, have ${card.balance} ${card.currency}`);
|
|
52985
53058
|
process.exit(1);
|
|
52986
53059
|
}
|
|
52987
53060
|
const existing = await getDomainByName2(name);
|
|
52988
53061
|
if (existing) {
|
|
52989
|
-
|
|
53062
|
+
printErrorLine(`Domain '${name}' already exists in portfolio.`);
|
|
52990
53063
|
process.exit(1);
|
|
52991
53064
|
}
|
|
52992
53065
|
const domain = await createDomain2({
|
|
@@ -53010,13 +53083,13 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53010
53083
|
notes: `Purchased ${name} for ${price} ${currency} via wallet card ${cardId}`
|
|
53011
53084
|
});
|
|
53012
53085
|
if (opts.json) {
|
|
53013
|
-
|
|
53086
|
+
printLine(JSON.stringify({ domain, card_id: cardId, price, currency }, null, 2));
|
|
53014
53087
|
} else {
|
|
53015
|
-
|
|
53016
|
-
|
|
53088
|
+
printLine(`Purchased ${name} for ${price} ${currency} via wallet card`);
|
|
53089
|
+
printLine(` Added to portfolio as ${domain.id}`);
|
|
53017
53090
|
}
|
|
53018
53091
|
} catch (error) {
|
|
53019
|
-
|
|
53092
|
+
printErrorLine(`Wallet purchase failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
53020
53093
|
process.exit(1);
|
|
53021
53094
|
}
|
|
53022
53095
|
});
|
|
@@ -53024,7 +53097,7 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53024
53097
|
const price = parseFloat(opts.price);
|
|
53025
53098
|
const domain = await getDomainByName2(name);
|
|
53026
53099
|
if (!domain) {
|
|
53027
|
-
|
|
53100
|
+
printErrorLine(`Domain '${name}' not found in portfolio.`);
|
|
53028
53101
|
process.exit(1);
|
|
53029
53102
|
}
|
|
53030
53103
|
try {
|
|
@@ -53032,7 +53105,7 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53032
53105
|
if (!cardId) {
|
|
53033
53106
|
const cards = await getAvailableCards();
|
|
53034
53107
|
if (cards.length === 0) {
|
|
53035
|
-
|
|
53108
|
+
printErrorLine("No active wallet cards found.");
|
|
53036
53109
|
process.exit(1);
|
|
53037
53110
|
}
|
|
53038
53111
|
cardId = cards[0].external_id;
|
|
@@ -53040,11 +53113,11 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53040
53113
|
const wallets = getWalletsModule();
|
|
53041
53114
|
const card = wallets.getCard(cardId);
|
|
53042
53115
|
if (!card) {
|
|
53043
|
-
|
|
53116
|
+
printErrorLine(`Card '${cardId}' not found.`);
|
|
53044
53117
|
process.exit(1);
|
|
53045
53118
|
}
|
|
53046
53119
|
if (card.balance < price) {
|
|
53047
|
-
|
|
53120
|
+
printErrorLine(`Insufficient funds: need ${price} ${opts.currency}, have ${card.balance} ${card.currency}`);
|
|
53048
53121
|
process.exit(1);
|
|
53049
53122
|
}
|
|
53050
53123
|
await createHistoryEntry2({
|
|
@@ -53060,13 +53133,13 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53060
53133
|
purchase_price: price
|
|
53061
53134
|
});
|
|
53062
53135
|
if (opts.json) {
|
|
53063
|
-
|
|
53136
|
+
printLine(JSON.stringify({ domain: name, card_id: cardId, price, new_expiry: expiryDate.toISOString() }, null, 2));
|
|
53064
53137
|
} else {
|
|
53065
|
-
|
|
53066
|
-
|
|
53138
|
+
printLine(`Renewed ${name} for ${price} ${opts.currency} via wallet card`);
|
|
53139
|
+
printLine(` New expiry: ${expiryDate.toISOString().split("T")[0]}`);
|
|
53067
53140
|
}
|
|
53068
53141
|
} catch (error) {
|
|
53069
|
-
|
|
53142
|
+
printErrorLine(`Wallet renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
53070
53143
|
process.exit(1);
|
|
53071
53144
|
}
|
|
53072
53145
|
});
|
|
@@ -53075,6 +53148,7 @@ var WALLET_MODULE_ENV = "DOMAINS_WALLET_MODULE";
|
|
|
53075
53148
|
var init_wallet = __esm(() => {
|
|
53076
53149
|
init_domains();
|
|
53077
53150
|
init_history();
|
|
53151
|
+
init_stdout();
|
|
53078
53152
|
});
|
|
53079
53153
|
|
|
53080
53154
|
// src/lib/provision-state.ts
|
|
@@ -53249,23 +53323,23 @@ function registerProvisionCommand(program2) {
|
|
|
53249
53323
|
signals["publicNsAreCloudflare"] = false;
|
|
53250
53324
|
}
|
|
53251
53325
|
} catch (e4) {
|
|
53252
|
-
|
|
53326
|
+
printErrorLine(`Error gathering signals: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
53253
53327
|
}
|
|
53254
53328
|
const state = deriveDomainState(signals);
|
|
53255
|
-
|
|
53329
|
+
printLine(`
|
|
53256
53330
|
Domain: ${name}`);
|
|
53257
|
-
|
|
53258
|
-
|
|
53331
|
+
printLine(`State: ${state}`);
|
|
53332
|
+
printLine(`Signals: ${JSON.stringify(signals)}`);
|
|
53259
53333
|
const path = domainHappyPath();
|
|
53260
53334
|
const idx = path.indexOf(state);
|
|
53261
|
-
|
|
53335
|
+
printLine(`Progress: ${idx >= 0 ? idx + 1 : "?"}/${path.length} [${path.join(" \u2192 ")}]`);
|
|
53262
53336
|
});
|
|
53263
53337
|
provision.command("daemon").description("Reconcile domains toward ready (CF zone + NS delegation + propagation)").option("--domains <list>", "Comma-separated domains (default: all active in the portfolio)").option("--once", "Run a single reconcile tick and exit").option("--interval <sec>", "Seconds between ticks", "30").option("--max-ticks <n>", "Stop after N ticks").action(async (opts) => {
|
|
53264
53338
|
const { applyPurchaseProfile: applyPurchaseProfile2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
53265
53339
|
applyPurchaseProfile2();
|
|
53266
53340
|
const { makeDomainDaemonDeps: makeDomainDaemonDeps2 } = await Promise.resolve().then(() => (init_domain_daemon_deps(), exports_domain_daemon_deps));
|
|
53267
53341
|
const { reconcileDomainTick: reconcileDomainTick2, runDomainDaemon: runDomainDaemon2 } = await Promise.resolve().then(() => (init_domain_daemon(), exports_domain_daemon));
|
|
53268
|
-
const deps = { ...makeDomainDaemonDeps2(), log: (e4, d4) =>
|
|
53342
|
+
const deps = { ...makeDomainDaemonDeps2(), log: (e4, d4) => printLine(`[${e4}] ${JSON.stringify(d4)}`) };
|
|
53269
53343
|
const listDomains4 = async () => {
|
|
53270
53344
|
if (opts.domains)
|
|
53271
53345
|
return opts.domains.split(",").map((d4) => d4.trim());
|
|
@@ -53274,16 +53348,16 @@ Domain: ${name}`);
|
|
|
53274
53348
|
};
|
|
53275
53349
|
if (opts.once) {
|
|
53276
53350
|
const s2 = await reconcileDomainTick2(await listDomains4(), deps);
|
|
53277
|
-
|
|
53351
|
+
printLine(`\u2713 tick: ${s2.advanced} advanced, ${s2.ready} ready, ${s2.errors} errors (${s2.processed} processed)`);
|
|
53278
53352
|
return;
|
|
53279
53353
|
}
|
|
53280
|
-
|
|
53354
|
+
printLine(`Domain provisioning daemon started (interval ${opts.interval}s). Ctrl-C to stop.`);
|
|
53281
53355
|
const total = await runDomainDaemon2(listDomains4, {
|
|
53282
53356
|
...deps,
|
|
53283
53357
|
intervalSec: parseInt(opts.interval, 10),
|
|
53284
53358
|
maxTicks: opts.maxTicks ? parseInt(opts.maxTicks, 10) : undefined
|
|
53285
53359
|
});
|
|
53286
|
-
|
|
53360
|
+
printLine(`daemon stopped: ${total.advanced} advanced, ${total.ready} ready, ${total.errors} errors`);
|
|
53287
53361
|
});
|
|
53288
53362
|
}
|
|
53289
53363
|
var CF_NS_SUFFIX2 = ".ns.cloudflare.com";
|
|
@@ -53291,6 +53365,7 @@ var init_provision = __esm(() => {
|
|
|
53291
53365
|
init_provision_state();
|
|
53292
53366
|
init_route53();
|
|
53293
53367
|
init_cloudflare();
|
|
53368
|
+
init_stdout();
|
|
53294
53369
|
});
|
|
53295
53370
|
|
|
53296
53371
|
// src/cli/tui/format.ts
|
|
@@ -54012,10 +54087,12 @@ __export(exports_interactive, {
|
|
|
54012
54087
|
import chalk from "chalk";
|
|
54013
54088
|
import { render } from "ink";
|
|
54014
54089
|
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
54015
|
-
function assertInteractiveTty() {
|
|
54090
|
+
function assertInteractiveTty(emit = (line) => {
|
|
54091
|
+
printErrorLine(line);
|
|
54092
|
+
}) {
|
|
54016
54093
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
54017
|
-
|
|
54018
|
-
|
|
54094
|
+
emit(chalk.red("Interactive mode requires a TTY terminal."));
|
|
54095
|
+
emit(chalk.dim("Use `domains domain list` or `domains domain get <name>` for non-interactive use."));
|
|
54019
54096
|
process.exit(1);
|
|
54020
54097
|
}
|
|
54021
54098
|
}
|
|
@@ -54029,6 +54106,7 @@ function registerInteractiveCommand(program2) {
|
|
|
54029
54106
|
}
|
|
54030
54107
|
var init_interactive = __esm(() => {
|
|
54031
54108
|
init_App();
|
|
54109
|
+
init_stdout();
|
|
54032
54110
|
});
|
|
54033
54111
|
|
|
54034
54112
|
// node_modules/@hasna/events/dist/commander.js
|
|
@@ -55589,6 +55667,7 @@ function getCapability(name) {
|
|
|
55589
55667
|
}
|
|
55590
55668
|
|
|
55591
55669
|
// src/cli/commands/domain.ts
|
|
55670
|
+
init_stdout();
|
|
55592
55671
|
var DOMAIN_STATUS_HELP = DOMAIN_STATUSES.join("/");
|
|
55593
55672
|
var DOMAIN_OFFER_STATUS_HELP = DOMAIN_OFFER_STATUSES.join("/");
|
|
55594
55673
|
var DOMAIN_EMAIL_TYPE_HELP = DOMAIN_EMAIL_TYPES.join("/");
|
|
@@ -55615,7 +55694,7 @@ async function createDnsZoneForProvider(domain, provider) {
|
|
|
55615
55694
|
async function requireDomain(identifier) {
|
|
55616
55695
|
const details = await getDomainDetails2(identifier);
|
|
55617
55696
|
if (!details) {
|
|
55618
|
-
|
|
55697
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
55619
55698
|
process.exit(1);
|
|
55620
55699
|
}
|
|
55621
55700
|
return details;
|
|
@@ -55631,7 +55710,7 @@ function registerDomainCommand(program2) {
|
|
|
55631
55710
|
jsonLimit = opts.limit === undefined ? undefined : parseLimit(opts.limit, undefined, Infinity);
|
|
55632
55711
|
offset = parseOffset(opts.offset);
|
|
55633
55712
|
} catch (error) {
|
|
55634
|
-
|
|
55713
|
+
printErrorLine(error instanceof Error ? error.message : String(error));
|
|
55635
55714
|
process.exit(1);
|
|
55636
55715
|
}
|
|
55637
55716
|
const filters = {
|
|
@@ -55648,7 +55727,7 @@ function registerDomainCommand(program2) {
|
|
|
55648
55727
|
fallbackLimit: Infinity,
|
|
55649
55728
|
maxLimit: Infinity
|
|
55650
55729
|
});
|
|
55651
|
-
|
|
55730
|
+
printLine(JSON.stringify({
|
|
55652
55731
|
domains: jsonPage.items,
|
|
55653
55732
|
count: jsonPage.shown,
|
|
55654
55733
|
total: jsonPage.total,
|
|
@@ -55661,7 +55740,7 @@ function registerDomainCommand(program2) {
|
|
|
55661
55740
|
}
|
|
55662
55741
|
const page = pageItemsOrExit(domains, { limit, offset, all: opts.all });
|
|
55663
55742
|
if (page.items.length === 0) {
|
|
55664
|
-
|
|
55743
|
+
printLine("No domains found.");
|
|
55665
55744
|
return;
|
|
55666
55745
|
}
|
|
55667
55746
|
for (const d4 of page.items) {
|
|
@@ -55670,47 +55749,47 @@ function registerDomainCommand(program2) {
|
|
|
55670
55749
|
if (opts.verbose) {
|
|
55671
55750
|
const registrar = d4.registrar ? ` reg:${truncateText(d4.registrar, 24)}` : "";
|
|
55672
55751
|
const notes = d4.notes ? ` notes:${truncateText(d4.notes, 60)}` : "";
|
|
55673
|
-
|
|
55752
|
+
printLine(` ${d4.name} [${d4.status}]${registrar}${exp}${premium}${notes}`);
|
|
55674
55753
|
} else {
|
|
55675
|
-
|
|
55754
|
+
printLine(` ${d4.name} [${d4.status}]${exp}${premium}`);
|
|
55676
55755
|
}
|
|
55677
55756
|
}
|
|
55678
|
-
|
|
55757
|
+
printLine(`
|
|
55679
55758
|
${compactHint(page, "domain(s)", "Use --verbose for registrar/notes or domain get <id|name> for details.")}`);
|
|
55680
55759
|
});
|
|
55681
55760
|
domain.command("get <identifier>").description("Get a domain by ID or name").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
55682
55761
|
const details = await getDomainDetails2(identifier);
|
|
55683
55762
|
if (!details) {
|
|
55684
|
-
|
|
55763
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
55685
55764
|
process.exit(1);
|
|
55686
55765
|
}
|
|
55687
55766
|
if (opts.json) {
|
|
55688
|
-
|
|
55767
|
+
printLine(JSON.stringify(details, null, 2));
|
|
55689
55768
|
return;
|
|
55690
55769
|
}
|
|
55691
55770
|
const d4 = details.domain;
|
|
55692
|
-
|
|
55771
|
+
printLine(`
|
|
55693
55772
|
${d4.name} [${d4.status}]`);
|
|
55694
55773
|
if (d4.registrar)
|
|
55695
|
-
|
|
55774
|
+
printLine(` Registrar: ${d4.registrar}`);
|
|
55696
55775
|
if (d4.expires_at)
|
|
55697
|
-
|
|
55776
|
+
printLine(` Expires: ${formatDate(d4.expires_at)}`);
|
|
55698
55777
|
if (d4.purchase_date)
|
|
55699
|
-
|
|
55778
|
+
printLine(` Purchased: ${formatDate(d4.purchase_date)}`);
|
|
55700
55779
|
if (d4.purchase_price !== null)
|
|
55701
|
-
|
|
55702
|
-
|
|
55780
|
+
printLine(` Purchase price: ${d4.purchase_price}`);
|
|
55781
|
+
printLine(` Auto-renew: ${d4.auto_renew ? "yes" : "no"}`);
|
|
55703
55782
|
if (d4.is_premium) {
|
|
55704
|
-
|
|
55783
|
+
printLine(` Premium: yes`);
|
|
55705
55784
|
if (d4.premium_price !== null)
|
|
55706
|
-
|
|
55785
|
+
printLine(` Premium ask: ${d4.premium_price}`);
|
|
55707
55786
|
}
|
|
55708
55787
|
if (d4.standard_price !== null)
|
|
55709
|
-
|
|
55788
|
+
printLine(` Standard price: ${d4.standard_price}`);
|
|
55710
55789
|
if (d4.notes)
|
|
55711
|
-
|
|
55790
|
+
printLine(` Notes: ${truncateText(d4.notes, 160)}`);
|
|
55712
55791
|
if (details.offers.length > 0) {
|
|
55713
|
-
|
|
55792
|
+
printLine(`
|
|
55714
55793
|
Offers:`);
|
|
55715
55794
|
const offerPage = pageItemsOrExit(details.offers, { fallbackLimit: 5 });
|
|
55716
55795
|
for (const offer of offerPage.items) {
|
|
@@ -55721,23 +55800,23 @@ Offers:`);
|
|
|
55721
55800
|
offer.their_ask !== null ? `their=${offer.their_ask}` : null,
|
|
55722
55801
|
offer.notes
|
|
55723
55802
|
].filter(Boolean);
|
|
55724
|
-
|
|
55803
|
+
printLine(` - ${parts.join(" | ")}`);
|
|
55725
55804
|
}
|
|
55726
55805
|
if (offerPage.hasMore)
|
|
55727
|
-
|
|
55806
|
+
printLine(` ${compactHint(offerPage, "offer(s)", "Use --json for the full offer history.", { paging: "none" })}`);
|
|
55728
55807
|
}
|
|
55729
55808
|
if (details.emails.length > 0) {
|
|
55730
|
-
|
|
55809
|
+
printLine(`
|
|
55731
55810
|
Emails:`);
|
|
55732
55811
|
const emailPage = pageItemsOrExit(details.emails, { fallbackLimit: 5 });
|
|
55733
55812
|
for (const email of emailPage.items) {
|
|
55734
55813
|
const threadPart = email.thread_id ? ` thread=${email.thread_id}` : "";
|
|
55735
|
-
|
|
55814
|
+
printLine(` - ${email.type}: ${email.email_id}${threadPart}`);
|
|
55736
55815
|
}
|
|
55737
55816
|
if (emailPage.hasMore)
|
|
55738
|
-
|
|
55817
|
+
printLine(` ${compactHint(emailPage, "email link(s)", "Use --json for the full email list.", { paging: "none" })}`);
|
|
55739
55818
|
}
|
|
55740
|
-
|
|
55819
|
+
printLine();
|
|
55741
55820
|
});
|
|
55742
55821
|
domain.command("add").description("Add a domain to the portfolio").requiredOption("--name <name>", "Domain name").option("--registrar <name>", "Registrar name").option("--status <s>", `Status (${DOMAIN_STATUS_HELP})`, "active").option("--expires <date>", "Expiry date (YYYY-MM-DD)").option("--premium", "Mark the domain as premium").option("--premium-price <price>", "Premium asking price").option("--standard-price <price>", "Standard registration price").option("--purchase-price <price>", "Acquisition price paid").option("--purchase-date <date>", "Purchase date (ISO or YYYY-MM-DD)").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
55743
55822
|
const premiumPrice = parseOptionalNumber(opts.premiumPrice, "--premium-price");
|
|
@@ -55756,10 +55835,10 @@ Emails:`);
|
|
|
55756
55835
|
notes: opts.notes
|
|
55757
55836
|
});
|
|
55758
55837
|
if (opts.json) {
|
|
55759
|
-
|
|
55838
|
+
printLine(JSON.stringify(d4, null, 2));
|
|
55760
55839
|
return;
|
|
55761
55840
|
}
|
|
55762
|
-
|
|
55841
|
+
printLine(`Created domain: ${d4.name} (${d4.id})`);
|
|
55763
55842
|
});
|
|
55764
55843
|
domain.command("update <id>").description("Update a domain").option("--registrar <name>", "Registrar").option("--status <s>", `Status (${DOMAIN_STATUS_HELP})`).option("--expires <date>", "Expiry date").option("--premium <bool>", "Premium flag (true/false)").option("--premium-price <price>", "Premium asking price").option("--standard-price <price>", "Standard registration price").option("--purchase-price <price>", "Purchase price paid").option("--purchase-date <date>", "Purchase date").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (id, opts) => {
|
|
55765
55844
|
const premiumPrice = parseOptionalNumber(opts.premiumPrice, "--premium-price");
|
|
@@ -55777,23 +55856,23 @@ Emails:`);
|
|
|
55777
55856
|
notes: opts.notes
|
|
55778
55857
|
});
|
|
55779
55858
|
if (!d4) {
|
|
55780
|
-
|
|
55859
|
+
printErrorLine(`Domain '${id}' not found.`);
|
|
55781
55860
|
process.exit(1);
|
|
55782
55861
|
}
|
|
55783
55862
|
if (opts.json) {
|
|
55784
|
-
|
|
55863
|
+
printLine(JSON.stringify(d4, null, 2));
|
|
55785
55864
|
return;
|
|
55786
55865
|
}
|
|
55787
|
-
|
|
55866
|
+
printLine(`Updated: ${d4.name}`);
|
|
55788
55867
|
});
|
|
55789
55868
|
domain.command("delete <id>").description("Delete a domain from the portfolio").option("-f, --force", "Required confirmation for destructive delete").option("-j, --json", "Output JSON").action(async (id, opts) => {
|
|
55790
55869
|
if (!opts.force) {
|
|
55791
55870
|
const message = `Refusing to delete domain '${id}' without --force.`;
|
|
55792
55871
|
if (opts.json) {
|
|
55793
|
-
|
|
55872
|
+
printLine(JSON.stringify({ deleted: false, id, error: message }, null, 2));
|
|
55794
55873
|
} else {
|
|
55795
|
-
|
|
55796
|
-
|
|
55874
|
+
printErrorLine(message);
|
|
55875
|
+
printErrorLine("Re-run with --force to confirm deletion.");
|
|
55797
55876
|
}
|
|
55798
55877
|
process.exit(1);
|
|
55799
55878
|
}
|
|
@@ -55801,105 +55880,105 @@ Emails:`);
|
|
|
55801
55880
|
if (!deleted) {
|
|
55802
55881
|
const message = `Domain '${id}' not found.`;
|
|
55803
55882
|
if (opts.json) {
|
|
55804
|
-
|
|
55883
|
+
printLine(JSON.stringify({ deleted: false, id, error: message }, null, 2));
|
|
55805
55884
|
} else {
|
|
55806
|
-
|
|
55885
|
+
printErrorLine(message);
|
|
55807
55886
|
}
|
|
55808
55887
|
process.exit(1);
|
|
55809
55888
|
}
|
|
55810
55889
|
if (opts.json) {
|
|
55811
|
-
|
|
55890
|
+
printLine(JSON.stringify({ deleted: true, id }, null, 2));
|
|
55812
55891
|
return;
|
|
55813
55892
|
}
|
|
55814
|
-
|
|
55893
|
+
printLine(`Deleted domain ${id}`);
|
|
55815
55894
|
});
|
|
55816
55895
|
domain.command("search <query>").description("Search domains by name, registrar, or notes").option("--limit <n>", "Limit number of displayed domains").option("--offset <n>", "Skip first N domains", "0").option("--all", "Show all matching domains").option("--verbose", "Show registrar and truncated notes").option("-j, --json", "Output JSON").action(async (query, opts) => {
|
|
55817
55896
|
const results = await searchDomains2(query);
|
|
55818
55897
|
if (opts.json) {
|
|
55819
|
-
|
|
55898
|
+
printLine(JSON.stringify({ results, count: results.length }, null, 2));
|
|
55820
55899
|
return;
|
|
55821
55900
|
}
|
|
55822
55901
|
let page;
|
|
55823
55902
|
try {
|
|
55824
55903
|
page = pageItemsOrExit(results, { limit: opts.limit, offset: opts.offset, all: opts.all });
|
|
55825
55904
|
} catch (error) {
|
|
55826
|
-
|
|
55905
|
+
printErrorLine(error instanceof Error ? error.message : String(error));
|
|
55827
55906
|
process.exit(1);
|
|
55828
55907
|
}
|
|
55829
55908
|
for (const d4 of page.items) {
|
|
55830
55909
|
const notes = opts.verbose && d4.notes ? ` \u2014 ${truncateText(d4.notes, 80)}` : "";
|
|
55831
|
-
|
|
55910
|
+
printLine(` ${d4.name} [${d4.status}]${notes}`);
|
|
55832
55911
|
}
|
|
55833
55912
|
if (results.length === 0)
|
|
55834
|
-
|
|
55913
|
+
printLine("No results.");
|
|
55835
55914
|
else
|
|
55836
|
-
|
|
55915
|
+
printLine(`
|
|
55837
55916
|
${compactHint(page, "result(s)", "Use --verbose for notes or domain get <id|name> for details.")}`);
|
|
55838
55917
|
});
|
|
55839
55918
|
domain.command("expiring").description("List domains expiring soon").option("--days <n>", "Days threshold", "30").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all matching domains").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
55840
55919
|
const domains = await listExpiring2(parseInt(opts.days));
|
|
55841
55920
|
if (opts.json) {
|
|
55842
|
-
|
|
55921
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
55843
55922
|
return;
|
|
55844
55923
|
}
|
|
55845
55924
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
55846
55925
|
if (page.items.length === 0) {
|
|
55847
|
-
|
|
55926
|
+
printLine(`No domains expiring within ${opts.days} days.`);
|
|
55848
55927
|
return;
|
|
55849
55928
|
}
|
|
55850
|
-
|
|
55929
|
+
printLine(`
|
|
55851
55930
|
Expiring within ${opts.days} days:`);
|
|
55852
55931
|
for (const d4 of page.items)
|
|
55853
|
-
|
|
55854
|
-
|
|
55932
|
+
printLine(` ${d4.name.padEnd(40)} expires ${formatDate(d4.expires_at)}`);
|
|
55933
|
+
printLine(`
|
|
55855
55934
|
${compactHint(page, "domain(s)", "Use --all to display every expiring domain.", { paging: "limit" })}`);
|
|
55856
55935
|
});
|
|
55857
55936
|
domain.command("stats").description("Show portfolio statistics").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
55858
55937
|
const stats = await getDomainStats2();
|
|
55859
55938
|
if (opts.json) {
|
|
55860
|
-
|
|
55939
|
+
printLine(JSON.stringify(stats, null, 2));
|
|
55861
55940
|
return;
|
|
55862
55941
|
}
|
|
55863
|
-
|
|
55942
|
+
printLine("Domain Portfolio Stats:");
|
|
55864
55943
|
for (const [k4, v2] of Object.entries(stats)) {
|
|
55865
|
-
|
|
55944
|
+
printLine(` ${k4.replace(/_/g, " ")}: ${v2}`);
|
|
55866
55945
|
}
|
|
55867
55946
|
});
|
|
55868
55947
|
domain.command("whois <name>").description("Run WHOIS lookup and update local DB record").option("-j, --json", "Output JSON").action(async (name, opts) => {
|
|
55869
55948
|
try {
|
|
55870
55949
|
const result = await whoisLookup(name);
|
|
55871
55950
|
if (opts.json) {
|
|
55872
|
-
|
|
55951
|
+
printLine(JSON.stringify(result, null, 2));
|
|
55873
55952
|
return;
|
|
55874
55953
|
}
|
|
55875
|
-
|
|
55954
|
+
printLine(`
|
|
55876
55955
|
WHOIS for ${result.domain} [${result.source}]:`);
|
|
55877
|
-
|
|
55878
|
-
|
|
55956
|
+
printLine(` Registrar: ${result.registrar ?? "unknown"}`);
|
|
55957
|
+
printLine(` Expires: ${result.expires_at ?? "unknown"}`);
|
|
55879
55958
|
if (result.nameservers.length) {
|
|
55880
|
-
|
|
55959
|
+
printLine(` NS: ${result.nameservers.join(", ")}`);
|
|
55881
55960
|
}
|
|
55882
55961
|
const r4 = result.registrant;
|
|
55883
55962
|
if (r4?.name || r4?.email || r4?.organization) {
|
|
55884
|
-
|
|
55963
|
+
printLine(` Registrant:`);
|
|
55885
55964
|
if (r4.name)
|
|
55886
|
-
|
|
55965
|
+
printLine(` Name: ${r4.name}`);
|
|
55887
55966
|
if (r4.email)
|
|
55888
|
-
|
|
55967
|
+
printLine(` Email: ${r4.email}`);
|
|
55889
55968
|
if (r4.phone)
|
|
55890
|
-
|
|
55969
|
+
printLine(` Phone: ${r4.phone}`);
|
|
55891
55970
|
if (r4.organization)
|
|
55892
|
-
|
|
55971
|
+
printLine(` Org: ${r4.organization}`);
|
|
55893
55972
|
}
|
|
55894
|
-
|
|
55973
|
+
printLine();
|
|
55895
55974
|
} catch (error) {
|
|
55896
|
-
|
|
55975
|
+
printErrorLine(`WHOIS lookup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
55897
55976
|
process.exit(1);
|
|
55898
55977
|
}
|
|
55899
55978
|
});
|
|
55900
55979
|
domain.command("export").description("Export all domains as CSV or JSON").option("--format <fmt>", "Format: csv or json", "json").action(async (opts) => {
|
|
55901
55980
|
const output = await exportPortfolio(opts.format);
|
|
55902
|
-
|
|
55981
|
+
printLine(output);
|
|
55903
55982
|
});
|
|
55904
55983
|
domain.command("check <domains...>").description("Check domain availability via configured registrar").option("--provider <name>", "Registrar provider to use").option("-j, --json", "Output JSON").action(async (domains, opts) => {
|
|
55905
55984
|
const cfg = loadConfig3();
|
|
@@ -55917,19 +55996,19 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55917
55996
|
const error = reason instanceof Error ? reason.message : String(reason);
|
|
55918
55997
|
output.push({ domain: domains[i4], error });
|
|
55919
55998
|
if (!opts.json) {
|
|
55920
|
-
|
|
55999
|
+
printErrorLine(`\u2717 ${domains[i4]}: ${error}`);
|
|
55921
56000
|
}
|
|
55922
56001
|
anyError = true;
|
|
55923
56002
|
} else {
|
|
55924
56003
|
const result = r4.value;
|
|
55925
56004
|
output.push({ domain: result.domain, available: result.available });
|
|
55926
56005
|
if (!opts.json) {
|
|
55927
|
-
|
|
56006
|
+
printLine(`${result.available ? "\u2713" : "\u2717"} ${result.domain} is ${result.available ? "available" : "not available"}`);
|
|
55928
56007
|
}
|
|
55929
56008
|
}
|
|
55930
56009
|
}
|
|
55931
56010
|
if (opts.json) {
|
|
55932
|
-
|
|
56011
|
+
printLine(JSON.stringify({
|
|
55933
56012
|
provider: providerName,
|
|
55934
56013
|
count: output.length,
|
|
55935
56014
|
ok: !anyError,
|
|
@@ -55938,11 +56017,11 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55938
56017
|
} else {
|
|
55939
56018
|
for (const result of output) {
|
|
55940
56019
|
if (result.available !== undefined && "is_premium" in result && result.is_premium) {
|
|
55941
|
-
|
|
56020
|
+
printLine(` Premium ask: ${result.premium_price ?? "unknown"}`);
|
|
55942
56021
|
}
|
|
55943
56022
|
if ("standard_price" in result && result.standard_price !== undefined) {
|
|
55944
56023
|
const currency = "currency" in result && result.currency ? ` ${result.currency}` : "";
|
|
55945
|
-
|
|
56024
|
+
printLine(` Standard price: ${result.standard_price}${currency}`);
|
|
55946
56025
|
}
|
|
55947
56026
|
}
|
|
55948
56027
|
}
|
|
@@ -55968,11 +56047,11 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55968
56047
|
try {
|
|
55969
56048
|
const provider = getDomainInventoryProvider(name);
|
|
55970
56049
|
const result = await provider.syncToLocalDb({ getDomainByName: getDomainByName2, createDomain: createDomain2, updateDomain: updateDomain2 });
|
|
55971
|
-
|
|
56050
|
+
printLine(`\u2713 [${name}] Synced ${result.synced} (${result.created} new, ${result.updated} updated)`);
|
|
55972
56051
|
if (result.errors.length > 0)
|
|
55973
|
-
|
|
56052
|
+
printLine(` Errors: ${result.errors.join(", ")}`);
|
|
55974
56053
|
} catch (e4) {
|
|
55975
|
-
|
|
56054
|
+
printErrorLine(`\u2717 [${name}] ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
55976
56055
|
}
|
|
55977
56056
|
}
|
|
55978
56057
|
});
|
|
@@ -55981,14 +56060,14 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55981
56060
|
const standardPrice = parseOptionalNumber(opts.standard, "--standard");
|
|
55982
56061
|
const updated = await markDomainPremium2(identifier, premiumPrice, standardPrice);
|
|
55983
56062
|
if (!updated) {
|
|
55984
|
-
|
|
56063
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
55985
56064
|
process.exit(1);
|
|
55986
56065
|
}
|
|
55987
56066
|
if (opts.json) {
|
|
55988
|
-
|
|
56067
|
+
printLine(JSON.stringify(updated, null, 2));
|
|
55989
56068
|
return;
|
|
55990
56069
|
}
|
|
55991
|
-
|
|
56070
|
+
printLine(`Marked ${updated.name} as premium at ${premiumPrice}`);
|
|
55992
56071
|
});
|
|
55993
56072
|
domain.command("offer <identifier>").description("Record a negotiation step for a domain").option("--our <price>", "Our offer").option("--their <price>", "Their asking price").option("--status <status>", `Offer status (${DOMAIN_OFFER_STATUS_HELP})`, "pending").option("--notes <text>", "Negotiation notes").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
55994
56073
|
const details = await requireDomain(identifier);
|
|
@@ -56003,37 +56082,37 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56003
56082
|
await updateDomainLifecycleStatus2(details.domain.id, opts.their || opts.our ? "negotiating" : "offered");
|
|
56004
56083
|
}
|
|
56005
56084
|
if (opts.json) {
|
|
56006
|
-
|
|
56085
|
+
printLine(JSON.stringify(offer, null, 2));
|
|
56007
56086
|
return;
|
|
56008
56087
|
}
|
|
56009
|
-
|
|
56088
|
+
printLine(`Logged offer for ${details.domain.name}: ${offer.status}`);
|
|
56010
56089
|
});
|
|
56011
56090
|
domain.command("status <identifier> <status>").description("Update the lifecycle status of a domain").option("--notes <text>", "Optional note to store with the status change").option("-j, --json", "Output JSON").action(async (identifier, status, opts) => {
|
|
56012
56091
|
const updated = await updateDomainLifecycleStatus2(identifier, status, opts.notes);
|
|
56013
56092
|
if (!updated) {
|
|
56014
|
-
|
|
56093
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
56015
56094
|
process.exit(1);
|
|
56016
56095
|
}
|
|
56017
56096
|
if (opts.json) {
|
|
56018
|
-
|
|
56097
|
+
printLine(JSON.stringify(updated, null, 2));
|
|
56019
56098
|
return;
|
|
56020
56099
|
}
|
|
56021
|
-
|
|
56100
|
+
printLine(`Updated ${updated.name} to ${updated.status}`);
|
|
56022
56101
|
});
|
|
56023
56102
|
domain.command("emails <identifier>").description("Show email threads linked to a domain").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
56024
56103
|
const details = await requireDomain(identifier);
|
|
56025
56104
|
const emails = await listDomainEmailLinks2(details.domain.id);
|
|
56026
56105
|
if (opts.json) {
|
|
56027
|
-
|
|
56106
|
+
printLine(JSON.stringify({ domain: details.domain.name, emails, count: emails.length }, null, 2));
|
|
56028
56107
|
return;
|
|
56029
56108
|
}
|
|
56030
56109
|
if (emails.length === 0) {
|
|
56031
|
-
|
|
56110
|
+
printLine(`No linked emails for ${details.domain.name}.`);
|
|
56032
56111
|
return;
|
|
56033
56112
|
}
|
|
56034
56113
|
for (const email of emails) {
|
|
56035
56114
|
const threadPart = email.thread_id ? ` (${email.thread_id})` : "";
|
|
56036
|
-
|
|
56115
|
+
printLine(` ${email.type}: ${email.email_id}${threadPart}`);
|
|
56037
56116
|
}
|
|
56038
56117
|
});
|
|
56039
56118
|
domain.command("link-email <identifier> <emailId>").description("Link an email or email thread to a domain").requiredOption("--type <type>", `Link type (${DOMAIN_EMAIL_TYPE_HELP})`).option("--thread-id <threadId>", "Email thread ID").option("-j, --json", "Output JSON").action(async (identifier, emailId, opts) => {
|
|
@@ -56045,25 +56124,25 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56045
56124
|
type: opts.type
|
|
56046
56125
|
});
|
|
56047
56126
|
if (opts.json) {
|
|
56048
|
-
|
|
56127
|
+
printLine(JSON.stringify(link, null, 2));
|
|
56049
56128
|
return;
|
|
56050
56129
|
}
|
|
56051
|
-
|
|
56130
|
+
printLine(`Linked ${emailId} to ${details.domain.name}`);
|
|
56052
56131
|
});
|
|
56053
56132
|
domain.command("renew <name>").description("Renew a domain via its registrar provider").option("--provider <name>", "Override provider").option("--years <n>", "Number of years to renew", "1").action(async (name, opts) => {
|
|
56054
56133
|
const providerName = opts.provider ?? await autoDetectRegistrar(name, getDomainByName2) ?? loadConfig3().default_registrar;
|
|
56055
56134
|
if (!providerName) {
|
|
56056
|
-
|
|
56135
|
+
printErrorLine("Could not detect provider. Use --provider.");
|
|
56057
56136
|
process.exit(1);
|
|
56058
56137
|
}
|
|
56059
56138
|
const provider = getRegistrarProvider(providerName);
|
|
56060
56139
|
const result = await provider.renewDomain(name, parseInt(opts.years, 10));
|
|
56061
56140
|
if (result.success) {
|
|
56062
|
-
|
|
56141
|
+
printLine(`\u2713 Renewed: ${name}`);
|
|
56063
56142
|
if (result.orderId)
|
|
56064
|
-
|
|
56143
|
+
printLine(` Order: ${result.orderId}`);
|
|
56065
56144
|
} else {
|
|
56066
|
-
|
|
56145
|
+
printErrorLine(`\u2717 Renewal failed or not supported for ${providerName}`);
|
|
56067
56146
|
process.exit(1);
|
|
56068
56147
|
}
|
|
56069
56148
|
});
|
|
@@ -56080,13 +56159,13 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56080
56159
|
auto_renew: opts.autoRenew ? opts.autoRenew === "true" : domainRecord.auto_renew
|
|
56081
56160
|
});
|
|
56082
56161
|
if (!purchased) {
|
|
56083
|
-
|
|
56162
|
+
printErrorLine(`Domain '${name}' not found.`);
|
|
56084
56163
|
process.exit(1);
|
|
56085
56164
|
}
|
|
56086
56165
|
if (opts.wait) {
|
|
56087
56166
|
await updateDomainLifecycleStatus2(purchased.id, "active");
|
|
56088
56167
|
}
|
|
56089
|
-
|
|
56168
|
+
printLine(`Recorded purchase for ${purchased.name} at ${recordedPrice}`);
|
|
56090
56169
|
return;
|
|
56091
56170
|
}
|
|
56092
56171
|
const cfg = loadConfig3();
|
|
@@ -56094,44 +56173,44 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56094
56173
|
const dnsProvider = opts.dns ?? cfg.default_dns ?? "cloudflare";
|
|
56095
56174
|
const purchaseProfile = providerName === "route53" ? applyPurchaseProfile() : undefined;
|
|
56096
56175
|
if (purchaseProfile)
|
|
56097
|
-
|
|
56176
|
+
printLine(`Using purchase AWS profile: ${purchaseProfile}`);
|
|
56098
56177
|
if (providerName !== "route53") {
|
|
56099
56178
|
try {
|
|
56100
56179
|
const capability = getCapability(providerName);
|
|
56101
56180
|
if (!capability.canBuy) {
|
|
56102
|
-
|
|
56181
|
+
printErrorLine(`Direct domain purchase is not supported for ${providerName}. ${capability.notes} Use route53 or record a marketplace/manual purchase with --price.`);
|
|
56103
56182
|
process.exit(1);
|
|
56104
56183
|
}
|
|
56105
56184
|
if (capability.gated && !opts.allowGated) {
|
|
56106
|
-
|
|
56185
|
+
printErrorLine(`Registrar '${providerName}' is gated/enterprise-only. Pass --allow-gated only when this account is contract-approved. ${capability.notes}`);
|
|
56107
56186
|
process.exit(1);
|
|
56108
56187
|
}
|
|
56109
56188
|
const provider = getRegistrarProvider(providerName);
|
|
56110
56189
|
if (!provider.registerDomain) {
|
|
56111
|
-
|
|
56190
|
+
printErrorLine(`Direct domain purchase is not supported for ${providerName}. Use route53 or record a marketplace/manual purchase with --price.`);
|
|
56112
56191
|
process.exit(1);
|
|
56113
56192
|
}
|
|
56114
56193
|
const avail = await provider.checkAvailability(name);
|
|
56115
56194
|
if (!avail.available) {
|
|
56116
|
-
|
|
56195
|
+
printErrorLine(`\u2717 ${name} is not available`);
|
|
56117
56196
|
process.exit(1);
|
|
56118
56197
|
}
|
|
56119
|
-
|
|
56198
|
+
printLine(`\u2713 Available via ${providerName}`);
|
|
56120
56199
|
let contact;
|
|
56121
56200
|
try {
|
|
56122
56201
|
contact = resolveContact(opts);
|
|
56123
56202
|
} catch (e4) {
|
|
56124
|
-
|
|
56203
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56125
56204
|
process.exit(1);
|
|
56126
56205
|
}
|
|
56127
|
-
|
|
56206
|
+
printLine(`Registering ${name} via ${providerName}...`);
|
|
56128
56207
|
const reg = await provider.registerDomain(name, contact, {
|
|
56129
56208
|
years: parseInt(opts.years, 10),
|
|
56130
56209
|
premiumPrice: avail.premium_price,
|
|
56131
56210
|
autoRenew: opts.autoRenew ? opts.autoRenew === "true" : true
|
|
56132
56211
|
});
|
|
56133
56212
|
if (!reg.success) {
|
|
56134
|
-
|
|
56213
|
+
printErrorLine(`\u2717 Registration failed via ${providerName}`);
|
|
56135
56214
|
process.exit(1);
|
|
56136
56215
|
}
|
|
56137
56216
|
const existing = await getDomainByName2(name);
|
|
@@ -56149,45 +56228,45 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56149
56228
|
await updateDomain2(existing.id, dbInput);
|
|
56150
56229
|
else
|
|
56151
56230
|
await createDomain2({ name, ...dbInput });
|
|
56152
|
-
|
|
56231
|
+
printLine(`\u2713 Registered and added to portfolio`);
|
|
56153
56232
|
if (reg.orderId)
|
|
56154
|
-
|
|
56233
|
+
printLine(` Order: ${reg.orderId}`);
|
|
56155
56234
|
if (opts.delegate !== false) {
|
|
56156
56235
|
if (!provider.updateNameservers) {
|
|
56157
|
-
|
|
56236
|
+
printLine(` DNS: ${providerName} registration succeeded, but nameserver updates are not implemented for this provider.`);
|
|
56158
56237
|
} else {
|
|
56159
56238
|
const zone = await createDnsZoneForProvider(name, dnsProvider);
|
|
56160
56239
|
const nsUpdate = await provider.updateNameservers(name, zone.nameservers);
|
|
56161
56240
|
const existing2 = await getDomainByName2(name);
|
|
56162
56241
|
if (existing2)
|
|
56163
56242
|
await updateDomain2(existing2.id, { nameservers: zone.nameservers });
|
|
56164
|
-
|
|
56243
|
+
printLine(`\u2713 ${dnsProvider} zone ${zone.zoneId}; nameservers updated${nsUpdate.operationId ? ` (op ${nsUpdate.operationId})` : ""}`);
|
|
56165
56244
|
}
|
|
56166
56245
|
}
|
|
56167
56246
|
return;
|
|
56168
56247
|
} catch (e4) {
|
|
56169
|
-
|
|
56248
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56170
56249
|
process.exit(1);
|
|
56171
56250
|
}
|
|
56172
56251
|
}
|
|
56173
56252
|
try {
|
|
56174
56253
|
const avail = await checkAvailability3(name);
|
|
56175
56254
|
if (!avail.available) {
|
|
56176
|
-
|
|
56255
|
+
printErrorLine(`\u2717 ${name} is not available`);
|
|
56177
56256
|
process.exit(1);
|
|
56178
56257
|
}
|
|
56179
56258
|
const price = avail.price ? ` (USD ${avail.price}/yr)` : "";
|
|
56180
|
-
|
|
56259
|
+
printLine(`\u2713 Available${price}`);
|
|
56181
56260
|
let contact;
|
|
56182
56261
|
try {
|
|
56183
56262
|
contact = resolveContact(opts);
|
|
56184
56263
|
} catch (e4) {
|
|
56185
|
-
|
|
56264
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56186
56265
|
process.exit(1);
|
|
56187
56266
|
}
|
|
56188
|
-
|
|
56267
|
+
printLine(`Registering ${name}...`);
|
|
56189
56268
|
const reg = await registerDomain2(name, contact, parseInt(opts.years));
|
|
56190
|
-
|
|
56269
|
+
printLine(`\u2713 Submitted (operation: ${reg.operationId})`);
|
|
56191
56270
|
if (opts.wait) {
|
|
56192
56271
|
let status = "IN_PROGRESS";
|
|
56193
56272
|
while (status === "IN_PROGRESS" || status === "SUBMITTED") {
|
|
@@ -56196,12 +56275,12 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56196
56275
|
status = s2.status;
|
|
56197
56276
|
process.stdout.write(` Status: ${status}\r`);
|
|
56198
56277
|
}
|
|
56199
|
-
|
|
56278
|
+
printLine();
|
|
56200
56279
|
if (status !== "SUCCESSFUL") {
|
|
56201
|
-
|
|
56280
|
+
printErrorLine(`\u2717 Registration ${status}`);
|
|
56202
56281
|
process.exit(1);
|
|
56203
56282
|
}
|
|
56204
|
-
|
|
56283
|
+
printLine(`\u2713 Registration complete`);
|
|
56205
56284
|
}
|
|
56206
56285
|
const existing = await getDomainByName2(name);
|
|
56207
56286
|
if (existing) {
|
|
@@ -56224,13 +56303,13 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56224
56303
|
standard_price: avail.price ? Number(avail.price) : undefined
|
|
56225
56304
|
});
|
|
56226
56305
|
}
|
|
56227
|
-
|
|
56306
|
+
printLine(`\u2713 Added to portfolio`);
|
|
56228
56307
|
if (opts.delegate !== false) {
|
|
56229
56308
|
if (!opts.wait) {
|
|
56230
|
-
|
|
56309
|
+
printLine(` DNS: run 'domains domain buy ${name} --wait' or delegate later \u2014 registration must finish before NS can change.`);
|
|
56231
56310
|
} else {
|
|
56232
56311
|
try {
|
|
56233
|
-
|
|
56312
|
+
printLine(`Delegating DNS to ${dnsProvider}...`);
|
|
56234
56313
|
const del = dnsProvider === "cloudflare" ? await delegateDomainToCloudflare(name, {
|
|
56235
56314
|
createCloudflareZone: async (d4) => {
|
|
56236
56315
|
const z = await ensureZone(d4);
|
|
@@ -56245,17 +56324,17 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56245
56324
|
const existing2 = await getDomainByName2(name);
|
|
56246
56325
|
if (existing2)
|
|
56247
56326
|
await updateDomain2(existing2.id, { nameservers: del.nameservers });
|
|
56248
|
-
|
|
56327
|
+
printLine(`\u2713 ${dnsProvider} zone ${del.zoneId}; nameservers \u2192 ${del.nameservers.join(", ")} (op ${del.operationId})`);
|
|
56249
56328
|
} catch (e4) {
|
|
56250
|
-
|
|
56251
|
-
|
|
56329
|
+
printErrorLine(`\u26A0 DNS delegation failed (domain is registered): ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56330
|
+
printErrorLine(` Retry: create the DNS zone and point Route53 NS at it.`);
|
|
56252
56331
|
}
|
|
56253
56332
|
}
|
|
56254
56333
|
}
|
|
56255
56334
|
if (!opts.wait)
|
|
56256
|
-
|
|
56335
|
+
printLine(` Check: domains r53 status ${reg.operationId}`);
|
|
56257
56336
|
} catch (e4) {
|
|
56258
|
-
|
|
56337
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56259
56338
|
process.exit(1);
|
|
56260
56339
|
}
|
|
56261
56340
|
});
|
|
@@ -56263,34 +56342,34 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56263
56342
|
const cfg = loadConfig3();
|
|
56264
56343
|
const registrarName = opts.registrar ?? cfg.default_registrar ?? "route53";
|
|
56265
56344
|
const dnsName = opts.dns ?? cfg.default_dns ?? "cloudflare";
|
|
56266
|
-
|
|
56345
|
+
printLine(`
|
|
56267
56346
|
Setting up ${name}`);
|
|
56268
|
-
|
|
56347
|
+
printLine(` Registrar: ${registrarName} | DNS: ${dnsName}
|
|
56269
56348
|
`);
|
|
56270
56349
|
try {
|
|
56271
56350
|
process.stdout.write(opts.wait ? "[1/5] Checking availability... " : "[1/4] Checking availability... ");
|
|
56272
56351
|
const avail = await checkAvailability3(name);
|
|
56273
56352
|
if (!avail.available) {
|
|
56274
|
-
|
|
56275
|
-
|
|
56353
|
+
printLine("not available");
|
|
56354
|
+
printErrorLine(`\u2717 ${name} is not available`);
|
|
56276
56355
|
process.exit(1);
|
|
56277
56356
|
}
|
|
56278
56357
|
const price = avail.price ? `(USD ${avail.price}/yr)` : "";
|
|
56279
|
-
|
|
56358
|
+
printLine(`available ${price}`);
|
|
56280
56359
|
if (registrarName !== "route53") {
|
|
56281
|
-
|
|
56360
|
+
printErrorLine("Direct domain purchase currently only supported via route53.");
|
|
56282
56361
|
process.exit(1);
|
|
56283
56362
|
}
|
|
56284
56363
|
let contact;
|
|
56285
56364
|
try {
|
|
56286
56365
|
contact = resolveContact(opts);
|
|
56287
56366
|
} catch (e4) {
|
|
56288
|
-
|
|
56367
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56289
56368
|
process.exit(1);
|
|
56290
56369
|
}
|
|
56291
56370
|
process.stdout.write(opts.wait ? "[2/5] Registering domain... " : "[2/4] Registering domain... ");
|
|
56292
56371
|
const reg = await registerDomain2(name, contact, parseInt(opts.years));
|
|
56293
|
-
|
|
56372
|
+
printLine(`submitted (${reg.operationId})`);
|
|
56294
56373
|
if (opts.wait) {
|
|
56295
56374
|
let status = "IN_PROGRESS";
|
|
56296
56375
|
while (status === "IN_PROGRESS" || status === "SUBMITTED") {
|
|
@@ -56299,36 +56378,36 @@ Setting up ${name}`);
|
|
|
56299
56378
|
status = s2.status;
|
|
56300
56379
|
process.stdout.write(` Waiting: ${status}...\r`);
|
|
56301
56380
|
}
|
|
56302
|
-
|
|
56381
|
+
printLine();
|
|
56303
56382
|
if (status !== "SUCCESSFUL") {
|
|
56304
|
-
|
|
56383
|
+
printErrorLine(`\u2717 Registration ${status}`);
|
|
56305
56384
|
process.exit(1);
|
|
56306
56385
|
}
|
|
56307
|
-
|
|
56386
|
+
printLine(" Registration confirmed");
|
|
56308
56387
|
}
|
|
56309
56388
|
process.stdout.write(opts.wait ? "[3/5] Creating DNS zone... " : "[3/4] Creating DNS zone... ");
|
|
56310
56389
|
let nameservers = [];
|
|
56311
56390
|
if (dnsName === "cloudflare") {
|
|
56312
56391
|
const zone = await ensureZone(name);
|
|
56313
56392
|
nameservers = zone.nameservers ?? [];
|
|
56314
|
-
|
|
56393
|
+
printLine("ready (" + zone.id + ")");
|
|
56315
56394
|
} else {
|
|
56316
56395
|
const zone = await createHostedZone(name, "Managed by domains CLI");
|
|
56317
56396
|
nameservers = zone.name_servers ?? [];
|
|
56318
|
-
|
|
56397
|
+
printLine(`created (${zone.id})`);
|
|
56319
56398
|
}
|
|
56320
56399
|
if (nameservers.length > 0) {
|
|
56321
56400
|
if (opts.wait) {
|
|
56322
56401
|
process.stdout.write("[4/5] Updating registrar nameservers... ");
|
|
56323
56402
|
if (registrarName !== "route53") {
|
|
56324
|
-
|
|
56325
|
-
|
|
56403
|
+
printLine("skipped");
|
|
56404
|
+
printErrorLine("Only Route53 nameserver delegation is currently implemented for setup.");
|
|
56326
56405
|
process.exit(1);
|
|
56327
56406
|
}
|
|
56328
56407
|
const nsUpdate = await updateNameservers2(name, nameservers);
|
|
56329
|
-
|
|
56408
|
+
printLine("submitted (" + nsUpdate.operationId + ")");
|
|
56330
56409
|
} else {
|
|
56331
|
-
|
|
56410
|
+
printLine(" Nameserver delegation skipped until registration completes; re-run with --wait or use domains r53 domain-info/status first.");
|
|
56332
56411
|
}
|
|
56333
56412
|
}
|
|
56334
56413
|
process.stdout.write(opts.wait ? "[5/5] Adding to portfolio... " : "[4/4] Adding to portfolio... ");
|
|
@@ -56338,22 +56417,22 @@ Setting up ${name}`);
|
|
|
56338
56417
|
await updateDomain2(existing.id, dbInput);
|
|
56339
56418
|
else
|
|
56340
56419
|
await createDomain2({ name, ...dbInput });
|
|
56341
|
-
|
|
56342
|
-
|
|
56420
|
+
printLine("done");
|
|
56421
|
+
printLine(`
|
|
56343
56422
|
\u2713 Setup complete for ${name}`);
|
|
56344
56423
|
if (!opts.wait) {
|
|
56345
|
-
|
|
56346
|
-
|
|
56424
|
+
printLine(` \u26A0 Registration pending \u2014 check: domains r53 status ${reg.operationId}`);
|
|
56425
|
+
printLine(` \u26A0 If registration fails, clean up: domains zone delete <zoneId> --force`);
|
|
56347
56426
|
}
|
|
56348
56427
|
if (nameservers.length > 0) {
|
|
56349
|
-
|
|
56428
|
+
printLine(`
|
|
56350
56429
|
Point your registrar to these name servers:`);
|
|
56351
56430
|
for (const ns of nameservers)
|
|
56352
|
-
|
|
56431
|
+
printLine(` ${ns}`);
|
|
56353
56432
|
}
|
|
56354
|
-
|
|
56433
|
+
printLine();
|
|
56355
56434
|
} catch (e4) {
|
|
56356
|
-
|
|
56435
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56357
56436
|
process.exit(1);
|
|
56358
56437
|
}
|
|
56359
56438
|
});
|
|
@@ -56472,6 +56551,7 @@ function getDnsApplyBlockReason(plan, opts) {
|
|
|
56472
56551
|
}
|
|
56473
56552
|
|
|
56474
56553
|
// src/cli/commands/dns.ts
|
|
56554
|
+
init_stdout();
|
|
56475
56555
|
var SUPPORTED_DNS_TYPES = new Set(["A", "AAAA", "CNAME", "MX", "TXT", "NS", "SRV"]);
|
|
56476
56556
|
function partitionPullableRecords(records) {
|
|
56477
56557
|
const keep = [];
|
|
@@ -56486,13 +56566,13 @@ function partitionPullableRecords(records) {
|
|
|
56486
56566
|
return { keep, skipped };
|
|
56487
56567
|
}
|
|
56488
56568
|
function printDnsPlan(plan) {
|
|
56489
|
-
|
|
56569
|
+
printLine(`DNS plan for ${plan.domain}: ${plan.creates} create, ${plan.updates} update, ${plan.deletes} delete, ${plan.unchanged} unchanged`);
|
|
56490
56570
|
for (const op of plan.operations) {
|
|
56491
56571
|
if (op.op === "unchanged")
|
|
56492
56572
|
continue;
|
|
56493
56573
|
const priority = op.record.priority == null ? "" : ` priority=${op.record.priority}`;
|
|
56494
56574
|
const currentTtl = op.current && op.current.ttl !== op.record.ttl ? ` ttl ${op.current.ttl}->${op.record.ttl}` : "";
|
|
56495
|
-
|
|
56575
|
+
printLine(` ${op.op.toUpperCase()} ${op.record.type} ${op.record.name} ${op.record.value} ttl=${op.record.ttl}${priority}${currentTtl}`);
|
|
56496
56576
|
}
|
|
56497
56577
|
}
|
|
56498
56578
|
async function loadDnsPlan(domain, providerName, file) {
|
|
@@ -56509,11 +56589,11 @@ function registerDnsCommands(program2) {
|
|
|
56509
56589
|
try {
|
|
56510
56590
|
const plan = await loadDnsPlan(domain, providerName, opts.file);
|
|
56511
56591
|
if (opts.json)
|
|
56512
|
-
|
|
56592
|
+
printLine(JSON.stringify(plan, null, 2));
|
|
56513
56593
|
else
|
|
56514
56594
|
printDnsPlan(plan);
|
|
56515
56595
|
} catch (e4) {
|
|
56516
|
-
|
|
56596
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56517
56597
|
process.exit(1);
|
|
56518
56598
|
}
|
|
56519
56599
|
});
|
|
@@ -56522,13 +56602,13 @@ function registerDnsCommands(program2) {
|
|
|
56522
56602
|
try {
|
|
56523
56603
|
const plan = await loadDnsPlan(domain, providerName, opts.file);
|
|
56524
56604
|
if (opts.json)
|
|
56525
|
-
|
|
56605
|
+
printLine(JSON.stringify(plan, null, 2));
|
|
56526
56606
|
else
|
|
56527
56607
|
printDnsPlan(plan);
|
|
56528
56608
|
if (planHasChanges(plan))
|
|
56529
56609
|
process.exitCode = 2;
|
|
56530
56610
|
} catch (e4) {
|
|
56531
|
-
|
|
56611
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56532
56612
|
process.exit(1);
|
|
56533
56613
|
}
|
|
56534
56614
|
});
|
|
@@ -56542,7 +56622,7 @@ function registerDnsCommands(program2) {
|
|
|
56542
56622
|
const plan = createDnsPlan(planDomain, current, desired.records);
|
|
56543
56623
|
if (!planHasChanges(plan)) {
|
|
56544
56624
|
if (opts.json)
|
|
56545
|
-
|
|
56625
|
+
printLine(JSON.stringify({ applied: false, reason: "no-changes", plan }, null, 2));
|
|
56546
56626
|
else
|
|
56547
56627
|
printDnsPlan(plan);
|
|
56548
56628
|
return;
|
|
@@ -56550,15 +56630,15 @@ function registerDnsCommands(program2) {
|
|
|
56550
56630
|
const blockReason = getDnsApplyBlockReason(plan, { yes: opts.yes, allowDelete: opts.allowDelete });
|
|
56551
56631
|
if (blockReason) {
|
|
56552
56632
|
if (opts.json)
|
|
56553
|
-
|
|
56633
|
+
printLine(JSON.stringify({ applied: false, reason: blockReason, plan }, null, 2));
|
|
56554
56634
|
else {
|
|
56555
56635
|
printDnsPlan(plan);
|
|
56556
56636
|
if (blockReason === "confirmation-required")
|
|
56557
|
-
|
|
56637
|
+
printErrorLine("Refusing to apply without --yes.");
|
|
56558
56638
|
if (blockReason === "delete-confirmation-required")
|
|
56559
|
-
|
|
56639
|
+
printErrorLine("Refusing to delete DNS records without --allow-delete.");
|
|
56560
56640
|
if (blockReason === "delete-apply-unsupported")
|
|
56561
|
-
|
|
56641
|
+
printErrorLine(`Refusing to apply delete plan on ${providerName}: this provider path cannot guarantee delete convergence without partial mutation yet.`);
|
|
56562
56642
|
}
|
|
56563
56643
|
process.exit(1);
|
|
56564
56644
|
}
|
|
@@ -56566,39 +56646,39 @@ function registerDnsCommands(program2) {
|
|
|
56566
56646
|
const verified = createDnsPlan(planDomain, await provider.getDnsRecords(planDomain), desired.records);
|
|
56567
56647
|
if (planHasChanges(verified)) {
|
|
56568
56648
|
if (opts.json)
|
|
56569
|
-
|
|
56649
|
+
printLine(JSON.stringify({ applied: false, provider: providerName, reason: "verification-failed", plan, verification: verified }, null, 2));
|
|
56570
56650
|
else {
|
|
56571
56651
|
printDnsPlan(verified);
|
|
56572
|
-
|
|
56652
|
+
printErrorLine(`Provider ${providerName} did not converge to the desired DNS state for ${planDomain}.`);
|
|
56573
56653
|
}
|
|
56574
56654
|
process.exit(1);
|
|
56575
56655
|
}
|
|
56576
56656
|
if (opts.json)
|
|
56577
|
-
|
|
56657
|
+
printLine(JSON.stringify({ applied: true, provider: providerName, plan, verification: verified }, null, 2));
|
|
56578
56658
|
else {
|
|
56579
56659
|
printDnsPlan(plan);
|
|
56580
|
-
|
|
56660
|
+
printLine(`\u2713 Applied and verified desired DNS state on ${providerName} for ${planDomain}`);
|
|
56581
56661
|
}
|
|
56582
56662
|
} catch (e4) {
|
|
56583
|
-
|
|
56663
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56584
56664
|
process.exit(1);
|
|
56585
56665
|
}
|
|
56586
56666
|
});
|
|
56587
56667
|
dnsCmd.command("list").description("List DNS records for a domain").argument("<domain-id>", "Domain ID").option("--type <type>", "Filter by record type (A/AAAA/CNAME/MX/TXT/NS/SRV)").option("--limit <n>", "Limit number of displayed records").option("--all", "Show all matching records").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
|
|
56588
56668
|
const records = await listDnsRecords2(domainId, opts.type);
|
|
56589
56669
|
if (opts.json) {
|
|
56590
|
-
|
|
56670
|
+
printLine(JSON.stringify(records, null, 2));
|
|
56591
56671
|
} else {
|
|
56592
56672
|
const page = pageItemsOrExit(records, { limit: opts.limit, all: opts.all });
|
|
56593
56673
|
if (page.items.length === 0) {
|
|
56594
|
-
|
|
56674
|
+
printLine("No DNS records found.");
|
|
56595
56675
|
return;
|
|
56596
56676
|
}
|
|
56597
56677
|
for (const r4 of page.items) {
|
|
56598
56678
|
const priority = r4.priority !== null ? ` (priority: ${r4.priority})` : "";
|
|
56599
|
-
|
|
56679
|
+
printLine(` ${r4.type} ${r4.name} ${truncateText(r4.value, 80)} TTL:${r4.ttl}${priority}`);
|
|
56600
56680
|
}
|
|
56601
|
-
|
|
56681
|
+
printLine(`
|
|
56602
56682
|
${compactHint(page, "record(s)", "Use --all for every record or --json for full values.", { paging: "limit" })}`);
|
|
56603
56683
|
}
|
|
56604
56684
|
});
|
|
@@ -56612,9 +56692,9 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56612
56692
|
priority: opts.priority ? parseInt(opts.priority) : undefined
|
|
56613
56693
|
});
|
|
56614
56694
|
if (opts.json) {
|
|
56615
|
-
|
|
56695
|
+
printLine(JSON.stringify(record, null, 2));
|
|
56616
56696
|
} else {
|
|
56617
|
-
|
|
56697
|
+
printLine(`Created DNS record: ${record.type} ${record.name} -> ${record.value} (${record.id})`);
|
|
56618
56698
|
}
|
|
56619
56699
|
});
|
|
56620
56700
|
dnsCmd.command("update").description("Update a DNS record").argument("<id>", "Record ID").option("--type <type>", "Record type").option("--name <name>", "Record name").option("--value <value>", "Record value").option("--ttl <ttl>", "TTL in seconds").option("--priority <n>", "Priority").option("--json", "Output as JSON", false).action(async (id, opts) => {
|
|
@@ -56631,21 +56711,21 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56631
56711
|
input.priority = parseInt(opts.priority);
|
|
56632
56712
|
const record = await updateDnsRecord2(id, input);
|
|
56633
56713
|
if (!record) {
|
|
56634
|
-
|
|
56714
|
+
printErrorLine(`DNS record '${id}' not found.`);
|
|
56635
56715
|
process.exit(1);
|
|
56636
56716
|
}
|
|
56637
56717
|
if (opts.json) {
|
|
56638
|
-
|
|
56718
|
+
printLine(JSON.stringify(record, null, 2));
|
|
56639
56719
|
} else {
|
|
56640
|
-
|
|
56720
|
+
printLine(`Updated DNS record: ${record.type} ${record.name} -> ${record.value}`);
|
|
56641
56721
|
}
|
|
56642
56722
|
});
|
|
56643
56723
|
dnsCmd.command("remove").description("Remove a DNS record").argument("<id>", "Record ID").action(async (id) => {
|
|
56644
56724
|
const deleted = await deleteDnsRecord2(id);
|
|
56645
56725
|
if (deleted) {
|
|
56646
|
-
|
|
56726
|
+
printLine(`Deleted DNS record ${id}`);
|
|
56647
56727
|
} else {
|
|
56648
|
-
|
|
56728
|
+
printErrorLine(`DNS record '${id}' not found.`);
|
|
56649
56729
|
process.exit(1);
|
|
56650
56730
|
}
|
|
56651
56731
|
});
|
|
@@ -56653,32 +56733,32 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56653
56733
|
try {
|
|
56654
56734
|
const result = await checkDnsPropagation(domain, opts.record);
|
|
56655
56735
|
if (opts.json) {
|
|
56656
|
-
|
|
56736
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56657
56737
|
} else {
|
|
56658
|
-
|
|
56659
|
-
|
|
56738
|
+
printLine(`DNS Propagation for ${result.domain} (${result.record_type}):`);
|
|
56739
|
+
printLine(` Consistent: ${result.consistent ? "yes" : "NO"}`);
|
|
56660
56740
|
for (const s2 of result.servers) {
|
|
56661
56741
|
const values = s2.values.length > 0 ? s2.values.join(", ") : "(empty)";
|
|
56662
56742
|
const status = s2.status === "error" ? ` [ERROR: ${s2.error}]` : "";
|
|
56663
|
-
|
|
56743
|
+
printLine(` ${s2.name} (${s2.server}): ${values}${status}`);
|
|
56664
56744
|
}
|
|
56665
56745
|
}
|
|
56666
56746
|
} catch (error) {
|
|
56667
|
-
|
|
56747
|
+
printErrorLine(`DNS propagation check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
56668
56748
|
process.exit(1);
|
|
56669
56749
|
}
|
|
56670
56750
|
});
|
|
56671
56751
|
dnsCmd.command("export").description("Export DNS records as BIND zone file").argument("<domain-id>", "Domain ID").option("--output <file>", "Write to file instead of stdout").action(async (domainId, opts) => {
|
|
56672
56752
|
const zone = await exportZoneFile(domainId);
|
|
56673
56753
|
if (!zone) {
|
|
56674
|
-
|
|
56754
|
+
printErrorLine(`Domain '${domainId}' not found.`);
|
|
56675
56755
|
process.exit(1);
|
|
56676
56756
|
}
|
|
56677
56757
|
if (opts.output) {
|
|
56678
56758
|
writeFileSync2(opts.output, zone, "utf-8");
|
|
56679
|
-
|
|
56759
|
+
printLine(`Exported zone file to ${opts.output}`);
|
|
56680
56760
|
} else {
|
|
56681
|
-
|
|
56761
|
+
printLine(zone);
|
|
56682
56762
|
}
|
|
56683
56763
|
});
|
|
56684
56764
|
dnsCmd.command("import").description("Import DNS records from a BIND zone file").argument("<domain-id>", "Domain ID").requiredOption("--file <path>", "Path to zone file").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
|
|
@@ -56686,22 +56766,22 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56686
56766
|
try {
|
|
56687
56767
|
content = readFileSync4(opts.file, "utf-8");
|
|
56688
56768
|
} catch {
|
|
56689
|
-
|
|
56769
|
+
printErrorLine(`Could not read file: ${opts.file}`);
|
|
56690
56770
|
process.exit(1);
|
|
56691
56771
|
}
|
|
56692
56772
|
const result = await importZoneFile(domainId, content);
|
|
56693
56773
|
if (!result) {
|
|
56694
|
-
|
|
56774
|
+
printErrorLine(`Domain '${domainId}' not found.`);
|
|
56695
56775
|
process.exit(1);
|
|
56696
56776
|
}
|
|
56697
56777
|
if (opts.json) {
|
|
56698
|
-
|
|
56778
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56699
56779
|
} else {
|
|
56700
|
-
|
|
56780
|
+
printLine(`Imported ${result.imported} record(s), skipped ${result.skipped}`);
|
|
56701
56781
|
if (result.errors.length > 0) {
|
|
56702
|
-
|
|
56782
|
+
printLine("Errors:");
|
|
56703
56783
|
for (const e4 of result.errors) {
|
|
56704
|
-
|
|
56784
|
+
printLine(` - ${e4}`);
|
|
56705
56785
|
}
|
|
56706
56786
|
}
|
|
56707
56787
|
}
|
|
@@ -56709,42 +56789,42 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56709
56789
|
dnsCmd.command("discover-subdomains").description("Discover subdomains via certificate transparency logs (crt.sh)").argument("<domain>", "Domain name").option("--limit <n>", "Limit number of displayed subdomains").option("--all", "Show all discovered subdomains").option("--json", "Output as JSON", false).action(async (domain, opts) => {
|
|
56710
56790
|
const result = await discoverSubdomains(domain);
|
|
56711
56791
|
if (opts.json) {
|
|
56712
|
-
|
|
56792
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56713
56793
|
} else {
|
|
56714
56794
|
if (result.error) {
|
|
56715
|
-
|
|
56795
|
+
printErrorLine(`Discovery failed: ${result.error}`);
|
|
56716
56796
|
process.exit(1);
|
|
56717
56797
|
}
|
|
56718
56798
|
if (result.subdomains.length === 0) {
|
|
56719
|
-
|
|
56799
|
+
printLine(`No subdomains found for ${domain}.`);
|
|
56720
56800
|
return;
|
|
56721
56801
|
}
|
|
56722
56802
|
const page = pageItemsOrExit(result.subdomains, { limit: opts.limit, all: opts.all });
|
|
56723
|
-
|
|
56803
|
+
printLine(`Subdomains for ${domain} (source: ${result.source}):`);
|
|
56724
56804
|
for (const s2 of page.items) {
|
|
56725
|
-
|
|
56805
|
+
printLine(` ${s2}`);
|
|
56726
56806
|
}
|
|
56727
|
-
|
|
56807
|
+
printLine(`
|
|
56728
56808
|
${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --json for the full result.", { paging: "limit" })}`);
|
|
56729
56809
|
}
|
|
56730
56810
|
});
|
|
56731
56811
|
dnsCmd.command("validate").description("Validate DNS records for common issues").argument("<domain-id>", "Domain ID").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
|
|
56732
56812
|
const result = await validateDns(domainId);
|
|
56733
56813
|
if (!result) {
|
|
56734
|
-
|
|
56814
|
+
printErrorLine(`Domain '${domainId}' not found.`);
|
|
56735
56815
|
process.exit(1);
|
|
56736
56816
|
}
|
|
56737
56817
|
if (opts.json) {
|
|
56738
|
-
|
|
56818
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56739
56819
|
} else {
|
|
56740
|
-
|
|
56741
|
-
|
|
56820
|
+
printLine(`DNS Validation for ${result.domain_name}:`);
|
|
56821
|
+
printLine(` Valid: ${result.valid ? "yes" : "NO"}`);
|
|
56742
56822
|
if (result.issues.length === 0) {
|
|
56743
|
-
|
|
56823
|
+
printLine(" No issues found.");
|
|
56744
56824
|
} else {
|
|
56745
56825
|
for (const issue of result.issues) {
|
|
56746
56826
|
const prefix = issue.type === "error" ? "ERROR" : "WARN";
|
|
56747
|
-
|
|
56827
|
+
printLine(` [${prefix}] ${issue.message}`);
|
|
56748
56828
|
}
|
|
56749
56829
|
}
|
|
56750
56830
|
}
|
|
@@ -56756,7 +56836,7 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56756
56836
|
const records = await provider.getDnsRecords(domain);
|
|
56757
56837
|
const dbDomain = await getDomainByName2(domain);
|
|
56758
56838
|
if (!dbDomain) {
|
|
56759
|
-
|
|
56839
|
+
printErrorLine(`Domain '${domain}' not found in local DB. Add it first: domains domain add --name ${domain}`);
|
|
56760
56840
|
process.exit(1);
|
|
56761
56841
|
}
|
|
56762
56842
|
const { keep, skipped } = partitionPullableRecords(records);
|
|
@@ -56765,13 +56845,13 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56765
56845
|
await createDnsRecord2({ domain_id: dbDomain.id, type: r4.type, name: r4.name, value: r4.value, ttl: r4.ttl, priority: r4.priority });
|
|
56766
56846
|
count++;
|
|
56767
56847
|
}
|
|
56768
|
-
|
|
56848
|
+
printLine(`\u2713 Pulled ${count} record(s) from ${providerName} into local DB for ${domain}`);
|
|
56769
56849
|
if (skipped.size > 0) {
|
|
56770
56850
|
const summary = Array.from(skipped.entries()).map(([t2, n2]) => `${n2} ${t2}`).join(", ");
|
|
56771
|
-
|
|
56851
|
+
printLine(` Skipped ${summary} record(s) (unsupported/provider-managed type).`);
|
|
56772
56852
|
}
|
|
56773
56853
|
} catch (e4) {
|
|
56774
|
-
|
|
56854
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56775
56855
|
process.exit(1);
|
|
56776
56856
|
}
|
|
56777
56857
|
});
|
|
@@ -56780,7 +56860,7 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56780
56860
|
try {
|
|
56781
56861
|
const records = await listDnsRecords2(domainId);
|
|
56782
56862
|
if (records.length === 0) {
|
|
56783
|
-
|
|
56863
|
+
printLine("No local DNS records to push.");
|
|
56784
56864
|
return;
|
|
56785
56865
|
}
|
|
56786
56866
|
const dbDomain = await getDomain2(domainId) ?? (() => {
|
|
@@ -56794,9 +56874,9 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56794
56874
|
ttl: r4.ttl,
|
|
56795
56875
|
priority: r4.priority ?? undefined
|
|
56796
56876
|
})));
|
|
56797
|
-
|
|
56877
|
+
printLine(`\u2713 Pushed ${records.length} record(s) to ${providerName} for ${dbDomain.name}`);
|
|
56798
56878
|
} catch (e4) {
|
|
56799
|
-
|
|
56879
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56800
56880
|
process.exit(1);
|
|
56801
56881
|
}
|
|
56802
56882
|
});
|
|
@@ -56806,6 +56886,7 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56806
56886
|
init_config();
|
|
56807
56887
|
init_route53();
|
|
56808
56888
|
init_cloudflare();
|
|
56889
|
+
init_stdout();
|
|
56809
56890
|
function resolveProvider(flag) {
|
|
56810
56891
|
return flag ?? loadConfig3().default_dns ?? "route53";
|
|
56811
56892
|
}
|
|
@@ -56821,24 +56902,24 @@ function registerZoneCommand(program2) {
|
|
|
56821
56902
|
zones = await listHostedZones();
|
|
56822
56903
|
}
|
|
56823
56904
|
if (opts.json) {
|
|
56824
|
-
|
|
56905
|
+
printLine(JSON.stringify(zones, null, 2));
|
|
56825
56906
|
return;
|
|
56826
56907
|
}
|
|
56827
56908
|
const page = pageItemsOrExit(zones, { limit: opts.limit, all: opts.all });
|
|
56828
56909
|
if (page.items.length === 0) {
|
|
56829
|
-
|
|
56910
|
+
printLine("No hosted zones.");
|
|
56830
56911
|
return;
|
|
56831
56912
|
}
|
|
56832
|
-
|
|
56913
|
+
printLine(`
|
|
56833
56914
|
Hosted Zones (${provider}):`);
|
|
56834
56915
|
for (const z of page.items) {
|
|
56835
56916
|
const extra = z.record_count !== undefined ? ` ${z.record_count} records` : "";
|
|
56836
|
-
|
|
56917
|
+
printLine(` ${z.id.padEnd(32)} ${z.name}${extra}`);
|
|
56837
56918
|
}
|
|
56838
|
-
|
|
56919
|
+
printLine(`
|
|
56839
56920
|
${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> for details.", { paging: "limit" })}`);
|
|
56840
56921
|
} catch (e4) {
|
|
56841
|
-
|
|
56922
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56842
56923
|
process.exit(1);
|
|
56843
56924
|
}
|
|
56844
56925
|
});
|
|
@@ -56847,23 +56928,23 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> f
|
|
|
56847
56928
|
try {
|
|
56848
56929
|
if (provider === "cloudflare") {
|
|
56849
56930
|
const z = await createZone(domain);
|
|
56850
|
-
|
|
56931
|
+
printLine(`\u2713 Zone created: ${domain} (${z.id})`);
|
|
56851
56932
|
if (z.nameservers?.length) {
|
|
56852
|
-
|
|
56933
|
+
printLine(` Name servers:`);
|
|
56853
56934
|
for (const ns of z.nameservers)
|
|
56854
|
-
|
|
56935
|
+
printLine(` ${ns}`);
|
|
56855
56936
|
}
|
|
56856
56937
|
} else {
|
|
56857
56938
|
const z = await createHostedZone(domain, opts.comment);
|
|
56858
|
-
|
|
56939
|
+
printLine(`\u2713 Zone created: ${domain} (${z.id})`);
|
|
56859
56940
|
if (z.name_servers?.length) {
|
|
56860
|
-
|
|
56941
|
+
printLine(` Name servers:`);
|
|
56861
56942
|
for (const ns of z.name_servers)
|
|
56862
|
-
|
|
56943
|
+
printLine(` ${ns}`);
|
|
56863
56944
|
}
|
|
56864
56945
|
}
|
|
56865
56946
|
} catch (e4) {
|
|
56866
|
-
|
|
56947
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56867
56948
|
process.exit(1);
|
|
56868
56949
|
}
|
|
56869
56950
|
});
|
|
@@ -56874,44 +56955,44 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> f
|
|
|
56874
56955
|
const zones = await listZones();
|
|
56875
56956
|
const z = zones.find((z2) => z2.id === zoneId || z2.name === zoneId);
|
|
56876
56957
|
if (!z) {
|
|
56877
|
-
|
|
56958
|
+
printErrorLine(`Zone not found: ${zoneId}`);
|
|
56878
56959
|
process.exit(1);
|
|
56879
56960
|
}
|
|
56880
56961
|
if (opts.json) {
|
|
56881
|
-
|
|
56962
|
+
printLine(JSON.stringify(z, null, 2));
|
|
56882
56963
|
return;
|
|
56883
56964
|
}
|
|
56884
|
-
|
|
56965
|
+
printLine(`
|
|
56885
56966
|
Zone: ${z.name}`);
|
|
56886
|
-
|
|
56887
|
-
|
|
56967
|
+
printLine(` ID: ${z.id}`);
|
|
56968
|
+
printLine(` Status: ${z.status}`);
|
|
56888
56969
|
if (z.nameservers?.length) {
|
|
56889
|
-
|
|
56970
|
+
printLine(` Name servers:`);
|
|
56890
56971
|
for (const ns of z.nameservers)
|
|
56891
|
-
|
|
56972
|
+
printLine(` ${ns}`);
|
|
56892
56973
|
}
|
|
56893
|
-
|
|
56974
|
+
printLine();
|
|
56894
56975
|
} else {
|
|
56895
56976
|
const z = await getHostedZone(zoneId);
|
|
56896
56977
|
if (opts.json) {
|
|
56897
|
-
|
|
56978
|
+
printLine(JSON.stringify(z, null, 2));
|
|
56898
56979
|
return;
|
|
56899
56980
|
}
|
|
56900
|
-
|
|
56981
|
+
printLine(`
|
|
56901
56982
|
Zone: ${z.name}`);
|
|
56902
|
-
|
|
56903
|
-
|
|
56983
|
+
printLine(` ID: ${z.id}`);
|
|
56984
|
+
printLine(` Records: ${z.record_count}`);
|
|
56904
56985
|
if (z.comment)
|
|
56905
|
-
|
|
56986
|
+
printLine(` Comment: ${z.comment}`);
|
|
56906
56987
|
if (z.name_servers?.length) {
|
|
56907
|
-
|
|
56988
|
+
printLine(` Name servers:`);
|
|
56908
56989
|
for (const ns of z.name_servers)
|
|
56909
|
-
|
|
56990
|
+
printLine(` ${ns}`);
|
|
56910
56991
|
}
|
|
56911
|
-
|
|
56992
|
+
printLine();
|
|
56912
56993
|
}
|
|
56913
56994
|
} catch (e4) {
|
|
56914
|
-
|
|
56995
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56915
56996
|
process.exit(1);
|
|
56916
56997
|
}
|
|
56917
56998
|
});
|
|
@@ -56919,8 +57000,8 @@ Zone: ${z.name}`);
|
|
|
56919
57000
|
const provider = resolveProvider(opts.provider);
|
|
56920
57001
|
try {
|
|
56921
57002
|
if (!opts.force) {
|
|
56922
|
-
|
|
56923
|
-
|
|
57003
|
+
printLine(`Would delete zone: ${zoneId} (${provider})`);
|
|
57004
|
+
printLine("Re-run with --force to confirm.");
|
|
56924
57005
|
return;
|
|
56925
57006
|
}
|
|
56926
57007
|
if (provider === "cloudflare") {
|
|
@@ -56928,9 +57009,9 @@ Zone: ${z.name}`);
|
|
|
56928
57009
|
} else {
|
|
56929
57010
|
await deleteHostedZone(zoneId);
|
|
56930
57011
|
}
|
|
56931
|
-
|
|
57012
|
+
printLine(`\u2713 Zone deleted: ${zoneId}`);
|
|
56932
57013
|
} catch (e4) {
|
|
56933
|
-
|
|
57014
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56934
57015
|
process.exit(1);
|
|
56935
57016
|
}
|
|
56936
57017
|
});
|
|
@@ -56938,52 +57019,54 @@ Zone: ${z.name}`);
|
|
|
56938
57019
|
|
|
56939
57020
|
// src/cli/commands/ssl.ts
|
|
56940
57021
|
init_domains();
|
|
57022
|
+
init_stdout();
|
|
56941
57023
|
function registerSslCommand(program2) {
|
|
56942
57024
|
const ssl = program2.command("ssl").description("SSL certificate management");
|
|
56943
57025
|
ssl.command("check <domain>").description("Check SSL certificate for a domain and update the local DB record").option("--json", "Output JSON").action(async (domain, opts) => {
|
|
56944
57026
|
try {
|
|
56945
57027
|
const result = await checkSsl(domain);
|
|
56946
57028
|
if (opts.json) {
|
|
56947
|
-
|
|
57029
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56948
57030
|
return;
|
|
56949
57031
|
}
|
|
56950
|
-
|
|
57032
|
+
printLine(`
|
|
56951
57033
|
SSL Certificate for ${result.domain}:`);
|
|
56952
57034
|
if (result.error) {
|
|
56953
|
-
|
|
57035
|
+
printLine(` Error: ${result.error}`);
|
|
56954
57036
|
} else {
|
|
56955
|
-
|
|
56956
|
-
|
|
57037
|
+
printLine(` Issuer: ${result.issuer ?? "unknown"}`);
|
|
57038
|
+
printLine(` Expires: ${result.expires_at ? result.expires_at.split("T")[0] : "unknown"}`);
|
|
56957
57039
|
}
|
|
56958
|
-
|
|
57040
|
+
printLine();
|
|
56959
57041
|
} catch (error) {
|
|
56960
|
-
|
|
57042
|
+
printErrorLine(`SSL check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
56961
57043
|
process.exit(1);
|
|
56962
57044
|
}
|
|
56963
57045
|
});
|
|
56964
57046
|
ssl.command("expiring").description("List domains with SSL certificates expiring soon").option("--days <n>", "Days threshold", "30").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all matching domains").option("--json", "Output JSON").action(async (opts) => {
|
|
56965
57047
|
const domains = await listSslExpiring2(parseInt(opts.days));
|
|
56966
57048
|
if (opts.json) {
|
|
56967
|
-
|
|
57049
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
56968
57050
|
return;
|
|
56969
57051
|
}
|
|
56970
57052
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
56971
57053
|
if (page.items.length === 0) {
|
|
56972
|
-
|
|
57054
|
+
printLine(`No SSL certificates expiring within ${opts.days} days.`);
|
|
56973
57055
|
return;
|
|
56974
57056
|
}
|
|
56975
|
-
|
|
57057
|
+
printLine(`
|
|
56976
57058
|
SSL expiring within ${opts.days} days:`);
|
|
56977
57059
|
for (const d4 of page.items) {
|
|
56978
57060
|
const exp = d4.ssl_expires_at ? formatDate(d4.ssl_expires_at) : "unknown";
|
|
56979
|
-
|
|
57061
|
+
printLine(` ${d4.name.padEnd(40)} expires ${exp}`);
|
|
56980
57062
|
}
|
|
56981
|
-
|
|
57063
|
+
printLine(`
|
|
56982
57064
|
${compactHint(page, "domain(s)", "Use --all to display every matching SSL certificate.", { paging: "limit" })}`);
|
|
56983
57065
|
});
|
|
56984
57066
|
}
|
|
56985
57067
|
|
|
56986
57068
|
// src/cli/commands/alerts.ts
|
|
57069
|
+
init_stdout();
|
|
56987
57070
|
init_domains();
|
|
56988
57071
|
function registerAlertCommands(program2) {
|
|
56989
57072
|
const alertCmd = program2.command("alert").description("Alert management");
|
|
@@ -56994,40 +57077,41 @@ function registerAlertCommands(program2) {
|
|
|
56994
57077
|
trigger_days_before: opts.daysBefore ? parseInt(opts.daysBefore) : undefined
|
|
56995
57078
|
});
|
|
56996
57079
|
if (opts.json) {
|
|
56997
|
-
|
|
57080
|
+
printLine(JSON.stringify(alert, null, 2));
|
|
56998
57081
|
} else {
|
|
56999
57082
|
const daysBefore = alert.trigger_days_before ? ` (${alert.trigger_days_before} days before)` : "";
|
|
57000
|
-
|
|
57083
|
+
printLine(`Created alert: ${alert.type}${daysBefore} for domain ${alert.domain_id} (${alert.id})`);
|
|
57001
57084
|
}
|
|
57002
57085
|
});
|
|
57003
57086
|
alertCmd.command("list").description("List alerts for a domain").argument("<domain-id>", "Domain ID").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
|
|
57004
57087
|
const alerts = await listAlerts2(domainId);
|
|
57005
57088
|
if (opts.json) {
|
|
57006
|
-
|
|
57089
|
+
printLine(JSON.stringify(alerts, null, 2));
|
|
57007
57090
|
} else {
|
|
57008
57091
|
if (alerts.length === 0) {
|
|
57009
|
-
|
|
57092
|
+
printLine("No alerts set.");
|
|
57010
57093
|
return;
|
|
57011
57094
|
}
|
|
57012
57095
|
for (const a4 of alerts) {
|
|
57013
57096
|
const daysBefore = a4.trigger_days_before ? ` (${a4.trigger_days_before} days before)` : "";
|
|
57014
57097
|
const sent = a4.sent_at ? ` \u2014 sent ${a4.sent_at}` : "";
|
|
57015
|
-
|
|
57098
|
+
printLine(` ${a4.type}${daysBefore}${sent}`);
|
|
57016
57099
|
}
|
|
57017
57100
|
}
|
|
57018
57101
|
});
|
|
57019
57102
|
alertCmd.command("remove").description("Remove an alert").argument("<id>", "Alert ID").action(async (id) => {
|
|
57020
57103
|
const deleted = await deleteAlert2(id);
|
|
57021
57104
|
if (deleted) {
|
|
57022
|
-
|
|
57105
|
+
printLine(`Deleted alert ${id}`);
|
|
57023
57106
|
} else {
|
|
57024
|
-
|
|
57107
|
+
printErrorLine(`Alert '${id}' not found.`);
|
|
57025
57108
|
process.exit(1);
|
|
57026
57109
|
}
|
|
57027
57110
|
});
|
|
57028
57111
|
}
|
|
57029
57112
|
|
|
57030
57113
|
// src/cli/commands/provider.ts
|
|
57114
|
+
init_stdout();
|
|
57031
57115
|
function isAwsAccessDenied(error) {
|
|
57032
57116
|
const msg = error instanceof Error ? error.message : String(error);
|
|
57033
57117
|
return msg.includes("AccessDenied") || msg.includes("route53domains:ListDomains");
|
|
@@ -57037,21 +57121,21 @@ function registerProviderCommand(program2) {
|
|
|
57037
57121
|
provider.command("list").description("Show all providers and their configuration status").option("-j, --json", "Output JSON").action((opts) => {
|
|
57038
57122
|
const providers = getAvailableProviders();
|
|
57039
57123
|
if (opts.json) {
|
|
57040
|
-
|
|
57124
|
+
printLine(JSON.stringify(providers, null, 2));
|
|
57041
57125
|
return;
|
|
57042
57126
|
}
|
|
57043
|
-
|
|
57127
|
+
printLine(`
|
|
57044
57128
|
Registrar / DNS Providers:`);
|
|
57045
57129
|
for (const p2 of providers) {
|
|
57046
57130
|
const status = p2.configured ? "\u2713 configured" : "\u2717 not configured";
|
|
57047
57131
|
const type = p2.type === "full" ? "registrar + dns" : p2.type;
|
|
57048
57132
|
const capabilities = [type, p2.inventory ? "inventory" : null].filter(Boolean).join(", ");
|
|
57049
|
-
|
|
57133
|
+
printLine(` ${p2.name.padEnd(12)} [${capabilities}] ${status}`);
|
|
57050
57134
|
if (!p2.configured) {
|
|
57051
|
-
|
|
57135
|
+
printLine(` Missing: ${p2.envVars.join(", ")}`);
|
|
57052
57136
|
}
|
|
57053
57137
|
}
|
|
57054
|
-
|
|
57138
|
+
printLine();
|
|
57055
57139
|
});
|
|
57056
57140
|
provider.command("test <name>").description("Live-test a provider's credentials").option("-j, --json", "Output JSON").action(async (name, opts) => {
|
|
57057
57141
|
const providerName = name.toLowerCase();
|
|
@@ -57060,16 +57144,16 @@ Registrar / DNS Providers:`);
|
|
|
57060
57144
|
if (!info) {
|
|
57061
57145
|
const error = `Unknown provider: ${name}`;
|
|
57062
57146
|
if (opts.json) {
|
|
57063
|
-
|
|
57147
|
+
printLine(JSON.stringify({ provider: providerName, ok: false, error }, null, 2));
|
|
57064
57148
|
} else {
|
|
57065
|
-
|
|
57149
|
+
printErrorLine(error);
|
|
57066
57150
|
}
|
|
57067
57151
|
process.exit(1);
|
|
57068
57152
|
}
|
|
57069
57153
|
if (!info.configured) {
|
|
57070
57154
|
const error = `${providerName} is not configured. Set: ${info.envVars.join(", ")}`;
|
|
57071
57155
|
if (opts.json) {
|
|
57072
|
-
|
|
57156
|
+
printLine(JSON.stringify({
|
|
57073
57157
|
provider: providerName,
|
|
57074
57158
|
ok: false,
|
|
57075
57159
|
configured: false,
|
|
@@ -57077,12 +57161,12 @@ Registrar / DNS Providers:`);
|
|
|
57077
57161
|
error
|
|
57078
57162
|
}, null, 2));
|
|
57079
57163
|
} else {
|
|
57080
|
-
|
|
57164
|
+
printErrorLine(`\u2717 ${error}`);
|
|
57081
57165
|
}
|
|
57082
57166
|
process.exit(1);
|
|
57083
57167
|
}
|
|
57084
57168
|
if (!opts.json) {
|
|
57085
|
-
|
|
57169
|
+
printLine(`Testing ${providerName}...`);
|
|
57086
57170
|
}
|
|
57087
57171
|
let registrarOk = null;
|
|
57088
57172
|
let dnsOk = null;
|
|
@@ -57096,21 +57180,21 @@ Registrar / DNS Providers:`);
|
|
|
57096
57180
|
await listRegisteredDomains2();
|
|
57097
57181
|
registrarOk = true;
|
|
57098
57182
|
if (!opts.json)
|
|
57099
|
-
|
|
57183
|
+
printLine("\u2713 Registrar connection OK");
|
|
57100
57184
|
} catch (error) {
|
|
57101
57185
|
if (!isAwsAccessDenied(error))
|
|
57102
57186
|
throw error;
|
|
57103
57187
|
registrarOk = false;
|
|
57104
57188
|
notes.push("route53domains-listdomains-access-denied");
|
|
57105
57189
|
if (!opts.json)
|
|
57106
|
-
|
|
57190
|
+
printLine("\u2022 Route53 Domains registrar API is not available for these AWS credentials");
|
|
57107
57191
|
}
|
|
57108
57192
|
} else {
|
|
57109
57193
|
const reg = getRegistrarProvider(providerName);
|
|
57110
57194
|
await reg.listDomains();
|
|
57111
57195
|
registrarOk = true;
|
|
57112
57196
|
if (!opts.json)
|
|
57113
|
-
|
|
57197
|
+
printLine("\u2713 Registrar connection OK");
|
|
57114
57198
|
}
|
|
57115
57199
|
}
|
|
57116
57200
|
if (info.type === "dns" || info.type === "full") {
|
|
@@ -57118,13 +57202,13 @@ Registrar / DNS Providers:`);
|
|
|
57118
57202
|
dnsOk = null;
|
|
57119
57203
|
notes.push("dns-not-probed-with-synthetic-invalid-domain");
|
|
57120
57204
|
if (!opts.json)
|
|
57121
|
-
|
|
57205
|
+
printLine("\u2022 DNS not probed with synthetic invalid domain");
|
|
57122
57206
|
} else {
|
|
57123
57207
|
const dns = getDnsProvider(providerName);
|
|
57124
57208
|
await dns.getDnsRecords("__test_nonexistent_domain__.invalid");
|
|
57125
57209
|
dnsOk = true;
|
|
57126
57210
|
if (!opts.json)
|
|
57127
|
-
|
|
57211
|
+
printLine("\u2713 DNS connection OK");
|
|
57128
57212
|
}
|
|
57129
57213
|
}
|
|
57130
57214
|
if (info.type === "marketplace") {
|
|
@@ -57134,10 +57218,10 @@ Registrar / DNS Providers:`);
|
|
|
57134
57218
|
await listSedoPortfolio2({ limit: 1 });
|
|
57135
57219
|
marketplaceOk = true;
|
|
57136
57220
|
if (!opts.json)
|
|
57137
|
-
|
|
57221
|
+
printLine("\u2713 Marketplace connection OK");
|
|
57138
57222
|
}
|
|
57139
57223
|
if (opts.json) {
|
|
57140
|
-
|
|
57224
|
+
printLine(JSON.stringify({
|
|
57141
57225
|
provider: providerName,
|
|
57142
57226
|
ok: true,
|
|
57143
57227
|
configured: true,
|
|
@@ -57152,7 +57236,7 @@ Registrar / DNS Providers:`);
|
|
|
57152
57236
|
const msg = e4 instanceof Error ? e4.message : String(e4);
|
|
57153
57237
|
if (msg.includes("not found") || msg.includes("No hosted zone") || msg.includes("NXDOMAIN")) {
|
|
57154
57238
|
if (opts.json) {
|
|
57155
|
-
|
|
57239
|
+
printLine(JSON.stringify({
|
|
57156
57240
|
provider: providerName,
|
|
57157
57241
|
ok: true,
|
|
57158
57242
|
configured: true,
|
|
@@ -57164,12 +57248,12 @@ Registrar / DNS Providers:`);
|
|
|
57164
57248
|
...notes.length > 0 ? { notes } : {}
|
|
57165
57249
|
}, null, 2));
|
|
57166
57250
|
} else {
|
|
57167
|
-
|
|
57251
|
+
printLine("\u2713 Connection OK (no domains yet)");
|
|
57168
57252
|
}
|
|
57169
57253
|
return;
|
|
57170
57254
|
}
|
|
57171
57255
|
if (opts.json) {
|
|
57172
|
-
|
|
57256
|
+
printLine(JSON.stringify({
|
|
57173
57257
|
provider: providerName,
|
|
57174
57258
|
ok: false,
|
|
57175
57259
|
configured: true,
|
|
@@ -57180,7 +57264,7 @@ Registrar / DNS Providers:`);
|
|
|
57180
57264
|
error: msg
|
|
57181
57265
|
}, null, 2));
|
|
57182
57266
|
} else {
|
|
57183
|
-
|
|
57267
|
+
printErrorLine(`\u2717 ${providerName} test failed: ${msg}`);
|
|
57184
57268
|
}
|
|
57185
57269
|
process.exit(1);
|
|
57186
57270
|
}
|
|
@@ -57189,6 +57273,7 @@ Registrar / DNS Providers:`);
|
|
|
57189
57273
|
|
|
57190
57274
|
// src/cli/commands/providers.ts
|
|
57191
57275
|
init_config();
|
|
57276
|
+
init_stdout();
|
|
57192
57277
|
init_domains();
|
|
57193
57278
|
function registrarProviderNames() {
|
|
57194
57279
|
return getAvailableProviders().filter((p2) => providerHasRegistrar(p2.name)).map((p2) => p2.name).join(", ");
|
|
@@ -57218,15 +57303,15 @@ function registerProviderCommands(program2) {
|
|
|
57218
57303
|
program2.command("providers").description("Show which providers are configured").option("--json", "Output as JSON", false).action((opts) => {
|
|
57219
57304
|
const providers = getAvailableProviders();
|
|
57220
57305
|
if (opts.json) {
|
|
57221
|
-
|
|
57306
|
+
printLine(JSON.stringify(providers, null, 2));
|
|
57222
57307
|
} else {
|
|
57223
|
-
|
|
57308
|
+
printLine("Providers:");
|
|
57224
57309
|
for (const p2 of providers) {
|
|
57225
57310
|
const status = p2.configured ? "CONFIGURED" : "not configured";
|
|
57226
57311
|
const capabilities = [p2.type, p2.inventory ? "inventory" : null].filter(Boolean).join(", ");
|
|
57227
|
-
|
|
57312
|
+
printLine(` ${p2.name} [${capabilities}]: ${status}`);
|
|
57228
57313
|
if (!p2.configured) {
|
|
57229
|
-
|
|
57314
|
+
printLine(` Accepted env: ${p2.envVars.join(", ")}`);
|
|
57230
57315
|
}
|
|
57231
57316
|
}
|
|
57232
57317
|
}
|
|
@@ -57240,28 +57325,28 @@ function registerProviderCommands(program2) {
|
|
|
57240
57325
|
updateDomain: updateDomain2
|
|
57241
57326
|
});
|
|
57242
57327
|
if (opts.json) {
|
|
57243
|
-
|
|
57328
|
+
printLine(JSON.stringify(result, null, 2));
|
|
57244
57329
|
} else {
|
|
57245
|
-
|
|
57330
|
+
printLine(`Synced ${result.totalSynced} domain(s) from ${result.providers.length} provider(s)`);
|
|
57246
57331
|
for (const p2 of result.providers) {
|
|
57247
|
-
|
|
57332
|
+
printLine(` ${p2.name}: ${p2.result.synced} synced (${p2.result.created} new, ${p2.result.updated} updated)`);
|
|
57248
57333
|
}
|
|
57249
57334
|
if (result.totalErrors.length > 0) {
|
|
57250
|
-
|
|
57335
|
+
printLine("Errors:");
|
|
57251
57336
|
for (const e4 of result.totalErrors) {
|
|
57252
|
-
|
|
57337
|
+
printLine(` - ${e4}`);
|
|
57253
57338
|
}
|
|
57254
57339
|
}
|
|
57255
57340
|
}
|
|
57256
57341
|
} catch (error) {
|
|
57257
|
-
|
|
57342
|
+
printErrorLine(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57258
57343
|
process.exit(1);
|
|
57259
57344
|
}
|
|
57260
57345
|
return;
|
|
57261
57346
|
}
|
|
57262
57347
|
const provider = (opts.provider || "").toLowerCase();
|
|
57263
57348
|
if (!provider) {
|
|
57264
|
-
|
|
57349
|
+
printErrorLine("Specify --provider <name> or --all");
|
|
57265
57350
|
process.exit(1);
|
|
57266
57351
|
}
|
|
57267
57352
|
try {
|
|
@@ -57272,17 +57357,17 @@ function registerProviderCommands(program2) {
|
|
|
57272
57357
|
updateDomain: updateDomain2
|
|
57273
57358
|
});
|
|
57274
57359
|
if (opts.json) {
|
|
57275
|
-
|
|
57360
|
+
printLine(JSON.stringify({ provider, ...result }, null, 2));
|
|
57276
57361
|
} else {
|
|
57277
|
-
|
|
57362
|
+
printLine(`Synced ${result.synced} domain(s) from ${provider} (${result.created} new, ${result.updated} updated)`);
|
|
57278
57363
|
if (result.errors.length > 0) {
|
|
57279
|
-
|
|
57364
|
+
printLine("Errors:");
|
|
57280
57365
|
for (const e4 of result.errors)
|
|
57281
|
-
|
|
57366
|
+
printLine(` - ${e4}`);
|
|
57282
57367
|
}
|
|
57283
57368
|
}
|
|
57284
57369
|
} catch (error) {
|
|
57285
|
-
|
|
57370
|
+
printErrorLine(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57286
57371
|
process.exit(1);
|
|
57287
57372
|
}
|
|
57288
57373
|
});
|
|
@@ -57291,12 +57376,12 @@ function registerProviderCommands(program2) {
|
|
|
57291
57376
|
if (!provider) {
|
|
57292
57377
|
const detected = autoDetectRegistrar(name, getDomainByName2);
|
|
57293
57378
|
if (!detected) {
|
|
57294
|
-
|
|
57379
|
+
printErrorLine(`Could not auto-detect registrar for '${name}'. Use --provider.`);
|
|
57295
57380
|
process.exit(1);
|
|
57296
57381
|
}
|
|
57297
57382
|
provider = detected;
|
|
57298
57383
|
if (!opts.json)
|
|
57299
|
-
|
|
57384
|
+
printLine(`Auto-detected registrar: ${provider}`);
|
|
57300
57385
|
}
|
|
57301
57386
|
try {
|
|
57302
57387
|
requireRegistrarProvider(provider);
|
|
@@ -57305,16 +57390,16 @@ function registerProviderCommands(program2) {
|
|
|
57305
57390
|
throw new Error(`Renewal failed or is not supported for ${provider}`);
|
|
57306
57391
|
}
|
|
57307
57392
|
if (opts.json) {
|
|
57308
|
-
|
|
57393
|
+
printLine(JSON.stringify({ provider, ...result }, null, 2));
|
|
57309
57394
|
} else {
|
|
57310
|
-
|
|
57395
|
+
printLine(`Renewed ${result.domain} successfully via ${provider}`);
|
|
57311
57396
|
if (result.chargedAmount)
|
|
57312
|
-
|
|
57397
|
+
printLine(` Charged: $${result.chargedAmount}`);
|
|
57313
57398
|
if (result.orderId)
|
|
57314
|
-
|
|
57399
|
+
printLine(` Order ID: ${result.orderId}`);
|
|
57315
57400
|
}
|
|
57316
57401
|
} catch (error) {
|
|
57317
|
-
|
|
57402
|
+
printErrorLine(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57318
57403
|
process.exit(1);
|
|
57319
57404
|
}
|
|
57320
57405
|
});
|
|
@@ -57324,18 +57409,18 @@ function registerProviderCommands(program2) {
|
|
|
57324
57409
|
requireRegistrarProvider(providerName);
|
|
57325
57410
|
const result = await getRegistrarProvider(providerName).checkAvailability(name);
|
|
57326
57411
|
if (opts.json) {
|
|
57327
|
-
|
|
57412
|
+
printLine(JSON.stringify({ provider: providerName, ...result }, null, 2));
|
|
57328
57413
|
} else {
|
|
57329
|
-
|
|
57414
|
+
printLine(`${result.domain} is ${result.available ? "AVAILABLE" : "NOT available"} (via ${providerName})`);
|
|
57330
57415
|
if (result.is_premium)
|
|
57331
|
-
|
|
57416
|
+
printLine(` Premium ask: ${result.premium_price ?? "unknown"}`);
|
|
57332
57417
|
if (result.standard_price !== undefined) {
|
|
57333
57418
|
const currency = result.currency ? ` ${result.currency}` : "";
|
|
57334
|
-
|
|
57419
|
+
printLine(` Standard price: ${result.standard_price}${currency}`);
|
|
57335
57420
|
}
|
|
57336
57421
|
}
|
|
57337
57422
|
} catch (error) {
|
|
57338
|
-
|
|
57423
|
+
printErrorLine(`Availability check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57339
57424
|
process.exit(1);
|
|
57340
57425
|
}
|
|
57341
57426
|
});
|
|
@@ -57343,6 +57428,7 @@ function registerProviderCommands(program2) {
|
|
|
57343
57428
|
|
|
57344
57429
|
// src/cli/commands/config.ts
|
|
57345
57430
|
init_config();
|
|
57431
|
+
init_stdout();
|
|
57346
57432
|
var VALID_KEYS = [
|
|
57347
57433
|
"default-registrar",
|
|
57348
57434
|
"default-dns",
|
|
@@ -57363,33 +57449,33 @@ function registerConfigCommands(program2) {
|
|
|
57363
57449
|
config2.command("show").description("Show current configuration").option("--json", "Output JSON").action((opts) => {
|
|
57364
57450
|
const cfg = loadConfig3();
|
|
57365
57451
|
if (opts.json) {
|
|
57366
|
-
|
|
57452
|
+
printLine(JSON.stringify(cfg, null, 2));
|
|
57367
57453
|
return;
|
|
57368
57454
|
}
|
|
57369
|
-
|
|
57455
|
+
printLine(`
|
|
57370
57456
|
Configuration:`);
|
|
57371
|
-
|
|
57372
|
-
|
|
57373
|
-
|
|
57457
|
+
printLine(` default-registrar: ${cfg.default_registrar ?? "(not set)"}`);
|
|
57458
|
+
printLine(` default-dns: ${cfg.default_dns ?? "(not set)"}`);
|
|
57459
|
+
printLine(` purchase-aws-profile: ${cfg.purchase_aws_profile ?? "(not set)"}`);
|
|
57374
57460
|
if (cfg.contact && Object.keys(cfg.contact).length > 0) {
|
|
57375
|
-
|
|
57461
|
+
printLine(`
|
|
57376
57462
|
contact:`);
|
|
57377
57463
|
for (const [k4, v2] of Object.entries(cfg.contact)) {
|
|
57378
57464
|
if (v2)
|
|
57379
|
-
|
|
57465
|
+
printLine(` ${k4}: ${v2}`);
|
|
57380
57466
|
}
|
|
57381
57467
|
} else {
|
|
57382
|
-
|
|
57468
|
+
printLine(" contact: (not set)");
|
|
57383
57469
|
}
|
|
57384
|
-
|
|
57470
|
+
printLine();
|
|
57385
57471
|
});
|
|
57386
57472
|
config2.command("set <key> <value>").description(`Set a config value. Keys: ${VALID_KEYS.join(", ")}`).action((key, value) => {
|
|
57387
57473
|
const normalized = key.replace(/-/g, "_");
|
|
57388
57474
|
try {
|
|
57389
57475
|
setConfigKey(normalized, value);
|
|
57390
|
-
|
|
57476
|
+
printLine(`\u2713 Set ${key} = ${value}`);
|
|
57391
57477
|
} catch (e4) {
|
|
57392
|
-
|
|
57478
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
57393
57479
|
process.exit(1);
|
|
57394
57480
|
}
|
|
57395
57481
|
});
|
|
@@ -57403,13 +57489,14 @@ Configuration:`);
|
|
|
57403
57489
|
delete cfg.contact[parts[1]];
|
|
57404
57490
|
}
|
|
57405
57491
|
saveConfig(cfg);
|
|
57406
|
-
|
|
57492
|
+
printLine(`\u2713 Unset ${key}`);
|
|
57407
57493
|
});
|
|
57408
57494
|
}
|
|
57409
57495
|
|
|
57410
57496
|
// src/cli/commands/doctor.ts
|
|
57411
57497
|
init_config();
|
|
57412
57498
|
init_domains();
|
|
57499
|
+
init_stdout();
|
|
57413
57500
|
import { execSync } from "child_process";
|
|
57414
57501
|
function registerDoctorCommand(program2) {
|
|
57415
57502
|
program2.command("doctor").description("Run diagnostics \u2014 check credentials, DB, and provider connectivity").option("--json", "Output structured JSON").action(async (opts) => {
|
|
@@ -57420,22 +57507,22 @@ function registerDoctorCommand(program2) {
|
|
|
57420
57507
|
function section(name) {
|
|
57421
57508
|
currentSection = name;
|
|
57422
57509
|
if (!opts.json) {
|
|
57423
|
-
|
|
57510
|
+
printLine(`
|
|
57424
57511
|
\u2500\u2500 ${name} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
57425
57512
|
}
|
|
57426
57513
|
}
|
|
57427
57514
|
function ok(msg) {
|
|
57428
57515
|
checks.push({ section: currentSection, status: "pass", message: msg });
|
|
57429
57516
|
if (!opts.json)
|
|
57430
|
-
|
|
57517
|
+
printLine(` \u2713 ${msg}`);
|
|
57431
57518
|
passed++;
|
|
57432
57519
|
}
|
|
57433
57520
|
function fail(msg, fix) {
|
|
57434
57521
|
checks.push({ section: currentSection, status: "fail", message: msg, fix });
|
|
57435
57522
|
if (!opts.json) {
|
|
57436
|
-
|
|
57523
|
+
printLine(` \u2717 ${msg}`);
|
|
57437
57524
|
if (fix)
|
|
57438
|
-
|
|
57525
|
+
printLine(` \u2192 ${fix}`);
|
|
57439
57526
|
}
|
|
57440
57527
|
failed++;
|
|
57441
57528
|
}
|
|
@@ -57514,16 +57601,16 @@ function registerDoctorCommand(program2) {
|
|
|
57514
57601
|
fail("whois not installed", "apt install whois / brew install whois");
|
|
57515
57602
|
}
|
|
57516
57603
|
if (opts.json) {
|
|
57517
|
-
|
|
57604
|
+
printLine(JSON.stringify({
|
|
57518
57605
|
passed,
|
|
57519
57606
|
failed,
|
|
57520
57607
|
healthy: failed === 0,
|
|
57521
57608
|
checks
|
|
57522
57609
|
}, null, 2));
|
|
57523
57610
|
} else {
|
|
57524
|
-
|
|
57611
|
+
printLine(`
|
|
57525
57612
|
${"\u2500".repeat(45)}`);
|
|
57526
|
-
|
|
57613
|
+
printLine(` ${passed} passed / ${failed} failed
|
|
57527
57614
|
`);
|
|
57528
57615
|
}
|
|
57529
57616
|
if (failed > 0)
|
|
@@ -57532,6 +57619,7 @@ ${"\u2500".repeat(45)}`);
|
|
|
57532
57619
|
}
|
|
57533
57620
|
|
|
57534
57621
|
// src/cli/commands/mcp-install.ts
|
|
57622
|
+
init_stdout();
|
|
57535
57623
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
57536
57624
|
import { homedir as homedir4 } from "os";
|
|
57537
57625
|
import { dirname as dirname5, join as join4 } from "path";
|
|
@@ -57577,28 +57665,28 @@ function registerMcpCommand(program2) {
|
|
|
57577
57665
|
mcpServers[MCP_SERVER_NAME] = { command: binary, args: [] };
|
|
57578
57666
|
config2.mcpServers = mcpServers;
|
|
57579
57667
|
writeFileSync3(configPath2, JSON.stringify(config2, null, 2), "utf-8");
|
|
57580
|
-
|
|
57581
|
-
|
|
57582
|
-
|
|
57583
|
-
|
|
57668
|
+
printLine(`\u2713 MCP server registered: ${MCP_SERVER_NAME}`);
|
|
57669
|
+
printLine(` Config: ${configPath2}`);
|
|
57670
|
+
printLine(` Binary: ${binary}`);
|
|
57671
|
+
printLine(`
|
|
57584
57672
|
Restart Claude Code to activate.`);
|
|
57585
57673
|
});
|
|
57586
57674
|
mcp.command("uninstall").description("Remove domains MCP server from Claude Code config").option("--project", "Remove from project config instead of global").action((opts) => {
|
|
57587
57675
|
const paths = getClaudeConfigPaths();
|
|
57588
57676
|
const configPath2 = opts.project ? paths.project : paths.global;
|
|
57589
57677
|
if (!existsSync3(configPath2)) {
|
|
57590
|
-
|
|
57678
|
+
printLine("Config file not found \u2014 nothing to remove.");
|
|
57591
57679
|
return;
|
|
57592
57680
|
}
|
|
57593
57681
|
const config2 = readConfig(configPath2);
|
|
57594
57682
|
const mcpServers = config2.mcpServers;
|
|
57595
57683
|
if (!mcpServers?.[MCP_SERVER_NAME]) {
|
|
57596
|
-
|
|
57684
|
+
printLine(`MCP server '${MCP_SERVER_NAME}' is not registered.`);
|
|
57597
57685
|
return;
|
|
57598
57686
|
}
|
|
57599
57687
|
delete mcpServers[MCP_SERVER_NAME];
|
|
57600
57688
|
writeFileSync3(configPath2, JSON.stringify(config2, null, 2), "utf-8");
|
|
57601
|
-
|
|
57689
|
+
printLine(`\u2713 MCP server removed: ${MCP_SERVER_NAME}`);
|
|
57602
57690
|
});
|
|
57603
57691
|
mcp.command("status").description("Check if domains MCP server is registered").option("-j, --json", "Output JSON").action((opts) => {
|
|
57604
57692
|
const paths = getClaudeConfigPaths();
|
|
@@ -57628,22 +57716,22 @@ function registerMcpCommand(program2) {
|
|
|
57628
57716
|
}
|
|
57629
57717
|
}
|
|
57630
57718
|
if (opts.json) {
|
|
57631
|
-
|
|
57719
|
+
printLine(JSON.stringify({ server: MCP_SERVER_NAME, checks: status }, null, 2));
|
|
57632
57720
|
return;
|
|
57633
57721
|
}
|
|
57634
57722
|
for (const item of status) {
|
|
57635
57723
|
if (!item.exists) {
|
|
57636
|
-
|
|
57724
|
+
printLine(` ${item.scope}: not found`);
|
|
57637
57725
|
continue;
|
|
57638
57726
|
}
|
|
57639
57727
|
if (item.error) {
|
|
57640
|
-
|
|
57728
|
+
printLine(` ${item.scope}: error reading config`);
|
|
57641
57729
|
continue;
|
|
57642
57730
|
}
|
|
57643
57731
|
if (item.registered) {
|
|
57644
|
-
|
|
57732
|
+
printLine(` ${item.scope}: \u2713 registered`);
|
|
57645
57733
|
} else {
|
|
57646
|
-
|
|
57734
|
+
printLine(` ${item.scope}: \u2717 not registered`);
|
|
57647
57735
|
}
|
|
57648
57736
|
}
|
|
57649
57737
|
});
|
|
@@ -57652,6 +57740,7 @@ function registerMcpCommand(program2) {
|
|
|
57652
57740
|
// src/cli/commands/serve.ts
|
|
57653
57741
|
init_domains();
|
|
57654
57742
|
init_version();
|
|
57743
|
+
init_stdout();
|
|
57655
57744
|
function registerServeCommand(program2) {
|
|
57656
57745
|
const packageVersion = getPackageVersion();
|
|
57657
57746
|
program2.command("serve").description("Start HTTP API server").option("--port <n>", "Port to listen on", "3000").option("--host <h>", "Host to bind to", "127.0.0.1").action(async (opts) => {
|
|
@@ -57719,16 +57808,16 @@ function registerServeCommand(program2) {
|
|
|
57719
57808
|
}
|
|
57720
57809
|
}
|
|
57721
57810
|
});
|
|
57722
|
-
|
|
57723
|
-
|
|
57724
|
-
|
|
57725
|
-
|
|
57726
|
-
|
|
57727
|
-
|
|
57728
|
-
|
|
57729
|
-
|
|
57730
|
-
|
|
57731
|
-
|
|
57811
|
+
printLine(`\u2713 domains API server running at http://${opts.host}:${port}`);
|
|
57812
|
+
printLine(` GET /health`);
|
|
57813
|
+
printLine(` GET /domains`);
|
|
57814
|
+
printLine(` POST /domains`);
|
|
57815
|
+
printLine(` GET /domains/:id`);
|
|
57816
|
+
printLine(` PUT /domains/:id`);
|
|
57817
|
+
printLine(` DELETE /domains/:id`);
|
|
57818
|
+
printLine(` GET /domains/:id/dns`);
|
|
57819
|
+
printLine(` POST /domains/:id/dns`);
|
|
57820
|
+
printLine(`
|
|
57732
57821
|
Press Ctrl+C to stop.`);
|
|
57733
57822
|
await new Promise(() => {});
|
|
57734
57823
|
});
|
|
@@ -58104,6 +58193,7 @@ async function runMigrations(opts = {}) {
|
|
|
58104
58193
|
}
|
|
58105
58194
|
|
|
58106
58195
|
// src/cli/commands/db.ts
|
|
58196
|
+
init_stdout();
|
|
58107
58197
|
function registerDbCommands(program2) {
|
|
58108
58198
|
const db = program2.command("db").description("Cloud database migrations (Postgres / RDS)");
|
|
58109
58199
|
db.command("migrate").description("Apply all pending migrations to the cloud Postgres (owner DSN)").option("--dry-run", "Report the plan without applying", false).option("--json", "Output JSON", false).action(async (opts) => {
|
|
@@ -58112,22 +58202,22 @@ function registerDbCommands(program2) {
|
|
|
58112
58202
|
const pending = result.plan.filter((p2) => p2.state === "pending").map((p2) => p2.migration.id);
|
|
58113
58203
|
const applied = result.applied.map((a4) => a4.id);
|
|
58114
58204
|
if (opts.json) {
|
|
58115
|
-
|
|
58205
|
+
printLine(JSON.stringify({ ok: true, dryRun: result.dryRun, pending, applied }, null, 2));
|
|
58116
58206
|
} else if (result.dryRun) {
|
|
58117
|
-
|
|
58207
|
+
printLine(`Dry run \u2014 ${pending.length} pending migration(s):`);
|
|
58118
58208
|
for (const id of pending)
|
|
58119
|
-
|
|
58209
|
+
printLine(` \u2022 ${id}`);
|
|
58120
58210
|
if (pending.length === 0)
|
|
58121
|
-
|
|
58211
|
+
printLine(" (schema up to date)");
|
|
58122
58212
|
} else {
|
|
58123
|
-
|
|
58213
|
+
printLine(`\u2713 migrations applied \u2014 ${applied.length} total, ${pending.length} were pending`);
|
|
58124
58214
|
}
|
|
58125
58215
|
} catch (e4) {
|
|
58126
58216
|
const msg = e4 instanceof Error ? e4.message : String(e4);
|
|
58127
58217
|
if (opts.json)
|
|
58128
|
-
|
|
58218
|
+
printLine(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
58129
58219
|
else
|
|
58130
|
-
|
|
58220
|
+
printErrorLine(`\u2717 migration failed: ${msg}`);
|
|
58131
58221
|
process.exitCode = 1;
|
|
58132
58222
|
}
|
|
58133
58223
|
});
|
|
@@ -58137,18 +58227,18 @@ function registerDbCommands(program2) {
|
|
|
58137
58227
|
const pending = result.plan.filter((p2) => p2.state === "pending").map((p2) => p2.migration.id);
|
|
58138
58228
|
const applied = result.applied.map((a4) => a4.id);
|
|
58139
58229
|
if (opts.json) {
|
|
58140
|
-
|
|
58230
|
+
printLine(JSON.stringify({ ok: true, pending, applied }, null, 2));
|
|
58141
58231
|
} else {
|
|
58142
|
-
|
|
58232
|
+
printLine(`Applied: ${applied.length} Pending: ${pending.length}`);
|
|
58143
58233
|
for (const id of pending)
|
|
58144
|
-
|
|
58234
|
+
printLine(` pending: ${id}`);
|
|
58145
58235
|
}
|
|
58146
58236
|
} catch (e4) {
|
|
58147
58237
|
const msg = e4 instanceof Error ? e4.message : String(e4);
|
|
58148
58238
|
if (opts.json)
|
|
58149
|
-
|
|
58239
|
+
printLine(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
58150
58240
|
else
|
|
58151
|
-
|
|
58241
|
+
printErrorLine(`\u2717 ${msg}`);
|
|
58152
58242
|
process.exitCode = 1;
|
|
58153
58243
|
}
|
|
58154
58244
|
});
|
|
@@ -58197,6 +58287,7 @@ async function setupDomainZone(domain, deps) {
|
|
|
58197
58287
|
// src/cli/commands/route53.ts
|
|
58198
58288
|
init_domains();
|
|
58199
58289
|
init_config();
|
|
58290
|
+
init_stdout();
|
|
58200
58291
|
function registerRoute53Commands(program2) {
|
|
58201
58292
|
const r53 = program2.command("r53").description("AWS Route 53 \u2014 domain purchase, hosted zones & DNS");
|
|
58202
58293
|
r53.command("check <domains...>").description("Check if one or more domains are available for purchase").action(async (domains) => {
|
|
@@ -58207,7 +58298,7 @@ function registerRoute53Commands(program2) {
|
|
|
58207
58298
|
const r4 = results[i4];
|
|
58208
58299
|
if (r4.status === "rejected") {
|
|
58209
58300
|
const reason = r4.reason;
|
|
58210
|
-
|
|
58301
|
+
printErrorLine(`\u2717 ${domains[i4]}: ${reason instanceof Error ? reason.message : String(reason)}`);
|
|
58211
58302
|
anyError = true;
|
|
58212
58303
|
continue;
|
|
58213
58304
|
}
|
|
@@ -58218,15 +58309,15 @@ function registerRoute53Commands(program2) {
|
|
|
58218
58309
|
const ren = result.renewal_price ? `renew ${cur} ${result.renewal_price}` : "";
|
|
58219
58310
|
const xfr = result.transfer_price ? `transfer ${cur} ${result.transfer_price}` : "";
|
|
58220
58311
|
const pricing = [reg, ren, xfr].filter(Boolean).join(" / ");
|
|
58221
|
-
|
|
58312
|
+
printLine(`\u2713 ${result.domain} is available${pricing ? ` (${pricing})` : ""}`);
|
|
58222
58313
|
} else {
|
|
58223
|
-
|
|
58314
|
+
printLine(`\u2717 ${result.domain} is not available`);
|
|
58224
58315
|
}
|
|
58225
58316
|
}
|
|
58226
58317
|
if (anyError)
|
|
58227
58318
|
process.exit(1);
|
|
58228
58319
|
} catch (e4) {
|
|
58229
|
-
|
|
58320
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58230
58321
|
process.exit(1);
|
|
58231
58322
|
}
|
|
58232
58323
|
});
|
|
@@ -58234,36 +58325,36 @@ function registerRoute53Commands(program2) {
|
|
|
58234
58325
|
try {
|
|
58235
58326
|
const avail = await checkAvailability3(domain);
|
|
58236
58327
|
if (!avail.available) {
|
|
58237
|
-
|
|
58328
|
+
printErrorLine(`\u2717 ${domain} is not available for registration`);
|
|
58238
58329
|
process.exit(1);
|
|
58239
58330
|
}
|
|
58240
58331
|
let contact;
|
|
58241
58332
|
try {
|
|
58242
58333
|
contact = resolveContact(opts);
|
|
58243
58334
|
} catch (e4) {
|
|
58244
|
-
|
|
58335
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58245
58336
|
process.exit(1);
|
|
58246
58337
|
}
|
|
58247
|
-
|
|
58338
|
+
printLine(`Registering ${domain}...`);
|
|
58248
58339
|
const result = await registerDomain2(domain, contact, parseInt(opts.years), opts.autoRenew);
|
|
58249
|
-
|
|
58250
|
-
|
|
58251
|
-
|
|
58340
|
+
printLine(`\u2713 Registration submitted: ${domain}`);
|
|
58341
|
+
printLine(` Operation ID: ${result.operationId}`);
|
|
58342
|
+
printLine(` Check status: domains r53 status ${result.operationId}`);
|
|
58252
58343
|
} catch (e4) {
|
|
58253
|
-
|
|
58344
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58254
58345
|
process.exit(1);
|
|
58255
58346
|
}
|
|
58256
58347
|
});
|
|
58257
58348
|
r53.command("status <operationId>").description("Check domain registration status").action(async (operationId) => {
|
|
58258
58349
|
try {
|
|
58259
58350
|
const result = await getRegistrationStatus(operationId);
|
|
58260
|
-
|
|
58351
|
+
printLine(`Status: ${result.status}`);
|
|
58261
58352
|
if (result.domain)
|
|
58262
|
-
|
|
58353
|
+
printLine(`Domain: ${result.domain}`);
|
|
58263
58354
|
if (result.message)
|
|
58264
|
-
|
|
58355
|
+
printLine(`Message: ${result.message}`);
|
|
58265
58356
|
} catch (e4) {
|
|
58266
|
-
|
|
58357
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58267
58358
|
process.exit(1);
|
|
58268
58359
|
}
|
|
58269
58360
|
});
|
|
@@ -58271,26 +58362,26 @@ function registerRoute53Commands(program2) {
|
|
|
58271
58362
|
try {
|
|
58272
58363
|
const domains = await listRegisteredDomains();
|
|
58273
58364
|
if (opts.json) {
|
|
58274
|
-
|
|
58365
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
58275
58366
|
return;
|
|
58276
58367
|
}
|
|
58277
58368
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
58278
58369
|
if (page.items.length === 0) {
|
|
58279
|
-
|
|
58370
|
+
printLine("No registered domains.");
|
|
58280
58371
|
return;
|
|
58281
58372
|
}
|
|
58282
|
-
|
|
58373
|
+
printLine(`
|
|
58283
58374
|
Registered Domains:`);
|
|
58284
58375
|
for (const d4 of page.items) {
|
|
58285
58376
|
const expiry = d4.expiry ? ` (expires ${d4.expiry.split("T")[0]})` : "";
|
|
58286
58377
|
const renew = d4.auto_renew ? " [auto-renew]" : "";
|
|
58287
58378
|
const lock = d4.transfer_lock ? " [locked]" : "";
|
|
58288
|
-
|
|
58379
|
+
printLine(` ${d4.domain}${expiry}${renew}${lock}`);
|
|
58289
58380
|
}
|
|
58290
|
-
|
|
58381
|
+
printLine(`
|
|
58291
58382
|
${compactHint(page, "domain(s)", "Use --all for every Route53 domain or r53 domain-info <domain> for details.", { paging: "limit" })}`);
|
|
58292
58383
|
} catch (e4) {
|
|
58293
|
-
|
|
58384
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58294
58385
|
process.exit(1);
|
|
58295
58386
|
}
|
|
58296
58387
|
});
|
|
@@ -58298,41 +58389,41 @@ ${compactHint(page, "domain(s)", "Use --all for every Route53 domain or r53 doma
|
|
|
58298
58389
|
try {
|
|
58299
58390
|
const detail = await getDomainDetail(domain);
|
|
58300
58391
|
if (opts.json) {
|
|
58301
|
-
|
|
58392
|
+
printLine(JSON.stringify(detail, null, 2));
|
|
58302
58393
|
return;
|
|
58303
58394
|
}
|
|
58304
|
-
|
|
58395
|
+
printLine(`
|
|
58305
58396
|
Domain: ${detail.domain}`);
|
|
58306
|
-
|
|
58307
|
-
|
|
58308
|
-
|
|
58309
|
-
|
|
58397
|
+
printLine(` Created: ${detail.created ? detail.created.split("T")[0] : "\u2014"}`);
|
|
58398
|
+
printLine(` Expires: ${detail.expiry ? detail.expiry.split("T")[0] : "\u2014"}`);
|
|
58399
|
+
printLine(` Auto-renew: ${detail.auto_renew ? "yes" : "no"}`);
|
|
58400
|
+
printLine(` Transfer lock: ${detail.transfer_lock ? "yes" : "no"}`);
|
|
58310
58401
|
if (detail.nameservers.length > 0) {
|
|
58311
|
-
|
|
58402
|
+
printLine(` Name servers:`);
|
|
58312
58403
|
for (const ns of detail.nameservers)
|
|
58313
|
-
|
|
58404
|
+
printLine(` ${ns}`);
|
|
58314
58405
|
}
|
|
58315
|
-
|
|
58406
|
+
printLine();
|
|
58316
58407
|
} catch (e4) {
|
|
58317
|
-
|
|
58408
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58318
58409
|
process.exit(1);
|
|
58319
58410
|
}
|
|
58320
58411
|
});
|
|
58321
58412
|
r53.command("zone-create <domain>").description("Create a hosted zone").option("--comment <text>", "Zone comment").action(async (domain, opts) => {
|
|
58322
58413
|
try {
|
|
58323
58414
|
const zone = await createHostedZone(domain, opts.comment);
|
|
58324
|
-
|
|
58325
|
-
|
|
58415
|
+
printLine(`\u2713 Hosted zone created: ${domain}`);
|
|
58416
|
+
printLine(` Zone ID: ${zone.id}`);
|
|
58326
58417
|
if (zone.name_servers && zone.name_servers.length > 0) {
|
|
58327
|
-
|
|
58418
|
+
printLine(`
|
|
58328
58419
|
Name servers (set at your registrar):`);
|
|
58329
58420
|
for (const ns of zone.name_servers) {
|
|
58330
|
-
|
|
58421
|
+
printLine(` ${ns}`);
|
|
58331
58422
|
}
|
|
58332
58423
|
}
|
|
58333
|
-
|
|
58424
|
+
printLine();
|
|
58334
58425
|
} catch (e4) {
|
|
58335
|
-
|
|
58426
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58336
58427
|
process.exit(1);
|
|
58337
58428
|
}
|
|
58338
58429
|
});
|
|
@@ -58340,24 +58431,24 @@ Domain: ${detail.domain}`);
|
|
|
58340
58431
|
try {
|
|
58341
58432
|
const zones = await listHostedZones();
|
|
58342
58433
|
if (opts.json) {
|
|
58343
|
-
|
|
58434
|
+
printLine(JSON.stringify(zones, null, 2));
|
|
58344
58435
|
return;
|
|
58345
58436
|
}
|
|
58346
58437
|
const page = pageItemsOrExit(zones, { limit: opts.limit, all: opts.all });
|
|
58347
58438
|
if (page.items.length === 0) {
|
|
58348
|
-
|
|
58439
|
+
printLine("No hosted zones.");
|
|
58349
58440
|
return;
|
|
58350
58441
|
}
|
|
58351
|
-
|
|
58442
|
+
printLine(`
|
|
58352
58443
|
Hosted Zones:`);
|
|
58353
58444
|
for (const z of page.items) {
|
|
58354
58445
|
const comment = z.comment ? ` \u2014 ${truncateText(z.comment, 60)}` : "";
|
|
58355
|
-
|
|
58446
|
+
printLine(` ${z.id} ${z.name} ${z.record_count} records${comment}`);
|
|
58356
58447
|
}
|
|
58357
|
-
|
|
58448
|
+
printLine(`
|
|
58358
58449
|
${compactHint(page, "zone(s)", "Use --all for every zone or r53 zone-info <zoneId> for details.", { paging: "limit" })}`);
|
|
58359
58450
|
} catch (e4) {
|
|
58360
|
-
|
|
58451
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58361
58452
|
process.exit(1);
|
|
58362
58453
|
}
|
|
58363
58454
|
});
|
|
@@ -58365,24 +58456,24 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or r53 zone-info <zoneI
|
|
|
58365
58456
|
try {
|
|
58366
58457
|
const zone = await getHostedZone(zoneId);
|
|
58367
58458
|
if (opts.json) {
|
|
58368
|
-
|
|
58459
|
+
printLine(JSON.stringify(zone, null, 2));
|
|
58369
58460
|
return;
|
|
58370
58461
|
}
|
|
58371
|
-
|
|
58462
|
+
printLine(`
|
|
58372
58463
|
Hosted Zone: ${zone.name}`);
|
|
58373
|
-
|
|
58374
|
-
|
|
58464
|
+
printLine(` ID: ${zone.id}`);
|
|
58465
|
+
printLine(` Records: ${zone.record_count}`);
|
|
58375
58466
|
if (zone.comment)
|
|
58376
|
-
|
|
58467
|
+
printLine(` Comment: ${zone.comment}`);
|
|
58377
58468
|
if (zone.name_servers && zone.name_servers.length > 0) {
|
|
58378
|
-
|
|
58469
|
+
printLine(` Name servers:`);
|
|
58379
58470
|
for (const ns of zone.name_servers) {
|
|
58380
|
-
|
|
58471
|
+
printLine(` ${ns}`);
|
|
58381
58472
|
}
|
|
58382
58473
|
}
|
|
58383
|
-
|
|
58474
|
+
printLine();
|
|
58384
58475
|
} catch (e4) {
|
|
58385
|
-
|
|
58476
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58386
58477
|
process.exit(1);
|
|
58387
58478
|
}
|
|
58388
58479
|
});
|
|
@@ -58390,18 +58481,18 @@ Hosted Zone: ${zone.name}`);
|
|
|
58390
58481
|
try {
|
|
58391
58482
|
const zone = await getHostedZone(zoneId);
|
|
58392
58483
|
if (!opts.force) {
|
|
58393
|
-
|
|
58394
|
-
|
|
58395
|
-
|
|
58396
|
-
|
|
58397
|
-
|
|
58484
|
+
printLine(`Would delete hosted zone:`);
|
|
58485
|
+
printLine(` ID: ${zone.id}`);
|
|
58486
|
+
printLine(` Domain: ${zone.name}`);
|
|
58487
|
+
printLine(` Records: ${zone.record_count}`);
|
|
58488
|
+
printLine(`
|
|
58398
58489
|
This is irreversible. Re-run with --force to confirm.`);
|
|
58399
58490
|
process.exit(0);
|
|
58400
58491
|
}
|
|
58401
58492
|
await deleteHostedZone(zoneId);
|
|
58402
|
-
|
|
58493
|
+
printLine(`\u2713 Hosted zone deleted: ${zone.name} (${zone.id})`);
|
|
58403
58494
|
} catch (e4) {
|
|
58404
|
-
|
|
58495
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58405
58496
|
process.exit(1);
|
|
58406
58497
|
}
|
|
58407
58498
|
});
|
|
@@ -58409,30 +58500,30 @@ This is irreversible. Re-run with --force to confirm.`);
|
|
|
58409
58500
|
try {
|
|
58410
58501
|
const zone = await findHostedZoneByDomain(domain);
|
|
58411
58502
|
if (!zone) {
|
|
58412
|
-
|
|
58503
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58413
58504
|
process.exit(1);
|
|
58414
58505
|
}
|
|
58415
58506
|
const records = await listRecords(zone.id);
|
|
58416
58507
|
if (opts.json) {
|
|
58417
|
-
|
|
58508
|
+
printLine(JSON.stringify(records, null, 2));
|
|
58418
58509
|
return;
|
|
58419
58510
|
}
|
|
58420
58511
|
const page = pageItemsOrExit(records, { limit: opts.limit, all: opts.all });
|
|
58421
58512
|
if (page.items.length === 0) {
|
|
58422
|
-
|
|
58513
|
+
printLine("No records.");
|
|
58423
58514
|
return;
|
|
58424
58515
|
}
|
|
58425
|
-
|
|
58516
|
+
printLine(`
|
|
58426
58517
|
DNS Records for ${domain}:`);
|
|
58427
58518
|
for (const r4 of page.items) {
|
|
58428
58519
|
const val = r4.alias_target ? `ALIAS \u2192 ${r4.alias_target.dns_name}` : truncateText(r4.values.join(", "), 90);
|
|
58429
58520
|
const ttl = r4.alias_target ? "" : ` TTL:${r4.ttl}`;
|
|
58430
|
-
|
|
58521
|
+
printLine(` ${r4.type.padEnd(6)} ${r4.name.padEnd(40)}${ttl} ${val}`);
|
|
58431
58522
|
}
|
|
58432
|
-
|
|
58523
|
+
printLine(`
|
|
58433
58524
|
${compactHint(page, "record(s)", "Use --all for every record or --json for full values.", { paging: "limit" })}`);
|
|
58434
58525
|
} catch (e4) {
|
|
58435
|
-
|
|
58526
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58436
58527
|
process.exit(1);
|
|
58437
58528
|
}
|
|
58438
58529
|
});
|
|
@@ -58443,20 +58534,20 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58443
58534
|
try {
|
|
58444
58535
|
const isAlias = !!(opts.aliasZone && opts.aliasDns);
|
|
58445
58536
|
if (!isAlias && (!opts.value || opts.value.length === 0)) {
|
|
58446
|
-
|
|
58537
|
+
printErrorLine("Error: provide --value (repeatable) or both --alias-zone and --alias-dns");
|
|
58447
58538
|
process.exit(1);
|
|
58448
58539
|
}
|
|
58449
58540
|
const zone = await findHostedZoneByDomain(domain);
|
|
58450
58541
|
if (!zone) {
|
|
58451
|
-
|
|
58542
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58452
58543
|
process.exit(1);
|
|
58453
58544
|
}
|
|
58454
58545
|
const aliasTarget = isAlias ? { hosted_zone_id: opts.aliasZone, dns_name: opts.aliasDns } : undefined;
|
|
58455
58546
|
await upsertRecord(zone.id, { name: opts.name, type: opts.type, ttl: parseInt(opts.ttl), values: opts.value, alias_target: aliasTarget });
|
|
58456
58547
|
const desc = isAlias ? `alias \u2192 ${opts.aliasDns}` : `${opts.value.length} value(s)`;
|
|
58457
|
-
|
|
58548
|
+
printLine(`\u2713 Record upserted: ${opts.type} ${opts.name} (${desc})`);
|
|
58458
58549
|
} catch (e4) {
|
|
58459
|
-
|
|
58550
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58460
58551
|
process.exit(1);
|
|
58461
58552
|
}
|
|
58462
58553
|
});
|
|
@@ -58464,14 +58555,14 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58464
58555
|
try {
|
|
58465
58556
|
const zone = await findHostedZoneByDomain(domain);
|
|
58466
58557
|
if (!zone) {
|
|
58467
|
-
|
|
58558
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58468
58559
|
process.exit(1);
|
|
58469
58560
|
}
|
|
58470
58561
|
const records = await listRecords(zone.id);
|
|
58471
58562
|
const normName = opts.name.endsWith(".") ? opts.name : `${opts.name}.`;
|
|
58472
58563
|
const existing = records.find((r4) => r4.type === opts.type.toUpperCase() && (r4.name === opts.name || r4.name === normName));
|
|
58473
58564
|
if (!existing) {
|
|
58474
|
-
|
|
58565
|
+
printErrorLine(`\u2717 No ${opts.type} record found for ${opts.name} in zone ${domain}`);
|
|
58475
58566
|
process.exit(1);
|
|
58476
58567
|
}
|
|
58477
58568
|
await deleteRecord(zone.id, {
|
|
@@ -58481,9 +58572,9 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58481
58572
|
values: existing.values,
|
|
58482
58573
|
alias_target: existing.alias_target
|
|
58483
58574
|
});
|
|
58484
|
-
|
|
58575
|
+
printLine(`\u2713 Record deleted: ${existing.type} ${existing.name}`);
|
|
58485
58576
|
} catch (e4) {
|
|
58486
|
-
|
|
58577
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58487
58578
|
process.exit(1);
|
|
58488
58579
|
}
|
|
58489
58580
|
});
|
|
@@ -58493,23 +58584,23 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58493
58584
|
try {
|
|
58494
58585
|
raw = readFileSync7(opts.file, "utf-8");
|
|
58495
58586
|
} catch {
|
|
58496
|
-
|
|
58587
|
+
printErrorLine(`Could not read file: ${opts.file}`);
|
|
58497
58588
|
process.exit(1);
|
|
58498
58589
|
}
|
|
58499
58590
|
const records = JSON.parse(raw);
|
|
58500
58591
|
if (!Array.isArray(records)) {
|
|
58501
|
-
|
|
58592
|
+
printErrorLine("JSON file must be an array of record objects");
|
|
58502
58593
|
process.exit(1);
|
|
58503
58594
|
}
|
|
58504
58595
|
const zone = await findHostedZoneByDomain(domain);
|
|
58505
58596
|
if (!zone) {
|
|
58506
|
-
|
|
58597
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58507
58598
|
process.exit(1);
|
|
58508
58599
|
}
|
|
58509
58600
|
await upsertRecords(zone.id, records);
|
|
58510
|
-
|
|
58601
|
+
printLine(`\u2713 Upserted ${records.length} record(s) in ${domain}`);
|
|
58511
58602
|
} catch (e4) {
|
|
58512
|
-
|
|
58603
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58513
58604
|
process.exit(1);
|
|
58514
58605
|
}
|
|
58515
58606
|
});
|
|
@@ -58521,36 +58612,36 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58521
58612
|
createDomain: createDomain2,
|
|
58522
58613
|
updateDomain: updateDomain2
|
|
58523
58614
|
});
|
|
58524
|
-
|
|
58615
|
+
printLine(`\u2713 Synced ${result.synced} domains (${result.created} new, ${result.updated} updated)`);
|
|
58525
58616
|
if (result.errors.length > 0) {
|
|
58526
|
-
|
|
58617
|
+
printLine(` Errors: ${result.errors.join(", ")}`);
|
|
58527
58618
|
}
|
|
58528
58619
|
} catch (e4) {
|
|
58529
|
-
|
|
58620
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58530
58621
|
process.exit(1);
|
|
58531
58622
|
}
|
|
58532
58623
|
});
|
|
58533
58624
|
r53.command("full-setup <domain>").description("Buy domain + create zone + sync to DB \u2014 all in one (contact defaults from: domains config set contact.*)").option("--email <email>", "Registrant email").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--phone <phone>", "Phone").option("--address <addr>", "Street address").option("--city <city>", "City").option("--state <state>", "State/province").option("--country <code>", "Country code").option("--zip <zip>", "ZIP code").option("--org <name>", "Organization name").option("--years <n>", "Registration years", "1").option("--wait", "Poll until registration completes (or fails)").action(async (domain, opts) => {
|
|
58534
58625
|
try {
|
|
58535
|
-
|
|
58626
|
+
printLine(`[1/4] Checking availability...`);
|
|
58536
58627
|
const avail = await checkAvailability3(domain);
|
|
58537
58628
|
if (!avail.available) {
|
|
58538
|
-
|
|
58629
|
+
printErrorLine(`\u2717 ${domain} is not available`);
|
|
58539
58630
|
process.exit(1);
|
|
58540
58631
|
}
|
|
58541
58632
|
const price = avail.price ? ` (${avail.currency ?? "USD"} ${avail.price}/yr)` : "";
|
|
58542
|
-
|
|
58543
|
-
|
|
58633
|
+
printLine(` \u2713 Available${price}`);
|
|
58634
|
+
printLine(`[2/4] Registering domain...`);
|
|
58544
58635
|
let contact;
|
|
58545
58636
|
try {
|
|
58546
58637
|
contact = resolveContact(opts);
|
|
58547
58638
|
} catch (e4) {
|
|
58548
|
-
|
|
58639
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58549
58640
|
process.exit(1);
|
|
58550
58641
|
}
|
|
58551
58642
|
const reg = await registerDomain2(domain, contact, parseInt(opts.years));
|
|
58552
|
-
|
|
58553
|
-
|
|
58643
|
+
printLine(` \u2713 Submitted (operation: ${reg.operationId})`);
|
|
58644
|
+
printLine(` Waiting for registration to complete...`);
|
|
58554
58645
|
let status = "IN_PROGRESS";
|
|
58555
58646
|
while (status === "IN_PROGRESS" || status === "SUBMITTED") {
|
|
58556
58647
|
await new Promise((r4) => setTimeout(r4, 1e4));
|
|
@@ -58558,13 +58649,13 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58558
58649
|
status = s2.status;
|
|
58559
58650
|
process.stdout.write(` Status: ${status}\r`);
|
|
58560
58651
|
}
|
|
58561
|
-
|
|
58652
|
+
printLine();
|
|
58562
58653
|
if (status !== "SUCCESSFUL") {
|
|
58563
|
-
|
|
58654
|
+
printErrorLine(`\u2717 Registration ${status}`);
|
|
58564
58655
|
process.exit(1);
|
|
58565
58656
|
}
|
|
58566
|
-
|
|
58567
|
-
|
|
58657
|
+
printLine(` \u2713 Registration complete`);
|
|
58658
|
+
printLine(`[3/4] Configuring hosted zone...`);
|
|
58568
58659
|
const setup = await setupDomainZone(domain, {
|
|
58569
58660
|
findExistingZone: async (d4) => {
|
|
58570
58661
|
const z = await findHostedZoneByDomain(d4);
|
|
@@ -58582,8 +58673,8 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58582
58673
|
await updateNameservers2(d4, ns);
|
|
58583
58674
|
}
|
|
58584
58675
|
});
|
|
58585
|
-
|
|
58586
|
-
|
|
58676
|
+
printLine(` \u2713 Zone ${setup.created ? "created" : "reused"} (${setup.zoneId})` + (setup.nsUpdated ? ` \u2014 registry NS repointed to this zone` : ``));
|
|
58677
|
+
printLine(`[4/4] Adding to local database...`);
|
|
58587
58678
|
createDomain2({
|
|
58588
58679
|
name: domain,
|
|
58589
58680
|
registrar: "AWS Route 53",
|
|
@@ -58591,20 +58682,20 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58591
58682
|
auto_renew: true,
|
|
58592
58683
|
nameservers: setup.nameServers
|
|
58593
58684
|
});
|
|
58594
|
-
|
|
58595
|
-
|
|
58685
|
+
printLine(` \u2713 Added to portfolio`);
|
|
58686
|
+
printLine(`
|
|
58596
58687
|
\u2713 Full setup complete for ${domain}`);
|
|
58597
|
-
|
|
58688
|
+
printLine(` Check: domains r53 status ${reg.operationId}`);
|
|
58598
58689
|
if (setup.nameServers && setup.nameServers.length > 0) {
|
|
58599
|
-
|
|
58690
|
+
printLine(`
|
|
58600
58691
|
Name servers:`);
|
|
58601
58692
|
for (const ns of setup.nameServers) {
|
|
58602
|
-
|
|
58693
|
+
printLine(` ${ns}`);
|
|
58603
58694
|
}
|
|
58604
58695
|
}
|
|
58605
|
-
|
|
58696
|
+
printLine();
|
|
58606
58697
|
} catch (e4) {
|
|
58607
|
-
|
|
58698
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58608
58699
|
process.exit(1);
|
|
58609
58700
|
}
|
|
58610
58701
|
});
|
|
@@ -58971,6 +59062,7 @@ function coverageRegressions(current, baseline) {
|
|
|
58971
59062
|
}
|
|
58972
59063
|
|
|
58973
59064
|
// src/cli/commands/reconcile-expiry.ts
|
|
59065
|
+
init_stdout();
|
|
58974
59066
|
var IANA_RDAP_BOOTSTRAP = "https://data.iana.org/rdap/dns.json";
|
|
58975
59067
|
var TLD_WHOIS = {
|
|
58976
59068
|
ag: "whois.nic.ag",
|
|
@@ -59065,18 +59157,18 @@ function registerReconcileExpiryCommand(program2) {
|
|
|
59065
59157
|
program2.command("reconcile-expiry").description("READ-ONLY: compare each domain's REGISTRAR expiry against the REGISTRY's own expiry").option("--from <file>", "Registrar dump JSON (array of {domain, expiresAt, status, registrar})").option("--provider <name>", "Read the registrar inventory live via a configured provider").option("--bootstrap <file>", "Local RDAP bootstrap JSON (default: fetch from IANA)").option("--baseline <file>", "Prior run's JSON; enables coverage-regression detection").option("--only <list>", "Comma-separated domains, or a TLD like '.md'").option("--limit <n>", "Cap the number of domains checked").option("--sample <n>", "Deterministic every-Nth sample across the population").option("--rdap-delay <ms>", "Delay between RDAP queries", "1100").option("--whois-delay <ms>", "Delay between WHOIS queries", "2500").option("--self-test", "Run the pre-arm self-test and exit").option("--json", "Output JSON").action(async (opts) => {
|
|
59066
59158
|
const arm = prearm();
|
|
59067
59159
|
if (!opts.json) {
|
|
59068
|
-
|
|
59160
|
+
printLine("=== PRE-ARM SELF-TEST (two-sided) ===");
|
|
59069
59161
|
for (const c4 of arm.cases)
|
|
59070
|
-
|
|
59071
|
-
|
|
59162
|
+
printLine(` [${c4.passed ? "PASS" : "FAIL"}] ${c4.name.padEnd(58)} -> ${c4.got}`);
|
|
59163
|
+
printLine(`=== PRE-ARM ${arm.ok ? "PASS - instrument can fire AND can stay silent" : "FAIL - DO NOT TRUST ANY RESULT"} ===`);
|
|
59072
59164
|
}
|
|
59073
59165
|
if (!arm.ok) {
|
|
59074
|
-
|
|
59166
|
+
printErrorLine("REFUSING TO RUN: pre-arm failed.");
|
|
59075
59167
|
process.exit(3);
|
|
59076
59168
|
}
|
|
59077
59169
|
if (opts.selfTest) {
|
|
59078
59170
|
if (opts.json)
|
|
59079
|
-
|
|
59171
|
+
printLine(JSON.stringify({ prearm: arm }, null, 2));
|
|
59080
59172
|
process.exit(0);
|
|
59081
59173
|
}
|
|
59082
59174
|
let rows;
|
|
@@ -59084,8 +59176,8 @@ function registerReconcileExpiryCommand(program2) {
|
|
|
59084
59176
|
rows = await loadRows(opts);
|
|
59085
59177
|
} catch (e4) {
|
|
59086
59178
|
const configured = getAvailableProviders().filter((p2) => p2.configured).map((p2) => p2.name).join(", ") || "none";
|
|
59087
|
-
|
|
59088
|
-
|
|
59179
|
+
printErrorLine(`${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
59180
|
+
printErrorLine(`configured providers: ${configured}`);
|
|
59089
59181
|
process.exit(2);
|
|
59090
59182
|
return;
|
|
59091
59183
|
}
|
|
@@ -59124,9 +59216,9 @@ function registerReconcileExpiryCommand(program2) {
|
|
|
59124
59216
|
}
|
|
59125
59217
|
};
|
|
59126
59218
|
if (!opts.json) {
|
|
59127
|
-
|
|
59219
|
+
printLine(`
|
|
59128
59220
|
REGISTRAR rows=${rows.length} unique=${unique.length} dupes_removed=${dupesRemoved}`);
|
|
59129
|
-
|
|
59221
|
+
printLine(`SELECTED=${selected.length}`);
|
|
59130
59222
|
}
|
|
59131
59223
|
const report = await reconcileExpiry(selected, deps);
|
|
59132
59224
|
let regressed = [];
|
|
@@ -59137,40 +59229,40 @@ REGISTRAR rows=${rows.length} unique=${unique.length} dupes_removed=${dupesRemov
|
|
|
59137
59229
|
report.exitCode = Math.max(report.exitCode, 2);
|
|
59138
59230
|
}
|
|
59139
59231
|
if (opts.json) {
|
|
59140
|
-
|
|
59232
|
+
printLine(JSON.stringify({ ...report, coverageRegressions: regressed, queries }, null, 2));
|
|
59141
59233
|
process.exit(report.exitCode);
|
|
59142
59234
|
return;
|
|
59143
59235
|
}
|
|
59144
59236
|
const order = ["MATCH", "MISMATCH", "NOT_AT_REGISTRY", "UNVERIFIABLE_EXPECTED", "UNVERIFIABLE_UNEXPECTED"];
|
|
59145
|
-
|
|
59237
|
+
printLine(`
|
|
59146
59238
|
=== VERDICT TALLY (n=${report.records.length}) ===`);
|
|
59147
59239
|
for (const k4 of order)
|
|
59148
|
-
|
|
59240
|
+
printLine(` ${k4.padEnd(24)} ${String(report.tally[k4]).padStart(5)}`);
|
|
59149
59241
|
const pct = report.records.length ? (100 * report.comparable / report.records.length).toFixed(1) : "0.0";
|
|
59150
|
-
|
|
59242
|
+
printLine(`COMPARABLE = ${report.comparable} of ${report.records.length} (${pct}%)`);
|
|
59151
59243
|
const show = (title, rs) => {
|
|
59152
59244
|
if (rs.length === 0)
|
|
59153
59245
|
return;
|
|
59154
|
-
|
|
59246
|
+
printLine(`
|
|
59155
59247
|
=== ${title} ===`);
|
|
59156
59248
|
for (const r4 of rs)
|
|
59157
|
-
|
|
59249
|
+
printLine(` ${r4.domain.padEnd(26)} ${r4.why.slice(0, 120)}`);
|
|
59158
59250
|
};
|
|
59159
59251
|
show("MISMATCHES", report.records.filter((r4) => r4.verdict === "MISMATCH"));
|
|
59160
59252
|
show("NOT AT REGISTRY", report.records.filter((r4) => r4.verdict === "NOT_AT_REGISTRY"));
|
|
59161
59253
|
show("UNVERIFIABLE / UNEXPECTED (coverage loss - these are NOT clean)", report.records.filter((r4) => r4.verdict === "UNVERIFIABLE_UNEXPECTED"));
|
|
59162
|
-
|
|
59254
|
+
printLine(`
|
|
59163
59255
|
REGISTRY EXPIRY WITHIN ${STALE_SOON_DAYS}d: ${report.expiringSoon.length}`);
|
|
59164
59256
|
for (const r4 of report.expiringSoon) {
|
|
59165
|
-
|
|
59257
|
+
printLine(` ${r4.domain.padEnd(26)} registry=${r4.registry} in ${r4.daysToRegistryExpiry}d verdict=${r4.verdict}`);
|
|
59166
59258
|
}
|
|
59167
59259
|
if (opts.baseline) {
|
|
59168
|
-
|
|
59260
|
+
printLine(`
|
|
59169
59261
|
COVERAGE REGRESSION vs baseline: ${regressed.length}`);
|
|
59170
59262
|
for (const d4 of regressed.slice(0, 20))
|
|
59171
|
-
|
|
59263
|
+
printLine(` ${d4} was comparable, now unverifiable`);
|
|
59172
59264
|
}
|
|
59173
|
-
|
|
59265
|
+
printLine(`
|
|
59174
59266
|
EXIT=${report.exitCode}`);
|
|
59175
59267
|
process.exit(report.exitCode);
|
|
59176
59268
|
});
|
|
@@ -59178,6 +59270,7 @@ EXIT=${report.exitCode}`);
|
|
|
59178
59270
|
|
|
59179
59271
|
// src/cli/index.ts
|
|
59180
59272
|
init_version();
|
|
59273
|
+
init_stdout();
|
|
59181
59274
|
var OPTIONAL_GROUPS = [
|
|
59182
59275
|
"brandsight",
|
|
59183
59276
|
"events",
|
|
@@ -59238,7 +59331,7 @@ async function registerOptionalCommands(program2, groups) {
|
|
|
59238
59331
|
const { registerEventsCommands: registerEventsCommands2 } = await Promise.resolve().then(() => (init_commander(), exports_commander));
|
|
59239
59332
|
registerEventsCommands2(program2, { source: "domains" });
|
|
59240
59333
|
} catch (error) {
|
|
59241
|
-
|
|
59334
|
+
printErrorLine(`Events command group is enabled but @hasna/events could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
|
|
59242
59335
|
}
|
|
59243
59336
|
}
|
|
59244
59337
|
}
|
|
@@ -59252,15 +59345,15 @@ function registerOptionalHelp(program2) {
|
|
|
59252
59345
|
enable_some: "DOMAINS_COMMAND_GROUPS=marketplace,owner domains <command>"
|
|
59253
59346
|
};
|
|
59254
59347
|
if (opts.json) {
|
|
59255
|
-
|
|
59348
|
+
printLine(JSON.stringify(body, null, 2));
|
|
59256
59349
|
return;
|
|
59257
59350
|
}
|
|
59258
|
-
|
|
59351
|
+
printLine("Optional command groups:");
|
|
59259
59352
|
for (const group of body.available)
|
|
59260
|
-
|
|
59261
|
-
|
|
59353
|
+
printLine(` ${groups.has(group) ? "\u2713" : " "} ${group}`);
|
|
59354
|
+
printLine(`
|
|
59262
59355
|
Enable all: DOMAINS_ENABLE_EXTRAS=1 domains <command>`);
|
|
59263
|
-
|
|
59356
|
+
printLine("Enable some: DOMAINS_COMMAND_GROUPS=marketplace,owner domains <command>");
|
|
59264
59357
|
});
|
|
59265
59358
|
}
|
|
59266
59359
|
var program2 = new Command;
|