@hasna/microservices 0.0.4 → 0.0.6
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/bin/index.js +9 -1
- package/bin/mcp.js +9 -1
- package/dist/index.js +9 -1
- package/microservices/microservice-ads/src/cli/index.ts +198 -0
- package/microservices/microservice-ads/src/db/campaigns.ts +304 -0
- package/microservices/microservice-ads/src/mcp/index.ts +160 -0
- package/microservices/microservice-company/package.json +27 -0
- package/microservices/microservice-company/src/cli/index.ts +1126 -0
- package/microservices/microservice-company/src/db/company.ts +854 -0
- package/microservices/microservice-company/src/db/database.ts +93 -0
- package/microservices/microservice-company/src/db/migrations.ts +214 -0
- package/microservices/microservice-company/src/db/workflow-migrations.ts +44 -0
- package/microservices/microservice-company/src/index.ts +60 -0
- package/microservices/microservice-company/src/lib/audit.ts +168 -0
- package/microservices/microservice-company/src/lib/finance.ts +299 -0
- package/microservices/microservice-company/src/lib/settings.ts +85 -0
- package/microservices/microservice-company/src/lib/workflows.ts +698 -0
- package/microservices/microservice-company/src/mcp/index.ts +991 -0
- package/microservices/microservice-contracts/src/cli/index.ts +410 -23
- package/microservices/microservice-contracts/src/db/contracts.ts +430 -1
- package/microservices/microservice-contracts/src/db/migrations.ts +83 -0
- package/microservices/microservice-contracts/src/mcp/index.ts +312 -3
- package/microservices/microservice-domains/src/cli/index.ts +673 -0
- package/microservices/microservice-domains/src/db/domains.ts +613 -0
- package/microservices/microservice-domains/src/index.ts +21 -0
- package/microservices/microservice-domains/src/lib/brandsight.ts +285 -0
- package/microservices/microservice-domains/src/lib/godaddy.ts +328 -0
- package/microservices/microservice-domains/src/lib/namecheap.ts +474 -0
- package/microservices/microservice-domains/src/lib/registrar.ts +355 -0
- package/microservices/microservice-domains/src/mcp/index.ts +413 -0
- package/microservices/microservice-hiring/src/cli/index.ts +318 -8
- package/microservices/microservice-hiring/src/db/hiring.ts +503 -0
- package/microservices/microservice-hiring/src/db/migrations.ts +21 -0
- package/microservices/microservice-hiring/src/index.ts +29 -0
- package/microservices/microservice-hiring/src/lib/scoring.ts +206 -0
- package/microservices/microservice-hiring/src/mcp/index.ts +245 -0
- package/microservices/microservice-payments/src/cli/index.ts +255 -3
- package/microservices/microservice-payments/src/db/migrations.ts +18 -0
- package/microservices/microservice-payments/src/db/payments.ts +552 -0
- package/microservices/microservice-payments/src/mcp/index.ts +223 -0
- package/microservices/microservice-payroll/src/cli/index.ts +269 -0
- package/microservices/microservice-payroll/src/db/migrations.ts +26 -0
- package/microservices/microservice-payroll/src/db/payroll.ts +636 -0
- package/microservices/microservice-payroll/src/mcp/index.ts +246 -0
- package/microservices/microservice-shipping/src/cli/index.ts +211 -3
- package/microservices/microservice-shipping/src/db/migrations.ts +8 -0
- package/microservices/microservice-shipping/src/db/shipping.ts +453 -3
- package/microservices/microservice-shipping/src/mcp/index.ts +149 -1
- package/microservices/microservice-social/src/cli/index.ts +244 -2
- package/microservices/microservice-social/src/db/migrations.ts +33 -0
- package/microservices/microservice-social/src/db/social.ts +378 -4
- package/microservices/microservice-social/src/mcp/index.ts +221 -1
- package/microservices/microservice-subscriptions/src/cli/index.ts +315 -0
- package/microservices/microservice-subscriptions/src/db/migrations.ts +68 -0
- package/microservices/microservice-subscriptions/src/db/subscriptions.ts +567 -3
- package/microservices/microservice-subscriptions/src/mcp/index.ts +267 -1
- package/package.json +1 -1
|
@@ -19,7 +19,38 @@ import {
|
|
|
19
19
|
createAlert,
|
|
20
20
|
listAlerts,
|
|
21
21
|
deleteAlert,
|
|
22
|
+
whoisLookup,
|
|
23
|
+
checkDnsPropagation,
|
|
24
|
+
checkSsl,
|
|
25
|
+
exportZoneFile,
|
|
26
|
+
importZoneFile,
|
|
27
|
+
discoverSubdomains,
|
|
28
|
+
validateDns,
|
|
29
|
+
exportPortfolio,
|
|
30
|
+
checkAllDomains,
|
|
31
|
+
getDomainByName,
|
|
22
32
|
} from "../db/domains.js";
|
|
33
|
+
import {
|
|
34
|
+
syncToLocalDb,
|
|
35
|
+
renewDomain as namecheapRenew,
|
|
36
|
+
checkAvailability as namecheapCheck,
|
|
37
|
+
} from "../lib/namecheap.js";
|
|
38
|
+
import {
|
|
39
|
+
syncToLocalDb as godaddySyncToLocalDb,
|
|
40
|
+
renewDomain as godaddyRenewDomain,
|
|
41
|
+
} from "../lib/godaddy.js";
|
|
42
|
+
import {
|
|
43
|
+
getAvailableProviders,
|
|
44
|
+
syncAll,
|
|
45
|
+
autoDetectRegistrar,
|
|
46
|
+
getProvider,
|
|
47
|
+
} from "../lib/registrar.js";
|
|
48
|
+
import {
|
|
49
|
+
monitorBrand,
|
|
50
|
+
getSimilarDomains,
|
|
51
|
+
getThreatAssessment,
|
|
52
|
+
} from "../lib/brandsight.js";
|
|
53
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
23
54
|
|
|
24
55
|
const program = new Command();
|
|
25
56
|
|
|
@@ -269,6 +300,109 @@ program
|
|
|
269
300
|
}
|
|
270
301
|
});
|
|
271
302
|
|
|
303
|
+
// --- WHOIS Lookup ---
|
|
304
|
+
|
|
305
|
+
program
|
|
306
|
+
.command("whois")
|
|
307
|
+
.description("Run WHOIS lookup for a domain and update DB record")
|
|
308
|
+
.argument("<name>", "Domain name (e.g. example.com)")
|
|
309
|
+
.option("--json", "Output as JSON", false)
|
|
310
|
+
.action((name, opts) => {
|
|
311
|
+
try {
|
|
312
|
+
const result = whoisLookup(name);
|
|
313
|
+
if (opts.json) {
|
|
314
|
+
console.log(JSON.stringify(result, null, 2));
|
|
315
|
+
} else {
|
|
316
|
+
console.log(`WHOIS for ${result.domain}:`);
|
|
317
|
+
console.log(` Registrar: ${result.registrar || "unknown"}`);
|
|
318
|
+
console.log(` Expires: ${result.expires_at || "unknown"}`);
|
|
319
|
+
if (result.nameservers.length > 0) {
|
|
320
|
+
console.log(` Nameservers: ${result.nameservers.join(", ")}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
} catch (error: unknown) {
|
|
324
|
+
console.error(`WHOIS lookup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// --- SSL Check ---
|
|
330
|
+
|
|
331
|
+
program
|
|
332
|
+
.command("ssl-check")
|
|
333
|
+
.description("Check SSL certificate for a domain and update DB record")
|
|
334
|
+
.argument("<name>", "Domain name (e.g. example.com)")
|
|
335
|
+
.option("--json", "Output as JSON", false)
|
|
336
|
+
.action((name, opts) => {
|
|
337
|
+
const result = checkSsl(name);
|
|
338
|
+
if (opts.json) {
|
|
339
|
+
console.log(JSON.stringify(result, null, 2));
|
|
340
|
+
} else {
|
|
341
|
+
if (result.error) {
|
|
342
|
+
console.error(`SSL check failed: ${result.error}`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
console.log(`SSL Certificate for ${result.domain}:`);
|
|
346
|
+
console.log(` Issuer: ${result.issuer || "unknown"}`);
|
|
347
|
+
console.log(` Expires: ${result.expires_at || "unknown"}`);
|
|
348
|
+
if (result.subject) console.log(` Subject: ${result.subject}`);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// --- Portfolio Export ---
|
|
353
|
+
|
|
354
|
+
program
|
|
355
|
+
.command("export")
|
|
356
|
+
.description("Export all domains as CSV or JSON")
|
|
357
|
+
.option("--format <format>", "Export format (csv or json)", "json")
|
|
358
|
+
.option("--output <file>", "Write to file instead of stdout")
|
|
359
|
+
.action((opts) => {
|
|
360
|
+
const format = opts.format === "csv" ? "csv" : "json";
|
|
361
|
+
const output = exportPortfolio(format as "csv" | "json");
|
|
362
|
+
if (opts.output) {
|
|
363
|
+
writeFileSync(opts.output, output, "utf-8");
|
|
364
|
+
console.log(`Exported to ${opts.output}`);
|
|
365
|
+
} else {
|
|
366
|
+
console.log(output);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// --- Bulk Domain Check ---
|
|
371
|
+
|
|
372
|
+
program
|
|
373
|
+
.command("check-all")
|
|
374
|
+
.description("Run WHOIS + SSL + DNS validation on all domains")
|
|
375
|
+
.option("--json", "Output as JSON", false)
|
|
376
|
+
.action((opts) => {
|
|
377
|
+
const results = checkAllDomains();
|
|
378
|
+
if (opts.json) {
|
|
379
|
+
console.log(JSON.stringify(results, null, 2));
|
|
380
|
+
} else {
|
|
381
|
+
if (results.length === 0) {
|
|
382
|
+
console.log("No domains to check.");
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
for (const r of results) {
|
|
386
|
+
console.log(`\n${r.domain}:`);
|
|
387
|
+
if (r.whois) {
|
|
388
|
+
console.log(` WHOIS: registrar=${r.whois.registrar || "?"}, expires=${r.whois.expires_at || "?"}`);
|
|
389
|
+
if (r.whois.error) console.log(` Error: ${r.whois.error}`);
|
|
390
|
+
}
|
|
391
|
+
if (r.ssl) {
|
|
392
|
+
console.log(` SSL: issuer=${r.ssl.issuer || "?"}, expires=${r.ssl.expires_at || "?"}`);
|
|
393
|
+
if (r.ssl.error) console.log(` Error: ${r.ssl.error}`);
|
|
394
|
+
}
|
|
395
|
+
if (r.dns_validation) {
|
|
396
|
+
console.log(` DNS: valid=${r.dns_validation.valid}, issues=${r.dns_validation.issue_count}`);
|
|
397
|
+
for (const e of r.dns_validation.errors) {
|
|
398
|
+
console.log(` ${e}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
console.log(`\nChecked ${results.length} domain(s)`);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
272
406
|
// --- DNS Records ---
|
|
273
407
|
|
|
274
408
|
const dnsCmd = program
|
|
@@ -370,6 +504,145 @@ dnsCmd
|
|
|
370
504
|
}
|
|
371
505
|
});
|
|
372
506
|
|
|
507
|
+
// --- DNS Propagation Check ---
|
|
508
|
+
|
|
509
|
+
dnsCmd
|
|
510
|
+
.command("check-propagation")
|
|
511
|
+
.description("Check DNS propagation across multiple servers")
|
|
512
|
+
.argument("<domain>", "Domain name to check")
|
|
513
|
+
.option("--record <type>", "Record type (A/AAAA/CNAME/MX/TXT/NS)", "A")
|
|
514
|
+
.option("--json", "Output as JSON", false)
|
|
515
|
+
.action((domain, opts) => {
|
|
516
|
+
const result = checkDnsPropagation(domain, opts.record);
|
|
517
|
+
if (opts.json) {
|
|
518
|
+
console.log(JSON.stringify(result, null, 2));
|
|
519
|
+
} else {
|
|
520
|
+
console.log(`DNS Propagation for ${result.domain} (${result.record_type}):`);
|
|
521
|
+
console.log(` Consistent: ${result.consistent ? "yes" : "NO"}`);
|
|
522
|
+
for (const s of result.servers) {
|
|
523
|
+
const values = s.values.length > 0 ? s.values.join(", ") : "(empty)";
|
|
524
|
+
const status = s.status === "error" ? ` [ERROR: ${s.error}]` : "";
|
|
525
|
+
console.log(` ${s.name} (${s.server}): ${values}${status}`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// --- Zone File Export ---
|
|
531
|
+
|
|
532
|
+
dnsCmd
|
|
533
|
+
.command("export")
|
|
534
|
+
.description("Export DNS records as BIND zone file")
|
|
535
|
+
.argument("<domain-id>", "Domain ID")
|
|
536
|
+
.option("--format <format>", "Export format (zone)", "zone")
|
|
537
|
+
.option("--output <file>", "Write to file instead of stdout")
|
|
538
|
+
.action((domainId, opts) => {
|
|
539
|
+
const zone = exportZoneFile(domainId);
|
|
540
|
+
if (!zone) {
|
|
541
|
+
console.error(`Domain '${domainId}' not found.`);
|
|
542
|
+
process.exit(1);
|
|
543
|
+
}
|
|
544
|
+
if (opts.output) {
|
|
545
|
+
writeFileSync(opts.output, zone, "utf-8");
|
|
546
|
+
console.log(`Exported zone file to ${opts.output}`);
|
|
547
|
+
} else {
|
|
548
|
+
console.log(zone);
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// --- Zone File Import ---
|
|
553
|
+
|
|
554
|
+
dnsCmd
|
|
555
|
+
.command("import")
|
|
556
|
+
.description("Import DNS records from a BIND zone file")
|
|
557
|
+
.argument("<domain-id>", "Domain ID")
|
|
558
|
+
.requiredOption("--file <path>", "Path to zone file")
|
|
559
|
+
.option("--json", "Output as JSON", false)
|
|
560
|
+
.action((domainId, opts) => {
|
|
561
|
+
let content: string;
|
|
562
|
+
try {
|
|
563
|
+
content = readFileSync(opts.file, "utf-8");
|
|
564
|
+
} catch {
|
|
565
|
+
console.error(`Could not read file: ${opts.file}`);
|
|
566
|
+
process.exit(1);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const result = importZoneFile(domainId, content);
|
|
570
|
+
if (!result) {
|
|
571
|
+
console.error(`Domain '${domainId}' not found.`);
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (opts.json) {
|
|
576
|
+
console.log(JSON.stringify(result, null, 2));
|
|
577
|
+
} else {
|
|
578
|
+
console.log(`Imported ${result.imported} record(s), skipped ${result.skipped}`);
|
|
579
|
+
if (result.errors.length > 0) {
|
|
580
|
+
console.log("Errors:");
|
|
581
|
+
for (const e of result.errors) {
|
|
582
|
+
console.log(` - ${e}`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
// --- Subdomain Discovery ---
|
|
589
|
+
|
|
590
|
+
dnsCmd
|
|
591
|
+
.command("discover-subdomains")
|
|
592
|
+
.description("Discover subdomains via certificate transparency logs (crt.sh)")
|
|
593
|
+
.argument("<domain>", "Domain name")
|
|
594
|
+
.option("--json", "Output as JSON", false)
|
|
595
|
+
.action(async (domain, opts) => {
|
|
596
|
+
const result = await discoverSubdomains(domain);
|
|
597
|
+
if (opts.json) {
|
|
598
|
+
console.log(JSON.stringify(result, null, 2));
|
|
599
|
+
} else {
|
|
600
|
+
if (result.error) {
|
|
601
|
+
console.error(`Discovery failed: ${result.error}`);
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
604
|
+
if (result.subdomains.length === 0) {
|
|
605
|
+
console.log(`No subdomains found for ${domain}.`);
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
console.log(`Subdomains for ${domain} (source: ${result.source}):`);
|
|
609
|
+
for (const s of result.subdomains) {
|
|
610
|
+
console.log(` ${s}`);
|
|
611
|
+
}
|
|
612
|
+
console.log(`\n${result.subdomains.length} subdomain(s) found`);
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
// --- DNS Validation ---
|
|
617
|
+
|
|
618
|
+
dnsCmd
|
|
619
|
+
.command("validate")
|
|
620
|
+
.description("Validate DNS records for common issues")
|
|
621
|
+
.argument("<domain-id>", "Domain ID")
|
|
622
|
+
.option("--json", "Output as JSON", false)
|
|
623
|
+
.action((domainId, opts) => {
|
|
624
|
+
const result = validateDns(domainId);
|
|
625
|
+
if (!result) {
|
|
626
|
+
console.error(`Domain '${domainId}' not found.`);
|
|
627
|
+
process.exit(1);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (opts.json) {
|
|
631
|
+
console.log(JSON.stringify(result, null, 2));
|
|
632
|
+
} else {
|
|
633
|
+
console.log(`DNS Validation for ${result.domain_name}:`);
|
|
634
|
+
console.log(` Valid: ${result.valid ? "yes" : "NO"}`);
|
|
635
|
+
if (result.issues.length === 0) {
|
|
636
|
+
console.log(" No issues found.");
|
|
637
|
+
} else {
|
|
638
|
+
for (const issue of result.issues) {
|
|
639
|
+
const prefix = issue.type === "error" ? "ERROR" : "WARN";
|
|
640
|
+
console.log(` [${prefix}] ${issue.message}`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
|
|
373
646
|
// --- Alerts ---
|
|
374
647
|
|
|
375
648
|
const alertCmd = program
|
|
@@ -435,4 +708,404 @@ alertCmd
|
|
|
435
708
|
}
|
|
436
709
|
});
|
|
437
710
|
|
|
711
|
+
// --- Namecheap Integration ---
|
|
712
|
+
|
|
713
|
+
program
|
|
714
|
+
.command("sync")
|
|
715
|
+
.description("Sync domains from a provider to local DB")
|
|
716
|
+
.requiredOption("--provider <provider>", "Provider name (namecheap, godaddy)")
|
|
717
|
+
.option("--json", "Output as JSON", false)
|
|
718
|
+
.action(async (opts) => {
|
|
719
|
+
const provider = opts.provider.toLowerCase();
|
|
720
|
+
|
|
721
|
+
if (provider === "namecheap") {
|
|
722
|
+
try {
|
|
723
|
+
const result = await syncToLocalDb({
|
|
724
|
+
getDomainByName,
|
|
725
|
+
createDomain,
|
|
726
|
+
updateDomain,
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
if (opts.json) {
|
|
730
|
+
console.log(JSON.stringify(result, null, 2));
|
|
731
|
+
} else {
|
|
732
|
+
console.log(`Synced ${result.synced} domain(s) from Namecheap`);
|
|
733
|
+
for (const d of result.domains) {
|
|
734
|
+
console.log(` ${d}`);
|
|
735
|
+
}
|
|
736
|
+
if (result.errors.length > 0) {
|
|
737
|
+
console.log("Errors:");
|
|
738
|
+
for (const e of result.errors) {
|
|
739
|
+
console.log(` - ${e}`);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
} catch (error: unknown) {
|
|
744
|
+
console.error(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
745
|
+
process.exit(1);
|
|
746
|
+
}
|
|
747
|
+
} else if (provider === "godaddy") {
|
|
748
|
+
try {
|
|
749
|
+
const result = await godaddySyncToLocalDb({
|
|
750
|
+
getDomainByName,
|
|
751
|
+
createDomain,
|
|
752
|
+
updateDomain,
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
if (opts.json) {
|
|
756
|
+
console.log(JSON.stringify(result, null, 2));
|
|
757
|
+
} else {
|
|
758
|
+
console.log(`Synced ${result.synced} domain(s) from GoDaddy (created: ${result.created}, updated: ${result.updated})`);
|
|
759
|
+
if (result.errors.length > 0) {
|
|
760
|
+
console.log("Errors:");
|
|
761
|
+
for (const e of result.errors) {
|
|
762
|
+
console.log(` - ${e}`);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
} catch (error: unknown) {
|
|
767
|
+
console.error(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
768
|
+
process.exit(1);
|
|
769
|
+
}
|
|
770
|
+
} else {
|
|
771
|
+
console.error(`Unsupported provider: ${opts.provider}. Supported: namecheap, godaddy`);
|
|
772
|
+
process.exit(1);
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
program
|
|
777
|
+
.command("renew")
|
|
778
|
+
.description("Renew a domain via provider")
|
|
779
|
+
.argument("<name>", "Domain name (e.g. example.com)")
|
|
780
|
+
.requiredOption("--provider <provider>", "Provider name (namecheap, godaddy)")
|
|
781
|
+
.option("--years <n>", "Number of years to renew", "1")
|
|
782
|
+
.option("--json", "Output as JSON", false)
|
|
783
|
+
.action(async (name, opts) => {
|
|
784
|
+
const provider = opts.provider.toLowerCase();
|
|
785
|
+
|
|
786
|
+
if (provider === "namecheap") {
|
|
787
|
+
try {
|
|
788
|
+
const result = await namecheapRenew(name, parseInt(opts.years));
|
|
789
|
+
|
|
790
|
+
if (opts.json) {
|
|
791
|
+
console.log(JSON.stringify(result, null, 2));
|
|
792
|
+
} else {
|
|
793
|
+
console.log(`Renewed ${result.domain} successfully`);
|
|
794
|
+
if (result.chargedAmount) console.log(` Charged: $${result.chargedAmount}`);
|
|
795
|
+
if (result.orderId) console.log(` Order ID: ${result.orderId}`);
|
|
796
|
+
if (result.transactionId) console.log(` Transaction ID: ${result.transactionId}`);
|
|
797
|
+
}
|
|
798
|
+
} catch (error: unknown) {
|
|
799
|
+
console.error(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
} else if (provider === "godaddy") {
|
|
803
|
+
try {
|
|
804
|
+
const result = await godaddyRenewDomain(name);
|
|
805
|
+
|
|
806
|
+
if (opts.json) {
|
|
807
|
+
console.log(JSON.stringify(result, null, 2));
|
|
808
|
+
} else {
|
|
809
|
+
console.log(`Renewed ${name} successfully via GoDaddy`);
|
|
810
|
+
if (result.orderId) console.log(` Order ID: ${result.orderId}`);
|
|
811
|
+
if (result.total) console.log(` Total: $${(result.total / 100).toFixed(2)}`);
|
|
812
|
+
}
|
|
813
|
+
} catch (error: unknown) {
|
|
814
|
+
console.error(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
815
|
+
process.exit(1);
|
|
816
|
+
}
|
|
817
|
+
} else {
|
|
818
|
+
console.error(`Unsupported provider: ${opts.provider}. Supported: namecheap, godaddy`);
|
|
819
|
+
process.exit(1);
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
program
|
|
824
|
+
.command("check")
|
|
825
|
+
.description("Check domain availability")
|
|
826
|
+
.argument("<name>", "Domain name (e.g. example.com)")
|
|
827
|
+
.option("--json", "Output as JSON", false)
|
|
828
|
+
.action(async (name, opts) => {
|
|
829
|
+
try {
|
|
830
|
+
const result = await namecheapCheck(name);
|
|
831
|
+
|
|
832
|
+
if (opts.json) {
|
|
833
|
+
console.log(JSON.stringify(result, null, 2));
|
|
834
|
+
} else {
|
|
835
|
+
if (result.available) {
|
|
836
|
+
console.log(`${result.domain} is AVAILABLE`);
|
|
837
|
+
} else {
|
|
838
|
+
console.log(`${result.domain} is NOT available`);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
} catch (error: unknown) {
|
|
842
|
+
console.error(`Availability check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
843
|
+
process.exit(1);
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// --- Unified Provider Commands ---
|
|
848
|
+
|
|
849
|
+
program
|
|
850
|
+
.command("providers")
|
|
851
|
+
.description("Show which registrar providers are configured")
|
|
852
|
+
.option("--json", "Output as JSON", false)
|
|
853
|
+
.action((opts) => {
|
|
854
|
+
const providers = getAvailableProviders();
|
|
855
|
+
|
|
856
|
+
if (opts.json) {
|
|
857
|
+
console.log(JSON.stringify(providers, null, 2));
|
|
858
|
+
} else {
|
|
859
|
+
console.log("Registrar Providers:");
|
|
860
|
+
for (const p of providers) {
|
|
861
|
+
const status = p.configured ? "CONFIGURED" : "not configured";
|
|
862
|
+
console.log(` ${p.name}: ${status}`);
|
|
863
|
+
if (!p.configured) {
|
|
864
|
+
console.log(` Missing: ${p.envVars.join(", ")}`);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
// Override sync command to support --all flag
|
|
871
|
+
program.commands = program.commands.filter((c) => c.name() !== "sync");
|
|
872
|
+
|
|
873
|
+
program
|
|
874
|
+
.command("sync")
|
|
875
|
+
.description("Sync domains from a provider to local DB")
|
|
876
|
+
.option("--provider <provider>", "Provider name (namecheap, godaddy)")
|
|
877
|
+
.option("--all", "Sync from all configured providers")
|
|
878
|
+
.option("--json", "Output as JSON", false)
|
|
879
|
+
.action(async (opts) => {
|
|
880
|
+
if (opts.all) {
|
|
881
|
+
try {
|
|
882
|
+
const result = await syncAll({
|
|
883
|
+
getDomainByName,
|
|
884
|
+
createDomain,
|
|
885
|
+
updateDomain,
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
if (opts.json) {
|
|
889
|
+
console.log(JSON.stringify(result, null, 2));
|
|
890
|
+
} else {
|
|
891
|
+
console.log(`Synced ${result.totalSynced} domain(s) from ${result.providers.length} provider(s)`);
|
|
892
|
+
for (const p of result.providers) {
|
|
893
|
+
console.log(` ${p.name}: ${p.result.synced} synced`);
|
|
894
|
+
}
|
|
895
|
+
if (result.totalErrors.length > 0) {
|
|
896
|
+
console.log("Errors:");
|
|
897
|
+
for (const e of result.totalErrors) {
|
|
898
|
+
console.log(` - ${e}`);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
} catch (error: unknown) {
|
|
903
|
+
console.error(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
904
|
+
process.exit(1);
|
|
905
|
+
}
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const provider = (opts.provider || "").toLowerCase();
|
|
910
|
+
if (!provider) {
|
|
911
|
+
console.error("Specify --provider <name> or --all");
|
|
912
|
+
process.exit(1);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
if (provider === "namecheap") {
|
|
916
|
+
try {
|
|
917
|
+
const result = await syncToLocalDb({
|
|
918
|
+
getDomainByName,
|
|
919
|
+
createDomain,
|
|
920
|
+
updateDomain,
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
if (opts.json) {
|
|
924
|
+
console.log(JSON.stringify(result, null, 2));
|
|
925
|
+
} else {
|
|
926
|
+
console.log(`Synced ${result.synced} domain(s) from Namecheap`);
|
|
927
|
+
for (const d of result.domains) {
|
|
928
|
+
console.log(` ${d}`);
|
|
929
|
+
}
|
|
930
|
+
if (result.errors.length > 0) {
|
|
931
|
+
console.log("Errors:");
|
|
932
|
+
for (const e of result.errors) {
|
|
933
|
+
console.log(` - ${e}`);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
} catch (error: unknown) {
|
|
938
|
+
console.error(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
939
|
+
process.exit(1);
|
|
940
|
+
}
|
|
941
|
+
} else if (provider === "godaddy") {
|
|
942
|
+
try {
|
|
943
|
+
const result = await godaddySyncToLocalDb({
|
|
944
|
+
getDomainByName,
|
|
945
|
+
createDomain,
|
|
946
|
+
updateDomain,
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
if (opts.json) {
|
|
950
|
+
console.log(JSON.stringify(result, null, 2));
|
|
951
|
+
} else {
|
|
952
|
+
console.log(`Synced ${result.synced} domain(s) from GoDaddy (created: ${result.created}, updated: ${result.updated})`);
|
|
953
|
+
if (result.errors.length > 0) {
|
|
954
|
+
console.log("Errors:");
|
|
955
|
+
for (const e of result.errors) {
|
|
956
|
+
console.log(` - ${e}`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
} catch (error: unknown) {
|
|
961
|
+
console.error(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
962
|
+
process.exit(1);
|
|
963
|
+
}
|
|
964
|
+
} else {
|
|
965
|
+
console.error(`Unsupported provider: ${provider}. Supported: namecheap, godaddy`);
|
|
966
|
+
process.exit(1);
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
// Override renew command to support auto-detect
|
|
971
|
+
program.commands = program.commands.filter((c) => c.name() !== "renew");
|
|
972
|
+
|
|
973
|
+
program
|
|
974
|
+
.command("renew")
|
|
975
|
+
.description("Renew a domain via provider (auto-detects registrar from DB if --provider not given)")
|
|
976
|
+
.argument("<name>", "Domain name (e.g. example.com)")
|
|
977
|
+
.option("--provider <provider>", "Provider name (namecheap, godaddy)")
|
|
978
|
+
.option("--years <n>", "Number of years to renew", "1")
|
|
979
|
+
.option("--json", "Output as JSON", false)
|
|
980
|
+
.action(async (name, opts) => {
|
|
981
|
+
let provider = (opts.provider || "").toLowerCase();
|
|
982
|
+
|
|
983
|
+
if (!provider) {
|
|
984
|
+
const detected = autoDetectRegistrar(name, getDomainByName);
|
|
985
|
+
if (!detected) {
|
|
986
|
+
console.error(`Could not auto-detect registrar for '${name}'. Use --provider.`);
|
|
987
|
+
process.exit(1);
|
|
988
|
+
}
|
|
989
|
+
provider = detected;
|
|
990
|
+
console.log(`Auto-detected registrar: ${provider}`);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (provider === "namecheap") {
|
|
994
|
+
try {
|
|
995
|
+
const result = await namecheapRenew(name, parseInt(opts.years));
|
|
996
|
+
if (opts.json) {
|
|
997
|
+
console.log(JSON.stringify(result, null, 2));
|
|
998
|
+
} else {
|
|
999
|
+
console.log(`Renewed ${result.domain} successfully via Namecheap`);
|
|
1000
|
+
if (result.chargedAmount) console.log(` Charged: $${result.chargedAmount}`);
|
|
1001
|
+
if (result.orderId) console.log(` Order ID: ${result.orderId}`);
|
|
1002
|
+
}
|
|
1003
|
+
} catch (error: unknown) {
|
|
1004
|
+
console.error(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1005
|
+
process.exit(1);
|
|
1006
|
+
}
|
|
1007
|
+
} else if (provider === "godaddy") {
|
|
1008
|
+
try {
|
|
1009
|
+
const result = await godaddyRenewDomain(name);
|
|
1010
|
+
if (opts.json) {
|
|
1011
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1012
|
+
} else {
|
|
1013
|
+
console.log(`Renewed ${name} successfully via GoDaddy`);
|
|
1014
|
+
if (result.orderId) console.log(` Order ID: ${result.orderId}`);
|
|
1015
|
+
if (result.total) console.log(` Total: $${(result.total / 100).toFixed(2)}`);
|
|
1016
|
+
}
|
|
1017
|
+
} catch (error: unknown) {
|
|
1018
|
+
console.error(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1019
|
+
process.exit(1);
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
console.error(`Unsupported provider: ${provider}. Supported: namecheap, godaddy`);
|
|
1023
|
+
process.exit(1);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
// --- Brandsight Commands ---
|
|
1028
|
+
|
|
1029
|
+
program
|
|
1030
|
+
.command("monitor")
|
|
1031
|
+
.description("Monitor a brand for similar domain registrations (Brandsight)")
|
|
1032
|
+
.argument("<brand>", "Brand name to monitor")
|
|
1033
|
+
.option("--json", "Output as JSON", false)
|
|
1034
|
+
.action(async (brand, opts) => {
|
|
1035
|
+
try {
|
|
1036
|
+
const result = await monitorBrand(brand);
|
|
1037
|
+
if (opts.json) {
|
|
1038
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1039
|
+
} else {
|
|
1040
|
+
if (result.stub) console.log("(stub data — Brandsight API unreachable)");
|
|
1041
|
+
console.log(`Brand monitoring for "${result.brand}":`);
|
|
1042
|
+
if (result.alerts.length === 0) {
|
|
1043
|
+
console.log(" No alerts.");
|
|
1044
|
+
} else {
|
|
1045
|
+
for (const a of result.alerts) {
|
|
1046
|
+
console.log(` [${a.type}] ${a.domain} — registered ${a.registered_at}`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
console.log(`\n${result.alerts.length} alert(s)`);
|
|
1050
|
+
}
|
|
1051
|
+
} catch (error: unknown) {
|
|
1052
|
+
console.error(`Monitor failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1053
|
+
process.exit(1);
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
program
|
|
1058
|
+
.command("similar")
|
|
1059
|
+
.description("Find typosquat/competing domains similar to a domain (Brandsight)")
|
|
1060
|
+
.argument("<domain>", "Domain to check")
|
|
1061
|
+
.option("--json", "Output as JSON", false)
|
|
1062
|
+
.action(async (domain, opts) => {
|
|
1063
|
+
try {
|
|
1064
|
+
const result = await getSimilarDomains(domain);
|
|
1065
|
+
if (opts.json) {
|
|
1066
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1067
|
+
} else {
|
|
1068
|
+
if (result.stub) console.log("(stub data — Brandsight API unreachable)");
|
|
1069
|
+
console.log(`Similar domains for ${result.domain}:`);
|
|
1070
|
+
for (const d of result.similar) {
|
|
1071
|
+
console.log(` ${d}`);
|
|
1072
|
+
}
|
|
1073
|
+
console.log(`\n${result.similar.length} similar domain(s)`);
|
|
1074
|
+
}
|
|
1075
|
+
} catch (error: unknown) {
|
|
1076
|
+
console.error(`Similar domains check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1077
|
+
process.exit(1);
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
program
|
|
1082
|
+
.command("threats")
|
|
1083
|
+
.description("Get threat assessment for a domain (Brandsight)")
|
|
1084
|
+
.argument("<domain>", "Domain to assess")
|
|
1085
|
+
.option("--json", "Output as JSON", false)
|
|
1086
|
+
.action(async (domain, opts) => {
|
|
1087
|
+
try {
|
|
1088
|
+
const result = await getThreatAssessment(domain);
|
|
1089
|
+
if (opts.json) {
|
|
1090
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1091
|
+
} else {
|
|
1092
|
+
if (result.stub) console.log("(stub data — Brandsight API unreachable)");
|
|
1093
|
+
console.log(`Threat Assessment for ${result.domain}:`);
|
|
1094
|
+
console.log(` Risk Level: ${result.risk_level}`);
|
|
1095
|
+
if (result.threats.length > 0) {
|
|
1096
|
+
console.log(" Threats:");
|
|
1097
|
+
for (const t of result.threats) {
|
|
1098
|
+
console.log(` - ${t}`);
|
|
1099
|
+
}
|
|
1100
|
+
} else {
|
|
1101
|
+
console.log(" Threats: none detected");
|
|
1102
|
+
}
|
|
1103
|
+
console.log(` Recommendation: ${result.recommendation}`);
|
|
1104
|
+
}
|
|
1105
|
+
} catch (error: unknown) {
|
|
1106
|
+
console.error(`Threat assessment failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1107
|
+
process.exit(1);
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1110
|
+
|
|
438
1111
|
program.parse(process.argv);
|