@zhin.js/plugin-nettools 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/CHANGELOG.md +20 -0
- package/commands/dns/[name]/[[type]]/index.js +5 -5
- package/commands/dns/[name]/[[type]]/index.ts +5 -5
- package/commands/domain-price/[suffix]/[[order]]/index.js +5 -5
- package/commands/domain-price/[suffix]/[[order]]/index.ts +5 -5
- package/commands/ping/[host]/index.js +4 -4
- package/commands/ping/[host]/index.ts +4 -4
- package/commands/whois/[domain]/index.js +4 -4
- package/commands/whois/[domain]/index.ts +4 -4
- package/lib/address-policy.d.ts +2 -0
- package/lib/address-policy.js +55 -54
- package/lib/address-policy.js.map +1 -1
- package/lib/cooldown.js +2 -1
- package/lib/cooldown.js.map +1 -1
- package/lib/dns.d.ts +2 -1
- package/lib/dns.js +14 -12
- package/lib/dns.js.map +1 -1
- package/lib/domain-price.d.ts +2 -1
- package/lib/domain-price.js +16 -19
- package/lib/domain-price.js.map +1 -1
- package/lib/errors.d.ts +5 -2
- package/lib/errors.js +8 -4
- package/lib/errors.js.map +1 -1
- package/lib/http.js +12 -11
- package/lib/http.js.map +1 -1
- package/lib/messages.d.ts +329 -0
- package/lib/messages.js +335 -0
- package/lib/messages.js.map +1 -0
- package/lib/ping.d.ts +2 -1
- package/lib/ping.js +13 -11
- package/lib/ping.js.map +1 -1
- package/lib/presentation.d.ts +1 -0
- package/lib/presentation.js +36 -0
- package/lib/presentation.js.map +1 -0
- package/lib/service.d.ts +6 -5
- package/lib/service.js +16 -15
- package/lib/service.js.map +1 -1
- package/lib/target-guard.js +6 -4
- package/lib/target-guard.js.map +1 -1
- package/lib/whois.d.ts +2 -1
- package/lib/whois.js +18 -16
- package/lib/whois.js.map +1 -1
- package/package.json +7 -7
- package/skills/nettools/tools/dns_lookup/index.js +1 -1
- package/skills/nettools/tools/domain_price/index.js +1 -1
- package/skills/nettools/tools/net_ping/index.js +1 -1
- package/skills/nettools/tools/whois_lookup/index.js +1 -1
package/lib/messages.js
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
2
|
+
const catalog = {
|
|
3
|
+
"cloudMetadata": {
|
|
4
|
+
"zh-CN": "云服务元数据地址",
|
|
5
|
+
"en": "Cloud metadata address"
|
|
6
|
+
},
|
|
7
|
+
"unspecifiedV4": {
|
|
8
|
+
"zh-CN": "未指定 / “本网络”地址",
|
|
9
|
+
"en": "Unspecified / current-network address"
|
|
10
|
+
},
|
|
11
|
+
"privateV4": {
|
|
12
|
+
"zh-CN": "私有地址 (RFC 1918)",
|
|
13
|
+
"en": "Private address (RFC 1918)"
|
|
14
|
+
},
|
|
15
|
+
"cgnat": {
|
|
16
|
+
"zh-CN": "运营商级 NAT 地址 (CGNAT, RFC 6598)",
|
|
17
|
+
"en": "Carrier-grade NAT address (CGNAT, RFC 6598)"
|
|
18
|
+
},
|
|
19
|
+
"loopback": {
|
|
20
|
+
"zh-CN": "回环地址",
|
|
21
|
+
"en": "Loopback address"
|
|
22
|
+
},
|
|
23
|
+
"linkLocal": {
|
|
24
|
+
"zh-CN": "链路本地地址",
|
|
25
|
+
"en": "Link-local address"
|
|
26
|
+
},
|
|
27
|
+
"ietfReserved": {
|
|
28
|
+
"zh-CN": "IETF 协议保留地址",
|
|
29
|
+
"en": "IETF protocol reserved address"
|
|
30
|
+
},
|
|
31
|
+
"documentation": {
|
|
32
|
+
"zh-CN": "文档示例地址",
|
|
33
|
+
"en": "Documentation address"
|
|
34
|
+
},
|
|
35
|
+
"relay6to4": {
|
|
36
|
+
"zh-CN": "已废弃的 6to4 中继地址",
|
|
37
|
+
"en": "Deprecated 6to4 relay address"
|
|
38
|
+
},
|
|
39
|
+
"benchmark": {
|
|
40
|
+
"zh-CN": "基准测试保留地址",
|
|
41
|
+
"en": "Benchmarking address"
|
|
42
|
+
},
|
|
43
|
+
"multicast": {
|
|
44
|
+
"zh-CN": "组播地址",
|
|
45
|
+
"en": "Multicast address"
|
|
46
|
+
},
|
|
47
|
+
"reservedBroadcast": {
|
|
48
|
+
"zh-CN": "保留地址(含广播地址)",
|
|
49
|
+
"en": "Reserved address (including broadcast)"
|
|
50
|
+
},
|
|
51
|
+
"teredo": {
|
|
52
|
+
"zh-CN": "Teredo 隧道地址",
|
|
53
|
+
"en": "Teredo tunnel address"
|
|
54
|
+
},
|
|
55
|
+
"orchid": {
|
|
56
|
+
"zh-CN": "ORCHID 保留地址",
|
|
57
|
+
"en": "ORCHID reserved address"
|
|
58
|
+
},
|
|
59
|
+
"hostRequired": {
|
|
60
|
+
"zh-CN": "请提供主机名或 IP 地址",
|
|
61
|
+
"en": "Provide a hostname or IP address"
|
|
62
|
+
},
|
|
63
|
+
"hostTooLong": {
|
|
64
|
+
"zh-CN": "主机名过长",
|
|
65
|
+
"en": "Hostname is too long"
|
|
66
|
+
},
|
|
67
|
+
"bareHost": {
|
|
68
|
+
"zh-CN": "只接受裸主机名或 IP,不要带协议、端口、路径或特殊字符",
|
|
69
|
+
"en": "Use a bare hostname or IP, without a scheme, port, path or special characters"
|
|
70
|
+
},
|
|
71
|
+
"ipv6NoPort": {
|
|
72
|
+
"zh-CN": "不是有效的 IPv6 地址(如需端口请去掉端口)",
|
|
73
|
+
"en": "Invalid IPv6 address; omit any port"
|
|
74
|
+
},
|
|
75
|
+
"invalidHost": {
|
|
76
|
+
"zh-CN": "不是有效的主机名或 IP 地址",
|
|
77
|
+
"en": "Invalid hostname or IP address"
|
|
78
|
+
},
|
|
79
|
+
"hostLength": {
|
|
80
|
+
"zh-CN": "主机名长度不合法",
|
|
81
|
+
"en": "Invalid hostname length"
|
|
82
|
+
},
|
|
83
|
+
"fullDomain": {
|
|
84
|
+
"zh-CN": "请提供完整域名(例如 example.com)",
|
|
85
|
+
"en": "Provide a full domain name, such as example.com"
|
|
86
|
+
},
|
|
87
|
+
"invalidLabel": {
|
|
88
|
+
"zh-CN": "域名标签不合法:{label}",
|
|
89
|
+
"en": "Invalid domain label: {label}"
|
|
90
|
+
},
|
|
91
|
+
"empty": {
|
|
92
|
+
"zh-CN": "(空)",
|
|
93
|
+
"en": "(empty)"
|
|
94
|
+
},
|
|
95
|
+
"numericTld": {
|
|
96
|
+
"zh-CN": "顶级域不能是纯数字",
|
|
97
|
+
"en": "The top-level domain cannot be entirely numeric"
|
|
98
|
+
},
|
|
99
|
+
"notIp": {
|
|
100
|
+
"zh-CN": "不是 IP 地址:{address}",
|
|
101
|
+
"en": "Not an IP address: {address}"
|
|
102
|
+
},
|
|
103
|
+
"localhost": {
|
|
104
|
+
"zh-CN": "本机主机名",
|
|
105
|
+
"en": "Local hostname"
|
|
106
|
+
},
|
|
107
|
+
"reservedSuffix": {
|
|
108
|
+
"zh-CN": "内网或保留域名后缀 .{suffix}",
|
|
109
|
+
"en": "Private or reserved domain suffix .{suffix}"
|
|
110
|
+
},
|
|
111
|
+
"unspecifiedV6": {
|
|
112
|
+
"zh-CN": "未指定地址 (::)",
|
|
113
|
+
"en": "Unspecified address (::)"
|
|
114
|
+
},
|
|
115
|
+
"loopbackV6": {
|
|
116
|
+
"zh-CN": "回环地址 (::1)",
|
|
117
|
+
"en": "Loopback address (::1)"
|
|
118
|
+
},
|
|
119
|
+
"mappedV4": {
|
|
120
|
+
"zh-CN": "IPv4 映射地址",
|
|
121
|
+
"en": "IPv4-mapped address"
|
|
122
|
+
},
|
|
123
|
+
"nat64": {
|
|
124
|
+
"zh-CN": "NAT64 地址",
|
|
125
|
+
"en": "NAT64 address"
|
|
126
|
+
},
|
|
127
|
+
"localNat64": {
|
|
128
|
+
"zh-CN": "本地 NAT64 地址",
|
|
129
|
+
"en": "Local NAT64 address"
|
|
130
|
+
},
|
|
131
|
+
"sixToFour": {
|
|
132
|
+
"zh-CN": "6to4 地址",
|
|
133
|
+
"en": "6to4 address"
|
|
134
|
+
},
|
|
135
|
+
"ula": {
|
|
136
|
+
"zh-CN": "唯一本地地址 (ULA, fc00::/7)",
|
|
137
|
+
"en": "Unique-local address (ULA, fc00::/7)"
|
|
138
|
+
},
|
|
139
|
+
"linkLocalV6": {
|
|
140
|
+
"zh-CN": "链路本地地址 (fe80::/10)",
|
|
141
|
+
"en": "Link-local address (fe80::/10)"
|
|
142
|
+
},
|
|
143
|
+
"siteLocalV6": {
|
|
144
|
+
"zh-CN": "已废弃的站点本地地址 (fec0::/10)",
|
|
145
|
+
"en": "Deprecated site-local address (fec0::/10)"
|
|
146
|
+
},
|
|
147
|
+
"multicastV6": {
|
|
148
|
+
"zh-CN": "组播地址 (ff00::/8)",
|
|
149
|
+
"en": "Multicast address (ff00::/8)"
|
|
150
|
+
},
|
|
151
|
+
"notGlobalV6": {
|
|
152
|
+
"zh-CN": "非全球单播 IPv6 地址",
|
|
153
|
+
"en": "Non-global-unicast IPv6 address"
|
|
154
|
+
},
|
|
155
|
+
"embeddedV4": {
|
|
156
|
+
"zh-CN": "{wrapper}指向 {address}({reason})",
|
|
157
|
+
"en": "{wrapper} points to {address} ({reason})"
|
|
158
|
+
},
|
|
159
|
+
"invalidV4": {
|
|
160
|
+
"zh-CN": "不是有效的 IPv4 地址:{address}",
|
|
161
|
+
"en": "Invalid IPv4 address: {address}"
|
|
162
|
+
},
|
|
163
|
+
"invalidV6": {
|
|
164
|
+
"zh-CN": "不是有效的 IPv6 地址:{address}",
|
|
165
|
+
"en": "Invalid IPv6 address: {address}"
|
|
166
|
+
},
|
|
167
|
+
"invalidV6Group": {
|
|
168
|
+
"zh-CN": "IPv6 分组不合法:{group}",
|
|
169
|
+
"en": "Invalid IPv6 group: {group}"
|
|
170
|
+
},
|
|
171
|
+
"reverseNeedsIp": {
|
|
172
|
+
"zh-CN": "反向解析需要 IP 地址",
|
|
173
|
+
"en": "Reverse lookup requires an IP address"
|
|
174
|
+
},
|
|
175
|
+
"probeBlocked": {
|
|
176
|
+
"zh-CN": "拒绝探测 {host}:{reason}",
|
|
177
|
+
"en": "Refused to probe {host}: {reason}"
|
|
178
|
+
},
|
|
179
|
+
"queryBlocked": {
|
|
180
|
+
"zh-CN": "拒绝查询 {host}:{reason}",
|
|
181
|
+
"en": "Refused to query {host}: {reason}"
|
|
182
|
+
},
|
|
183
|
+
"whoisDomainOnly": {
|
|
184
|
+
"zh-CN": "whois 目前只支持域名查询",
|
|
185
|
+
"en": "WHOIS supports domain names only"
|
|
186
|
+
},
|
|
187
|
+
"reverseOnly": {
|
|
188
|
+
"zh-CN": "IP 地址只能做反向解析,请使用 PTR 记录类型",
|
|
189
|
+
"en": "IP addresses only support reverse lookup; select the PTR record type"
|
|
190
|
+
},
|
|
191
|
+
"noAddresses": {
|
|
192
|
+
"zh-CN": "无法解析 {host}(没有 A/AAAA 记录)",
|
|
193
|
+
"en": "Cannot resolve {host} (no A/AAAA records)"
|
|
194
|
+
},
|
|
195
|
+
"resolvedBlocked": {
|
|
196
|
+
"zh-CN": "拒绝探测 {host}:解析到 {address}({reason})",
|
|
197
|
+
"en": "Refused to probe {host}: resolves to {address} ({reason})"
|
|
198
|
+
},
|
|
199
|
+
"unknownAddress": {
|
|
200
|
+
"zh-CN": "无法识别的地址记录",
|
|
201
|
+
"en": "Unrecognized address record"
|
|
202
|
+
},
|
|
203
|
+
"cooldown": {
|
|
204
|
+
"zh-CN": "操作太频繁,请 {seconds} 秒后再试",
|
|
205
|
+
"en": "Too many requests. Try again in {seconds} seconds"
|
|
206
|
+
},
|
|
207
|
+
"dnsType": {
|
|
208
|
+
"zh-CN": "不支持的记录类型 {type},可选:{types}",
|
|
209
|
+
"en": "Unsupported record type {type}; choose {types}"
|
|
210
|
+
},
|
|
211
|
+
"queryFailed": {
|
|
212
|
+
"zh-CN": "{provider} 查询失败",
|
|
213
|
+
"en": "{provider} lookup failed"
|
|
214
|
+
},
|
|
215
|
+
"dnsUnavailable": {
|
|
216
|
+
"zh-CN": "所有 DNS 服务均不可用:{failures}",
|
|
217
|
+
"en": "All DNS services are unavailable: {failures}"
|
|
218
|
+
},
|
|
219
|
+
"dnsMalformed": {
|
|
220
|
+
"zh-CN": "{provider} 返回了无法识别的 DNS 响应",
|
|
221
|
+
"en": "{provider} returned an unrecognized DNS response"
|
|
222
|
+
},
|
|
223
|
+
"dnsFailed": {
|
|
224
|
+
"zh-CN": "{provider} 解析失败({rcode})",
|
|
225
|
+
"en": "{provider} lookup failed ({rcode})"
|
|
226
|
+
},
|
|
227
|
+
"requestFailed": {
|
|
228
|
+
"zh-CN": "{provider} 请求失败",
|
|
229
|
+
"en": "{provider} request failed"
|
|
230
|
+
},
|
|
231
|
+
"responseMalformed": {
|
|
232
|
+
"zh-CN": "{provider} 返回了无法解析的数据",
|
|
233
|
+
"en": "{provider} returned data that could not be parsed"
|
|
234
|
+
},
|
|
235
|
+
"timeout": {
|
|
236
|
+
"zh-CN": "{provider} 响应超时({seconds}s)",
|
|
237
|
+
"en": "{provider} timed out ({seconds}s)"
|
|
238
|
+
},
|
|
239
|
+
"network": {
|
|
240
|
+
"zh-CN": "无法连接 {provider}:{detail}",
|
|
241
|
+
"en": "Cannot connect to {provider}: {detail}"
|
|
242
|
+
},
|
|
243
|
+
"rateLimited": {
|
|
244
|
+
"zh-CN": "{provider} 请求过于频繁,请稍后再试",
|
|
245
|
+
"en": "{provider} rate limit reached; try again later"
|
|
246
|
+
},
|
|
247
|
+
"http": {
|
|
248
|
+
"zh-CN": "{provider} 返回错误 HTTP {status}",
|
|
249
|
+
"en": "{provider} returned HTTP {status}"
|
|
250
|
+
},
|
|
251
|
+
"tooLarge": {
|
|
252
|
+
"zh-CN": "响应体过大,已拒绝读取",
|
|
253
|
+
"en": "Response body is too large; reading was refused"
|
|
254
|
+
},
|
|
255
|
+
"providerAborted": {
|
|
256
|
+
"zh-CN": "{provider} 请求已取消",
|
|
257
|
+
"en": "{provider} request was cancelled"
|
|
258
|
+
},
|
|
259
|
+
"aborted": {
|
|
260
|
+
"zh-CN": "请求已取消",
|
|
261
|
+
"en": "Request was cancelled"
|
|
262
|
+
},
|
|
263
|
+
"pingRefused": {
|
|
264
|
+
"zh-CN": "check-host.net 拒绝了请求:{detail}",
|
|
265
|
+
"en": "check-host.net refused the request: {detail}"
|
|
266
|
+
},
|
|
267
|
+
"pingMalformed": {
|
|
268
|
+
"zh-CN": "check-host.net 返回了无法识别的数据",
|
|
269
|
+
"en": "check-host.net returned unrecognized data"
|
|
270
|
+
},
|
|
271
|
+
"priceKind": {
|
|
272
|
+
"zh-CN": "价格类型可选:注册(register) / 续费(renew) / 转入(transfer)",
|
|
273
|
+
"en": "Price type must be register, renew, or transfer"
|
|
274
|
+
},
|
|
275
|
+
"suffixRequired": {
|
|
276
|
+
"zh-CN": "请提供域名后缀,例如 com 或 .cn",
|
|
277
|
+
"en": "Provide a domain suffix, such as com or .cn"
|
|
278
|
+
},
|
|
279
|
+
"suffixNotIp": {
|
|
280
|
+
"zh-CN": "请提供域名或后缀,而不是 IP 地址",
|
|
281
|
+
"en": "Provide a domain name or suffix, rather than an IP address"
|
|
282
|
+
},
|
|
283
|
+
"priceMalformed": {
|
|
284
|
+
"zh-CN": "nazhumi.com 返回了无法识别的数据",
|
|
285
|
+
"en": "nazhumi.com returned unrecognized data"
|
|
286
|
+
},
|
|
287
|
+
"priceError": {
|
|
288
|
+
"zh-CN": "nazhumi.com 返回错误 {code}{detail}",
|
|
289
|
+
"en": "nazhumi.com returned error {code}{detail}"
|
|
290
|
+
},
|
|
291
|
+
"rdapFailed": {
|
|
292
|
+
"zh-CN": "RDAP / WHOIS 查询失败",
|
|
293
|
+
"en": "RDAP / WHOIS lookup failed"
|
|
294
|
+
},
|
|
295
|
+
"ianaMalformed": {
|
|
296
|
+
"zh-CN": "IANA RDAP 引导数据格式异常",
|
|
297
|
+
"en": "Invalid IANA RDAP bootstrap data"
|
|
298
|
+
},
|
|
299
|
+
"rdapMalformed": {
|
|
300
|
+
"zh-CN": "RDAP 返回了无法识别的数据",
|
|
301
|
+
"en": "RDAP returned unrecognized data"
|
|
302
|
+
},
|
|
303
|
+
"rdapNotDomain": {
|
|
304
|
+
"zh-CN": "RDAP 返回的不是域名对象",
|
|
305
|
+
"en": "RDAP did not return a domain object"
|
|
306
|
+
},
|
|
307
|
+
"whoisMalformed": {
|
|
308
|
+
"zh-CN": "WHOIS 服务返回了无法识别的数据",
|
|
309
|
+
"en": "WHOIS service returned unrecognized data"
|
|
310
|
+
},
|
|
311
|
+
"whoisError": {
|
|
312
|
+
"zh-CN": "WHOIS 服务返回错误 {code}",
|
|
313
|
+
"en": "WHOIS service returned error {code}"
|
|
314
|
+
},
|
|
315
|
+
"unexpected": {
|
|
316
|
+
"zh-CN": "出错了:{detail}",
|
|
317
|
+
"en": "An error occurred: {detail}"
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const translate = createMessages(catalog);
|
|
321
|
+
/** Stable source keys preserve nested provider/target reasons until the caller chooses a language. */
|
|
322
|
+
export function message(key, values = {}) {
|
|
323
|
+
return { key, values };
|
|
324
|
+
}
|
|
325
|
+
export function formatMessage(detail, locale = 'zh-CN') {
|
|
326
|
+
const value = (item) => {
|
|
327
|
+
if (typeof item === 'string' || typeof item === 'number')
|
|
328
|
+
return item;
|
|
329
|
+
if (Array.isArray(item))
|
|
330
|
+
return item.map((part) => value(part)).join(locale === 'en' ? '; ' : ';');
|
|
331
|
+
return formatMessage(item, locale);
|
|
332
|
+
};
|
|
333
|
+
return translate(locale, detail.key, Object.fromEntries(Object.entries(detail.values).map(([key, item]) => [key, value(item)])));
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { createMessages, type Locale } from 'zhin.js/i18n';\n\nconst catalog = {\n \"cloudMetadata\": {\n \"zh-CN\": \"云服务元数据地址\",\n \"en\": \"Cloud metadata address\"\n },\n \"unspecifiedV4\": {\n \"zh-CN\": \"未指定 / “本网络”地址\",\n \"en\": \"Unspecified / current-network address\"\n },\n \"privateV4\": {\n \"zh-CN\": \"私有地址 (RFC 1918)\",\n \"en\": \"Private address (RFC 1918)\"\n },\n \"cgnat\": {\n \"zh-CN\": \"运营商级 NAT 地址 (CGNAT, RFC 6598)\",\n \"en\": \"Carrier-grade NAT address (CGNAT, RFC 6598)\"\n },\n \"loopback\": {\n \"zh-CN\": \"回环地址\",\n \"en\": \"Loopback address\"\n },\n \"linkLocal\": {\n \"zh-CN\": \"链路本地地址\",\n \"en\": \"Link-local address\"\n },\n \"ietfReserved\": {\n \"zh-CN\": \"IETF 协议保留地址\",\n \"en\": \"IETF protocol reserved address\"\n },\n \"documentation\": {\n \"zh-CN\": \"文档示例地址\",\n \"en\": \"Documentation address\"\n },\n \"relay6to4\": {\n \"zh-CN\": \"已废弃的 6to4 中继地址\",\n \"en\": \"Deprecated 6to4 relay address\"\n },\n \"benchmark\": {\n \"zh-CN\": \"基准测试保留地址\",\n \"en\": \"Benchmarking address\"\n },\n \"multicast\": {\n \"zh-CN\": \"组播地址\",\n \"en\": \"Multicast address\"\n },\n \"reservedBroadcast\": {\n \"zh-CN\": \"保留地址(含广播地址)\",\n \"en\": \"Reserved address (including broadcast)\"\n },\n \"teredo\": {\n \"zh-CN\": \"Teredo 隧道地址\",\n \"en\": \"Teredo tunnel address\"\n },\n \"orchid\": {\n \"zh-CN\": \"ORCHID 保留地址\",\n \"en\": \"ORCHID reserved address\"\n },\n \"hostRequired\": {\n \"zh-CN\": \"请提供主机名或 IP 地址\",\n \"en\": \"Provide a hostname or IP address\"\n },\n \"hostTooLong\": {\n \"zh-CN\": \"主机名过长\",\n \"en\": \"Hostname is too long\"\n },\n \"bareHost\": {\n \"zh-CN\": \"只接受裸主机名或 IP,不要带协议、端口、路径或特殊字符\",\n \"en\": \"Use a bare hostname or IP, without a scheme, port, path or special characters\"\n },\n \"ipv6NoPort\": {\n \"zh-CN\": \"不是有效的 IPv6 地址(如需端口请去掉端口)\",\n \"en\": \"Invalid IPv6 address; omit any port\"\n },\n \"invalidHost\": {\n \"zh-CN\": \"不是有效的主机名或 IP 地址\",\n \"en\": \"Invalid hostname or IP address\"\n },\n \"hostLength\": {\n \"zh-CN\": \"主机名长度不合法\",\n \"en\": \"Invalid hostname length\"\n },\n \"fullDomain\": {\n \"zh-CN\": \"请提供完整域名(例如 example.com)\",\n \"en\": \"Provide a full domain name, such as example.com\"\n },\n \"invalidLabel\": {\n \"zh-CN\": \"域名标签不合法:{label}\",\n \"en\": \"Invalid domain label: {label}\"\n },\n \"empty\": {\n \"zh-CN\": \"(空)\",\n \"en\": \"(empty)\"\n },\n \"numericTld\": {\n \"zh-CN\": \"顶级域不能是纯数字\",\n \"en\": \"The top-level domain cannot be entirely numeric\"\n },\n \"notIp\": {\n \"zh-CN\": \"不是 IP 地址:{address}\",\n \"en\": \"Not an IP address: {address}\"\n },\n \"localhost\": {\n \"zh-CN\": \"本机主机名\",\n \"en\": \"Local hostname\"\n },\n \"reservedSuffix\": {\n \"zh-CN\": \"内网或保留域名后缀 .{suffix}\",\n \"en\": \"Private or reserved domain suffix .{suffix}\"\n },\n \"unspecifiedV6\": {\n \"zh-CN\": \"未指定地址 (::)\",\n \"en\": \"Unspecified address (::)\"\n },\n \"loopbackV6\": {\n \"zh-CN\": \"回环地址 (::1)\",\n \"en\": \"Loopback address (::1)\"\n },\n \"mappedV4\": {\n \"zh-CN\": \"IPv4 映射地址\",\n \"en\": \"IPv4-mapped address\"\n },\n \"nat64\": {\n \"zh-CN\": \"NAT64 地址\",\n \"en\": \"NAT64 address\"\n },\n \"localNat64\": {\n \"zh-CN\": \"本地 NAT64 地址\",\n \"en\": \"Local NAT64 address\"\n },\n \"sixToFour\": {\n \"zh-CN\": \"6to4 地址\",\n \"en\": \"6to4 address\"\n },\n \"ula\": {\n \"zh-CN\": \"唯一本地地址 (ULA, fc00::/7)\",\n \"en\": \"Unique-local address (ULA, fc00::/7)\"\n },\n \"linkLocalV6\": {\n \"zh-CN\": \"链路本地地址 (fe80::/10)\",\n \"en\": \"Link-local address (fe80::/10)\"\n },\n \"siteLocalV6\": {\n \"zh-CN\": \"已废弃的站点本地地址 (fec0::/10)\",\n \"en\": \"Deprecated site-local address (fec0::/10)\"\n },\n \"multicastV6\": {\n \"zh-CN\": \"组播地址 (ff00::/8)\",\n \"en\": \"Multicast address (ff00::/8)\"\n },\n \"notGlobalV6\": {\n \"zh-CN\": \"非全球单播 IPv6 地址\",\n \"en\": \"Non-global-unicast IPv6 address\"\n },\n \"embeddedV4\": {\n \"zh-CN\": \"{wrapper}指向 {address}({reason})\",\n \"en\": \"{wrapper} points to {address} ({reason})\"\n },\n \"invalidV4\": {\n \"zh-CN\": \"不是有效的 IPv4 地址:{address}\",\n \"en\": \"Invalid IPv4 address: {address}\"\n },\n \"invalidV6\": {\n \"zh-CN\": \"不是有效的 IPv6 地址:{address}\",\n \"en\": \"Invalid IPv6 address: {address}\"\n },\n \"invalidV6Group\": {\n \"zh-CN\": \"IPv6 分组不合法:{group}\",\n \"en\": \"Invalid IPv6 group: {group}\"\n },\n \"reverseNeedsIp\": {\n \"zh-CN\": \"反向解析需要 IP 地址\",\n \"en\": \"Reverse lookup requires an IP address\"\n },\n \"probeBlocked\": {\n \"zh-CN\": \"拒绝探测 {host}:{reason}\",\n \"en\": \"Refused to probe {host}: {reason}\"\n },\n \"queryBlocked\": {\n \"zh-CN\": \"拒绝查询 {host}:{reason}\",\n \"en\": \"Refused to query {host}: {reason}\"\n },\n \"whoisDomainOnly\": {\n \"zh-CN\": \"whois 目前只支持域名查询\",\n \"en\": \"WHOIS supports domain names only\"\n },\n \"reverseOnly\": {\n \"zh-CN\": \"IP 地址只能做反向解析,请使用 PTR 记录类型\",\n \"en\": \"IP addresses only support reverse lookup; select the PTR record type\"\n },\n \"noAddresses\": {\n \"zh-CN\": \"无法解析 {host}(没有 A/AAAA 记录)\",\n \"en\": \"Cannot resolve {host} (no A/AAAA records)\"\n },\n \"resolvedBlocked\": {\n \"zh-CN\": \"拒绝探测 {host}:解析到 {address}({reason})\",\n \"en\": \"Refused to probe {host}: resolves to {address} ({reason})\"\n },\n \"unknownAddress\": {\n \"zh-CN\": \"无法识别的地址记录\",\n \"en\": \"Unrecognized address record\"\n },\n \"cooldown\": {\n \"zh-CN\": \"操作太频繁,请 {seconds} 秒后再试\",\n \"en\": \"Too many requests. Try again in {seconds} seconds\"\n },\n \"dnsType\": {\n \"zh-CN\": \"不支持的记录类型 {type},可选:{types}\",\n \"en\": \"Unsupported record type {type}; choose {types}\"\n },\n \"queryFailed\": {\n \"zh-CN\": \"{provider} 查询失败\",\n \"en\": \"{provider} lookup failed\"\n },\n \"dnsUnavailable\": {\n \"zh-CN\": \"所有 DNS 服务均不可用:{failures}\",\n \"en\": \"All DNS services are unavailable: {failures}\"\n },\n \"dnsMalformed\": {\n \"zh-CN\": \"{provider} 返回了无法识别的 DNS 响应\",\n \"en\": \"{provider} returned an unrecognized DNS response\"\n },\n \"dnsFailed\": {\n \"zh-CN\": \"{provider} 解析失败({rcode})\",\n \"en\": \"{provider} lookup failed ({rcode})\"\n },\n \"requestFailed\": {\n \"zh-CN\": \"{provider} 请求失败\",\n \"en\": \"{provider} request failed\"\n },\n \"responseMalformed\": {\n \"zh-CN\": \"{provider} 返回了无法解析的数据\",\n \"en\": \"{provider} returned data that could not be parsed\"\n },\n \"timeout\": {\n \"zh-CN\": \"{provider} 响应超时({seconds}s)\",\n \"en\": \"{provider} timed out ({seconds}s)\"\n },\n \"network\": {\n \"zh-CN\": \"无法连接 {provider}:{detail}\",\n \"en\": \"Cannot connect to {provider}: {detail}\"\n },\n \"rateLimited\": {\n \"zh-CN\": \"{provider} 请求过于频繁,请稍后再试\",\n \"en\": \"{provider} rate limit reached; try again later\"\n },\n \"http\": {\n \"zh-CN\": \"{provider} 返回错误 HTTP {status}\",\n \"en\": \"{provider} returned HTTP {status}\"\n },\n \"tooLarge\": {\n \"zh-CN\": \"响应体过大,已拒绝读取\",\n \"en\": \"Response body is too large; reading was refused\"\n },\n \"providerAborted\": {\n \"zh-CN\": \"{provider} 请求已取消\",\n \"en\": \"{provider} request was cancelled\"\n },\n \"aborted\": {\n \"zh-CN\": \"请求已取消\",\n \"en\": \"Request was cancelled\"\n },\n \"pingRefused\": {\n \"zh-CN\": \"check-host.net 拒绝了请求:{detail}\",\n \"en\": \"check-host.net refused the request: {detail}\"\n },\n \"pingMalformed\": {\n \"zh-CN\": \"check-host.net 返回了无法识别的数据\",\n \"en\": \"check-host.net returned unrecognized data\"\n },\n \"priceKind\": {\n \"zh-CN\": \"价格类型可选:注册(register) / 续费(renew) / 转入(transfer)\",\n \"en\": \"Price type must be register, renew, or transfer\"\n },\n \"suffixRequired\": {\n \"zh-CN\": \"请提供域名后缀,例如 com 或 .cn\",\n \"en\": \"Provide a domain suffix, such as com or .cn\"\n },\n \"suffixNotIp\": {\n \"zh-CN\": \"请提供域名或后缀,而不是 IP 地址\",\n \"en\": \"Provide a domain name or suffix, rather than an IP address\"\n },\n \"priceMalformed\": {\n \"zh-CN\": \"nazhumi.com 返回了无法识别的数据\",\n \"en\": \"nazhumi.com returned unrecognized data\"\n },\n \"priceError\": {\n \"zh-CN\": \"nazhumi.com 返回错误 {code}{detail}\",\n \"en\": \"nazhumi.com returned error {code}{detail}\"\n },\n \"rdapFailed\": {\n \"zh-CN\": \"RDAP / WHOIS 查询失败\",\n \"en\": \"RDAP / WHOIS lookup failed\"\n },\n \"ianaMalformed\": {\n \"zh-CN\": \"IANA RDAP 引导数据格式异常\",\n \"en\": \"Invalid IANA RDAP bootstrap data\"\n },\n \"rdapMalformed\": {\n \"zh-CN\": \"RDAP 返回了无法识别的数据\",\n \"en\": \"RDAP returned unrecognized data\"\n },\n \"rdapNotDomain\": {\n \"zh-CN\": \"RDAP 返回的不是域名对象\",\n \"en\": \"RDAP did not return a domain object\"\n },\n \"whoisMalformed\": {\n \"zh-CN\": \"WHOIS 服务返回了无法识别的数据\",\n \"en\": \"WHOIS service returned unrecognized data\"\n },\n \"whoisError\": {\n \"zh-CN\": \"WHOIS 服务返回错误 {code}\",\n \"en\": \"WHOIS service returned error {code}\"\n },\n \"unexpected\": {\n \"zh-CN\": \"出错了:{detail}\",\n \"en\": \"An error occurred: {detail}\"\n }\n} as const;\nconst translate = createMessages(catalog);\n\nexport type NettoolsMessageKey = keyof typeof catalog;\nexport type NettoolsMessageValue = string | number | NettoolsMessage | readonly (string | NettoolsMessage)[];\nexport interface NettoolsMessage {\n readonly key: NettoolsMessageKey;\n readonly values: Readonly<Record<string, NettoolsMessageValue>>;\n}\n\n/** Stable source keys preserve nested provider/target reasons until the caller chooses a language. */\nexport function message(key: NettoolsMessageKey, values: Readonly<Record<string, NettoolsMessageValue>> = {}): NettoolsMessage {\n return { key, values };\n}\n\nexport function formatMessage(detail: NettoolsMessage, locale: Locale = 'zh-CN'): string {\n const value = (item: NettoolsMessageValue): string | number => {\n if (typeof item === 'string' || typeof item === 'number') return item;\n if (Array.isArray(item)) return item.map((part) => value(part)).join(locale === 'en' ? '; ' : ';');\n return formatMessage(item as NettoolsMessage, locale);\n };\n return translate(locale, detail.key, Object.fromEntries(Object.entries(detail.values).map(([key, item]) => [key, value(item)])));\n}\n"]}
|
package/lib/ping.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Locale } from 'zhin.js/i18n';
|
|
1
2
|
import type { HttpClient } from './http.js';
|
|
2
3
|
export declare const CHECK_HOST_BASE_URL = "https://check-host.net/";
|
|
3
4
|
export interface PingOptions {
|
|
@@ -41,5 +42,5 @@ interface StartedCheck {
|
|
|
41
42
|
export declare function runMultiRegionPing(http: HttpClient, host: string, options: PingOptions): Promise<PingReport>;
|
|
42
43
|
export declare function parseStartResponse(body: unknown): StartedCheck;
|
|
43
44
|
export declare function parsePingResults(body: unknown): Map<string, PingNodeResult>;
|
|
44
|
-
export declare function formatPingReport(report: PingReport): string;
|
|
45
|
+
export declare function formatPingReport(report: PingReport, locale?: Locale): string;
|
|
45
46
|
export {};
|
package/lib/ping.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { messages } from './presentation.js';
|
|
2
|
+
import { message } from './messages.js';
|
|
1
3
|
/**
|
|
2
4
|
* Multi-region ping through check-host.net's public API.
|
|
3
5
|
*
|
|
@@ -66,7 +68,7 @@ export function parseStartResponse(body) {
|
|
|
66
68
|
throw malformed();
|
|
67
69
|
}
|
|
68
70
|
if (typeof body.error === 'string' && body.error.length > 0) {
|
|
69
|
-
throw new NettoolsError('http',
|
|
71
|
+
throw new NettoolsError('http', message('pingRefused', { detail: body.error }));
|
|
70
72
|
}
|
|
71
73
|
const requestId = body.request_id;
|
|
72
74
|
if (typeof requestId !== 'string' || !/^[A-Za-z0-9]{1,64}$/u.test(requestId)) {
|
|
@@ -158,36 +160,36 @@ function parseNodeResult(raw) {
|
|
|
158
160
|
address,
|
|
159
161
|
};
|
|
160
162
|
}
|
|
161
|
-
export function formatPingReport(report) {
|
|
162
|
-
const lines = [
|
|
163
|
+
export function formatPingReport(report, locale = 'zh-CN') {
|
|
164
|
+
const lines = [messages(locale, 'pingHeader', { host: report.host })];
|
|
163
165
|
for (const { node, result } of report.nodes) {
|
|
164
166
|
const place = [node.countryCode, node.city || node.country].filter(Boolean).join(' ') || node.id;
|
|
165
|
-
lines.push(`${place}:${describeNodeResult(result)}`);
|
|
167
|
+
lines.push(`${place}:${describeNodeResult(result, locale)}`);
|
|
166
168
|
}
|
|
167
169
|
if (report.permanentLink) {
|
|
168
|
-
lines.push(
|
|
170
|
+
lines.push(messages(locale, 'detail', { link: report.permanentLink }));
|
|
169
171
|
}
|
|
170
172
|
return lines.join('\n');
|
|
171
173
|
}
|
|
172
|
-
function describeNodeResult(result) {
|
|
174
|
+
function describeNodeResult(result, locale) {
|
|
173
175
|
if (result.state === 'pending') {
|
|
174
|
-
return '
|
|
176
|
+
return messages(locale, 'pending');
|
|
175
177
|
}
|
|
176
178
|
if (result.state === 'unresolved') {
|
|
177
|
-
return '
|
|
179
|
+
return messages(locale, 'unresolved');
|
|
178
180
|
}
|
|
179
181
|
const loss = Math.round(((result.sent - result.received) / result.sent) * 100);
|
|
180
182
|
const via = result.address ? ` → ${result.address}` : '';
|
|
181
183
|
if (result.averageMs === undefined) {
|
|
182
|
-
return
|
|
184
|
+
return messages(locale, 'allTimeout', { loss, via });
|
|
183
185
|
}
|
|
184
186
|
const average = result.averageMs.toFixed(1);
|
|
185
187
|
const min = (result.minMs ?? result.averageMs).toFixed(1);
|
|
186
188
|
const max = (result.maxMs ?? result.averageMs).toFixed(1);
|
|
187
|
-
return
|
|
189
|
+
return messages(locale, 'pingStats', { average, min, max, loss, via });
|
|
188
190
|
}
|
|
189
191
|
function malformed() {
|
|
190
|
-
return new NettoolsError('malformed', '
|
|
192
|
+
return new NettoolsError('malformed', message('pingMalformed'));
|
|
191
193
|
}
|
|
192
194
|
function isRecord(value) {
|
|
193
195
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
package/lib/ping.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ping.js","sourceRoot":"","sources":["../src/ping.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Multi-region ping through check-host.net's public API.\n *\n * Flow: `GET /check-ping?host=…&max_nodes=N` returns a request id plus the\n * chosen probe nodes; `GET /check-result/<id>` returns one entry per node,\n * `null` while that node is still working. We poll a bounded number of times\n * and report whatever finished; unfinished nodes are shown as \"no result\".\n *\n * Result shape per node (tolerantly parsed, anything else is ignored):\n * [[ [\"OK\", 0.044, \"93.184.216.34\"], [\"TIMEOUT\", 3.0], … ]] finished\n * [[ null ]] could not resolve\n * null still running\n */\nimport { NettoolsError } from './errors.js';\nimport type { HttpClient } from './http.js';\n\nexport const CHECK_HOST_BASE_URL = 'https://check-host.net/';\nconst PROVIDER = 'check-host.net';\n\nexport interface PingOptions {\n readonly maxNodes: number;\n readonly pollIntervalMs: number;\n readonly maxPolls: number;\n readonly signal?: AbortSignal;\n}\n\nexport interface PingNode {\n readonly id: string;\n readonly countryCode: string;\n readonly country: string;\n readonly city: string;\n}\n\nexport type PingNodeResult =\n | { readonly state: 'pending' }\n | { readonly state: 'unresolved' }\n | {\n readonly state: 'done';\n readonly sent: number;\n readonly received: number;\n readonly averageMs: number | undefined;\n readonly minMs: number | undefined;\n readonly maxMs: number | undefined;\n readonly address: string | undefined;\n };\n\nexport interface PingReport {\n readonly host: string;\n readonly permanentLink: string | undefined;\n readonly nodes: readonly { readonly node: PingNode; readonly result: PingNodeResult }[];\n}\n\ninterface StartedCheck {\n readonly requestId: string;\n readonly permanentLink: string | undefined;\n readonly nodes: readonly PingNode[];\n}\n\nexport async function runMultiRegionPing(http: HttpClient, host: string, options: PingOptions): Promise<PingReport> {\n const started = await startPingCheck(http, host, options);\n let results = new Map<string, PingNodeResult>();\n let anyPollSucceeded = false;\n let lastPollError: unknown;\n for (let poll = 0; poll < options.maxPolls; poll += 1) {\n await http.dependencies.sleep(options.pollIntervalMs, options.signal);\n try {\n results = await fetchPingResults(http, started.requestId, options.signal);\n anyPollSucceeded = true;\n } catch (error) {\n // One failed poll (after its own retries) should not discard a check\n // that is still running remotely; keep polling until the budget is used.\n if (error instanceof NettoolsError && error.kind === 'aborted') {\n throw error;\n }\n lastPollError = error;\n continue;\n }\n const allFinished = started.nodes.every((node) => {\n const result = results.get(node.id);\n return result !== undefined && result.state !== 'pending';\n });\n if (allFinished) {\n break;\n }\n }\n if (!anyPollSucceeded && lastPollError !== undefined) {\n throw lastPollError;\n }\n const nodes = started.nodes.map((node) => ({\n node,\n result: results.get(node.id) ?? ({ state: 'pending' } as const),\n }));\n return Object.freeze({ host, permanentLink: started.permanentLink, nodes: Object.freeze(nodes) });\n}\n\nasync function startPingCheck(http: HttpClient, host: string, options: PingOptions): Promise<StartedCheck> {\n const url = new URL('check-ping', CHECK_HOST_BASE_URL);\n url.searchParams.set('host', host);\n url.searchParams.set('max_nodes', String(options.maxNodes));\n const response = await http.fetchJson(url, {\n provider: PROVIDER,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n return parseStartResponse(response.body);\n}\n\nexport function parseStartResponse(body: unknown): StartedCheck {\n if (!isRecord(body)) {\n throw malformed();\n }\n if (typeof body.error === 'string' && body.error.length > 0) {\n throw new NettoolsError('http', `check-host.net 拒绝了请求:${body.error}`);\n }\n const requestId = body.request_id;\n if (typeof requestId !== 'string' || !/^[A-Za-z0-9]{1,64}$/u.test(requestId)) {\n throw malformed();\n }\n const nodes: PingNode[] = [];\n if (isRecord(body.nodes)) {\n for (const [id, info] of Object.entries(body.nodes)) {\n nodes.push(parseNodeInfo(id, info));\n }\n }\n if (nodes.length === 0) {\n throw malformed();\n }\n const permanentLink = typeof body.permanent_link === 'string' && body.permanent_link.startsWith('https://')\n ? body.permanent_link\n : undefined;\n return Object.freeze({ requestId, permanentLink, nodes: Object.freeze(nodes) });\n}\n\nfunction parseNodeInfo(id: string, info: unknown): PingNode {\n const fields = Array.isArray(info) ? info : [];\n const text = (index: number): string => {\n const value = fields[index];\n return typeof value === 'string' ? value : '';\n };\n return Object.freeze({\n id,\n countryCode: text(0).toUpperCase(),\n country: text(1),\n city: text(2),\n });\n}\n\nasync function fetchPingResults(http: HttpClient, requestId: string, signal?: AbortSignal): Promise<Map<string, PingNodeResult>> {\n const url = new URL(`check-result/${encodeURIComponent(requestId)}`, CHECK_HOST_BASE_URL);\n const response = await http.fetchJson(url, {\n provider: PROVIDER,\n ...(signal ? { signal } : {}),\n });\n return parsePingResults(response.body);\n}\n\nexport function parsePingResults(body: unknown): Map<string, PingNodeResult> {\n if (!isRecord(body)) {\n throw malformed();\n }\n const results = new Map<string, PingNodeResult>();\n for (const [nodeId, raw] of Object.entries(body)) {\n results.set(nodeId, parseNodeResult(raw));\n }\n return results;\n}\n\nfunction parseNodeResult(raw: unknown): PingNodeResult {\n if (raw === null || raw === undefined) {\n return { state: 'pending' };\n }\n const outer = Array.isArray(raw) ? raw : [];\n const probes = Array.isArray(outer[0]) ? outer[0] : [];\n const firstProbe = probes[0];\n if (probes.length === 0 || firstProbe === null) {\n return { state: 'unresolved' };\n }\n const latencies: number[] = [];\n let address: string | undefined;\n let sent = 0;\n for (const probe of probes) {\n if (!Array.isArray(probe)) {\n continue;\n }\n sent += 1;\n const [status, seconds, ip] = probe as unknown[];\n if (address === undefined && typeof ip === 'string') {\n address = ip;\n }\n if (status === 'OK' && typeof seconds === 'number' && Number.isFinite(seconds)) {\n latencies.push(seconds * 1000);\n }\n }\n if (sent === 0) {\n return { state: 'unresolved' };\n }\n const received = latencies.length;\n const total = latencies.reduce((sum, value) => sum + value, 0);\n return {\n state: 'done',\n sent,\n received,\n averageMs: received > 0 ? total / received : undefined,\n minMs: received > 0 ? Math.min(...latencies) : undefined,\n maxMs: received > 0 ? Math.max(...latencies) : undefined,\n address,\n };\n}\n\nexport function formatPingReport(report: PingReport): string {\n const lines = [`📡 ${report.host} 多地 Ping(check-host.net)`];\n for (const { node, result } of report.nodes) {\n const place = [node.countryCode, node.city || node.country].filter(Boolean).join(' ') || node.id;\n lines.push(`${place}:${describeNodeResult(result)}`);\n }\n if (report.permanentLink) {\n lines.push(`详情:${report.permanentLink}`);\n }\n return lines.join('\\n');\n}\n\nfunction describeNodeResult(result: PingNodeResult): string {\n if (result.state === 'pending') {\n return '未返回结果(超时)';\n }\n if (result.state === 'unresolved') {\n return '无法解析或不可达';\n }\n const loss = Math.round(((result.sent - result.received) / result.sent) * 100);\n const via = result.address ? ` → ${result.address}` : '';\n if (result.averageMs === undefined) {\n return `全部超时(丢包 ${loss}%)${via}`;\n }\n const average = result.averageMs.toFixed(1);\n const min = (result.minMs ?? result.averageMs).toFixed(1);\n const max = (result.maxMs ?? result.averageMs).toFixed(1);\n return `平均 ${average}ms(${min}/${max}),丢包 ${loss}%${via}`;\n}\n\nfunction malformed(): NettoolsError {\n return new NettoolsError('malformed', 'check-host.net 返回了无法识别的数据');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ping.js","sourceRoot":"","sources":["../src/ping.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Locale } from 'zhin.js/i18n';\nimport { messages } from './presentation.js';\nimport { message } from './messages.js';\n/**\n * Multi-region ping through check-host.net's public API.\n *\n * Flow: `GET /check-ping?host=…&max_nodes=N` returns a request id plus the\n * chosen probe nodes; `GET /check-result/<id>` returns one entry per node,\n * `null` while that node is still working. We poll a bounded number of times\n * and report whatever finished; unfinished nodes are shown as \"no result\".\n *\n * Result shape per node (tolerantly parsed, anything else is ignored):\n * [[ [\"OK\", 0.044, \"93.184.216.34\"], [\"TIMEOUT\", 3.0], … ]] finished\n * [[ null ]] could not resolve\n * null still running\n */\nimport { NettoolsError } from './errors.js';\nimport type { HttpClient } from './http.js';\n\nexport const CHECK_HOST_BASE_URL = 'https://check-host.net/';\nconst PROVIDER = 'check-host.net';\n\nexport interface PingOptions {\n readonly maxNodes: number;\n readonly pollIntervalMs: number;\n readonly maxPolls: number;\n readonly signal?: AbortSignal;\n}\n\nexport interface PingNode {\n readonly id: string;\n readonly countryCode: string;\n readonly country: string;\n readonly city: string;\n}\n\nexport type PingNodeResult =\n | { readonly state: 'pending' }\n | { readonly state: 'unresolved' }\n | {\n readonly state: 'done';\n readonly sent: number;\n readonly received: number;\n readonly averageMs: number | undefined;\n readonly minMs: number | undefined;\n readonly maxMs: number | undefined;\n readonly address: string | undefined;\n };\n\nexport interface PingReport {\n readonly host: string;\n readonly permanentLink: string | undefined;\n readonly nodes: readonly { readonly node: PingNode; readonly result: PingNodeResult }[];\n}\n\ninterface StartedCheck {\n readonly requestId: string;\n readonly permanentLink: string | undefined;\n readonly nodes: readonly PingNode[];\n}\n\nexport async function runMultiRegionPing(http: HttpClient, host: string, options: PingOptions): Promise<PingReport> {\n const started = await startPingCheck(http, host, options);\n let results = new Map<string, PingNodeResult>();\n let anyPollSucceeded = false;\n let lastPollError: unknown;\n for (let poll = 0; poll < options.maxPolls; poll += 1) {\n await http.dependencies.sleep(options.pollIntervalMs, options.signal);\n try {\n results = await fetchPingResults(http, started.requestId, options.signal);\n anyPollSucceeded = true;\n } catch (error) {\n // One failed poll (after its own retries) should not discard a check\n // that is still running remotely; keep polling until the budget is used.\n if (error instanceof NettoolsError && error.kind === 'aborted') {\n throw error;\n }\n lastPollError = error;\n continue;\n }\n const allFinished = started.nodes.every((node) => {\n const result = results.get(node.id);\n return result !== undefined && result.state !== 'pending';\n });\n if (allFinished) {\n break;\n }\n }\n if (!anyPollSucceeded && lastPollError !== undefined) {\n throw lastPollError;\n }\n const nodes = started.nodes.map((node) => ({\n node,\n result: results.get(node.id) ?? ({ state: 'pending' } as const),\n }));\n return Object.freeze({ host, permanentLink: started.permanentLink, nodes: Object.freeze(nodes) });\n}\n\nasync function startPingCheck(http: HttpClient, host: string, options: PingOptions): Promise<StartedCheck> {\n const url = new URL('check-ping', CHECK_HOST_BASE_URL);\n url.searchParams.set('host', host);\n url.searchParams.set('max_nodes', String(options.maxNodes));\n const response = await http.fetchJson(url, {\n provider: PROVIDER,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n return parseStartResponse(response.body);\n}\n\nexport function parseStartResponse(body: unknown): StartedCheck {\n if (!isRecord(body)) {\n throw malformed();\n }\n if (typeof body.error === 'string' && body.error.length > 0) {\n throw new NettoolsError('http', message('pingRefused', { detail: body.error }));\n }\n const requestId = body.request_id;\n if (typeof requestId !== 'string' || !/^[A-Za-z0-9]{1,64}$/u.test(requestId)) {\n throw malformed();\n }\n const nodes: PingNode[] = [];\n if (isRecord(body.nodes)) {\n for (const [id, info] of Object.entries(body.nodes)) {\n nodes.push(parseNodeInfo(id, info));\n }\n }\n if (nodes.length === 0) {\n throw malformed();\n }\n const permanentLink = typeof body.permanent_link === 'string' && body.permanent_link.startsWith('https://')\n ? body.permanent_link\n : undefined;\n return Object.freeze({ requestId, permanentLink, nodes: Object.freeze(nodes) });\n}\n\nfunction parseNodeInfo(id: string, info: unknown): PingNode {\n const fields = Array.isArray(info) ? info : [];\n const text = (index: number): string => {\n const value = fields[index];\n return typeof value === 'string' ? value : '';\n };\n return Object.freeze({\n id,\n countryCode: text(0).toUpperCase(),\n country: text(1),\n city: text(2),\n });\n}\n\nasync function fetchPingResults(http: HttpClient, requestId: string, signal?: AbortSignal): Promise<Map<string, PingNodeResult>> {\n const url = new URL(`check-result/${encodeURIComponent(requestId)}`, CHECK_HOST_BASE_URL);\n const response = await http.fetchJson(url, {\n provider: PROVIDER,\n ...(signal ? { signal } : {}),\n });\n return parsePingResults(response.body);\n}\n\nexport function parsePingResults(body: unknown): Map<string, PingNodeResult> {\n if (!isRecord(body)) {\n throw malformed();\n }\n const results = new Map<string, PingNodeResult>();\n for (const [nodeId, raw] of Object.entries(body)) {\n results.set(nodeId, parseNodeResult(raw));\n }\n return results;\n}\n\nfunction parseNodeResult(raw: unknown): PingNodeResult {\n if (raw === null || raw === undefined) {\n return { state: 'pending' };\n }\n const outer = Array.isArray(raw) ? raw : [];\n const probes = Array.isArray(outer[0]) ? outer[0] : [];\n const firstProbe = probes[0];\n if (probes.length === 0 || firstProbe === null) {\n return { state: 'unresolved' };\n }\n const latencies: number[] = [];\n let address: string | undefined;\n let sent = 0;\n for (const probe of probes) {\n if (!Array.isArray(probe)) {\n continue;\n }\n sent += 1;\n const [status, seconds, ip] = probe as unknown[];\n if (address === undefined && typeof ip === 'string') {\n address = ip;\n }\n if (status === 'OK' && typeof seconds === 'number' && Number.isFinite(seconds)) {\n latencies.push(seconds * 1000);\n }\n }\n if (sent === 0) {\n return { state: 'unresolved' };\n }\n const received = latencies.length;\n const total = latencies.reduce((sum, value) => sum + value, 0);\n return {\n state: 'done',\n sent,\n received,\n averageMs: received > 0 ? total / received : undefined,\n minMs: received > 0 ? Math.min(...latencies) : undefined,\n maxMs: received > 0 ? Math.max(...latencies) : undefined,\n address,\n };\n}\n\nexport function formatPingReport(report: PingReport, locale: Locale = 'zh-CN'): string {\n const lines = [messages(locale, 'pingHeader', { host: report.host })];\n for (const { node, result } of report.nodes) {\n const place = [node.countryCode, node.city || node.country].filter(Boolean).join(' ') || node.id;\n lines.push(`${place}:${describeNodeResult(result, locale)}`);\n }\n if (report.permanentLink) {\n lines.push(messages(locale, 'detail', { link: report.permanentLink }));\n }\n return lines.join('\\n');\n}\n\nfunction describeNodeResult(result: PingNodeResult, locale: Locale): string {\n if (result.state === 'pending') {\n return messages(locale, 'pending');\n }\n if (result.state === 'unresolved') {\n return messages(locale, 'unresolved');\n }\n const loss = Math.round(((result.sent - result.received) / result.sent) * 100);\n const via = result.address ? ` → ${result.address}` : '';\n if (result.averageMs === undefined) {\n return messages(locale, 'allTimeout', { loss, via });\n }\n const average = result.averageMs.toFixed(1);\n const min = (result.minMs ?? result.averageMs).toFixed(1);\n const max = (result.maxMs ?? result.averageMs).toFixed(1);\n return messages(locale, 'pingStats', { average, min, max, loss, via });\n}\n\nfunction malformed(): NettoolsError {\n return new NettoolsError('malformed', message('pingMalformed'));\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const messages: (locale: import("zhin.js").Locale | undefined, key: "detail" | "dnsHeader" | "verified" | "nxdomain" | "noRecord" | "moreRecords" | "noDirectRecord" | "pingHeader" | "pending" | "unresolved" | "allTimeout" | "pingStats" | "noWhois" | "whoisHeader" | "registrar" | "createdAt" | "expiresAt" | "updatedAt" | "status" | "nameservers" | "dnssec" | "enabled" | "disabled" | "register" | "renew" | "transfer" | "noPrice" | "priceHeader" | "promo" | "registrars" | "priceUpdated" | "priceNote", values?: import("zhin.js").MessageValues) => string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
2
|
+
export const messages = createMessages({
|
|
3
|
+
dnsHeader: { 'zh-CN': '🔎 {name} {type} 记录({provider}{verified})', en: '🔎 {name} {type} records ({provider}{verified})' },
|
|
4
|
+
verified: { 'zh-CN': ',DNSSEC 已验证', en: ', DNSSEC validated' },
|
|
5
|
+
nxdomain: { 'zh-CN': '域名不存在 (NXDOMAIN)', en: 'Domain does not exist (NXDOMAIN)' },
|
|
6
|
+
noRecord: { 'zh-CN': '没有 {type} 记录', en: 'No {type} records' },
|
|
7
|
+
moreRecords: { 'zh-CN': '…另有 {count} 条', en: '…{count} more records' },
|
|
8
|
+
noDirectRecord: { 'zh-CN': '没有直接的 {type} 记录', en: 'No direct {type} records' },
|
|
9
|
+
pingHeader: { 'zh-CN': '📡 {host} 多地 Ping(check-host.net)', en: '📡 {host} multi-region ping (check-host.net)' },
|
|
10
|
+
detail: { 'zh-CN': '详情:{link}', en: 'Details: {link}' },
|
|
11
|
+
pending: { 'zh-CN': '未返回结果(超时)', en: 'No result returned (timed out)' },
|
|
12
|
+
unresolved: { 'zh-CN': '无法解析或不可达', en: 'Unresolvable or unreachable' },
|
|
13
|
+
allTimeout: { 'zh-CN': '全部超时(丢包 {loss}%){via}', en: 'All probes timed out ({loss}% packet loss){via}' },
|
|
14
|
+
pingStats: { 'zh-CN': '平均 {average}ms({min}/{max}),丢包 {loss}%{via}', en: 'Average {average}ms ({min}/{max}), {loss}% packet loss{via}' },
|
|
15
|
+
noWhois: { 'zh-CN': '📇 {domain}\n未查询到注册信息(可能未注册,或该后缀未提供 RDAP)', en: '📇 {domain}\nNo registration information found (the domain may be unregistered or RDAP may be unavailable for this suffix)' },
|
|
16
|
+
whoisHeader: { 'zh-CN': '📇 {domain} 注册信息(来源:{source})', en: '📇 {domain} registration (source: {source})' },
|
|
17
|
+
registrar: { 'zh-CN': '注册商:{value}', en: 'Registrar: {value}' },
|
|
18
|
+
createdAt: { 'zh-CN': '注册时间:{value}', en: 'Registered: {value}' },
|
|
19
|
+
expiresAt: { 'zh-CN': '到期时间:{value}', en: 'Expires: {value}' },
|
|
20
|
+
updatedAt: { 'zh-CN': '最近更新:{value}', en: 'Updated: {value}' },
|
|
21
|
+
status: { 'zh-CN': '状态:{value}', en: 'Status: {value}' },
|
|
22
|
+
nameservers: { 'zh-CN': 'DNS 服务器:{value}', en: 'Name servers: {value}' },
|
|
23
|
+
dnssec: { 'zh-CN': 'DNSSEC:{value}', en: 'DNSSEC: {value}' },
|
|
24
|
+
enabled: { 'zh-CN': '已启用', en: 'Enabled' },
|
|
25
|
+
disabled: { 'zh-CN': '未启用', en: 'Disabled' },
|
|
26
|
+
register: { 'zh-CN': '注册', en: 'registration' },
|
|
27
|
+
renew: { 'zh-CN': '续费', en: 'renewal' },
|
|
28
|
+
transfer: { 'zh-CN': '转入', en: 'transfer' },
|
|
29
|
+
noPrice: { 'zh-CN': '💰 .{suffix} 暂无{kind}价格数据', en: '💰 No {kind} prices for .{suffix}' },
|
|
30
|
+
priceHeader: { 'zh-CN': '💰 .{suffix} {kind}价格(低→高,nazhumi.com)', en: '💰 .{suffix} {kind} prices (low → high, nazhumi.com)' },
|
|
31
|
+
promo: { 'zh-CN': ' 🎟️有优惠码', en: ' 🎟️Promo code available' },
|
|
32
|
+
registrars: { 'zh-CN': '…共 {count} 家', en: '…{count} registrars in total' },
|
|
33
|
+
priceUpdated: { 'zh-CN': ',数据更新于 {date}', en: ', updated {date}' },
|
|
34
|
+
priceNote: { 'zh-CN': '价格仅供参考{updated},以注册商官网为准', en: 'Prices are indicative{updated}; confirm on the registrar website' },
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.js","sourceRoot":"","sources":["../src/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC;IACrC,SAAS,EAAE,EAAE,OAAO,EAAE,2CAA2C,EAAE,EAAE,EAAE,iDAAiD,EAAE;IAC1H,QAAQ,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,oBAAoB,EAAE;IAC9D,QAAQ,EAAE,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE,EAAE,kCAAkC,EAAE;IACjF,QAAQ,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,mBAAmB,EAAE;IAC9D,WAAW,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,uBAAuB,EAAE;IACtE,cAAc,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,0BAA0B,EAAE;IAC9E,UAAU,EAAE,EAAE,OAAO,EAAE,mCAAmC,EAAE,EAAE,EAAE,8CAA8C,EAAE;IAChH,MAAM,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,iBAAiB,EAAE;IACvD,OAAO,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,gCAAgC,EAAE;IACvE,UAAU,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,6BAA6B,EAAE;IACtE,UAAU,EAAE,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE,EAAE,iDAAiD,EAAE;IACvG,SAAS,EAAE,EAAE,OAAO,EAAE,6CAA6C,EAAE,EAAE,EAAE,6DAA6D,EAAE;IACxI,OAAO,EAAE,EAAE,OAAO,EAAE,2CAA2C,EAAE,EAAE,EAAE,4HAA4H,EAAE;IACnM,WAAW,EAAE,EAAE,OAAO,EAAE,+BAA+B,EAAE,EAAE,EAAE,6CAA6C,EAAE;IAC5G,SAAS,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,oBAAoB,EAAE;IAC/D,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,qBAAqB,EAAE;IACjE,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,kBAAkB,EAAE;IAC9D,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,kBAAkB,EAAE;IAC9D,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,iBAAiB,EAAE;IACxD,WAAW,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,uBAAuB,EAAE;IACxE,MAAM,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,iBAAiB,EAAE;IAC5D,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE;IAC1C,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE;IAC5C,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,cAAc,EAAE;IAC/C,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE;IACvC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE;IAC3C,OAAO,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,EAAE,EAAE,mCAAmC,EAAE;IAC1F,WAAW,EAAE,EAAE,OAAO,EAAE,wCAAwC,EAAE,EAAE,EAAE,sDAAsD,EAAE;IAC9H,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,0BAA0B,EAAE;IAC9D,UAAU,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,8BAA8B,EAAE;IAC3E,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,kBAAkB,EAAE;IAClE,SAAS,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,EAAE,EAAE,kEAAkE,EAAE;CAC3H,CAAC,CAAC","sourcesContent":["import { createMessages } from 'zhin.js/i18n';\n\nexport const messages = createMessages({\n dnsHeader: { 'zh-CN': '🔎 {name} {type} 记录({provider}{verified})', en: '🔎 {name} {type} records ({provider}{verified})' },\n verified: { 'zh-CN': ',DNSSEC 已验证', en: ', DNSSEC validated' },\n nxdomain: { 'zh-CN': '域名不存在 (NXDOMAIN)', en: 'Domain does not exist (NXDOMAIN)' },\n noRecord: { 'zh-CN': '没有 {type} 记录', en: 'No {type} records' },\n moreRecords: { 'zh-CN': '…另有 {count} 条', en: '…{count} more records' },\n noDirectRecord: { 'zh-CN': '没有直接的 {type} 记录', en: 'No direct {type} records' },\n pingHeader: { 'zh-CN': '📡 {host} 多地 Ping(check-host.net)', en: '📡 {host} multi-region ping (check-host.net)' },\n detail: { 'zh-CN': '详情:{link}', en: 'Details: {link}' },\n pending: { 'zh-CN': '未返回结果(超时)', en: 'No result returned (timed out)' },\n unresolved: { 'zh-CN': '无法解析或不可达', en: 'Unresolvable or unreachable' },\n allTimeout: { 'zh-CN': '全部超时(丢包 {loss}%){via}', en: 'All probes timed out ({loss}% packet loss){via}' },\n pingStats: { 'zh-CN': '平均 {average}ms({min}/{max}),丢包 {loss}%{via}', en: 'Average {average}ms ({min}/{max}), {loss}% packet loss{via}' },\n noWhois: { 'zh-CN': '📇 {domain}\\n未查询到注册信息(可能未注册,或该后缀未提供 RDAP)', en: '📇 {domain}\\nNo registration information found (the domain may be unregistered or RDAP may be unavailable for this suffix)' },\n whoisHeader: { 'zh-CN': '📇 {domain} 注册信息(来源:{source})', en: '📇 {domain} registration (source: {source})' },\n registrar: { 'zh-CN': '注册商:{value}', en: 'Registrar: {value}' },\n createdAt: { 'zh-CN': '注册时间:{value}', en: 'Registered: {value}' },\n expiresAt: { 'zh-CN': '到期时间:{value}', en: 'Expires: {value}' },\n updatedAt: { 'zh-CN': '最近更新:{value}', en: 'Updated: {value}' },\n status: { 'zh-CN': '状态:{value}', en: 'Status: {value}' },\n nameservers: { 'zh-CN': 'DNS 服务器:{value}', en: 'Name servers: {value}' },\n dnssec: { 'zh-CN': 'DNSSEC:{value}', en: 'DNSSEC: {value}' },\n enabled: { 'zh-CN': '已启用', en: 'Enabled' },\n disabled: { 'zh-CN': '未启用', en: 'Disabled' },\n register: { 'zh-CN': '注册', en: 'registration' },\n renew: { 'zh-CN': '续费', en: 'renewal' },\n transfer: { 'zh-CN': '转入', en: 'transfer' },\n noPrice: { 'zh-CN': '💰 .{suffix} 暂无{kind}价格数据', en: '💰 No {kind} prices for .{suffix}' },\n priceHeader: { 'zh-CN': '💰 .{suffix} {kind}价格(低→高,nazhumi.com)', en: '💰 .{suffix} {kind} prices (low → high, nazhumi.com)' },\n promo: { 'zh-CN': ' 🎟️有优惠码', en: ' 🎟️Promo code available' },\n registrars: { 'zh-CN': '…共 {count} 家', en: '…{count} registrars in total' },\n priceUpdated: { 'zh-CN': ',数据更新于 {date}', en: ', updated {date}' },\n priceNote: { 'zh-CN': '价格仅供参考{updated},以注册商官网为准', en: 'Prices are indicative{updated}; confirm on the registrar website' },\n});\n"]}
|
package/lib/service.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Locale } from 'zhin.js/i18n';
|
|
1
2
|
import { type NettoolsConfig, type ResolvedNettoolsConfig } from './config.js';
|
|
2
3
|
import { type HttpDependencies } from './http.js';
|
|
3
4
|
export interface NettoolsServiceOptions {
|
|
@@ -10,9 +11,9 @@ export declare class NettoolsService {
|
|
|
10
11
|
readonly config: ResolvedNettoolsConfig;
|
|
11
12
|
constructor(options?: NettoolsServiceOptions);
|
|
12
13
|
/** Run one operation and always resolve to a user-facing string. */
|
|
13
|
-
run(operation: () => Promise<string
|
|
14
|
-
ping(hostInput: string, callerKey: string, signal?: AbortSignal): Promise<string>;
|
|
15
|
-
whois(domainInput: string, callerKey: string, signal?: AbortSignal): Promise<string>;
|
|
16
|
-
dns(nameInput: string, typeInput: string | undefined, callerKey: string, signal?: AbortSignal): Promise<string>;
|
|
17
|
-
domainPrice(suffixInput: string, kindInput: string | undefined, callerKey: string, signal?: AbortSignal): Promise<string>;
|
|
14
|
+
run(operation: () => Promise<string>, locale?: Locale): Promise<string>;
|
|
15
|
+
ping(hostInput: string, callerKey: string, signal?: AbortSignal, locale?: Locale): Promise<string>;
|
|
16
|
+
whois(domainInput: string, callerKey: string, signal?: AbortSignal, locale?: Locale): Promise<string>;
|
|
17
|
+
dns(nameInput: string, typeInput: string | undefined, callerKey: string, signal?: AbortSignal, locale?: Locale): Promise<string>;
|
|
18
|
+
domainPrice(suffixInput: string, kindInput: string | undefined, callerKey: string, signal?: AbortSignal, locale?: Locale): Promise<string>;
|
|
18
19
|
}
|