@hasna/domains 0.0.36 → 0.0.38
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 +4 -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 +906 -749
- package/dist/db/dns-tools.d.ts.map +1 -1
- package/dist/index.js +74 -16
- package/dist/lib/cloudflare.d.ts.map +1 -1
- package/dist/lib/cloudflare.js +57 -7
- package/dist/lib/dns-plan.d.ts +1 -0
- package/dist/lib/dns-plan.d.ts.map +1 -1
- package/dist/lib/registrar.d.ts +4 -0
- package/dist/lib/registrar.d.ts.map +1 -1
- package/dist/lib/registrar.js +58 -7
- package/dist/lib/route53.d.ts.map +1 -1
- package/dist/lib/route53.js +1 -0
- package/dist/lib/stdout.d.ts +54 -0
- package/dist/lib/stdout.d.ts.map +1 -0
- package/dist/mcp/index.js +74 -16
- 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/
|
|
28949
|
+
var __dirname = "/home/hasna/.hasna/repos/worktrees/domains/0a933b3e-a459-4bcb-b94d-6ab12a2ec235/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();
|
|
@@ -50208,6 +50215,7 @@ function createRoute53Provider(config2) {
|
|
|
50208
50215
|
}
|
|
50209
50216
|
return {
|
|
50210
50217
|
name: "route53",
|
|
50218
|
+
dnsWriteScope: "changed-groups",
|
|
50211
50219
|
async listDomains() {
|
|
50212
50220
|
return listDomainInventory();
|
|
50213
50221
|
},
|
|
@@ -50577,16 +50585,51 @@ async function listRecordsByNameType(zoneId, type, name, config2) {
|
|
|
50577
50585
|
proxied: r4.proxied
|
|
50578
50586
|
}));
|
|
50579
50587
|
}
|
|
50580
|
-
|
|
50588
|
+
function sameRecordIdentity(a4, b4) {
|
|
50589
|
+
return a4.type === b4.type && a4.name === b4.name && a4.content === b4.content && (a4.priority ?? undefined) === (b4.priority ?? undefined);
|
|
50590
|
+
}
|
|
50591
|
+
function resolveDesiredProxied(records, existing) {
|
|
50592
|
+
const omitted = records.filter((record) => record.proxied === undefined);
|
|
50593
|
+
if (omitted.length === 0)
|
|
50594
|
+
return records;
|
|
50595
|
+
const { type, name } = records[0];
|
|
50596
|
+
if (omitted.length === records.length) {
|
|
50597
|
+
const proxyStates = new Set(existing.map((record) => record.proxied));
|
|
50598
|
+
if (proxyStates.size > 1) {
|
|
50599
|
+
throw new Error(`Cannot safely preserve Cloudflare proxied state for ${type} ${name}: ` + "existing records have mixed proxied values while desired records omit proxied; " + "set proxied explicitly on every desired record");
|
|
50600
|
+
}
|
|
50601
|
+
const inherited = existing[0]?.proxied;
|
|
50602
|
+
return inherited === undefined ? records : records.map((record) => ({ ...record, proxied: inherited }));
|
|
50603
|
+
}
|
|
50604
|
+
const existingHasProxyState = existing.some((record) => record.proxied !== undefined);
|
|
50605
|
+
return records.map((record) => {
|
|
50606
|
+
if (record.proxied !== undefined)
|
|
50607
|
+
return record;
|
|
50608
|
+
const matches = existing.filter((candidate) => sameRecordIdentity(candidate, record));
|
|
50609
|
+
if (matches.length === 1 && matches[0].proxied !== undefined) {
|
|
50610
|
+
return { ...record, proxied: matches[0].proxied };
|
|
50611
|
+
}
|
|
50612
|
+
if (!existingHasProxyState)
|
|
50613
|
+
return record;
|
|
50614
|
+
throw new Error(`Cannot safely preserve Cloudflare proxied state for ${type} ${name} record ${record.content}: ` + "omitted proxied does not resolve to exactly one existing value; " + "set proxied explicitly on this desired record");
|
|
50615
|
+
});
|
|
50616
|
+
}
|
|
50617
|
+
async function prepareRecordsByNameType(zoneId, records, config2) {
|
|
50581
50618
|
if (records.length === 0)
|
|
50582
50619
|
return;
|
|
50583
50620
|
const { type, name } = records[0];
|
|
50584
50621
|
const existing = await listRecordsByNameType(zoneId, type, name, config2);
|
|
50585
|
-
|
|
50622
|
+
if (existing.length === records.length && records.every((record) => existing.some((candidate) => sameRecordIdentity(candidate, record) && candidate.ttl === record.ttl && (record.proxied === undefined || candidate.proxied === record.proxied)))) {
|
|
50623
|
+
return;
|
|
50624
|
+
}
|
|
50625
|
+
return { existing, desired: resolveDesiredProxied(records, existing) };
|
|
50626
|
+
}
|
|
50627
|
+
async function replaceRecordsByNameType(zoneId, replacement, config2) {
|
|
50628
|
+
for (const record of replacement.existing) {
|
|
50586
50629
|
if (record.id)
|
|
50587
50630
|
await deleteRecord2(zoneId, record.id, config2);
|
|
50588
50631
|
}
|
|
50589
|
-
for (const record of
|
|
50632
|
+
for (const record of replacement.desired) {
|
|
50590
50633
|
await cfFetch(`/zones/${zoneId}/dns_records`, {
|
|
50591
50634
|
method: "POST",
|
|
50592
50635
|
body: {
|
|
@@ -50595,7 +50638,7 @@ async function replaceRecordsByNameType(zoneId, records, config2) {
|
|
|
50595
50638
|
content: record.content,
|
|
50596
50639
|
ttl: record.ttl ?? 1,
|
|
50597
50640
|
priority: record.priority,
|
|
50598
|
-
proxied: record.proxied
|
|
50641
|
+
...record.proxied === undefined ? {} : { proxied: record.proxied }
|
|
50599
50642
|
},
|
|
50600
50643
|
config: config2
|
|
50601
50644
|
});
|
|
@@ -50630,6 +50673,7 @@ function createCloudflareProvider(config2) {
|
|
|
50630
50673
|
const cfg = config2 ?? getConfig3();
|
|
50631
50674
|
return {
|
|
50632
50675
|
name: "cloudflare",
|
|
50676
|
+
dnsWriteScope: "changed-groups",
|
|
50633
50677
|
async listDomains() {
|
|
50634
50678
|
const zones = await listZones(cfg);
|
|
50635
50679
|
return zones.map(zoneToDomainInfo);
|
|
@@ -50680,7 +50724,8 @@ function createCloudflareProvider(config2) {
|
|
|
50680
50724
|
name: r4.name,
|
|
50681
50725
|
value: r4.content,
|
|
50682
50726
|
ttl: r4.ttl === 1 ? 0 : r4.ttl,
|
|
50683
|
-
priority: r4.priority
|
|
50727
|
+
priority: r4.priority,
|
|
50728
|
+
...r4.proxied === undefined ? {} : { proxied: r4.proxied }
|
|
50684
50729
|
}));
|
|
50685
50730
|
},
|
|
50686
50731
|
async setDnsRecords(domain, records) {
|
|
@@ -50691,11 +50736,24 @@ function createCloudflareProvider(config2) {
|
|
|
50691
50736
|
for (const r4 of records) {
|
|
50692
50737
|
const key = `${r4.type}|${r4.name}`;
|
|
50693
50738
|
const existing = grouped.get(key) ?? [];
|
|
50694
|
-
existing.push({
|
|
50739
|
+
existing.push({
|
|
50740
|
+
type: r4.type,
|
|
50741
|
+
name: r4.name,
|
|
50742
|
+
content: r4.value,
|
|
50743
|
+
ttl: r4.ttl || 1,
|
|
50744
|
+
priority: r4.priority,
|
|
50745
|
+
...r4.proxied === undefined ? {} : { proxied: r4.proxied }
|
|
50746
|
+
});
|
|
50695
50747
|
grouped.set(key, existing);
|
|
50696
50748
|
}
|
|
50749
|
+
const replacements = [];
|
|
50697
50750
|
for (const group of grouped.values()) {
|
|
50698
|
-
await
|
|
50751
|
+
const replacement = await prepareRecordsByNameType(zone.id, group, cfg);
|
|
50752
|
+
if (replacement)
|
|
50753
|
+
replacements.push(replacement);
|
|
50754
|
+
}
|
|
50755
|
+
for (const replacement of replacements) {
|
|
50756
|
+
await replaceRecordsByNameType(zone.id, replacement, cfg);
|
|
50699
50757
|
}
|
|
50700
50758
|
return true;
|
|
50701
50759
|
}
|
|
@@ -51383,6 +51441,65 @@ function compactHint(page, noun, detailHint, options = {}) {
|
|
|
51383
51441
|
}
|
|
51384
51442
|
var DEFAULT_LIST_LIMIT = 20, MAX_LIST_LIMIT = 200;
|
|
51385
51443
|
|
|
51444
|
+
// src/lib/stdout.ts
|
|
51445
|
+
import { writeSync } from "fs";
|
|
51446
|
+
import { format } from "util";
|
|
51447
|
+
function awaitDrain() {
|
|
51448
|
+
Atomics.wait(backpressureWait, 0, 0, BACKPRESSURE_WAIT_MS);
|
|
51449
|
+
}
|
|
51450
|
+
function errorCodeOf(error) {
|
|
51451
|
+
if (typeof error !== "object" || error === null)
|
|
51452
|
+
return null;
|
|
51453
|
+
const code = error.code;
|
|
51454
|
+
return typeof code === "string" ? code : null;
|
|
51455
|
+
}
|
|
51456
|
+
function writeAllBytesSync(bytes, writer) {
|
|
51457
|
+
let offset = 0;
|
|
51458
|
+
while (offset < bytes.length) {
|
|
51459
|
+
let accepted;
|
|
51460
|
+
try {
|
|
51461
|
+
accepted = writer(bytes.subarray(offset));
|
|
51462
|
+
} catch (error) {
|
|
51463
|
+
const code = errorCodeOf(error);
|
|
51464
|
+
if (code === "EAGAIN" || code === "EWOULDBLOCK") {
|
|
51465
|
+
awaitDrain();
|
|
51466
|
+
continue;
|
|
51467
|
+
}
|
|
51468
|
+
if (code === "EPIPE" || code === "ERR_STREAM_DESTROYED")
|
|
51469
|
+
return "reader-closed";
|
|
51470
|
+
throw error;
|
|
51471
|
+
}
|
|
51472
|
+
if (accepted <= 0) {
|
|
51473
|
+
awaitDrain();
|
|
51474
|
+
continue;
|
|
51475
|
+
}
|
|
51476
|
+
offset += accepted;
|
|
51477
|
+
}
|
|
51478
|
+
return "complete";
|
|
51479
|
+
}
|
|
51480
|
+
function writeAllSync(text, writer) {
|
|
51481
|
+
return writeAllBytesSync(Buffer.from(text, "utf8"), writer);
|
|
51482
|
+
}
|
|
51483
|
+
function writeStdout(text, writer = stdoutWriter) {
|
|
51484
|
+
return writeAllSync(text, writer);
|
|
51485
|
+
}
|
|
51486
|
+
function formatLine(...args) {
|
|
51487
|
+
return `${format(...args)}
|
|
51488
|
+
`;
|
|
51489
|
+
}
|
|
51490
|
+
function printLine(...args) {
|
|
51491
|
+
return writeStdout(formatLine(...args));
|
|
51492
|
+
}
|
|
51493
|
+
function printErrorLine(...args) {
|
|
51494
|
+
return writeAllSync(formatLine(...args), stderrWriter);
|
|
51495
|
+
}
|
|
51496
|
+
var BACKPRESSURE_WAIT_MS = 1, backpressureWait, fdWriter = (fd) => (chunk) => writeSync(fd, chunk), stdoutWriter, stderrWriter;
|
|
51497
|
+
var init_stdout = __esm(() => {
|
|
51498
|
+
backpressureWait = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
51499
|
+
stdoutWriter = fdWriter(1);
|
|
51500
|
+
stderrWriter = fdWriter(2);
|
|
51501
|
+
});
|
|
51502
|
+
|
|
51386
51503
|
// src/db/history.ts
|
|
51387
51504
|
function createHistoryEntry2(input) {
|
|
51388
51505
|
return getStore().createHistoryEntry(input);
|
|
@@ -51772,22 +51889,22 @@ function registerMonitorCommand(program2) {
|
|
|
51772
51889
|
try {
|
|
51773
51890
|
const result = await monitorBrand(brand);
|
|
51774
51891
|
if (opts.json) {
|
|
51775
|
-
|
|
51892
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51776
51893
|
return;
|
|
51777
51894
|
}
|
|
51778
51895
|
const page = pageItemsOrExit(result.alerts, { limit: opts.limit, all: opts.all });
|
|
51779
|
-
|
|
51896
|
+
printLine(`Monitor: ${result.brand}${result.stub ? " [stub]" : ""}`);
|
|
51780
51897
|
if (page.items.length === 0) {
|
|
51781
|
-
|
|
51898
|
+
printLine("No alerts.");
|
|
51782
51899
|
return;
|
|
51783
51900
|
}
|
|
51784
51901
|
for (const alert of page.items) {
|
|
51785
|
-
|
|
51902
|
+
printLine(` ${alert.domain} [${alert.type}] registered:${alert.registered_at}`);
|
|
51786
51903
|
}
|
|
51787
|
-
|
|
51904
|
+
printLine(`
|
|
51788
51905
|
${compactHint(page, "alert(s)", "Use --all for every alert or --json for full monitor details.", { paging: "limit" })}`);
|
|
51789
51906
|
} catch (e4) {
|
|
51790
|
-
|
|
51907
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
51791
51908
|
process.exit(1);
|
|
51792
51909
|
}
|
|
51793
51910
|
});
|
|
@@ -51795,21 +51912,21 @@ ${compactHint(page, "alert(s)", "Use --all for every alert or --json for full mo
|
|
|
51795
51912
|
try {
|
|
51796
51913
|
const result = await getSimilarDomains(domain);
|
|
51797
51914
|
if (opts.json) {
|
|
51798
|
-
|
|
51915
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51799
51916
|
return;
|
|
51800
51917
|
}
|
|
51801
51918
|
const page = pageItemsOrExit(result.similar, { limit: opts.limit, all: opts.all });
|
|
51802
|
-
|
|
51919
|
+
printLine(`Similar domains for ${result.domain}${result.stub ? " [stub]" : ""}:`);
|
|
51803
51920
|
if (page.items.length === 0) {
|
|
51804
|
-
|
|
51921
|
+
printLine("No similar domains found.");
|
|
51805
51922
|
return;
|
|
51806
51923
|
}
|
|
51807
51924
|
for (const name of page.items)
|
|
51808
|
-
|
|
51809
|
-
|
|
51925
|
+
printLine(` ${name}`);
|
|
51926
|
+
printLine(`
|
|
51810
51927
|
${compactHint(page, "domain(s)", "Use --all for every result or --json for full response metadata.", { paging: "limit" })}`);
|
|
51811
51928
|
} catch (e4) {
|
|
51812
|
-
|
|
51929
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
51813
51930
|
process.exit(1);
|
|
51814
51931
|
}
|
|
51815
51932
|
});
|
|
@@ -51817,28 +51934,29 @@ ${compactHint(page, "domain(s)", "Use --all for every result or --json for full
|
|
|
51817
51934
|
try {
|
|
51818
51935
|
const result = await getThreatAssessment(domain);
|
|
51819
51936
|
if (opts.json) {
|
|
51820
|
-
|
|
51937
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51821
51938
|
return;
|
|
51822
51939
|
}
|
|
51823
51940
|
const page = pageItemsOrExit(result.threats, { limit: opts.limit, all: opts.all });
|
|
51824
|
-
|
|
51941
|
+
printLine(`Threat assessment for ${result.domain}${result.stub ? " [stub]" : ""}: ${result.risk_level}`);
|
|
51825
51942
|
if (page.items.length === 0) {
|
|
51826
|
-
|
|
51943
|
+
printLine("No immediate threats detected.");
|
|
51827
51944
|
} else {
|
|
51828
51945
|
for (const threat of page.items)
|
|
51829
|
-
|
|
51946
|
+
printLine(` - ${truncateText(threat, 100)}`);
|
|
51830
51947
|
}
|
|
51831
|
-
|
|
51832
|
-
|
|
51948
|
+
printLine(`Recommendation: ${truncateText(result.recommendation, 140)}`);
|
|
51949
|
+
printLine(`
|
|
51833
51950
|
${compactHint(page, "threat(s)", "Use --all for every threat or --json for the full assessment.", { paging: "limit" })}`);
|
|
51834
51951
|
} catch (e4) {
|
|
51835
|
-
|
|
51952
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
51836
51953
|
process.exit(1);
|
|
51837
51954
|
}
|
|
51838
51955
|
});
|
|
51839
51956
|
}
|
|
51840
51957
|
var init_monitor = __esm(() => {
|
|
51841
51958
|
init_brandsight();
|
|
51959
|
+
init_stdout();
|
|
51842
51960
|
});
|
|
51843
51961
|
|
|
51844
51962
|
// src/cli/commands/sedo.ts
|
|
@@ -51851,7 +51969,7 @@ function parseSedoLimit(value, fallback) {
|
|
|
51851
51969
|
return fallback;
|
|
51852
51970
|
const parsed = Number(value);
|
|
51853
51971
|
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
51854
|
-
|
|
51972
|
+
printErrorLine("--limit must be a non-negative integer");
|
|
51855
51973
|
process.exit(1);
|
|
51856
51974
|
}
|
|
51857
51975
|
return parsed;
|
|
@@ -51868,19 +51986,19 @@ function registerSedoCommand(program2) {
|
|
|
51868
51986
|
maxPrice: opts.maxPrice ? parseInt(opts.maxPrice) : undefined
|
|
51869
51987
|
});
|
|
51870
51988
|
if (opts.json) {
|
|
51871
|
-
|
|
51989
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51872
51990
|
} else {
|
|
51873
51991
|
if (result.domains.length === 0) {
|
|
51874
|
-
|
|
51992
|
+
printLine(`No domains found for "${keyword}".`);
|
|
51875
51993
|
return;
|
|
51876
51994
|
}
|
|
51877
|
-
|
|
51995
|
+
printLine(`Sedo marketplace \u2014 "${keyword}" (${result.total} total):`);
|
|
51878
51996
|
for (const d4 of result.domains) {
|
|
51879
51997
|
const price = d4.price ? ` \u2014 ${d4.price.toLocaleString()} ${d4.currency || ""}`.trimEnd() : " \u2014 make offer";
|
|
51880
51998
|
const premium = d4.isPremium ? " [PREMIUM]" : "";
|
|
51881
|
-
|
|
51999
|
+
printLine(` ${d4.domain}${price}${premium}`);
|
|
51882
52000
|
}
|
|
51883
|
-
|
|
52001
|
+
printLine(`
|
|
51884
52002
|
Showing ${result.domains.length}/${result.total} marketplace result(s). Use --limit <n> for more or --json for full fields.`);
|
|
51885
52003
|
}
|
|
51886
52004
|
});
|
|
@@ -51888,12 +52006,12 @@ Showing ${result.domains.length}/${result.total} marketplace result(s). Use --li
|
|
|
51888
52006
|
const { checkSedoStatus: checkSedoStatus2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
|
|
51889
52007
|
const results = await checkSedoStatus2(domains);
|
|
51890
52008
|
if (opts.json) {
|
|
51891
|
-
|
|
52009
|
+
printLine(JSON.stringify(results, null, 2));
|
|
51892
52010
|
} else {
|
|
51893
52011
|
for (const r4 of results) {
|
|
51894
52012
|
const listed = r4.listed ? "listed" : "not listed";
|
|
51895
52013
|
const sale = r4.forSale ? ` for sale (${r4.price || "?"} ${r4.currency || ""})` : "";
|
|
51896
|
-
|
|
52014
|
+
printLine(` ${r4.domain}: ${listed}${sale}`);
|
|
51897
52015
|
}
|
|
51898
52016
|
}
|
|
51899
52017
|
});
|
|
@@ -51902,19 +52020,19 @@ Showing ${result.domains.length}/${result.total} marketplace result(s). Use --li
|
|
|
51902
52020
|
const limit = parseSedoLimit(opts.limit, opts.json || opts.all ? 100 : 20);
|
|
51903
52021
|
const domains = await listSedoPortfolio2({ limit });
|
|
51904
52022
|
if (opts.json) {
|
|
51905
|
-
|
|
52023
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
51906
52024
|
} else {
|
|
51907
52025
|
if (domains.length === 0) {
|
|
51908
|
-
|
|
52026
|
+
printLine("No domains in your Sedo portfolio.");
|
|
51909
52027
|
return;
|
|
51910
52028
|
}
|
|
51911
52029
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
51912
|
-
|
|
52030
|
+
printLine(`Sedo Portfolio:`);
|
|
51913
52031
|
for (const d4 of page.items) {
|
|
51914
52032
|
const sale = d4.forSale ? `[for sale ${d4.price || "?"} ${d4.currency || ""}]` : "";
|
|
51915
|
-
|
|
52033
|
+
printLine(` ${d4.domain} ${sale}`);
|
|
51916
52034
|
}
|
|
51917
|
-
|
|
52035
|
+
printLine(`
|
|
51918
52036
|
${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full marketplace fields.", { paging: "limit" })}`);
|
|
51919
52037
|
}
|
|
51920
52038
|
});
|
|
@@ -51929,9 +52047,9 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51929
52047
|
buyNowPrice: opts.buyNowPrice ? parseInt(opts.buyNowPrice) : undefined
|
|
51930
52048
|
});
|
|
51931
52049
|
if (opts.json) {
|
|
51932
|
-
|
|
52050
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51933
52051
|
} else {
|
|
51934
|
-
|
|
52052
|
+
printLine(`Added ${domain} to Sedo marketplace`);
|
|
51935
52053
|
}
|
|
51936
52054
|
});
|
|
51937
52055
|
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 +52061,18 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51943
52061
|
buyNowPrice: opts.buyNowPrice ? parseInt(opts.buyNowPrice) : undefined
|
|
51944
52062
|
});
|
|
51945
52063
|
if (opts.json) {
|
|
51946
|
-
|
|
52064
|
+
printLine(JSON.stringify(result, null, 2));
|
|
51947
52065
|
} else {
|
|
51948
|
-
|
|
52066
|
+
printLine(`Updated ${domain} on Sedo`);
|
|
51949
52067
|
}
|
|
51950
52068
|
});
|
|
51951
52069
|
sedo.command("remove").description("Remove a domain from Sedo marketplace").argument("<domain>", "Domain name to remove").action(async (domain) => {
|
|
51952
52070
|
const { removeDomainFromSedo: removeDomainFromSedo2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
|
|
51953
52071
|
const removed = await removeDomainFromSedo2(domain);
|
|
51954
52072
|
if (removed) {
|
|
51955
|
-
|
|
52073
|
+
printLine(`Removed ${domain} from Sedo marketplace`);
|
|
51956
52074
|
} else {
|
|
51957
|
-
|
|
52075
|
+
printErrorLine(`Failed to remove ${domain} from Sedo`);
|
|
51958
52076
|
process.exit(1);
|
|
51959
52077
|
}
|
|
51960
52078
|
});
|
|
@@ -51962,10 +52080,10 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51962
52080
|
const { checkSedoBlacklist: checkSedoBlacklist2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
|
|
51963
52081
|
const results = await checkSedoBlacklist2(domains);
|
|
51964
52082
|
if (opts.json) {
|
|
51965
|
-
|
|
52083
|
+
printLine(JSON.stringify(results, null, 2));
|
|
51966
52084
|
} else {
|
|
51967
52085
|
for (const r4 of results) {
|
|
51968
|
-
|
|
52086
|
+
printLine(` ${r4.domain}: ${r4.blacklisted ? "BLACKLISTED" : "clean"}`);
|
|
51969
52087
|
}
|
|
51970
52088
|
}
|
|
51971
52089
|
});
|
|
@@ -51974,13 +52092,15 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
|
|
|
51974
52092
|
const price = parseInt(opts.price);
|
|
51975
52093
|
const created = recordSedoPurchase2(domain, price, opts.orderId);
|
|
51976
52094
|
if (opts.json) {
|
|
51977
|
-
|
|
52095
|
+
printLine(JSON.stringify(created, null, 2));
|
|
51978
52096
|
} else {
|
|
51979
|
-
|
|
52097
|
+
printLine(`Recorded Sedo purchase: ${domain} for $${price}`);
|
|
51980
52098
|
}
|
|
51981
52099
|
});
|
|
51982
52100
|
}
|
|
51983
|
-
var init_sedo2 = () => {
|
|
52101
|
+
var init_sedo2 = __esm(() => {
|
|
52102
|
+
init_stdout();
|
|
52103
|
+
});
|
|
51984
52104
|
|
|
51985
52105
|
// src/db/owners.ts
|
|
51986
52106
|
function createDomainOwner2(input) {
|
|
@@ -52073,7 +52193,7 @@ __export(exports_owner, {
|
|
|
52073
52193
|
async function requireDomain2(identifier) {
|
|
52074
52194
|
const details = await getDomainDetails2(identifier);
|
|
52075
52195
|
if (!details) {
|
|
52076
|
-
|
|
52196
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52077
52197
|
process.exit(1);
|
|
52078
52198
|
}
|
|
52079
52199
|
return details;
|
|
@@ -52084,21 +52204,21 @@ function registerOwnerCommand(program2) {
|
|
|
52084
52204
|
if (opts.withDomains) {
|
|
52085
52205
|
const results = await listDomainsWithOwners2();
|
|
52086
52206
|
if (opts.json) {
|
|
52087
|
-
|
|
52207
|
+
printLine(JSON.stringify({ owners: results, count: results.length }, null, 2));
|
|
52088
52208
|
return;
|
|
52089
52209
|
}
|
|
52090
52210
|
const page2 = pageItemsOrExit(results, { limit: opts.limit, all: opts.all });
|
|
52091
52211
|
if (page2.items.length === 0) {
|
|
52092
|
-
|
|
52212
|
+
printLine("No premium domain owners found.");
|
|
52093
52213
|
return;
|
|
52094
52214
|
}
|
|
52095
52215
|
for (const r4 of page2.items) {
|
|
52096
52216
|
const verified = r4.verified ? " [verified]" : "";
|
|
52097
52217
|
const org = r4.owner_organization ? ` @ ${r4.owner_organization}` : "";
|
|
52098
52218
|
const email = opts.verbose && r4.owner_email ? ` email:${r4.owner_email}` : "";
|
|
52099
|
-
|
|
52219
|
+
printLine(` ${r4.domain_name} (${r4.domain_status}) \u2014 ${r4.owner_name ?? r4.owner_email ?? "unknown"}${org}${verified}${email}`);
|
|
52100
52220
|
}
|
|
52101
|
-
|
|
52221
|
+
printLine(`
|
|
52102
52222
|
${compactHint(page2, "domain(s) with owner info", "Use --verbose for email details or owner info <domain> for full details.", { paging: "limit" })}`);
|
|
52103
52223
|
return;
|
|
52104
52224
|
}
|
|
@@ -52108,87 +52228,87 @@ ${compactHint(page2, "domain(s) with owner info", "Use --verbose for email detai
|
|
|
52108
52228
|
verified: opts.verifiedOnly ? true : undefined
|
|
52109
52229
|
});
|
|
52110
52230
|
if (opts.json) {
|
|
52111
|
-
|
|
52231
|
+
printLine(JSON.stringify({ owners, count: owners.length }, null, 2));
|
|
52112
52232
|
return;
|
|
52113
52233
|
}
|
|
52114
52234
|
const page = pageItemsOrExit(owners, { limit: opts.limit, all: opts.all });
|
|
52115
52235
|
if (page.items.length === 0) {
|
|
52116
|
-
|
|
52236
|
+
printLine("No owners found.");
|
|
52117
52237
|
return;
|
|
52118
52238
|
}
|
|
52119
52239
|
for (const o2 of page.items) {
|
|
52120
52240
|
const verified = o2.verified ? " [verified]" : "";
|
|
52121
52241
|
const org = o2.owner_organization ? ` @ ${o2.owner_organization}` : "";
|
|
52122
|
-
|
|
52242
|
+
printLine(` ${truncateText(o2.owner_name ?? o2.owner_email ?? "unknown", 48)}${org} [${o2.source}]${verified}`);
|
|
52123
52243
|
if (opts.verbose && o2.owner_email)
|
|
52124
|
-
|
|
52244
|
+
printLine(` email: ${o2.owner_email}`);
|
|
52125
52245
|
if (opts.verbose && o2.owner_phone)
|
|
52126
|
-
|
|
52246
|
+
printLine(` phone: ${o2.owner_phone}`);
|
|
52127
52247
|
}
|
|
52128
|
-
|
|
52248
|
+
printLine(`
|
|
52129
52249
|
${compactHint(page, "owner(s)", "Use --verbose for contact fields or owner get <id> for details.", { paging: "limit" })}`);
|
|
52130
52250
|
});
|
|
52131
52251
|
owner.command("get <ownerId>").description("Get owner details by ID").option("-j, --json", "Output JSON").action(async (ownerId, opts) => {
|
|
52132
52252
|
const o2 = await getDomainOwner2(ownerId);
|
|
52133
52253
|
if (!o2) {
|
|
52134
|
-
|
|
52254
|
+
printErrorLine(`Owner '${ownerId}' not found.`);
|
|
52135
52255
|
process.exit(1);
|
|
52136
52256
|
}
|
|
52137
52257
|
if (opts.json) {
|
|
52138
|
-
|
|
52258
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52139
52259
|
return;
|
|
52140
52260
|
}
|
|
52141
|
-
|
|
52261
|
+
printLine(`
|
|
52142
52262
|
Owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52143
52263
|
if (o2.owner_organization)
|
|
52144
|
-
|
|
52264
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52145
52265
|
if (o2.owner_email)
|
|
52146
|
-
|
|
52266
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52147
52267
|
if (o2.owner_phone)
|
|
52148
|
-
|
|
52149
|
-
|
|
52150
|
-
|
|
52268
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52269
|
+
printLine(` Source: ${o2.source}`);
|
|
52270
|
+
printLine(` Verified: ${o2.verified ? "yes" : "no"}`);
|
|
52151
52271
|
if (o2.contact_id)
|
|
52152
|
-
|
|
52272
|
+
printLine(` Contacts ID: ${o2.contact_id}`);
|
|
52153
52273
|
if (o2.notes)
|
|
52154
|
-
|
|
52155
|
-
|
|
52274
|
+
printLine(` Notes: ${truncateText(o2.notes, 160)}`);
|
|
52275
|
+
printLine();
|
|
52156
52276
|
});
|
|
52157
52277
|
owner.command("info <identifier>").description("Show owner info for a specific domain").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52158
52278
|
const details = await requireDomain2(identifier);
|
|
52159
52279
|
const o2 = await getDomainOwnerByDomain2(details.domain.id);
|
|
52160
52280
|
if (!o2) {
|
|
52161
52281
|
if (opts.json) {
|
|
52162
|
-
|
|
52282
|
+
printLine(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
|
|
52163
52283
|
return;
|
|
52164
52284
|
}
|
|
52165
|
-
|
|
52285
|
+
printLine(`No owner info for ${details.domain.name}.`);
|
|
52166
52286
|
return;
|
|
52167
52287
|
}
|
|
52168
52288
|
const result = { domain: details.domain.name, owner: o2 };
|
|
52169
52289
|
if (opts.json) {
|
|
52170
|
-
|
|
52290
|
+
printLine(JSON.stringify(result, null, 2));
|
|
52171
52291
|
return;
|
|
52172
52292
|
}
|
|
52173
|
-
|
|
52293
|
+
printLine(`
|
|
52174
52294
|
Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
52175
|
-
|
|
52295
|
+
printLine(` Owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52176
52296
|
if (o2.owner_organization)
|
|
52177
|
-
|
|
52297
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52178
52298
|
if (o2.owner_email)
|
|
52179
|
-
|
|
52299
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52180
52300
|
if (o2.owner_phone)
|
|
52181
|
-
|
|
52182
|
-
|
|
52183
|
-
|
|
52301
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52302
|
+
printLine(` Source: ${o2.source}`);
|
|
52303
|
+
printLine(` Verified: ${o2.verified ? "yes" : "no"}`);
|
|
52184
52304
|
if (o2.contact_id)
|
|
52185
|
-
|
|
52186
|
-
|
|
52305
|
+
printLine(` Contacts ID: ${o2.contact_id}`);
|
|
52306
|
+
printLine();
|
|
52187
52307
|
});
|
|
52188
52308
|
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
52309
|
const details = await requireDomain2(identifier);
|
|
52190
52310
|
if (!opts.name && !opts.email && !opts.organization && !opts.contactId) {
|
|
52191
|
-
|
|
52311
|
+
printErrorLine("At least one of --name, --email, --organization, or --contact-id is required.");
|
|
52192
52312
|
process.exit(1);
|
|
52193
52313
|
}
|
|
52194
52314
|
const input = {
|
|
@@ -52204,15 +52324,15 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
|
52204
52324
|
};
|
|
52205
52325
|
const o2 = await createDomainOwner2(input);
|
|
52206
52326
|
if (opts.json) {
|
|
52207
|
-
|
|
52327
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52208
52328
|
return;
|
|
52209
52329
|
}
|
|
52210
|
-
|
|
52330
|
+
printLine(`Added owner for ${details.domain.name}: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52211
52331
|
});
|
|
52212
52332
|
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
52333
|
const existing = await getDomainOwner2(ownerId);
|
|
52214
52334
|
if (!existing) {
|
|
52215
|
-
|
|
52335
|
+
printErrorLine(`Owner '${ownerId}' not found.`);
|
|
52216
52336
|
process.exit(1);
|
|
52217
52337
|
}
|
|
52218
52338
|
const update = {};
|
|
@@ -52234,72 +52354,72 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
|
52234
52354
|
update.notes = opts.notes;
|
|
52235
52355
|
const o2 = await updateDomainOwner2(ownerId, update);
|
|
52236
52356
|
if (!o2) {
|
|
52237
|
-
|
|
52357
|
+
printErrorLine("Update failed.");
|
|
52238
52358
|
process.exit(1);
|
|
52239
52359
|
}
|
|
52240
52360
|
if (opts.json) {
|
|
52241
|
-
|
|
52361
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52242
52362
|
return;
|
|
52243
52363
|
}
|
|
52244
|
-
|
|
52364
|
+
printLine(`Updated owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
|
|
52245
52365
|
});
|
|
52246
52366
|
owner.command("delete <ownerId>").description("Delete an owner record").option("-f, --force", "Required confirmation").action(async (ownerId, opts) => {
|
|
52247
52367
|
if (!opts.force) {
|
|
52248
|
-
|
|
52368
|
+
printErrorLine(`Refusing to delete owner '${ownerId}' without --force.`);
|
|
52249
52369
|
process.exit(1);
|
|
52250
52370
|
}
|
|
52251
52371
|
const deleted = await deleteDomainOwner2(ownerId);
|
|
52252
52372
|
if (!deleted) {
|
|
52253
|
-
|
|
52373
|
+
printErrorLine(`Owner '${ownerId}' not found.`);
|
|
52254
52374
|
process.exit(1);
|
|
52255
52375
|
}
|
|
52256
|
-
|
|
52376
|
+
printLine(`Deleted owner ${ownerId}`);
|
|
52257
52377
|
});
|
|
52258
52378
|
owner.command("extract <identifier>").description("Extract owner info from WHOIS lookup").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52259
52379
|
const details = await requireDomain2(identifier);
|
|
52260
52380
|
const whois = await whoisLookup(details.domain.name);
|
|
52261
52381
|
if (!whois.raw) {
|
|
52262
|
-
|
|
52382
|
+
printErrorLine("WHOIS returned no data.");
|
|
52263
52383
|
process.exit(1);
|
|
52264
52384
|
}
|
|
52265
52385
|
const o2 = await extractOwnerFromWhois(details.domain.name, whois.raw);
|
|
52266
52386
|
if (!o2) {
|
|
52267
|
-
|
|
52387
|
+
printLine("No owner information found in WHOIS data.");
|
|
52268
52388
|
return;
|
|
52269
52389
|
}
|
|
52270
52390
|
if (opts.json) {
|
|
52271
|
-
|
|
52391
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52272
52392
|
return;
|
|
52273
52393
|
}
|
|
52274
|
-
|
|
52394
|
+
printLine(`Extracted owner for ${details.domain.name}:`);
|
|
52275
52395
|
if (o2.owner_name)
|
|
52276
|
-
|
|
52396
|
+
printLine(` Name: ${o2.owner_name}`);
|
|
52277
52397
|
if (o2.owner_email)
|
|
52278
|
-
|
|
52398
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52279
52399
|
if (o2.owner_phone)
|
|
52280
|
-
|
|
52400
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52281
52401
|
if (o2.owner_organization)
|
|
52282
|
-
|
|
52283
|
-
|
|
52402
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52403
|
+
printLine();
|
|
52284
52404
|
});
|
|
52285
52405
|
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
52406
|
const details = await requireDomain2(identifier);
|
|
52287
52407
|
const o2 = await getDomainOwnerByDomain2(details.domain.id);
|
|
52288
52408
|
if (!o2) {
|
|
52289
|
-
|
|
52409
|
+
printErrorLine(`No owner record for ${details.domain.name}. Add one first.`);
|
|
52290
52410
|
process.exit(1);
|
|
52291
52411
|
}
|
|
52292
52412
|
if (opts.contactId) {
|
|
52293
52413
|
const updated = await updateDomainOwner2(o2.id, { contact_id: opts.contactId });
|
|
52294
52414
|
if (!updated) {
|
|
52295
|
-
|
|
52415
|
+
printErrorLine("Link failed.");
|
|
52296
52416
|
process.exit(1);
|
|
52297
52417
|
}
|
|
52298
52418
|
if (opts.json) {
|
|
52299
|
-
|
|
52419
|
+
printLine(JSON.stringify(updated, null, 2));
|
|
52300
52420
|
return;
|
|
52301
52421
|
}
|
|
52302
|
-
|
|
52422
|
+
printLine(`Linked ${details.domain.name} to contact ${opts.contactId}`);
|
|
52303
52423
|
return;
|
|
52304
52424
|
}
|
|
52305
52425
|
if (opts.auto) {
|
|
@@ -52311,64 +52431,65 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
|
|
|
52311
52431
|
getContactByEmail: (email) => contacts.getContactByEmail(email)
|
|
52312
52432
|
});
|
|
52313
52433
|
if (!contactId) {
|
|
52314
|
-
|
|
52434
|
+
printErrorLine("Could not create/find contact \u2014 owner has no email.");
|
|
52315
52435
|
process.exit(1);
|
|
52316
52436
|
}
|
|
52317
52437
|
if (opts.json) {
|
|
52318
|
-
|
|
52438
|
+
printLine(JSON.stringify({ domain: details.domain.name, contact_id: contactId }, null, 2));
|
|
52319
52439
|
return;
|
|
52320
52440
|
}
|
|
52321
|
-
|
|
52441
|
+
printLine(`Created/linked contact ${contactId} for ${details.domain.name}`);
|
|
52322
52442
|
} catch (e4) {
|
|
52323
52443
|
const message = e4 instanceof Error ? e4.message : String(e4);
|
|
52324
52444
|
if (typeof e4 === "object" && e4 !== null && "code" in e4 && e4.code === "MODULE_NOT_FOUND" || message.includes("@hasna/contacts")) {
|
|
52325
|
-
|
|
52445
|
+
printErrorLine("@hasna/contacts is not installed. Install it alongside @hasna/domains, or pass --contact-id to link an existing contact ID.");
|
|
52326
52446
|
} else {
|
|
52327
|
-
|
|
52447
|
+
printErrorLine(`Failed to link to open-contacts: ${message}`);
|
|
52328
52448
|
}
|
|
52329
52449
|
process.exit(1);
|
|
52330
52450
|
}
|
|
52331
52451
|
return;
|
|
52332
52452
|
}
|
|
52333
|
-
|
|
52453
|
+
printErrorLine("Use --contact-id <id> or --auto to link.");
|
|
52334
52454
|
process.exit(1);
|
|
52335
52455
|
});
|
|
52336
52456
|
owner.command("whois <identifier>").description("WHOIS lookup and save owner info").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52337
52457
|
const details = await requireDomain2(identifier);
|
|
52338
52458
|
const whois = await whoisLookup(details.domain.name);
|
|
52339
52459
|
if (!whois.raw) {
|
|
52340
|
-
|
|
52460
|
+
printErrorLine("WHOIS returned no data.");
|
|
52341
52461
|
process.exit(1);
|
|
52342
52462
|
}
|
|
52343
52463
|
const o2 = await extractOwnerFromWhois(details.domain.name, whois.raw);
|
|
52344
52464
|
if (!o2) {
|
|
52345
52465
|
if (opts.json) {
|
|
52346
|
-
|
|
52466
|
+
printLine(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
|
|
52347
52467
|
return;
|
|
52348
52468
|
}
|
|
52349
|
-
|
|
52469
|
+
printLine("No owner information found in WHOIS data.");
|
|
52350
52470
|
return;
|
|
52351
52471
|
}
|
|
52352
52472
|
if (opts.json) {
|
|
52353
|
-
|
|
52473
|
+
printLine(JSON.stringify(o2, null, 2));
|
|
52354
52474
|
return;
|
|
52355
52475
|
}
|
|
52356
|
-
|
|
52476
|
+
printLine(`WHOIS owner for ${details.domain.name}:`);
|
|
52357
52477
|
if (o2.owner_name)
|
|
52358
|
-
|
|
52478
|
+
printLine(` Name: ${o2.owner_name}`);
|
|
52359
52479
|
if (o2.owner_email)
|
|
52360
|
-
|
|
52480
|
+
printLine(` Email: ${o2.owner_email}`);
|
|
52361
52481
|
if (o2.owner_phone)
|
|
52362
|
-
|
|
52482
|
+
printLine(` Phone: ${o2.owner_phone}`);
|
|
52363
52483
|
if (o2.owner_organization)
|
|
52364
|
-
|
|
52365
|
-
|
|
52366
|
-
|
|
52484
|
+
printLine(` Organization: ${o2.owner_organization}`);
|
|
52485
|
+
printLine(` Source: ${o2.source}`);
|
|
52486
|
+
printLine();
|
|
52367
52487
|
});
|
|
52368
52488
|
}
|
|
52369
52489
|
var init_owner = __esm(() => {
|
|
52370
52490
|
init_owners();
|
|
52371
52491
|
init_domains();
|
|
52492
|
+
init_stdout();
|
|
52372
52493
|
});
|
|
52373
52494
|
|
|
52374
52495
|
// src/cli/commands/history.ts
|
|
@@ -52381,7 +52502,7 @@ function registerHistoryCommand(program2) {
|
|
|
52381
52502
|
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
52503
|
const domain = await getDomainDetails2(identifier);
|
|
52383
52504
|
if (!domain) {
|
|
52384
|
-
|
|
52505
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52385
52506
|
process.exit(1);
|
|
52386
52507
|
}
|
|
52387
52508
|
const entries = await getHistoryByDomain2(domain.domain.id, {
|
|
@@ -52389,94 +52510,95 @@ function registerHistoryCommand(program2) {
|
|
|
52389
52510
|
limit: opts.limit ? parseInt(opts.limit) : undefined
|
|
52390
52511
|
});
|
|
52391
52512
|
if (opts.json) {
|
|
52392
|
-
|
|
52513
|
+
printLine(JSON.stringify({ domain: domain.domain.name, history: entries, count: entries.length }, null, 2));
|
|
52393
52514
|
return;
|
|
52394
52515
|
}
|
|
52395
52516
|
if (entries.length === 0) {
|
|
52396
|
-
|
|
52517
|
+
printLine(`No history entries for ${domain.domain.name}.`);
|
|
52397
52518
|
return;
|
|
52398
52519
|
}
|
|
52399
|
-
|
|
52520
|
+
printLine(`History for ${domain.domain.name}:`);
|
|
52400
52521
|
for (const e4 of entries) {
|
|
52401
|
-
|
|
52522
|
+
printLine(` [${e4.created_at}] ${e4.snapshot_type} \u2014 ${e4.registrant_name ?? e4.registrant_email ?? "no owner info"}`);
|
|
52402
52523
|
if (e4.registrar)
|
|
52403
|
-
|
|
52524
|
+
printLine(` Registrar: ${e4.registrar}`);
|
|
52404
52525
|
if (e4.notes)
|
|
52405
|
-
|
|
52526
|
+
printLine(` Notes: ${truncateText(e4.notes, 120)}`);
|
|
52406
52527
|
}
|
|
52407
|
-
|
|
52528
|
+
printLine(`
|
|
52408
52529
|
${entries.length} entry(ies). Use --limit <n> for a different page size or --json for full snapshots.`);
|
|
52409
52530
|
});
|
|
52410
52531
|
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
52532
|
const results = await listDomainsWithHistoryChanges2();
|
|
52412
52533
|
if (opts.json) {
|
|
52413
|
-
|
|
52534
|
+
printLine(JSON.stringify({ domains: results, count: results.length }, null, 2));
|
|
52414
52535
|
return;
|
|
52415
52536
|
}
|
|
52416
52537
|
if (results.length === 0) {
|
|
52417
|
-
|
|
52538
|
+
printLine("No domains with history entries.");
|
|
52418
52539
|
return;
|
|
52419
52540
|
}
|
|
52420
52541
|
const page = pageItemsOrExit(results, { limit: opts.limit, all: opts.all });
|
|
52421
|
-
|
|
52542
|
+
printLine("Domain History Timeline:");
|
|
52422
52543
|
for (const r4 of page.items) {
|
|
52423
|
-
|
|
52544
|
+
printLine(` ${r4.domain_name} \u2014 ${r4.snapshot_count} snapshots, latest: ${r4.latest_snapshot_type} at ${r4.latest_snapshot_at}`);
|
|
52424
52545
|
}
|
|
52425
|
-
|
|
52546
|
+
printLine(`
|
|
52426
52547
|
${compactHint(page, "domain(s) with history", "Use history list <domain> for domain details or --json for full data.", { paging: "limit" })}`);
|
|
52427
52548
|
});
|
|
52428
52549
|
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
52550
|
const entries = await getHistoryByDateRange2(opts.from, opts.to, opts.domain);
|
|
52430
52551
|
if (opts.json) {
|
|
52431
|
-
|
|
52552
|
+
printLine(JSON.stringify({ history: entries, count: entries.length }, null, 2));
|
|
52432
52553
|
return;
|
|
52433
52554
|
}
|
|
52434
52555
|
if (entries.length === 0) {
|
|
52435
|
-
|
|
52556
|
+
printLine(`No history entries between ${opts.from} and ${opts.to}.`);
|
|
52436
52557
|
return;
|
|
52437
52558
|
}
|
|
52438
52559
|
const page = pageItemsOrExit(entries, { limit: opts.limit, all: opts.all });
|
|
52439
|
-
|
|
52560
|
+
printLine(`History from ${opts.from} to ${opts.to}:`);
|
|
52440
52561
|
for (const e4 of page.items) {
|
|
52441
52562
|
const extra = opts.verbose ? ` registrar:${truncateText(e4.registrar ?? "-", 40)} notes:${truncateText(e4.notes ?? "-", 80)}` : "";
|
|
52442
|
-
|
|
52563
|
+
printLine(` [${e4.created_at}] ${e4.snapshot_type} \u2014 domain ${e4.domain_id}${extra}`);
|
|
52443
52564
|
}
|
|
52444
|
-
|
|
52565
|
+
printLine(`
|
|
52445
52566
|
${compactHint(page, "entry(s)", "Use --verbose for more columns or --json for full snapshots.", { paging: "limit" })}`);
|
|
52446
52567
|
});
|
|
52447
52568
|
history.command("delete <entryId>").description("Delete a history entry").option("-f, --force", "Required confirmation").action(async (entryId, opts) => {
|
|
52448
52569
|
if (!opts.force) {
|
|
52449
|
-
|
|
52570
|
+
printErrorLine(`Refusing to delete history '${entryId}' without --force.`);
|
|
52450
52571
|
process.exit(1);
|
|
52451
52572
|
}
|
|
52452
52573
|
const deleted = await deleteHistoryEntry2(entryId);
|
|
52453
52574
|
if (!deleted) {
|
|
52454
|
-
|
|
52575
|
+
printErrorLine(`History entry '${entryId}' not found.`);
|
|
52455
52576
|
process.exit(1);
|
|
52456
52577
|
}
|
|
52457
|
-
|
|
52578
|
+
printLine(`Deleted history entry ${entryId}`);
|
|
52458
52579
|
});
|
|
52459
52580
|
history.command("purge <identifier>").description("Delete all history for a domain").option("-f, --force", "Required confirmation").action(async (identifier, opts) => {
|
|
52460
52581
|
if (!opts.force) {
|
|
52461
|
-
|
|
52582
|
+
printErrorLine(`Refusing to purge history for '${identifier}' without --force.`);
|
|
52462
52583
|
process.exit(1);
|
|
52463
52584
|
}
|
|
52464
52585
|
const domain = await getDomainDetails2(identifier);
|
|
52465
52586
|
if (!domain) {
|
|
52466
|
-
|
|
52587
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52467
52588
|
process.exit(1);
|
|
52468
52589
|
}
|
|
52469
52590
|
const deleted = await deleteHistoryByDomain2(domain.domain.id);
|
|
52470
52591
|
if (!deleted) {
|
|
52471
|
-
|
|
52592
|
+
printErrorLine(`No history to purge for ${domain.domain.name}.`);
|
|
52472
52593
|
process.exit(1);
|
|
52473
52594
|
}
|
|
52474
|
-
|
|
52595
|
+
printLine(`Purged all history for ${domain.domain.name}`);
|
|
52475
52596
|
});
|
|
52476
52597
|
}
|
|
52477
52598
|
var init_history2 = __esm(() => {
|
|
52478
52599
|
init_history();
|
|
52479
52600
|
init_domains();
|
|
52601
|
+
init_stdout();
|
|
52480
52602
|
});
|
|
52481
52603
|
|
|
52482
52604
|
// src/db/domain-research.ts
|
|
@@ -52643,13 +52765,13 @@ function registerResearchCommand(program2) {
|
|
|
52643
52765
|
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
52766
|
const domain = await getDomainDetails2(identifier);
|
|
52645
52767
|
if (!domain) {
|
|
52646
|
-
|
|
52768
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52647
52769
|
process.exit(1);
|
|
52648
52770
|
}
|
|
52649
52771
|
try {
|
|
52650
52772
|
const result = await researchDomain(domain.domain.name);
|
|
52651
52773
|
if (opts.json) {
|
|
52652
|
-
|
|
52774
|
+
printLine(JSON.stringify({
|
|
52653
52775
|
domain: result.domain,
|
|
52654
52776
|
summary: result.summary,
|
|
52655
52777
|
results: result.results.map((r4) => ({ title: r4.title, url: r4.url, score: r4.score })),
|
|
@@ -52658,124 +52780,124 @@ function registerResearchCommand(program2) {
|
|
|
52658
52780
|
}, null, 2));
|
|
52659
52781
|
return;
|
|
52660
52782
|
}
|
|
52661
|
-
|
|
52783
|
+
printLine(`Exa Research for ${result.domain}:`);
|
|
52662
52784
|
if (result.summary)
|
|
52663
|
-
|
|
52785
|
+
printLine(`
|
|
52664
52786
|
Summary: ${truncateText(result.summary, 240)}`);
|
|
52665
52787
|
if (result.results.length > 0) {
|
|
52666
52788
|
const page = pageItemsOrExit(result.results, { limit: opts.limit, all: opts.all });
|
|
52667
|
-
|
|
52789
|
+
printLine(`
|
|
52668
52790
|
Web Results:`);
|
|
52669
52791
|
for (const r4 of page.items) {
|
|
52670
|
-
|
|
52671
|
-
|
|
52792
|
+
printLine(` - ${truncateText(r4.title, 100)} (${r4.score.toFixed(2)})`);
|
|
52793
|
+
printLine(` ${r4.url}`);
|
|
52672
52794
|
}
|
|
52673
|
-
|
|
52795
|
+
printLine(` ${compactHint(page, "web result(s)", "Use --all for every result or --json for structured output.", { paging: "limit" })}`);
|
|
52674
52796
|
}
|
|
52675
52797
|
if (result.companies.length > 0) {
|
|
52676
52798
|
const page = pageItemsOrExit(result.companies, { limit: opts.limit, all: opts.all });
|
|
52677
|
-
|
|
52799
|
+
printLine(`
|
|
52678
52800
|
Companies:`);
|
|
52679
52801
|
for (const c4 of page.items) {
|
|
52680
|
-
|
|
52802
|
+
printLine(` - ${c4.name}: ${c4.domain}`);
|
|
52681
52803
|
}
|
|
52682
|
-
|
|
52804
|
+
printLine(` ${compactHint(page, "company result(s)", "Use --all for every company or --json for structured output.", { paging: "limit" })}`);
|
|
52683
52805
|
}
|
|
52684
52806
|
if (result.savedHistory) {
|
|
52685
|
-
|
|
52807
|
+
printLine(`
|
|
52686
52808
|
Saved to history: ${result.savedHistory.id}`);
|
|
52687
52809
|
}
|
|
52688
|
-
|
|
52810
|
+
printLine();
|
|
52689
52811
|
} catch (error) {
|
|
52690
|
-
|
|
52812
|
+
printErrorLine(`Research failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
52691
52813
|
process.exit(1);
|
|
52692
52814
|
}
|
|
52693
52815
|
});
|
|
52694
52816
|
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
52817
|
const domain = await getDomainDetails2(identifier);
|
|
52696
52818
|
if (!domain) {
|
|
52697
|
-
|
|
52819
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52698
52820
|
process.exit(1);
|
|
52699
52821
|
}
|
|
52700
52822
|
try {
|
|
52701
52823
|
const answer = await answerAboutDomain(domain.domain.name, question);
|
|
52702
52824
|
if (opts.json) {
|
|
52703
|
-
|
|
52825
|
+
printLine(JSON.stringify({ domain: domain.domain.name, question, answer }, null, 2));
|
|
52704
52826
|
return;
|
|
52705
52827
|
}
|
|
52706
52828
|
if (!answer) {
|
|
52707
|
-
|
|
52829
|
+
printLine("No answer found.");
|
|
52708
52830
|
return;
|
|
52709
52831
|
}
|
|
52710
|
-
|
|
52711
|
-
|
|
52832
|
+
printLine(`Q: ${question}`);
|
|
52833
|
+
printLine(`A: ${answer}`);
|
|
52712
52834
|
} catch (error) {
|
|
52713
|
-
|
|
52835
|
+
printErrorLine(`Answer failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
52714
52836
|
process.exit(1);
|
|
52715
52837
|
}
|
|
52716
52838
|
});
|
|
52717
52839
|
research.command("reputation <identifier>").description("Check domain reputation and blacklist status").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
52718
52840
|
const domain = await getDomainDetails2(identifier);
|
|
52719
52841
|
if (!domain) {
|
|
52720
|
-
|
|
52842
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
52721
52843
|
process.exit(1);
|
|
52722
52844
|
}
|
|
52723
52845
|
const { reputation, dnsBlacklist } = await checkDomainReputation(domain.domain.name);
|
|
52724
52846
|
if (opts.json) {
|
|
52725
|
-
|
|
52847
|
+
printLine(JSON.stringify({ domain: domain.domain.name, reputation, dnsBlacklist }, null, 2));
|
|
52726
52848
|
return;
|
|
52727
52849
|
}
|
|
52728
|
-
|
|
52850
|
+
printLine(`Reputation for ${domain.domain.name}:`);
|
|
52729
52851
|
if (reputation) {
|
|
52730
|
-
|
|
52852
|
+
printLine(` Blacklisted: ${reputation.is_blacklisted ? "yes" : "no"}`);
|
|
52731
52853
|
if (reputation.threat_score !== null)
|
|
52732
|
-
|
|
52854
|
+
printLine(` Threat Score: ${reputation.threat_score}`);
|
|
52733
52855
|
if (reputation.spam_score !== null)
|
|
52734
|
-
|
|
52735
|
-
|
|
52736
|
-
|
|
52856
|
+
printLine(` Spam Score: ${reputation.spam_score}`);
|
|
52857
|
+
printLine(` Malware: ${reputation.malware_detected ? "detected" : "clean"}`);
|
|
52858
|
+
printLine(` Phishing: ${reputation.phishing_detected ? "detected" : "clean"}`);
|
|
52737
52859
|
if (reputation.last_checked_at)
|
|
52738
|
-
|
|
52860
|
+
printLine(` Last Checked: ${reputation.last_checked_at}`);
|
|
52739
52861
|
} else {
|
|
52740
|
-
|
|
52862
|
+
printLine(" No reputation data yet.");
|
|
52741
52863
|
}
|
|
52742
|
-
|
|
52864
|
+
printLine(` DNS Blacklist: ${dnsBlacklist.listed ? `listed in ${dnsBlacklist.zones.join(", ")}` : "clean"}`);
|
|
52743
52865
|
});
|
|
52744
52866
|
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
52867
|
const domains = await listBlacklistedDomains2();
|
|
52746
52868
|
if (opts.json) {
|
|
52747
|
-
|
|
52869
|
+
printLine(JSON.stringify({ domains, count: domains.length }, null, 2));
|
|
52748
52870
|
return;
|
|
52749
52871
|
}
|
|
52750
52872
|
if (domains.length === 0) {
|
|
52751
|
-
|
|
52873
|
+
printLine("No blacklisted domains.");
|
|
52752
52874
|
return;
|
|
52753
52875
|
}
|
|
52754
52876
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
52755
|
-
|
|
52877
|
+
printLine("Blacklisted domains:");
|
|
52756
52878
|
for (const d4 of page.items) {
|
|
52757
|
-
|
|
52879
|
+
printLine(` domain_id: ${d4.domain_id} (sources: ${truncateText(d4.blacklist_sources.join(", "), 100)})`);
|
|
52758
52880
|
}
|
|
52759
|
-
|
|
52881
|
+
printLine(`
|
|
52760
52882
|
${compactHint(page, "blacklisted domain(s)", "Use --all for every domain or --json for full source arrays.", { paging: "limit" })}`);
|
|
52761
52883
|
});
|
|
52762
52884
|
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
52885
|
const threshold = parseInt(opts.threshold ?? "70");
|
|
52764
52886
|
const domains = await listHighThreatDomains2(threshold);
|
|
52765
52887
|
if (opts.json) {
|
|
52766
|
-
|
|
52888
|
+
printLine(JSON.stringify({ domains, threshold, count: domains.length }, null, 2));
|
|
52767
52889
|
return;
|
|
52768
52890
|
}
|
|
52769
52891
|
if (domains.length === 0) {
|
|
52770
|
-
|
|
52892
|
+
printLine(`No domains with threat score >= ${threshold}.`);
|
|
52771
52893
|
return;
|
|
52772
52894
|
}
|
|
52773
52895
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
52774
|
-
|
|
52896
|
+
printLine(`Domains with threat score >= ${threshold}:`);
|
|
52775
52897
|
for (const d4 of page.items) {
|
|
52776
|
-
|
|
52898
|
+
printLine(` domain_id: ${d4.domain_id} \u2014 score: ${d4.threat_score ?? "?"}`);
|
|
52777
52899
|
}
|
|
52778
|
-
|
|
52900
|
+
printLine(`
|
|
52779
52901
|
${compactHint(page, "domain(s)", "Use --all for every domain or --json for full reputation records.", { paging: "limit" })}`);
|
|
52780
52902
|
});
|
|
52781
52903
|
}
|
|
@@ -52783,6 +52905,7 @@ var init_research = __esm(() => {
|
|
|
52783
52905
|
init_domain_research();
|
|
52784
52906
|
init_domains();
|
|
52785
52907
|
init_reputation();
|
|
52908
|
+
init_stdout();
|
|
52786
52909
|
});
|
|
52787
52910
|
|
|
52788
52911
|
// src/cli/commands/outreach.ts
|
|
@@ -52795,7 +52918,7 @@ import { promisify as promisify3 } from "util";
|
|
|
52795
52918
|
async function requireDomainOwner(identifier) {
|
|
52796
52919
|
const owner = await getDomainOwnerByDomainName2(identifier);
|
|
52797
52920
|
if (!owner) {
|
|
52798
|
-
|
|
52921
|
+
printErrorLine(`No owner info found for '${identifier}'.`);
|
|
52799
52922
|
process.exit(1);
|
|
52800
52923
|
}
|
|
52801
52924
|
return owner;
|
|
@@ -52805,7 +52928,7 @@ function registerOutreachCommand(program2) {
|
|
|
52805
52928
|
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
52929
|
const owner = await requireDomainOwner(identifier);
|
|
52807
52930
|
if (!owner.owner_phone) {
|
|
52808
|
-
|
|
52931
|
+
printErrorLine(`No phone number for '${identifier}'.`);
|
|
52809
52932
|
process.exit(1);
|
|
52810
52933
|
}
|
|
52811
52934
|
try {
|
|
@@ -52821,20 +52944,20 @@ function registerOutreachCommand(program2) {
|
|
|
52821
52944
|
], { encoding: "utf-8" });
|
|
52822
52945
|
const result = JSON.parse(stdout);
|
|
52823
52946
|
if (opts.json) {
|
|
52824
|
-
|
|
52947
|
+
printLine(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
|
|
52825
52948
|
} else {
|
|
52826
|
-
|
|
52949
|
+
printLine(`SMS sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
|
|
52827
52950
|
}
|
|
52828
52951
|
} catch (error) {
|
|
52829
52952
|
const msg = error instanceof Error ? error.message : String(error);
|
|
52830
|
-
|
|
52953
|
+
printErrorLine(`SMS send failed: ${msg}`);
|
|
52831
52954
|
process.exit(1);
|
|
52832
52955
|
}
|
|
52833
52956
|
});
|
|
52834
52957
|
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
52958
|
const owner = await requireDomainOwner(identifier);
|
|
52836
52959
|
if (!owner.owner_phone) {
|
|
52837
|
-
|
|
52960
|
+
printErrorLine(`No phone number for '${identifier}'.`);
|
|
52838
52961
|
process.exit(1);
|
|
52839
52962
|
}
|
|
52840
52963
|
try {
|
|
@@ -52850,20 +52973,20 @@ function registerOutreachCommand(program2) {
|
|
|
52850
52973
|
], { encoding: "utf-8" });
|
|
52851
52974
|
const result = JSON.parse(stdout);
|
|
52852
52975
|
if (opts.json) {
|
|
52853
|
-
|
|
52976
|
+
printLine(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
|
|
52854
52977
|
} else {
|
|
52855
|
-
|
|
52978
|
+
printLine(`WhatsApp sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
|
|
52856
52979
|
}
|
|
52857
52980
|
} catch (error) {
|
|
52858
52981
|
const msg = error instanceof Error ? error.message : String(error);
|
|
52859
|
-
|
|
52982
|
+
printErrorLine(`WhatsApp send failed: ${msg}`);
|
|
52860
52983
|
process.exit(1);
|
|
52861
52984
|
}
|
|
52862
52985
|
});
|
|
52863
52986
|
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
52987
|
const owner = await requireDomainOwner(identifier);
|
|
52865
52988
|
if (!owner.owner_email) {
|
|
52866
|
-
|
|
52989
|
+
printErrorLine(`No email for '${identifier}'.`);
|
|
52867
52990
|
process.exit(1);
|
|
52868
52991
|
}
|
|
52869
52992
|
try {
|
|
@@ -52881,13 +53004,13 @@ function registerOutreachCommand(program2) {
|
|
|
52881
53004
|
], { encoding: "utf-8" });
|
|
52882
53005
|
const result = JSON.parse(stdout);
|
|
52883
53006
|
if (opts.json) {
|
|
52884
|
-
|
|
53007
|
+
printLine(JSON.stringify({ domain: identifier, to: owner.owner_email, result }, null, 2));
|
|
52885
53008
|
} else {
|
|
52886
|
-
|
|
53009
|
+
printLine(`Email sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_email}): "${opts.subject}"`);
|
|
52887
53010
|
}
|
|
52888
53011
|
} catch (error) {
|
|
52889
53012
|
const msg = error instanceof Error ? error.message : String(error);
|
|
52890
|
-
|
|
53013
|
+
printErrorLine(`Email send failed: ${msg}`);
|
|
52891
53014
|
process.exit(1);
|
|
52892
53015
|
}
|
|
52893
53016
|
});
|
|
@@ -52895,6 +53018,7 @@ function registerOutreachCommand(program2) {
|
|
|
52895
53018
|
var execFileAsync2;
|
|
52896
53019
|
var init_outreach = __esm(() => {
|
|
52897
53020
|
init_owners();
|
|
53021
|
+
init_stdout();
|
|
52898
53022
|
execFileAsync2 = promisify3(execFile2);
|
|
52899
53023
|
});
|
|
52900
53024
|
|
|
@@ -52934,22 +53058,22 @@ function registerWalletCommand(program2) {
|
|
|
52934
53058
|
try {
|
|
52935
53059
|
const cards = await getAvailableCards();
|
|
52936
53060
|
if (opts.json) {
|
|
52937
|
-
|
|
53061
|
+
printLine(JSON.stringify(cards, null, 2));
|
|
52938
53062
|
} else {
|
|
52939
53063
|
if (cards.length === 0) {
|
|
52940
|
-
|
|
53064
|
+
printLine("No active wallet cards found.");
|
|
52941
53065
|
return;
|
|
52942
53066
|
}
|
|
52943
53067
|
const page = pageItemsOrExit(cards, { limit: opts.limit, all: opts.all });
|
|
52944
|
-
|
|
53068
|
+
printLine("Available wallet cards:");
|
|
52945
53069
|
for (const c4 of page.items) {
|
|
52946
|
-
|
|
53070
|
+
printLine(` ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} \u2014 ${c4.name} (${c4.balance} ${c4.currency})`);
|
|
52947
53071
|
}
|
|
52948
|
-
|
|
53072
|
+
printLine(`
|
|
52949
53073
|
${compactHint(page, "card(s)", "Use --all for every card or --json for full card fields.", { paging: "limit" })}`);
|
|
52950
53074
|
}
|
|
52951
53075
|
} catch (error) {
|
|
52952
|
-
|
|
53076
|
+
printErrorLine(`Failed to list cards: ${error instanceof Error ? error.message : String(error)}`);
|
|
52953
53077
|
process.exit(1);
|
|
52954
53078
|
}
|
|
52955
53079
|
});
|
|
@@ -52961,15 +53085,15 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
52961
53085
|
if (!cardId) {
|
|
52962
53086
|
const cards = await getAvailableCards();
|
|
52963
53087
|
if (cards.length === 0) {
|
|
52964
|
-
|
|
53088
|
+
printErrorLine("No active wallet cards found. Add a card first.");
|
|
52965
53089
|
process.exit(1);
|
|
52966
53090
|
}
|
|
52967
53091
|
if (cards.length === 1) {
|
|
52968
53092
|
cardId = cards[0].external_id;
|
|
52969
53093
|
} else {
|
|
52970
|
-
|
|
53094
|
+
printErrorLine("Multiple cards available. Specify --card-id:");
|
|
52971
53095
|
for (const c4 of cards) {
|
|
52972
|
-
|
|
53096
|
+
printLine(` ${c4.id}: ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} (${c4.balance} ${c4.currency})`);
|
|
52973
53097
|
}
|
|
52974
53098
|
process.exit(1);
|
|
52975
53099
|
}
|
|
@@ -52977,16 +53101,16 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
52977
53101
|
const wallets = getWalletsModule();
|
|
52978
53102
|
const card = wallets.getCard(cardId);
|
|
52979
53103
|
if (!card) {
|
|
52980
|
-
|
|
53104
|
+
printErrorLine(`Card '${cardId}' not found.`);
|
|
52981
53105
|
process.exit(1);
|
|
52982
53106
|
}
|
|
52983
53107
|
if (card.balance < price) {
|
|
52984
|
-
|
|
53108
|
+
printErrorLine(`Insufficient funds: need ${price} ${currency}, have ${card.balance} ${card.currency}`);
|
|
52985
53109
|
process.exit(1);
|
|
52986
53110
|
}
|
|
52987
53111
|
const existing = await getDomainByName2(name);
|
|
52988
53112
|
if (existing) {
|
|
52989
|
-
|
|
53113
|
+
printErrorLine(`Domain '${name}' already exists in portfolio.`);
|
|
52990
53114
|
process.exit(1);
|
|
52991
53115
|
}
|
|
52992
53116
|
const domain = await createDomain2({
|
|
@@ -53010,13 +53134,13 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53010
53134
|
notes: `Purchased ${name} for ${price} ${currency} via wallet card ${cardId}`
|
|
53011
53135
|
});
|
|
53012
53136
|
if (opts.json) {
|
|
53013
|
-
|
|
53137
|
+
printLine(JSON.stringify({ domain, card_id: cardId, price, currency }, null, 2));
|
|
53014
53138
|
} else {
|
|
53015
|
-
|
|
53016
|
-
|
|
53139
|
+
printLine(`Purchased ${name} for ${price} ${currency} via wallet card`);
|
|
53140
|
+
printLine(` Added to portfolio as ${domain.id}`);
|
|
53017
53141
|
}
|
|
53018
53142
|
} catch (error) {
|
|
53019
|
-
|
|
53143
|
+
printErrorLine(`Wallet purchase failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
53020
53144
|
process.exit(1);
|
|
53021
53145
|
}
|
|
53022
53146
|
});
|
|
@@ -53024,7 +53148,7 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53024
53148
|
const price = parseFloat(opts.price);
|
|
53025
53149
|
const domain = await getDomainByName2(name);
|
|
53026
53150
|
if (!domain) {
|
|
53027
|
-
|
|
53151
|
+
printErrorLine(`Domain '${name}' not found in portfolio.`);
|
|
53028
53152
|
process.exit(1);
|
|
53029
53153
|
}
|
|
53030
53154
|
try {
|
|
@@ -53032,7 +53156,7 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53032
53156
|
if (!cardId) {
|
|
53033
53157
|
const cards = await getAvailableCards();
|
|
53034
53158
|
if (cards.length === 0) {
|
|
53035
|
-
|
|
53159
|
+
printErrorLine("No active wallet cards found.");
|
|
53036
53160
|
process.exit(1);
|
|
53037
53161
|
}
|
|
53038
53162
|
cardId = cards[0].external_id;
|
|
@@ -53040,11 +53164,11 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53040
53164
|
const wallets = getWalletsModule();
|
|
53041
53165
|
const card = wallets.getCard(cardId);
|
|
53042
53166
|
if (!card) {
|
|
53043
|
-
|
|
53167
|
+
printErrorLine(`Card '${cardId}' not found.`);
|
|
53044
53168
|
process.exit(1);
|
|
53045
53169
|
}
|
|
53046
53170
|
if (card.balance < price) {
|
|
53047
|
-
|
|
53171
|
+
printErrorLine(`Insufficient funds: need ${price} ${opts.currency}, have ${card.balance} ${card.currency}`);
|
|
53048
53172
|
process.exit(1);
|
|
53049
53173
|
}
|
|
53050
53174
|
await createHistoryEntry2({
|
|
@@ -53060,13 +53184,13 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
|
|
|
53060
53184
|
purchase_price: price
|
|
53061
53185
|
});
|
|
53062
53186
|
if (opts.json) {
|
|
53063
|
-
|
|
53187
|
+
printLine(JSON.stringify({ domain: name, card_id: cardId, price, new_expiry: expiryDate.toISOString() }, null, 2));
|
|
53064
53188
|
} else {
|
|
53065
|
-
|
|
53066
|
-
|
|
53189
|
+
printLine(`Renewed ${name} for ${price} ${opts.currency} via wallet card`);
|
|
53190
|
+
printLine(` New expiry: ${expiryDate.toISOString().split("T")[0]}`);
|
|
53067
53191
|
}
|
|
53068
53192
|
} catch (error) {
|
|
53069
|
-
|
|
53193
|
+
printErrorLine(`Wallet renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
53070
53194
|
process.exit(1);
|
|
53071
53195
|
}
|
|
53072
53196
|
});
|
|
@@ -53075,6 +53199,7 @@ var WALLET_MODULE_ENV = "DOMAINS_WALLET_MODULE";
|
|
|
53075
53199
|
var init_wallet = __esm(() => {
|
|
53076
53200
|
init_domains();
|
|
53077
53201
|
init_history();
|
|
53202
|
+
init_stdout();
|
|
53078
53203
|
});
|
|
53079
53204
|
|
|
53080
53205
|
// src/lib/provision-state.ts
|
|
@@ -53249,23 +53374,23 @@ function registerProvisionCommand(program2) {
|
|
|
53249
53374
|
signals["publicNsAreCloudflare"] = false;
|
|
53250
53375
|
}
|
|
53251
53376
|
} catch (e4) {
|
|
53252
|
-
|
|
53377
|
+
printErrorLine(`Error gathering signals: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
53253
53378
|
}
|
|
53254
53379
|
const state = deriveDomainState(signals);
|
|
53255
|
-
|
|
53380
|
+
printLine(`
|
|
53256
53381
|
Domain: ${name}`);
|
|
53257
|
-
|
|
53258
|
-
|
|
53382
|
+
printLine(`State: ${state}`);
|
|
53383
|
+
printLine(`Signals: ${JSON.stringify(signals)}`);
|
|
53259
53384
|
const path = domainHappyPath();
|
|
53260
53385
|
const idx = path.indexOf(state);
|
|
53261
|
-
|
|
53386
|
+
printLine(`Progress: ${idx >= 0 ? idx + 1 : "?"}/${path.length} [${path.join(" \u2192 ")}]`);
|
|
53262
53387
|
});
|
|
53263
53388
|
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
53389
|
const { applyPurchaseProfile: applyPurchaseProfile2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
53265
53390
|
applyPurchaseProfile2();
|
|
53266
53391
|
const { makeDomainDaemonDeps: makeDomainDaemonDeps2 } = await Promise.resolve().then(() => (init_domain_daemon_deps(), exports_domain_daemon_deps));
|
|
53267
53392
|
const { reconcileDomainTick: reconcileDomainTick2, runDomainDaemon: runDomainDaemon2 } = await Promise.resolve().then(() => (init_domain_daemon(), exports_domain_daemon));
|
|
53268
|
-
const deps = { ...makeDomainDaemonDeps2(), log: (e4, d4) =>
|
|
53393
|
+
const deps = { ...makeDomainDaemonDeps2(), log: (e4, d4) => printLine(`[${e4}] ${JSON.stringify(d4)}`) };
|
|
53269
53394
|
const listDomains4 = async () => {
|
|
53270
53395
|
if (opts.domains)
|
|
53271
53396
|
return opts.domains.split(",").map((d4) => d4.trim());
|
|
@@ -53274,16 +53399,16 @@ Domain: ${name}`);
|
|
|
53274
53399
|
};
|
|
53275
53400
|
if (opts.once) {
|
|
53276
53401
|
const s2 = await reconcileDomainTick2(await listDomains4(), deps);
|
|
53277
|
-
|
|
53402
|
+
printLine(`\u2713 tick: ${s2.advanced} advanced, ${s2.ready} ready, ${s2.errors} errors (${s2.processed} processed)`);
|
|
53278
53403
|
return;
|
|
53279
53404
|
}
|
|
53280
|
-
|
|
53405
|
+
printLine(`Domain provisioning daemon started (interval ${opts.interval}s). Ctrl-C to stop.`);
|
|
53281
53406
|
const total = await runDomainDaemon2(listDomains4, {
|
|
53282
53407
|
...deps,
|
|
53283
53408
|
intervalSec: parseInt(opts.interval, 10),
|
|
53284
53409
|
maxTicks: opts.maxTicks ? parseInt(opts.maxTicks, 10) : undefined
|
|
53285
53410
|
});
|
|
53286
|
-
|
|
53411
|
+
printLine(`daemon stopped: ${total.advanced} advanced, ${total.ready} ready, ${total.errors} errors`);
|
|
53287
53412
|
});
|
|
53288
53413
|
}
|
|
53289
53414
|
var CF_NS_SUFFIX2 = ".ns.cloudflare.com";
|
|
@@ -53291,6 +53416,7 @@ var init_provision = __esm(() => {
|
|
|
53291
53416
|
init_provision_state();
|
|
53292
53417
|
init_route53();
|
|
53293
53418
|
init_cloudflare();
|
|
53419
|
+
init_stdout();
|
|
53294
53420
|
});
|
|
53295
53421
|
|
|
53296
53422
|
// src/cli/tui/format.ts
|
|
@@ -54012,10 +54138,12 @@ __export(exports_interactive, {
|
|
|
54012
54138
|
import chalk from "chalk";
|
|
54013
54139
|
import { render } from "ink";
|
|
54014
54140
|
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
54015
|
-
function assertInteractiveTty() {
|
|
54141
|
+
function assertInteractiveTty(emit = (line) => {
|
|
54142
|
+
printErrorLine(line);
|
|
54143
|
+
}) {
|
|
54016
54144
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
54017
|
-
|
|
54018
|
-
|
|
54145
|
+
emit(chalk.red("Interactive mode requires a TTY terminal."));
|
|
54146
|
+
emit(chalk.dim("Use `domains domain list` or `domains domain get <name>` for non-interactive use."));
|
|
54019
54147
|
process.exit(1);
|
|
54020
54148
|
}
|
|
54021
54149
|
}
|
|
@@ -54029,6 +54157,7 @@ function registerInteractiveCommand(program2) {
|
|
|
54029
54157
|
}
|
|
54030
54158
|
var init_interactive = __esm(() => {
|
|
54031
54159
|
init_App();
|
|
54160
|
+
init_stdout();
|
|
54032
54161
|
});
|
|
54033
54162
|
|
|
54034
54163
|
// node_modules/@hasna/events/dist/commander.js
|
|
@@ -55589,6 +55718,7 @@ function getCapability(name) {
|
|
|
55589
55718
|
}
|
|
55590
55719
|
|
|
55591
55720
|
// src/cli/commands/domain.ts
|
|
55721
|
+
init_stdout();
|
|
55592
55722
|
var DOMAIN_STATUS_HELP = DOMAIN_STATUSES.join("/");
|
|
55593
55723
|
var DOMAIN_OFFER_STATUS_HELP = DOMAIN_OFFER_STATUSES.join("/");
|
|
55594
55724
|
var DOMAIN_EMAIL_TYPE_HELP = DOMAIN_EMAIL_TYPES.join("/");
|
|
@@ -55615,7 +55745,7 @@ async function createDnsZoneForProvider(domain, provider) {
|
|
|
55615
55745
|
async function requireDomain(identifier) {
|
|
55616
55746
|
const details = await getDomainDetails2(identifier);
|
|
55617
55747
|
if (!details) {
|
|
55618
|
-
|
|
55748
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
55619
55749
|
process.exit(1);
|
|
55620
55750
|
}
|
|
55621
55751
|
return details;
|
|
@@ -55631,7 +55761,7 @@ function registerDomainCommand(program2) {
|
|
|
55631
55761
|
jsonLimit = opts.limit === undefined ? undefined : parseLimit(opts.limit, undefined, Infinity);
|
|
55632
55762
|
offset = parseOffset(opts.offset);
|
|
55633
55763
|
} catch (error) {
|
|
55634
|
-
|
|
55764
|
+
printErrorLine(error instanceof Error ? error.message : String(error));
|
|
55635
55765
|
process.exit(1);
|
|
55636
55766
|
}
|
|
55637
55767
|
const filters = {
|
|
@@ -55648,7 +55778,7 @@ function registerDomainCommand(program2) {
|
|
|
55648
55778
|
fallbackLimit: Infinity,
|
|
55649
55779
|
maxLimit: Infinity
|
|
55650
55780
|
});
|
|
55651
|
-
|
|
55781
|
+
printLine(JSON.stringify({
|
|
55652
55782
|
domains: jsonPage.items,
|
|
55653
55783
|
count: jsonPage.shown,
|
|
55654
55784
|
total: jsonPage.total,
|
|
@@ -55661,7 +55791,7 @@ function registerDomainCommand(program2) {
|
|
|
55661
55791
|
}
|
|
55662
55792
|
const page = pageItemsOrExit(domains, { limit, offset, all: opts.all });
|
|
55663
55793
|
if (page.items.length === 0) {
|
|
55664
|
-
|
|
55794
|
+
printLine("No domains found.");
|
|
55665
55795
|
return;
|
|
55666
55796
|
}
|
|
55667
55797
|
for (const d4 of page.items) {
|
|
@@ -55670,47 +55800,47 @@ function registerDomainCommand(program2) {
|
|
|
55670
55800
|
if (opts.verbose) {
|
|
55671
55801
|
const registrar = d4.registrar ? ` reg:${truncateText(d4.registrar, 24)}` : "";
|
|
55672
55802
|
const notes = d4.notes ? ` notes:${truncateText(d4.notes, 60)}` : "";
|
|
55673
|
-
|
|
55803
|
+
printLine(` ${d4.name} [${d4.status}]${registrar}${exp}${premium}${notes}`);
|
|
55674
55804
|
} else {
|
|
55675
|
-
|
|
55805
|
+
printLine(` ${d4.name} [${d4.status}]${exp}${premium}`);
|
|
55676
55806
|
}
|
|
55677
55807
|
}
|
|
55678
|
-
|
|
55808
|
+
printLine(`
|
|
55679
55809
|
${compactHint(page, "domain(s)", "Use --verbose for registrar/notes or domain get <id|name> for details.")}`);
|
|
55680
55810
|
});
|
|
55681
55811
|
domain.command("get <identifier>").description("Get a domain by ID or name").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
55682
55812
|
const details = await getDomainDetails2(identifier);
|
|
55683
55813
|
if (!details) {
|
|
55684
|
-
|
|
55814
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
55685
55815
|
process.exit(1);
|
|
55686
55816
|
}
|
|
55687
55817
|
if (opts.json) {
|
|
55688
|
-
|
|
55818
|
+
printLine(JSON.stringify(details, null, 2));
|
|
55689
55819
|
return;
|
|
55690
55820
|
}
|
|
55691
55821
|
const d4 = details.domain;
|
|
55692
|
-
|
|
55822
|
+
printLine(`
|
|
55693
55823
|
${d4.name} [${d4.status}]`);
|
|
55694
55824
|
if (d4.registrar)
|
|
55695
|
-
|
|
55825
|
+
printLine(` Registrar: ${d4.registrar}`);
|
|
55696
55826
|
if (d4.expires_at)
|
|
55697
|
-
|
|
55827
|
+
printLine(` Expires: ${formatDate(d4.expires_at)}`);
|
|
55698
55828
|
if (d4.purchase_date)
|
|
55699
|
-
|
|
55829
|
+
printLine(` Purchased: ${formatDate(d4.purchase_date)}`);
|
|
55700
55830
|
if (d4.purchase_price !== null)
|
|
55701
|
-
|
|
55702
|
-
|
|
55831
|
+
printLine(` Purchase price: ${d4.purchase_price}`);
|
|
55832
|
+
printLine(` Auto-renew: ${d4.auto_renew ? "yes" : "no"}`);
|
|
55703
55833
|
if (d4.is_premium) {
|
|
55704
|
-
|
|
55834
|
+
printLine(` Premium: yes`);
|
|
55705
55835
|
if (d4.premium_price !== null)
|
|
55706
|
-
|
|
55836
|
+
printLine(` Premium ask: ${d4.premium_price}`);
|
|
55707
55837
|
}
|
|
55708
55838
|
if (d4.standard_price !== null)
|
|
55709
|
-
|
|
55839
|
+
printLine(` Standard price: ${d4.standard_price}`);
|
|
55710
55840
|
if (d4.notes)
|
|
55711
|
-
|
|
55841
|
+
printLine(` Notes: ${truncateText(d4.notes, 160)}`);
|
|
55712
55842
|
if (details.offers.length > 0) {
|
|
55713
|
-
|
|
55843
|
+
printLine(`
|
|
55714
55844
|
Offers:`);
|
|
55715
55845
|
const offerPage = pageItemsOrExit(details.offers, { fallbackLimit: 5 });
|
|
55716
55846
|
for (const offer of offerPage.items) {
|
|
@@ -55721,23 +55851,23 @@ Offers:`);
|
|
|
55721
55851
|
offer.their_ask !== null ? `their=${offer.their_ask}` : null,
|
|
55722
55852
|
offer.notes
|
|
55723
55853
|
].filter(Boolean);
|
|
55724
|
-
|
|
55854
|
+
printLine(` - ${parts.join(" | ")}`);
|
|
55725
55855
|
}
|
|
55726
55856
|
if (offerPage.hasMore)
|
|
55727
|
-
|
|
55857
|
+
printLine(` ${compactHint(offerPage, "offer(s)", "Use --json for the full offer history.", { paging: "none" })}`);
|
|
55728
55858
|
}
|
|
55729
55859
|
if (details.emails.length > 0) {
|
|
55730
|
-
|
|
55860
|
+
printLine(`
|
|
55731
55861
|
Emails:`);
|
|
55732
55862
|
const emailPage = pageItemsOrExit(details.emails, { fallbackLimit: 5 });
|
|
55733
55863
|
for (const email of emailPage.items) {
|
|
55734
55864
|
const threadPart = email.thread_id ? ` thread=${email.thread_id}` : "";
|
|
55735
|
-
|
|
55865
|
+
printLine(` - ${email.type}: ${email.email_id}${threadPart}`);
|
|
55736
55866
|
}
|
|
55737
55867
|
if (emailPage.hasMore)
|
|
55738
|
-
|
|
55868
|
+
printLine(` ${compactHint(emailPage, "email link(s)", "Use --json for the full email list.", { paging: "none" })}`);
|
|
55739
55869
|
}
|
|
55740
|
-
|
|
55870
|
+
printLine();
|
|
55741
55871
|
});
|
|
55742
55872
|
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
55873
|
const premiumPrice = parseOptionalNumber(opts.premiumPrice, "--premium-price");
|
|
@@ -55756,10 +55886,10 @@ Emails:`);
|
|
|
55756
55886
|
notes: opts.notes
|
|
55757
55887
|
});
|
|
55758
55888
|
if (opts.json) {
|
|
55759
|
-
|
|
55889
|
+
printLine(JSON.stringify(d4, null, 2));
|
|
55760
55890
|
return;
|
|
55761
55891
|
}
|
|
55762
|
-
|
|
55892
|
+
printLine(`Created domain: ${d4.name} (${d4.id})`);
|
|
55763
55893
|
});
|
|
55764
55894
|
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
55895
|
const premiumPrice = parseOptionalNumber(opts.premiumPrice, "--premium-price");
|
|
@@ -55777,23 +55907,23 @@ Emails:`);
|
|
|
55777
55907
|
notes: opts.notes
|
|
55778
55908
|
});
|
|
55779
55909
|
if (!d4) {
|
|
55780
|
-
|
|
55910
|
+
printErrorLine(`Domain '${id}' not found.`);
|
|
55781
55911
|
process.exit(1);
|
|
55782
55912
|
}
|
|
55783
55913
|
if (opts.json) {
|
|
55784
|
-
|
|
55914
|
+
printLine(JSON.stringify(d4, null, 2));
|
|
55785
55915
|
return;
|
|
55786
55916
|
}
|
|
55787
|
-
|
|
55917
|
+
printLine(`Updated: ${d4.name}`);
|
|
55788
55918
|
});
|
|
55789
55919
|
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
55920
|
if (!opts.force) {
|
|
55791
55921
|
const message = `Refusing to delete domain '${id}' without --force.`;
|
|
55792
55922
|
if (opts.json) {
|
|
55793
|
-
|
|
55923
|
+
printLine(JSON.stringify({ deleted: false, id, error: message }, null, 2));
|
|
55794
55924
|
} else {
|
|
55795
|
-
|
|
55796
|
-
|
|
55925
|
+
printErrorLine(message);
|
|
55926
|
+
printErrorLine("Re-run with --force to confirm deletion.");
|
|
55797
55927
|
}
|
|
55798
55928
|
process.exit(1);
|
|
55799
55929
|
}
|
|
@@ -55801,105 +55931,105 @@ Emails:`);
|
|
|
55801
55931
|
if (!deleted) {
|
|
55802
55932
|
const message = `Domain '${id}' not found.`;
|
|
55803
55933
|
if (opts.json) {
|
|
55804
|
-
|
|
55934
|
+
printLine(JSON.stringify({ deleted: false, id, error: message }, null, 2));
|
|
55805
55935
|
} else {
|
|
55806
|
-
|
|
55936
|
+
printErrorLine(message);
|
|
55807
55937
|
}
|
|
55808
55938
|
process.exit(1);
|
|
55809
55939
|
}
|
|
55810
55940
|
if (opts.json) {
|
|
55811
|
-
|
|
55941
|
+
printLine(JSON.stringify({ deleted: true, id }, null, 2));
|
|
55812
55942
|
return;
|
|
55813
55943
|
}
|
|
55814
|
-
|
|
55944
|
+
printLine(`Deleted domain ${id}`);
|
|
55815
55945
|
});
|
|
55816
55946
|
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
55947
|
const results = await searchDomains2(query);
|
|
55818
55948
|
if (opts.json) {
|
|
55819
|
-
|
|
55949
|
+
printLine(JSON.stringify({ results, count: results.length }, null, 2));
|
|
55820
55950
|
return;
|
|
55821
55951
|
}
|
|
55822
55952
|
let page;
|
|
55823
55953
|
try {
|
|
55824
55954
|
page = pageItemsOrExit(results, { limit: opts.limit, offset: opts.offset, all: opts.all });
|
|
55825
55955
|
} catch (error) {
|
|
55826
|
-
|
|
55956
|
+
printErrorLine(error instanceof Error ? error.message : String(error));
|
|
55827
55957
|
process.exit(1);
|
|
55828
55958
|
}
|
|
55829
55959
|
for (const d4 of page.items) {
|
|
55830
55960
|
const notes = opts.verbose && d4.notes ? ` \u2014 ${truncateText(d4.notes, 80)}` : "";
|
|
55831
|
-
|
|
55961
|
+
printLine(` ${d4.name} [${d4.status}]${notes}`);
|
|
55832
55962
|
}
|
|
55833
55963
|
if (results.length === 0)
|
|
55834
|
-
|
|
55964
|
+
printLine("No results.");
|
|
55835
55965
|
else
|
|
55836
|
-
|
|
55966
|
+
printLine(`
|
|
55837
55967
|
${compactHint(page, "result(s)", "Use --verbose for notes or domain get <id|name> for details.")}`);
|
|
55838
55968
|
});
|
|
55839
55969
|
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
55970
|
const domains = await listExpiring2(parseInt(opts.days));
|
|
55841
55971
|
if (opts.json) {
|
|
55842
|
-
|
|
55972
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
55843
55973
|
return;
|
|
55844
55974
|
}
|
|
55845
55975
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
55846
55976
|
if (page.items.length === 0) {
|
|
55847
|
-
|
|
55977
|
+
printLine(`No domains expiring within ${opts.days} days.`);
|
|
55848
55978
|
return;
|
|
55849
55979
|
}
|
|
55850
|
-
|
|
55980
|
+
printLine(`
|
|
55851
55981
|
Expiring within ${opts.days} days:`);
|
|
55852
55982
|
for (const d4 of page.items)
|
|
55853
|
-
|
|
55854
|
-
|
|
55983
|
+
printLine(` ${d4.name.padEnd(40)} expires ${formatDate(d4.expires_at)}`);
|
|
55984
|
+
printLine(`
|
|
55855
55985
|
${compactHint(page, "domain(s)", "Use --all to display every expiring domain.", { paging: "limit" })}`);
|
|
55856
55986
|
});
|
|
55857
55987
|
domain.command("stats").description("Show portfolio statistics").option("-j, --json", "Output JSON").action(async (opts) => {
|
|
55858
55988
|
const stats = await getDomainStats2();
|
|
55859
55989
|
if (opts.json) {
|
|
55860
|
-
|
|
55990
|
+
printLine(JSON.stringify(stats, null, 2));
|
|
55861
55991
|
return;
|
|
55862
55992
|
}
|
|
55863
|
-
|
|
55993
|
+
printLine("Domain Portfolio Stats:");
|
|
55864
55994
|
for (const [k4, v2] of Object.entries(stats)) {
|
|
55865
|
-
|
|
55995
|
+
printLine(` ${k4.replace(/_/g, " ")}: ${v2}`);
|
|
55866
55996
|
}
|
|
55867
55997
|
});
|
|
55868
55998
|
domain.command("whois <name>").description("Run WHOIS lookup and update local DB record").option("-j, --json", "Output JSON").action(async (name, opts) => {
|
|
55869
55999
|
try {
|
|
55870
56000
|
const result = await whoisLookup(name);
|
|
55871
56001
|
if (opts.json) {
|
|
55872
|
-
|
|
56002
|
+
printLine(JSON.stringify(result, null, 2));
|
|
55873
56003
|
return;
|
|
55874
56004
|
}
|
|
55875
|
-
|
|
56005
|
+
printLine(`
|
|
55876
56006
|
WHOIS for ${result.domain} [${result.source}]:`);
|
|
55877
|
-
|
|
55878
|
-
|
|
56007
|
+
printLine(` Registrar: ${result.registrar ?? "unknown"}`);
|
|
56008
|
+
printLine(` Expires: ${result.expires_at ?? "unknown"}`);
|
|
55879
56009
|
if (result.nameservers.length) {
|
|
55880
|
-
|
|
56010
|
+
printLine(` NS: ${result.nameservers.join(", ")}`);
|
|
55881
56011
|
}
|
|
55882
56012
|
const r4 = result.registrant;
|
|
55883
56013
|
if (r4?.name || r4?.email || r4?.organization) {
|
|
55884
|
-
|
|
56014
|
+
printLine(` Registrant:`);
|
|
55885
56015
|
if (r4.name)
|
|
55886
|
-
|
|
56016
|
+
printLine(` Name: ${r4.name}`);
|
|
55887
56017
|
if (r4.email)
|
|
55888
|
-
|
|
56018
|
+
printLine(` Email: ${r4.email}`);
|
|
55889
56019
|
if (r4.phone)
|
|
55890
|
-
|
|
56020
|
+
printLine(` Phone: ${r4.phone}`);
|
|
55891
56021
|
if (r4.organization)
|
|
55892
|
-
|
|
56022
|
+
printLine(` Org: ${r4.organization}`);
|
|
55893
56023
|
}
|
|
55894
|
-
|
|
56024
|
+
printLine();
|
|
55895
56025
|
} catch (error) {
|
|
55896
|
-
|
|
56026
|
+
printErrorLine(`WHOIS lookup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
55897
56027
|
process.exit(1);
|
|
55898
56028
|
}
|
|
55899
56029
|
});
|
|
55900
56030
|
domain.command("export").description("Export all domains as CSV or JSON").option("--format <fmt>", "Format: csv or json", "json").action(async (opts) => {
|
|
55901
56031
|
const output = await exportPortfolio(opts.format);
|
|
55902
|
-
|
|
56032
|
+
printLine(output);
|
|
55903
56033
|
});
|
|
55904
56034
|
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
56035
|
const cfg = loadConfig3();
|
|
@@ -55917,19 +56047,19 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55917
56047
|
const error = reason instanceof Error ? reason.message : String(reason);
|
|
55918
56048
|
output.push({ domain: domains[i4], error });
|
|
55919
56049
|
if (!opts.json) {
|
|
55920
|
-
|
|
56050
|
+
printErrorLine(`\u2717 ${domains[i4]}: ${error}`);
|
|
55921
56051
|
}
|
|
55922
56052
|
anyError = true;
|
|
55923
56053
|
} else {
|
|
55924
56054
|
const result = r4.value;
|
|
55925
56055
|
output.push({ domain: result.domain, available: result.available });
|
|
55926
56056
|
if (!opts.json) {
|
|
55927
|
-
|
|
56057
|
+
printLine(`${result.available ? "\u2713" : "\u2717"} ${result.domain} is ${result.available ? "available" : "not available"}`);
|
|
55928
56058
|
}
|
|
55929
56059
|
}
|
|
55930
56060
|
}
|
|
55931
56061
|
if (opts.json) {
|
|
55932
|
-
|
|
56062
|
+
printLine(JSON.stringify({
|
|
55933
56063
|
provider: providerName,
|
|
55934
56064
|
count: output.length,
|
|
55935
56065
|
ok: !anyError,
|
|
@@ -55938,11 +56068,11 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55938
56068
|
} else {
|
|
55939
56069
|
for (const result of output) {
|
|
55940
56070
|
if (result.available !== undefined && "is_premium" in result && result.is_premium) {
|
|
55941
|
-
|
|
56071
|
+
printLine(` Premium ask: ${result.premium_price ?? "unknown"}`);
|
|
55942
56072
|
}
|
|
55943
56073
|
if ("standard_price" in result && result.standard_price !== undefined) {
|
|
55944
56074
|
const currency = "currency" in result && result.currency ? ` ${result.currency}` : "";
|
|
55945
|
-
|
|
56075
|
+
printLine(` Standard price: ${result.standard_price}${currency}`);
|
|
55946
56076
|
}
|
|
55947
56077
|
}
|
|
55948
56078
|
}
|
|
@@ -55968,11 +56098,11 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55968
56098
|
try {
|
|
55969
56099
|
const provider = getDomainInventoryProvider(name);
|
|
55970
56100
|
const result = await provider.syncToLocalDb({ getDomainByName: getDomainByName2, createDomain: createDomain2, updateDomain: updateDomain2 });
|
|
55971
|
-
|
|
56101
|
+
printLine(`\u2713 [${name}] Synced ${result.synced} (${result.created} new, ${result.updated} updated)`);
|
|
55972
56102
|
if (result.errors.length > 0)
|
|
55973
|
-
|
|
56103
|
+
printLine(` Errors: ${result.errors.join(", ")}`);
|
|
55974
56104
|
} catch (e4) {
|
|
55975
|
-
|
|
56105
|
+
printErrorLine(`\u2717 [${name}] ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
55976
56106
|
}
|
|
55977
56107
|
}
|
|
55978
56108
|
});
|
|
@@ -55981,14 +56111,14 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
55981
56111
|
const standardPrice = parseOptionalNumber(opts.standard, "--standard");
|
|
55982
56112
|
const updated = await markDomainPremium2(identifier, premiumPrice, standardPrice);
|
|
55983
56113
|
if (!updated) {
|
|
55984
|
-
|
|
56114
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
55985
56115
|
process.exit(1);
|
|
55986
56116
|
}
|
|
55987
56117
|
if (opts.json) {
|
|
55988
|
-
|
|
56118
|
+
printLine(JSON.stringify(updated, null, 2));
|
|
55989
56119
|
return;
|
|
55990
56120
|
}
|
|
55991
|
-
|
|
56121
|
+
printLine(`Marked ${updated.name} as premium at ${premiumPrice}`);
|
|
55992
56122
|
});
|
|
55993
56123
|
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
56124
|
const details = await requireDomain(identifier);
|
|
@@ -56003,37 +56133,37 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56003
56133
|
await updateDomainLifecycleStatus2(details.domain.id, opts.their || opts.our ? "negotiating" : "offered");
|
|
56004
56134
|
}
|
|
56005
56135
|
if (opts.json) {
|
|
56006
|
-
|
|
56136
|
+
printLine(JSON.stringify(offer, null, 2));
|
|
56007
56137
|
return;
|
|
56008
56138
|
}
|
|
56009
|
-
|
|
56139
|
+
printLine(`Logged offer for ${details.domain.name}: ${offer.status}`);
|
|
56010
56140
|
});
|
|
56011
56141
|
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
56142
|
const updated = await updateDomainLifecycleStatus2(identifier, status, opts.notes);
|
|
56013
56143
|
if (!updated) {
|
|
56014
|
-
|
|
56144
|
+
printErrorLine(`Domain '${identifier}' not found.`);
|
|
56015
56145
|
process.exit(1);
|
|
56016
56146
|
}
|
|
56017
56147
|
if (opts.json) {
|
|
56018
|
-
|
|
56148
|
+
printLine(JSON.stringify(updated, null, 2));
|
|
56019
56149
|
return;
|
|
56020
56150
|
}
|
|
56021
|
-
|
|
56151
|
+
printLine(`Updated ${updated.name} to ${updated.status}`);
|
|
56022
56152
|
});
|
|
56023
56153
|
domain.command("emails <identifier>").description("Show email threads linked to a domain").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
|
|
56024
56154
|
const details = await requireDomain(identifier);
|
|
56025
56155
|
const emails = await listDomainEmailLinks2(details.domain.id);
|
|
56026
56156
|
if (opts.json) {
|
|
56027
|
-
|
|
56157
|
+
printLine(JSON.stringify({ domain: details.domain.name, emails, count: emails.length }, null, 2));
|
|
56028
56158
|
return;
|
|
56029
56159
|
}
|
|
56030
56160
|
if (emails.length === 0) {
|
|
56031
|
-
|
|
56161
|
+
printLine(`No linked emails for ${details.domain.name}.`);
|
|
56032
56162
|
return;
|
|
56033
56163
|
}
|
|
56034
56164
|
for (const email of emails) {
|
|
56035
56165
|
const threadPart = email.thread_id ? ` (${email.thread_id})` : "";
|
|
56036
|
-
|
|
56166
|
+
printLine(` ${email.type}: ${email.email_id}${threadPart}`);
|
|
56037
56167
|
}
|
|
56038
56168
|
});
|
|
56039
56169
|
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 +56175,25 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56045
56175
|
type: opts.type
|
|
56046
56176
|
});
|
|
56047
56177
|
if (opts.json) {
|
|
56048
|
-
|
|
56178
|
+
printLine(JSON.stringify(link, null, 2));
|
|
56049
56179
|
return;
|
|
56050
56180
|
}
|
|
56051
|
-
|
|
56181
|
+
printLine(`Linked ${emailId} to ${details.domain.name}`);
|
|
56052
56182
|
});
|
|
56053
56183
|
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
56184
|
const providerName = opts.provider ?? await autoDetectRegistrar(name, getDomainByName2) ?? loadConfig3().default_registrar;
|
|
56055
56185
|
if (!providerName) {
|
|
56056
|
-
|
|
56186
|
+
printErrorLine("Could not detect provider. Use --provider.");
|
|
56057
56187
|
process.exit(1);
|
|
56058
56188
|
}
|
|
56059
56189
|
const provider = getRegistrarProvider(providerName);
|
|
56060
56190
|
const result = await provider.renewDomain(name, parseInt(opts.years, 10));
|
|
56061
56191
|
if (result.success) {
|
|
56062
|
-
|
|
56192
|
+
printLine(`\u2713 Renewed: ${name}`);
|
|
56063
56193
|
if (result.orderId)
|
|
56064
|
-
|
|
56194
|
+
printLine(` Order: ${result.orderId}`);
|
|
56065
56195
|
} else {
|
|
56066
|
-
|
|
56196
|
+
printErrorLine(`\u2717 Renewal failed or not supported for ${providerName}`);
|
|
56067
56197
|
process.exit(1);
|
|
56068
56198
|
}
|
|
56069
56199
|
});
|
|
@@ -56080,13 +56210,13 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56080
56210
|
auto_renew: opts.autoRenew ? opts.autoRenew === "true" : domainRecord.auto_renew
|
|
56081
56211
|
});
|
|
56082
56212
|
if (!purchased) {
|
|
56083
|
-
|
|
56213
|
+
printErrorLine(`Domain '${name}' not found.`);
|
|
56084
56214
|
process.exit(1);
|
|
56085
56215
|
}
|
|
56086
56216
|
if (opts.wait) {
|
|
56087
56217
|
await updateDomainLifecycleStatus2(purchased.id, "active");
|
|
56088
56218
|
}
|
|
56089
|
-
|
|
56219
|
+
printLine(`Recorded purchase for ${purchased.name} at ${recordedPrice}`);
|
|
56090
56220
|
return;
|
|
56091
56221
|
}
|
|
56092
56222
|
const cfg = loadConfig3();
|
|
@@ -56094,44 +56224,44 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56094
56224
|
const dnsProvider = opts.dns ?? cfg.default_dns ?? "cloudflare";
|
|
56095
56225
|
const purchaseProfile = providerName === "route53" ? applyPurchaseProfile() : undefined;
|
|
56096
56226
|
if (purchaseProfile)
|
|
56097
|
-
|
|
56227
|
+
printLine(`Using purchase AWS profile: ${purchaseProfile}`);
|
|
56098
56228
|
if (providerName !== "route53") {
|
|
56099
56229
|
try {
|
|
56100
56230
|
const capability = getCapability(providerName);
|
|
56101
56231
|
if (!capability.canBuy) {
|
|
56102
|
-
|
|
56232
|
+
printErrorLine(`Direct domain purchase is not supported for ${providerName}. ${capability.notes} Use route53 or record a marketplace/manual purchase with --price.`);
|
|
56103
56233
|
process.exit(1);
|
|
56104
56234
|
}
|
|
56105
56235
|
if (capability.gated && !opts.allowGated) {
|
|
56106
|
-
|
|
56236
|
+
printErrorLine(`Registrar '${providerName}' is gated/enterprise-only. Pass --allow-gated only when this account is contract-approved. ${capability.notes}`);
|
|
56107
56237
|
process.exit(1);
|
|
56108
56238
|
}
|
|
56109
56239
|
const provider = getRegistrarProvider(providerName);
|
|
56110
56240
|
if (!provider.registerDomain) {
|
|
56111
|
-
|
|
56241
|
+
printErrorLine(`Direct domain purchase is not supported for ${providerName}. Use route53 or record a marketplace/manual purchase with --price.`);
|
|
56112
56242
|
process.exit(1);
|
|
56113
56243
|
}
|
|
56114
56244
|
const avail = await provider.checkAvailability(name);
|
|
56115
56245
|
if (!avail.available) {
|
|
56116
|
-
|
|
56246
|
+
printErrorLine(`\u2717 ${name} is not available`);
|
|
56117
56247
|
process.exit(1);
|
|
56118
56248
|
}
|
|
56119
|
-
|
|
56249
|
+
printLine(`\u2713 Available via ${providerName}`);
|
|
56120
56250
|
let contact;
|
|
56121
56251
|
try {
|
|
56122
56252
|
contact = resolveContact(opts);
|
|
56123
56253
|
} catch (e4) {
|
|
56124
|
-
|
|
56254
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56125
56255
|
process.exit(1);
|
|
56126
56256
|
}
|
|
56127
|
-
|
|
56257
|
+
printLine(`Registering ${name} via ${providerName}...`);
|
|
56128
56258
|
const reg = await provider.registerDomain(name, contact, {
|
|
56129
56259
|
years: parseInt(opts.years, 10),
|
|
56130
56260
|
premiumPrice: avail.premium_price,
|
|
56131
56261
|
autoRenew: opts.autoRenew ? opts.autoRenew === "true" : true
|
|
56132
56262
|
});
|
|
56133
56263
|
if (!reg.success) {
|
|
56134
|
-
|
|
56264
|
+
printErrorLine(`\u2717 Registration failed via ${providerName}`);
|
|
56135
56265
|
process.exit(1);
|
|
56136
56266
|
}
|
|
56137
56267
|
const existing = await getDomainByName2(name);
|
|
@@ -56149,45 +56279,45 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56149
56279
|
await updateDomain2(existing.id, dbInput);
|
|
56150
56280
|
else
|
|
56151
56281
|
await createDomain2({ name, ...dbInput });
|
|
56152
|
-
|
|
56282
|
+
printLine(`\u2713 Registered and added to portfolio`);
|
|
56153
56283
|
if (reg.orderId)
|
|
56154
|
-
|
|
56284
|
+
printLine(` Order: ${reg.orderId}`);
|
|
56155
56285
|
if (opts.delegate !== false) {
|
|
56156
56286
|
if (!provider.updateNameservers) {
|
|
56157
|
-
|
|
56287
|
+
printLine(` DNS: ${providerName} registration succeeded, but nameserver updates are not implemented for this provider.`);
|
|
56158
56288
|
} else {
|
|
56159
56289
|
const zone = await createDnsZoneForProvider(name, dnsProvider);
|
|
56160
56290
|
const nsUpdate = await provider.updateNameservers(name, zone.nameservers);
|
|
56161
56291
|
const existing2 = await getDomainByName2(name);
|
|
56162
56292
|
if (existing2)
|
|
56163
56293
|
await updateDomain2(existing2.id, { nameservers: zone.nameservers });
|
|
56164
|
-
|
|
56294
|
+
printLine(`\u2713 ${dnsProvider} zone ${zone.zoneId}; nameservers updated${nsUpdate.operationId ? ` (op ${nsUpdate.operationId})` : ""}`);
|
|
56165
56295
|
}
|
|
56166
56296
|
}
|
|
56167
56297
|
return;
|
|
56168
56298
|
} catch (e4) {
|
|
56169
|
-
|
|
56299
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56170
56300
|
process.exit(1);
|
|
56171
56301
|
}
|
|
56172
56302
|
}
|
|
56173
56303
|
try {
|
|
56174
56304
|
const avail = await checkAvailability3(name);
|
|
56175
56305
|
if (!avail.available) {
|
|
56176
|
-
|
|
56306
|
+
printErrorLine(`\u2717 ${name} is not available`);
|
|
56177
56307
|
process.exit(1);
|
|
56178
56308
|
}
|
|
56179
56309
|
const price = avail.price ? ` (USD ${avail.price}/yr)` : "";
|
|
56180
|
-
|
|
56310
|
+
printLine(`\u2713 Available${price}`);
|
|
56181
56311
|
let contact;
|
|
56182
56312
|
try {
|
|
56183
56313
|
contact = resolveContact(opts);
|
|
56184
56314
|
} catch (e4) {
|
|
56185
|
-
|
|
56315
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56186
56316
|
process.exit(1);
|
|
56187
56317
|
}
|
|
56188
|
-
|
|
56318
|
+
printLine(`Registering ${name}...`);
|
|
56189
56319
|
const reg = await registerDomain2(name, contact, parseInt(opts.years));
|
|
56190
|
-
|
|
56320
|
+
printLine(`\u2713 Submitted (operation: ${reg.operationId})`);
|
|
56191
56321
|
if (opts.wait) {
|
|
56192
56322
|
let status = "IN_PROGRESS";
|
|
56193
56323
|
while (status === "IN_PROGRESS" || status === "SUBMITTED") {
|
|
@@ -56196,12 +56326,12 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56196
56326
|
status = s2.status;
|
|
56197
56327
|
process.stdout.write(` Status: ${status}\r`);
|
|
56198
56328
|
}
|
|
56199
|
-
|
|
56329
|
+
printLine();
|
|
56200
56330
|
if (status !== "SUCCESSFUL") {
|
|
56201
|
-
|
|
56331
|
+
printErrorLine(`\u2717 Registration ${status}`);
|
|
56202
56332
|
process.exit(1);
|
|
56203
56333
|
}
|
|
56204
|
-
|
|
56334
|
+
printLine(`\u2713 Registration complete`);
|
|
56205
56335
|
}
|
|
56206
56336
|
const existing = await getDomainByName2(name);
|
|
56207
56337
|
if (existing) {
|
|
@@ -56224,13 +56354,13 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56224
56354
|
standard_price: avail.price ? Number(avail.price) : undefined
|
|
56225
56355
|
});
|
|
56226
56356
|
}
|
|
56227
|
-
|
|
56357
|
+
printLine(`\u2713 Added to portfolio`);
|
|
56228
56358
|
if (opts.delegate !== false) {
|
|
56229
56359
|
if (!opts.wait) {
|
|
56230
|
-
|
|
56360
|
+
printLine(` DNS: run 'domains domain buy ${name} --wait' or delegate later \u2014 registration must finish before NS can change.`);
|
|
56231
56361
|
} else {
|
|
56232
56362
|
try {
|
|
56233
|
-
|
|
56363
|
+
printLine(`Delegating DNS to ${dnsProvider}...`);
|
|
56234
56364
|
const del = dnsProvider === "cloudflare" ? await delegateDomainToCloudflare(name, {
|
|
56235
56365
|
createCloudflareZone: async (d4) => {
|
|
56236
56366
|
const z = await ensureZone(d4);
|
|
@@ -56245,17 +56375,17 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56245
56375
|
const existing2 = await getDomainByName2(name);
|
|
56246
56376
|
if (existing2)
|
|
56247
56377
|
await updateDomain2(existing2.id, { nameservers: del.nameservers });
|
|
56248
|
-
|
|
56378
|
+
printLine(`\u2713 ${dnsProvider} zone ${del.zoneId}; nameservers \u2192 ${del.nameservers.join(", ")} (op ${del.operationId})`);
|
|
56249
56379
|
} catch (e4) {
|
|
56250
|
-
|
|
56251
|
-
|
|
56380
|
+
printErrorLine(`\u26A0 DNS delegation failed (domain is registered): ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56381
|
+
printErrorLine(` Retry: create the DNS zone and point Route53 NS at it.`);
|
|
56252
56382
|
}
|
|
56253
56383
|
}
|
|
56254
56384
|
}
|
|
56255
56385
|
if (!opts.wait)
|
|
56256
|
-
|
|
56386
|
+
printLine(` Check: domains r53 status ${reg.operationId}`);
|
|
56257
56387
|
} catch (e4) {
|
|
56258
|
-
|
|
56388
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56259
56389
|
process.exit(1);
|
|
56260
56390
|
}
|
|
56261
56391
|
});
|
|
@@ -56263,34 +56393,34 @@ WHOIS for ${result.domain} [${result.source}]:`);
|
|
|
56263
56393
|
const cfg = loadConfig3();
|
|
56264
56394
|
const registrarName = opts.registrar ?? cfg.default_registrar ?? "route53";
|
|
56265
56395
|
const dnsName = opts.dns ?? cfg.default_dns ?? "cloudflare";
|
|
56266
|
-
|
|
56396
|
+
printLine(`
|
|
56267
56397
|
Setting up ${name}`);
|
|
56268
|
-
|
|
56398
|
+
printLine(` Registrar: ${registrarName} | DNS: ${dnsName}
|
|
56269
56399
|
`);
|
|
56270
56400
|
try {
|
|
56271
56401
|
process.stdout.write(opts.wait ? "[1/5] Checking availability... " : "[1/4] Checking availability... ");
|
|
56272
56402
|
const avail = await checkAvailability3(name);
|
|
56273
56403
|
if (!avail.available) {
|
|
56274
|
-
|
|
56275
|
-
|
|
56404
|
+
printLine("not available");
|
|
56405
|
+
printErrorLine(`\u2717 ${name} is not available`);
|
|
56276
56406
|
process.exit(1);
|
|
56277
56407
|
}
|
|
56278
56408
|
const price = avail.price ? `(USD ${avail.price}/yr)` : "";
|
|
56279
|
-
|
|
56409
|
+
printLine(`available ${price}`);
|
|
56280
56410
|
if (registrarName !== "route53") {
|
|
56281
|
-
|
|
56411
|
+
printErrorLine("Direct domain purchase currently only supported via route53.");
|
|
56282
56412
|
process.exit(1);
|
|
56283
56413
|
}
|
|
56284
56414
|
let contact;
|
|
56285
56415
|
try {
|
|
56286
56416
|
contact = resolveContact(opts);
|
|
56287
56417
|
} catch (e4) {
|
|
56288
|
-
|
|
56418
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56289
56419
|
process.exit(1);
|
|
56290
56420
|
}
|
|
56291
56421
|
process.stdout.write(opts.wait ? "[2/5] Registering domain... " : "[2/4] Registering domain... ");
|
|
56292
56422
|
const reg = await registerDomain2(name, contact, parseInt(opts.years));
|
|
56293
|
-
|
|
56423
|
+
printLine(`submitted (${reg.operationId})`);
|
|
56294
56424
|
if (opts.wait) {
|
|
56295
56425
|
let status = "IN_PROGRESS";
|
|
56296
56426
|
while (status === "IN_PROGRESS" || status === "SUBMITTED") {
|
|
@@ -56299,36 +56429,36 @@ Setting up ${name}`);
|
|
|
56299
56429
|
status = s2.status;
|
|
56300
56430
|
process.stdout.write(` Waiting: ${status}...\r`);
|
|
56301
56431
|
}
|
|
56302
|
-
|
|
56432
|
+
printLine();
|
|
56303
56433
|
if (status !== "SUCCESSFUL") {
|
|
56304
|
-
|
|
56434
|
+
printErrorLine(`\u2717 Registration ${status}`);
|
|
56305
56435
|
process.exit(1);
|
|
56306
56436
|
}
|
|
56307
|
-
|
|
56437
|
+
printLine(" Registration confirmed");
|
|
56308
56438
|
}
|
|
56309
56439
|
process.stdout.write(opts.wait ? "[3/5] Creating DNS zone... " : "[3/4] Creating DNS zone... ");
|
|
56310
56440
|
let nameservers = [];
|
|
56311
56441
|
if (dnsName === "cloudflare") {
|
|
56312
56442
|
const zone = await ensureZone(name);
|
|
56313
56443
|
nameservers = zone.nameservers ?? [];
|
|
56314
|
-
|
|
56444
|
+
printLine("ready (" + zone.id + ")");
|
|
56315
56445
|
} else {
|
|
56316
56446
|
const zone = await createHostedZone(name, "Managed by domains CLI");
|
|
56317
56447
|
nameservers = zone.name_servers ?? [];
|
|
56318
|
-
|
|
56448
|
+
printLine(`created (${zone.id})`);
|
|
56319
56449
|
}
|
|
56320
56450
|
if (nameservers.length > 0) {
|
|
56321
56451
|
if (opts.wait) {
|
|
56322
56452
|
process.stdout.write("[4/5] Updating registrar nameservers... ");
|
|
56323
56453
|
if (registrarName !== "route53") {
|
|
56324
|
-
|
|
56325
|
-
|
|
56454
|
+
printLine("skipped");
|
|
56455
|
+
printErrorLine("Only Route53 nameserver delegation is currently implemented for setup.");
|
|
56326
56456
|
process.exit(1);
|
|
56327
56457
|
}
|
|
56328
56458
|
const nsUpdate = await updateNameservers2(name, nameservers);
|
|
56329
|
-
|
|
56459
|
+
printLine("submitted (" + nsUpdate.operationId + ")");
|
|
56330
56460
|
} else {
|
|
56331
|
-
|
|
56461
|
+
printLine(" Nameserver delegation skipped until registration completes; re-run with --wait or use domains r53 domain-info/status first.");
|
|
56332
56462
|
}
|
|
56333
56463
|
}
|
|
56334
56464
|
process.stdout.write(opts.wait ? "[5/5] Adding to portfolio... " : "[4/4] Adding to portfolio... ");
|
|
@@ -56338,22 +56468,22 @@ Setting up ${name}`);
|
|
|
56338
56468
|
await updateDomain2(existing.id, dbInput);
|
|
56339
56469
|
else
|
|
56340
56470
|
await createDomain2({ name, ...dbInput });
|
|
56341
|
-
|
|
56342
|
-
|
|
56471
|
+
printLine("done");
|
|
56472
|
+
printLine(`
|
|
56343
56473
|
\u2713 Setup complete for ${name}`);
|
|
56344
56474
|
if (!opts.wait) {
|
|
56345
|
-
|
|
56346
|
-
|
|
56475
|
+
printLine(` \u26A0 Registration pending \u2014 check: domains r53 status ${reg.operationId}`);
|
|
56476
|
+
printLine(` \u26A0 If registration fails, clean up: domains zone delete <zoneId> --force`);
|
|
56347
56477
|
}
|
|
56348
56478
|
if (nameservers.length > 0) {
|
|
56349
|
-
|
|
56479
|
+
printLine(`
|
|
56350
56480
|
Point your registrar to these name servers:`);
|
|
56351
56481
|
for (const ns of nameservers)
|
|
56352
|
-
|
|
56482
|
+
printLine(` ${ns}`);
|
|
56353
56483
|
}
|
|
56354
|
-
|
|
56484
|
+
printLine();
|
|
56355
56485
|
} catch (e4) {
|
|
56356
|
-
|
|
56486
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56357
56487
|
process.exit(1);
|
|
56358
56488
|
}
|
|
56359
56489
|
});
|
|
@@ -56378,13 +56508,16 @@ function normalizeDnsRecord(record, domain) {
|
|
|
56378
56508
|
} else if (lowerName.endsWith(`.${normalizedDomain}`)) {
|
|
56379
56509
|
name = name.replace(/\.$/, "").slice(0, -(normalizedDomain.length + 1));
|
|
56380
56510
|
}
|
|
56381
|
-
|
|
56511
|
+
const normalized = {
|
|
56382
56512
|
type,
|
|
56383
56513
|
name,
|
|
56384
56514
|
value: String(record.value).trim(),
|
|
56385
56515
|
ttl: Number.isFinite(record.ttl) && record.ttl > 0 ? Math.trunc(record.ttl) : 300,
|
|
56386
56516
|
priority: record.priority
|
|
56387
56517
|
};
|
|
56518
|
+
if (record.proxied !== undefined)
|
|
56519
|
+
normalized.proxied = record.proxied;
|
|
56520
|
+
return normalized;
|
|
56388
56521
|
}
|
|
56389
56522
|
function parseDesiredDnsState(input, domainHint) {
|
|
56390
56523
|
let parsed;
|
|
@@ -56415,7 +56548,8 @@ function parseDesiredDnsState(input, domainHint) {
|
|
|
56415
56548
|
name: r4["name"],
|
|
56416
56549
|
value: r4["value"],
|
|
56417
56550
|
ttl: typeof r4["ttl"] === "number" ? r4["ttl"] : Number(r4["ttl"] ?? 300),
|
|
56418
|
-
priority: r4["priority"] == null ? undefined : Number(r4["priority"])
|
|
56551
|
+
priority: r4["priority"] == null ? undefined : Number(r4["priority"]),
|
|
56552
|
+
proxied: typeof r4["proxied"] === "boolean" ? r4["proxied"] : undefined
|
|
56419
56553
|
}, domain);
|
|
56420
56554
|
})
|
|
56421
56555
|
};
|
|
@@ -56424,7 +56558,7 @@ function identity(record) {
|
|
|
56424
56558
|
return [record.type, record.name, record.value, record.priority ?? ""].join("\x00");
|
|
56425
56559
|
}
|
|
56426
56560
|
function sameMutableFields(a4, b4) {
|
|
56427
|
-
return a4.ttl === b4.ttl;
|
|
56561
|
+
return a4.ttl === b4.ttl && (b4.proxied === undefined || a4.proxied === b4.proxied);
|
|
56428
56562
|
}
|
|
56429
56563
|
function createDnsPlan(domain, current, desired) {
|
|
56430
56564
|
const normalizedCurrent = current.map((record) => normalizeDnsRecord(record, domain));
|
|
@@ -56459,6 +56593,13 @@ function createDnsPlan(domain, current, desired) {
|
|
|
56459
56593
|
function planHasChanges(plan) {
|
|
56460
56594
|
return plan.creates + plan.updates + plan.deletes > 0;
|
|
56461
56595
|
}
|
|
56596
|
+
function dnsRecordGroupKey(record) {
|
|
56597
|
+
return `${record.type}\x00${record.name}`;
|
|
56598
|
+
}
|
|
56599
|
+
function selectChangedDnsRecords(plan, desired) {
|
|
56600
|
+
const changedGroups = new Set(plan.operations.filter((operation) => operation.op !== "unchanged").map((operation) => dnsRecordGroupKey(operation.record)));
|
|
56601
|
+
return desired.filter((record) => changedGroups.has(dnsRecordGroupKey(normalizeDnsRecord(record, plan.domain))));
|
|
56602
|
+
}
|
|
56462
56603
|
function getDnsApplyBlockReason(plan, opts) {
|
|
56463
56604
|
if (!planHasChanges(plan))
|
|
56464
56605
|
return;
|
|
@@ -56472,6 +56613,7 @@ function getDnsApplyBlockReason(plan, opts) {
|
|
|
56472
56613
|
}
|
|
56473
56614
|
|
|
56474
56615
|
// src/cli/commands/dns.ts
|
|
56616
|
+
init_stdout();
|
|
56475
56617
|
var SUPPORTED_DNS_TYPES = new Set(["A", "AAAA", "CNAME", "MX", "TXT", "NS", "SRV"]);
|
|
56476
56618
|
function partitionPullableRecords(records) {
|
|
56477
56619
|
const keep = [];
|
|
@@ -56486,49 +56628,50 @@ function partitionPullableRecords(records) {
|
|
|
56486
56628
|
return { keep, skipped };
|
|
56487
56629
|
}
|
|
56488
56630
|
function printDnsPlan(plan) {
|
|
56489
|
-
|
|
56631
|
+
printLine(`DNS plan for ${plan.domain}: ${plan.creates} create, ${plan.updates} update, ${plan.deletes} delete, ${plan.unchanged} unchanged`);
|
|
56490
56632
|
for (const op of plan.operations) {
|
|
56491
56633
|
if (op.op === "unchanged")
|
|
56492
56634
|
continue;
|
|
56493
56635
|
const priority = op.record.priority == null ? "" : ` priority=${op.record.priority}`;
|
|
56494
56636
|
const currentTtl = op.current && op.current.ttl !== op.record.ttl ? ` ttl ${op.current.ttl}->${op.record.ttl}` : "";
|
|
56495
|
-
|
|
56637
|
+
printLine(` ${op.op.toUpperCase()} ${op.record.type} ${op.record.name} ${op.record.value} ttl=${op.record.ttl}${priority}${currentTtl}`);
|
|
56496
56638
|
}
|
|
56497
56639
|
}
|
|
56498
|
-
async function loadDnsPlan(domain, providerName, file) {
|
|
56640
|
+
async function loadDnsPlan(domain, providerName, file, resolveDnsProvider = getDnsProvider) {
|
|
56499
56641
|
const desired = parseDesiredDnsState(readFileSync4(file, "utf-8"), domain);
|
|
56500
56642
|
const planDomain = desired.domain ?? domain;
|
|
56501
|
-
const provider =
|
|
56643
|
+
const provider = resolveDnsProvider(providerName);
|
|
56502
56644
|
const current = await provider.getDnsRecords(planDomain);
|
|
56503
56645
|
return createDnsPlan(planDomain, current, desired.records);
|
|
56504
56646
|
}
|
|
56505
|
-
function registerDnsCommands(program2) {
|
|
56647
|
+
function registerDnsCommands(program2, deps = {}) {
|
|
56648
|
+
const resolveDnsProvider = deps.getDnsProvider ?? getDnsProvider;
|
|
56506
56649
|
const dnsCmd = program2.command("dns").description("DNS record management");
|
|
56507
56650
|
dnsCmd.command("plan <domain>").description("Preview desired DNS state changes from a JSON file without mutating provider records").requiredOption("--file <path>", "Desired DNS state JSON file").option("--provider <name>", "DNS provider \u2014 defaults to config default-dns").option("--json", "Output as JSON", false).action(async (domain, opts) => {
|
|
56508
56651
|
const providerName = opts.provider ?? loadConfig3().default_dns ?? "route53";
|
|
56509
56652
|
try {
|
|
56510
|
-
const plan = await loadDnsPlan(domain, providerName, opts.file);
|
|
56653
|
+
const plan = await loadDnsPlan(domain, providerName, opts.file, resolveDnsProvider);
|
|
56511
56654
|
if (opts.json)
|
|
56512
|
-
|
|
56655
|
+
printLine(JSON.stringify(plan, null, 2));
|
|
56513
56656
|
else
|
|
56514
56657
|
printDnsPlan(plan);
|
|
56515
56658
|
} catch (e4) {
|
|
56516
|
-
|
|
56659
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56517
56660
|
process.exit(1);
|
|
56518
56661
|
}
|
|
56519
56662
|
});
|
|
56520
56663
|
dnsCmd.command("diff <domain>").description("Alias of dns plan: show live provider DNS drift against desired JSON state").requiredOption("--file <path>", "Desired DNS state JSON file").option("--provider <name>", "DNS provider \u2014 defaults to config default-dns").option("--json", "Output as JSON", false).action(async (domain, opts) => {
|
|
56521
56664
|
const providerName = opts.provider ?? loadConfig3().default_dns ?? "route53";
|
|
56522
56665
|
try {
|
|
56523
|
-
const plan = await loadDnsPlan(domain, providerName, opts.file);
|
|
56666
|
+
const plan = await loadDnsPlan(domain, providerName, opts.file, resolveDnsProvider);
|
|
56524
56667
|
if (opts.json)
|
|
56525
|
-
|
|
56668
|
+
printLine(JSON.stringify(plan, null, 2));
|
|
56526
56669
|
else
|
|
56527
56670
|
printDnsPlan(plan);
|
|
56528
56671
|
if (planHasChanges(plan))
|
|
56529
56672
|
process.exitCode = 2;
|
|
56530
56673
|
} catch (e4) {
|
|
56531
|
-
|
|
56674
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56532
56675
|
process.exit(1);
|
|
56533
56676
|
}
|
|
56534
56677
|
});
|
|
@@ -56537,12 +56680,12 @@ function registerDnsCommands(program2) {
|
|
|
56537
56680
|
try {
|
|
56538
56681
|
const desired = parseDesiredDnsState(readFileSync4(opts.file, "utf-8"), domain);
|
|
56539
56682
|
const planDomain = desired.domain ?? domain;
|
|
56540
|
-
const provider =
|
|
56683
|
+
const provider = resolveDnsProvider(providerName);
|
|
56541
56684
|
const current = await provider.getDnsRecords(planDomain);
|
|
56542
56685
|
const plan = createDnsPlan(planDomain, current, desired.records);
|
|
56543
56686
|
if (!planHasChanges(plan)) {
|
|
56544
56687
|
if (opts.json)
|
|
56545
|
-
|
|
56688
|
+
printLine(JSON.stringify({ applied: false, reason: "no-changes", plan }, null, 2));
|
|
56546
56689
|
else
|
|
56547
56690
|
printDnsPlan(plan);
|
|
56548
56691
|
return;
|
|
@@ -56550,55 +56693,56 @@ function registerDnsCommands(program2) {
|
|
|
56550
56693
|
const blockReason = getDnsApplyBlockReason(plan, { yes: opts.yes, allowDelete: opts.allowDelete });
|
|
56551
56694
|
if (blockReason) {
|
|
56552
56695
|
if (opts.json)
|
|
56553
|
-
|
|
56696
|
+
printLine(JSON.stringify({ applied: false, reason: blockReason, plan }, null, 2));
|
|
56554
56697
|
else {
|
|
56555
56698
|
printDnsPlan(plan);
|
|
56556
56699
|
if (blockReason === "confirmation-required")
|
|
56557
|
-
|
|
56700
|
+
printErrorLine("Refusing to apply without --yes.");
|
|
56558
56701
|
if (blockReason === "delete-confirmation-required")
|
|
56559
|
-
|
|
56702
|
+
printErrorLine("Refusing to delete DNS records without --allow-delete.");
|
|
56560
56703
|
if (blockReason === "delete-apply-unsupported")
|
|
56561
|
-
|
|
56704
|
+
printErrorLine(`Refusing to apply delete plan on ${providerName}: this provider path cannot guarantee delete convergence without partial mutation yet.`);
|
|
56562
56705
|
}
|
|
56563
56706
|
process.exit(1);
|
|
56564
56707
|
}
|
|
56565
|
-
|
|
56708
|
+
const recordsToApply = provider.dnsWriteScope === "changed-groups" ? selectChangedDnsRecords(plan, desired.records) : desired.records;
|
|
56709
|
+
await provider.setDnsRecords(planDomain, recordsToApply);
|
|
56566
56710
|
const verified = createDnsPlan(planDomain, await provider.getDnsRecords(planDomain), desired.records);
|
|
56567
56711
|
if (planHasChanges(verified)) {
|
|
56568
56712
|
if (opts.json)
|
|
56569
|
-
|
|
56713
|
+
printLine(JSON.stringify({ applied: false, provider: providerName, reason: "verification-failed", plan, verification: verified }, null, 2));
|
|
56570
56714
|
else {
|
|
56571
56715
|
printDnsPlan(verified);
|
|
56572
|
-
|
|
56716
|
+
printErrorLine(`Provider ${providerName} did not converge to the desired DNS state for ${planDomain}.`);
|
|
56573
56717
|
}
|
|
56574
56718
|
process.exit(1);
|
|
56575
56719
|
}
|
|
56576
56720
|
if (opts.json)
|
|
56577
|
-
|
|
56721
|
+
printLine(JSON.stringify({ applied: true, provider: providerName, plan, verification: verified }, null, 2));
|
|
56578
56722
|
else {
|
|
56579
56723
|
printDnsPlan(plan);
|
|
56580
|
-
|
|
56724
|
+
printLine(`\u2713 Applied and verified desired DNS state on ${providerName} for ${planDomain}`);
|
|
56581
56725
|
}
|
|
56582
56726
|
} catch (e4) {
|
|
56583
|
-
|
|
56727
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56584
56728
|
process.exit(1);
|
|
56585
56729
|
}
|
|
56586
56730
|
});
|
|
56587
56731
|
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
56732
|
const records = await listDnsRecords2(domainId, opts.type);
|
|
56589
56733
|
if (opts.json) {
|
|
56590
|
-
|
|
56734
|
+
printLine(JSON.stringify(records, null, 2));
|
|
56591
56735
|
} else {
|
|
56592
56736
|
const page = pageItemsOrExit(records, { limit: opts.limit, all: opts.all });
|
|
56593
56737
|
if (page.items.length === 0) {
|
|
56594
|
-
|
|
56738
|
+
printLine("No DNS records found.");
|
|
56595
56739
|
return;
|
|
56596
56740
|
}
|
|
56597
56741
|
for (const r4 of page.items) {
|
|
56598
56742
|
const priority = r4.priority !== null ? ` (priority: ${r4.priority})` : "";
|
|
56599
|
-
|
|
56743
|
+
printLine(` ${r4.type} ${r4.name} ${truncateText(r4.value, 80)} TTL:${r4.ttl}${priority}`);
|
|
56600
56744
|
}
|
|
56601
|
-
|
|
56745
|
+
printLine(`
|
|
56602
56746
|
${compactHint(page, "record(s)", "Use --all for every record or --json for full values.", { paging: "limit" })}`);
|
|
56603
56747
|
}
|
|
56604
56748
|
});
|
|
@@ -56612,9 +56756,9 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56612
56756
|
priority: opts.priority ? parseInt(opts.priority) : undefined
|
|
56613
56757
|
});
|
|
56614
56758
|
if (opts.json) {
|
|
56615
|
-
|
|
56759
|
+
printLine(JSON.stringify(record, null, 2));
|
|
56616
56760
|
} else {
|
|
56617
|
-
|
|
56761
|
+
printLine(`Created DNS record: ${record.type} ${record.name} -> ${record.value} (${record.id})`);
|
|
56618
56762
|
}
|
|
56619
56763
|
});
|
|
56620
56764
|
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 +56775,21 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56631
56775
|
input.priority = parseInt(opts.priority);
|
|
56632
56776
|
const record = await updateDnsRecord2(id, input);
|
|
56633
56777
|
if (!record) {
|
|
56634
|
-
|
|
56778
|
+
printErrorLine(`DNS record '${id}' not found.`);
|
|
56635
56779
|
process.exit(1);
|
|
56636
56780
|
}
|
|
56637
56781
|
if (opts.json) {
|
|
56638
|
-
|
|
56782
|
+
printLine(JSON.stringify(record, null, 2));
|
|
56639
56783
|
} else {
|
|
56640
|
-
|
|
56784
|
+
printLine(`Updated DNS record: ${record.type} ${record.name} -> ${record.value}`);
|
|
56641
56785
|
}
|
|
56642
56786
|
});
|
|
56643
56787
|
dnsCmd.command("remove").description("Remove a DNS record").argument("<id>", "Record ID").action(async (id) => {
|
|
56644
56788
|
const deleted = await deleteDnsRecord2(id);
|
|
56645
56789
|
if (deleted) {
|
|
56646
|
-
|
|
56790
|
+
printLine(`Deleted DNS record ${id}`);
|
|
56647
56791
|
} else {
|
|
56648
|
-
|
|
56792
|
+
printErrorLine(`DNS record '${id}' not found.`);
|
|
56649
56793
|
process.exit(1);
|
|
56650
56794
|
}
|
|
56651
56795
|
});
|
|
@@ -56653,32 +56797,32 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56653
56797
|
try {
|
|
56654
56798
|
const result = await checkDnsPropagation(domain, opts.record);
|
|
56655
56799
|
if (opts.json) {
|
|
56656
|
-
|
|
56800
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56657
56801
|
} else {
|
|
56658
|
-
|
|
56659
|
-
|
|
56802
|
+
printLine(`DNS Propagation for ${result.domain} (${result.record_type}):`);
|
|
56803
|
+
printLine(` Consistent: ${result.consistent ? "yes" : "NO"}`);
|
|
56660
56804
|
for (const s2 of result.servers) {
|
|
56661
56805
|
const values = s2.values.length > 0 ? s2.values.join(", ") : "(empty)";
|
|
56662
56806
|
const status = s2.status === "error" ? ` [ERROR: ${s2.error}]` : "";
|
|
56663
|
-
|
|
56807
|
+
printLine(` ${s2.name} (${s2.server}): ${values}${status}`);
|
|
56664
56808
|
}
|
|
56665
56809
|
}
|
|
56666
56810
|
} catch (error) {
|
|
56667
|
-
|
|
56811
|
+
printErrorLine(`DNS propagation check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
56668
56812
|
process.exit(1);
|
|
56669
56813
|
}
|
|
56670
56814
|
});
|
|
56671
56815
|
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
56816
|
const zone = await exportZoneFile(domainId);
|
|
56673
56817
|
if (!zone) {
|
|
56674
|
-
|
|
56818
|
+
printErrorLine(`Domain '${domainId}' not found.`);
|
|
56675
56819
|
process.exit(1);
|
|
56676
56820
|
}
|
|
56677
56821
|
if (opts.output) {
|
|
56678
56822
|
writeFileSync2(opts.output, zone, "utf-8");
|
|
56679
|
-
|
|
56823
|
+
printLine(`Exported zone file to ${opts.output}`);
|
|
56680
56824
|
} else {
|
|
56681
|
-
|
|
56825
|
+
printLine(zone);
|
|
56682
56826
|
}
|
|
56683
56827
|
});
|
|
56684
56828
|
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 +56830,22 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56686
56830
|
try {
|
|
56687
56831
|
content = readFileSync4(opts.file, "utf-8");
|
|
56688
56832
|
} catch {
|
|
56689
|
-
|
|
56833
|
+
printErrorLine(`Could not read file: ${opts.file}`);
|
|
56690
56834
|
process.exit(1);
|
|
56691
56835
|
}
|
|
56692
56836
|
const result = await importZoneFile(domainId, content);
|
|
56693
56837
|
if (!result) {
|
|
56694
|
-
|
|
56838
|
+
printErrorLine(`Domain '${domainId}' not found.`);
|
|
56695
56839
|
process.exit(1);
|
|
56696
56840
|
}
|
|
56697
56841
|
if (opts.json) {
|
|
56698
|
-
|
|
56842
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56699
56843
|
} else {
|
|
56700
|
-
|
|
56844
|
+
printLine(`Imported ${result.imported} record(s), skipped ${result.skipped}`);
|
|
56701
56845
|
if (result.errors.length > 0) {
|
|
56702
|
-
|
|
56846
|
+
printLine("Errors:");
|
|
56703
56847
|
for (const e4 of result.errors) {
|
|
56704
|
-
|
|
56848
|
+
printLine(` - ${e4}`);
|
|
56705
56849
|
}
|
|
56706
56850
|
}
|
|
56707
56851
|
}
|
|
@@ -56709,42 +56853,42 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
56709
56853
|
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
56854
|
const result = await discoverSubdomains(domain);
|
|
56711
56855
|
if (opts.json) {
|
|
56712
|
-
|
|
56856
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56713
56857
|
} else {
|
|
56714
56858
|
if (result.error) {
|
|
56715
|
-
|
|
56859
|
+
printErrorLine(`Discovery failed: ${result.error}`);
|
|
56716
56860
|
process.exit(1);
|
|
56717
56861
|
}
|
|
56718
56862
|
if (result.subdomains.length === 0) {
|
|
56719
|
-
|
|
56863
|
+
printLine(`No subdomains found for ${domain}.`);
|
|
56720
56864
|
return;
|
|
56721
56865
|
}
|
|
56722
56866
|
const page = pageItemsOrExit(result.subdomains, { limit: opts.limit, all: opts.all });
|
|
56723
|
-
|
|
56867
|
+
printLine(`Subdomains for ${domain} (source: ${result.source}):`);
|
|
56724
56868
|
for (const s2 of page.items) {
|
|
56725
|
-
|
|
56869
|
+
printLine(` ${s2}`);
|
|
56726
56870
|
}
|
|
56727
|
-
|
|
56871
|
+
printLine(`
|
|
56728
56872
|
${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --json for the full result.", { paging: "limit" })}`);
|
|
56729
56873
|
}
|
|
56730
56874
|
});
|
|
56731
56875
|
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
56876
|
const result = await validateDns(domainId);
|
|
56733
56877
|
if (!result) {
|
|
56734
|
-
|
|
56878
|
+
printErrorLine(`Domain '${domainId}' not found.`);
|
|
56735
56879
|
process.exit(1);
|
|
56736
56880
|
}
|
|
56737
56881
|
if (opts.json) {
|
|
56738
|
-
|
|
56882
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56739
56883
|
} else {
|
|
56740
|
-
|
|
56741
|
-
|
|
56884
|
+
printLine(`DNS Validation for ${result.domain_name}:`);
|
|
56885
|
+
printLine(` Valid: ${result.valid ? "yes" : "NO"}`);
|
|
56742
56886
|
if (result.issues.length === 0) {
|
|
56743
|
-
|
|
56887
|
+
printLine(" No issues found.");
|
|
56744
56888
|
} else {
|
|
56745
56889
|
for (const issue of result.issues) {
|
|
56746
56890
|
const prefix = issue.type === "error" ? "ERROR" : "WARN";
|
|
56747
|
-
|
|
56891
|
+
printLine(` [${prefix}] ${issue.message}`);
|
|
56748
56892
|
}
|
|
56749
56893
|
}
|
|
56750
56894
|
}
|
|
@@ -56752,11 +56896,11 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56752
56896
|
dnsCmd.command("pull <domain>").description("Pull live DNS records from provider into local DB").option("--provider <name>", "DNS provider (route53, cloudflare) \u2014 defaults to config default-dns").action(async (domain, opts) => {
|
|
56753
56897
|
const providerName = opts.provider ?? loadConfig3().default_dns ?? "route53";
|
|
56754
56898
|
try {
|
|
56755
|
-
const provider =
|
|
56899
|
+
const provider = resolveDnsProvider(providerName);
|
|
56756
56900
|
const records = await provider.getDnsRecords(domain);
|
|
56757
56901
|
const dbDomain = await getDomainByName2(domain);
|
|
56758
56902
|
if (!dbDomain) {
|
|
56759
|
-
|
|
56903
|
+
printErrorLine(`Domain '${domain}' not found in local DB. Add it first: domains domain add --name ${domain}`);
|
|
56760
56904
|
process.exit(1);
|
|
56761
56905
|
}
|
|
56762
56906
|
const { keep, skipped } = partitionPullableRecords(records);
|
|
@@ -56765,13 +56909,13 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56765
56909
|
await createDnsRecord2({ domain_id: dbDomain.id, type: r4.type, name: r4.name, value: r4.value, ttl: r4.ttl, priority: r4.priority });
|
|
56766
56910
|
count++;
|
|
56767
56911
|
}
|
|
56768
|
-
|
|
56912
|
+
printLine(`\u2713 Pulled ${count} record(s) from ${providerName} into local DB for ${domain}`);
|
|
56769
56913
|
if (skipped.size > 0) {
|
|
56770
56914
|
const summary = Array.from(skipped.entries()).map(([t2, n2]) => `${n2} ${t2}`).join(", ");
|
|
56771
|
-
|
|
56915
|
+
printLine(` Skipped ${summary} record(s) (unsupported/provider-managed type).`);
|
|
56772
56916
|
}
|
|
56773
56917
|
} catch (e4) {
|
|
56774
|
-
|
|
56918
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56775
56919
|
process.exit(1);
|
|
56776
56920
|
}
|
|
56777
56921
|
});
|
|
@@ -56780,13 +56924,13 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56780
56924
|
try {
|
|
56781
56925
|
const records = await listDnsRecords2(domainId);
|
|
56782
56926
|
if (records.length === 0) {
|
|
56783
|
-
|
|
56927
|
+
printLine("No local DNS records to push.");
|
|
56784
56928
|
return;
|
|
56785
56929
|
}
|
|
56786
56930
|
const dbDomain = await getDomain2(domainId) ?? (() => {
|
|
56787
56931
|
throw new Error(`Domain '${domainId}' not found`);
|
|
56788
56932
|
})();
|
|
56789
|
-
const provider =
|
|
56933
|
+
const provider = resolveDnsProvider(providerName);
|
|
56790
56934
|
await provider.setDnsRecords(dbDomain.name, records.map((r4) => ({
|
|
56791
56935
|
type: r4.type,
|
|
56792
56936
|
name: r4.name,
|
|
@@ -56794,9 +56938,9 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56794
56938
|
ttl: r4.ttl,
|
|
56795
56939
|
priority: r4.priority ?? undefined
|
|
56796
56940
|
})));
|
|
56797
|
-
|
|
56941
|
+
printLine(`\u2713 Pushed ${records.length} record(s) to ${providerName} for ${dbDomain.name}`);
|
|
56798
56942
|
} catch (e4) {
|
|
56799
|
-
|
|
56943
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56800
56944
|
process.exit(1);
|
|
56801
56945
|
}
|
|
56802
56946
|
});
|
|
@@ -56806,6 +56950,7 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
|
|
|
56806
56950
|
init_config();
|
|
56807
56951
|
init_route53();
|
|
56808
56952
|
init_cloudflare();
|
|
56953
|
+
init_stdout();
|
|
56809
56954
|
function resolveProvider(flag) {
|
|
56810
56955
|
return flag ?? loadConfig3().default_dns ?? "route53";
|
|
56811
56956
|
}
|
|
@@ -56821,24 +56966,24 @@ function registerZoneCommand(program2) {
|
|
|
56821
56966
|
zones = await listHostedZones();
|
|
56822
56967
|
}
|
|
56823
56968
|
if (opts.json) {
|
|
56824
|
-
|
|
56969
|
+
printLine(JSON.stringify(zones, null, 2));
|
|
56825
56970
|
return;
|
|
56826
56971
|
}
|
|
56827
56972
|
const page = pageItemsOrExit(zones, { limit: opts.limit, all: opts.all });
|
|
56828
56973
|
if (page.items.length === 0) {
|
|
56829
|
-
|
|
56974
|
+
printLine("No hosted zones.");
|
|
56830
56975
|
return;
|
|
56831
56976
|
}
|
|
56832
|
-
|
|
56977
|
+
printLine(`
|
|
56833
56978
|
Hosted Zones (${provider}):`);
|
|
56834
56979
|
for (const z of page.items) {
|
|
56835
56980
|
const extra = z.record_count !== undefined ? ` ${z.record_count} records` : "";
|
|
56836
|
-
|
|
56981
|
+
printLine(` ${z.id.padEnd(32)} ${z.name}${extra}`);
|
|
56837
56982
|
}
|
|
56838
|
-
|
|
56983
|
+
printLine(`
|
|
56839
56984
|
${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> for details.", { paging: "limit" })}`);
|
|
56840
56985
|
} catch (e4) {
|
|
56841
|
-
|
|
56986
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56842
56987
|
process.exit(1);
|
|
56843
56988
|
}
|
|
56844
56989
|
});
|
|
@@ -56847,23 +56992,23 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> f
|
|
|
56847
56992
|
try {
|
|
56848
56993
|
if (provider === "cloudflare") {
|
|
56849
56994
|
const z = await createZone(domain);
|
|
56850
|
-
|
|
56995
|
+
printLine(`\u2713 Zone created: ${domain} (${z.id})`);
|
|
56851
56996
|
if (z.nameservers?.length) {
|
|
56852
|
-
|
|
56997
|
+
printLine(` Name servers:`);
|
|
56853
56998
|
for (const ns of z.nameservers)
|
|
56854
|
-
|
|
56999
|
+
printLine(` ${ns}`);
|
|
56855
57000
|
}
|
|
56856
57001
|
} else {
|
|
56857
57002
|
const z = await createHostedZone(domain, opts.comment);
|
|
56858
|
-
|
|
57003
|
+
printLine(`\u2713 Zone created: ${domain} (${z.id})`);
|
|
56859
57004
|
if (z.name_servers?.length) {
|
|
56860
|
-
|
|
57005
|
+
printLine(` Name servers:`);
|
|
56861
57006
|
for (const ns of z.name_servers)
|
|
56862
|
-
|
|
57007
|
+
printLine(` ${ns}`);
|
|
56863
57008
|
}
|
|
56864
57009
|
}
|
|
56865
57010
|
} catch (e4) {
|
|
56866
|
-
|
|
57011
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56867
57012
|
process.exit(1);
|
|
56868
57013
|
}
|
|
56869
57014
|
});
|
|
@@ -56874,44 +57019,44 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> f
|
|
|
56874
57019
|
const zones = await listZones();
|
|
56875
57020
|
const z = zones.find((z2) => z2.id === zoneId || z2.name === zoneId);
|
|
56876
57021
|
if (!z) {
|
|
56877
|
-
|
|
57022
|
+
printErrorLine(`Zone not found: ${zoneId}`);
|
|
56878
57023
|
process.exit(1);
|
|
56879
57024
|
}
|
|
56880
57025
|
if (opts.json) {
|
|
56881
|
-
|
|
57026
|
+
printLine(JSON.stringify(z, null, 2));
|
|
56882
57027
|
return;
|
|
56883
57028
|
}
|
|
56884
|
-
|
|
57029
|
+
printLine(`
|
|
56885
57030
|
Zone: ${z.name}`);
|
|
56886
|
-
|
|
56887
|
-
|
|
57031
|
+
printLine(` ID: ${z.id}`);
|
|
57032
|
+
printLine(` Status: ${z.status}`);
|
|
56888
57033
|
if (z.nameservers?.length) {
|
|
56889
|
-
|
|
57034
|
+
printLine(` Name servers:`);
|
|
56890
57035
|
for (const ns of z.nameservers)
|
|
56891
|
-
|
|
57036
|
+
printLine(` ${ns}`);
|
|
56892
57037
|
}
|
|
56893
|
-
|
|
57038
|
+
printLine();
|
|
56894
57039
|
} else {
|
|
56895
57040
|
const z = await getHostedZone(zoneId);
|
|
56896
57041
|
if (opts.json) {
|
|
56897
|
-
|
|
57042
|
+
printLine(JSON.stringify(z, null, 2));
|
|
56898
57043
|
return;
|
|
56899
57044
|
}
|
|
56900
|
-
|
|
57045
|
+
printLine(`
|
|
56901
57046
|
Zone: ${z.name}`);
|
|
56902
|
-
|
|
56903
|
-
|
|
57047
|
+
printLine(` ID: ${z.id}`);
|
|
57048
|
+
printLine(` Records: ${z.record_count}`);
|
|
56904
57049
|
if (z.comment)
|
|
56905
|
-
|
|
57050
|
+
printLine(` Comment: ${z.comment}`);
|
|
56906
57051
|
if (z.name_servers?.length) {
|
|
56907
|
-
|
|
57052
|
+
printLine(` Name servers:`);
|
|
56908
57053
|
for (const ns of z.name_servers)
|
|
56909
|
-
|
|
57054
|
+
printLine(` ${ns}`);
|
|
56910
57055
|
}
|
|
56911
|
-
|
|
57056
|
+
printLine();
|
|
56912
57057
|
}
|
|
56913
57058
|
} catch (e4) {
|
|
56914
|
-
|
|
57059
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56915
57060
|
process.exit(1);
|
|
56916
57061
|
}
|
|
56917
57062
|
});
|
|
@@ -56919,8 +57064,8 @@ Zone: ${z.name}`);
|
|
|
56919
57064
|
const provider = resolveProvider(opts.provider);
|
|
56920
57065
|
try {
|
|
56921
57066
|
if (!opts.force) {
|
|
56922
|
-
|
|
56923
|
-
|
|
57067
|
+
printLine(`Would delete zone: ${zoneId} (${provider})`);
|
|
57068
|
+
printLine("Re-run with --force to confirm.");
|
|
56924
57069
|
return;
|
|
56925
57070
|
}
|
|
56926
57071
|
if (provider === "cloudflare") {
|
|
@@ -56928,9 +57073,9 @@ Zone: ${z.name}`);
|
|
|
56928
57073
|
} else {
|
|
56929
57074
|
await deleteHostedZone(zoneId);
|
|
56930
57075
|
}
|
|
56931
|
-
|
|
57076
|
+
printLine(`\u2713 Zone deleted: ${zoneId}`);
|
|
56932
57077
|
} catch (e4) {
|
|
56933
|
-
|
|
57078
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
56934
57079
|
process.exit(1);
|
|
56935
57080
|
}
|
|
56936
57081
|
});
|
|
@@ -56938,52 +57083,54 @@ Zone: ${z.name}`);
|
|
|
56938
57083
|
|
|
56939
57084
|
// src/cli/commands/ssl.ts
|
|
56940
57085
|
init_domains();
|
|
57086
|
+
init_stdout();
|
|
56941
57087
|
function registerSslCommand(program2) {
|
|
56942
57088
|
const ssl = program2.command("ssl").description("SSL certificate management");
|
|
56943
57089
|
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
57090
|
try {
|
|
56945
57091
|
const result = await checkSsl(domain);
|
|
56946
57092
|
if (opts.json) {
|
|
56947
|
-
|
|
57093
|
+
printLine(JSON.stringify(result, null, 2));
|
|
56948
57094
|
return;
|
|
56949
57095
|
}
|
|
56950
|
-
|
|
57096
|
+
printLine(`
|
|
56951
57097
|
SSL Certificate for ${result.domain}:`);
|
|
56952
57098
|
if (result.error) {
|
|
56953
|
-
|
|
57099
|
+
printLine(` Error: ${result.error}`);
|
|
56954
57100
|
} else {
|
|
56955
|
-
|
|
56956
|
-
|
|
57101
|
+
printLine(` Issuer: ${result.issuer ?? "unknown"}`);
|
|
57102
|
+
printLine(` Expires: ${result.expires_at ? result.expires_at.split("T")[0] : "unknown"}`);
|
|
56957
57103
|
}
|
|
56958
|
-
|
|
57104
|
+
printLine();
|
|
56959
57105
|
} catch (error) {
|
|
56960
|
-
|
|
57106
|
+
printErrorLine(`SSL check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
56961
57107
|
process.exit(1);
|
|
56962
57108
|
}
|
|
56963
57109
|
});
|
|
56964
57110
|
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
57111
|
const domains = await listSslExpiring2(parseInt(opts.days));
|
|
56966
57112
|
if (opts.json) {
|
|
56967
|
-
|
|
57113
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
56968
57114
|
return;
|
|
56969
57115
|
}
|
|
56970
57116
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
56971
57117
|
if (page.items.length === 0) {
|
|
56972
|
-
|
|
57118
|
+
printLine(`No SSL certificates expiring within ${opts.days} days.`);
|
|
56973
57119
|
return;
|
|
56974
57120
|
}
|
|
56975
|
-
|
|
57121
|
+
printLine(`
|
|
56976
57122
|
SSL expiring within ${opts.days} days:`);
|
|
56977
57123
|
for (const d4 of page.items) {
|
|
56978
57124
|
const exp = d4.ssl_expires_at ? formatDate(d4.ssl_expires_at) : "unknown";
|
|
56979
|
-
|
|
57125
|
+
printLine(` ${d4.name.padEnd(40)} expires ${exp}`);
|
|
56980
57126
|
}
|
|
56981
|
-
|
|
57127
|
+
printLine(`
|
|
56982
57128
|
${compactHint(page, "domain(s)", "Use --all to display every matching SSL certificate.", { paging: "limit" })}`);
|
|
56983
57129
|
});
|
|
56984
57130
|
}
|
|
56985
57131
|
|
|
56986
57132
|
// src/cli/commands/alerts.ts
|
|
57133
|
+
init_stdout();
|
|
56987
57134
|
init_domains();
|
|
56988
57135
|
function registerAlertCommands(program2) {
|
|
56989
57136
|
const alertCmd = program2.command("alert").description("Alert management");
|
|
@@ -56994,40 +57141,41 @@ function registerAlertCommands(program2) {
|
|
|
56994
57141
|
trigger_days_before: opts.daysBefore ? parseInt(opts.daysBefore) : undefined
|
|
56995
57142
|
});
|
|
56996
57143
|
if (opts.json) {
|
|
56997
|
-
|
|
57144
|
+
printLine(JSON.stringify(alert, null, 2));
|
|
56998
57145
|
} else {
|
|
56999
57146
|
const daysBefore = alert.trigger_days_before ? ` (${alert.trigger_days_before} days before)` : "";
|
|
57000
|
-
|
|
57147
|
+
printLine(`Created alert: ${alert.type}${daysBefore} for domain ${alert.domain_id} (${alert.id})`);
|
|
57001
57148
|
}
|
|
57002
57149
|
});
|
|
57003
57150
|
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
57151
|
const alerts = await listAlerts2(domainId);
|
|
57005
57152
|
if (opts.json) {
|
|
57006
|
-
|
|
57153
|
+
printLine(JSON.stringify(alerts, null, 2));
|
|
57007
57154
|
} else {
|
|
57008
57155
|
if (alerts.length === 0) {
|
|
57009
|
-
|
|
57156
|
+
printLine("No alerts set.");
|
|
57010
57157
|
return;
|
|
57011
57158
|
}
|
|
57012
57159
|
for (const a4 of alerts) {
|
|
57013
57160
|
const daysBefore = a4.trigger_days_before ? ` (${a4.trigger_days_before} days before)` : "";
|
|
57014
57161
|
const sent = a4.sent_at ? ` \u2014 sent ${a4.sent_at}` : "";
|
|
57015
|
-
|
|
57162
|
+
printLine(` ${a4.type}${daysBefore}${sent}`);
|
|
57016
57163
|
}
|
|
57017
57164
|
}
|
|
57018
57165
|
});
|
|
57019
57166
|
alertCmd.command("remove").description("Remove an alert").argument("<id>", "Alert ID").action(async (id) => {
|
|
57020
57167
|
const deleted = await deleteAlert2(id);
|
|
57021
57168
|
if (deleted) {
|
|
57022
|
-
|
|
57169
|
+
printLine(`Deleted alert ${id}`);
|
|
57023
57170
|
} else {
|
|
57024
|
-
|
|
57171
|
+
printErrorLine(`Alert '${id}' not found.`);
|
|
57025
57172
|
process.exit(1);
|
|
57026
57173
|
}
|
|
57027
57174
|
});
|
|
57028
57175
|
}
|
|
57029
57176
|
|
|
57030
57177
|
// src/cli/commands/provider.ts
|
|
57178
|
+
init_stdout();
|
|
57031
57179
|
function isAwsAccessDenied(error) {
|
|
57032
57180
|
const msg = error instanceof Error ? error.message : String(error);
|
|
57033
57181
|
return msg.includes("AccessDenied") || msg.includes("route53domains:ListDomains");
|
|
@@ -57037,21 +57185,21 @@ function registerProviderCommand(program2) {
|
|
|
57037
57185
|
provider.command("list").description("Show all providers and their configuration status").option("-j, --json", "Output JSON").action((opts) => {
|
|
57038
57186
|
const providers = getAvailableProviders();
|
|
57039
57187
|
if (opts.json) {
|
|
57040
|
-
|
|
57188
|
+
printLine(JSON.stringify(providers, null, 2));
|
|
57041
57189
|
return;
|
|
57042
57190
|
}
|
|
57043
|
-
|
|
57191
|
+
printLine(`
|
|
57044
57192
|
Registrar / DNS Providers:`);
|
|
57045
57193
|
for (const p2 of providers) {
|
|
57046
57194
|
const status = p2.configured ? "\u2713 configured" : "\u2717 not configured";
|
|
57047
57195
|
const type = p2.type === "full" ? "registrar + dns" : p2.type;
|
|
57048
57196
|
const capabilities = [type, p2.inventory ? "inventory" : null].filter(Boolean).join(", ");
|
|
57049
|
-
|
|
57197
|
+
printLine(` ${p2.name.padEnd(12)} [${capabilities}] ${status}`);
|
|
57050
57198
|
if (!p2.configured) {
|
|
57051
|
-
|
|
57199
|
+
printLine(` Missing: ${p2.envVars.join(", ")}`);
|
|
57052
57200
|
}
|
|
57053
57201
|
}
|
|
57054
|
-
|
|
57202
|
+
printLine();
|
|
57055
57203
|
});
|
|
57056
57204
|
provider.command("test <name>").description("Live-test a provider's credentials").option("-j, --json", "Output JSON").action(async (name, opts) => {
|
|
57057
57205
|
const providerName = name.toLowerCase();
|
|
@@ -57060,16 +57208,16 @@ Registrar / DNS Providers:`);
|
|
|
57060
57208
|
if (!info) {
|
|
57061
57209
|
const error = `Unknown provider: ${name}`;
|
|
57062
57210
|
if (opts.json) {
|
|
57063
|
-
|
|
57211
|
+
printLine(JSON.stringify({ provider: providerName, ok: false, error }, null, 2));
|
|
57064
57212
|
} else {
|
|
57065
|
-
|
|
57213
|
+
printErrorLine(error);
|
|
57066
57214
|
}
|
|
57067
57215
|
process.exit(1);
|
|
57068
57216
|
}
|
|
57069
57217
|
if (!info.configured) {
|
|
57070
57218
|
const error = `${providerName} is not configured. Set: ${info.envVars.join(", ")}`;
|
|
57071
57219
|
if (opts.json) {
|
|
57072
|
-
|
|
57220
|
+
printLine(JSON.stringify({
|
|
57073
57221
|
provider: providerName,
|
|
57074
57222
|
ok: false,
|
|
57075
57223
|
configured: false,
|
|
@@ -57077,12 +57225,12 @@ Registrar / DNS Providers:`);
|
|
|
57077
57225
|
error
|
|
57078
57226
|
}, null, 2));
|
|
57079
57227
|
} else {
|
|
57080
|
-
|
|
57228
|
+
printErrorLine(`\u2717 ${error}`);
|
|
57081
57229
|
}
|
|
57082
57230
|
process.exit(1);
|
|
57083
57231
|
}
|
|
57084
57232
|
if (!opts.json) {
|
|
57085
|
-
|
|
57233
|
+
printLine(`Testing ${providerName}...`);
|
|
57086
57234
|
}
|
|
57087
57235
|
let registrarOk = null;
|
|
57088
57236
|
let dnsOk = null;
|
|
@@ -57096,21 +57244,21 @@ Registrar / DNS Providers:`);
|
|
|
57096
57244
|
await listRegisteredDomains2();
|
|
57097
57245
|
registrarOk = true;
|
|
57098
57246
|
if (!opts.json)
|
|
57099
|
-
|
|
57247
|
+
printLine("\u2713 Registrar connection OK");
|
|
57100
57248
|
} catch (error) {
|
|
57101
57249
|
if (!isAwsAccessDenied(error))
|
|
57102
57250
|
throw error;
|
|
57103
57251
|
registrarOk = false;
|
|
57104
57252
|
notes.push("route53domains-listdomains-access-denied");
|
|
57105
57253
|
if (!opts.json)
|
|
57106
|
-
|
|
57254
|
+
printLine("\u2022 Route53 Domains registrar API is not available for these AWS credentials");
|
|
57107
57255
|
}
|
|
57108
57256
|
} else {
|
|
57109
57257
|
const reg = getRegistrarProvider(providerName);
|
|
57110
57258
|
await reg.listDomains();
|
|
57111
57259
|
registrarOk = true;
|
|
57112
57260
|
if (!opts.json)
|
|
57113
|
-
|
|
57261
|
+
printLine("\u2713 Registrar connection OK");
|
|
57114
57262
|
}
|
|
57115
57263
|
}
|
|
57116
57264
|
if (info.type === "dns" || info.type === "full") {
|
|
@@ -57118,13 +57266,13 @@ Registrar / DNS Providers:`);
|
|
|
57118
57266
|
dnsOk = null;
|
|
57119
57267
|
notes.push("dns-not-probed-with-synthetic-invalid-domain");
|
|
57120
57268
|
if (!opts.json)
|
|
57121
|
-
|
|
57269
|
+
printLine("\u2022 DNS not probed with synthetic invalid domain");
|
|
57122
57270
|
} else {
|
|
57123
57271
|
const dns = getDnsProvider(providerName);
|
|
57124
57272
|
await dns.getDnsRecords("__test_nonexistent_domain__.invalid");
|
|
57125
57273
|
dnsOk = true;
|
|
57126
57274
|
if (!opts.json)
|
|
57127
|
-
|
|
57275
|
+
printLine("\u2713 DNS connection OK");
|
|
57128
57276
|
}
|
|
57129
57277
|
}
|
|
57130
57278
|
if (info.type === "marketplace") {
|
|
@@ -57134,10 +57282,10 @@ Registrar / DNS Providers:`);
|
|
|
57134
57282
|
await listSedoPortfolio2({ limit: 1 });
|
|
57135
57283
|
marketplaceOk = true;
|
|
57136
57284
|
if (!opts.json)
|
|
57137
|
-
|
|
57285
|
+
printLine("\u2713 Marketplace connection OK");
|
|
57138
57286
|
}
|
|
57139
57287
|
if (opts.json) {
|
|
57140
|
-
|
|
57288
|
+
printLine(JSON.stringify({
|
|
57141
57289
|
provider: providerName,
|
|
57142
57290
|
ok: true,
|
|
57143
57291
|
configured: true,
|
|
@@ -57152,7 +57300,7 @@ Registrar / DNS Providers:`);
|
|
|
57152
57300
|
const msg = e4 instanceof Error ? e4.message : String(e4);
|
|
57153
57301
|
if (msg.includes("not found") || msg.includes("No hosted zone") || msg.includes("NXDOMAIN")) {
|
|
57154
57302
|
if (opts.json) {
|
|
57155
|
-
|
|
57303
|
+
printLine(JSON.stringify({
|
|
57156
57304
|
provider: providerName,
|
|
57157
57305
|
ok: true,
|
|
57158
57306
|
configured: true,
|
|
@@ -57164,12 +57312,12 @@ Registrar / DNS Providers:`);
|
|
|
57164
57312
|
...notes.length > 0 ? { notes } : {}
|
|
57165
57313
|
}, null, 2));
|
|
57166
57314
|
} else {
|
|
57167
|
-
|
|
57315
|
+
printLine("\u2713 Connection OK (no domains yet)");
|
|
57168
57316
|
}
|
|
57169
57317
|
return;
|
|
57170
57318
|
}
|
|
57171
57319
|
if (opts.json) {
|
|
57172
|
-
|
|
57320
|
+
printLine(JSON.stringify({
|
|
57173
57321
|
provider: providerName,
|
|
57174
57322
|
ok: false,
|
|
57175
57323
|
configured: true,
|
|
@@ -57180,7 +57328,7 @@ Registrar / DNS Providers:`);
|
|
|
57180
57328
|
error: msg
|
|
57181
57329
|
}, null, 2));
|
|
57182
57330
|
} else {
|
|
57183
|
-
|
|
57331
|
+
printErrorLine(`\u2717 ${providerName} test failed: ${msg}`);
|
|
57184
57332
|
}
|
|
57185
57333
|
process.exit(1);
|
|
57186
57334
|
}
|
|
@@ -57189,6 +57337,7 @@ Registrar / DNS Providers:`);
|
|
|
57189
57337
|
|
|
57190
57338
|
// src/cli/commands/providers.ts
|
|
57191
57339
|
init_config();
|
|
57340
|
+
init_stdout();
|
|
57192
57341
|
init_domains();
|
|
57193
57342
|
function registrarProviderNames() {
|
|
57194
57343
|
return getAvailableProviders().filter((p2) => providerHasRegistrar(p2.name)).map((p2) => p2.name).join(", ");
|
|
@@ -57218,15 +57367,15 @@ function registerProviderCommands(program2) {
|
|
|
57218
57367
|
program2.command("providers").description("Show which providers are configured").option("--json", "Output as JSON", false).action((opts) => {
|
|
57219
57368
|
const providers = getAvailableProviders();
|
|
57220
57369
|
if (opts.json) {
|
|
57221
|
-
|
|
57370
|
+
printLine(JSON.stringify(providers, null, 2));
|
|
57222
57371
|
} else {
|
|
57223
|
-
|
|
57372
|
+
printLine("Providers:");
|
|
57224
57373
|
for (const p2 of providers) {
|
|
57225
57374
|
const status = p2.configured ? "CONFIGURED" : "not configured";
|
|
57226
57375
|
const capabilities = [p2.type, p2.inventory ? "inventory" : null].filter(Boolean).join(", ");
|
|
57227
|
-
|
|
57376
|
+
printLine(` ${p2.name} [${capabilities}]: ${status}`);
|
|
57228
57377
|
if (!p2.configured) {
|
|
57229
|
-
|
|
57378
|
+
printLine(` Accepted env: ${p2.envVars.join(", ")}`);
|
|
57230
57379
|
}
|
|
57231
57380
|
}
|
|
57232
57381
|
}
|
|
@@ -57240,28 +57389,28 @@ function registerProviderCommands(program2) {
|
|
|
57240
57389
|
updateDomain: updateDomain2
|
|
57241
57390
|
});
|
|
57242
57391
|
if (opts.json) {
|
|
57243
|
-
|
|
57392
|
+
printLine(JSON.stringify(result, null, 2));
|
|
57244
57393
|
} else {
|
|
57245
|
-
|
|
57394
|
+
printLine(`Synced ${result.totalSynced} domain(s) from ${result.providers.length} provider(s)`);
|
|
57246
57395
|
for (const p2 of result.providers) {
|
|
57247
|
-
|
|
57396
|
+
printLine(` ${p2.name}: ${p2.result.synced} synced (${p2.result.created} new, ${p2.result.updated} updated)`);
|
|
57248
57397
|
}
|
|
57249
57398
|
if (result.totalErrors.length > 0) {
|
|
57250
|
-
|
|
57399
|
+
printLine("Errors:");
|
|
57251
57400
|
for (const e4 of result.totalErrors) {
|
|
57252
|
-
|
|
57401
|
+
printLine(` - ${e4}`);
|
|
57253
57402
|
}
|
|
57254
57403
|
}
|
|
57255
57404
|
}
|
|
57256
57405
|
} catch (error) {
|
|
57257
|
-
|
|
57406
|
+
printErrorLine(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57258
57407
|
process.exit(1);
|
|
57259
57408
|
}
|
|
57260
57409
|
return;
|
|
57261
57410
|
}
|
|
57262
57411
|
const provider = (opts.provider || "").toLowerCase();
|
|
57263
57412
|
if (!provider) {
|
|
57264
|
-
|
|
57413
|
+
printErrorLine("Specify --provider <name> or --all");
|
|
57265
57414
|
process.exit(1);
|
|
57266
57415
|
}
|
|
57267
57416
|
try {
|
|
@@ -57272,17 +57421,17 @@ function registerProviderCommands(program2) {
|
|
|
57272
57421
|
updateDomain: updateDomain2
|
|
57273
57422
|
});
|
|
57274
57423
|
if (opts.json) {
|
|
57275
|
-
|
|
57424
|
+
printLine(JSON.stringify({ provider, ...result }, null, 2));
|
|
57276
57425
|
} else {
|
|
57277
|
-
|
|
57426
|
+
printLine(`Synced ${result.synced} domain(s) from ${provider} (${result.created} new, ${result.updated} updated)`);
|
|
57278
57427
|
if (result.errors.length > 0) {
|
|
57279
|
-
|
|
57428
|
+
printLine("Errors:");
|
|
57280
57429
|
for (const e4 of result.errors)
|
|
57281
|
-
|
|
57430
|
+
printLine(` - ${e4}`);
|
|
57282
57431
|
}
|
|
57283
57432
|
}
|
|
57284
57433
|
} catch (error) {
|
|
57285
|
-
|
|
57434
|
+
printErrorLine(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57286
57435
|
process.exit(1);
|
|
57287
57436
|
}
|
|
57288
57437
|
});
|
|
@@ -57291,12 +57440,12 @@ function registerProviderCommands(program2) {
|
|
|
57291
57440
|
if (!provider) {
|
|
57292
57441
|
const detected = autoDetectRegistrar(name, getDomainByName2);
|
|
57293
57442
|
if (!detected) {
|
|
57294
|
-
|
|
57443
|
+
printErrorLine(`Could not auto-detect registrar for '${name}'. Use --provider.`);
|
|
57295
57444
|
process.exit(1);
|
|
57296
57445
|
}
|
|
57297
57446
|
provider = detected;
|
|
57298
57447
|
if (!opts.json)
|
|
57299
|
-
|
|
57448
|
+
printLine(`Auto-detected registrar: ${provider}`);
|
|
57300
57449
|
}
|
|
57301
57450
|
try {
|
|
57302
57451
|
requireRegistrarProvider(provider);
|
|
@@ -57305,16 +57454,16 @@ function registerProviderCommands(program2) {
|
|
|
57305
57454
|
throw new Error(`Renewal failed or is not supported for ${provider}`);
|
|
57306
57455
|
}
|
|
57307
57456
|
if (opts.json) {
|
|
57308
|
-
|
|
57457
|
+
printLine(JSON.stringify({ provider, ...result }, null, 2));
|
|
57309
57458
|
} else {
|
|
57310
|
-
|
|
57459
|
+
printLine(`Renewed ${result.domain} successfully via ${provider}`);
|
|
57311
57460
|
if (result.chargedAmount)
|
|
57312
|
-
|
|
57461
|
+
printLine(` Charged: $${result.chargedAmount}`);
|
|
57313
57462
|
if (result.orderId)
|
|
57314
|
-
|
|
57463
|
+
printLine(` Order ID: ${result.orderId}`);
|
|
57315
57464
|
}
|
|
57316
57465
|
} catch (error) {
|
|
57317
|
-
|
|
57466
|
+
printErrorLine(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57318
57467
|
process.exit(1);
|
|
57319
57468
|
}
|
|
57320
57469
|
});
|
|
@@ -57324,18 +57473,18 @@ function registerProviderCommands(program2) {
|
|
|
57324
57473
|
requireRegistrarProvider(providerName);
|
|
57325
57474
|
const result = await getRegistrarProvider(providerName).checkAvailability(name);
|
|
57326
57475
|
if (opts.json) {
|
|
57327
|
-
|
|
57476
|
+
printLine(JSON.stringify({ provider: providerName, ...result }, null, 2));
|
|
57328
57477
|
} else {
|
|
57329
|
-
|
|
57478
|
+
printLine(`${result.domain} is ${result.available ? "AVAILABLE" : "NOT available"} (via ${providerName})`);
|
|
57330
57479
|
if (result.is_premium)
|
|
57331
|
-
|
|
57480
|
+
printLine(` Premium ask: ${result.premium_price ?? "unknown"}`);
|
|
57332
57481
|
if (result.standard_price !== undefined) {
|
|
57333
57482
|
const currency = result.currency ? ` ${result.currency}` : "";
|
|
57334
|
-
|
|
57483
|
+
printLine(` Standard price: ${result.standard_price}${currency}`);
|
|
57335
57484
|
}
|
|
57336
57485
|
}
|
|
57337
57486
|
} catch (error) {
|
|
57338
|
-
|
|
57487
|
+
printErrorLine(`Availability check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
57339
57488
|
process.exit(1);
|
|
57340
57489
|
}
|
|
57341
57490
|
});
|
|
@@ -57343,6 +57492,7 @@ function registerProviderCommands(program2) {
|
|
|
57343
57492
|
|
|
57344
57493
|
// src/cli/commands/config.ts
|
|
57345
57494
|
init_config();
|
|
57495
|
+
init_stdout();
|
|
57346
57496
|
var VALID_KEYS = [
|
|
57347
57497
|
"default-registrar",
|
|
57348
57498
|
"default-dns",
|
|
@@ -57363,33 +57513,33 @@ function registerConfigCommands(program2) {
|
|
|
57363
57513
|
config2.command("show").description("Show current configuration").option("--json", "Output JSON").action((opts) => {
|
|
57364
57514
|
const cfg = loadConfig3();
|
|
57365
57515
|
if (opts.json) {
|
|
57366
|
-
|
|
57516
|
+
printLine(JSON.stringify(cfg, null, 2));
|
|
57367
57517
|
return;
|
|
57368
57518
|
}
|
|
57369
|
-
|
|
57519
|
+
printLine(`
|
|
57370
57520
|
Configuration:`);
|
|
57371
|
-
|
|
57372
|
-
|
|
57373
|
-
|
|
57521
|
+
printLine(` default-registrar: ${cfg.default_registrar ?? "(not set)"}`);
|
|
57522
|
+
printLine(` default-dns: ${cfg.default_dns ?? "(not set)"}`);
|
|
57523
|
+
printLine(` purchase-aws-profile: ${cfg.purchase_aws_profile ?? "(not set)"}`);
|
|
57374
57524
|
if (cfg.contact && Object.keys(cfg.contact).length > 0) {
|
|
57375
|
-
|
|
57525
|
+
printLine(`
|
|
57376
57526
|
contact:`);
|
|
57377
57527
|
for (const [k4, v2] of Object.entries(cfg.contact)) {
|
|
57378
57528
|
if (v2)
|
|
57379
|
-
|
|
57529
|
+
printLine(` ${k4}: ${v2}`);
|
|
57380
57530
|
}
|
|
57381
57531
|
} else {
|
|
57382
|
-
|
|
57532
|
+
printLine(" contact: (not set)");
|
|
57383
57533
|
}
|
|
57384
|
-
|
|
57534
|
+
printLine();
|
|
57385
57535
|
});
|
|
57386
57536
|
config2.command("set <key> <value>").description(`Set a config value. Keys: ${VALID_KEYS.join(", ")}`).action((key, value) => {
|
|
57387
57537
|
const normalized = key.replace(/-/g, "_");
|
|
57388
57538
|
try {
|
|
57389
57539
|
setConfigKey(normalized, value);
|
|
57390
|
-
|
|
57540
|
+
printLine(`\u2713 Set ${key} = ${value}`);
|
|
57391
57541
|
} catch (e4) {
|
|
57392
|
-
|
|
57542
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
57393
57543
|
process.exit(1);
|
|
57394
57544
|
}
|
|
57395
57545
|
});
|
|
@@ -57403,13 +57553,14 @@ Configuration:`);
|
|
|
57403
57553
|
delete cfg.contact[parts[1]];
|
|
57404
57554
|
}
|
|
57405
57555
|
saveConfig(cfg);
|
|
57406
|
-
|
|
57556
|
+
printLine(`\u2713 Unset ${key}`);
|
|
57407
57557
|
});
|
|
57408
57558
|
}
|
|
57409
57559
|
|
|
57410
57560
|
// src/cli/commands/doctor.ts
|
|
57411
57561
|
init_config();
|
|
57412
57562
|
init_domains();
|
|
57563
|
+
init_stdout();
|
|
57413
57564
|
import { execSync } from "child_process";
|
|
57414
57565
|
function registerDoctorCommand(program2) {
|
|
57415
57566
|
program2.command("doctor").description("Run diagnostics \u2014 check credentials, DB, and provider connectivity").option("--json", "Output structured JSON").action(async (opts) => {
|
|
@@ -57420,22 +57571,22 @@ function registerDoctorCommand(program2) {
|
|
|
57420
57571
|
function section(name) {
|
|
57421
57572
|
currentSection = name;
|
|
57422
57573
|
if (!opts.json) {
|
|
57423
|
-
|
|
57574
|
+
printLine(`
|
|
57424
57575
|
\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
57576
|
}
|
|
57426
57577
|
}
|
|
57427
57578
|
function ok(msg) {
|
|
57428
57579
|
checks.push({ section: currentSection, status: "pass", message: msg });
|
|
57429
57580
|
if (!opts.json)
|
|
57430
|
-
|
|
57581
|
+
printLine(` \u2713 ${msg}`);
|
|
57431
57582
|
passed++;
|
|
57432
57583
|
}
|
|
57433
57584
|
function fail(msg, fix) {
|
|
57434
57585
|
checks.push({ section: currentSection, status: "fail", message: msg, fix });
|
|
57435
57586
|
if (!opts.json) {
|
|
57436
|
-
|
|
57587
|
+
printLine(` \u2717 ${msg}`);
|
|
57437
57588
|
if (fix)
|
|
57438
|
-
|
|
57589
|
+
printLine(` \u2192 ${fix}`);
|
|
57439
57590
|
}
|
|
57440
57591
|
failed++;
|
|
57441
57592
|
}
|
|
@@ -57514,16 +57665,16 @@ function registerDoctorCommand(program2) {
|
|
|
57514
57665
|
fail("whois not installed", "apt install whois / brew install whois");
|
|
57515
57666
|
}
|
|
57516
57667
|
if (opts.json) {
|
|
57517
|
-
|
|
57668
|
+
printLine(JSON.stringify({
|
|
57518
57669
|
passed,
|
|
57519
57670
|
failed,
|
|
57520
57671
|
healthy: failed === 0,
|
|
57521
57672
|
checks
|
|
57522
57673
|
}, null, 2));
|
|
57523
57674
|
} else {
|
|
57524
|
-
|
|
57675
|
+
printLine(`
|
|
57525
57676
|
${"\u2500".repeat(45)}`);
|
|
57526
|
-
|
|
57677
|
+
printLine(` ${passed} passed / ${failed} failed
|
|
57527
57678
|
`);
|
|
57528
57679
|
}
|
|
57529
57680
|
if (failed > 0)
|
|
@@ -57532,6 +57683,7 @@ ${"\u2500".repeat(45)}`);
|
|
|
57532
57683
|
}
|
|
57533
57684
|
|
|
57534
57685
|
// src/cli/commands/mcp-install.ts
|
|
57686
|
+
init_stdout();
|
|
57535
57687
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
57536
57688
|
import { homedir as homedir4 } from "os";
|
|
57537
57689
|
import { dirname as dirname5, join as join4 } from "path";
|
|
@@ -57577,28 +57729,28 @@ function registerMcpCommand(program2) {
|
|
|
57577
57729
|
mcpServers[MCP_SERVER_NAME] = { command: binary, args: [] };
|
|
57578
57730
|
config2.mcpServers = mcpServers;
|
|
57579
57731
|
writeFileSync3(configPath2, JSON.stringify(config2, null, 2), "utf-8");
|
|
57580
|
-
|
|
57581
|
-
|
|
57582
|
-
|
|
57583
|
-
|
|
57732
|
+
printLine(`\u2713 MCP server registered: ${MCP_SERVER_NAME}`);
|
|
57733
|
+
printLine(` Config: ${configPath2}`);
|
|
57734
|
+
printLine(` Binary: ${binary}`);
|
|
57735
|
+
printLine(`
|
|
57584
57736
|
Restart Claude Code to activate.`);
|
|
57585
57737
|
});
|
|
57586
57738
|
mcp.command("uninstall").description("Remove domains MCP server from Claude Code config").option("--project", "Remove from project config instead of global").action((opts) => {
|
|
57587
57739
|
const paths = getClaudeConfigPaths();
|
|
57588
57740
|
const configPath2 = opts.project ? paths.project : paths.global;
|
|
57589
57741
|
if (!existsSync3(configPath2)) {
|
|
57590
|
-
|
|
57742
|
+
printLine("Config file not found \u2014 nothing to remove.");
|
|
57591
57743
|
return;
|
|
57592
57744
|
}
|
|
57593
57745
|
const config2 = readConfig(configPath2);
|
|
57594
57746
|
const mcpServers = config2.mcpServers;
|
|
57595
57747
|
if (!mcpServers?.[MCP_SERVER_NAME]) {
|
|
57596
|
-
|
|
57748
|
+
printLine(`MCP server '${MCP_SERVER_NAME}' is not registered.`);
|
|
57597
57749
|
return;
|
|
57598
57750
|
}
|
|
57599
57751
|
delete mcpServers[MCP_SERVER_NAME];
|
|
57600
57752
|
writeFileSync3(configPath2, JSON.stringify(config2, null, 2), "utf-8");
|
|
57601
|
-
|
|
57753
|
+
printLine(`\u2713 MCP server removed: ${MCP_SERVER_NAME}`);
|
|
57602
57754
|
});
|
|
57603
57755
|
mcp.command("status").description("Check if domains MCP server is registered").option("-j, --json", "Output JSON").action((opts) => {
|
|
57604
57756
|
const paths = getClaudeConfigPaths();
|
|
@@ -57628,22 +57780,22 @@ function registerMcpCommand(program2) {
|
|
|
57628
57780
|
}
|
|
57629
57781
|
}
|
|
57630
57782
|
if (opts.json) {
|
|
57631
|
-
|
|
57783
|
+
printLine(JSON.stringify({ server: MCP_SERVER_NAME, checks: status }, null, 2));
|
|
57632
57784
|
return;
|
|
57633
57785
|
}
|
|
57634
57786
|
for (const item of status) {
|
|
57635
57787
|
if (!item.exists) {
|
|
57636
|
-
|
|
57788
|
+
printLine(` ${item.scope}: not found`);
|
|
57637
57789
|
continue;
|
|
57638
57790
|
}
|
|
57639
57791
|
if (item.error) {
|
|
57640
|
-
|
|
57792
|
+
printLine(` ${item.scope}: error reading config`);
|
|
57641
57793
|
continue;
|
|
57642
57794
|
}
|
|
57643
57795
|
if (item.registered) {
|
|
57644
|
-
|
|
57796
|
+
printLine(` ${item.scope}: \u2713 registered`);
|
|
57645
57797
|
} else {
|
|
57646
|
-
|
|
57798
|
+
printLine(` ${item.scope}: \u2717 not registered`);
|
|
57647
57799
|
}
|
|
57648
57800
|
}
|
|
57649
57801
|
});
|
|
@@ -57652,6 +57804,7 @@ function registerMcpCommand(program2) {
|
|
|
57652
57804
|
// src/cli/commands/serve.ts
|
|
57653
57805
|
init_domains();
|
|
57654
57806
|
init_version();
|
|
57807
|
+
init_stdout();
|
|
57655
57808
|
function registerServeCommand(program2) {
|
|
57656
57809
|
const packageVersion = getPackageVersion();
|
|
57657
57810
|
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 +57872,16 @@ function registerServeCommand(program2) {
|
|
|
57719
57872
|
}
|
|
57720
57873
|
}
|
|
57721
57874
|
});
|
|
57722
|
-
|
|
57723
|
-
|
|
57724
|
-
|
|
57725
|
-
|
|
57726
|
-
|
|
57727
|
-
|
|
57728
|
-
|
|
57729
|
-
|
|
57730
|
-
|
|
57731
|
-
|
|
57875
|
+
printLine(`\u2713 domains API server running at http://${opts.host}:${port}`);
|
|
57876
|
+
printLine(` GET /health`);
|
|
57877
|
+
printLine(` GET /domains`);
|
|
57878
|
+
printLine(` POST /domains`);
|
|
57879
|
+
printLine(` GET /domains/:id`);
|
|
57880
|
+
printLine(` PUT /domains/:id`);
|
|
57881
|
+
printLine(` DELETE /domains/:id`);
|
|
57882
|
+
printLine(` GET /domains/:id/dns`);
|
|
57883
|
+
printLine(` POST /domains/:id/dns`);
|
|
57884
|
+
printLine(`
|
|
57732
57885
|
Press Ctrl+C to stop.`);
|
|
57733
57886
|
await new Promise(() => {});
|
|
57734
57887
|
});
|
|
@@ -58104,6 +58257,7 @@ async function runMigrations(opts = {}) {
|
|
|
58104
58257
|
}
|
|
58105
58258
|
|
|
58106
58259
|
// src/cli/commands/db.ts
|
|
58260
|
+
init_stdout();
|
|
58107
58261
|
function registerDbCommands(program2) {
|
|
58108
58262
|
const db = program2.command("db").description("Cloud database migrations (Postgres / RDS)");
|
|
58109
58263
|
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 +58266,22 @@ function registerDbCommands(program2) {
|
|
|
58112
58266
|
const pending = result.plan.filter((p2) => p2.state === "pending").map((p2) => p2.migration.id);
|
|
58113
58267
|
const applied = result.applied.map((a4) => a4.id);
|
|
58114
58268
|
if (opts.json) {
|
|
58115
|
-
|
|
58269
|
+
printLine(JSON.stringify({ ok: true, dryRun: result.dryRun, pending, applied }, null, 2));
|
|
58116
58270
|
} else if (result.dryRun) {
|
|
58117
|
-
|
|
58271
|
+
printLine(`Dry run \u2014 ${pending.length} pending migration(s):`);
|
|
58118
58272
|
for (const id of pending)
|
|
58119
|
-
|
|
58273
|
+
printLine(` \u2022 ${id}`);
|
|
58120
58274
|
if (pending.length === 0)
|
|
58121
|
-
|
|
58275
|
+
printLine(" (schema up to date)");
|
|
58122
58276
|
} else {
|
|
58123
|
-
|
|
58277
|
+
printLine(`\u2713 migrations applied \u2014 ${applied.length} total, ${pending.length} were pending`);
|
|
58124
58278
|
}
|
|
58125
58279
|
} catch (e4) {
|
|
58126
58280
|
const msg = e4 instanceof Error ? e4.message : String(e4);
|
|
58127
58281
|
if (opts.json)
|
|
58128
|
-
|
|
58282
|
+
printLine(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
58129
58283
|
else
|
|
58130
|
-
|
|
58284
|
+
printErrorLine(`\u2717 migration failed: ${msg}`);
|
|
58131
58285
|
process.exitCode = 1;
|
|
58132
58286
|
}
|
|
58133
58287
|
});
|
|
@@ -58137,18 +58291,18 @@ function registerDbCommands(program2) {
|
|
|
58137
58291
|
const pending = result.plan.filter((p2) => p2.state === "pending").map((p2) => p2.migration.id);
|
|
58138
58292
|
const applied = result.applied.map((a4) => a4.id);
|
|
58139
58293
|
if (opts.json) {
|
|
58140
|
-
|
|
58294
|
+
printLine(JSON.stringify({ ok: true, pending, applied }, null, 2));
|
|
58141
58295
|
} else {
|
|
58142
|
-
|
|
58296
|
+
printLine(`Applied: ${applied.length} Pending: ${pending.length}`);
|
|
58143
58297
|
for (const id of pending)
|
|
58144
|
-
|
|
58298
|
+
printLine(` pending: ${id}`);
|
|
58145
58299
|
}
|
|
58146
58300
|
} catch (e4) {
|
|
58147
58301
|
const msg = e4 instanceof Error ? e4.message : String(e4);
|
|
58148
58302
|
if (opts.json)
|
|
58149
|
-
|
|
58303
|
+
printLine(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
58150
58304
|
else
|
|
58151
|
-
|
|
58305
|
+
printErrorLine(`\u2717 ${msg}`);
|
|
58152
58306
|
process.exitCode = 1;
|
|
58153
58307
|
}
|
|
58154
58308
|
});
|
|
@@ -58197,6 +58351,7 @@ async function setupDomainZone(domain, deps) {
|
|
|
58197
58351
|
// src/cli/commands/route53.ts
|
|
58198
58352
|
init_domains();
|
|
58199
58353
|
init_config();
|
|
58354
|
+
init_stdout();
|
|
58200
58355
|
function registerRoute53Commands(program2) {
|
|
58201
58356
|
const r53 = program2.command("r53").description("AWS Route 53 \u2014 domain purchase, hosted zones & DNS");
|
|
58202
58357
|
r53.command("check <domains...>").description("Check if one or more domains are available for purchase").action(async (domains) => {
|
|
@@ -58207,7 +58362,7 @@ function registerRoute53Commands(program2) {
|
|
|
58207
58362
|
const r4 = results[i4];
|
|
58208
58363
|
if (r4.status === "rejected") {
|
|
58209
58364
|
const reason = r4.reason;
|
|
58210
|
-
|
|
58365
|
+
printErrorLine(`\u2717 ${domains[i4]}: ${reason instanceof Error ? reason.message : String(reason)}`);
|
|
58211
58366
|
anyError = true;
|
|
58212
58367
|
continue;
|
|
58213
58368
|
}
|
|
@@ -58218,15 +58373,15 @@ function registerRoute53Commands(program2) {
|
|
|
58218
58373
|
const ren = result.renewal_price ? `renew ${cur} ${result.renewal_price}` : "";
|
|
58219
58374
|
const xfr = result.transfer_price ? `transfer ${cur} ${result.transfer_price}` : "";
|
|
58220
58375
|
const pricing = [reg, ren, xfr].filter(Boolean).join(" / ");
|
|
58221
|
-
|
|
58376
|
+
printLine(`\u2713 ${result.domain} is available${pricing ? ` (${pricing})` : ""}`);
|
|
58222
58377
|
} else {
|
|
58223
|
-
|
|
58378
|
+
printLine(`\u2717 ${result.domain} is not available`);
|
|
58224
58379
|
}
|
|
58225
58380
|
}
|
|
58226
58381
|
if (anyError)
|
|
58227
58382
|
process.exit(1);
|
|
58228
58383
|
} catch (e4) {
|
|
58229
|
-
|
|
58384
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58230
58385
|
process.exit(1);
|
|
58231
58386
|
}
|
|
58232
58387
|
});
|
|
@@ -58234,36 +58389,36 @@ function registerRoute53Commands(program2) {
|
|
|
58234
58389
|
try {
|
|
58235
58390
|
const avail = await checkAvailability3(domain);
|
|
58236
58391
|
if (!avail.available) {
|
|
58237
|
-
|
|
58392
|
+
printErrorLine(`\u2717 ${domain} is not available for registration`);
|
|
58238
58393
|
process.exit(1);
|
|
58239
58394
|
}
|
|
58240
58395
|
let contact;
|
|
58241
58396
|
try {
|
|
58242
58397
|
contact = resolveContact(opts);
|
|
58243
58398
|
} catch (e4) {
|
|
58244
|
-
|
|
58399
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58245
58400
|
process.exit(1);
|
|
58246
58401
|
}
|
|
58247
|
-
|
|
58402
|
+
printLine(`Registering ${domain}...`);
|
|
58248
58403
|
const result = await registerDomain2(domain, contact, parseInt(opts.years), opts.autoRenew);
|
|
58249
|
-
|
|
58250
|
-
|
|
58251
|
-
|
|
58404
|
+
printLine(`\u2713 Registration submitted: ${domain}`);
|
|
58405
|
+
printLine(` Operation ID: ${result.operationId}`);
|
|
58406
|
+
printLine(` Check status: domains r53 status ${result.operationId}`);
|
|
58252
58407
|
} catch (e4) {
|
|
58253
|
-
|
|
58408
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58254
58409
|
process.exit(1);
|
|
58255
58410
|
}
|
|
58256
58411
|
});
|
|
58257
58412
|
r53.command("status <operationId>").description("Check domain registration status").action(async (operationId) => {
|
|
58258
58413
|
try {
|
|
58259
58414
|
const result = await getRegistrationStatus(operationId);
|
|
58260
|
-
|
|
58415
|
+
printLine(`Status: ${result.status}`);
|
|
58261
58416
|
if (result.domain)
|
|
58262
|
-
|
|
58417
|
+
printLine(`Domain: ${result.domain}`);
|
|
58263
58418
|
if (result.message)
|
|
58264
|
-
|
|
58419
|
+
printLine(`Message: ${result.message}`);
|
|
58265
58420
|
} catch (e4) {
|
|
58266
|
-
|
|
58421
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58267
58422
|
process.exit(1);
|
|
58268
58423
|
}
|
|
58269
58424
|
});
|
|
@@ -58271,26 +58426,26 @@ function registerRoute53Commands(program2) {
|
|
|
58271
58426
|
try {
|
|
58272
58427
|
const domains = await listRegisteredDomains();
|
|
58273
58428
|
if (opts.json) {
|
|
58274
|
-
|
|
58429
|
+
printLine(JSON.stringify(domains, null, 2));
|
|
58275
58430
|
return;
|
|
58276
58431
|
}
|
|
58277
58432
|
const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
|
|
58278
58433
|
if (page.items.length === 0) {
|
|
58279
|
-
|
|
58434
|
+
printLine("No registered domains.");
|
|
58280
58435
|
return;
|
|
58281
58436
|
}
|
|
58282
|
-
|
|
58437
|
+
printLine(`
|
|
58283
58438
|
Registered Domains:`);
|
|
58284
58439
|
for (const d4 of page.items) {
|
|
58285
58440
|
const expiry = d4.expiry ? ` (expires ${d4.expiry.split("T")[0]})` : "";
|
|
58286
58441
|
const renew = d4.auto_renew ? " [auto-renew]" : "";
|
|
58287
58442
|
const lock = d4.transfer_lock ? " [locked]" : "";
|
|
58288
|
-
|
|
58443
|
+
printLine(` ${d4.domain}${expiry}${renew}${lock}`);
|
|
58289
58444
|
}
|
|
58290
|
-
|
|
58445
|
+
printLine(`
|
|
58291
58446
|
${compactHint(page, "domain(s)", "Use --all for every Route53 domain or r53 domain-info <domain> for details.", { paging: "limit" })}`);
|
|
58292
58447
|
} catch (e4) {
|
|
58293
|
-
|
|
58448
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58294
58449
|
process.exit(1);
|
|
58295
58450
|
}
|
|
58296
58451
|
});
|
|
@@ -58298,41 +58453,41 @@ ${compactHint(page, "domain(s)", "Use --all for every Route53 domain or r53 doma
|
|
|
58298
58453
|
try {
|
|
58299
58454
|
const detail = await getDomainDetail(domain);
|
|
58300
58455
|
if (opts.json) {
|
|
58301
|
-
|
|
58456
|
+
printLine(JSON.stringify(detail, null, 2));
|
|
58302
58457
|
return;
|
|
58303
58458
|
}
|
|
58304
|
-
|
|
58459
|
+
printLine(`
|
|
58305
58460
|
Domain: ${detail.domain}`);
|
|
58306
|
-
|
|
58307
|
-
|
|
58308
|
-
|
|
58309
|
-
|
|
58461
|
+
printLine(` Created: ${detail.created ? detail.created.split("T")[0] : "\u2014"}`);
|
|
58462
|
+
printLine(` Expires: ${detail.expiry ? detail.expiry.split("T")[0] : "\u2014"}`);
|
|
58463
|
+
printLine(` Auto-renew: ${detail.auto_renew ? "yes" : "no"}`);
|
|
58464
|
+
printLine(` Transfer lock: ${detail.transfer_lock ? "yes" : "no"}`);
|
|
58310
58465
|
if (detail.nameservers.length > 0) {
|
|
58311
|
-
|
|
58466
|
+
printLine(` Name servers:`);
|
|
58312
58467
|
for (const ns of detail.nameservers)
|
|
58313
|
-
|
|
58468
|
+
printLine(` ${ns}`);
|
|
58314
58469
|
}
|
|
58315
|
-
|
|
58470
|
+
printLine();
|
|
58316
58471
|
} catch (e4) {
|
|
58317
|
-
|
|
58472
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58318
58473
|
process.exit(1);
|
|
58319
58474
|
}
|
|
58320
58475
|
});
|
|
58321
58476
|
r53.command("zone-create <domain>").description("Create a hosted zone").option("--comment <text>", "Zone comment").action(async (domain, opts) => {
|
|
58322
58477
|
try {
|
|
58323
58478
|
const zone = await createHostedZone(domain, opts.comment);
|
|
58324
|
-
|
|
58325
|
-
|
|
58479
|
+
printLine(`\u2713 Hosted zone created: ${domain}`);
|
|
58480
|
+
printLine(` Zone ID: ${zone.id}`);
|
|
58326
58481
|
if (zone.name_servers && zone.name_servers.length > 0) {
|
|
58327
|
-
|
|
58482
|
+
printLine(`
|
|
58328
58483
|
Name servers (set at your registrar):`);
|
|
58329
58484
|
for (const ns of zone.name_servers) {
|
|
58330
|
-
|
|
58485
|
+
printLine(` ${ns}`);
|
|
58331
58486
|
}
|
|
58332
58487
|
}
|
|
58333
|
-
|
|
58488
|
+
printLine();
|
|
58334
58489
|
} catch (e4) {
|
|
58335
|
-
|
|
58490
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58336
58491
|
process.exit(1);
|
|
58337
58492
|
}
|
|
58338
58493
|
});
|
|
@@ -58340,24 +58495,24 @@ Domain: ${detail.domain}`);
|
|
|
58340
58495
|
try {
|
|
58341
58496
|
const zones = await listHostedZones();
|
|
58342
58497
|
if (opts.json) {
|
|
58343
|
-
|
|
58498
|
+
printLine(JSON.stringify(zones, null, 2));
|
|
58344
58499
|
return;
|
|
58345
58500
|
}
|
|
58346
58501
|
const page = pageItemsOrExit(zones, { limit: opts.limit, all: opts.all });
|
|
58347
58502
|
if (page.items.length === 0) {
|
|
58348
|
-
|
|
58503
|
+
printLine("No hosted zones.");
|
|
58349
58504
|
return;
|
|
58350
58505
|
}
|
|
58351
|
-
|
|
58506
|
+
printLine(`
|
|
58352
58507
|
Hosted Zones:`);
|
|
58353
58508
|
for (const z of page.items) {
|
|
58354
58509
|
const comment = z.comment ? ` \u2014 ${truncateText(z.comment, 60)}` : "";
|
|
58355
|
-
|
|
58510
|
+
printLine(` ${z.id} ${z.name} ${z.record_count} records${comment}`);
|
|
58356
58511
|
}
|
|
58357
|
-
|
|
58512
|
+
printLine(`
|
|
58358
58513
|
${compactHint(page, "zone(s)", "Use --all for every zone or r53 zone-info <zoneId> for details.", { paging: "limit" })}`);
|
|
58359
58514
|
} catch (e4) {
|
|
58360
|
-
|
|
58515
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58361
58516
|
process.exit(1);
|
|
58362
58517
|
}
|
|
58363
58518
|
});
|
|
@@ -58365,24 +58520,24 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or r53 zone-info <zoneI
|
|
|
58365
58520
|
try {
|
|
58366
58521
|
const zone = await getHostedZone(zoneId);
|
|
58367
58522
|
if (opts.json) {
|
|
58368
|
-
|
|
58523
|
+
printLine(JSON.stringify(zone, null, 2));
|
|
58369
58524
|
return;
|
|
58370
58525
|
}
|
|
58371
|
-
|
|
58526
|
+
printLine(`
|
|
58372
58527
|
Hosted Zone: ${zone.name}`);
|
|
58373
|
-
|
|
58374
|
-
|
|
58528
|
+
printLine(` ID: ${zone.id}`);
|
|
58529
|
+
printLine(` Records: ${zone.record_count}`);
|
|
58375
58530
|
if (zone.comment)
|
|
58376
|
-
|
|
58531
|
+
printLine(` Comment: ${zone.comment}`);
|
|
58377
58532
|
if (zone.name_servers && zone.name_servers.length > 0) {
|
|
58378
|
-
|
|
58533
|
+
printLine(` Name servers:`);
|
|
58379
58534
|
for (const ns of zone.name_servers) {
|
|
58380
|
-
|
|
58535
|
+
printLine(` ${ns}`);
|
|
58381
58536
|
}
|
|
58382
58537
|
}
|
|
58383
|
-
|
|
58538
|
+
printLine();
|
|
58384
58539
|
} catch (e4) {
|
|
58385
|
-
|
|
58540
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58386
58541
|
process.exit(1);
|
|
58387
58542
|
}
|
|
58388
58543
|
});
|
|
@@ -58390,18 +58545,18 @@ Hosted Zone: ${zone.name}`);
|
|
|
58390
58545
|
try {
|
|
58391
58546
|
const zone = await getHostedZone(zoneId);
|
|
58392
58547
|
if (!opts.force) {
|
|
58393
|
-
|
|
58394
|
-
|
|
58395
|
-
|
|
58396
|
-
|
|
58397
|
-
|
|
58548
|
+
printLine(`Would delete hosted zone:`);
|
|
58549
|
+
printLine(` ID: ${zone.id}`);
|
|
58550
|
+
printLine(` Domain: ${zone.name}`);
|
|
58551
|
+
printLine(` Records: ${zone.record_count}`);
|
|
58552
|
+
printLine(`
|
|
58398
58553
|
This is irreversible. Re-run with --force to confirm.`);
|
|
58399
58554
|
process.exit(0);
|
|
58400
58555
|
}
|
|
58401
58556
|
await deleteHostedZone(zoneId);
|
|
58402
|
-
|
|
58557
|
+
printLine(`\u2713 Hosted zone deleted: ${zone.name} (${zone.id})`);
|
|
58403
58558
|
} catch (e4) {
|
|
58404
|
-
|
|
58559
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58405
58560
|
process.exit(1);
|
|
58406
58561
|
}
|
|
58407
58562
|
});
|
|
@@ -58409,30 +58564,30 @@ This is irreversible. Re-run with --force to confirm.`);
|
|
|
58409
58564
|
try {
|
|
58410
58565
|
const zone = await findHostedZoneByDomain(domain);
|
|
58411
58566
|
if (!zone) {
|
|
58412
|
-
|
|
58567
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58413
58568
|
process.exit(1);
|
|
58414
58569
|
}
|
|
58415
58570
|
const records = await listRecords(zone.id);
|
|
58416
58571
|
if (opts.json) {
|
|
58417
|
-
|
|
58572
|
+
printLine(JSON.stringify(records, null, 2));
|
|
58418
58573
|
return;
|
|
58419
58574
|
}
|
|
58420
58575
|
const page = pageItemsOrExit(records, { limit: opts.limit, all: opts.all });
|
|
58421
58576
|
if (page.items.length === 0) {
|
|
58422
|
-
|
|
58577
|
+
printLine("No records.");
|
|
58423
58578
|
return;
|
|
58424
58579
|
}
|
|
58425
|
-
|
|
58580
|
+
printLine(`
|
|
58426
58581
|
DNS Records for ${domain}:`);
|
|
58427
58582
|
for (const r4 of page.items) {
|
|
58428
58583
|
const val = r4.alias_target ? `ALIAS \u2192 ${r4.alias_target.dns_name}` : truncateText(r4.values.join(", "), 90);
|
|
58429
58584
|
const ttl = r4.alias_target ? "" : ` TTL:${r4.ttl}`;
|
|
58430
|
-
|
|
58585
|
+
printLine(` ${r4.type.padEnd(6)} ${r4.name.padEnd(40)}${ttl} ${val}`);
|
|
58431
58586
|
}
|
|
58432
|
-
|
|
58587
|
+
printLine(`
|
|
58433
58588
|
${compactHint(page, "record(s)", "Use --all for every record or --json for full values.", { paging: "limit" })}`);
|
|
58434
58589
|
} catch (e4) {
|
|
58435
|
-
|
|
58590
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58436
58591
|
process.exit(1);
|
|
58437
58592
|
}
|
|
58438
58593
|
});
|
|
@@ -58443,20 +58598,20 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58443
58598
|
try {
|
|
58444
58599
|
const isAlias = !!(opts.aliasZone && opts.aliasDns);
|
|
58445
58600
|
if (!isAlias && (!opts.value || opts.value.length === 0)) {
|
|
58446
|
-
|
|
58601
|
+
printErrorLine("Error: provide --value (repeatable) or both --alias-zone and --alias-dns");
|
|
58447
58602
|
process.exit(1);
|
|
58448
58603
|
}
|
|
58449
58604
|
const zone = await findHostedZoneByDomain(domain);
|
|
58450
58605
|
if (!zone) {
|
|
58451
|
-
|
|
58606
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58452
58607
|
process.exit(1);
|
|
58453
58608
|
}
|
|
58454
58609
|
const aliasTarget = isAlias ? { hosted_zone_id: opts.aliasZone, dns_name: opts.aliasDns } : undefined;
|
|
58455
58610
|
await upsertRecord(zone.id, { name: opts.name, type: opts.type, ttl: parseInt(opts.ttl), values: opts.value, alias_target: aliasTarget });
|
|
58456
58611
|
const desc = isAlias ? `alias \u2192 ${opts.aliasDns}` : `${opts.value.length} value(s)`;
|
|
58457
|
-
|
|
58612
|
+
printLine(`\u2713 Record upserted: ${opts.type} ${opts.name} (${desc})`);
|
|
58458
58613
|
} catch (e4) {
|
|
58459
|
-
|
|
58614
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58460
58615
|
process.exit(1);
|
|
58461
58616
|
}
|
|
58462
58617
|
});
|
|
@@ -58464,14 +58619,14 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58464
58619
|
try {
|
|
58465
58620
|
const zone = await findHostedZoneByDomain(domain);
|
|
58466
58621
|
if (!zone) {
|
|
58467
|
-
|
|
58622
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58468
58623
|
process.exit(1);
|
|
58469
58624
|
}
|
|
58470
58625
|
const records = await listRecords(zone.id);
|
|
58471
58626
|
const normName = opts.name.endsWith(".") ? opts.name : `${opts.name}.`;
|
|
58472
58627
|
const existing = records.find((r4) => r4.type === opts.type.toUpperCase() && (r4.name === opts.name || r4.name === normName));
|
|
58473
58628
|
if (!existing) {
|
|
58474
|
-
|
|
58629
|
+
printErrorLine(`\u2717 No ${opts.type} record found for ${opts.name} in zone ${domain}`);
|
|
58475
58630
|
process.exit(1);
|
|
58476
58631
|
}
|
|
58477
58632
|
await deleteRecord(zone.id, {
|
|
@@ -58481,9 +58636,9 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58481
58636
|
values: existing.values,
|
|
58482
58637
|
alias_target: existing.alias_target
|
|
58483
58638
|
});
|
|
58484
|
-
|
|
58639
|
+
printLine(`\u2713 Record deleted: ${existing.type} ${existing.name}`);
|
|
58485
58640
|
} catch (e4) {
|
|
58486
|
-
|
|
58641
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58487
58642
|
process.exit(1);
|
|
58488
58643
|
}
|
|
58489
58644
|
});
|
|
@@ -58493,23 +58648,23 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58493
58648
|
try {
|
|
58494
58649
|
raw = readFileSync7(opts.file, "utf-8");
|
|
58495
58650
|
} catch {
|
|
58496
|
-
|
|
58651
|
+
printErrorLine(`Could not read file: ${opts.file}`);
|
|
58497
58652
|
process.exit(1);
|
|
58498
58653
|
}
|
|
58499
58654
|
const records = JSON.parse(raw);
|
|
58500
58655
|
if (!Array.isArray(records)) {
|
|
58501
|
-
|
|
58656
|
+
printErrorLine("JSON file must be an array of record objects");
|
|
58502
58657
|
process.exit(1);
|
|
58503
58658
|
}
|
|
58504
58659
|
const zone = await findHostedZoneByDomain(domain);
|
|
58505
58660
|
if (!zone) {
|
|
58506
|
-
|
|
58661
|
+
printErrorLine(`No hosted zone found for ${domain}`);
|
|
58507
58662
|
process.exit(1);
|
|
58508
58663
|
}
|
|
58509
58664
|
await upsertRecords(zone.id, records);
|
|
58510
|
-
|
|
58665
|
+
printLine(`\u2713 Upserted ${records.length} record(s) in ${domain}`);
|
|
58511
58666
|
} catch (e4) {
|
|
58512
|
-
|
|
58667
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58513
58668
|
process.exit(1);
|
|
58514
58669
|
}
|
|
58515
58670
|
});
|
|
@@ -58521,36 +58676,36 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58521
58676
|
createDomain: createDomain2,
|
|
58522
58677
|
updateDomain: updateDomain2
|
|
58523
58678
|
});
|
|
58524
|
-
|
|
58679
|
+
printLine(`\u2713 Synced ${result.synced} domains (${result.created} new, ${result.updated} updated)`);
|
|
58525
58680
|
if (result.errors.length > 0) {
|
|
58526
|
-
|
|
58681
|
+
printLine(` Errors: ${result.errors.join(", ")}`);
|
|
58527
58682
|
}
|
|
58528
58683
|
} catch (e4) {
|
|
58529
|
-
|
|
58684
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58530
58685
|
process.exit(1);
|
|
58531
58686
|
}
|
|
58532
58687
|
});
|
|
58533
58688
|
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
58689
|
try {
|
|
58535
|
-
|
|
58690
|
+
printLine(`[1/4] Checking availability...`);
|
|
58536
58691
|
const avail = await checkAvailability3(domain);
|
|
58537
58692
|
if (!avail.available) {
|
|
58538
|
-
|
|
58693
|
+
printErrorLine(`\u2717 ${domain} is not available`);
|
|
58539
58694
|
process.exit(1);
|
|
58540
58695
|
}
|
|
58541
58696
|
const price = avail.price ? ` (${avail.currency ?? "USD"} ${avail.price}/yr)` : "";
|
|
58542
|
-
|
|
58543
|
-
|
|
58697
|
+
printLine(` \u2713 Available${price}`);
|
|
58698
|
+
printLine(`[2/4] Registering domain...`);
|
|
58544
58699
|
let contact;
|
|
58545
58700
|
try {
|
|
58546
58701
|
contact = resolveContact(opts);
|
|
58547
58702
|
} catch (e4) {
|
|
58548
|
-
|
|
58703
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58549
58704
|
process.exit(1);
|
|
58550
58705
|
}
|
|
58551
58706
|
const reg = await registerDomain2(domain, contact, parseInt(opts.years));
|
|
58552
|
-
|
|
58553
|
-
|
|
58707
|
+
printLine(` \u2713 Submitted (operation: ${reg.operationId})`);
|
|
58708
|
+
printLine(` Waiting for registration to complete...`);
|
|
58554
58709
|
let status = "IN_PROGRESS";
|
|
58555
58710
|
while (status === "IN_PROGRESS" || status === "SUBMITTED") {
|
|
58556
58711
|
await new Promise((r4) => setTimeout(r4, 1e4));
|
|
@@ -58558,13 +58713,13 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58558
58713
|
status = s2.status;
|
|
58559
58714
|
process.stdout.write(` Status: ${status}\r`);
|
|
58560
58715
|
}
|
|
58561
|
-
|
|
58716
|
+
printLine();
|
|
58562
58717
|
if (status !== "SUCCESSFUL") {
|
|
58563
|
-
|
|
58718
|
+
printErrorLine(`\u2717 Registration ${status}`);
|
|
58564
58719
|
process.exit(1);
|
|
58565
58720
|
}
|
|
58566
|
-
|
|
58567
|
-
|
|
58721
|
+
printLine(` \u2713 Registration complete`);
|
|
58722
|
+
printLine(`[3/4] Configuring hosted zone...`);
|
|
58568
58723
|
const setup = await setupDomainZone(domain, {
|
|
58569
58724
|
findExistingZone: async (d4) => {
|
|
58570
58725
|
const z = await findHostedZoneByDomain(d4);
|
|
@@ -58582,8 +58737,8 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58582
58737
|
await updateNameservers2(d4, ns);
|
|
58583
58738
|
}
|
|
58584
58739
|
});
|
|
58585
|
-
|
|
58586
|
-
|
|
58740
|
+
printLine(` \u2713 Zone ${setup.created ? "created" : "reused"} (${setup.zoneId})` + (setup.nsUpdated ? ` \u2014 registry NS repointed to this zone` : ``));
|
|
58741
|
+
printLine(`[4/4] Adding to local database...`);
|
|
58587
58742
|
createDomain2({
|
|
58588
58743
|
name: domain,
|
|
58589
58744
|
registrar: "AWS Route 53",
|
|
@@ -58591,20 +58746,20 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
|
|
|
58591
58746
|
auto_renew: true,
|
|
58592
58747
|
nameservers: setup.nameServers
|
|
58593
58748
|
});
|
|
58594
|
-
|
|
58595
|
-
|
|
58749
|
+
printLine(` \u2713 Added to portfolio`);
|
|
58750
|
+
printLine(`
|
|
58596
58751
|
\u2713 Full setup complete for ${domain}`);
|
|
58597
|
-
|
|
58752
|
+
printLine(` Check: domains r53 status ${reg.operationId}`);
|
|
58598
58753
|
if (setup.nameServers && setup.nameServers.length > 0) {
|
|
58599
|
-
|
|
58754
|
+
printLine(`
|
|
58600
58755
|
Name servers:`);
|
|
58601
58756
|
for (const ns of setup.nameServers) {
|
|
58602
|
-
|
|
58757
|
+
printLine(` ${ns}`);
|
|
58603
58758
|
}
|
|
58604
58759
|
}
|
|
58605
|
-
|
|
58760
|
+
printLine();
|
|
58606
58761
|
} catch (e4) {
|
|
58607
|
-
|
|
58762
|
+
printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
58608
58763
|
process.exit(1);
|
|
58609
58764
|
}
|
|
58610
58765
|
});
|
|
@@ -58971,6 +59126,7 @@ function coverageRegressions(current, baseline) {
|
|
|
58971
59126
|
}
|
|
58972
59127
|
|
|
58973
59128
|
// src/cli/commands/reconcile-expiry.ts
|
|
59129
|
+
init_stdout();
|
|
58974
59130
|
var IANA_RDAP_BOOTSTRAP = "https://data.iana.org/rdap/dns.json";
|
|
58975
59131
|
var TLD_WHOIS = {
|
|
58976
59132
|
ag: "whois.nic.ag",
|
|
@@ -59065,18 +59221,18 @@ function registerReconcileExpiryCommand(program2) {
|
|
|
59065
59221
|
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
59222
|
const arm = prearm();
|
|
59067
59223
|
if (!opts.json) {
|
|
59068
|
-
|
|
59224
|
+
printLine("=== PRE-ARM SELF-TEST (two-sided) ===");
|
|
59069
59225
|
for (const c4 of arm.cases)
|
|
59070
|
-
|
|
59071
|
-
|
|
59226
|
+
printLine(` [${c4.passed ? "PASS" : "FAIL"}] ${c4.name.padEnd(58)} -> ${c4.got}`);
|
|
59227
|
+
printLine(`=== PRE-ARM ${arm.ok ? "PASS - instrument can fire AND can stay silent" : "FAIL - DO NOT TRUST ANY RESULT"} ===`);
|
|
59072
59228
|
}
|
|
59073
59229
|
if (!arm.ok) {
|
|
59074
|
-
|
|
59230
|
+
printErrorLine("REFUSING TO RUN: pre-arm failed.");
|
|
59075
59231
|
process.exit(3);
|
|
59076
59232
|
}
|
|
59077
59233
|
if (opts.selfTest) {
|
|
59078
59234
|
if (opts.json)
|
|
59079
|
-
|
|
59235
|
+
printLine(JSON.stringify({ prearm: arm }, null, 2));
|
|
59080
59236
|
process.exit(0);
|
|
59081
59237
|
}
|
|
59082
59238
|
let rows;
|
|
@@ -59084,8 +59240,8 @@ function registerReconcileExpiryCommand(program2) {
|
|
|
59084
59240
|
rows = await loadRows(opts);
|
|
59085
59241
|
} catch (e4) {
|
|
59086
59242
|
const configured = getAvailableProviders().filter((p2) => p2.configured).map((p2) => p2.name).join(", ") || "none";
|
|
59087
|
-
|
|
59088
|
-
|
|
59243
|
+
printErrorLine(`${e4 instanceof Error ? e4.message : String(e4)}`);
|
|
59244
|
+
printErrorLine(`configured providers: ${configured}`);
|
|
59089
59245
|
process.exit(2);
|
|
59090
59246
|
return;
|
|
59091
59247
|
}
|
|
@@ -59124,9 +59280,9 @@ function registerReconcileExpiryCommand(program2) {
|
|
|
59124
59280
|
}
|
|
59125
59281
|
};
|
|
59126
59282
|
if (!opts.json) {
|
|
59127
|
-
|
|
59283
|
+
printLine(`
|
|
59128
59284
|
REGISTRAR rows=${rows.length} unique=${unique.length} dupes_removed=${dupesRemoved}`);
|
|
59129
|
-
|
|
59285
|
+
printLine(`SELECTED=${selected.length}`);
|
|
59130
59286
|
}
|
|
59131
59287
|
const report = await reconcileExpiry(selected, deps);
|
|
59132
59288
|
let regressed = [];
|
|
@@ -59137,40 +59293,40 @@ REGISTRAR rows=${rows.length} unique=${unique.length} dupes_removed=${dupesRemov
|
|
|
59137
59293
|
report.exitCode = Math.max(report.exitCode, 2);
|
|
59138
59294
|
}
|
|
59139
59295
|
if (opts.json) {
|
|
59140
|
-
|
|
59296
|
+
printLine(JSON.stringify({ ...report, coverageRegressions: regressed, queries }, null, 2));
|
|
59141
59297
|
process.exit(report.exitCode);
|
|
59142
59298
|
return;
|
|
59143
59299
|
}
|
|
59144
59300
|
const order = ["MATCH", "MISMATCH", "NOT_AT_REGISTRY", "UNVERIFIABLE_EXPECTED", "UNVERIFIABLE_UNEXPECTED"];
|
|
59145
|
-
|
|
59301
|
+
printLine(`
|
|
59146
59302
|
=== VERDICT TALLY (n=${report.records.length}) ===`);
|
|
59147
59303
|
for (const k4 of order)
|
|
59148
|
-
|
|
59304
|
+
printLine(` ${k4.padEnd(24)} ${String(report.tally[k4]).padStart(5)}`);
|
|
59149
59305
|
const pct = report.records.length ? (100 * report.comparable / report.records.length).toFixed(1) : "0.0";
|
|
59150
|
-
|
|
59306
|
+
printLine(`COMPARABLE = ${report.comparable} of ${report.records.length} (${pct}%)`);
|
|
59151
59307
|
const show = (title, rs) => {
|
|
59152
59308
|
if (rs.length === 0)
|
|
59153
59309
|
return;
|
|
59154
|
-
|
|
59310
|
+
printLine(`
|
|
59155
59311
|
=== ${title} ===`);
|
|
59156
59312
|
for (const r4 of rs)
|
|
59157
|
-
|
|
59313
|
+
printLine(` ${r4.domain.padEnd(26)} ${r4.why.slice(0, 120)}`);
|
|
59158
59314
|
};
|
|
59159
59315
|
show("MISMATCHES", report.records.filter((r4) => r4.verdict === "MISMATCH"));
|
|
59160
59316
|
show("NOT AT REGISTRY", report.records.filter((r4) => r4.verdict === "NOT_AT_REGISTRY"));
|
|
59161
59317
|
show("UNVERIFIABLE / UNEXPECTED (coverage loss - these are NOT clean)", report.records.filter((r4) => r4.verdict === "UNVERIFIABLE_UNEXPECTED"));
|
|
59162
|
-
|
|
59318
|
+
printLine(`
|
|
59163
59319
|
REGISTRY EXPIRY WITHIN ${STALE_SOON_DAYS}d: ${report.expiringSoon.length}`);
|
|
59164
59320
|
for (const r4 of report.expiringSoon) {
|
|
59165
|
-
|
|
59321
|
+
printLine(` ${r4.domain.padEnd(26)} registry=${r4.registry} in ${r4.daysToRegistryExpiry}d verdict=${r4.verdict}`);
|
|
59166
59322
|
}
|
|
59167
59323
|
if (opts.baseline) {
|
|
59168
|
-
|
|
59324
|
+
printLine(`
|
|
59169
59325
|
COVERAGE REGRESSION vs baseline: ${regressed.length}`);
|
|
59170
59326
|
for (const d4 of regressed.slice(0, 20))
|
|
59171
|
-
|
|
59327
|
+
printLine(` ${d4} was comparable, now unverifiable`);
|
|
59172
59328
|
}
|
|
59173
|
-
|
|
59329
|
+
printLine(`
|
|
59174
59330
|
EXIT=${report.exitCode}`);
|
|
59175
59331
|
process.exit(report.exitCode);
|
|
59176
59332
|
});
|
|
@@ -59178,6 +59334,7 @@ EXIT=${report.exitCode}`);
|
|
|
59178
59334
|
|
|
59179
59335
|
// src/cli/index.ts
|
|
59180
59336
|
init_version();
|
|
59337
|
+
init_stdout();
|
|
59181
59338
|
var OPTIONAL_GROUPS = [
|
|
59182
59339
|
"brandsight",
|
|
59183
59340
|
"events",
|
|
@@ -59238,7 +59395,7 @@ async function registerOptionalCommands(program2, groups) {
|
|
|
59238
59395
|
const { registerEventsCommands: registerEventsCommands2 } = await Promise.resolve().then(() => (init_commander(), exports_commander));
|
|
59239
59396
|
registerEventsCommands2(program2, { source: "domains" });
|
|
59240
59397
|
} catch (error) {
|
|
59241
|
-
|
|
59398
|
+
printErrorLine(`Events command group is enabled but @hasna/events could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
|
|
59242
59399
|
}
|
|
59243
59400
|
}
|
|
59244
59401
|
}
|
|
@@ -59252,15 +59409,15 @@ function registerOptionalHelp(program2) {
|
|
|
59252
59409
|
enable_some: "DOMAINS_COMMAND_GROUPS=marketplace,owner domains <command>"
|
|
59253
59410
|
};
|
|
59254
59411
|
if (opts.json) {
|
|
59255
|
-
|
|
59412
|
+
printLine(JSON.stringify(body, null, 2));
|
|
59256
59413
|
return;
|
|
59257
59414
|
}
|
|
59258
|
-
|
|
59415
|
+
printLine("Optional command groups:");
|
|
59259
59416
|
for (const group of body.available)
|
|
59260
|
-
|
|
59261
|
-
|
|
59417
|
+
printLine(` ${groups.has(group) ? "\u2713" : " "} ${group}`);
|
|
59418
|
+
printLine(`
|
|
59262
59419
|
Enable all: DOMAINS_ENABLE_EXTRAS=1 domains <command>`);
|
|
59263
|
-
|
|
59420
|
+
printLine("Enable some: DOMAINS_COMMAND_GROUPS=marketplace,owner domains <command>");
|
|
59264
59421
|
});
|
|
59265
59422
|
}
|
|
59266
59423
|
var program2 = new Command;
|