@hasna/domains 0.0.15 → 0.0.17
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/README.md +18 -2
- package/dist/cli/commands/interactive.d.ts +3 -0
- package/dist/cli/commands/interactive.d.ts.map +1 -0
- package/dist/cli/commands/providers.d.ts.map +1 -1
- package/dist/cli/index.js +650 -8
- package/dist/cli/tui/App.d.ts +6 -0
- package/dist/cli/tui/App.d.ts.map +1 -0
- package/dist/cli/tui/DomainDetail.d.ts +11 -0
- package/dist/cli/tui/DomainDetail.d.ts.map +1 -0
- package/dist/cli/tui/DomainTable.d.ts +10 -0
- package/dist/cli/tui/DomainTable.d.ts.map +1 -0
- package/dist/cli/tui/Header.d.ts +10 -0
- package/dist/cli/tui/Header.d.ts.map +1 -0
- package/dist/cli/tui/SearchView.d.ts +12 -0
- package/dist/cli/tui/SearchView.d.ts.map +1 -0
- package/dist/cli/tui/format.d.ts +17 -0
- package/dist/cli/tui/format.d.ts.map +1 -0
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ Domain portfolio and DNS management for AI agents — CLI + MCP server with SQLi
|
|
|
17
17
|
- **Registrar sync** — Namecheap and GoDaddy integration
|
|
18
18
|
- **Brand monitoring** — typosquat/threat detection via Brandsight API
|
|
19
19
|
- **MCP server** — full Model Context Protocol support for AI agents
|
|
20
|
+
- **Interactive TUI** — browse your portfolio in the terminal with `domains interactive`
|
|
20
21
|
|
|
21
22
|
## Installation
|
|
22
23
|
|
|
@@ -29,7 +30,10 @@ Data is stored at `~/.hasna/domains/domains.db`. Override with `HASNA_DOMAINS_DI
|
|
|
29
30
|
## CLI Usage
|
|
30
31
|
|
|
31
32
|
```bash
|
|
32
|
-
#
|
|
33
|
+
# Interactive portfolio browser (Ink TUI)
|
|
34
|
+
domains interactive
|
|
35
|
+
domains interactive --status active
|
|
36
|
+
```
|
|
33
37
|
domains add --name example.com --registrar Namecheap --expires-at 2025-01-01
|
|
34
38
|
domains list
|
|
35
39
|
domains list --status active --registrar Namecheap
|
|
@@ -74,7 +78,12 @@ domains sync --provider namecheap
|
|
|
74
78
|
domains sync --provider godaddy
|
|
75
79
|
domains sync --all
|
|
76
80
|
domains renew example.com --provider namecheap
|
|
77
|
-
|
|
81
|
+
|
|
82
|
+
# Availability checks — pick the registrar with --provider
|
|
83
|
+
domains check example.com # default registrar (config default-registrar, else namecheap)
|
|
84
|
+
domains check --provider route53 example.com # AWS Route 53 availability
|
|
85
|
+
domains check --provider godaddy example.com
|
|
86
|
+
domains r53 check example.com # Route 53-specific subcommand (same backend)
|
|
78
87
|
|
|
79
88
|
# Brand monitoring
|
|
80
89
|
domains monitor mybrand
|
|
@@ -82,6 +91,13 @@ domains similar example.com
|
|
|
82
91
|
domains threats example.com
|
|
83
92
|
```
|
|
84
93
|
|
|
94
|
+
> **Prefer the `domains` CLI over raw `aws` commands.** For Route 53 availability,
|
|
95
|
+
> registration status, and DNS, use `domains check --provider route53`,
|
|
96
|
+
> `domains r53 status`, and `domains dns …` instead of `aws route53domains …` /
|
|
97
|
+
> `aws route53 …`. The CLI applies the configured purchase profile, records the
|
|
98
|
+
> result in the local portfolio DB, and works the same across registrars — raw
|
|
99
|
+
> `aws` calls bypass all of that.
|
|
100
|
+
|
|
85
101
|
## MCP Server
|
|
86
102
|
|
|
87
103
|
```bash
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/interactive.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgBjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuM/D"}
|
package/dist/cli/index.js
CHANGED
|
@@ -37527,6 +37527,7 @@ Registrar / DNS Providers:`);
|
|
|
37527
37527
|
}
|
|
37528
37528
|
|
|
37529
37529
|
// src/cli/commands/providers.ts
|
|
37530
|
+
init_config();
|
|
37530
37531
|
init_domains();
|
|
37531
37532
|
function registerProviderCommands(program2) {
|
|
37532
37533
|
program2.command("providers").description("Show which registrar providers are configured").option("--json", "Output as JSON", false).action((opts) => {
|
|
@@ -37677,17 +37678,14 @@ function registerProviderCommands(program2) {
|
|
|
37677
37678
|
process.exit(1);
|
|
37678
37679
|
}
|
|
37679
37680
|
});
|
|
37680
|
-
program2.command("check").description("Check domain availability").argument("<name>", "Domain name (e.g. example.com)").option("--json", "Output as JSON", false).action(async (name, opts) => {
|
|
37681
|
+
program2.command("check").description("Check domain availability via a registrar provider (route53, namecheap, godaddy)").argument("<name>", "Domain name (e.g. example.com)").option("--provider <name>", "Registrar provider \u2014 defaults to config default-registrar, else namecheap").option("--json", "Output as JSON", false).action(async (name, opts) => {
|
|
37681
37682
|
try {
|
|
37682
|
-
const
|
|
37683
|
+
const providerName = opts.provider ?? loadConfig3().default_registrar ?? "namecheap";
|
|
37684
|
+
const result = providerName === "namecheap" ? await checkAvailability(name) : await getRegistrarProvider(providerName).checkAvailability(name);
|
|
37683
37685
|
if (opts.json) {
|
|
37684
|
-
console.log(JSON.stringify(result, null, 2));
|
|
37686
|
+
console.log(JSON.stringify({ provider: providerName, ...result }, null, 2));
|
|
37685
37687
|
} else {
|
|
37686
|
-
|
|
37687
|
-
console.log(`${result.domain} is AVAILABLE`);
|
|
37688
|
-
} else {
|
|
37689
|
-
console.log(`${result.domain} is NOT available`);
|
|
37690
|
-
}
|
|
37688
|
+
console.log(`${result.domain} is ${result.available ? "AVAILABLE" : "NOT available"} (via ${providerName})`);
|
|
37691
37689
|
}
|
|
37692
37690
|
} catch (error) {
|
|
37693
37691
|
console.error(`Availability check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -39944,6 +39942,649 @@ Domain: ${name}`);
|
|
|
39944
39942
|
});
|
|
39945
39943
|
}
|
|
39946
39944
|
|
|
39945
|
+
// src/cli/commands/interactive.tsx
|
|
39946
|
+
import chalk from "chalk";
|
|
39947
|
+
import { render } from "ink";
|
|
39948
|
+
|
|
39949
|
+
// src/cli/tui/App.tsx
|
|
39950
|
+
init_domains();
|
|
39951
|
+
init_dns_records();
|
|
39952
|
+
import { useCallback, useEffect, useMemo, useState as useState2 } from "react";
|
|
39953
|
+
import { Box as Box5, Text as Text5, useApp, useInput as useInput2 } from "ink";
|
|
39954
|
+
|
|
39955
|
+
// src/cli/tui/Header.tsx
|
|
39956
|
+
import { Box, Text } from "ink";
|
|
39957
|
+
|
|
39958
|
+
// src/cli/tui/format.ts
|
|
39959
|
+
var TABLE_COLS = {
|
|
39960
|
+
name: 28,
|
|
39961
|
+
status: 14,
|
|
39962
|
+
expires: 12,
|
|
39963
|
+
registrar: 16
|
|
39964
|
+
};
|
|
39965
|
+
function pad(value, width) {
|
|
39966
|
+
if (value.length > width)
|
|
39967
|
+
return value.slice(0, width - 1) + "\u2026";
|
|
39968
|
+
return value.padEnd(width);
|
|
39969
|
+
}
|
|
39970
|
+
function formatDate(iso) {
|
|
39971
|
+
if (!iso)
|
|
39972
|
+
return "\u2014";
|
|
39973
|
+
return iso.slice(0, 10);
|
|
39974
|
+
}
|
|
39975
|
+
function daysUntil(iso) {
|
|
39976
|
+
if (!iso)
|
|
39977
|
+
return "\u2014";
|
|
39978
|
+
const ms = new Date(iso).getTime() - Date.now();
|
|
39979
|
+
const days = Math.ceil(ms / (1000 * 60 * 60 * 24));
|
|
39980
|
+
if (days < 0)
|
|
39981
|
+
return "expired";
|
|
39982
|
+
if (days === 0)
|
|
39983
|
+
return "today";
|
|
39984
|
+
return `${days}d`;
|
|
39985
|
+
}
|
|
39986
|
+
var STATUS_COLORS = {
|
|
39987
|
+
discovered: "gray",
|
|
39988
|
+
researching: "blue",
|
|
39989
|
+
offered: "yellow",
|
|
39990
|
+
negotiating: "yellow",
|
|
39991
|
+
purchased: "green",
|
|
39992
|
+
active: "green",
|
|
39993
|
+
not_available: "red",
|
|
39994
|
+
premium_only: "magenta",
|
|
39995
|
+
declined: "red",
|
|
39996
|
+
expired: "red",
|
|
39997
|
+
transferring: "cyan",
|
|
39998
|
+
redemption: "red"
|
|
39999
|
+
};
|
|
40000
|
+
var DOMAIN_FILTERS = ["all", "active", "expiring", "premium"];
|
|
40001
|
+
function filterLabel(filter) {
|
|
40002
|
+
switch (filter) {
|
|
40003
|
+
case "all":
|
|
40004
|
+
return "All";
|
|
40005
|
+
case "active":
|
|
40006
|
+
return "Active";
|
|
40007
|
+
case "expiring":
|
|
40008
|
+
return "Expiring (30d)";
|
|
40009
|
+
case "premium":
|
|
40010
|
+
return "Premium";
|
|
40011
|
+
}
|
|
40012
|
+
}
|
|
40013
|
+
|
|
40014
|
+
// src/cli/tui/Header.tsx
|
|
40015
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
40016
|
+
function Header({ count, filter, view }) {
|
|
40017
|
+
const viewLabel = view === "list" ? "Portfolio" : view === "detail" ? "Detail" : "Search";
|
|
40018
|
+
return /* @__PURE__ */ jsxDEV(Box, {
|
|
40019
|
+
flexDirection: "column",
|
|
40020
|
+
marginBottom: 1,
|
|
40021
|
+
children: [
|
|
40022
|
+
/* @__PURE__ */ jsxDEV(Box, {
|
|
40023
|
+
children: [
|
|
40024
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
40025
|
+
bold: true,
|
|
40026
|
+
color: "cyan",
|
|
40027
|
+
children: "domains"
|
|
40028
|
+
}, undefined, false, undefined, this),
|
|
40029
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
40030
|
+
dimColor: true,
|
|
40031
|
+
children: " \u2014 interactive portfolio browser"
|
|
40032
|
+
}, undefined, false, undefined, this)
|
|
40033
|
+
]
|
|
40034
|
+
}, undefined, true, undefined, this),
|
|
40035
|
+
/* @__PURE__ */ jsxDEV(Box, {
|
|
40036
|
+
children: /* @__PURE__ */ jsxDEV(Text, {
|
|
40037
|
+
dimColor: true,
|
|
40038
|
+
children: [
|
|
40039
|
+
viewLabel,
|
|
40040
|
+
" \xB7 ",
|
|
40041
|
+
filterLabel(filter),
|
|
40042
|
+
" \xB7 ",
|
|
40043
|
+
count,
|
|
40044
|
+
" domain",
|
|
40045
|
+
count === 1 ? "" : "s"
|
|
40046
|
+
]
|
|
40047
|
+
}, undefined, true, undefined, this)
|
|
40048
|
+
}, undefined, false, undefined, this)
|
|
40049
|
+
]
|
|
40050
|
+
}, undefined, true, undefined, this);
|
|
40051
|
+
}
|
|
40052
|
+
|
|
40053
|
+
// src/cli/tui/DomainTable.tsx
|
|
40054
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
40055
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
40056
|
+
var VISIBLE_ROWS = 16;
|
|
40057
|
+
function DomainTable({ domains, selectedIndex, compact = false }) {
|
|
40058
|
+
if (domains.length === 0) {
|
|
40059
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
40060
|
+
flexDirection: "column",
|
|
40061
|
+
paddingLeft: compact ? 0 : 1,
|
|
40062
|
+
children: /* @__PURE__ */ jsxDEV2(Text2, {
|
|
40063
|
+
dimColor: true,
|
|
40064
|
+
children: "No domains match this filter. Press [f] to change filter or [r] to refresh."
|
|
40065
|
+
}, undefined, false, undefined, this)
|
|
40066
|
+
}, undefined, false, undefined, this);
|
|
40067
|
+
}
|
|
40068
|
+
const start = Math.max(0, Math.min(selectedIndex - Math.floor(VISIBLE_ROWS / 2), Math.max(0, domains.length - VISIBLE_ROWS)));
|
|
40069
|
+
const visible = domains.slice(start, start + VISIBLE_ROWS);
|
|
40070
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
40071
|
+
flexDirection: "column",
|
|
40072
|
+
width: "100%",
|
|
40073
|
+
paddingRight: 0,
|
|
40074
|
+
children: [
|
|
40075
|
+
/* @__PURE__ */ jsxDEV2(Box2, {
|
|
40076
|
+
children: /* @__PURE__ */ jsxDEV2(Text2, {
|
|
40077
|
+
bold: true,
|
|
40078
|
+
dimColor: true,
|
|
40079
|
+
children: [
|
|
40080
|
+
pad("NAME", TABLE_COLS.name),
|
|
40081
|
+
pad("STATUS", TABLE_COLS.status),
|
|
40082
|
+
pad("EXPIRES", TABLE_COLS.expires),
|
|
40083
|
+
pad("REGISTRAR", TABLE_COLS.registrar),
|
|
40084
|
+
!compact ? " TTL" : ""
|
|
40085
|
+
]
|
|
40086
|
+
}, undefined, true, undefined, this)
|
|
40087
|
+
}, undefined, false, undefined, this),
|
|
40088
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
40089
|
+
dimColor: true,
|
|
40090
|
+
children: "\u2500".repeat(TABLE_COLS.name + TABLE_COLS.status + TABLE_COLS.expires + TABLE_COLS.registrar + (compact ? 0 : 6))
|
|
40091
|
+
}, undefined, false, undefined, this),
|
|
40092
|
+
start > 0 && /* @__PURE__ */ jsxDEV2(Text2, {
|
|
40093
|
+
dimColor: true,
|
|
40094
|
+
children: [
|
|
40095
|
+
" \u2191 ",
|
|
40096
|
+
start,
|
|
40097
|
+
" more above"
|
|
40098
|
+
]
|
|
40099
|
+
}, undefined, true, undefined, this),
|
|
40100
|
+
visible.map((domain, offset) => {
|
|
40101
|
+
const index = start + offset;
|
|
40102
|
+
const selected = index === selectedIndex;
|
|
40103
|
+
const statusColor = STATUS_COLORS[domain.status] ?? "white";
|
|
40104
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
40105
|
+
children: [
|
|
40106
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
40107
|
+
color: selected ? "cyan" : undefined,
|
|
40108
|
+
bold: selected,
|
|
40109
|
+
children: selected ? "\u276F " : " "
|
|
40110
|
+
}, undefined, false, undefined, this),
|
|
40111
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
40112
|
+
bold: selected,
|
|
40113
|
+
children: pad(domain.name, TABLE_COLS.name)
|
|
40114
|
+
}, undefined, false, undefined, this),
|
|
40115
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
40116
|
+
color: statusColor,
|
|
40117
|
+
children: pad(domain.status, TABLE_COLS.status)
|
|
40118
|
+
}, undefined, false, undefined, this),
|
|
40119
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
40120
|
+
children: pad(formatDate(domain.expires_at), TABLE_COLS.expires)
|
|
40121
|
+
}, undefined, false, undefined, this),
|
|
40122
|
+
/* @__PURE__ */ jsxDEV2(Text2, {
|
|
40123
|
+
dimColor: true,
|
|
40124
|
+
children: pad(domain.registrar ?? "\u2014", TABLE_COLS.registrar)
|
|
40125
|
+
}, undefined, false, undefined, this),
|
|
40126
|
+
!compact && /* @__PURE__ */ jsxDEV2(Text2, {
|
|
40127
|
+
dimColor: true,
|
|
40128
|
+
children: [
|
|
40129
|
+
" ",
|
|
40130
|
+
daysUntil(domain.expires_at)
|
|
40131
|
+
]
|
|
40132
|
+
}, undefined, true, undefined, this)
|
|
40133
|
+
]
|
|
40134
|
+
}, domain.id, true, undefined, this);
|
|
40135
|
+
}),
|
|
40136
|
+
start + visible.length < domains.length && /* @__PURE__ */ jsxDEV2(Text2, {
|
|
40137
|
+
dimColor: true,
|
|
40138
|
+
children: [
|
|
40139
|
+
" \u2193 ",
|
|
40140
|
+
domains.length - start - visible.length,
|
|
40141
|
+
" more below"
|
|
40142
|
+
]
|
|
40143
|
+
}, undefined, true, undefined, this)
|
|
40144
|
+
]
|
|
40145
|
+
}, undefined, true, undefined, this);
|
|
40146
|
+
}
|
|
40147
|
+
|
|
40148
|
+
// src/cli/tui/DomainDetail.tsx
|
|
40149
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
40150
|
+
import { jsxDEV as jsxDEV3, Fragment } from "react/jsx-dev-runtime";
|
|
40151
|
+
function DomainDetail({ details, dnsRecords = [], compact = false }) {
|
|
40152
|
+
const { domain, offers, emails } = details;
|
|
40153
|
+
const statusColor = STATUS_COLORS[domain.status] ?? "white";
|
|
40154
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40155
|
+
flexDirection: "column",
|
|
40156
|
+
width: compact ? "45%" : "100%",
|
|
40157
|
+
paddingLeft: compact ? 1 : 0,
|
|
40158
|
+
children: [
|
|
40159
|
+
!compact && /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40160
|
+
marginBottom: 1,
|
|
40161
|
+
children: /* @__PURE__ */ jsxDEV3(Text3, {
|
|
40162
|
+
dimColor: true,
|
|
40163
|
+
children: "[esc] back \xB7 [r] refresh \xB7 q quit"
|
|
40164
|
+
}, undefined, false, undefined, this)
|
|
40165
|
+
}, undefined, false, undefined, this),
|
|
40166
|
+
/* @__PURE__ */ jsxDEV3(Box3, {
|
|
40167
|
+
flexDirection: "column",
|
|
40168
|
+
marginBottom: 1,
|
|
40169
|
+
children: [
|
|
40170
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40171
|
+
bold: true,
|
|
40172
|
+
color: "cyan",
|
|
40173
|
+
children: domain.name
|
|
40174
|
+
}, undefined, false, undefined, this),
|
|
40175
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40176
|
+
color: statusColor,
|
|
40177
|
+
children: [
|
|
40178
|
+
"[",
|
|
40179
|
+
domain.status,
|
|
40180
|
+
"]"
|
|
40181
|
+
]
|
|
40182
|
+
}, undefined, true, undefined, this)
|
|
40183
|
+
]
|
|
40184
|
+
}, undefined, true, undefined, this),
|
|
40185
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40186
|
+
label: "Registrar",
|
|
40187
|
+
value: domain.registrar
|
|
40188
|
+
}, undefined, false, undefined, this),
|
|
40189
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40190
|
+
label: "Registered",
|
|
40191
|
+
value: formatDate(domain.registered_at)
|
|
40192
|
+
}, undefined, false, undefined, this),
|
|
40193
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40194
|
+
label: "Expires",
|
|
40195
|
+
value: formatDate(domain.expires_at)
|
|
40196
|
+
}, undefined, false, undefined, this),
|
|
40197
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40198
|
+
label: "Auto-renew",
|
|
40199
|
+
value: domain.auto_renew ? "yes" : "no"
|
|
40200
|
+
}, undefined, false, undefined, this),
|
|
40201
|
+
domain.is_premium && /* @__PURE__ */ jsxDEV3(Fragment, {
|
|
40202
|
+
children: [
|
|
40203
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40204
|
+
label: "Premium",
|
|
40205
|
+
value: "yes"
|
|
40206
|
+
}, undefined, false, undefined, this),
|
|
40207
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40208
|
+
label: "Premium ask",
|
|
40209
|
+
value: domain.premium_price?.toString() ?? "\u2014"
|
|
40210
|
+
}, undefined, false, undefined, this)
|
|
40211
|
+
]
|
|
40212
|
+
}, undefined, true, undefined, this),
|
|
40213
|
+
domain.purchase_price !== null && /* @__PURE__ */ jsxDEV3(Field, {
|
|
40214
|
+
label: "Purchase price",
|
|
40215
|
+
value: String(domain.purchase_price)
|
|
40216
|
+
}, undefined, false, undefined, this),
|
|
40217
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40218
|
+
label: "SSL issuer",
|
|
40219
|
+
value: domain.ssl_issuer
|
|
40220
|
+
}, undefined, false, undefined, this),
|
|
40221
|
+
/* @__PURE__ */ jsxDEV3(Field, {
|
|
40222
|
+
label: "SSL expires",
|
|
40223
|
+
value: formatDate(domain.ssl_expires_at)
|
|
40224
|
+
}, undefined, false, undefined, this),
|
|
40225
|
+
domain.nameservers.length > 0 && /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40226
|
+
flexDirection: "column",
|
|
40227
|
+
marginTop: 1,
|
|
40228
|
+
children: [
|
|
40229
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40230
|
+
bold: true,
|
|
40231
|
+
dimColor: true,
|
|
40232
|
+
children: "Nameservers"
|
|
40233
|
+
}, undefined, false, undefined, this),
|
|
40234
|
+
domain.nameservers.slice(0, compact ? 3 : 8).map((ns) => /* @__PURE__ */ jsxDEV3(Text3, {
|
|
40235
|
+
dimColor: true,
|
|
40236
|
+
children: [
|
|
40237
|
+
" ",
|
|
40238
|
+
ns
|
|
40239
|
+
]
|
|
40240
|
+
}, ns, true, undefined, this))
|
|
40241
|
+
]
|
|
40242
|
+
}, undefined, true, undefined, this),
|
|
40243
|
+
!compact && dnsRecords.length > 0 && /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40244
|
+
flexDirection: "column",
|
|
40245
|
+
marginTop: 1,
|
|
40246
|
+
children: [
|
|
40247
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40248
|
+
bold: true,
|
|
40249
|
+
children: [
|
|
40250
|
+
"DNS records (",
|
|
40251
|
+
dnsRecords.length,
|
|
40252
|
+
")"
|
|
40253
|
+
]
|
|
40254
|
+
}, undefined, true, undefined, this),
|
|
40255
|
+
dnsRecords.slice(0, 8).map((record) => /* @__PURE__ */ jsxDEV3(Text3, {
|
|
40256
|
+
dimColor: true,
|
|
40257
|
+
children: [
|
|
40258
|
+
" ",
|
|
40259
|
+
record.type,
|
|
40260
|
+
" ",
|
|
40261
|
+
record.name,
|
|
40262
|
+
" \u2192 ",
|
|
40263
|
+
record.value
|
|
40264
|
+
]
|
|
40265
|
+
}, record.id, true, undefined, this)),
|
|
40266
|
+
dnsRecords.length > 8 && /* @__PURE__ */ jsxDEV3(Text3, {
|
|
40267
|
+
dimColor: true,
|
|
40268
|
+
children: [
|
|
40269
|
+
" \u2026 ",
|
|
40270
|
+
dnsRecords.length - 8,
|
|
40271
|
+
" more"
|
|
40272
|
+
]
|
|
40273
|
+
}, undefined, true, undefined, this)
|
|
40274
|
+
]
|
|
40275
|
+
}, undefined, true, undefined, this),
|
|
40276
|
+
(offers.length > 0 || emails.length > 0) && /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40277
|
+
marginTop: 1,
|
|
40278
|
+
children: /* @__PURE__ */ jsxDEV3(Text3, {
|
|
40279
|
+
dimColor: true,
|
|
40280
|
+
children: [
|
|
40281
|
+
"Offers: ",
|
|
40282
|
+
offers.length,
|
|
40283
|
+
" \xB7 Linked emails: ",
|
|
40284
|
+
emails.length,
|
|
40285
|
+
dnsRecords.length > 0 ? ` \xB7 DNS: ${dnsRecords.length}` : ""
|
|
40286
|
+
]
|
|
40287
|
+
}, undefined, true, undefined, this)
|
|
40288
|
+
}, undefined, false, undefined, this),
|
|
40289
|
+
domain.notes && !compact && /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40290
|
+
flexDirection: "column",
|
|
40291
|
+
marginTop: 1,
|
|
40292
|
+
children: [
|
|
40293
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40294
|
+
bold: true,
|
|
40295
|
+
dimColor: true,
|
|
40296
|
+
children: "Notes"
|
|
40297
|
+
}, undefined, false, undefined, this),
|
|
40298
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40299
|
+
wrap: "wrap",
|
|
40300
|
+
children: domain.notes
|
|
40301
|
+
}, undefined, false, undefined, this)
|
|
40302
|
+
]
|
|
40303
|
+
}, undefined, true, undefined, this),
|
|
40304
|
+
!compact && /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40305
|
+
marginTop: 1,
|
|
40306
|
+
children: /* @__PURE__ */ jsxDEV3(Text3, {
|
|
40307
|
+
dimColor: true,
|
|
40308
|
+
children: [
|
|
40309
|
+
"ID: ",
|
|
40310
|
+
domain.id
|
|
40311
|
+
]
|
|
40312
|
+
}, undefined, true, undefined, this)
|
|
40313
|
+
}, undefined, false, undefined, this)
|
|
40314
|
+
]
|
|
40315
|
+
}, undefined, true, undefined, this);
|
|
40316
|
+
}
|
|
40317
|
+
function Field({ label, value }) {
|
|
40318
|
+
if (!value || value === "\u2014") {
|
|
40319
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40320
|
+
children: [
|
|
40321
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40322
|
+
dimColor: true,
|
|
40323
|
+
children: label.padEnd(14)
|
|
40324
|
+
}, undefined, false, undefined, this),
|
|
40325
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40326
|
+
dimColor: true,
|
|
40327
|
+
children: "\u2014"
|
|
40328
|
+
}, undefined, false, undefined, this)
|
|
40329
|
+
]
|
|
40330
|
+
}, undefined, true, undefined, this);
|
|
40331
|
+
}
|
|
40332
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
40333
|
+
children: [
|
|
40334
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40335
|
+
dimColor: true,
|
|
40336
|
+
children: label.padEnd(14)
|
|
40337
|
+
}, undefined, false, undefined, this),
|
|
40338
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
40339
|
+
children: value
|
|
40340
|
+
}, undefined, false, undefined, this)
|
|
40341
|
+
]
|
|
40342
|
+
}, undefined, true, undefined, this);
|
|
40343
|
+
}
|
|
40344
|
+
|
|
40345
|
+
// src/cli/tui/SearchView.tsx
|
|
40346
|
+
import { useState } from "react";
|
|
40347
|
+
import { Box as Box4, Text as Text4, useInput } from "ink";
|
|
40348
|
+
import TextInput from "ink-text-input";
|
|
40349
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
40350
|
+
function SearchView({
|
|
40351
|
+
results,
|
|
40352
|
+
selectedIndex,
|
|
40353
|
+
onSearch,
|
|
40354
|
+
onSelect,
|
|
40355
|
+
onBack
|
|
40356
|
+
}) {
|
|
40357
|
+
const [query, setQuery] = useState("");
|
|
40358
|
+
useInput((input, key) => {
|
|
40359
|
+
if (key.escape)
|
|
40360
|
+
onBack();
|
|
40361
|
+
if (key.return && results[selectedIndex]) {
|
|
40362
|
+
onSelect(results[selectedIndex]);
|
|
40363
|
+
}
|
|
40364
|
+
});
|
|
40365
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
40366
|
+
flexDirection: "column",
|
|
40367
|
+
children: [
|
|
40368
|
+
/* @__PURE__ */ jsxDEV4(Box4, {
|
|
40369
|
+
marginBottom: 1,
|
|
40370
|
+
children: /* @__PURE__ */ jsxDEV4(Text4, {
|
|
40371
|
+
bold: true,
|
|
40372
|
+
children: "Search domains"
|
|
40373
|
+
}, undefined, false, undefined, this)
|
|
40374
|
+
}, undefined, false, undefined, this),
|
|
40375
|
+
/* @__PURE__ */ jsxDEV4(Box4, {
|
|
40376
|
+
marginBottom: 1,
|
|
40377
|
+
children: [
|
|
40378
|
+
/* @__PURE__ */ jsxDEV4(Text4, {
|
|
40379
|
+
dimColor: true,
|
|
40380
|
+
children: "Query: "
|
|
40381
|
+
}, undefined, false, undefined, this),
|
|
40382
|
+
/* @__PURE__ */ jsxDEV4(TextInput, {
|
|
40383
|
+
value: query,
|
|
40384
|
+
onChange: (value) => {
|
|
40385
|
+
setQuery(value);
|
|
40386
|
+
onSearch(value);
|
|
40387
|
+
},
|
|
40388
|
+
placeholder: "name, registrar, notes\u2026"
|
|
40389
|
+
}, undefined, false, undefined, this)
|
|
40390
|
+
]
|
|
40391
|
+
}, undefined, true, undefined, this),
|
|
40392
|
+
/* @__PURE__ */ jsxDEV4(Text4, {
|
|
40393
|
+
dimColor: true,
|
|
40394
|
+
children: "[enter] open \xB7 [esc] back"
|
|
40395
|
+
}, undefined, false, undefined, this),
|
|
40396
|
+
/* @__PURE__ */ jsxDEV4(Box4, {
|
|
40397
|
+
marginTop: 1,
|
|
40398
|
+
children: /* @__PURE__ */ jsxDEV4(DomainTable, {
|
|
40399
|
+
domains: results,
|
|
40400
|
+
selectedIndex
|
|
40401
|
+
}, undefined, false, undefined, this)
|
|
40402
|
+
}, undefined, false, undefined, this)
|
|
40403
|
+
]
|
|
40404
|
+
}, undefined, true, undefined, this);
|
|
40405
|
+
}
|
|
40406
|
+
|
|
40407
|
+
// src/cli/tui/App.tsx
|
|
40408
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
40409
|
+
function loadDomainsForFilter(activeFilter) {
|
|
40410
|
+
switch (activeFilter) {
|
|
40411
|
+
case "active":
|
|
40412
|
+
return listDomains({ status: "active" });
|
|
40413
|
+
case "premium":
|
|
40414
|
+
return listDomains({ is_premium: true });
|
|
40415
|
+
case "expiring":
|
|
40416
|
+
return listExpiring(30);
|
|
40417
|
+
default:
|
|
40418
|
+
return listDomains();
|
|
40419
|
+
}
|
|
40420
|
+
}
|
|
40421
|
+
function App({ initialStatus }) {
|
|
40422
|
+
const { exit } = useApp();
|
|
40423
|
+
const [view, setView] = useState2("list");
|
|
40424
|
+
const initialFilter = initialStatus === "active" ? "active" : initialStatus === "premium" ? "premium" : "all";
|
|
40425
|
+
const [filter, setFilter] = useState2(initialFilter);
|
|
40426
|
+
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
40427
|
+
const [details, setDetails] = useState2(null);
|
|
40428
|
+
const [searchResults, setSearchResults] = useState2([]);
|
|
40429
|
+
const [searchIndex, setSearchIndex] = useState2(0);
|
|
40430
|
+
const [domains, setDomains] = useState2(() => loadDomainsForFilter(initialFilter));
|
|
40431
|
+
const refresh = useCallback(() => {
|
|
40432
|
+
const next = loadDomainsForFilter(filter);
|
|
40433
|
+
setDomains(next);
|
|
40434
|
+
setSelectedIndex((current) => Math.min(current, Math.max(0, next.length - 1)));
|
|
40435
|
+
return next;
|
|
40436
|
+
}, [filter]);
|
|
40437
|
+
useEffect(() => {
|
|
40438
|
+
refresh();
|
|
40439
|
+
}, [refresh]);
|
|
40440
|
+
const selectedDomain = domains[selectedIndex] ?? null;
|
|
40441
|
+
const previewDetails = useMemo(() => {
|
|
40442
|
+
if (!selectedDomain)
|
|
40443
|
+
return null;
|
|
40444
|
+
return getDomainDetails(selectedDomain.id);
|
|
40445
|
+
}, [selectedDomain]);
|
|
40446
|
+
const previewDns = useMemo(() => {
|
|
40447
|
+
if (!selectedDomain)
|
|
40448
|
+
return [];
|
|
40449
|
+
return listDnsRecords(selectedDomain.id);
|
|
40450
|
+
}, [selectedDomain]);
|
|
40451
|
+
useInput2((input, key) => {
|
|
40452
|
+
if (input === "q" && view !== "search") {
|
|
40453
|
+
exit();
|
|
40454
|
+
return;
|
|
40455
|
+
}
|
|
40456
|
+
if (view === "list") {
|
|
40457
|
+
if (key.upArrow || input === "k") {
|
|
40458
|
+
setSelectedIndex((index) => Math.max(0, index - 1));
|
|
40459
|
+
} else if (key.downArrow || input === "j") {
|
|
40460
|
+
setSelectedIndex((index) => Math.min(domains.length - 1, index + 1));
|
|
40461
|
+
} else if (key.return && selectedDomain) {
|
|
40462
|
+
const full = getDomainDetails(selectedDomain.id);
|
|
40463
|
+
if (full) {
|
|
40464
|
+
setDetails(full);
|
|
40465
|
+
setView("detail");
|
|
40466
|
+
}
|
|
40467
|
+
} else if (input === "/") {
|
|
40468
|
+
setSearchResults([]);
|
|
40469
|
+
setSearchIndex(0);
|
|
40470
|
+
setView("search");
|
|
40471
|
+
} else if (input === "f") {
|
|
40472
|
+
setFilter((current) => {
|
|
40473
|
+
const index = DOMAIN_FILTERS.indexOf(current);
|
|
40474
|
+
return DOMAIN_FILTERS[(index + 1) % DOMAIN_FILTERS.length];
|
|
40475
|
+
});
|
|
40476
|
+
} else if (input === "r") {
|
|
40477
|
+
refresh();
|
|
40478
|
+
}
|
|
40479
|
+
return;
|
|
40480
|
+
}
|
|
40481
|
+
if (view === "search") {
|
|
40482
|
+
if (key.upArrow || input === "k") {
|
|
40483
|
+
setSearchIndex((index) => Math.max(0, index - 1));
|
|
40484
|
+
} else if (key.downArrow || input === "j") {
|
|
40485
|
+
setSearchIndex((index) => Math.min(searchResults.length - 1, index + 1));
|
|
40486
|
+
}
|
|
40487
|
+
return;
|
|
40488
|
+
}
|
|
40489
|
+
if (view === "detail") {
|
|
40490
|
+
if (key.escape) {
|
|
40491
|
+
setView("list");
|
|
40492
|
+
refresh();
|
|
40493
|
+
} else if (input === "r" && details) {
|
|
40494
|
+
setDetails(getDomainDetails(details.domain.id));
|
|
40495
|
+
}
|
|
40496
|
+
}
|
|
40497
|
+
});
|
|
40498
|
+
const handleSearch = useCallback((query) => {
|
|
40499
|
+
const trimmed = query.trim();
|
|
40500
|
+
if (trimmed.length < 2) {
|
|
40501
|
+
setSearchResults([]);
|
|
40502
|
+
setSearchIndex(0);
|
|
40503
|
+
return;
|
|
40504
|
+
}
|
|
40505
|
+
const results = searchDomains(trimmed);
|
|
40506
|
+
setSearchResults(results);
|
|
40507
|
+
setSearchIndex(0);
|
|
40508
|
+
}, []);
|
|
40509
|
+
const handleSearchSelect = useCallback((domain) => {
|
|
40510
|
+
const full = getDomainDetails(domain.id);
|
|
40511
|
+
if (full) {
|
|
40512
|
+
setDetails(full);
|
|
40513
|
+
setView("detail");
|
|
40514
|
+
}
|
|
40515
|
+
}, []);
|
|
40516
|
+
const detailDns = details ? listDnsRecords(details.domain.id) : [];
|
|
40517
|
+
return /* @__PURE__ */ jsxDEV5(Box5, {
|
|
40518
|
+
flexDirection: "column",
|
|
40519
|
+
padding: 1,
|
|
40520
|
+
children: [
|
|
40521
|
+
/* @__PURE__ */ jsxDEV5(Header, {
|
|
40522
|
+
count: view === "search" ? searchResults.length : domains.length,
|
|
40523
|
+
filter,
|
|
40524
|
+
view
|
|
40525
|
+
}, undefined, false, undefined, this),
|
|
40526
|
+
view === "list" && /* @__PURE__ */ jsxDEV5(Box5, {
|
|
40527
|
+
flexDirection: "column",
|
|
40528
|
+
children: [
|
|
40529
|
+
/* @__PURE__ */ jsxDEV5(DomainTable, {
|
|
40530
|
+
domains,
|
|
40531
|
+
selectedIndex
|
|
40532
|
+
}, undefined, false, undefined, this),
|
|
40533
|
+
previewDetails && /* @__PURE__ */ jsxDEV5(Box5, {
|
|
40534
|
+
marginTop: 1,
|
|
40535
|
+
flexDirection: "column",
|
|
40536
|
+
children: [
|
|
40537
|
+
/* @__PURE__ */ jsxDEV5(Text5, {
|
|
40538
|
+
bold: true,
|
|
40539
|
+
dimColor: true,
|
|
40540
|
+
children: "Selected"
|
|
40541
|
+
}, undefined, false, undefined, this),
|
|
40542
|
+
/* @__PURE__ */ jsxDEV5(DomainDetail, {
|
|
40543
|
+
details: previewDetails,
|
|
40544
|
+
dnsRecords: previewDns,
|
|
40545
|
+
compact: true
|
|
40546
|
+
}, undefined, false, undefined, this)
|
|
40547
|
+
]
|
|
40548
|
+
}, undefined, true, undefined, this),
|
|
40549
|
+
/* @__PURE__ */ jsxDEV5(Box5, {
|
|
40550
|
+
marginTop: 1,
|
|
40551
|
+
children: /* @__PURE__ */ jsxDEV5(Text5, {
|
|
40552
|
+
dimColor: true,
|
|
40553
|
+
children: "\u2191\u2193 j/k navigate \xB7 enter detail \xB7 / search \xB7 f filter \xB7 r refresh \xB7 q quit"
|
|
40554
|
+
}, undefined, false, undefined, this)
|
|
40555
|
+
}, undefined, false, undefined, this)
|
|
40556
|
+
]
|
|
40557
|
+
}, undefined, true, undefined, this),
|
|
40558
|
+
view === "detail" && details && /* @__PURE__ */ jsxDEV5(DomainDetail, {
|
|
40559
|
+
details,
|
|
40560
|
+
dnsRecords: detailDns
|
|
40561
|
+
}, undefined, false, undefined, this),
|
|
40562
|
+
view === "search" && /* @__PURE__ */ jsxDEV5(SearchView, {
|
|
40563
|
+
results: searchResults,
|
|
40564
|
+
selectedIndex: searchIndex,
|
|
40565
|
+
onSearch: handleSearch,
|
|
40566
|
+
onSelect: handleSearchSelect,
|
|
40567
|
+
onBack: () => setView("list")
|
|
40568
|
+
}, undefined, false, undefined, this)
|
|
40569
|
+
]
|
|
40570
|
+
}, undefined, true, undefined, this);
|
|
40571
|
+
}
|
|
40572
|
+
|
|
40573
|
+
// src/cli/commands/interactive.tsx
|
|
40574
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
40575
|
+
function registerInteractiveCommand(program2) {
|
|
40576
|
+
program2.command("interactive").description("Launch interactive domain portfolio browser (Ink TUI)").option("--status <status>", "Initial filter status (e.g. active, premium)").action((opts) => {
|
|
40577
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
40578
|
+
console.error(chalk.red("Interactive mode requires a TTY terminal."));
|
|
40579
|
+
console.error(chalk.dim("Use `domains domain list` or `domains domain get <name>` for non-interactive use."));
|
|
40580
|
+
process.exit(1);
|
|
40581
|
+
}
|
|
40582
|
+
render(/* @__PURE__ */ jsxDEV6(App, {
|
|
40583
|
+
initialStatus: opts.status
|
|
40584
|
+
}, undefined, false, undefined, this));
|
|
40585
|
+
});
|
|
40586
|
+
}
|
|
40587
|
+
|
|
39947
40588
|
// src/cli/index.ts
|
|
39948
40589
|
init_version();
|
|
39949
40590
|
var program2 = new Command;
|
|
@@ -39968,4 +40609,5 @@ registerOutreachCommand(program2);
|
|
|
39968
40609
|
registerSedoCommand(program2);
|
|
39969
40610
|
registerWalletCommand(program2);
|
|
39970
40611
|
registerProvisionCommand(program2);
|
|
40612
|
+
registerInteractiveCommand(program2);
|
|
39971
40613
|
program2.parse(process.argv);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoD,MAAM,OAAO,CAAC;AAmBzE,MAAM,WAAW,QAAQ;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAeD,wBAAgB,GAAG,CAAC,EAAE,aAAa,EAAE,EAAE,QAAQ,qBAqJ9C"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { DomainDetails } from "../../db/domains.js";
|
|
3
|
+
import type { DnsRecord } from "../../db/dns-records.js";
|
|
4
|
+
interface DomainDetailProps {
|
|
5
|
+
details: DomainDetails;
|
|
6
|
+
dnsRecords?: DnsRecord[];
|
|
7
|
+
compact?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function DomainDetail({ details, dnsRecords, compact }: DomainDetailProps): React.JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=DomainDetail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DomainDetail.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/DomainDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGzD,UAAU,iBAAiB;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,UAAe,EAAE,OAAe,EAAE,EAAE,iBAAiB,qBAqF5F"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Domain } from "../../db/domains.js";
|
|
3
|
+
interface DomainTableProps {
|
|
4
|
+
domains: Domain[];
|
|
5
|
+
selectedIndex: number;
|
|
6
|
+
compact?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function DomainTable({ domains, selectedIndex, compact }: DomainTableProps): React.JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=DomainTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DomainTable.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/DomainTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAWlD,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,OAAe,EAAE,EAAE,gBAAgB,qBA2DxF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { DomainFilter } from "./format.js";
|
|
3
|
+
interface HeaderProps {
|
|
4
|
+
count: number;
|
|
5
|
+
filter: DomainFilter;
|
|
6
|
+
view: "list" | "detail" | "search";
|
|
7
|
+
}
|
|
8
|
+
export declare function Header({ count, filter, view }: HeaderProps): React.JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=Header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACpC;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,WAAW,qBAmB1D"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Domain } from "../../db/domains.js";
|
|
3
|
+
interface SearchViewProps {
|
|
4
|
+
results: Domain[];
|
|
5
|
+
selectedIndex: number;
|
|
6
|
+
onSearch: (query: string) => void;
|
|
7
|
+
onSelect: (domain: Domain) => void;
|
|
8
|
+
onBack: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function SearchView({ results, selectedIndex, onSearch, onSelect, onBack, }: SearchViewProps): React.JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=SearchView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchView.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/SearchView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,MAAM,GACP,EAAE,eAAe,qBAgCjB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Domain, DomainStatus } from "../../db/domains.js";
|
|
2
|
+
export declare const TABLE_COLS: {
|
|
3
|
+
readonly name: 28;
|
|
4
|
+
readonly status: 14;
|
|
5
|
+
readonly expires: 12;
|
|
6
|
+
readonly registrar: 16;
|
|
7
|
+
};
|
|
8
|
+
export declare function pad(value: string, width: number): string;
|
|
9
|
+
export declare function formatDate(iso: string | null | undefined): string;
|
|
10
|
+
export declare function daysUntil(iso: string | null | undefined): string;
|
|
11
|
+
export declare const STATUS_COLORS: Record<DomainStatus, string>;
|
|
12
|
+
export declare function domainRowLabel(domain: Domain): string;
|
|
13
|
+
export declare function stripAnsi(value: string | undefined): string;
|
|
14
|
+
export type DomainFilter = "all" | "active" | "expiring" | "premium";
|
|
15
|
+
export declare const DOMAIN_FILTERS: DomainFilter[];
|
|
16
|
+
export declare function filterLabel(filter: DomainFilter): string;
|
|
17
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEhE,eAAO,MAAM,UAAU;;;;;CAKb,CAAC;AAEX,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGjE;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAOhE;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAatD,CAAC;AAEF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAErE,eAAO,MAAM,cAAc,EAAE,YAAY,EAA6C,CAAC;AAEvF,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAWxD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/domains",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "Domain portfolio and DNS management for AI agents — CLI + MCP server with SQLite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"README.md"
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
|
-
"build": "bun build src/cli/index.ts --outdir dist/cli --target bun --external @modelcontextprotocol/sdk --external @hasna/cloud && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @hasna/cloud && bun build src/index.ts --outdir dist --target bun --external @hasna/cloud && tsc --emitDeclarationOnly --outDir dist",
|
|
24
|
+
"build": "bun build src/cli/index.ts --outdir dist/cli --target bun --external ink --external react --external chalk --external ink-text-input --external @modelcontextprotocol/sdk --external @hasna/cloud && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @hasna/cloud && bun build src/index.ts --outdir dist --target bun --external @hasna/cloud && tsc --emitDeclarationOnly --outDir dist",
|
|
25
25
|
"typecheck": "tsc --noEmit",
|
|
26
26
|
"test": "bun test",
|
|
27
27
|
"dev:cli": "bun run src/cli/index.ts",
|
|
@@ -65,11 +65,17 @@
|
|
|
65
65
|
"@hasna/contacts": "^0.6.16",
|
|
66
66
|
"@hasna/wallets": "^0.1.7",
|
|
67
67
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
68
|
+
"chalk": "^5.4.1",
|
|
68
69
|
"commander": "^13.1.0",
|
|
70
|
+
"ink": "^5.2.0",
|
|
71
|
+
"ink-text-input": "^6.0.0",
|
|
72
|
+
"react": "^18.3.1",
|
|
69
73
|
"zod": "^3.24.2"
|
|
70
74
|
},
|
|
71
75
|
"devDependencies": {
|
|
72
76
|
"@types/bun": "^1.2.4",
|
|
77
|
+
"@types/react": "^18.3.18",
|
|
78
|
+
"ink-testing-library": "^4.0.0",
|
|
73
79
|
"typescript": "^5.7.3"
|
|
74
80
|
}
|
|
75
81
|
}
|