domsniper 0.1.1 → 0.1.3
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/package.json +1 -1
- package/src/app.tsx +44 -40
- package/src/index.tsx +11 -2
package/package.json
CHANGED
package/src/app.tsx
CHANGED
|
@@ -90,7 +90,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
90
90
|
const [showPortfolio, setShowPortfolio] = useState(false);
|
|
91
91
|
const [filter, setFilter] = useState<FilterConfig>({ ...DEFAULT_FILTER });
|
|
92
92
|
const [logs, setLogs] = useState<{ id: number; time: string; msg: string; fg: string }[]>([
|
|
93
|
-
{ id: 0, time: ts(), msg: "Domain Sniper
|
|
93
|
+
{ id: 0, time: ts(), msg: "Domain Sniper v0.1.3 initialized", fg: theme.textMuted },
|
|
94
94
|
{ id: 1, time: ts(), msg: "Press ? for all commands", fg: theme.textMuted },
|
|
95
95
|
]);
|
|
96
96
|
const [registrarConfig] = useState<RegistrarConfig | null>(loadConfigFromEnv());
|
|
@@ -424,7 +424,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
424
424
|
if (showPortfolio && key === "escape") { setShowPortfolio(false); return; }
|
|
425
425
|
|
|
426
426
|
// ── Marketplace toggle ──
|
|
427
|
-
if (key === "M" && mode !== "input"
|
|
427
|
+
if (key === "M" && mode !== "input") {
|
|
428
428
|
if (!showMarket) {
|
|
429
429
|
setShowMarket(true);
|
|
430
430
|
setMarketView("browse");
|
|
@@ -569,6 +569,35 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
569
569
|
return;
|
|
570
570
|
}
|
|
571
571
|
|
|
572
|
+
// ── Overlay toggles (work in any non-input mode) ──
|
|
573
|
+
|
|
574
|
+
// Toggle recon mode (already past input mode guard)
|
|
575
|
+
if (key === "n" && !ctrl) {
|
|
576
|
+
setReconMode((v) => {
|
|
577
|
+
const newVal = !v;
|
|
578
|
+
log(newVal ? "Recon mode ON (full pentest — rescan to apply)" : "Recon mode OFF (fast scan)", newVal ? theme.warning : theme.textMuted);
|
|
579
|
+
return newVal;
|
|
580
|
+
});
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Snipe selected domain (already past input mode guard)
|
|
585
|
+
if (key === "S" && selected) {
|
|
586
|
+
if (selected.status === "taken" || selected.status === "expired") {
|
|
587
|
+
snipeDomain(selected.domain, {
|
|
588
|
+
expiryDate: selected.whois?.expiryDate || undefined,
|
|
589
|
+
});
|
|
590
|
+
const phase = selected.status === "expired" ? "frequent" : "hourly";
|
|
591
|
+
log(`Sniping ${selected.domain} — ${selected.status === "expired" ? "expired, checking every 5 min" : "watching for expiry"}`, theme.warning);
|
|
592
|
+
log(`Run 'domain-sniper snipe run' to start the engine`, theme.textDisabled);
|
|
593
|
+
} else if (selected.status === "available") {
|
|
594
|
+
log(`${selected.domain} is already available — press r to register now`, theme.primary);
|
|
595
|
+
} else {
|
|
596
|
+
log(`Cannot snipe ${selected.domain} (status: ${selected.status})`, theme.textMuted);
|
|
597
|
+
}
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
|
|
572
601
|
// ── Navigation ──
|
|
573
602
|
if (mode === "scanning" || mode === "done" || mode === "watching") {
|
|
574
603
|
if (key === "up" || key === "k" || (ctrl && key === "p")) setSelectedIndex((i: number) => Math.max(0, i - 1));
|
|
@@ -696,15 +725,6 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
696
725
|
}
|
|
697
726
|
}
|
|
698
727
|
|
|
699
|
-
// Toggle recon mode (Issue 4: fix inverted message)
|
|
700
|
-
else if (key === "n") {
|
|
701
|
-
setReconMode((v) => {
|
|
702
|
-
const newVal = !v;
|
|
703
|
-
log(newVal ? "Recon mode ON (full pentest — rescan to apply)" : "Recon mode OFF (fast scan)", newVal ? theme.warning : theme.textMuted);
|
|
704
|
-
return newVal;
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
|
|
708
728
|
// Add to portfolio
|
|
709
729
|
else if (key === "p" && selected) {
|
|
710
730
|
try {
|
|
@@ -719,22 +739,6 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
719
739
|
}
|
|
720
740
|
}
|
|
721
741
|
|
|
722
|
-
// Snipe selected domain
|
|
723
|
-
else if (key === "S" && selected) {
|
|
724
|
-
if (selected.status === "taken" || selected.status === "expired") {
|
|
725
|
-
snipeDomain(selected.domain, {
|
|
726
|
-
expiryDate: selected.whois?.expiryDate || undefined,
|
|
727
|
-
});
|
|
728
|
-
const phase = selected.status === "expired" ? "frequent" : "hourly";
|
|
729
|
-
log(`Sniping ${selected.domain} — ${selected.status === "expired" ? "expired, checking every 5 min" : "watching for expiry"}`, theme.warning);
|
|
730
|
-
log(`Run 'domain-sniper snipe run' to start the engine`, theme.textDisabled);
|
|
731
|
-
} else if (selected.status === "available") {
|
|
732
|
-
log(`${selected.domain} is already available — press r to register now`, theme.primary);
|
|
733
|
-
} else {
|
|
734
|
-
log(`Cannot snipe ${selected.domain} (status: ${selected.status})`, theme.textMuted);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
742
|
// Clear cache for selected domain
|
|
739
743
|
else if (key === "c" && selected) {
|
|
740
744
|
const count = clearCache(selected.domain);
|
|
@@ -1057,7 +1061,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
1057
1061
|
const status = item.status || "—";
|
|
1058
1062
|
const verified = item.verified ? "✓" : " ";
|
|
1059
1063
|
return (
|
|
1060
|
-
<box key={item.id || i} flexDirection="row" backgroundColor={active ? theme.secondaryDim : "transparent"} paddingLeft={1} gap={1}>
|
|
1064
|
+
<box key={item.id || i} flexDirection="row" backgroundColor={active ? theme.secondaryDim : "transparent"} paddingLeft={1} gap={1} onMouseDown={() => setMarketSelectedIdx(i)}>
|
|
1061
1065
|
<text content={verified} fg={theme.primary} />
|
|
1062
1066
|
<text content={pad(domain, 28)} fg={active ? theme.text : theme.textSecondary} />
|
|
1063
1067
|
<text content={`$${price}`} fg={theme.warning} />
|
|
@@ -1237,7 +1241,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
1237
1241
|
const cached = domainScores.get(entry.domain);
|
|
1238
1242
|
const gr = cached?.grade ?? scoreGrade(0);
|
|
1239
1243
|
return (
|
|
1240
|
-
<box key={entry.domain} flexDirection="row" backgroundColor={active ? theme.primaryDim : "transparent"} paddingLeft={1} gap={1}>
|
|
1244
|
+
<box key={entry.domain} flexDirection="row" backgroundColor={active ? theme.primaryDim : "transparent"} paddingLeft={1} gap={1} onMouseDown={() => setSelectedIndex(i)}>
|
|
1241
1245
|
<text content={entry.tagged ? "◉" : " "} fg={entry.tagged ? theme.info : "transparent"} />
|
|
1242
1246
|
<text content={ss.icon} fg={ss.fg} />
|
|
1243
1247
|
<text content={entry.domain} fg={active ? theme.text : theme.textSecondary} />
|
|
@@ -1282,7 +1286,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
1282
1286
|
{selected && !showHelp && (
|
|
1283
1287
|
<box flexDirection="row" paddingLeft={1} gap={1} flexShrink={0}>
|
|
1284
1288
|
{(["overview", "dns", "security", "recon"] as IntelTab[]).map((tab) => (
|
|
1285
|
-
<box key={tab} backgroundColor={intelTab === tab ? theme.primaryDim : "transparent"}>
|
|
1289
|
+
<box key={tab} backgroundColor={intelTab === tab ? theme.primaryDim : "transparent"} onMouseDown={() => setIntelTab(tab)}>
|
|
1286
1290
|
<text content={` ${tab.toUpperCase()} `} fg={intelTab === tab ? theme.primary : theme.textDisabled} />
|
|
1287
1291
|
</box>
|
|
1288
1292
|
))}
|
|
@@ -1876,7 +1880,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
1876
1880
|
<text content="" />
|
|
1877
1881
|
<box flexDirection="row" gap={1} justifyContent="center">
|
|
1878
1882
|
<text content="◆" fg={theme.primary} />
|
|
1879
|
-
<text content="DOMAIN SNIPER" fg={theme.primary} />
|
|
1883
|
+
<text content="DOMAIN SNIPER v0.1.3" fg={theme.primary} />
|
|
1880
1884
|
</box>
|
|
1881
1885
|
<box justifyContent="center">
|
|
1882
1886
|
<text content="Domain Intelligence & Security Recon" fg={theme.textDisabled} />
|
|
@@ -2020,18 +2024,18 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
2020
2024
|
<box flexDirection="row" gap={1}>
|
|
2021
2025
|
{mode !== "input" ? (
|
|
2022
2026
|
(() => {
|
|
2023
|
-
const footerHints: { key: string; label: string; priority: number }[] = [
|
|
2024
|
-
{ key: "/", label: "scan", priority: 1 },
|
|
2027
|
+
const footerHints: { key: string; label: string; priority: number; onClick?: () => void }[] = [
|
|
2028
|
+
{ key: "/", label: "scan", priority: 1, onClick: () => { setInputMode("domain"); setMode("input"); setInputValue(""); } },
|
|
2025
2029
|
{ key: "␣", label: "tag", priority: 2 },
|
|
2026
|
-
{ key: "?", label: "help", priority: 3 },
|
|
2027
|
-
{ key: "n", label: reconMode ? "recon:ON" : "recon", priority: 4 },
|
|
2028
|
-
{ key: "M", label: "market", priority: 5 },
|
|
2030
|
+
{ key: "?", label: "help", priority: 3, onClick: () => setShowHelp((v) => !v) },
|
|
2031
|
+
{ key: "n", label: reconMode ? "recon:ON" : "recon", priority: 4, onClick: () => setReconMode((v) => !v) },
|
|
2032
|
+
{ key: "M", label: "market", priority: 5, onClick: () => { if (!showMarket) { setShowMarket(true); setMarketView("browse"); setMarketSelectedIdx(0); void loadMarketListings(); } else { setShowMarket(false); } } },
|
|
2029
2033
|
{ key: "S", label: "snipe", priority: 6 },
|
|
2030
|
-
{ key: "e", label: "expand", priority: 7 },
|
|
2034
|
+
{ key: "e", label: "expand", priority: 7, onClick: () => { setInputMode("expand"); setMode("input"); setInputValue(""); } },
|
|
2031
2035
|
{ key: "Tab", label: "tabs", priority: 8 },
|
|
2032
2036
|
...(registrarConfig?.apiKey ? [{ key: "r", label: "reg", priority: 9 }] : []),
|
|
2033
2037
|
{ key: "d", label: "suggest", priority: 10 },
|
|
2034
|
-
{ key: "P", label: showPortfolio ? "close" : "dash", priority: 11 },
|
|
2038
|
+
{ key: "P", label: showPortfolio ? "close" : "dash", priority: 11, onClick: () => setShowPortfolio((v) => !v) },
|
|
2035
2039
|
{ key: "p", label: "portfolio", priority: 12 },
|
|
2036
2040
|
];
|
|
2037
2041
|
const maxHints = Math.floor((width - 20) / 10);
|
|
@@ -2039,7 +2043,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
2039
2043
|
return (
|
|
2040
2044
|
<>
|
|
2041
2045
|
{visibleHints.map((h) => (
|
|
2042
|
-
<box key={h.key} flexDirection="row" gap={0}>
|
|
2046
|
+
<box key={h.key} flexDirection="row" gap={0} onMouseDown={h.onClick}>
|
|
2043
2047
|
<box backgroundColor={theme.textDisabled}><text content={` ${h.key} `} fg={theme.background} /></box>
|
|
2044
2048
|
<text content={h.label} fg={h.key === "n" && reconMode ? theme.error : h.key === "P" && showPortfolio ? theme.primary : h.key === "M" && showMarket ? theme.secondary : theme.textMuted} />
|
|
2045
2049
|
</box>
|
|
@@ -2054,7 +2058,7 @@ export function App({ initialDomains, batchFile, autoRegister = false }: AppProp
|
|
|
2054
2058
|
</>
|
|
2055
2059
|
)}
|
|
2056
2060
|
</box>
|
|
2057
|
-
<text content={stats.total > 0 ? `${stats.available + stats.expired}/${stats.total} actionable` : "
|
|
2061
|
+
<text content={stats.total > 0 ? `${stats.available + stats.expired}/${stats.total} actionable` : "v0.1.3"} fg={theme.textDisabled} />
|
|
2058
2062
|
</box>
|
|
2059
2063
|
</box>
|
|
2060
2064
|
</box>
|
package/src/index.tsx
CHANGED
|
@@ -43,7 +43,7 @@ const program = new Command();
|
|
|
43
43
|
program
|
|
44
44
|
.name("dsniper")
|
|
45
45
|
.description("All-in-one domain intelligence toolkit — availability checker, security recon, portfolio manager")
|
|
46
|
-
.version("0.1.
|
|
46
|
+
.version("0.1.3")
|
|
47
47
|
.argument("[domains...]", "Domain(s) to check")
|
|
48
48
|
.option("-f, --file <path>", "Path to file with domains (one per line)")
|
|
49
49
|
.option("-a, --auto-register", "Automatically register available domains", false)
|
|
@@ -72,6 +72,7 @@ program
|
|
|
72
72
|
const renderer = await createCliRenderer({
|
|
73
73
|
exitOnCtrlC: true,
|
|
74
74
|
screenMode: "alternate-screen",
|
|
75
|
+
useMouse: true,
|
|
75
76
|
});
|
|
76
77
|
|
|
77
78
|
createRoot(renderer).render(
|
|
@@ -873,7 +874,15 @@ program
|
|
|
873
874
|
.option("--port <port>", "Port number", "3000")
|
|
874
875
|
.action(async (opts: { port: string }) => {
|
|
875
876
|
process.env.MARKET_PORT = opts.port;
|
|
876
|
-
|
|
877
|
+
const marketPath = "../marketplace/index.js";
|
|
878
|
+
try {
|
|
879
|
+
await import(/* @vite-ignore */ marketPath);
|
|
880
|
+
} catch {
|
|
881
|
+
console.error("Marketplace server not found. Clone the private marketplace repo:");
|
|
882
|
+
console.error(" git clone https://github.com/t-rhex/domain-sniper-marketplace marketplace/");
|
|
883
|
+
console.error(" bun run serve");
|
|
884
|
+
process.exit(1);
|
|
885
|
+
}
|
|
877
886
|
});
|
|
878
887
|
|
|
879
888
|
// ─── Market subcommand ─────────────────────────────────
|