@paulgit/mcp-dns-tools 2.3.0 → 2.4.1
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 +5 -3
- package/dist/index.js +138 -40
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/skills/dns-lookup/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ DNS and registration lookups come up more often than you'd think during developm
|
|
|
23
23
|
| `resolve_all` | Resolve common record types for a DNS overview; not for one named type |
|
|
24
24
|
| `check_nameservers` | Resolve NS, nameserver, authoritative nameserver, and delegation requests |
|
|
25
25
|
| `whois` | Query domain registration data using RDAP, with WHOIS fallback |
|
|
26
|
-
| `ip_whois` | Query IP allocation data using RDAP, with RIR WHOIS fallback
|
|
26
|
+
| `ip_whois` | Query IP allocation data using RDAP, with RIR WHOIS and RIPEstat fallback |
|
|
27
27
|
|
|
28
28
|
### Registration lookup behaviour
|
|
29
29
|
|
|
@@ -39,6 +39,8 @@ The existing `whois` and `ip_whois` tool names are retained for client compatibi
|
|
|
39
39
|
|
|
40
40
|
RDAP is authoritative when it returns `404 Not Found`; the tools do not then fall back to potentially stale WHOIS data. On a transport failure, rate limit, or unusable RDAP response, WHOIS is attempted and the result includes a warning explaining the fallback.
|
|
41
41
|
|
|
42
|
+
`ip_whois` adds a final last-resort fallback: if both RDAP and RIR WHOIS fail, it queries RIPEstat's RIR whois data over HTTPS. RIPEstat is a secondary aggregator rather than an authoritative source, so successful results are labelled `Protocol: RIPEstat (secondary source; data may lag the RIR whois database)` and carry the RDAP and WHOIS failure reasons as warnings. The caller identifies itself with the `sourceapp=mcp-dns-tools` parameter; RIPEstat asks heavy users (more than about 1000 requests per day) to register via the RIPE NCC. Domain `whois` lookups never use RIPEstat.
|
|
43
|
+
|
|
42
44
|
#### Failure reporting
|
|
43
45
|
|
|
44
46
|
A valid lookup that cannot be completed is returned as MCP error content with separate details for each attempted protocol:
|
|
@@ -56,7 +58,7 @@ WHOIS detail: connect ECONNREFUSED
|
|
|
56
58
|
Suggestion: Check outbound HTTPS and TCP port 43 access, then retry.
|
|
57
59
|
```
|
|
58
60
|
|
|
59
|
-
Stable reasons cover unavailable or missing RDAP, authoritative not-found responses, HTTP errors, rate limits, timeouts, DNS and connection failures, empty or invalid responses, retired or web-only WHOIS services, unsupported query formats, invalid encoding, response-size limits, and rejected, looping, or excessive referrals. Successful WHOIS fallback results retain the registration data and include the
|
|
61
|
+
Stable reasons cover unavailable or missing RDAP, authoritative not-found responses, HTTP errors, rate limits, timeouts, DNS and connection failures, empty or invalid responses, retired or web-only WHOIS services, unsupported query formats, invalid encoding, response-size limits, and rejected, looping, or excessive referrals. For `ip_whois`, RIPEstat failures add their own reason family (`RIPESTAT_NOT_FOUND`, `RIPESTAT_RATE_LIMITED`, `RIPESTAT_TIMEOUT`, `RIPESTAT_NETWORK_ERROR`, `RIPESTAT_HTTP_ERROR`, `RIPESTAT_INVALID_RESPONSE`, `RIPESTAT_DESTINATION_REJECTED`). Successful WHOIS or RIPEstat fallback results retain the registration data and include the earlier failure reasons as warnings.
|
|
60
62
|
|
|
61
63
|
## Install
|
|
62
64
|
|
|
@@ -116,7 +118,7 @@ docker build --platform linux/amd64 -t mcp-dns-tools:local .
|
|
|
116
118
|
docker run --rm -p 127.0.0.1:3000:3000 mcp-dns-tools:local
|
|
117
119
|
```
|
|
118
120
|
|
|
119
|
-
The public local-build fallback uses Chainguard's standard floating Node image, which includes BusyBox and npm. Forgejo overrides it with the private, versioned `node:24-slim`
|
|
121
|
+
The public local-build fallback uses Chainguard's standard floating Node image, which includes BusyBox and npm. Forgejo overrides it with the private, versioned base images: release tags use the shell-less, package-manager-free `node:24-slim` runtime, while development builds (`<version>-dev-<sha7>`) use the `node:24-dev` runtime so the published image retains a shell and package manager for debugging. Trivy gates the exact image before any tag is pushed.
|
|
120
122
|
|
|
121
123
|
For a hardened reference deployment, copy and adjust `compose.example.yml`:
|
|
122
124
|
|
package/dist/index.js
CHANGED
|
@@ -63,6 +63,8 @@ import dns from "dns/promises";
|
|
|
63
63
|
import net from "net";
|
|
64
64
|
import { domainToASCII } from "url";
|
|
65
65
|
import { Agent, fetch as undiciFetch } from "undici";
|
|
66
|
+
var RIPESTAT_WHOIS_ENDPOINT = "https://stat.ripe.net/data/whois/data.json";
|
|
67
|
+
var RIPESTAT_SOURCE_APP = "mcp-dns-tools";
|
|
66
68
|
var RDAP_DNS_BOOTSTRAP = "https://data.iana.org/rdap/dns.json";
|
|
67
69
|
var RDAP_IPV4_BOOTSTRAP = "https://data.iana.org/rdap/ipv4.json";
|
|
68
70
|
var RDAP_IPV6_BOOTSTRAP = "https://data.iana.org/rdap/ipv6.json";
|
|
@@ -238,6 +240,20 @@ function reasonForError(protocol, error) {
|
|
|
238
240
|
return "RESPONSE_TOO_LARGE";
|
|
239
241
|
if (message.includes("referral loop")) return "REFERRAL_LOOP";
|
|
240
242
|
if (message.includes("referral limit")) return "REFERRAL_LIMIT_REACHED";
|
|
243
|
+
if (protocol === "RIPESTAT") {
|
|
244
|
+
if (error instanceof RegistrationLookupError && error.kind === "not-found")
|
|
245
|
+
return "RIPESTAT_NOT_FOUND";
|
|
246
|
+
if (error instanceof RegistrationLookupError && error.kind === "rate-limited")
|
|
247
|
+
return "RIPESTAT_RATE_LIMITED";
|
|
248
|
+
if (message.includes("timed out") || code === "ETIMEDOUT")
|
|
249
|
+
return "RIPESTAT_TIMEOUT";
|
|
250
|
+
if (message.includes("http")) return "RIPESTAT_HTTP_ERROR";
|
|
251
|
+
if (error instanceof RegistrationLookupError && error.kind === "security")
|
|
252
|
+
return "RIPESTAT_DESTINATION_REJECTED";
|
|
253
|
+
if (error instanceof RegistrationLookupError && error.kind === "invalid-response")
|
|
254
|
+
return "RIPESTAT_INVALID_RESPONSE";
|
|
255
|
+
return "RIPESTAT_NETWORK_ERROR";
|
|
256
|
+
}
|
|
241
257
|
if (protocol === "RDAP") {
|
|
242
258
|
if (error instanceof RegistrationLookupError && error.kind === "not-found")
|
|
243
259
|
return "RDAP_NOT_FOUND";
|
|
@@ -271,11 +287,17 @@ function reasonForError(protocol, error) {
|
|
|
271
287
|
function warningText(warning) {
|
|
272
288
|
return `${warning.reason}: ${warning.detail}`;
|
|
273
289
|
}
|
|
274
|
-
function failureSuggestion(rdapReason, whoisReason) {
|
|
290
|
+
function failureSuggestion(rdapReason, whoisReason, ripestatReason) {
|
|
291
|
+
if (rdapReason === "RDAP_RATE_LIMITED" || whoisReason === "WHOIS_RATE_LIMITED" || ripestatReason === "RIPESTAT_RATE_LIMITED")
|
|
292
|
+
return "Retry later and reduce lookup frequency.";
|
|
293
|
+
if (ripestatReason !== void 0 && (rdapReason === "RDAP_NETWORK_ERROR" || rdapReason === "RDAP_TIMEOUT" || rdapReason === "RDAP_DESTINATION_REJECTED"))
|
|
294
|
+
return "Check outbound HTTPS access to the RDAP service, then retry.";
|
|
295
|
+
if (ripestatReason === "RIPESTAT_NOT_FOUND")
|
|
296
|
+
return "No RIPEstat registration data was found; consult the RIR whois database directly.";
|
|
297
|
+
if (ripestatReason !== void 0)
|
|
298
|
+
return "Check outbound HTTPS access to stat.ripe.net, then retry.";
|
|
275
299
|
if (whoisReason === "WHOIS_WEB_ONLY")
|
|
276
300
|
return "Use the registry's web-based registration lookup service.";
|
|
277
|
-
if (rdapReason === "RDAP_RATE_LIMITED" || whoisReason === "WHOIS_RATE_LIMITED")
|
|
278
|
-
return "Retry later and reduce lookup frequency.";
|
|
279
301
|
if (whoisReason === "WHOIS_SERVICE_RETIRED")
|
|
280
302
|
return "Use the registry's RDAP or web-based replacement service.";
|
|
281
303
|
if (whoisReason === "WHOIS_CONNECTION_REFUSED" || whoisReason === "WHOIS_CONNECTION_RESET" || whoisReason === "WHOIS_TIMEOUT" || whoisReason === "WHOIS_DNS_FAILURE")
|
|
@@ -286,9 +308,10 @@ function failureSuggestion(rdapReason, whoisReason) {
|
|
|
286
308
|
return "Use the last authoritative source shown or consult the registry website.";
|
|
287
309
|
return "Retry later or consult the registry's registration-data service.";
|
|
288
310
|
}
|
|
289
|
-
function formatLookupFailure(queryType, query, rdapError, whoisError) {
|
|
311
|
+
function formatLookupFailure(queryType, query, rdapError, whoisError, ripestatError) {
|
|
290
312
|
const rdapReason = reasonForError("RDAP", rdapError);
|
|
291
313
|
const whoisReason = reasonForError("WHOIS", whoisError);
|
|
314
|
+
const ripestatReason = ripestatError ? reasonForError("RIPESTAT", ripestatError) : void 0;
|
|
292
315
|
const rdapSource = rdapError instanceof RegistrationLookupError ? rdapError.source : void 0;
|
|
293
316
|
const whoisSource = whoisError instanceof RegistrationLookupError ? whoisError.source : void 0;
|
|
294
317
|
return [
|
|
@@ -302,7 +325,12 @@ function formatLookupFailure(queryType, query, rdapError, whoisError) {
|
|
|
302
325
|
`WHOIS reason: ${whoisReason}`,
|
|
303
326
|
...whoisSource ? [`WHOIS source: ${whoisSource}`] : [],
|
|
304
327
|
`WHOIS detail: ${errorMessage(whoisError)}`,
|
|
305
|
-
|
|
328
|
+
...ripestatError ? [
|
|
329
|
+
"RIPEstat status: failed",
|
|
330
|
+
`RIPEstat reason: ${ripestatReason}`,
|
|
331
|
+
`RIPEstat detail: ${errorMessage(ripestatError)}`
|
|
332
|
+
] : [],
|
|
333
|
+
`Suggestion: ${failureSuggestion(rdapReason, whoisReason, ripestatReason)}`
|
|
306
334
|
].join("\n");
|
|
307
335
|
}
|
|
308
336
|
async function readResponseBody(response, maximumBytes) {
|
|
@@ -360,7 +388,18 @@ function validateHttpsUrl(value) {
|
|
|
360
388
|
}
|
|
361
389
|
return url;
|
|
362
390
|
}
|
|
363
|
-
|
|
391
|
+
function jsonProtocolLabel(protocol) {
|
|
392
|
+
return protocol === "RIPESTAT" ? "RIPEstat" : "RDAP";
|
|
393
|
+
}
|
|
394
|
+
function jsonProtocolAccept(protocol) {
|
|
395
|
+
return protocol === "RIPESTAT" ? "application/json" : "application/rdap+json, application/json";
|
|
396
|
+
}
|
|
397
|
+
function jsonProtocolTimeoutReason(protocol) {
|
|
398
|
+
return protocol === "RIPESTAT" ? "RIPESTAT_TIMEOUT" : "RDAP_TIMEOUT";
|
|
399
|
+
}
|
|
400
|
+
async function fetchJson(initialUrl, maximumBytes, protocol = "RDAP") {
|
|
401
|
+
const label = jsonProtocolLabel(protocol);
|
|
402
|
+
const timeoutReason = jsonProtocolTimeoutReason(protocol);
|
|
364
403
|
let url = validateHttpsUrl(initialUrl);
|
|
365
404
|
for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {
|
|
366
405
|
let addresses;
|
|
@@ -377,7 +416,7 @@ async function fetchJson(initialUrl, maximumBytes) {
|
|
|
377
416
|
try {
|
|
378
417
|
const response = await undiciFetch(url, {
|
|
379
418
|
headers: {
|
|
380
|
-
accept:
|
|
419
|
+
accept: jsonProtocolAccept(protocol),
|
|
381
420
|
"user-agent": "mcp-dns-tools/registration-lookup"
|
|
382
421
|
},
|
|
383
422
|
dispatcher,
|
|
@@ -388,13 +427,13 @@ async function fetchJson(initialUrl, maximumBytes) {
|
|
|
388
427
|
const location = response.headers.get("location");
|
|
389
428
|
if (!location) {
|
|
390
429
|
throw new RegistrationLookupError(
|
|
391
|
-
|
|
430
|
+
`${label} redirect from ${url.hostname} has no location`,
|
|
392
431
|
"invalid-response"
|
|
393
432
|
);
|
|
394
433
|
}
|
|
395
434
|
if (redirects === MAX_REDIRECTS) {
|
|
396
435
|
throw new RegistrationLookupError(
|
|
397
|
-
|
|
436
|
+
`${label} redirect limit exceeded`,
|
|
398
437
|
"invalid-response"
|
|
399
438
|
);
|
|
400
439
|
}
|
|
@@ -413,13 +452,13 @@ async function fetchJson(initialUrl, maximumBytes) {
|
|
|
413
452
|
if (response.status === 429) {
|
|
414
453
|
const retryAfter = response.headers.get("retry-after");
|
|
415
454
|
throw new RegistrationLookupError(
|
|
416
|
-
|
|
455
|
+
`${label} service rate limited the request${retryAfter ? `; retry after ${retryAfter}` : ""}`,
|
|
417
456
|
"rate-limited"
|
|
418
457
|
);
|
|
419
458
|
}
|
|
420
459
|
if (!response.ok) {
|
|
421
460
|
throw new RegistrationLookupError(
|
|
422
|
-
|
|
461
|
+
`${label} service returned HTTP ${response.status}`,
|
|
423
462
|
"network"
|
|
424
463
|
);
|
|
425
464
|
}
|
|
@@ -428,13 +467,13 @@ async function fetchJson(initialUrl, maximumBytes) {
|
|
|
428
467
|
parsed = JSON.parse(body);
|
|
429
468
|
} catch {
|
|
430
469
|
throw new RegistrationLookupError(
|
|
431
|
-
|
|
470
|
+
`${label} service ${url.hostname} returned invalid JSON`,
|
|
432
471
|
"invalid-response"
|
|
433
472
|
);
|
|
434
473
|
}
|
|
435
474
|
if (!isRecord(parsed)) {
|
|
436
475
|
throw new RegistrationLookupError(
|
|
437
|
-
|
|
476
|
+
`${label} service ${url.hostname} returned an invalid object`,
|
|
438
477
|
"invalid-response"
|
|
439
478
|
);
|
|
440
479
|
}
|
|
@@ -445,7 +484,7 @@ async function fetchJson(initialUrl, maximumBytes) {
|
|
|
445
484
|
`Request to ${url.hostname} timed out`,
|
|
446
485
|
"network",
|
|
447
486
|
url.href,
|
|
448
|
-
|
|
487
|
+
timeoutReason
|
|
449
488
|
);
|
|
450
489
|
}
|
|
451
490
|
const sourcedError = ensureRegistrationErrorSource(error, url.href);
|
|
@@ -460,7 +499,7 @@ async function fetchJson(initialUrl, maximumBytes) {
|
|
|
460
499
|
await dispatcher.close();
|
|
461
500
|
}
|
|
462
501
|
}
|
|
463
|
-
throw new RegistrationLookupError(
|
|
502
|
+
throw new RegistrationLookupError(`${label} request failed`, "network");
|
|
464
503
|
}
|
|
465
504
|
async function getBootstrap(url) {
|
|
466
505
|
const cached = bootstrapCache.get(url);
|
|
@@ -969,9 +1008,61 @@ async function legacyWhois(query, discoveryQuery = query) {
|
|
|
969
1008
|
response
|
|
970
1009
|
].join("\n");
|
|
971
1010
|
}
|
|
972
|
-
function
|
|
1011
|
+
async function ripestatIpLookup(ip) {
|
|
1012
|
+
const url = new URL(RIPESTAT_WHOIS_ENDPOINT);
|
|
1013
|
+
url.searchParams.set("resource", ip);
|
|
1014
|
+
url.searchParams.set("sourceapp", RIPESTAT_SOURCE_APP);
|
|
1015
|
+
const response = await fetchJson(url.href, MAX_RDAP_BYTES, "RIPESTAT");
|
|
1016
|
+
const status = isRecord(response.data) ? stringValue(response.data.status) : void 0;
|
|
1017
|
+
if (status && status.toLowerCase() !== "ok") {
|
|
1018
|
+
const message = isRecord(response.data) ? stringValue(response.data.messages) : void 0;
|
|
1019
|
+
throw new RegistrationLookupError(
|
|
1020
|
+
`RIPEstat API returned error status ${status}${message ? `: ${message}` : ""}`,
|
|
1021
|
+
"invalid-response",
|
|
1022
|
+
url.href,
|
|
1023
|
+
"RIPESTAT_INVALID_RESPONSE"
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
1026
|
+
const topLevel = isRecord(response.data) ? response.data.data : void 0;
|
|
1027
|
+
const records = isRecord(topLevel) ? topLevel.records : void 0;
|
|
1028
|
+
if (!Array.isArray(records) || records.length === 0 || records.every((record) => !Array.isArray(record) || record.length === 0)) {
|
|
1029
|
+
throw new RegistrationLookupError(
|
|
1030
|
+
"No RIPEstat registration data found for this address",
|
|
1031
|
+
"not-found",
|
|
1032
|
+
url.href,
|
|
1033
|
+
"RIPESTAT_NOT_FOUND"
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
const lines = [];
|
|
1037
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1038
|
+
for (const record of records) {
|
|
1039
|
+
if (!Array.isArray(record)) continue;
|
|
1040
|
+
for (const entry of record) {
|
|
1041
|
+
if (!isRecord(entry)) continue;
|
|
1042
|
+
const key = stringValue(entry.key);
|
|
1043
|
+
const value = stringValue(entry.value);
|
|
1044
|
+
if (!key || !value) continue;
|
|
1045
|
+
const line = `${key}: ${value}`;
|
|
1046
|
+
if (seen.has(line)) continue;
|
|
1047
|
+
seen.add(line);
|
|
1048
|
+
lines.push(line);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return [
|
|
1052
|
+
"Protocol: RIPEstat (secondary source; data may lag the RIR whois database)",
|
|
1053
|
+
`Source: ${url.href}`,
|
|
1054
|
+
`IP: ${ip}`,
|
|
1055
|
+
...lines
|
|
1056
|
+
].join("\n");
|
|
1057
|
+
}
|
|
1058
|
+
function fallbackReport(error, protocol, fallback) {
|
|
1059
|
+
const reason = error === void 0 && protocol === "RDAP" ? "RDAP_NOT_AVAILABLE" : reasonForError(protocol, error);
|
|
973
1060
|
const source = error instanceof RegistrationLookupError && error.source ? ` at ${error.source}` : "";
|
|
974
|
-
|
|
1061
|
+
const detail = error === void 0 ? "RDAP was not attempted" : errorMessage(error);
|
|
1062
|
+
return `${reason}${source}: ${detail}; used ${fallback}`;
|
|
1063
|
+
}
|
|
1064
|
+
function fallbackWarning(error) {
|
|
1065
|
+
return fallbackReport(error, "RDAP", "WHOIS fallback");
|
|
975
1066
|
}
|
|
976
1067
|
async function domainRegistrationLookupResult(domain) {
|
|
977
1068
|
const normalised = normaliseRegistrationDomain(domain);
|
|
@@ -1104,26 +1195,33 @@ Warning: ${fallbackWarning(rdapError)}` : result,
|
|
|
1104
1195
|
failed: false
|
|
1105
1196
|
};
|
|
1106
1197
|
} catch (whoisError) {
|
|
1107
|
-
|
|
1198
|
+
try {
|
|
1199
|
+
const ripestat = await ripestatIpLookup(ip);
|
|
1200
|
+
const warnings = [
|
|
1201
|
+
`Warning: ${fallbackReport(rdapError, "RDAP", "WHOIS and RIPEstat fallbacks")}`,
|
|
1202
|
+
`Warning: ${fallbackReport(whoisError, "WHOIS", "RIPEstat fallback")}`
|
|
1203
|
+
].join("\n");
|
|
1204
|
+
return { text: `${ripestat}
|
|
1205
|
+
|
|
1206
|
+
${warnings}`, failed: false };
|
|
1207
|
+
} catch (ripestatError) {
|
|
1208
|
+
const rdapErrorForReport = rdapError ?? new RegistrationLookupError(
|
|
1209
|
+
"RDAP was not attempted",
|
|
1210
|
+
"unsupported",
|
|
1211
|
+
void 0,
|
|
1212
|
+
"RDAP_NOT_AVAILABLE"
|
|
1213
|
+
);
|
|
1108
1214
|
return {
|
|
1109
|
-
text: formatLookupFailure(
|
|
1215
|
+
text: formatLookupFailure(
|
|
1216
|
+
"IP",
|
|
1217
|
+
ip,
|
|
1218
|
+
rdapErrorForReport,
|
|
1219
|
+
whoisError,
|
|
1220
|
+
ripestatError
|
|
1221
|
+
),
|
|
1110
1222
|
failed: true
|
|
1111
1223
|
};
|
|
1112
1224
|
}
|
|
1113
|
-
return {
|
|
1114
|
-
text: formatLookupFailure(
|
|
1115
|
-
"IP",
|
|
1116
|
-
ip,
|
|
1117
|
-
new RegistrationLookupError(
|
|
1118
|
-
"RDAP was not attempted",
|
|
1119
|
-
"unsupported",
|
|
1120
|
-
void 0,
|
|
1121
|
-
"RDAP_NOT_AVAILABLE"
|
|
1122
|
-
),
|
|
1123
|
-
whoisError
|
|
1124
|
-
),
|
|
1125
|
-
failed: true
|
|
1126
|
-
};
|
|
1127
1225
|
}
|
|
1128
1226
|
}
|
|
1129
1227
|
|
|
@@ -1279,7 +1377,7 @@ import { z } from "zod";
|
|
|
1279
1377
|
var package_default = {
|
|
1280
1378
|
name: "@paulgit/mcp-dns-tools",
|
|
1281
1379
|
mcpName: "it.paulg/dns-tools",
|
|
1282
|
-
version: "2.
|
|
1380
|
+
version: "2.4.1",
|
|
1283
1381
|
description: "MCP server for DNS lookups, including CAA checks, reverse DNS, and RDAP-first domain or IP registration data with WHOIS fallback; zero auth, zero config",
|
|
1284
1382
|
type: "module",
|
|
1285
1383
|
publishConfig: {
|
|
@@ -1342,17 +1440,17 @@ var package_default = {
|
|
|
1342
1440
|
zod: "^3.25.0"
|
|
1343
1441
|
},
|
|
1344
1442
|
devDependencies: {
|
|
1345
|
-
"@eslint/js": "^
|
|
1346
|
-
"@types/node": "^
|
|
1347
|
-
eslint: "^
|
|
1443
|
+
"@eslint/js": "^10.0.0",
|
|
1444
|
+
"@types/node": "^24.0.0",
|
|
1445
|
+
eslint: "^10.0.0",
|
|
1348
1446
|
"eslint-config-prettier": "^10.0.0",
|
|
1349
1447
|
husky: "^9.0.0",
|
|
1350
|
-
"lint-staged": "^
|
|
1448
|
+
"lint-staged": "^17.0.0",
|
|
1351
1449
|
prettier: "^3.0.0",
|
|
1352
1450
|
tsup: "^8.0.0",
|
|
1353
1451
|
typescript: "^5.7.0",
|
|
1354
1452
|
"typescript-eslint": "^8.0.0",
|
|
1355
|
-
vitest: "^
|
|
1453
|
+
vitest: "^4.0.0"
|
|
1356
1454
|
},
|
|
1357
1455
|
"lint-staged": {
|
|
1358
1456
|
"*.{ts,tsx,js}": [
|
|
@@ -1470,7 +1568,7 @@ function createMcpServer() {
|
|
|
1470
1568
|
"ip_whois",
|
|
1471
1569
|
{
|
|
1472
1570
|
title: "IP registration lookup",
|
|
1473
|
-
description: "Query authoritative IPv4 or IPv6 allocation and network ownership data. Uses IANA RDAP bootstrap discovery over HTTPS, with bounded legacy WHOIS fallback to the appropriate Regional Internet Registry. Failures identify each attempted protocol, endpoint, stable reason code, detail, and suggested next action.",
|
|
1571
|
+
description: "Query authoritative IPv4 or IPv6 allocation and network ownership data. Uses IANA RDAP bootstrap discovery over HTTPS, with bounded legacy WHOIS fallback to the appropriate Regional Internet Registry. When both fail, falls back to RIPEstat's secondary RIR whois data over HTTPS as a last resort. Failures identify each attempted protocol, endpoint, stable reason code, detail, and suggested next action.",
|
|
1474
1572
|
inputSchema: {
|
|
1475
1573
|
ip: z.string().describe("IP address (e.g. 8.8.8.8 or 2001:4860:4860::8888)")
|
|
1476
1574
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/cli.ts","../src/dns.ts","../src/registration.ts","../src/http.ts","../src/server.ts","../package.json"],"sourcesContent":["import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { parseCliArgs } from \"./cli.js\";\nimport { configureDnsServers } from \"./dns.js\";\nimport { startHttpServer, stopHttpServer } from \"./http.js\";\nimport { createMcpServer } from \"./server.js\";\n\nconfigureDnsServers();\n\nasync function main() {\n const options = parseCliArgs(process.argv.slice(2));\n if (options.transport === \"stdio\") {\n const server = createMcpServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n return;\n }\n\n const httpServer = await startHttpServer(options);\n console.error(\n `MCP Streamable HTTP server listening on http://${options.host}:${options.port}/mcp`,\n );\n\n let shuttingDown = false;\n const shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n await stopHttpServer(httpServer);\n };\n\n process.once(\"SIGINT\", () => void shutdown());\n process.once(\"SIGTERM\", () => void shutdown());\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n","import { parseArgs } from \"node:util\";\n\nexport type CliOptions =\n | {\n transport: \"stdio\";\n }\n | {\n transport: \"http\";\n host: string;\n port: number;\n allowedHosts: string[];\n };\n\nexport function parseCliArgs(\n args: string[],\n env: NodeJS.ProcessEnv = process.env,\n): CliOptions {\n const { values } = parseArgs({\n args,\n options: {\n transport: {\n type: \"string\",\n default: \"stdio\",\n },\n host: {\n type: \"string\",\n },\n port: {\n type: \"string\",\n },\n \"allowed-host\": {\n type: \"string\",\n multiple: true,\n },\n },\n strict: true,\n });\n\n if (values.transport !== \"stdio\" && values.transport !== \"http\") {\n throw new Error(\n `Unsupported transport: ${values.transport}. Supported transports: stdio, http.`,\n );\n }\n\n if (values.transport === \"stdio\") {\n if (\n values.host !== undefined ||\n values.port !== undefined ||\n values[\"allowed-host\"] !== undefined\n ) {\n throw new Error(\n \"--host, --port, and --allowed-host can only be used with --transport http.\",\n );\n }\n return { transport: \"stdio\" };\n }\n\n const host = values.host ?? env.HOST ?? \"127.0.0.1\";\n const portValue = values.port ?? env.PORT ?? \"3000\";\n const port = Number(portValue);\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new Error(`Invalid HTTP port: ${portValue}. Expected 1-65535.`);\n }\n\n return {\n transport: \"http\",\n host,\n port,\n allowedHosts: values[\"allowed-host\"] ?? [],\n };\n}\n","import dns from \"node:dns/promises\";\nimport { setServers } from \"node:dns\";\nimport type { CaaRecord } from \"node:dns\";\nimport net from \"node:net\";\nimport type { RegistrationLookupResult } from \"./registration.js\";\nimport {\n domainRegistrationLookup,\n domainRegistrationLookupResult,\n ipRegistrationLookup,\n ipRegistrationLookupResult,\n} from \"./registration.js\";\n\nexport type { RegistrationLookupResult };\n\nexport type RecordType =\n | \"A\"\n | \"AAAA\"\n | \"MX\"\n | \"TXT\"\n | \"CNAME\"\n | \"NS\"\n | \"SOA\"\n | \"SRV\"\n | \"CAA\"\n | \"PTR\";\n\ninterface MxRecord {\n exchange: string;\n priority: number;\n}\n\ninterface SoaRecord {\n nsname: string;\n hostmaster: string;\n serial: number;\n refresh: number;\n retry: number;\n expire: number;\n minttl: number;\n}\n\ninterface SrvRecord {\n priority: number;\n weight: number;\n port: number;\n name: string;\n}\n\nexport function configureDnsServers(env = process.env): void {\n const raw = env.DNS_SERVERS;\n if (!raw) return;\n const servers = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => net.isIP(s) !== 0);\n if (servers.length > 0) {\n setServers(servers);\n }\n}\n\nfunction mapDnsError(error: unknown, type: string, target: string): string {\n const code = (error as NodeJS.ErrnoException).code;\n switch (code) {\n case \"ENODATA\":\n return `No ${type} records found for ${target}.`;\n case \"ENOTFOUND\":\n return `Domain not found: ${target}`;\n case \"EREFUSED\":\n return `DNS server refused the ${type} query for ${target}. The local resolver may not support this record type; set DNS_SERVERS to use a different resolver.`;\n case \"ETIMEOUT\":\n return `DNS query for ${target} (${type}) timed out.`;\n default:\n return `DNS lookup failed for ${target} (${type}): ${code ?? \"unknown error\"}`;\n }\n}\n\nconst DOMAIN_RE =\n /^(?=.{1,253}$)[a-zA-Z0-9_]([a-zA-Z0-9_-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9_]([a-zA-Z0-9_-]{0,61}[a-zA-Z0-9])?)*\\.?$/;\n\nfunction assertValidDomain(domain: string): void {\n if (!DOMAIN_RE.test(domain)) {\n throw new Error(\"Invalid domain\");\n }\n}\n\nexport async function dnsLookup(\n domain: string,\n type: RecordType,\n): Promise<string> {\n assertValidDomain(domain);\n let records: unknown;\n try {\n records = await dns.resolve(domain, type);\n } catch (error) {\n return mapDnsError(error, type, domain);\n }\n\n switch (type) {\n case \"MX\": {\n const mx = records as MxRecord[];\n if (mx.length === 0) return \"No MX records found.\";\n return mx\n .sort((a, b) => a.priority - b.priority)\n .map((r) => `${r.priority} ${r.exchange}`)\n .join(\"\\n\");\n }\n case \"TXT\": {\n const txt = records as string[][];\n if (txt.length === 0) return \"No TXT records found.\";\n return txt.map((entries) => entries.join(\"\")).join(\"\\n\");\n }\n case \"CAA\": {\n const caa = records as CaaRecord[];\n if (caa.length === 0) return \"No CAA records found.\";\n const formatted = caa.flatMap(({ critical, ...tags }) =>\n Object.entries(tags)\n .filter(\n (entry): entry is [string, string] =>\n entry[0] !== \"type\" && typeof entry[1] === \"string\",\n )\n .map(([tag, value]) => `${critical} ${tag} ${JSON.stringify(value)}`),\n );\n return formatted.length > 0\n ? formatted.join(\"\\n\")\n : \"No CAA records found.\";\n }\n case \"SOA\": {\n const soa = records as SoaRecord[];\n const s = soa[0];\n if (!s) return \"No SOA record found.\";\n return [\n `nsname: ${s.nsname}`,\n `hostmaster: ${s.hostmaster}`,\n `serial: ${s.serial}`,\n `refresh: ${s.refresh}`,\n `retry: ${s.retry}`,\n `expire: ${s.expire}`,\n `minttl: ${s.minttl}`,\n ].join(\"\\n\");\n }\n case \"SRV\": {\n const srv = records as SrvRecord[];\n if (srv.length === 0) return \"No SRV records found.\";\n return srv\n .map((r) => `${r.priority} ${r.weight} ${r.port} ${r.name}`)\n .join(\"\\n\");\n }\n default: {\n const arr = records as string[];\n if (arr.length === 0) return `No ${type} records found.`;\n return arr.join(\"\\n\");\n }\n }\n}\n\nexport async function reverseDns(ip: string): Promise<string> {\n if (net.isIP(ip) === 0) {\n throw new Error(\"Invalid IP address\");\n }\n let hostnames: string[];\n try {\n hostnames = await dns.reverse(ip);\n } catch (error) {\n return mapDnsError(error, \"PTR\", ip);\n }\n return hostnames.length > 0 ? hostnames.join(\"\\n\") : \"No PTR records found.\";\n}\n\nexport async function resolveAll(domain: string): Promise<string> {\n assertValidDomain(domain);\n const types: { name: string; type: RecordType }[] = [\n { name: \"A\", type: \"A\" },\n { name: \"AAAA\", type: \"AAAA\" },\n { name: \"MX\", type: \"MX\" },\n { name: \"TXT\", type: \"TXT\" },\n { name: \"CAA\", type: \"CAA\" },\n { name: \"NS\", type: \"NS\" },\n { name: \"CNAME\", type: \"CNAME\" },\n ];\n\n const results: string[] = [];\n for (const { name, type } of types) {\n try {\n const records = await dnsLookup(domain, type);\n results.push(`=== ${name} ===\\n${records}`);\n } catch {\n results.push(`=== ${name} ===\\n(no records or error)`);\n }\n }\n return results.join(\"\\n\\n\");\n}\n\nexport async function checkNameservers(domain: string): Promise<string> {\n assertValidDomain(domain);\n let nameservers: string[];\n try {\n nameservers = await dns.resolveNs(domain);\n } catch (error) {\n return mapDnsError(error, \"NS\", domain);\n }\n return nameservers.length > 0\n ? nameservers.join(\"\\n\")\n : \"No nameserver records found.\";\n}\n\nexport async function whoisLookup(domain: string): Promise<string> {\n return await domainRegistrationLookup(domain);\n}\n\nexport async function whoisLookupResult(\n domain: string,\n): Promise<RegistrationLookupResult> {\n return await domainRegistrationLookupResult(domain);\n}\n\nexport async function ipWhois(ip: string): Promise<string> {\n return await ipRegistrationLookup(ip);\n}\n\nexport async function ipWhoisResult(\n ip: string,\n): Promise<RegistrationLookupResult> {\n return await ipRegistrationLookupResult(ip);\n}\n","import dns from \"node:dns/promises\";\nimport net from \"node:net\";\nimport { domainToASCII } from \"node:url\";\nimport { Agent, fetch as undiciFetch } from \"undici\";\n\nconst RDAP_DNS_BOOTSTRAP = \"https://data.iana.org/rdap/dns.json\";\nconst RDAP_IPV4_BOOTSTRAP = \"https://data.iana.org/rdap/ipv4.json\";\nconst RDAP_IPV6_BOOTSTRAP = \"https://data.iana.org/rdap/ipv6.json\";\nconst BOOTSTRAP_TTL_MS = 24 * 60 * 60 * 1000;\nconst REQUEST_TIMEOUT_MS = 10_000;\nconst MAX_REDIRECTS = 3;\nconst MAX_RDAP_BYTES = 1024 * 1024;\nconst MAX_BOOTSTRAP_BYTES = 2 * 1024 * 1024;\nconst MAX_WHOIS_BYTES = 1024 * 1024;\nconst MAX_WHOIS_QUERIES = 3;\n\ninterface BootstrapData {\n services: unknown[];\n}\n\ninterface BootstrapCacheEntry {\n data: BootstrapData;\n expiresAt: number;\n}\n\ninterface RdapResponse {\n data: Record<string, unknown>;\n source: string;\n}\n\ninterface WhoisEndpoint {\n host: string;\n port: number;\n}\n\ninterface ResolvedAddress {\n address: string;\n family: 4 | 6;\n}\n\nexport interface RegistrationLookupResult {\n text: string;\n failed: boolean;\n}\n\nexport type RegistrationReason =\n | \"RDAP_NOT_AVAILABLE\"\n | \"RDAP_NOT_FOUND\"\n | \"RDAP_RATE_LIMITED\"\n | \"RDAP_TIMEOUT\"\n | \"RDAP_NETWORK_ERROR\"\n | \"RDAP_HTTP_ERROR\"\n | \"RDAP_INVALID_RESPONSE\"\n | \"RDAP_DESTINATION_REJECTED\"\n | \"WHOIS_NOT_ADVERTISED\"\n | \"WHOIS_NOT_FOUND\"\n | \"WHOIS_CONNECTION_REFUSED\"\n | \"WHOIS_CONNECTION_RESET\"\n | \"WHOIS_TIMEOUT\"\n | \"WHOIS_DNS_FAILURE\"\n | \"WHOIS_EMPTY_RESPONSE\"\n | \"WHOIS_RATE_LIMITED\"\n | \"WHOIS_SERVICE_RETIRED\"\n | \"WHOIS_WEB_ONLY\"\n | \"WHOIS_UNSUPPORTED_RESPONSE\"\n | \"WHOIS_INVALID_ENCODING\"\n | \"REFERRAL_REJECTED\"\n | \"REFERRAL_LOOP\"\n | \"REFERRAL_LIMIT_REACHED\"\n | \"RESPONSE_TOO_LARGE\"\n | \"UNKNOWN_ERROR\";\n\ninterface RegistrationWarning {\n reason: RegistrationReason;\n detail: string;\n}\n\nclass RegistrationLookupError extends Error {\n constructor(\n message: string,\n readonly kind:\n | \"invalid-response\"\n | \"network\"\n | \"not-found\"\n | \"rate-limited\"\n | \"security\"\n | \"unsupported\",\n readonly source?: string,\n readonly reason?: RegistrationReason,\n ) {\n super(message);\n this.name = \"RegistrationLookupError\";\n }\n}\n\nfunction ensureRegistrationErrorSource(\n error: unknown,\n source: string,\n): unknown {\n if (!(error instanceof RegistrationLookupError) || error.source !== undefined)\n return error;\n return new RegistrationLookupError(\n error.message,\n error.kind,\n source,\n error.reason,\n );\n}\n\nconst bootstrapCache = new Map<string, BootstrapCacheEntry>();\n\nconst blockedAddresses = new net.BlockList();\nconst syntheticHttpsProxyAddresses = new net.BlockList();\n// Some sandboxed network transports map public hosts into this benchmarking range.\nsyntheticHttpsProxyAddresses.addSubnet(\"198.18.0.0\", 15, \"ipv4\");\nfor (const [address, prefix] of [\n [\"0.0.0.0\", 8],\n [\"10.0.0.0\", 8],\n [\"100.64.0.0\", 10],\n [\"127.0.0.0\", 8],\n [\"169.254.0.0\", 16],\n [\"172.16.0.0\", 12],\n [\"192.0.0.0\", 24],\n [\"192.0.2.0\", 24],\n [\"192.168.0.0\", 16],\n [\"198.18.0.0\", 15],\n [\"198.51.100.0\", 24],\n [\"203.0.113.0\", 24],\n [\"224.0.0.0\", 4],\n [\"240.0.0.0\", 4],\n] as const) {\n blockedAddresses.addSubnet(address, prefix, \"ipv4\");\n}\nfor (const [address, prefix] of [\n [\"::\", 128],\n [\"::1\", 128],\n [\"64:ff9b:1::\", 48],\n [\"100::\", 64],\n [\"2001:db8::\", 32],\n [\"fc00::\", 7],\n [\"fe80::\", 10],\n [\"fec0::\", 10],\n [\"ff00::\", 8],\n] as const) {\n blockedAddresses.addSubnet(address, prefix, \"ipv6\");\n}\n\nexport function resetRegistrationCaches(): void {\n bootstrapCache.clear();\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringValue(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.trim()) return value.trim();\n if (Array.isArray(value)) {\n const values = value\n .map((entry) => stringValue(entry))\n .filter((entry): entry is string => entry !== undefined);\n return values.length > 0 ? values.join(\", \") : undefined;\n }\n return undefined;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter(\n (entry): entry is string => typeof entry === \"string\" && entry.length > 0,\n );\n}\n\nfunction isBlockedAddress(address: string): boolean {\n const family = net.isIP(address);\n if (family === 4) return blockedAddresses.check(address, \"ipv4\");\n if (family === 6) return blockedAddresses.check(address, \"ipv6\");\n return true;\n}\n\nasync function resolvePublicHostname(\n hostname: string,\n allowSyntheticNetworkProxy = false,\n): Promise<ResolvedAddress[]> {\n const normalised = hostname\n .replace(/^\\[|\\]$/g, \"\")\n .replace(/\\.$/, \"\")\n .toLowerCase();\n if (\n !normalised ||\n normalised === \"localhost\" ||\n normalised.endsWith(\".local\")\n ) {\n throw new RegistrationLookupError(\n `Refusing registration-data connection to ${hostname}`,\n \"security\",\n );\n }\n\n if (net.isIP(normalised) !== 0) {\n if (isBlockedAddress(normalised)) {\n throw new RegistrationLookupError(\n `Refusing registration-data connection to non-public address ${hostname}`,\n \"security\",\n );\n }\n return [\n {\n address: normalised,\n family: net.isIP(normalised) as 4 | 6,\n },\n ];\n }\n\n let addresses: { address: string; family: number }[];\n try {\n addresses = await dns.lookup(normalised, {\n all: true,\n verbatim: true,\n });\n } catch (error) {\n throw new RegistrationLookupError(\n `Unable to resolve registration-data service ${hostname}: ${errorMessage(error)}`,\n \"network\",\n );\n }\n\n const resolved = addresses.filter(\n (entry): entry is ResolvedAddress =>\n entry.family === 4 || entry.family === 6,\n );\n if (\n resolved.length === 0 ||\n resolved.some(\n (entry) =>\n isBlockedAddress(entry.address) &&\n !(\n allowSyntheticNetworkProxy &&\n entry.family === 4 &&\n syntheticHttpsProxyAddresses.check(entry.address, \"ipv4\")\n ),\n )\n ) {\n throw new RegistrationLookupError(\n `Refusing registration-data connection to ${hostname}: destination is not public`,\n \"security\",\n );\n }\n return resolved;\n}\n\nfunction pinnedLookup(addresses: ResolvedAddress[]): net.LookupFunction {\n return (_hostname, options, callback): void => {\n const requestedFamily = options.family ?? 0;\n const candidates = addresses.filter(\n (entry) => requestedFamily === 0 || entry.family === requestedFamily,\n );\n if (candidates.length === 0) {\n const error = new Error(\n `No validated address for requested family ${requestedFamily}`,\n ) as NodeJS.ErrnoException;\n error.code = \"EAI_ADDRFAMILY\";\n callback(error, \"\");\n return;\n }\n if (options.all) {\n callback(null, candidates);\n return;\n }\n const [selected] = candidates;\n if (!selected) {\n callback(new Error(\"No validated address available\"), \"\");\n return;\n }\n callback(null, selected.address, selected.family);\n };\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"unknown error\";\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return error instanceof Error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\nfunction reasonForError(\n protocol: \"RDAP\" | \"WHOIS\",\n error: unknown,\n): RegistrationReason {\n if (error instanceof RegistrationLookupError && error.reason)\n return error.reason;\n\n const message = errorMessage(error).toLowerCase();\n const code = errorCode(error);\n if (message.includes(\"exceeds\") && message.includes(\"bytes\"))\n return \"RESPONSE_TOO_LARGE\";\n if (message.includes(\"referral loop\")) return \"REFERRAL_LOOP\";\n if (message.includes(\"referral limit\")) return \"REFERRAL_LIMIT_REACHED\";\n\n if (protocol === \"RDAP\") {\n if (error instanceof RegistrationLookupError && error.kind === \"not-found\")\n return \"RDAP_NOT_FOUND\";\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"rate-limited\"\n )\n return \"RDAP_RATE_LIMITED\";\n if (message.includes(\"timed out\") || code === \"ETIMEDOUT\")\n return \"RDAP_TIMEOUT\";\n if (message.includes(\"http \")) return \"RDAP_HTTP_ERROR\";\n if (error instanceof RegistrationLookupError && error.kind === \"security\")\n return \"RDAP_DESTINATION_REJECTED\";\n if (\n error instanceof RegistrationLookupError &&\n (error.kind === \"invalid-response\" || error.kind === \"unsupported\")\n )\n return error.kind === \"unsupported\"\n ? \"RDAP_NOT_AVAILABLE\"\n : \"RDAP_INVALID_RESPONSE\";\n return \"RDAP_NETWORK_ERROR\";\n }\n\n if (code === \"ECONNREFUSED\") return \"WHOIS_CONNECTION_REFUSED\";\n if (code === \"ECONNRESET\") return \"WHOIS_CONNECTION_RESET\";\n if (code === \"ENOTFOUND\" || code === \"EAI_AGAIN\") return \"WHOIS_DNS_FAILURE\";\n if (message.includes(\"unable to resolve registration-data service\"))\n return \"WHOIS_DNS_FAILURE\";\n if (message.includes(\"timed out\") || code === \"ETIMEDOUT\")\n return \"WHOIS_TIMEOUT\";\n if (message.includes(\"no whois data\")) return \"WHOIS_EMPTY_RESPONSE\";\n if (error instanceof RegistrationLookupError && error.kind === \"unsupported\")\n return \"WHOIS_NOT_ADVERTISED\";\n if (error instanceof RegistrationLookupError && error.kind === \"rate-limited\")\n return \"WHOIS_RATE_LIMITED\";\n if (error instanceof RegistrationLookupError && error.kind === \"security\")\n return \"REFERRAL_REJECTED\";\n return \"UNKNOWN_ERROR\";\n}\n\nfunction warningText(warning: RegistrationWarning): string {\n return `${warning.reason}: ${warning.detail}`;\n}\n\nfunction failureSuggestion(\n rdapReason: RegistrationReason,\n whoisReason: RegistrationReason,\n): string {\n if (whoisReason === \"WHOIS_WEB_ONLY\")\n return \"Use the registry's web-based registration lookup service.\";\n if (\n rdapReason === \"RDAP_RATE_LIMITED\" ||\n whoisReason === \"WHOIS_RATE_LIMITED\"\n )\n return \"Retry later and reduce lookup frequency.\";\n if (whoisReason === \"WHOIS_SERVICE_RETIRED\")\n return \"Use the registry's RDAP or web-based replacement service.\";\n if (\n whoisReason === \"WHOIS_CONNECTION_REFUSED\" ||\n whoisReason === \"WHOIS_CONNECTION_RESET\" ||\n whoisReason === \"WHOIS_TIMEOUT\" ||\n whoisReason === \"WHOIS_DNS_FAILURE\"\n )\n return \"Check outbound HTTPS and TCP port 43 access, then retry.\";\n if (\n whoisReason === \"WHOIS_NOT_ADVERTISED\" ||\n whoisReason === \"WHOIS_UNSUPPORTED_RESPONSE\"\n )\n return \"Consult the TLD registry website for its supported lookup service.\";\n if (whoisReason === \"REFERRAL_REJECTED\" || whoisReason === \"REFERRAL_LOOP\")\n return \"Use the last authoritative source shown or consult the registry website.\";\n return \"Retry later or consult the registry's registration-data service.\";\n}\n\nfunction formatLookupFailure(\n queryType: \"Domain\" | \"IP\",\n query: string,\n rdapError: unknown,\n whoisError: unknown,\n): string {\n const rdapReason = reasonForError(\"RDAP\", rdapError);\n const whoisReason = reasonForError(\"WHOIS\", whoisError);\n const rdapSource =\n rdapError instanceof RegistrationLookupError ? rdapError.source : undefined;\n const whoisSource =\n whoisError instanceof RegistrationLookupError\n ? whoisError.source\n : undefined;\n return [\n \"Status: failed\",\n `${queryType}: ${query}`,\n \"RDAP status: failed\",\n `RDAP reason: ${rdapReason}`,\n ...(rdapSource ? [`RDAP source: ${rdapSource}`] : []),\n `RDAP detail: ${errorMessage(rdapError)}`,\n \"WHOIS status: failed\",\n `WHOIS reason: ${whoisReason}`,\n ...(whoisSource ? [`WHOIS source: ${whoisSource}`] : []),\n `WHOIS detail: ${errorMessage(whoisError)}`,\n `Suggestion: ${failureSuggestion(rdapReason, whoisReason)}`,\n ].join(\"\\n\");\n}\n\nasync function readResponseBody(\n response: Response,\n maximumBytes: number,\n): Promise<string> {\n const contentLength = response.headers.get(\"content-length\");\n if (contentLength && Number(contentLength) > maximumBytes) {\n await response.body?.cancel();\n throw new RegistrationLookupError(\n `Registration-data response exceeds ${maximumBytes} bytes`,\n \"invalid-response\",\n );\n }\n\n if (!response.body) return \"\";\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maximumBytes) {\n try {\n await reader.cancel();\n } catch {\n // The size-limit error below is more useful than a cancellation error.\n }\n throw new RegistrationLookupError(\n `Registration-data response exceeds ${maximumBytes} bytes`,\n \"invalid-response\",\n );\n }\n chunks.push(value);\n }\n\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(body);\n}\n\nfunction validateHttpsUrl(value: string): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new RegistrationLookupError(\n `Invalid RDAP service URL: ${value}`,\n \"invalid-response\",\n );\n }\n if (\n url.protocol !== \"https:\" ||\n url.username ||\n url.password ||\n (url.port && url.port !== \"443\")\n ) {\n throw new RegistrationLookupError(\n `Refusing non-standard RDAP service URL: ${value}`,\n \"security\",\n );\n }\n return url;\n}\n\nasync function fetchJson(\n initialUrl: string,\n maximumBytes: number,\n): Promise<{ data: Record<string, unknown>; source: string }> {\n let url = validateHttpsUrl(initialUrl);\n\n for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {\n let addresses: ResolvedAddress[];\n try {\n addresses = await resolvePublicHostname(url.hostname, true);\n } catch (error) {\n throw ensureRegistrationErrorSource(error, url.href);\n }\n const dispatcher = new Agent({\n connect: { lookup: pinnedLookup(addresses) },\n });\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n try {\n const response = (await undiciFetch(url, {\n headers: {\n accept: \"application/rdap+json, application/json\",\n \"user-agent\": \"mcp-dns-tools/registration-lookup\",\n },\n dispatcher,\n redirect: \"manual\",\n signal: controller.signal,\n })) as unknown as Response;\n\n if ([301, 302, 303, 307, 308].includes(response.status)) {\n const location = response.headers.get(\"location\");\n if (!location) {\n throw new RegistrationLookupError(\n `RDAP redirect from ${url.hostname} has no location`,\n \"invalid-response\",\n );\n }\n if (redirects === MAX_REDIRECTS) {\n throw new RegistrationLookupError(\n \"RDAP redirect limit exceeded\",\n \"invalid-response\",\n );\n }\n await response.body?.cancel();\n url = validateHttpsUrl(new URL(location, url).href);\n continue;\n }\n\n const body = await readResponseBody(response, maximumBytes);\n if (response.status === 404) {\n throw new RegistrationLookupError(\n \"Registration data not found\",\n \"not-found\",\n url.href,\n );\n }\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n throw new RegistrationLookupError(\n `RDAP service rate limited the request${retryAfter ? `; retry after ${retryAfter}` : \"\"}`,\n \"rate-limited\",\n );\n }\n if (!response.ok) {\n throw new RegistrationLookupError(\n `RDAP service returned HTTP ${response.status}`,\n \"network\",\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new RegistrationLookupError(\n `RDAP service ${url.hostname} returned invalid JSON`,\n \"invalid-response\",\n );\n }\n if (!isRecord(parsed)) {\n throw new RegistrationLookupError(\n `RDAP service ${url.hostname} returned an invalid object`,\n \"invalid-response\",\n );\n }\n return { data: parsed, source: url.href };\n } catch (error) {\n if (controller.signal.aborted) {\n throw new RegistrationLookupError(\n `Request to ${url.hostname} timed out`,\n \"network\",\n url.href,\n \"RDAP_TIMEOUT\",\n );\n }\n const sourcedError = ensureRegistrationErrorSource(error, url.href);\n if (sourcedError instanceof RegistrationLookupError) throw sourcedError;\n throw new RegistrationLookupError(\n `Request to ${url.hostname} failed: ${errorMessage(sourcedError)}`,\n \"network\",\n url.href,\n );\n } finally {\n clearTimeout(timeout);\n await dispatcher.close();\n }\n }\n\n throw new RegistrationLookupError(\"RDAP request failed\", \"network\");\n}\n\nasync function getBootstrap(url: string): Promise<BootstrapData> {\n const cached = bootstrapCache.get(url);\n if (cached && cached.expiresAt > Date.now()) return cached.data;\n\n const response = await fetchJson(url, MAX_BOOTSTRAP_BYTES);\n const services = response.data.services;\n if (!Array.isArray(services)) {\n throw new RegistrationLookupError(\n \"IANA RDAP bootstrap response has no services array\",\n \"invalid-response\",\n );\n }\n const data = { services };\n bootstrapCache.set(url, { data, expiresAt: Date.now() + BOOTSTRAP_TTL_MS });\n return data;\n}\n\nfunction bootstrapServices(\n data: BootstrapData,\n): { entries: string[]; urls: string[] }[] {\n const services: { entries: string[]; urls: string[] }[] = [];\n for (const service of data.services) {\n if (!Array.isArray(service) || service.length !== 2) continue;\n const entries = stringArray(service[0]).map((entry) => entry.toLowerCase());\n const urls = stringArray(service[1]).filter((url) =>\n url.startsWith(\"https://\"),\n );\n if (entries.length > 0 && urls.length > 0) services.push({ entries, urls });\n }\n return services;\n}\n\nfunction domainServiceUrls(data: BootstrapData, domain: string): string[] {\n let longestMatch = -1;\n let urls: string[] = [];\n for (const service of bootstrapServices(data)) {\n for (const entry of service.entries) {\n if (domain !== entry && !domain.endsWith(`.${entry}`)) continue;\n const labels = entry.split(\".\").length;\n if (labels > longestMatch) {\n longestMatch = labels;\n urls = [...service.urls];\n } else if (labels === longestMatch) {\n urls.push(...service.urls);\n }\n }\n }\n return [...new Set(urls)];\n}\n\nfunction ipServiceUrls(data: BootstrapData, ip: string): string[] {\n const family = net.isIP(ip);\n const type = family === 4 ? \"ipv4\" : \"ipv6\";\n let longestPrefix = -1;\n let urls: string[] = [];\n\n for (const service of bootstrapServices(data)) {\n for (const entry of service.entries) {\n const [network, rawPrefix] = entry.split(\"/\");\n const prefix = Number(rawPrefix);\n if (!network || !Number.isInteger(prefix) || net.isIP(network) !== family)\n continue;\n try {\n const block = new net.BlockList();\n block.addSubnet(network, prefix, type);\n if (!block.check(ip, type)) continue;\n } catch {\n continue;\n }\n if (prefix > longestPrefix) {\n longestPrefix = prefix;\n urls = [...service.urls];\n } else if (prefix === longestPrefix) {\n urls.push(...service.urls);\n }\n }\n }\n return [...new Set(urls)];\n}\n\nasync function queryFirstRdapService(\n baseUrls: string[],\n path: string,\n): Promise<RdapResponse> {\n let lastError: unknown;\n for (const baseUrl of baseUrls) {\n try {\n const base = validateHttpsUrl(baseUrl);\n if (!base.pathname.endsWith(\"/\")) base.pathname += \"/\";\n const queryUrl = new URL(path, base);\n return await fetchJson(queryUrl.href, MAX_RDAP_BYTES);\n } catch (error) {\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"not-found\"\n ) {\n throw error;\n }\n lastError = error;\n }\n }\n throw (\n lastError ??\n new RegistrationLookupError(\"No usable RDAP service\", \"unsupported\")\n );\n}\n\nfunction relatedRdapUrl(data: Record<string, unknown>): string | undefined {\n if (!Array.isArray(data.links)) return undefined;\n for (const value of data.links) {\n if (!isRecord(value) || value.rel !== \"related\") continue;\n const href = stringValue(value.href);\n const type = stringValue(value.type);\n if (href && type?.toLowerCase().includes(\"application/rdap+json\"))\n return href;\n }\n return undefined;\n}\n\nfunction eventLines(data: Record<string, unknown>): string[] {\n if (!Array.isArray(data.events)) return [];\n const labels: Record<string, string> = {\n registration: \"Registered\",\n expiration: \"Expires\",\n \"last changed\": \"Updated\",\n \"last update of RDAP database\": \"RDAP database updated\",\n };\n const lines: string[] = [];\n for (const event of data.events) {\n if (!isRecord(event)) continue;\n const action = stringValue(event.eventAction);\n const date = stringValue(event.eventDate);\n if (action && date) lines.push(`${labels[action] ?? action}: ${date}`);\n }\n return lines;\n}\n\nfunction vcardFields(entity: Record<string, unknown>): Map<string, string[]> {\n const fields = new Map<string, string[]>();\n if (!Array.isArray(entity.vcardArray) || !Array.isArray(entity.vcardArray[1]))\n return fields;\n for (const property of entity.vcardArray[1]) {\n if (!Array.isArray(property) || property.length < 4) continue;\n const name = stringValue(property[0])?.toLowerCase();\n const value = stringValue(property[3]);\n if (!name || !value) continue;\n fields.set(name, [...(fields.get(name) ?? []), value]);\n }\n return fields;\n}\n\nfunction entityLines(data: Record<string, unknown>): string[] {\n if (!Array.isArray(data.entities)) return [];\n const lines: string[] = [];\n const visit = (entity: unknown): void => {\n if (!isRecord(entity)) return;\n const roles = stringArray(entity.roles);\n const fields = vcardFields(entity);\n const name = fields.get(\"fn\")?.[0] ?? fields.get(\"org\")?.[0];\n const handle = stringValue(entity.handle);\n const identity = name ?? handle;\n if (identity) {\n const publicIds = Array.isArray(entity.publicIds)\n ? entity.publicIds\n .map((value) => {\n if (!isRecord(value)) return undefined;\n const type = stringValue(value.type);\n const identifier = stringValue(value.identifier);\n return type && identifier ? `${type} ${identifier}` : undefined;\n })\n .filter((value): value is string => value !== undefined)\n : [];\n const details = [\n ...publicIds,\n ...(fields.get(\"email\") ?? []).map((value) => `email ${value}`),\n ...(fields.get(\"tel\") ?? []).map((value) => `telephone ${value}`),\n ];\n lines.push(\n `Entity${roles.length > 0 ? ` (${roles.join(\", \")})` : \"\"}: ${identity}${details.length > 0 ? `; ${details.join(\"; \")}` : \"\"}`,\n );\n }\n if (Array.isArray(entity.entities)) entity.entities.forEach(visit);\n };\n data.entities.forEach(visit);\n return [...new Set(lines)];\n}\n\nfunction noticeTitles(data: Record<string, unknown>): string[] {\n if (!Array.isArray(data.notices)) return [];\n return data.notices\n .map((notice) => (isRecord(notice) ? stringValue(notice.title) : undefined))\n .filter((title): title is string => title !== undefined);\n}\n\nfunction formatDomainRdap(\n responses: RdapResponse[],\n requestedDomain: string,\n warnings: string[],\n): string {\n const data: Record<string, unknown> = Object.assign(\n {},\n ...responses\n .slice()\n .reverse()\n .map((response) => response.data),\n );\n data.entities = responses.flatMap((response) =>\n Array.isArray(response.data.entities) ? response.data.entities : [],\n );\n data.notices = responses.flatMap((response) =>\n Array.isArray(response.data.notices) ? response.data.notices : [],\n );\n data.events = responses.flatMap((response) =>\n Array.isArray(response.data.events) ? response.data.events : [],\n );\n const lines = [\n \"Protocol: RDAP\",\n ...responses.map((response) => `Source: ${response.source}`),\n `Domain: ${stringValue(data.unicodeName) ?? stringValue(data.ldhName) ?? requestedDomain}`,\n ];\n const handle = stringValue(data.handle);\n if (handle) lines.push(`Registry ID: ${handle}`);\n lines.push(...eventLines(data));\n const statuses = stringArray(data.status);\n if (statuses.length > 0) lines.push(`Status: ${statuses.join(\", \")}`);\n\n if (Array.isArray(data.nameservers)) {\n const nameservers = data.nameservers\n .map((value) =>\n isRecord(value)\n ? (stringValue(value.unicodeName) ?? stringValue(value.ldhName))\n : undefined,\n )\n .filter((value): value is string => value !== undefined);\n if (nameservers.length > 0)\n lines.push(`Nameservers: ${nameservers.join(\", \")}`);\n }\n if (isRecord(data.secureDNS)) {\n const signed = data.secureDNS.delegationSigned;\n if (typeof signed === \"boolean\")\n lines.push(`DNSSEC: ${signed ? \"signed\" : \"unsigned\"}`);\n }\n lines.push(...entityLines(data));\n const notices = noticeTitles(data);\n if (notices.length > 0) lines.push(`Notices: ${notices.join(\"; \")}`);\n lines.push(...warnings.map((warning) => `Warning: ${warning}`));\n return lines.join(\"\\n\");\n}\n\nfunction formatIpRdap(response: RdapResponse, ip: string): string {\n const { data } = response;\n const lines = [\"Protocol: RDAP\", `Source: ${response.source}`, `IP: ${ip}`];\n for (const [label, key] of [\n [\"Network\", \"name\"],\n [\"Handle\", \"handle\"],\n [\"Start address\", \"startAddress\"],\n [\"End address\", \"endAddress\"],\n [\"IP version\", \"ipVersion\"],\n [\"Type\", \"type\"],\n [\"Country\", \"country\"],\n [\"Parent handle\", \"parentHandle\"],\n ] as const) {\n const value = stringValue(data[key]);\n if (value) lines.push(`${label}: ${value}`);\n }\n const statuses = stringArray(data.status);\n if (statuses.length > 0) lines.push(`Status: ${statuses.join(\", \")}`);\n lines.push(...eventLines(data), ...entityLines(data));\n const notices = noticeTitles(data);\n if (notices.length > 0) lines.push(`Notices: ${notices.join(\"; \")}`);\n return lines.join(\"\\n\");\n}\n\nexport function normaliseRegistrationDomain(domain: string): string {\n const candidate = domain.trim().replace(/\\.$/, \"\");\n const containsControlCharacter = [...candidate].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || codePoint === 0x7f;\n });\n if (!candidate || containsControlCharacter) {\n throw new Error(\"Invalid domain\");\n }\n const ascii = domainToASCII(candidate).toLowerCase();\n if (!ascii || ascii.length > 253) throw new Error(\"Invalid domain\");\n const labels = ascii.split(\".\");\n if (\n labels.some(\n (label) =>\n label.length === 0 ||\n label.length > 63 ||\n !/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label),\n )\n ) {\n throw new Error(\"Invalid domain\");\n }\n return ascii;\n}\n\nfunction ianaWhoisDiscoveryQuery(domain: string): string {\n // IANA registry referrals are keyed by the DNS root TLD, not an effective\n // public suffix. For example, both example.co.uk and example.me.uk use uk.\n return domain.split(\".\").at(-1) ?? domain;\n}\n\nfunction parseWhoisEndpoint(\n value: string,\n allowWebScheme = false,\n): WhoisEndpoint {\n const candidate = value.includes(\"://\") ? value : `whois://${value}`;\n let url: URL;\n try {\n url = new URL(candidate);\n } catch {\n throw new RegistrationLookupError(\n `Invalid WHOIS referral: ${value}`,\n \"invalid-response\",\n undefined,\n \"REFERRAL_REJECTED\",\n );\n }\n const webScheme = url.protocol === \"http:\" || url.protocol === \"https:\";\n const port = webScheme ? 43 : url.port ? Number(url.port) : 43;\n if (\n (url.protocol !== \"whois:\" && !(allowWebScheme && webScheme)) ||\n !url.hostname ||\n url.username ||\n url.password ||\n (url.pathname && url.pathname !== \"/\") ||\n url.search ||\n url.hash ||\n (!webScheme && url.port && url.port !== \"43\")\n ) {\n throw new RegistrationLookupError(\n `Refusing unsafe WHOIS referral: ${value}`,\n \"security\",\n undefined,\n \"REFERRAL_REJECTED\",\n );\n }\n return { host: url.hostname.replace(/^\\[|\\]$/g, \"\").toLowerCase(), port };\n}\n\nfunction whoisReferral(response: string): WhoisEndpoint | undefined {\n for (const [pattern, allowWebScheme] of [\n [/^refer:[ \\t]*(\\S+)/im, false],\n [/^whois:[ \\t]*(\\S+)/im, false],\n [/^Registrar WHOIS Server:[ \\t]*(\\S+)/im, true],\n [/^ReferralServer:[ \\t]*(\\S+)/im, false],\n ] as const) {\n const match = response.match(pattern);\n if (match?.[1]) return parseWhoisEndpoint(match[1].trim(), allowWebScheme);\n }\n return undefined;\n}\n\nfunction inspectWhoisResponse(response: string): {\n notFound: boolean;\n warnings: RegistrationWarning[];\n} {\n const hasRegistrationData =\n /^(?:Domain Name|Domain|domain|NetRange|CIDR|inetnum|network|route):[ \\t]*\\S+/imu.test(\n response,\n );\n if (\n !hasRegistrationData &&\n /(?:rate limit|query limit|quota exceeded|too many quer(?:y|ies)|maximum number of quer(?:y|ies)|try again later)/iu.test(\n response,\n )\n ) {\n throw new RegistrationLookupError(\n \"WHOIS service rate limited the request\",\n \"rate-limited\",\n undefined,\n \"WHOIS_RATE_LIMITED\",\n );\n }\n if (\n !hasRegistrationData &&\n /(?:whois service (?:has been |is )?(?:retired|discontinued)|whois is no longer available)/iu.test(\n response,\n )\n ) {\n throw new RegistrationLookupError(\n \"WHOIS service reports that it has been retired\",\n \"unsupported\",\n undefined,\n \"WHOIS_SERVICE_RETIRED\",\n );\n }\n if (\n !hasRegistrationData &&\n /(?:web[- ]based whois|web whois|visit .{0,80}whois)/isu.test(response)\n ) {\n throw new RegistrationLookupError(\n \"Registry directs queries to a web-based WHOIS service\",\n \"unsupported\",\n undefined,\n \"WHOIS_WEB_ONLY\",\n );\n }\n if (\n !hasRegistrationData &&\n /(?:invalid query|malformed query|unsupported query|syntax error|^usage:)/imu.test(\n response,\n )\n ) {\n throw new RegistrationLookupError(\n \"WHOIS service rejected the query syntax\",\n \"invalid-response\",\n undefined,\n \"WHOIS_UNSUPPORTED_RESPONSE\",\n );\n }\n\n const warnings: RegistrationWarning[] = [];\n if (response.includes(\"\\uFFFD\")) {\n warnings.push({\n reason: \"WHOIS_INVALID_ENCODING\",\n detail: \"WHOIS response contains bytes that are not valid UTF-8\",\n });\n }\n return {\n notFound:\n !hasRegistrationData &&\n /(?:no match for|not found|no entries found|no object found)/iu.test(\n response,\n ),\n warnings,\n };\n}\n\nfunction whoisQueryValue(host: string, query: string): string {\n if (host === \"whois.jprs.jp\" && !query.endsWith(\"/e\")) return `${query}/e`;\n if (host === \"whois.denic.de\") return `-T dn,ace ${query}`;\n return query;\n}\n\nasync function whoisQuery(\n endpoint: WhoisEndpoint,\n query: string,\n): Promise<string> {\n const addresses = await resolvePublicHostname(endpoint.host, true);\n return await new Promise((resolve, reject) => {\n let settled = false;\n let total = 0;\n const chunks: Buffer[] = [];\n const timeoutError = (): RegistrationLookupError =>\n new RegistrationLookupError(\n \"WHOIS query timed out\",\n \"network\",\n undefined,\n \"WHOIS_TIMEOUT\",\n );\n const socket = net.createConnection(\n { ...endpoint, lookup: pinnedLookup(addresses) },\n () => {\n socket.write(`${whoisQueryValue(endpoint.host, query)}\\r\\n`);\n },\n );\n const deadline = setTimeout(\n () => socket.destroy(timeoutError()),\n REQUEST_TIMEOUT_MS,\n );\n const finish = (error?: Error): void => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n if (error) reject(error);\n else resolve(Buffer.concat(chunks).toString(\"utf-8\"));\n };\n socket.on(\"data\", (chunk: Buffer) => {\n total += chunk.byteLength;\n if (total > MAX_WHOIS_BYTES) {\n socket.destroy(\n new RegistrationLookupError(\n `WHOIS response exceeds ${MAX_WHOIS_BYTES} bytes`,\n \"invalid-response\",\n undefined,\n \"RESPONSE_TOO_LARGE\",\n ),\n );\n return;\n }\n chunks.push(chunk);\n });\n socket.on(\"end\", () => finish());\n socket.on(\"error\", (error) => finish(error));\n socket.setTimeout(REQUEST_TIMEOUT_MS, () => {\n socket.destroy(timeoutError());\n });\n });\n}\n\nasync function legacyWhois(\n query: string,\n discoveryQuery = query,\n): Promise<string> {\n let endpoint = { host: \"whois.iana.org\", port: 43 };\n const visited = new Set<string>();\n let response = \"\";\n const warnings: RegistrationWarning[] = [];\n\n for (let index = 0; index < MAX_WHOIS_QUERIES; index += 1) {\n const key = `${endpoint.host}:${endpoint.port}`;\n if (visited.has(key)) {\n throw new RegistrationLookupError(\n \"WHOIS referral loop detected\",\n \"invalid-response\",\n `whois://${endpoint.host}:43`,\n \"REFERRAL_LOOP\",\n );\n }\n visited.add(key);\n try {\n response = (\n await whoisQuery(endpoint, index === 0 ? discoveryQuery : query)\n ).trim();\n } catch (error) {\n throw new RegistrationLookupError(\n errorMessage(error),\n error instanceof RegistrationLookupError ? error.kind : \"network\",\n `whois://${endpoint.host}:43`,\n reasonForError(\"WHOIS\", error),\n );\n }\n\n let referral: WhoisEndpoint | undefined;\n try {\n referral = whoisReferral(response);\n } catch (error) {\n if (index === 0) throw error;\n warnings.push({\n reason: reasonForError(\"WHOIS\", error),\n detail: errorMessage(error),\n });\n break;\n }\n if (!referral) {\n if (index === 0) {\n throw new RegistrationLookupError(\n \"IANA does not advertise a WHOIS service for this query\",\n \"unsupported\",\n \"whois://whois.iana.org:43\",\n \"WHOIS_NOT_ADVERTISED\",\n );\n }\n break;\n }\n const referralKey = `${referral.host}:${referral.port}`;\n if (visited.has(referralKey)) {\n if (referralKey === key) break;\n throw new RegistrationLookupError(\n \"WHOIS referral loop detected\",\n \"invalid-response\",\n `whois://${endpoint.host}:43`,\n \"REFERRAL_LOOP\",\n );\n }\n if (index === MAX_WHOIS_QUERIES - 1) {\n warnings.push({\n reason: \"REFERRAL_LIMIT_REACHED\",\n detail: `WHOIS referral limit of ${MAX_WHOIS_QUERIES} queries reached`,\n });\n break;\n }\n try {\n await resolvePublicHostname(referral.host, true);\n } catch (error) {\n if (index === 0) throw error;\n warnings.push({\n reason: reasonForError(\"WHOIS\", error),\n detail: errorMessage(error),\n });\n break;\n }\n endpoint = referral;\n }\n\n if (!response)\n throw new RegistrationLookupError(\n \"No WHOIS data returned\",\n \"network\",\n `whois://${endpoint.host}:43`,\n \"WHOIS_EMPTY_RESPONSE\",\n );\n let inspection: ReturnType<typeof inspectWhoisResponse>;\n try {\n inspection = inspectWhoisResponse(response);\n } catch (error) {\n throw new RegistrationLookupError(\n errorMessage(error),\n error instanceof RegistrationLookupError\n ? error.kind\n : \"invalid-response\",\n `whois://${endpoint.host}:43`,\n reasonForError(\"WHOIS\", error),\n );\n }\n warnings.push(...inspection.warnings);\n return [\n \"Protocol: WHOIS\",\n `Source: whois://${endpoint.host}:43`,\n ...(inspection.notFound\n ? [\"Status: not registered or not found\", \"Reason: WHOIS_NOT_FOUND\"]\n : []),\n ...warnings.map((warning) => `Warning: ${warningText(warning)}`),\n \"\",\n response,\n ].join(\"\\n\");\n}\n\nfunction fallbackWarning(error: unknown): string {\n const source =\n error instanceof RegistrationLookupError && error.source\n ? ` at ${error.source}`\n : \"\";\n return `${reasonForError(\"RDAP\", error)}${source}: ${errorMessage(error)}; used WHOIS fallback`;\n}\n\nexport async function domainRegistrationLookupResult(\n domain: string,\n): Promise<RegistrationLookupResult> {\n const normalised = normaliseRegistrationDomain(domain);\n let rdapError: unknown;\n try {\n const bootstrap = await getBootstrap(RDAP_DNS_BOOTSTRAP);\n const urls = domainServiceUrls(bootstrap, normalised);\n if (urls.length > 0) {\n try {\n const registry = await queryFirstRdapService(\n urls,\n `domain/${encodeURIComponent(normalised)}`,\n );\n const responses = [registry];\n const warnings: string[] = [];\n const related = relatedRdapUrl(registry.data);\n if (related) {\n try {\n responses.push(await fetchJson(related, MAX_RDAP_BYTES));\n } catch (error) {\n warnings.push(\n `${reasonForError(\"RDAP\", error)}: registrar RDAP lookup failed: ${errorMessage(error)}`,\n );\n }\n }\n return {\n text: formatDomainRdap(responses, normalised, warnings),\n failed: false,\n };\n } catch (error) {\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"not-found\"\n ) {\n return {\n text: `Protocol: RDAP\\nSource: ${error.source ?? \"authoritative RDAP service\"}\\nDomain: ${normalised}\\nStatus: not registered or not found\\nReason: RDAP_NOT_FOUND`,\n failed: false,\n };\n }\n rdapError = error;\n }\n } else {\n rdapError = new RegistrationLookupError(\n \"IANA has no RDAP bootstrap service for this TLD\",\n \"unsupported\",\n );\n }\n } catch (error) {\n rdapError = error;\n }\n\n try {\n const result = await legacyWhois(\n normalised,\n ianaWhoisDiscoveryQuery(normalised),\n );\n return {\n text: rdapError\n ? `${result}\\n\\nWarning: ${fallbackWarning(rdapError)}`\n : result,\n failed: false,\n };\n } catch (whoisError) {\n if (rdapError) {\n return {\n text: formatLookupFailure(\"Domain\", normalised, rdapError, whoisError),\n failed: true,\n };\n }\n return {\n text: formatLookupFailure(\n \"Domain\",\n normalised,\n new RegistrationLookupError(\n \"RDAP was not attempted\",\n \"unsupported\",\n undefined,\n \"RDAP_NOT_AVAILABLE\",\n ),\n whoisError,\n ),\n failed: true,\n };\n }\n}\n\nexport async function domainRegistrationLookup(\n domain: string,\n): Promise<string> {\n return (await domainRegistrationLookupResult(domain)).text;\n}\n\nexport async function ipRegistrationLookupResult(\n ip: string,\n): Promise<RegistrationLookupResult> {\n const family = net.isIP(ip);\n if (family === 0) throw new Error(\"Invalid IP address\");\n let rdapError: unknown;\n try {\n const bootstrap = await getBootstrap(\n family === 4 ? RDAP_IPV4_BOOTSTRAP : RDAP_IPV6_BOOTSTRAP,\n );\n const urls = ipServiceUrls(bootstrap, ip);\n if (urls.length > 0) {\n try {\n const response = await queryFirstRdapService(\n urls,\n `ip/${encodeURIComponent(ip)}`,\n );\n return { text: formatIpRdap(response, ip), failed: false };\n } catch (error) {\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"not-found\"\n ) {\n return {\n text: `Protocol: RDAP\\nSource: ${error.source ?? \"authoritative RDAP service\"}\\nIP: ${ip}\\nStatus: registration data not found\\nReason: RDAP_NOT_FOUND`,\n failed: false,\n };\n }\n rdapError = error;\n }\n } else {\n rdapError = new RegistrationLookupError(\n \"IANA has no RDAP bootstrap service for this address\",\n \"unsupported\",\n );\n }\n } catch (error) {\n rdapError = error;\n }\n\n try {\n const result = await legacyWhois(ip);\n return {\n text: rdapError\n ? `${result}\\n\\nWarning: ${fallbackWarning(rdapError)}`\n : result,\n failed: false,\n };\n } catch (whoisError) {\n if (rdapError) {\n return {\n text: formatLookupFailure(\"IP\", ip, rdapError, whoisError),\n failed: true,\n };\n }\n return {\n text: formatLookupFailure(\n \"IP\",\n ip,\n new RegistrationLookupError(\n \"RDAP was not attempted\",\n \"unsupported\",\n undefined,\n \"RDAP_NOT_AVAILABLE\",\n ),\n whoisError,\n ),\n failed: true,\n };\n }\n}\n\nexport async function ipRegistrationLookup(ip: string): Promise<string> {\n return (await ipRegistrationLookupResult(ip)).text;\n}\n","import {\n createServer,\n type IncomingMessage,\n type Server,\n type ServerResponse,\n} from \"node:http\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { createMcpServer } from \"./server.js\";\n\nexport interface HttpServerOptions {\n host: string;\n port: number;\n allowedHosts?: string[];\n}\n\nconst loopbackBindAddresses = new Set([\"127.0.0.1\", \"localhost\", \"::1\"]);\nconst loopbackHostnames = new Set([\"127.0.0.1\", \"localhost\", \"[::1]\"]);\nconst maxRequestBodyBytes = 1024 * 1024;\n\nclass HttpRequestError extends Error {\n constructor(\n message: string,\n readonly statusCode: number,\n readonly rpcCode: number,\n ) {\n super(message);\n }\n}\n\nfunction sendJson(\n response: ServerResponse,\n statusCode: number,\n body: unknown,\n): void {\n response.writeHead(statusCode, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"cache-control\": \"no-store\",\n });\n response.end(JSON.stringify(body));\n}\n\nfunction requestHostname(request: IncomingMessage): string | undefined {\n const host = request.headers.host;\n if (host === undefined) return undefined;\n\n try {\n return new URL(`http://${host}`).hostname;\n } catch {\n return undefined;\n }\n}\n\nfunction allowedHostnames(options: HttpServerOptions): Set<string> | undefined {\n if (options.allowedHosts !== undefined && options.allowedHosts.length > 0) {\n return new Set(options.allowedHosts);\n }\n if (loopbackBindAddresses.has(options.host)) {\n return loopbackHostnames;\n }\n return undefined;\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n const contentLength = request.headers[\"content-length\"];\n if (contentLength !== undefined) {\n const length = Number(contentLength);\n if (!Number.isSafeInteger(length) || length < 0) {\n throw new HttpRequestError(\"Invalid Content-Length\", 400, -32600);\n }\n if (length > maxRequestBodyBytes) {\n throw new HttpRequestError(\"Request body too large\", 413, -32600);\n }\n }\n\n const chunks: Buffer[] = [];\n let size = 0;\n await new Promise<void>((resolve, reject) => {\n const cleanup = () => {\n request.off(\"data\", onData);\n request.off(\"end\", onEnd);\n request.off(\"error\", onError);\n request.off(\"aborted\", onAborted);\n };\n const fail = (error: Error) => {\n request.pause();\n cleanup();\n reject(error);\n };\n const onData = (chunk: Buffer | string) => {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n size += buffer.byteLength;\n if (size > maxRequestBodyBytes) {\n fail(new HttpRequestError(\"Request body too large\", 413, -32600));\n return;\n }\n chunks.push(buffer);\n };\n const onEnd = () => {\n cleanup();\n resolve();\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n const onAborted = () => {\n fail(new HttpRequestError(\"Request body aborted\", 400, -32600));\n };\n\n request.on(\"data\", onData);\n request.once(\"end\", onEnd);\n request.once(\"error\", onError);\n request.once(\"aborted\", onAborted);\n });\n\n try {\n return JSON.parse(Buffer.concat(chunks, size).toString(\"utf8\")) as unknown;\n } catch {\n throw new HttpRequestError(\"Invalid JSON request body\", 400, -32700);\n }\n}\n\nasync function handleMcpRequest(\n request: IncomingMessage,\n response: ServerResponse,\n): Promise<void> {\n let parsedBody: unknown;\n try {\n parsedBody = await readJsonBody(request);\n } catch (error) {\n if (error instanceof HttpRequestError) {\n if (error.statusCode === 413) response.setHeader(\"connection\", \"close\");\n sendJson(response, error.statusCode, {\n jsonrpc: \"2.0\",\n error: { code: error.rpcCode, message: error.message },\n id: null,\n });\n return;\n }\n console.error(\"Failed to read HTTP MCP request:\", error);\n sendJson(response, 400, {\n jsonrpc: \"2.0\",\n error: { code: -32600, message: \"Failed to read request body\" },\n id: null,\n });\n return;\n }\n\n const server = createMcpServer();\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: true,\n });\n\n try {\n await server.connect(transport);\n await transport.handleRequest(request, response, parsedBody);\n } catch (error) {\n console.error(\"HTTP MCP request failed:\", error);\n if (!response.headersSent) {\n sendJson(response, 500, {\n jsonrpc: \"2.0\",\n error: { code: -32603, message: \"Internal server error\" },\n id: null,\n });\n } else if (!response.writableEnded) {\n response.end();\n }\n } finally {\n await Promise.allSettled([transport.close(), server.close()]);\n }\n}\n\nexport async function startHttpServer(\n options: HttpServerOptions,\n): Promise<Server> {\n const acceptedHosts = allowedHostnames(options);\n const httpServer = createServer((request, response) => {\n const pathname = new URL(request.url ?? \"/\", \"http://localhost\").pathname;\n\n if (pathname === \"/health\") {\n if (request.method !== \"GET\") {\n sendJson(response, 405, { error: \"Method not allowed\" });\n return;\n }\n sendJson(response, 200, { status: \"ok\" });\n return;\n }\n\n if (pathname !== \"/mcp\") {\n sendJson(response, 404, { error: \"Not found\" });\n return;\n }\n\n if (request.method !== \"POST\") {\n response.setHeader(\"allow\", \"POST\");\n sendJson(response, 405, {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Method not allowed\" },\n id: null,\n });\n return;\n }\n\n if (acceptedHosts !== undefined) {\n const hostname = requestHostname(request);\n if (hostname === undefined || !acceptedHosts.has(hostname)) {\n sendJson(response, 403, {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Invalid Host header\" },\n id: null,\n });\n return;\n }\n }\n\n void handleMcpRequest(request, response);\n });\n\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n httpServer.off(\"listening\", onListening);\n reject(error);\n };\n const onListening = () => {\n httpServer.off(\"error\", onError);\n resolve();\n };\n httpServer.once(\"error\", onError);\n httpServer.once(\"listening\", onListening);\n httpServer.listen(options.port, options.host);\n });\n\n return httpServer;\n}\n\nexport async function stopHttpServer(server: Server): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport {\n dnsLookup,\n reverseDns,\n resolveAll,\n checkNameservers,\n whoisLookupResult,\n ipWhoisResult,\n} from \"./dns.js\";\n\nconst recordTypeSchema = z\n .enum([\"A\", \"AAAA\", \"MX\", \"TXT\", \"CNAME\", \"NS\", \"SOA\", \"SRV\", \"CAA\", \"PTR\"])\n .default(\"A\");\n\nconst readOnlyAnnotations = {\n readOnlyHint: true,\n destructiveHint: false,\n};\n\nexport function createMcpServer(): McpServer {\n const server = new McpServer(\n {\n name: \"mcp-dns-tools\",\n version: packageJson.version,\n },\n {\n instructions:\n \"When the user names one DNS record type, call dns_lookup and pass that type, except for NS or nameserver-only requests, which must use check_nameservers. For CAA requests, call dns_lookup with type CAA. Use resolve_all only when the user asks for all records, multiple record types, a DNS overview, or a general investigation. Never use resolve_all for one named record type. Use whois for domain registration, registrar, registration status, or registration-date questions. Use ip_whois for IP allocation and network ownership questions.\",\n },\n );\n\n server.registerTool(\n \"dns_lookup\",\n {\n title: \"DNS record lookup\",\n description:\n \"Use this when the user requests one specific DNS record type, except for NS or nameserver requests, which must use check_nameservers. For CAA or certificate authority issuance questions, call this tool with type CAA. Supports A, AAAA, MX, TXT, CNAME, SOA, SRV, CAA, PTR, and NS for backwards compatibility. Do not use resolve_all when the user names one record type.\",\n inputSchema: {\n domain: z\n .string()\n .describe(\"Domain name to look up (e.g. example.com)\"),\n type: recordTypeSchema.describe(\n \"Specific record type to return: A, AAAA, MX, TXT, CNAME, NS, SOA, SRV, CAA, or PTR. Use CAA for certificate authority issuance policy.\",\n ),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain, type }) => {\n const result = await dnsLookup(domain, type);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"reverse_dns\",\n {\n title: \"Reverse DNS lookup\",\n description: \"Perform a reverse DNS (PTR) lookup on an IP address.\",\n inputSchema: {\n ip: z.string().describe(\"IP address (e.g. 8.8.8.8)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ ip }) => {\n const result = await reverseDns(ip);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"resolve_all\",\n {\n title: \"DNS overview\",\n description:\n \"Use this only when the user requests all common DNS records, multiple record types, a DNS overview, or a general domain investigation. Returns A, AAAA, MX, TXT, CAA, NS, and CNAME. Do not use this for one named record type.\",\n inputSchema: {\n domain: z\n .string()\n .describe(\"Domain name to resolve (e.g. example.com)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain }) => {\n const result = await resolveAll(domain);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"check_nameservers\",\n {\n title: \"Nameserver lookup\",\n description:\n \"Use this whenever the user requests NS records, nameservers, authoritative nameservers, or domain delegation nameservers.\",\n inputSchema: {\n domain: z.string().describe(\"Domain name (e.g. example.com)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain }) => {\n const result = await checkNameservers(domain);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"whois\",\n {\n title: \"Domain registration lookup\",\n description:\n \"Query authoritative domain registration data, including registrar, status, dates, nameservers, and DNSSEC. Uses IANA RDAP discovery over HTTPS and follows a registrar RDAP link when available, with bounded legacy WHOIS fallback for TLDs without working RDAP. Supports Unicode domain names. Failures identify each attempted protocol, endpoint, stable reason code, detail, and suggested next action.\",\n inputSchema: {\n domain: z\n .string()\n .describe(\"Domain name for registration lookup (e.g. example.com)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain }) => {\n const result = await whoisLookupResult(domain);\n return {\n content: [{ type: \"text\" as const, text: result.text }],\n isError: result.failed,\n };\n },\n );\n\n server.registerTool(\n \"ip_whois\",\n {\n title: \"IP registration lookup\",\n description:\n \"Query authoritative IPv4 or IPv6 allocation and network ownership data. Uses IANA RDAP bootstrap discovery over HTTPS, with bounded legacy WHOIS fallback to the appropriate Regional Internet Registry. Failures identify each attempted protocol, endpoint, stable reason code, detail, and suggested next action.\",\n inputSchema: {\n ip: z\n .string()\n .describe(\"IP address (e.g. 8.8.8.8 or 2001:4860:4860::8888)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ ip }) => {\n const result = await ipWhoisResult(ip);\n return {\n content: [{ type: \"text\" as const, text: result.text }],\n isError: result.failed,\n };\n },\n );\n\n return server;\n}\n","{\n \"name\": \"@paulgit/mcp-dns-tools\",\n \"mcpName\": \"it.paulg/dns-tools\",\n \"version\": \"2.3.0\",\n \"description\": \"MCP server for DNS lookups, including CAA checks, reverse DNS, and RDAP-first domain or IP registration data with WHOIS fallback; zero auth, zero config\",\n \"type\": \"module\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"engines\": {\n \"node\": \">=24\"\n },\n \"bin\": {\n \"mcp-dns-tools\": \"dist/index.js\"\n },\n \"files\": [\n \"dist\",\n \"skills\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"lint\": \"eslint . && prettier --check .\",\n \"format\": \"prettier --write .\",\n \"audit:deps\": \"npm audit --omit=dev --audit-level=high\",\n \"prepack\": \"npm run build\",\n \"prepublishOnly\": \"npm run lint && npm run typecheck && npm test\",\n \"prepare\": \"husky\"\n },\n \"keywords\": [\n \"mcp\",\n \"mcp-server\",\n \"model-context-protocol\",\n \"dns\",\n \"whois\",\n \"domain\",\n \"network\",\n \"lookup\",\n \"nameserver\",\n \"caa\",\n \"tls\",\n \"certificate-authority\",\n \"ai\",\n \"llm\",\n \"claude\",\n \"cursor\"\n ],\n \"author\": \"Paul Git (https://code.paulg.it/paulgit)\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://code.paulg.it/paulgit/mcp-dns-tools.git\"\n },\n \"bugs\": {\n \"url\": \"https://code.paulg.it/paulgit/mcp-dns-tools/issues\"\n },\n \"homepage\": \"https://code.paulg.it/paulgit/mcp-dns-tools#readme\",\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.26.0\",\n \"undici\": \"^8.10.0\",\n \"zod\": \"^3.25.0\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.0.0\",\n \"@types/node\": \"^22.0.0\",\n \"eslint\": \"^9.0.0\",\n \"eslint-config-prettier\": \"^10.0.0\",\n \"husky\": \"^9.0.0\",\n \"lint-staged\": \"^15.0.0\",\n \"prettier\": \"^3.0.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.7.0\",\n \"typescript-eslint\": \"^8.0.0\",\n \"vitest\": \"^3.2.0\"\n },\n \"lint-staged\": {\n \"*.{ts,tsx,js}\": [\n \"eslint --fix\",\n \"prettier --write\"\n ],\n \"*.{json,md,yml,yaml}\": [\n \"prettier --write\"\n ]\n },\n \"allowScripts\": {\n \"esbuild@0.27.2\": true,\n \"fsevents@2.3.3\": true\n }\n}\n"],"mappings":";;;AAAA,SAAS,4BAA4B;;;ACArC,SAAS,iBAAiB;AAanB,SAAS,aACd,MACA,MAAyB,QAAQ,KACrB;AACZ,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B;AAAA,IACA,SAAS;AAAA,MACP,WAAW;AAAA,QACT,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,MACR;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,MACR;AAAA,MACA,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AAED,MAAI,OAAO,cAAc,WAAW,OAAO,cAAc,QAAQ;AAC/D,UAAM,IAAI;AAAA,MACR,0BAA0B,OAAO,SAAS;AAAA,IAC5C;AAAA,EACF;AAEA,MAAI,OAAO,cAAc,SAAS;AAChC,QACE,OAAO,SAAS,UAChB,OAAO,SAAS,UAChB,OAAO,cAAc,MAAM,QAC3B;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,WAAW,QAAQ;AAAA,EAC9B;AAEA,QAAM,OAAO,OAAO,QAAQ,IAAI,QAAQ;AACxC,QAAM,YAAY,OAAO,QAAQ,IAAI,QAAQ;AAC7C,QAAM,OAAO,OAAO,SAAS;AAC7B,MAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,OAAQ;AACxD,UAAM,IAAI,MAAM,sBAAsB,SAAS,qBAAqB;AAAA,EACtE;AAEA,SAAO;AAAA,IACL,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,cAAc,OAAO,cAAc,KAAK,CAAC;AAAA,EAC3C;AACF;;;ACtEA,OAAOA,UAAS;AAChB,SAAS,kBAAkB;AAE3B,OAAOC,UAAS;;;ACHhB,OAAO,SAAS;AAChB,OAAO,SAAS;AAChB,SAAS,qBAAqB;AAC9B,SAAS,OAAO,SAAS,mBAAmB;AAE5C,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB,KAAK,KAAK,KAAK;AACxC,IAAM,qBAAqB;AAC3B,IAAM,gBAAgB;AACtB,IAAM,iBAAiB,OAAO;AAC9B,IAAM,sBAAsB,IAAI,OAAO;AACvC,IAAM,kBAAkB,OAAO;AAC/B,IAAM,oBAAoB;AA+D1B,IAAM,0BAAN,cAAsC,MAAM;AAAA,EAC1C,YACE,SACS,MAOA,QACA,QACT;AACA,UAAM,OAAO;AAVJ;AAOA;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AACF;AAEA,SAAS,8BACP,OACA,QACS;AACT,MAAI,EAAE,iBAAiB,4BAA4B,MAAM,WAAW;AAClE,WAAO;AACT,SAAO,IAAI;AAAA,IACT,MAAM;AAAA,IACN,MAAM;AAAA,IACN;AAAA,IACA,MAAM;AAAA,EACR;AACF;AAEA,IAAM,iBAAiB,oBAAI,IAAiC;AAE5D,IAAM,mBAAmB,IAAI,IAAI,UAAU;AAC3C,IAAM,+BAA+B,IAAI,IAAI,UAAU;AAEvD,6BAA6B,UAAU,cAAc,IAAI,MAAM;AAC/D,WAAW,CAAC,SAAS,MAAM,KAAK;AAAA,EAC9B,CAAC,WAAW,CAAC;AAAA,EACb,CAAC,YAAY,CAAC;AAAA,EACd,CAAC,cAAc,EAAE;AAAA,EACjB,CAAC,aAAa,CAAC;AAAA,EACf,CAAC,eAAe,EAAE;AAAA,EAClB,CAAC,cAAc,EAAE;AAAA,EACjB,CAAC,aAAa,EAAE;AAAA,EAChB,CAAC,aAAa,EAAE;AAAA,EAChB,CAAC,eAAe,EAAE;AAAA,EAClB,CAAC,cAAc,EAAE;AAAA,EACjB,CAAC,gBAAgB,EAAE;AAAA,EACnB,CAAC,eAAe,EAAE;AAAA,EAClB,CAAC,aAAa,CAAC;AAAA,EACf,CAAC,aAAa,CAAC;AACjB,GAAY;AACV,mBAAiB,UAAU,SAAS,QAAQ,MAAM;AACpD;AACA,WAAW,CAAC,SAAS,MAAM,KAAK;AAAA,EAC9B,CAAC,MAAM,GAAG;AAAA,EACV,CAAC,OAAO,GAAG;AAAA,EACX,CAAC,eAAe,EAAE;AAAA,EAClB,CAAC,SAAS,EAAE;AAAA,EACZ,CAAC,cAAc,EAAE;AAAA,EACjB,CAAC,UAAU,CAAC;AAAA,EACZ,CAAC,UAAU,EAAE;AAAA,EACb,CAAC,UAAU,EAAE;AAAA,EACb,CAAC,UAAU,CAAC;AACd,GAAY;AACV,mBAAiB,UAAU,SAAS,QAAQ,MAAM;AACpD;AAMA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,YAAY,OAAoC;AACvD,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAG,QAAO,MAAM,KAAK;AACjE,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAM,SAAS,MACZ,IAAI,CAAC,UAAU,YAAY,KAAK,CAAC,EACjC,OAAO,CAAC,UAA2B,UAAU,MAAS;AACzD,WAAO,OAAO,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI;AAAA,EACjD;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAA0B;AAC7C,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,SAAO,MAAM;AAAA,IACX,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS;AAAA,EAC1E;AACF;AAEA,SAAS,iBAAiB,SAA0B;AAClD,QAAM,SAAS,IAAI,KAAK,OAAO;AAC/B,MAAI,WAAW,EAAG,QAAO,iBAAiB,MAAM,SAAS,MAAM;AAC/D,MAAI,WAAW,EAAG,QAAO,iBAAiB,MAAM,SAAS,MAAM;AAC/D,SAAO;AACT;AAEA,eAAe,sBACb,UACA,6BAA6B,OACD;AAC5B,QAAM,aAAa,SAChB,QAAQ,YAAY,EAAE,EACtB,QAAQ,OAAO,EAAE,EACjB,YAAY;AACf,MACE,CAAC,cACD,eAAe,eACf,WAAW,SAAS,QAAQ,GAC5B;AACA,UAAM,IAAI;AAAA,MACR,4CAA4C,QAAQ;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,IAAI,KAAK,UAAU,MAAM,GAAG;AAC9B,QAAI,iBAAiB,UAAU,GAAG;AAChC,YAAM,IAAI;AAAA,QACR,+DAA+D,QAAQ;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,MACL;AAAA,QACE,SAAS;AAAA,QACT,QAAQ,IAAI,KAAK,UAAU;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,IAAI,OAAO,YAAY;AAAA,MACvC,KAAK;AAAA,MACL,UAAU;AAAA,IACZ,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,+CAA+C,QAAQ,KAAK,aAAa,KAAK,CAAC;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,UAAU;AAAA,IACzB,CAAC,UACC,MAAM,WAAW,KAAK,MAAM,WAAW;AAAA,EAC3C;AACA,MACE,SAAS,WAAW,KACpB,SAAS;AAAA,IACP,CAAC,UACC,iBAAiB,MAAM,OAAO,KAC9B,EACE,8BACA,MAAM,WAAW,KACjB,6BAA6B,MAAM,MAAM,SAAS,MAAM;AAAA,EAE9D,GACA;AACA,UAAM,IAAI;AAAA,MACR,4CAA4C,QAAQ;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,WAAkD;AACtE,SAAO,CAAC,WAAW,SAAS,aAAmB;AAC7C,UAAM,kBAAkB,QAAQ,UAAU;AAC1C,UAAM,aAAa,UAAU;AAAA,MAC3B,CAAC,UAAU,oBAAoB,KAAK,MAAM,WAAW;AAAA,IACvD;AACA,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,QAAQ,IAAI;AAAA,QAChB,6CAA6C,eAAe;AAAA,MAC9D;AACA,YAAM,OAAO;AACb,eAAS,OAAO,EAAE;AAClB;AAAA,IACF;AACA,QAAI,QAAQ,KAAK;AACf,eAAS,MAAM,UAAU;AACzB;AAAA,IACF;AACA,UAAM,CAAC,QAAQ,IAAI;AACnB,QAAI,CAAC,UAAU;AACb,eAAS,IAAI,MAAM,gCAAgC,GAAG,EAAE;AACxD;AAAA,IACF;AACA,aAAS,MAAM,SAAS,SAAS,SAAS,MAAM;AAAA,EAClD;AACF;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,iBAAiB,QAAQ,MAAM,UAAU;AAClD;AAEA,SAAS,UAAU,OAAoC;AACrD,SAAO,iBAAiB,QACnB,MAAgC,OACjC;AACN;AAEA,SAAS,eACP,UACA,OACoB;AACpB,MAAI,iBAAiB,2BAA2B,MAAM;AACpD,WAAO,MAAM;AAEf,QAAM,UAAU,aAAa,KAAK,EAAE,YAAY;AAChD,QAAM,OAAO,UAAU,KAAK;AAC5B,MAAI,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,OAAO;AACzD,WAAO;AACT,MAAI,QAAQ,SAAS,eAAe,EAAG,QAAO;AAC9C,MAAI,QAAQ,SAAS,gBAAgB,EAAG,QAAO;AAE/C,MAAI,aAAa,QAAQ;AACvB,QAAI,iBAAiB,2BAA2B,MAAM,SAAS;AAC7D,aAAO;AACT,QACE,iBAAiB,2BACjB,MAAM,SAAS;AAEf,aAAO;AACT,QAAI,QAAQ,SAAS,WAAW,KAAK,SAAS;AAC5C,aAAO;AACT,QAAI,QAAQ,SAAS,OAAO,EAAG,QAAO;AACtC,QAAI,iBAAiB,2BAA2B,MAAM,SAAS;AAC7D,aAAO;AACT,QACE,iBAAiB,4BAChB,MAAM,SAAS,sBAAsB,MAAM,SAAS;AAErD,aAAO,MAAM,SAAS,gBAClB,uBACA;AACN,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,eAAgB,QAAO;AACpC,MAAI,SAAS,aAAc,QAAO;AAClC,MAAI,SAAS,eAAe,SAAS,YAAa,QAAO;AACzD,MAAI,QAAQ,SAAS,6CAA6C;AAChE,WAAO;AACT,MAAI,QAAQ,SAAS,WAAW,KAAK,SAAS;AAC5C,WAAO;AACT,MAAI,QAAQ,SAAS,eAAe,EAAG,QAAO;AAC9C,MAAI,iBAAiB,2BAA2B,MAAM,SAAS;AAC7D,WAAO;AACT,MAAI,iBAAiB,2BAA2B,MAAM,SAAS;AAC7D,WAAO;AACT,MAAI,iBAAiB,2BAA2B,MAAM,SAAS;AAC7D,WAAO;AACT,SAAO;AACT;AAEA,SAAS,YAAY,SAAsC;AACzD,SAAO,GAAG,QAAQ,MAAM,KAAK,QAAQ,MAAM;AAC7C;AAEA,SAAS,kBACP,YACA,aACQ;AACR,MAAI,gBAAgB;AAClB,WAAO;AACT,MACE,eAAe,uBACf,gBAAgB;AAEhB,WAAO;AACT,MAAI,gBAAgB;AAClB,WAAO;AACT,MACE,gBAAgB,8BAChB,gBAAgB,4BAChB,gBAAgB,mBAChB,gBAAgB;AAEhB,WAAO;AACT,MACE,gBAAgB,0BAChB,gBAAgB;AAEhB,WAAO;AACT,MAAI,gBAAgB,uBAAuB,gBAAgB;AACzD,WAAO;AACT,SAAO;AACT;AAEA,SAAS,oBACP,WACA,OACA,WACA,YACQ;AACR,QAAM,aAAa,eAAe,QAAQ,SAAS;AACnD,QAAM,cAAc,eAAe,SAAS,UAAU;AACtD,QAAM,aACJ,qBAAqB,0BAA0B,UAAU,SAAS;AACpE,QAAM,cACJ,sBAAsB,0BAClB,WAAW,SACX;AACN,SAAO;AAAA,IACL;AAAA,IACA,GAAG,SAAS,KAAK,KAAK;AAAA,IACtB;AAAA,IACA,gBAAgB,UAAU;AAAA,IAC1B,GAAI,aAAa,CAAC,gBAAgB,UAAU,EAAE,IAAI,CAAC;AAAA,IACnD,gBAAgB,aAAa,SAAS,CAAC;AAAA,IACvC;AAAA,IACA,iBAAiB,WAAW;AAAA,IAC5B,GAAI,cAAc,CAAC,iBAAiB,WAAW,EAAE,IAAI,CAAC;AAAA,IACtD,iBAAiB,aAAa,UAAU,CAAC;AAAA,IACzC,eAAe,kBAAkB,YAAY,WAAW,CAAC;AAAA,EAC3D,EAAE,KAAK,IAAI;AACb;AAEA,eAAe,iBACb,UACA,cACiB;AACjB,QAAM,gBAAgB,SAAS,QAAQ,IAAI,gBAAgB;AAC3D,MAAI,iBAAiB,OAAO,aAAa,IAAI,cAAc;AACzD,UAAM,SAAS,MAAM,OAAO;AAC5B,UAAM,IAAI;AAAA,MACR,sCAAsC,YAAY;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,KAAM,QAAO;AAC3B,QAAM,SAAS,SAAS,KAAK,UAAU;AACvC,QAAM,SAAuB,CAAC;AAC9B,MAAI,QAAQ;AACZ,SAAO,MAAM;AACX,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,aAAS,MAAM;AACf,QAAI,QAAQ,cAAc;AACxB,UAAI;AACF,cAAM,OAAO,OAAO;AAAA,MACtB,QAAQ;AAAA,MAER;AACA,YAAM,IAAI;AAAA,QACR,sCAAsC,YAAY;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,QAAM,OAAO,IAAI,WAAW,KAAK;AACjC,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,SAAK,IAAI,OAAO,MAAM;AACtB,cAAU,MAAM;AAAA,EAClB;AACA,SAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AACtC;AAEA,SAAS,iBAAiB,OAAoB;AAC5C,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,KAAK;AAAA,EACrB,QAAQ;AACN,UAAM,IAAI;AAAA,MACR,6BAA6B,KAAK;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACA,MACE,IAAI,aAAa,YACjB,IAAI,YACJ,IAAI,YACH,IAAI,QAAQ,IAAI,SAAS,OAC1B;AACA,UAAM,IAAI;AAAA,MACR,2CAA2C,KAAK;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,UACb,YACA,cAC4D;AAC5D,MAAI,MAAM,iBAAiB,UAAU;AAErC,WAAS,YAAY,GAAG,aAAa,eAAe,aAAa,GAAG;AAClE,QAAI;AACJ,QAAI;AACF,kBAAY,MAAM,sBAAsB,IAAI,UAAU,IAAI;AAAA,IAC5D,SAAS,OAAO;AACd,YAAM,8BAA8B,OAAO,IAAI,IAAI;AAAA,IACrD;AACA,UAAM,aAAa,IAAI,MAAM;AAAA,MAC3B,SAAS,EAAE,QAAQ,aAAa,SAAS,EAAE;AAAA,IAC7C,CAAC;AACD,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,kBAAkB;AACvE,QAAI;AACF,YAAM,WAAY,MAAM,YAAY,KAAK;AAAA,QACvC,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,QAChB;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,UAAI,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG,EAAE,SAAS,SAAS,MAAM,GAAG;AACvD,cAAM,WAAW,SAAS,QAAQ,IAAI,UAAU;AAChD,YAAI,CAAC,UAAU;AACb,gBAAM,IAAI;AAAA,YACR,sBAAsB,IAAI,QAAQ;AAAA,YAClC;AAAA,UACF;AAAA,QACF;AACA,YAAI,cAAc,eAAe;AAC/B,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,cAAM,SAAS,MAAM,OAAO;AAC5B,cAAM,iBAAiB,IAAI,IAAI,UAAU,GAAG,EAAE,IAAI;AAClD;AAAA,MACF;AAEA,YAAM,OAAO,MAAM,iBAAiB,UAAU,YAAY;AAC1D,UAAI,SAAS,WAAW,KAAK;AAC3B,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,UACA,IAAI;AAAA,QACN;AAAA,MACF;AACA,UAAI,SAAS,WAAW,KAAK;AAC3B,cAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,cAAM,IAAI;AAAA,UACR,wCAAwC,aAAa,iBAAiB,UAAU,KAAK,EAAE;AAAA,UACvF;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI;AAAA,UACR,8BAA8B,SAAS,MAAM;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,iBAAS,KAAK,MAAM,IAAI;AAAA,MAC1B,QAAQ;AACN,cAAM,IAAI;AAAA,UACR,gBAAgB,IAAI,QAAQ;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,SAAS,MAAM,GAAG;AACrB,cAAM,IAAI;AAAA,UACR,gBAAgB,IAAI,QAAQ;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,MAAM,QAAQ,QAAQ,IAAI,KAAK;AAAA,IAC1C,SAAS,OAAO;AACd,UAAI,WAAW,OAAO,SAAS;AAC7B,cAAM,IAAI;AAAA,UACR,cAAc,IAAI,QAAQ;AAAA,UAC1B;AAAA,UACA,IAAI;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AACA,YAAM,eAAe,8BAA8B,OAAO,IAAI,IAAI;AAClE,UAAI,wBAAwB,wBAAyB,OAAM;AAC3D,YAAM,IAAI;AAAA,QACR,cAAc,IAAI,QAAQ,YAAY,aAAa,YAAY,CAAC;AAAA,QAChE;AAAA,QACA,IAAI;AAAA,MACN;AAAA,IACF,UAAE;AACA,mBAAa,OAAO;AACpB,YAAM,WAAW,MAAM;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,IAAI,wBAAwB,uBAAuB,SAAS;AACpE;AAEA,eAAe,aAAa,KAAqC;AAC/D,QAAM,SAAS,eAAe,IAAI,GAAG;AACrC,MAAI,UAAU,OAAO,YAAY,KAAK,IAAI,EAAG,QAAO,OAAO;AAE3D,QAAM,WAAW,MAAM,UAAU,KAAK,mBAAmB;AACzD,QAAM,WAAW,SAAS,KAAK;AAC/B,MAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO,EAAE,SAAS;AACxB,iBAAe,IAAI,KAAK,EAAE,MAAM,WAAW,KAAK,IAAI,IAAI,iBAAiB,CAAC;AAC1E,SAAO;AACT;AAEA,SAAS,kBACP,MACyC;AACzC,QAAM,WAAoD,CAAC;AAC3D,aAAW,WAAW,KAAK,UAAU;AACnC,QAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,EAAG;AACrD,UAAM,UAAU,YAAY,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,MAAM,YAAY,CAAC;AAC1E,UAAM,OAAO,YAAY,QAAQ,CAAC,CAAC,EAAE;AAAA,MAAO,CAAC,QAC3C,IAAI,WAAW,UAAU;AAAA,IAC3B;AACA,QAAI,QAAQ,SAAS,KAAK,KAAK,SAAS,EAAG,UAAS,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,EAC5E;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAqB,QAA0B;AACxE,MAAI,eAAe;AACnB,MAAI,OAAiB,CAAC;AACtB,aAAW,WAAW,kBAAkB,IAAI,GAAG;AAC7C,eAAW,SAAS,QAAQ,SAAS;AACnC,UAAI,WAAW,SAAS,CAAC,OAAO,SAAS,IAAI,KAAK,EAAE,EAAG;AACvD,YAAM,SAAS,MAAM,MAAM,GAAG,EAAE;AAChC,UAAI,SAAS,cAAc;AACzB,uBAAe;AACf,eAAO,CAAC,GAAG,QAAQ,IAAI;AAAA,MACzB,WAAW,WAAW,cAAc;AAClC,aAAK,KAAK,GAAG,QAAQ,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC;AAC1B;AAEA,SAAS,cAAc,MAAqB,IAAsB;AAChE,QAAM,SAAS,IAAI,KAAK,EAAE;AAC1B,QAAM,OAAO,WAAW,IAAI,SAAS;AACrC,MAAI,gBAAgB;AACpB,MAAI,OAAiB,CAAC;AAEtB,aAAW,WAAW,kBAAkB,IAAI,GAAG;AAC7C,eAAW,SAAS,QAAQ,SAAS;AACnC,YAAM,CAAC,SAAS,SAAS,IAAI,MAAM,MAAM,GAAG;AAC5C,YAAM,SAAS,OAAO,SAAS;AAC/B,UAAI,CAAC,WAAW,CAAC,OAAO,UAAU,MAAM,KAAK,IAAI,KAAK,OAAO,MAAM;AACjE;AACF,UAAI;AACF,cAAM,QAAQ,IAAI,IAAI,UAAU;AAChC,cAAM,UAAU,SAAS,QAAQ,IAAI;AACrC,YAAI,CAAC,MAAM,MAAM,IAAI,IAAI,EAAG;AAAA,MAC9B,QAAQ;AACN;AAAA,MACF;AACA,UAAI,SAAS,eAAe;AAC1B,wBAAgB;AAChB,eAAO,CAAC,GAAG,QAAQ,IAAI;AAAA,MACzB,WAAW,WAAW,eAAe;AACnC,aAAK,KAAK,GAAG,QAAQ,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC;AAC1B;AAEA,eAAe,sBACb,UACA,MACuB;AACvB,MAAI;AACJ,aAAW,WAAW,UAAU;AAC9B,QAAI;AACF,YAAM,OAAO,iBAAiB,OAAO;AACrC,UAAI,CAAC,KAAK,SAAS,SAAS,GAAG,EAAG,MAAK,YAAY;AACnD,YAAM,WAAW,IAAI,IAAI,MAAM,IAAI;AACnC,aAAO,MAAM,UAAU,SAAS,MAAM,cAAc;AAAA,IACtD,SAAS,OAAO;AACd,UACE,iBAAiB,2BACjB,MAAM,SAAS,aACf;AACA,cAAM;AAAA,MACR;AACA,kBAAY;AAAA,IACd;AAAA,EACF;AACA,QACE,aACA,IAAI,wBAAwB,0BAA0B,aAAa;AAEvE;AAEA,SAAS,eAAe,MAAmD;AACzE,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,EAAG,QAAO;AACvC,aAAW,SAAS,KAAK,OAAO;AAC9B,QAAI,CAAC,SAAS,KAAK,KAAK,MAAM,QAAQ,UAAW;AACjD,UAAM,OAAO,YAAY,MAAM,IAAI;AACnC,UAAM,OAAO,YAAY,MAAM,IAAI;AACnC,QAAI,QAAQ,MAAM,YAAY,EAAE,SAAS,uBAAuB;AAC9D,aAAO;AAAA,EACX;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAAyC;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,MAAM,EAAG,QAAO,CAAC;AACzC,QAAM,SAAiC;AAAA,IACrC,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,gCAAgC;AAAA,EAClC;AACA,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,KAAK,QAAQ;AAC/B,QAAI,CAAC,SAAS,KAAK,EAAG;AACtB,UAAM,SAAS,YAAY,MAAM,WAAW;AAC5C,UAAM,OAAO,YAAY,MAAM,SAAS;AACxC,QAAI,UAAU,KAAM,OAAM,KAAK,GAAG,OAAO,MAAM,KAAK,MAAM,KAAK,IAAI,EAAE;AAAA,EACvE;AACA,SAAO;AACT;AAEA,SAAS,YAAY,QAAwD;AAC3E,QAAM,SAAS,oBAAI,IAAsB;AACzC,MAAI,CAAC,MAAM,QAAQ,OAAO,UAAU,KAAK,CAAC,MAAM,QAAQ,OAAO,WAAW,CAAC,CAAC;AAC1E,WAAO;AACT,aAAW,YAAY,OAAO,WAAW,CAAC,GAAG;AAC3C,QAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS,EAAG;AACrD,UAAM,OAAO,YAAY,SAAS,CAAC,CAAC,GAAG,YAAY;AACnD,UAAM,QAAQ,YAAY,SAAS,CAAC,CAAC;AACrC,QAAI,CAAC,QAAQ,CAAC,MAAO;AACrB,WAAO,IAAI,MAAM,CAAC,GAAI,OAAO,IAAI,IAAI,KAAK,CAAC,GAAI,KAAK,CAAC;AAAA,EACvD;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAAyC;AAC5D,MAAI,CAAC,MAAM,QAAQ,KAAK,QAAQ,EAAG,QAAO,CAAC;AAC3C,QAAM,QAAkB,CAAC;AACzB,QAAM,QAAQ,CAAC,WAA0B;AACvC,QAAI,CAAC,SAAS,MAAM,EAAG;AACvB,UAAM,QAAQ,YAAY,OAAO,KAAK;AACtC,UAAM,SAAS,YAAY,MAAM;AACjC,UAAM,OAAO,OAAO,IAAI,IAAI,IAAI,CAAC,KAAK,OAAO,IAAI,KAAK,IAAI,CAAC;AAC3D,UAAM,SAAS,YAAY,OAAO,MAAM;AACxC,UAAM,WAAW,QAAQ;AACzB,QAAI,UAAU;AACZ,YAAM,YAAY,MAAM,QAAQ,OAAO,SAAS,IAC5C,OAAO,UACJ,IAAI,CAAC,UAAU;AACd,YAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAC7B,cAAM,OAAO,YAAY,MAAM,IAAI;AACnC,cAAM,aAAa,YAAY,MAAM,UAAU;AAC/C,eAAO,QAAQ,aAAa,GAAG,IAAI,IAAI,UAAU,KAAK;AAAA,MACxD,CAAC,EACA,OAAO,CAAC,UAA2B,UAAU,MAAS,IACzD,CAAC;AACL,YAAM,UAAU;AAAA,QACd,GAAG;AAAA,QACH,IAAI,OAAO,IAAI,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,SAAS,KAAK,EAAE;AAAA,QAC9D,IAAI,OAAO,IAAI,KAAK,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,aAAa,KAAK,EAAE;AAAA,MAClE;AACA,YAAM;AAAA,QACJ,SAAS,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,QAAQ,GAAG,QAAQ,SAAS,IAAI,KAAK,QAAQ,KAAK,IAAI,CAAC,KAAK,EAAE;AAAA,MAC9H;AAAA,IACF;AACA,QAAI,MAAM,QAAQ,OAAO,QAAQ,EAAG,QAAO,SAAS,QAAQ,KAAK;AAAA,EACnE;AACA,OAAK,SAAS,QAAQ,KAAK;AAC3B,SAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;AAC3B;AAEA,SAAS,aAAa,MAAyC;AAC7D,MAAI,CAAC,MAAM,QAAQ,KAAK,OAAO,EAAG,QAAO,CAAC;AAC1C,SAAO,KAAK,QACT,IAAI,CAAC,WAAY,SAAS,MAAM,IAAI,YAAY,OAAO,KAAK,IAAI,MAAU,EAC1E,OAAO,CAAC,UAA2B,UAAU,MAAS;AAC3D;AAEA,SAAS,iBACP,WACA,iBACA,UACQ;AACR,QAAM,OAAgC,OAAO;AAAA,IAC3C,CAAC;AAAA,IACD,GAAG,UACA,MAAM,EACN,QAAQ,EACR,IAAI,CAAC,aAAa,SAAS,IAAI;AAAA,EACpC;AACA,OAAK,WAAW,UAAU;AAAA,IAAQ,CAAC,aACjC,MAAM,QAAQ,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,WAAW,CAAC;AAAA,EACpE;AACA,OAAK,UAAU,UAAU;AAAA,IAAQ,CAAC,aAChC,MAAM,QAAQ,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,UAAU,CAAC;AAAA,EAClE;AACA,OAAK,SAAS,UAAU;AAAA,IAAQ,CAAC,aAC/B,MAAM,QAAQ,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,SAAS,CAAC;AAAA,EAChE;AACA,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,GAAG,UAAU,IAAI,CAAC,aAAa,WAAW,SAAS,MAAM,EAAE;AAAA,IAC3D,WAAW,YAAY,KAAK,WAAW,KAAK,YAAY,KAAK,OAAO,KAAK,eAAe;AAAA,EAC1F;AACA,QAAM,SAAS,YAAY,KAAK,MAAM;AACtC,MAAI,OAAQ,OAAM,KAAK,gBAAgB,MAAM,EAAE;AAC/C,QAAM,KAAK,GAAG,WAAW,IAAI,CAAC;AAC9B,QAAM,WAAW,YAAY,KAAK,MAAM;AACxC,MAAI,SAAS,SAAS,EAAG,OAAM,KAAK,WAAW,SAAS,KAAK,IAAI,CAAC,EAAE;AAEpE,MAAI,MAAM,QAAQ,KAAK,WAAW,GAAG;AACnC,UAAM,cAAc,KAAK,YACtB;AAAA,MAAI,CAAC,UACJ,SAAS,KAAK,IACT,YAAY,MAAM,WAAW,KAAK,YAAY,MAAM,OAAO,IAC5D;AAAA,IACN,EACC,OAAO,CAAC,UAA2B,UAAU,MAAS;AACzD,QAAI,YAAY,SAAS;AACvB,YAAM,KAAK,gBAAgB,YAAY,KAAK,IAAI,CAAC,EAAE;AAAA,EACvD;AACA,MAAI,SAAS,KAAK,SAAS,GAAG;AAC5B,UAAM,SAAS,KAAK,UAAU;AAC9B,QAAI,OAAO,WAAW;AACpB,YAAM,KAAK,WAAW,SAAS,WAAW,UAAU,EAAE;AAAA,EAC1D;AACA,QAAM,KAAK,GAAG,YAAY,IAAI,CAAC;AAC/B,QAAM,UAAU,aAAa,IAAI;AACjC,MAAI,QAAQ,SAAS,EAAG,OAAM,KAAK,YAAY,QAAQ,KAAK,IAAI,CAAC,EAAE;AACnE,QAAM,KAAK,GAAG,SAAS,IAAI,CAAC,YAAY,YAAY,OAAO,EAAE,CAAC;AAC9D,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,aAAa,UAAwB,IAAoB;AAChE,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,QAAQ,CAAC,kBAAkB,WAAW,SAAS,MAAM,IAAI,OAAO,EAAE,EAAE;AAC1E,aAAW,CAAC,OAAO,GAAG,KAAK;AAAA,IACzB,CAAC,WAAW,MAAM;AAAA,IAClB,CAAC,UAAU,QAAQ;AAAA,IACnB,CAAC,iBAAiB,cAAc;AAAA,IAChC,CAAC,eAAe,YAAY;AAAA,IAC5B,CAAC,cAAc,WAAW;AAAA,IAC1B,CAAC,QAAQ,MAAM;AAAA,IACf,CAAC,WAAW,SAAS;AAAA,IACrB,CAAC,iBAAiB,cAAc;AAAA,EAClC,GAAY;AACV,UAAM,QAAQ,YAAY,KAAK,GAAG,CAAC;AACnC,QAAI,MAAO,OAAM,KAAK,GAAG,KAAK,KAAK,KAAK,EAAE;AAAA,EAC5C;AACA,QAAM,WAAW,YAAY,KAAK,MAAM;AACxC,MAAI,SAAS,SAAS,EAAG,OAAM,KAAK,WAAW,SAAS,KAAK,IAAI,CAAC,EAAE;AACpE,QAAM,KAAK,GAAG,WAAW,IAAI,GAAG,GAAG,YAAY,IAAI,CAAC;AACpD,QAAM,UAAU,aAAa,IAAI;AACjC,MAAI,QAAQ,SAAS,EAAG,OAAM,KAAK,YAAY,QAAQ,KAAK,IAAI,CAAC,EAAE;AACnE,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,4BAA4B,QAAwB;AAClE,QAAM,YAAY,OAAO,KAAK,EAAE,QAAQ,OAAO,EAAE;AACjD,QAAM,2BAA2B,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,cAAc;AAClE,UAAM,YAAY,UAAU,YAAY,CAAC,KAAK;AAC9C,WAAO,aAAa,MAAQ,cAAc;AAAA,EAC5C,CAAC;AACD,MAAI,CAAC,aAAa,0BAA0B;AAC1C,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACA,QAAM,QAAQ,cAAc,SAAS,EAAE,YAAY;AACnD,MAAI,CAAC,SAAS,MAAM,SAAS,IAAK,OAAM,IAAI,MAAM,gBAAgB;AAClE,QAAM,SAAS,MAAM,MAAM,GAAG;AAC9B,MACE,OAAO;AAAA,IACL,CAAC,UACC,MAAM,WAAW,KACjB,MAAM,SAAS,MACf,CAAC,qCAAqC,KAAK,KAAK;AAAA,EACpD,GACA;AACA,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,QAAwB;AAGvD,SAAO,OAAO,MAAM,GAAG,EAAE,GAAG,EAAE,KAAK;AACrC;AAEA,SAAS,mBACP,OACA,iBAAiB,OACF;AACf,QAAM,YAAY,MAAM,SAAS,KAAK,IAAI,QAAQ,WAAW,KAAK;AAClE,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,SAAS;AAAA,EACzB,QAAQ;AACN,UAAM,IAAI;AAAA,MACR,2BAA2B,KAAK;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,YAAY,IAAI,aAAa,WAAW,IAAI,aAAa;AAC/D,QAAM,OAAO,YAAY,KAAK,IAAI,OAAO,OAAO,IAAI,IAAI,IAAI;AAC5D,MACG,IAAI,aAAa,YAAY,EAAE,kBAAkB,cAClD,CAAC,IAAI,YACL,IAAI,YACJ,IAAI,YACH,IAAI,YAAY,IAAI,aAAa,OAClC,IAAI,UACJ,IAAI,QACH,CAAC,aAAa,IAAI,QAAQ,IAAI,SAAS,MACxC;AACA,UAAM,IAAI;AAAA,MACR,mCAAmC,KAAK;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,MAAM,IAAI,SAAS,QAAQ,YAAY,EAAE,EAAE,YAAY,GAAG,KAAK;AAC1E;AAEA,SAAS,cAAc,UAA6C;AAClE,aAAW,CAAC,SAAS,cAAc,KAAK;AAAA,IACtC,CAAC,wBAAwB,KAAK;AAAA,IAC9B,CAAC,wBAAwB,KAAK;AAAA,IAC9B,CAAC,yCAAyC,IAAI;AAAA,IAC9C,CAAC,iCAAiC,KAAK;AAAA,EACzC,GAAY;AACV,UAAM,QAAQ,SAAS,MAAM,OAAO;AACpC,QAAI,QAAQ,CAAC,EAAG,QAAO,mBAAmB,MAAM,CAAC,EAAE,KAAK,GAAG,cAAc;AAAA,EAC3E;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,UAG5B;AACA,QAAM,sBACJ,kFAAkF;AAAA,IAChF;AAAA,EACF;AACF,MACE,CAAC,uBACD,qHAAqH;AAAA,IACnH;AAAA,EACF,GACA;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MACE,CAAC,uBACD,8FAA8F;AAAA,IAC5F;AAAA,EACF,GACA;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MACE,CAAC,uBACD,yDAAyD,KAAK,QAAQ,GACtE;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MACE,CAAC,uBACD,8EAA8E;AAAA,IAC5E;AAAA,EACF,GACA;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAkC,CAAC;AACzC,MAAI,SAAS,SAAS,QAAQ,GAAG;AAC/B,aAAS,KAAK;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,SAAO;AAAA,IACL,UACE,CAAC,uBACD,gEAAgE;AAAA,MAC9D;AAAA,IACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,MAAc,OAAuB;AAC5D,MAAI,SAAS,mBAAmB,CAAC,MAAM,SAAS,IAAI,EAAG,QAAO,GAAG,KAAK;AACtE,MAAI,SAAS,iBAAkB,QAAO,aAAa,KAAK;AACxD,SAAO;AACT;AAEA,eAAe,WACb,UACA,OACiB;AACjB,QAAM,YAAY,MAAM,sBAAsB,SAAS,MAAM,IAAI;AACjE,SAAO,MAAM,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC5C,QAAI,UAAU;AACd,QAAI,QAAQ;AACZ,UAAM,SAAmB,CAAC;AAC1B,UAAM,eAAe,MACnB,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACF,UAAM,SAAS,IAAI;AAAA,MACjB,EAAE,GAAG,UAAU,QAAQ,aAAa,SAAS,EAAE;AAAA,MAC/C,MAAM;AACJ,eAAO,MAAM,GAAG,gBAAgB,SAAS,MAAM,KAAK,CAAC;AAAA,CAAM;AAAA,MAC7D;AAAA,IACF;AACA,UAAM,WAAW;AAAA,MACf,MAAM,OAAO,QAAQ,aAAa,CAAC;AAAA,MACnC;AAAA,IACF;AACA,UAAM,SAAS,CAAC,UAAwB;AACtC,UAAI,QAAS;AACb,gBAAU;AACV,mBAAa,QAAQ;AACrB,UAAI,MAAO,QAAO,KAAK;AAAA,UAClB,SAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO,CAAC;AAAA,IACtD;AACA,WAAO,GAAG,QAAQ,CAAC,UAAkB;AACnC,eAAS,MAAM;AACf,UAAI,QAAQ,iBAAiB;AAC3B,eAAO;AAAA,UACL,IAAI;AAAA,YACF,0BAA0B,eAAe;AAAA,YACzC;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA;AAAA,MACF;AACA,aAAO,KAAK,KAAK;AAAA,IACnB,CAAC;AACD,WAAO,GAAG,OAAO,MAAM,OAAO,CAAC;AAC/B,WAAO,GAAG,SAAS,CAAC,UAAU,OAAO,KAAK,CAAC;AAC3C,WAAO,WAAW,oBAAoB,MAAM;AAC1C,aAAO,QAAQ,aAAa,CAAC;AAAA,IAC/B,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,YACb,OACA,iBAAiB,OACA;AACjB,MAAI,WAAW,EAAE,MAAM,kBAAkB,MAAM,GAAG;AAClD,QAAM,UAAU,oBAAI,IAAY;AAChC,MAAI,WAAW;AACf,QAAM,WAAkC,CAAC;AAEzC,WAAS,QAAQ,GAAG,QAAQ,mBAAmB,SAAS,GAAG;AACzD,UAAM,MAAM,GAAG,SAAS,IAAI,IAAI,SAAS,IAAI;AAC7C,QAAI,QAAQ,IAAI,GAAG,GAAG;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,WAAW,SAAS,IAAI;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AACA,YAAQ,IAAI,GAAG;AACf,QAAI;AACF,kBACE,MAAM,WAAW,UAAU,UAAU,IAAI,iBAAiB,KAAK,GAC/D,KAAK;AAAA,IACT,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,aAAa,KAAK;AAAA,QAClB,iBAAiB,0BAA0B,MAAM,OAAO;AAAA,QACxD,WAAW,SAAS,IAAI;AAAA,QACxB,eAAe,SAAS,KAAK;AAAA,MAC/B;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,cAAc,QAAQ;AAAA,IACnC,SAAS,OAAO;AACd,UAAI,UAAU,EAAG,OAAM;AACvB,eAAS,KAAK;AAAA,QACZ,QAAQ,eAAe,SAAS,KAAK;AAAA,QACrC,QAAQ,aAAa,KAAK;AAAA,MAC5B,CAAC;AACD;AAAA,IACF;AACA,QAAI,CAAC,UAAU;AACb,UAAI,UAAU,GAAG;AACf,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AACA,UAAM,cAAc,GAAG,SAAS,IAAI,IAAI,SAAS,IAAI;AACrD,QAAI,QAAQ,IAAI,WAAW,GAAG;AAC5B,UAAI,gBAAgB,IAAK;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,WAAW,SAAS,IAAI;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAU,oBAAoB,GAAG;AACnC,eAAS,KAAK;AAAA,QACZ,QAAQ;AAAA,QACR,QAAQ,2BAA2B,iBAAiB;AAAA,MACtD,CAAC;AACD;AAAA,IACF;AACA,QAAI;AACF,YAAM,sBAAsB,SAAS,MAAM,IAAI;AAAA,IACjD,SAAS,OAAO;AACd,UAAI,UAAU,EAAG,OAAM;AACvB,eAAS,KAAK;AAAA,QACZ,QAAQ,eAAe,SAAS,KAAK;AAAA,QACrC,QAAQ,aAAa,KAAK;AAAA,MAC5B,CAAC;AACD;AAAA,IACF;AACA,eAAW;AAAA,EACb;AAEA,MAAI,CAAC;AACH,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,WAAW,SAAS,IAAI;AAAA,MACxB;AAAA,IACF;AACF,MAAI;AACJ,MAAI;AACF,iBAAa,qBAAqB,QAAQ;AAAA,EAC5C,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,aAAa,KAAK;AAAA,MAClB,iBAAiB,0BACb,MAAM,OACN;AAAA,MACJ,WAAW,SAAS,IAAI;AAAA,MACxB,eAAe,SAAS,KAAK;AAAA,IAC/B;AAAA,EACF;AACA,WAAS,KAAK,GAAG,WAAW,QAAQ;AACpC,SAAO;AAAA,IACL;AAAA,IACA,mBAAmB,SAAS,IAAI;AAAA,IAChC,GAAI,WAAW,WACX,CAAC,uCAAuC,yBAAyB,IACjE,CAAC;AAAA,IACL,GAAG,SAAS,IAAI,CAAC,YAAY,YAAY,YAAY,OAAO,CAAC,EAAE;AAAA,IAC/D;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,QAAM,SACJ,iBAAiB,2BAA2B,MAAM,SAC9C,OAAO,MAAM,MAAM,KACnB;AACN,SAAO,GAAG,eAAe,QAAQ,KAAK,CAAC,GAAG,MAAM,KAAK,aAAa,KAAK,CAAC;AAC1E;AAEA,eAAsB,+BACpB,QACmC;AACnC,QAAM,aAAa,4BAA4B,MAAM;AACrD,MAAI;AACJ,MAAI;AACF,UAAM,YAAY,MAAM,aAAa,kBAAkB;AACvD,UAAM,OAAO,kBAAkB,WAAW,UAAU;AACpD,QAAI,KAAK,SAAS,GAAG;AACnB,UAAI;AACF,cAAM,WAAW,MAAM;AAAA,UACrB;AAAA,UACA,UAAU,mBAAmB,UAAU,CAAC;AAAA,QAC1C;AACA,cAAM,YAAY,CAAC,QAAQ;AAC3B,cAAM,WAAqB,CAAC;AAC5B,cAAM,UAAU,eAAe,SAAS,IAAI;AAC5C,YAAI,SAAS;AACX,cAAI;AACF,sBAAU,KAAK,MAAM,UAAU,SAAS,cAAc,CAAC;AAAA,UACzD,SAAS,OAAO;AACd,qBAAS;AAAA,cACP,GAAG,eAAe,QAAQ,KAAK,CAAC,mCAAmC,aAAa,KAAK,CAAC;AAAA,YACxF;AAAA,UACF;AAAA,QACF;AACA,eAAO;AAAA,UACL,MAAM,iBAAiB,WAAW,YAAY,QAAQ;AAAA,UACtD,QAAQ;AAAA,QACV;AAAA,MACF,SAAS,OAAO;AACd,YACE,iBAAiB,2BACjB,MAAM,SAAS,aACf;AACA,iBAAO;AAAA,YACL,MAAM;AAAA,UAA2B,MAAM,UAAU,4BAA4B;AAAA,UAAa,UAAU;AAAA;AAAA;AAAA,YACpG,QAAQ;AAAA,UACV;AAAA,QACF;AACA,oBAAY;AAAA,MACd;AAAA,IACF,OAAO;AACL,kBAAY,IAAI;AAAA,QACd;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,gBAAY;AAAA,EACd;AAEA,MAAI;AACF,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA,wBAAwB,UAAU;AAAA,IACpC;AACA,WAAO;AAAA,MACL,MAAM,YACF,GAAG,MAAM;AAAA;AAAA,WAAgB,gBAAgB,SAAS,CAAC,KACnD;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF,SAAS,YAAY;AACnB,QAAI,WAAW;AACb,aAAO;AAAA,QACL,MAAM,oBAAoB,UAAU,YAAY,WAAW,UAAU;AAAA,QACrE,QAAQ;AAAA,MACV;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,IAAI;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAQA,eAAsB,2BACpB,IACmC;AACnC,QAAM,SAAS,IAAI,KAAK,EAAE;AAC1B,MAAI,WAAW,EAAG,OAAM,IAAI,MAAM,oBAAoB;AACtD,MAAI;AACJ,MAAI;AACF,UAAM,YAAY,MAAM;AAAA,MACtB,WAAW,IAAI,sBAAsB;AAAA,IACvC;AACA,UAAM,OAAO,cAAc,WAAW,EAAE;AACxC,QAAI,KAAK,SAAS,GAAG;AACnB,UAAI;AACF,cAAM,WAAW,MAAM;AAAA,UACrB;AAAA,UACA,MAAM,mBAAmB,EAAE,CAAC;AAAA,QAC9B;AACA,eAAO,EAAE,MAAM,aAAa,UAAU,EAAE,GAAG,QAAQ,MAAM;AAAA,MAC3D,SAAS,OAAO;AACd,YACE,iBAAiB,2BACjB,MAAM,SAAS,aACf;AACA,iBAAO;AAAA,YACL,MAAM;AAAA,UAA2B,MAAM,UAAU,4BAA4B;AAAA,MAAS,EAAE;AAAA;AAAA;AAAA,YACxF,QAAQ;AAAA,UACV;AAAA,QACF;AACA,oBAAY;AAAA,MACd;AAAA,IACF,OAAO;AACL,kBAAY,IAAI;AAAA,QACd;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,gBAAY;AAAA,EACd;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,YAAY,EAAE;AACnC,WAAO;AAAA,MACL,MAAM,YACF,GAAG,MAAM;AAAA;AAAA,WAAgB,gBAAgB,SAAS,CAAC,KACnD;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF,SAAS,YAAY;AACnB,QAAI,WAAW;AACb,aAAO;AAAA,QACL,MAAM,oBAAoB,MAAM,IAAI,WAAW,UAAU;AAAA,QACzD,QAAQ;AAAA,MACV;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,IAAI;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF;;;ADtyCO,SAAS,oBAAoB,MAAM,QAAQ,KAAW;AAC3D,QAAM,MAAM,IAAI;AAChB,MAAI,CAAC,IAAK;AACV,QAAM,UAAU,IACb,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAMC,KAAI,KAAK,CAAC,MAAM,CAAC;AAClC,MAAI,QAAQ,SAAS,GAAG;AACtB,eAAW,OAAO;AAAA,EACpB;AACF;AAEA,SAAS,YAAY,OAAgB,MAAc,QAAwB;AACzE,QAAM,OAAQ,MAAgC;AAC9C,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,MAAM,IAAI,sBAAsB,MAAM;AAAA,IAC/C,KAAK;AACH,aAAO,qBAAqB,MAAM;AAAA,IACpC,KAAK;AACH,aAAO,0BAA0B,IAAI,cAAc,MAAM;AAAA,IAC3D,KAAK;AACH,aAAO,iBAAiB,MAAM,KAAK,IAAI;AAAA,IACzC;AACE,aAAO,yBAAyB,MAAM,KAAK,IAAI,MAAM,QAAQ,eAAe;AAAA,EAChF;AACF;AAEA,IAAM,YACJ;AAEF,SAAS,kBAAkB,QAAsB;AAC/C,MAAI,CAAC,UAAU,KAAK,MAAM,GAAG;AAC3B,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACF;AAEA,eAAsB,UACpB,QACA,MACiB;AACjB,oBAAkB,MAAM;AACxB,MAAI;AACJ,MAAI;AACF,cAAU,MAAMC,KAAI,QAAQ,QAAQ,IAAI;AAAA,EAC1C,SAAS,OAAO;AACd,WAAO,YAAY,OAAO,MAAM,MAAM;AAAA,EACxC;AAEA,UAAQ,MAAM;AAAA,IACZ,KAAK,MAAM;AACT,YAAM,KAAK;AACX,UAAI,GAAG,WAAW,EAAG,QAAO;AAC5B,aAAO,GACJ,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ,EACtC,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,KAAK,EAAE,QAAQ,EAAE,EACzC,KAAK,IAAI;AAAA,IACd;AAAA,IACA,KAAK,OAAO;AACV,YAAM,MAAM;AACZ,UAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,aAAO,IAAI,IAAI,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI;AAAA,IACzD;AAAA,IACA,KAAK,OAAO;AACV,YAAM,MAAM;AACZ,UAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,YAAM,YAAY,IAAI;AAAA,QAAQ,CAAC,EAAE,UAAU,GAAG,KAAK,MACjD,OAAO,QAAQ,IAAI,EAChB;AAAA,UACC,CAAC,UACC,MAAM,CAAC,MAAM,UAAU,OAAO,MAAM,CAAC,MAAM;AAAA,QAC/C,EACC,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,QAAQ,IAAI,GAAG,IAAI,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,MACxE;AACA,aAAO,UAAU,SAAS,IACtB,UAAU,KAAK,IAAI,IACnB;AAAA,IACN;AAAA,IACA,KAAK,OAAO;AACV,YAAM,MAAM;AACZ,YAAM,IAAI,IAAI,CAAC;AACf,UAAI,CAAC,EAAG,QAAO;AACf,aAAO;AAAA,QACL,cAAc,EAAE,MAAM;AAAA,QACtB,eAAe,EAAE,UAAU;AAAA,QAC3B,cAAc,EAAE,MAAM;AAAA,QACtB,cAAc,EAAE,OAAO;AAAA,QACvB,cAAc,EAAE,KAAK;AAAA,QACrB,cAAc,EAAE,MAAM;AAAA,QACtB,cAAc,EAAE,MAAM;AAAA,MACxB,EAAE,KAAK,IAAI;AAAA,IACb;AAAA,IACA,KAAK,OAAO;AACV,YAAM,MAAM;AACZ,UAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,aAAO,IACJ,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,IAAI,EAAE,MAAM,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,EAAE,EAC1D,KAAK,IAAI;AAAA,IACd;AAAA,IACA,SAAS;AACP,YAAM,MAAM;AACZ,UAAI,IAAI,WAAW,EAAG,QAAO,MAAM,IAAI;AACvC,aAAO,IAAI,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AACF;AAEA,eAAsB,WAAW,IAA6B;AAC5D,MAAID,KAAI,KAAK,EAAE,MAAM,GAAG;AACtB,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AACA,MAAI;AACJ,MAAI;AACF,gBAAY,MAAMC,KAAI,QAAQ,EAAE;AAAA,EAClC,SAAS,OAAO;AACd,WAAO,YAAY,OAAO,OAAO,EAAE;AAAA,EACrC;AACA,SAAO,UAAU,SAAS,IAAI,UAAU,KAAK,IAAI,IAAI;AACvD;AAEA,eAAsB,WAAW,QAAiC;AAChE,oBAAkB,MAAM;AACxB,QAAM,QAA8C;AAAA,IAClD,EAAE,MAAM,KAAK,MAAM,IAAI;AAAA,IACvB,EAAE,MAAM,QAAQ,MAAM,OAAO;AAAA,IAC7B,EAAE,MAAM,MAAM,MAAM,KAAK;AAAA,IACzB,EAAE,MAAM,OAAO,MAAM,MAAM;AAAA,IAC3B,EAAE,MAAM,OAAO,MAAM,MAAM;AAAA,IAC3B,EAAE,MAAM,MAAM,MAAM,KAAK;AAAA,IACzB,EAAE,MAAM,SAAS,MAAM,QAAQ;AAAA,EACjC;AAEA,QAAM,UAAoB,CAAC;AAC3B,aAAW,EAAE,MAAM,KAAK,KAAK,OAAO;AAClC,QAAI;AACF,YAAM,UAAU,MAAM,UAAU,QAAQ,IAAI;AAC5C,cAAQ,KAAK,OAAO,IAAI;AAAA,EAAS,OAAO,EAAE;AAAA,IAC5C,QAAQ;AACN,cAAQ,KAAK,OAAO,IAAI;AAAA,sBAA6B;AAAA,IACvD;AAAA,EACF;AACA,SAAO,QAAQ,KAAK,MAAM;AAC5B;AAEA,eAAsB,iBAAiB,QAAiC;AACtE,oBAAkB,MAAM;AACxB,MAAI;AACJ,MAAI;AACF,kBAAc,MAAMA,KAAI,UAAU,MAAM;AAAA,EAC1C,SAAS,OAAO;AACd,WAAO,YAAY,OAAO,MAAM,MAAM;AAAA,EACxC;AACA,SAAO,YAAY,SAAS,IACxB,YAAY,KAAK,IAAI,IACrB;AACN;AAMA,eAAsB,kBACpB,QACmC;AACnC,SAAO,MAAM,+BAA+B,MAAM;AACpD;AAMA,eAAsB,cACpB,IACmC;AACnC,SAAO,MAAM,2BAA2B,EAAE;AAC5C;;;AE/NA;AAAA,EACE;AAAA,OAIK;AACP,SAAS,qCAAqC;;;ACN9C,SAAS,iBAAiB;AAC1B,SAAS,SAAS;;;ACDlB;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,KAAO;AAAA,IACL,iBAAiB;AAAA,EACnB;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,WAAa;AAAA,IACb,MAAQ;AAAA,IACR,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,MAAQ;AAAA,IACR,QAAU;AAAA,IACV,cAAc;AAAA,IACd,SAAW;AAAA,IACX,gBAAkB;AAAA,IAClB,SAAW;AAAA,EACb;AAAA,EACA,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAU;AAAA,EACV,SAAW;AAAA,EACX,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,IACN,KAAO;AAAA,EACT;AAAA,EACA,UAAY;AAAA,EACZ,cAAgB;AAAA,IACd,6BAA6B;AAAA,IAC7B,QAAU;AAAA,IACV,KAAO;AAAA,EACT;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,QAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,OAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAY;AAAA,IACZ,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,EACZ;AAAA,EACA,eAAe;AAAA,IACb,iBAAiB;AAAA,MACf;AAAA,MACA;AAAA,IACF;AAAA,IACA,wBAAwB;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA,EACA,cAAgB;AAAA,IACd,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,EACpB;AACF;;;AD/EA,IAAM,mBAAmB,EACtB,KAAK,CAAC,KAAK,QAAQ,MAAM,OAAO,SAAS,MAAM,OAAO,OAAO,OAAO,KAAK,CAAC,EAC1E,QAAQ,GAAG;AAEd,IAAM,sBAAsB;AAAA,EAC1B,cAAc;AAAA,EACd,iBAAiB;AACnB;AAEO,SAAS,kBAA6B;AAC3C,QAAM,SAAS,IAAI;AAAA,IACjB;AAAA,MACE,MAAM;AAAA,MACN,SAAS,gBAAY;AAAA,IACvB;AAAA,IACA;AAAA,MACE,cACE;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa;AAAA,QACX,QAAQ,EACL,OAAO,EACP,SAAS,2CAA2C;AAAA,QACvD,MAAM,iBAAiB;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,QAAQ,KAAK,MAAM;AAC1B,YAAM,SAAS,MAAM,UAAU,QAAQ,IAAI;AAC3C,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,CAAC,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa;AAAA,QACX,IAAI,EAAE,OAAO,EAAE,SAAS,2BAA2B;AAAA,MACrD;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,GAAG,MAAM;AAChB,YAAM,SAAS,MAAM,WAAW,EAAE;AAClC,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,CAAC,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa;AAAA,QACX,QAAQ,EACL,OAAO,EACP,SAAS,2CAA2C;AAAA,MACzD;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,OAAO,MAAM;AACpB,YAAM,SAAS,MAAM,WAAW,MAAM;AACtC,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,CAAC,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa;AAAA,QACX,QAAQ,EAAE,OAAO,EAAE,SAAS,gCAAgC;AAAA,MAC9D;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,OAAO,MAAM;AACpB,YAAM,SAAS,MAAM,iBAAiB,MAAM;AAC5C,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,CAAC,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa;AAAA,QACX,QAAQ,EACL,OAAO,EACP,SAAS,wDAAwD;AAAA,MACtE;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,OAAO,MAAM;AACpB,YAAM,SAAS,MAAM,kBAAkB,MAAM;AAC7C,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,KAAK,CAAC;AAAA,QACtD,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,aAAa;AAAA,QACX,IAAI,EACD,OAAO,EACP,SAAS,mDAAmD;AAAA,MACjE;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,GAAG,MAAM;AAChB,YAAM,SAAS,MAAM,cAAc,EAAE;AACrC,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,KAAK,CAAC;AAAA,QACtD,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ADzIA,IAAM,wBAAwB,oBAAI,IAAI,CAAC,aAAa,aAAa,KAAK,CAAC;AACvE,IAAM,oBAAoB,oBAAI,IAAI,CAAC,aAAa,aAAa,OAAO,CAAC;AACrE,IAAM,sBAAsB,OAAO;AAEnC,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACnC,YACE,SACS,YACA,SACT;AACA,UAAM,OAAO;AAHJ;AACA;AAAA,EAGX;AACF;AAEA,SAAS,SACP,UACA,YACA,MACM;AACN,WAAS,UAAU,YAAY;AAAA,IAC7B,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,EACnB,CAAC;AACD,WAAS,IAAI,KAAK,UAAU,IAAI,CAAC;AACnC;AAEA,SAAS,gBAAgB,SAA8C;AACrE,QAAM,OAAO,QAAQ,QAAQ;AAC7B,MAAI,SAAS,OAAW,QAAO;AAE/B,MAAI;AACF,WAAO,IAAI,IAAI,UAAU,IAAI,EAAE,EAAE;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,SAAqD;AAC7E,MAAI,QAAQ,iBAAiB,UAAa,QAAQ,aAAa,SAAS,GAAG;AACzE,WAAO,IAAI,IAAI,QAAQ,YAAY;AAAA,EACrC;AACA,MAAI,sBAAsB,IAAI,QAAQ,IAAI,GAAG;AAC3C,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,eAAe,aAAa,SAA4C;AACtE,QAAM,gBAAgB,QAAQ,QAAQ,gBAAgB;AACtD,MAAI,kBAAkB,QAAW;AAC/B,UAAM,SAAS,OAAO,aAAa;AACnC,QAAI,CAAC,OAAO,cAAc,MAAM,KAAK,SAAS,GAAG;AAC/C,YAAM,IAAI,iBAAiB,0BAA0B,KAAK,MAAM;AAAA,IAClE;AACA,QAAI,SAAS,qBAAqB;AAChC,YAAM,IAAI,iBAAiB,0BAA0B,KAAK,MAAM;AAAA,IAClE;AAAA,EACF;AAEA,QAAM,SAAmB,CAAC;AAC1B,MAAI,OAAO;AACX,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAM,UAAU,MAAM;AACpB,cAAQ,IAAI,QAAQ,MAAM;AAC1B,cAAQ,IAAI,OAAO,KAAK;AACxB,cAAQ,IAAI,SAAS,OAAO;AAC5B,cAAQ,IAAI,WAAW,SAAS;AAAA,IAClC;AACA,UAAM,OAAO,CAAC,UAAiB;AAC7B,cAAQ,MAAM;AACd,cAAQ;AACR,aAAO,KAAK;AAAA,IACd;AACA,UAAM,SAAS,CAAC,UAA2B;AACzC,YAAM,SAAS,OAAO,SAAS,KAAK,IAAI,QAAQ,OAAO,KAAK,KAAK;AACjE,cAAQ,OAAO;AACf,UAAI,OAAO,qBAAqB;AAC9B,aAAK,IAAI,iBAAiB,0BAA0B,KAAK,MAAM,CAAC;AAChE;AAAA,MACF;AACA,aAAO,KAAK,MAAM;AAAA,IACpB;AACA,UAAM,QAAQ,MAAM;AAClB,cAAQ;AACR,cAAQ;AAAA,IACV;AACA,UAAM,UAAU,CAAC,UAAiB;AAChC,cAAQ;AACR,aAAO,KAAK;AAAA,IACd;AACA,UAAM,YAAY,MAAM;AACtB,WAAK,IAAI,iBAAiB,wBAAwB,KAAK,MAAM,CAAC;AAAA,IAChE;AAEA,YAAQ,GAAG,QAAQ,MAAM;AACzB,YAAQ,KAAK,OAAO,KAAK;AACzB,YAAQ,KAAK,SAAS,OAAO;AAC7B,YAAQ,KAAK,WAAW,SAAS;AAAA,EACnC,CAAC;AAED,MAAI;AACF,WAAO,KAAK,MAAM,OAAO,OAAO,QAAQ,IAAI,EAAE,SAAS,MAAM,CAAC;AAAA,EAChE,QAAQ;AACN,UAAM,IAAI,iBAAiB,6BAA6B,KAAK,MAAM;AAAA,EACrE;AACF;AAEA,eAAe,iBACb,SACA,UACe;AACf,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,aAAa,OAAO;AAAA,EACzC,SAAS,OAAO;AACd,QAAI,iBAAiB,kBAAkB;AACrC,UAAI,MAAM,eAAe,IAAK,UAAS,UAAU,cAAc,OAAO;AACtE,eAAS,UAAU,MAAM,YAAY;AAAA,QACnC,SAAS;AAAA,QACT,OAAO,EAAE,MAAM,MAAM,SAAS,SAAS,MAAM,QAAQ;AAAA,QACrD,IAAI;AAAA,MACN,CAAC;AACD;AAAA,IACF;AACA,YAAQ,MAAM,oCAAoC,KAAK;AACvD,aAAS,UAAU,KAAK;AAAA,MACtB,SAAS;AAAA,MACT,OAAO,EAAE,MAAM,QAAQ,SAAS,8BAA8B;AAAA,MAC9D,IAAI;AAAA,IACN,CAAC;AACD;AAAA,EACF;AAEA,QAAM,SAAS,gBAAgB;AAC/B,QAAM,YAAY,IAAI,8BAA8B;AAAA,IAClD,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,EACtB,CAAC;AAED,MAAI;AACF,UAAM,OAAO,QAAQ,SAAS;AAC9B,UAAM,UAAU,cAAc,SAAS,UAAU,UAAU;AAAA,EAC7D,SAAS,OAAO;AACd,YAAQ,MAAM,4BAA4B,KAAK;AAC/C,QAAI,CAAC,SAAS,aAAa;AACzB,eAAS,UAAU,KAAK;AAAA,QACtB,SAAS;AAAA,QACT,OAAO,EAAE,MAAM,QAAQ,SAAS,wBAAwB;AAAA,QACxD,IAAI;AAAA,MACN,CAAC;AAAA,IACH,WAAW,CAAC,SAAS,eAAe;AAClC,eAAS,IAAI;AAAA,IACf;AAAA,EACF,UAAE;AACA,UAAM,QAAQ,WAAW,CAAC,UAAU,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC;AAAA,EAC9D;AACF;AAEA,eAAsB,gBACpB,SACiB;AACjB,QAAM,gBAAgB,iBAAiB,OAAO;AAC9C,QAAM,aAAa,aAAa,CAAC,SAAS,aAAa;AACrD,UAAM,WAAW,IAAI,IAAI,QAAQ,OAAO,KAAK,kBAAkB,EAAE;AAEjE,QAAI,aAAa,WAAW;AAC1B,UAAI,QAAQ,WAAW,OAAO;AAC5B,iBAAS,UAAU,KAAK,EAAE,OAAO,qBAAqB,CAAC;AACvD;AAAA,MACF;AACA,eAAS,UAAU,KAAK,EAAE,QAAQ,KAAK,CAAC;AACxC;AAAA,IACF;AAEA,QAAI,aAAa,QAAQ;AACvB,eAAS,UAAU,KAAK,EAAE,OAAO,YAAY,CAAC;AAC9C;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,QAAQ;AAC7B,eAAS,UAAU,SAAS,MAAM;AAClC,eAAS,UAAU,KAAK;AAAA,QACtB,SAAS;AAAA,QACT,OAAO,EAAE,MAAM,OAAQ,SAAS,qBAAqB;AAAA,QACrD,IAAI;AAAA,MACN,CAAC;AACD;AAAA,IACF;AAEA,QAAI,kBAAkB,QAAW;AAC/B,YAAM,WAAW,gBAAgB,OAAO;AACxC,UAAI,aAAa,UAAa,CAAC,cAAc,IAAI,QAAQ,GAAG;AAC1D,iBAAS,UAAU,KAAK;AAAA,UACtB,SAAS;AAAA,UACT,OAAO,EAAE,MAAM,OAAQ,SAAS,sBAAsB;AAAA,UACtD,IAAI;AAAA,QACN,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAEA,SAAK,iBAAiB,SAAS,QAAQ;AAAA,EACzC,CAAC;AAED,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAM,UAAU,CAAC,UAAiB;AAChC,iBAAW,IAAI,aAAa,WAAW;AACvC,aAAO,KAAK;AAAA,IACd;AACA,UAAM,cAAc,MAAM;AACxB,iBAAW,IAAI,SAAS,OAAO;AAC/B,cAAQ;AAAA,IACV;AACA,eAAW,KAAK,SAAS,OAAO;AAChC,eAAW,KAAK,aAAa,WAAW;AACxC,eAAW,OAAO,QAAQ,MAAM,QAAQ,IAAI;AAAA,EAC9C,CAAC;AAED,SAAO;AACT;AAEA,eAAsB,eAAe,QAA+B;AAClE,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,WAAO,MAAM,CAAC,UAAU;AACtB,UAAI,MAAO,QAAO,KAAK;AAAA,UAClB,SAAQ;AAAA,IACf,CAAC;AAAA,EACH,CAAC;AACH;;;AJ7OA,oBAAoB;AAEpB,eAAe,OAAO;AACpB,QAAM,UAAU,aAAa,QAAQ,KAAK,MAAM,CAAC,CAAC;AAClD,MAAI,QAAQ,cAAc,SAAS;AACjC,UAAM,SAAS,gBAAgB;AAC/B,UAAM,YAAY,IAAI,qBAAqB;AAC3C,UAAM,OAAO,QAAQ,SAAS;AAC9B;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,gBAAgB,OAAO;AAChD,UAAQ;AAAA,IACN,kDAAkD,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAAA,EAChF;AAEA,MAAI,eAAe;AACnB,QAAM,WAAW,YAAY;AAC3B,QAAI,aAAc;AAClB,mBAAe;AACf,UAAM,eAAe,UAAU;AAAA,EACjC;AAEA,UAAQ,KAAK,UAAU,MAAM,KAAK,SAAS,CAAC;AAC5C,UAAQ,KAAK,WAAW,MAAM,KAAK,SAAS,CAAC;AAC/C;AAEA,KAAK,EAAE,MAAM,CAAC,UAAU;AACtB,UAAQ,MAAM,gBAAgB,KAAK;AACnC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["dns","net","net","dns"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cli.ts","../src/dns.ts","../src/registration.ts","../src/http.ts","../src/server.ts","../package.json"],"sourcesContent":["import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { parseCliArgs } from \"./cli.js\";\nimport { configureDnsServers } from \"./dns.js\";\nimport { startHttpServer, stopHttpServer } from \"./http.js\";\nimport { createMcpServer } from \"./server.js\";\n\nconfigureDnsServers();\n\nasync function main() {\n const options = parseCliArgs(process.argv.slice(2));\n if (options.transport === \"stdio\") {\n const server = createMcpServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n return;\n }\n\n const httpServer = await startHttpServer(options);\n console.error(\n `MCP Streamable HTTP server listening on http://${options.host}:${options.port}/mcp`,\n );\n\n let shuttingDown = false;\n const shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n await stopHttpServer(httpServer);\n };\n\n process.once(\"SIGINT\", () => void shutdown());\n process.once(\"SIGTERM\", () => void shutdown());\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n","import { parseArgs } from \"node:util\";\n\nexport type CliOptions =\n | {\n transport: \"stdio\";\n }\n | {\n transport: \"http\";\n host: string;\n port: number;\n allowedHosts: string[];\n };\n\nexport function parseCliArgs(\n args: string[],\n env: NodeJS.ProcessEnv = process.env,\n): CliOptions {\n const { values } = parseArgs({\n args,\n options: {\n transport: {\n type: \"string\",\n default: \"stdio\",\n },\n host: {\n type: \"string\",\n },\n port: {\n type: \"string\",\n },\n \"allowed-host\": {\n type: \"string\",\n multiple: true,\n },\n },\n strict: true,\n });\n\n if (values.transport !== \"stdio\" && values.transport !== \"http\") {\n throw new Error(\n `Unsupported transport: ${values.transport}. Supported transports: stdio, http.`,\n );\n }\n\n if (values.transport === \"stdio\") {\n if (\n values.host !== undefined ||\n values.port !== undefined ||\n values[\"allowed-host\"] !== undefined\n ) {\n throw new Error(\n \"--host, --port, and --allowed-host can only be used with --transport http.\",\n );\n }\n return { transport: \"stdio\" };\n }\n\n const host = values.host ?? env.HOST ?? \"127.0.0.1\";\n const portValue = values.port ?? env.PORT ?? \"3000\";\n const port = Number(portValue);\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new Error(`Invalid HTTP port: ${portValue}. Expected 1-65535.`);\n }\n\n return {\n transport: \"http\",\n host,\n port,\n allowedHosts: values[\"allowed-host\"] ?? [],\n };\n}\n","import dns from \"node:dns/promises\";\nimport { setServers } from \"node:dns\";\nimport type { CaaRecord } from \"node:dns\";\nimport net from \"node:net\";\nimport type { RegistrationLookupResult } from \"./registration.js\";\nimport {\n domainRegistrationLookup,\n domainRegistrationLookupResult,\n ipRegistrationLookup,\n ipRegistrationLookupResult,\n} from \"./registration.js\";\n\nexport type { RegistrationLookupResult };\n\nexport type RecordType =\n \"A\" | \"AAAA\" | \"MX\" | \"TXT\" | \"CNAME\" | \"NS\" | \"SOA\" | \"SRV\" | \"CAA\" | \"PTR\";\n\ninterface MxRecord {\n exchange: string;\n priority: number;\n}\n\ninterface SoaRecord {\n nsname: string;\n hostmaster: string;\n serial: number;\n refresh: number;\n retry: number;\n expire: number;\n minttl: number;\n}\n\ninterface SrvRecord {\n priority: number;\n weight: number;\n port: number;\n name: string;\n}\n\nexport function configureDnsServers(env = process.env): void {\n const raw = env.DNS_SERVERS;\n if (!raw) return;\n const servers = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => net.isIP(s) !== 0);\n if (servers.length > 0) {\n setServers(servers);\n }\n}\n\nfunction mapDnsError(error: unknown, type: string, target: string): string {\n const code = (error as NodeJS.ErrnoException).code;\n switch (code) {\n case \"ENODATA\":\n return `No ${type} records found for ${target}.`;\n case \"ENOTFOUND\":\n return `Domain not found: ${target}`;\n case \"EREFUSED\":\n return `DNS server refused the ${type} query for ${target}. The local resolver may not support this record type; set DNS_SERVERS to use a different resolver.`;\n case \"ETIMEOUT\":\n return `DNS query for ${target} (${type}) timed out.`;\n default:\n return `DNS lookup failed for ${target} (${type}): ${code ?? \"unknown error\"}`;\n }\n}\n\nconst DOMAIN_RE =\n /^(?=.{1,253}$)[a-zA-Z0-9_]([a-zA-Z0-9_-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9_]([a-zA-Z0-9_-]{0,61}[a-zA-Z0-9])?)*\\.?$/;\n\nfunction assertValidDomain(domain: string): void {\n if (!DOMAIN_RE.test(domain)) {\n throw new Error(\"Invalid domain\");\n }\n}\n\nexport async function dnsLookup(\n domain: string,\n type: RecordType,\n): Promise<string> {\n assertValidDomain(domain);\n let records: unknown;\n try {\n records = await dns.resolve(domain, type);\n } catch (error) {\n return mapDnsError(error, type, domain);\n }\n\n switch (type) {\n case \"MX\": {\n const mx = records as MxRecord[];\n if (mx.length === 0) return \"No MX records found.\";\n return mx\n .sort((a, b) => a.priority - b.priority)\n .map((r) => `${r.priority} ${r.exchange}`)\n .join(\"\\n\");\n }\n case \"TXT\": {\n const txt = records as string[][];\n if (txt.length === 0) return \"No TXT records found.\";\n return txt.map((entries) => entries.join(\"\")).join(\"\\n\");\n }\n case \"CAA\": {\n const caa = records as CaaRecord[];\n if (caa.length === 0) return \"No CAA records found.\";\n const formatted = caa.flatMap(({ critical, ...tags }) =>\n Object.entries(tags)\n .filter(\n (entry): entry is [string, string] =>\n entry[0] !== \"type\" && typeof entry[1] === \"string\",\n )\n .map(([tag, value]) => `${critical} ${tag} ${JSON.stringify(value)}`),\n );\n return formatted.length > 0\n ? formatted.join(\"\\n\")\n : \"No CAA records found.\";\n }\n case \"SOA\": {\n const soa = records as SoaRecord[];\n const s = soa[0];\n if (!s) return \"No SOA record found.\";\n return [\n `nsname: ${s.nsname}`,\n `hostmaster: ${s.hostmaster}`,\n `serial: ${s.serial}`,\n `refresh: ${s.refresh}`,\n `retry: ${s.retry}`,\n `expire: ${s.expire}`,\n `minttl: ${s.minttl}`,\n ].join(\"\\n\");\n }\n case \"SRV\": {\n const srv = records as SrvRecord[];\n if (srv.length === 0) return \"No SRV records found.\";\n return srv\n .map((r) => `${r.priority} ${r.weight} ${r.port} ${r.name}`)\n .join(\"\\n\");\n }\n default: {\n const arr = records as string[];\n if (arr.length === 0) return `No ${type} records found.`;\n return arr.join(\"\\n\");\n }\n }\n}\n\nexport async function reverseDns(ip: string): Promise<string> {\n if (net.isIP(ip) === 0) {\n throw new Error(\"Invalid IP address\");\n }\n let hostnames: string[];\n try {\n hostnames = await dns.reverse(ip);\n } catch (error) {\n return mapDnsError(error, \"PTR\", ip);\n }\n return hostnames.length > 0 ? hostnames.join(\"\\n\") : \"No PTR records found.\";\n}\n\nexport async function resolveAll(domain: string): Promise<string> {\n assertValidDomain(domain);\n const types: { name: string; type: RecordType }[] = [\n { name: \"A\", type: \"A\" },\n { name: \"AAAA\", type: \"AAAA\" },\n { name: \"MX\", type: \"MX\" },\n { name: \"TXT\", type: \"TXT\" },\n { name: \"CAA\", type: \"CAA\" },\n { name: \"NS\", type: \"NS\" },\n { name: \"CNAME\", type: \"CNAME\" },\n ];\n\n const results: string[] = [];\n for (const { name, type } of types) {\n try {\n const records = await dnsLookup(domain, type);\n results.push(`=== ${name} ===\\n${records}`);\n } catch {\n results.push(`=== ${name} ===\\n(no records or error)`);\n }\n }\n return results.join(\"\\n\\n\");\n}\n\nexport async function checkNameservers(domain: string): Promise<string> {\n assertValidDomain(domain);\n let nameservers: string[];\n try {\n nameservers = await dns.resolveNs(domain);\n } catch (error) {\n return mapDnsError(error, \"NS\", domain);\n }\n return nameservers.length > 0\n ? nameservers.join(\"\\n\")\n : \"No nameserver records found.\";\n}\n\nexport async function whoisLookup(domain: string): Promise<string> {\n return await domainRegistrationLookup(domain);\n}\n\nexport async function whoisLookupResult(\n domain: string,\n): Promise<RegistrationLookupResult> {\n return await domainRegistrationLookupResult(domain);\n}\n\nexport async function ipWhois(ip: string): Promise<string> {\n return await ipRegistrationLookup(ip);\n}\n\nexport async function ipWhoisResult(\n ip: string,\n): Promise<RegistrationLookupResult> {\n return await ipRegistrationLookupResult(ip);\n}\n","import dns from \"node:dns/promises\";\nimport net from \"node:net\";\nimport { domainToASCII } from \"node:url\";\nimport { Agent, fetch as undiciFetch } from \"undici\";\n\nconst RIPESTAT_WHOIS_ENDPOINT = \"https://stat.ripe.net/data/whois/data.json\";\nconst RIPESTAT_SOURCE_APP = \"mcp-dns-tools\";\nconst RDAP_DNS_BOOTSTRAP = \"https://data.iana.org/rdap/dns.json\";\nconst RDAP_IPV4_BOOTSTRAP = \"https://data.iana.org/rdap/ipv4.json\";\nconst RDAP_IPV6_BOOTSTRAP = \"https://data.iana.org/rdap/ipv6.json\";\nconst BOOTSTRAP_TTL_MS = 24 * 60 * 60 * 1000;\nconst REQUEST_TIMEOUT_MS = 10_000;\nconst MAX_REDIRECTS = 3;\nconst MAX_RDAP_BYTES = 1024 * 1024;\nconst MAX_BOOTSTRAP_BYTES = 2 * 1024 * 1024;\nconst MAX_WHOIS_BYTES = 1024 * 1024;\nconst MAX_WHOIS_QUERIES = 3;\n\ninterface BootstrapData {\n services: unknown[];\n}\n\ninterface BootstrapCacheEntry {\n data: BootstrapData;\n expiresAt: number;\n}\n\ninterface RdapResponse {\n data: Record<string, unknown>;\n source: string;\n}\n\ninterface WhoisEndpoint {\n host: string;\n port: number;\n}\n\ninterface ResolvedAddress {\n address: string;\n family: 4 | 6;\n}\n\nexport interface RegistrationLookupResult {\n /** Human-readable lookup output; embeds any fallback warnings as `Warning:` lines. */\n text: string;\n /**\n * True when no source returned data. When false but the text contains warning\n * lines, data was retrieved from a fallback source (for example RIPEstat) that\n * may lag the authoritative source.\n */\n failed: boolean;\n}\n\nexport type RegistrationReason =\n | \"RIPESTAT_NOT_FOUND\"\n | \"RIPESTAT_RATE_LIMITED\"\n | \"RIPESTAT_TIMEOUT\"\n | \"RIPESTAT_NETWORK_ERROR\"\n | \"RIPESTAT_HTTP_ERROR\"\n | \"RIPESTAT_INVALID_RESPONSE\"\n | \"RIPESTAT_DESTINATION_REJECTED\"\n | \"RDAP_NOT_AVAILABLE\"\n | \"RDAP_NOT_FOUND\"\n | \"RDAP_RATE_LIMITED\"\n | \"RDAP_TIMEOUT\"\n | \"RDAP_NETWORK_ERROR\"\n | \"RDAP_HTTP_ERROR\"\n | \"RDAP_INVALID_RESPONSE\"\n | \"RDAP_DESTINATION_REJECTED\"\n | \"WHOIS_NOT_ADVERTISED\"\n | \"WHOIS_NOT_FOUND\"\n | \"WHOIS_CONNECTION_REFUSED\"\n | \"WHOIS_CONNECTION_RESET\"\n | \"WHOIS_TIMEOUT\"\n | \"WHOIS_DNS_FAILURE\"\n | \"WHOIS_EMPTY_RESPONSE\"\n | \"WHOIS_RATE_LIMITED\"\n | \"WHOIS_SERVICE_RETIRED\"\n | \"WHOIS_WEB_ONLY\"\n | \"WHOIS_UNSUPPORTED_RESPONSE\"\n | \"WHOIS_INVALID_ENCODING\"\n | \"REFERRAL_REJECTED\"\n | \"REFERRAL_LOOP\"\n | \"REFERRAL_LIMIT_REACHED\"\n | \"RESPONSE_TOO_LARGE\"\n | \"UNKNOWN_ERROR\";\n\ninterface RegistrationWarning {\n reason: RegistrationReason;\n detail: string;\n}\n\nclass RegistrationLookupError extends Error {\n constructor(\n message: string,\n readonly kind:\n | \"invalid-response\"\n | \"network\"\n | \"not-found\"\n | \"rate-limited\"\n | \"security\"\n | \"unsupported\",\n readonly source?: string,\n readonly reason?: RegistrationReason,\n ) {\n super(message);\n this.name = \"RegistrationLookupError\";\n }\n}\n\nfunction ensureRegistrationErrorSource(\n error: unknown,\n source: string,\n): unknown {\n if (!(error instanceof RegistrationLookupError) || error.source !== undefined)\n return error;\n return new RegistrationLookupError(\n error.message,\n error.kind,\n source,\n error.reason,\n );\n}\n\nconst bootstrapCache = new Map<string, BootstrapCacheEntry>();\n\nconst blockedAddresses = new net.BlockList();\nconst syntheticHttpsProxyAddresses = new net.BlockList();\n// Some sandboxed network transports map public hosts into this benchmarking range.\nsyntheticHttpsProxyAddresses.addSubnet(\"198.18.0.0\", 15, \"ipv4\");\nfor (const [address, prefix] of [\n [\"0.0.0.0\", 8],\n [\"10.0.0.0\", 8],\n [\"100.64.0.0\", 10],\n [\"127.0.0.0\", 8],\n [\"169.254.0.0\", 16],\n [\"172.16.0.0\", 12],\n [\"192.0.0.0\", 24],\n [\"192.0.2.0\", 24],\n [\"192.168.0.0\", 16],\n [\"198.18.0.0\", 15],\n [\"198.51.100.0\", 24],\n [\"203.0.113.0\", 24],\n [\"224.0.0.0\", 4],\n [\"240.0.0.0\", 4],\n] as const) {\n blockedAddresses.addSubnet(address, prefix, \"ipv4\");\n}\nfor (const [address, prefix] of [\n [\"::\", 128],\n [\"::1\", 128],\n [\"64:ff9b:1::\", 48],\n [\"100::\", 64],\n [\"2001:db8::\", 32],\n [\"fc00::\", 7],\n [\"fe80::\", 10],\n [\"fec0::\", 10],\n [\"ff00::\", 8],\n] as const) {\n blockedAddresses.addSubnet(address, prefix, \"ipv6\");\n}\n\nexport function resetRegistrationCaches(): void {\n bootstrapCache.clear();\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringValue(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.trim()) return value.trim();\n if (Array.isArray(value)) {\n const values = value\n .map((entry) => stringValue(entry))\n .filter((entry): entry is string => entry !== undefined);\n return values.length > 0 ? values.join(\", \") : undefined;\n }\n return undefined;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter(\n (entry): entry is string => typeof entry === \"string\" && entry.length > 0,\n );\n}\n\nfunction isBlockedAddress(address: string): boolean {\n const family = net.isIP(address);\n if (family === 4) return blockedAddresses.check(address, \"ipv4\");\n if (family === 6) return blockedAddresses.check(address, \"ipv6\");\n return true;\n}\n\nasync function resolvePublicHostname(\n hostname: string,\n allowSyntheticNetworkProxy = false,\n): Promise<ResolvedAddress[]> {\n const normalised = hostname\n .replace(/^\\[|\\]$/g, \"\")\n .replace(/\\.$/, \"\")\n .toLowerCase();\n if (\n !normalised ||\n normalised === \"localhost\" ||\n normalised.endsWith(\".local\")\n ) {\n throw new RegistrationLookupError(\n `Refusing registration-data connection to ${hostname}`,\n \"security\",\n );\n }\n\n if (net.isIP(normalised) !== 0) {\n if (isBlockedAddress(normalised)) {\n throw new RegistrationLookupError(\n `Refusing registration-data connection to non-public address ${hostname}`,\n \"security\",\n );\n }\n return [\n {\n address: normalised,\n family: net.isIP(normalised) as 4 | 6,\n },\n ];\n }\n\n let addresses: { address: string; family: number }[];\n try {\n addresses = await dns.lookup(normalised, {\n all: true,\n verbatim: true,\n });\n } catch (error) {\n throw new RegistrationLookupError(\n `Unable to resolve registration-data service ${hostname}: ${errorMessage(error)}`,\n \"network\",\n );\n }\n\n const resolved = addresses.filter(\n (entry): entry is ResolvedAddress =>\n entry.family === 4 || entry.family === 6,\n );\n if (\n resolved.length === 0 ||\n resolved.some(\n (entry) =>\n isBlockedAddress(entry.address) &&\n !(\n allowSyntheticNetworkProxy &&\n entry.family === 4 &&\n syntheticHttpsProxyAddresses.check(entry.address, \"ipv4\")\n ),\n )\n ) {\n throw new RegistrationLookupError(\n `Refusing registration-data connection to ${hostname}: destination is not public`,\n \"security\",\n );\n }\n return resolved;\n}\n\nfunction pinnedLookup(addresses: ResolvedAddress[]): net.LookupFunction {\n return (_hostname, options, callback): void => {\n const requestedFamily = options.family ?? 0;\n const candidates = addresses.filter(\n (entry) => requestedFamily === 0 || entry.family === requestedFamily,\n );\n if (candidates.length === 0) {\n const error = new Error(\n `No validated address for requested family ${requestedFamily}`,\n ) as NodeJS.ErrnoException;\n error.code = \"EAI_ADDRFAMILY\";\n callback(error, \"\");\n return;\n }\n if (options.all) {\n callback(null, candidates);\n return;\n }\n const [selected] = candidates;\n if (!selected) {\n callback(new Error(\"No validated address available\"), \"\");\n return;\n }\n callback(null, selected.address, selected.family);\n };\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"unknown error\";\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return error instanceof Error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\nfunction reasonForError(\n protocol: \"RDAP\" | \"WHOIS\" | \"RIPESTAT\",\n error: unknown,\n): RegistrationReason {\n if (error instanceof RegistrationLookupError && error.reason)\n return error.reason;\n\n const message = errorMessage(error).toLowerCase();\n const code = errorCode(error);\n if (message.includes(\"exceeds\") && message.includes(\"bytes\"))\n return \"RESPONSE_TOO_LARGE\";\n if (message.includes(\"referral loop\")) return \"REFERRAL_LOOP\";\n if (message.includes(\"referral limit\")) return \"REFERRAL_LIMIT_REACHED\";\n\n if (protocol === \"RIPESTAT\") {\n if (error instanceof RegistrationLookupError && error.kind === \"not-found\")\n return \"RIPESTAT_NOT_FOUND\";\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"rate-limited\"\n )\n return \"RIPESTAT_RATE_LIMITED\";\n if (message.includes(\"timed out\") || code === \"ETIMEDOUT\")\n return \"RIPESTAT_TIMEOUT\";\n if (message.includes(\"http\")) return \"RIPESTAT_HTTP_ERROR\";\n if (error instanceof RegistrationLookupError && error.kind === \"security\")\n return \"RIPESTAT_DESTINATION_REJECTED\";\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"invalid-response\"\n )\n return \"RIPESTAT_INVALID_RESPONSE\";\n return \"RIPESTAT_NETWORK_ERROR\";\n }\n\n if (protocol === \"RDAP\") {\n if (error instanceof RegistrationLookupError && error.kind === \"not-found\")\n return \"RDAP_NOT_FOUND\";\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"rate-limited\"\n )\n return \"RDAP_RATE_LIMITED\";\n if (message.includes(\"timed out\") || code === \"ETIMEDOUT\")\n return \"RDAP_TIMEOUT\";\n if (message.includes(\"http \")) return \"RDAP_HTTP_ERROR\";\n if (error instanceof RegistrationLookupError && error.kind === \"security\")\n return \"RDAP_DESTINATION_REJECTED\";\n if (\n error instanceof RegistrationLookupError &&\n (error.kind === \"invalid-response\" || error.kind === \"unsupported\")\n )\n return error.kind === \"unsupported\"\n ? \"RDAP_NOT_AVAILABLE\"\n : \"RDAP_INVALID_RESPONSE\";\n return \"RDAP_NETWORK_ERROR\";\n }\n\n if (code === \"ECONNREFUSED\") return \"WHOIS_CONNECTION_REFUSED\";\n if (code === \"ECONNRESET\") return \"WHOIS_CONNECTION_RESET\";\n if (code === \"ENOTFOUND\" || code === \"EAI_AGAIN\") return \"WHOIS_DNS_FAILURE\";\n if (message.includes(\"unable to resolve registration-data service\"))\n return \"WHOIS_DNS_FAILURE\";\n if (message.includes(\"timed out\") || code === \"ETIMEDOUT\")\n return \"WHOIS_TIMEOUT\";\n if (message.includes(\"no whois data\")) return \"WHOIS_EMPTY_RESPONSE\";\n if (error instanceof RegistrationLookupError && error.kind === \"unsupported\")\n return \"WHOIS_NOT_ADVERTISED\";\n if (error instanceof RegistrationLookupError && error.kind === \"rate-limited\")\n return \"WHOIS_RATE_LIMITED\";\n if (error instanceof RegistrationLookupError && error.kind === \"security\")\n return \"REFERRAL_REJECTED\";\n return \"UNKNOWN_ERROR\";\n}\n\nfunction warningText(warning: RegistrationWarning): string {\n return `${warning.reason}: ${warning.detail}`;\n}\n\nfunction failureSuggestion(\n rdapReason: RegistrationReason,\n whoisReason: RegistrationReason,\n ripestatReason?: RegistrationReason,\n): string {\n if (\n rdapReason === \"RDAP_RATE_LIMITED\" ||\n whoisReason === \"WHOIS_RATE_LIMITED\" ||\n ripestatReason === \"RIPESTAT_RATE_LIMITED\"\n )\n return \"Retry later and reduce lookup frequency.\";\n if (\n ripestatReason !== undefined &&\n (rdapReason === \"RDAP_NETWORK_ERROR\" ||\n rdapReason === \"RDAP_TIMEOUT\" ||\n rdapReason === \"RDAP_DESTINATION_REJECTED\")\n )\n return \"Check outbound HTTPS access to the RDAP service, then retry.\";\n if (ripestatReason === \"RIPESTAT_NOT_FOUND\")\n return \"No RIPEstat registration data was found; consult the RIR whois database directly.\";\n if (ripestatReason !== undefined)\n return \"Check outbound HTTPS access to stat.ripe.net, then retry.\";\n if (whoisReason === \"WHOIS_WEB_ONLY\")\n return \"Use the registry's web-based registration lookup service.\";\n if (whoisReason === \"WHOIS_SERVICE_RETIRED\")\n return \"Use the registry's RDAP or web-based replacement service.\";\n if (\n whoisReason === \"WHOIS_CONNECTION_REFUSED\" ||\n whoisReason === \"WHOIS_CONNECTION_RESET\" ||\n whoisReason === \"WHOIS_TIMEOUT\" ||\n whoisReason === \"WHOIS_DNS_FAILURE\"\n )\n return \"Check outbound HTTPS and TCP port 43 access, then retry.\";\n if (\n whoisReason === \"WHOIS_NOT_ADVERTISED\" ||\n whoisReason === \"WHOIS_UNSUPPORTED_RESPONSE\"\n )\n return \"Consult the TLD registry website for its supported lookup service.\";\n if (whoisReason === \"REFERRAL_REJECTED\" || whoisReason === \"REFERRAL_LOOP\")\n return \"Use the last authoritative source shown or consult the registry website.\";\n return \"Retry later or consult the registry's registration-data service.\";\n}\n\nfunction formatLookupFailure(\n queryType: \"Domain\" | \"IP\",\n query: string,\n rdapError: unknown,\n whoisError: unknown,\n ripestatError?: unknown,\n): string {\n const rdapReason = reasonForError(\"RDAP\", rdapError);\n const whoisReason = reasonForError(\"WHOIS\", whoisError);\n const ripestatReason = ripestatError\n ? reasonForError(\"RIPESTAT\", ripestatError)\n : undefined;\n const rdapSource =\n rdapError instanceof RegistrationLookupError ? rdapError.source : undefined;\n const whoisSource =\n whoisError instanceof RegistrationLookupError\n ? whoisError.source\n : undefined;\n return [\n \"Status: failed\",\n `${queryType}: ${query}`,\n \"RDAP status: failed\",\n `RDAP reason: ${rdapReason}`,\n ...(rdapSource ? [`RDAP source: ${rdapSource}`] : []),\n `RDAP detail: ${errorMessage(rdapError)}`,\n \"WHOIS status: failed\",\n `WHOIS reason: ${whoisReason}`,\n ...(whoisSource ? [`WHOIS source: ${whoisSource}`] : []),\n `WHOIS detail: ${errorMessage(whoisError)}`,\n ...(ripestatError\n ? [\n \"RIPEstat status: failed\",\n `RIPEstat reason: ${ripestatReason}`,\n `RIPEstat detail: ${errorMessage(ripestatError)}`,\n ]\n : []),\n `Suggestion: ${failureSuggestion(rdapReason, whoisReason, ripestatReason)}`,\n ].join(\"\\n\");\n}\n\nasync function readResponseBody(\n response: Response,\n maximumBytes: number,\n): Promise<string> {\n const contentLength = response.headers.get(\"content-length\");\n if (contentLength && Number(contentLength) > maximumBytes) {\n await response.body?.cancel();\n throw new RegistrationLookupError(\n `Registration-data response exceeds ${maximumBytes} bytes`,\n \"invalid-response\",\n );\n }\n\n if (!response.body) return \"\";\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maximumBytes) {\n try {\n await reader.cancel();\n } catch {\n // The size-limit error below is more useful than a cancellation error.\n }\n throw new RegistrationLookupError(\n `Registration-data response exceeds ${maximumBytes} bytes`,\n \"invalid-response\",\n );\n }\n chunks.push(value);\n }\n\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(body);\n}\n\nfunction validateHttpsUrl(value: string): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new RegistrationLookupError(\n `Invalid RDAP service URL: ${value}`,\n \"invalid-response\",\n );\n }\n if (\n url.protocol !== \"https:\" ||\n url.username ||\n url.password ||\n (url.port && url.port !== \"443\")\n ) {\n throw new RegistrationLookupError(\n `Refusing non-standard RDAP service URL: ${value}`,\n \"security\",\n );\n }\n return url;\n}\n\ntype JsonProtocol = \"RDAP\" | \"RIPESTAT\";\n\nfunction jsonProtocolLabel(protocol: JsonProtocol): string {\n return protocol === \"RIPESTAT\" ? \"RIPEstat\" : \"RDAP\";\n}\n\nfunction jsonProtocolAccept(protocol: JsonProtocol): string {\n return protocol === \"RIPESTAT\"\n ? \"application/json\"\n : \"application/rdap+json, application/json\";\n}\n\nfunction jsonProtocolTimeoutReason(protocol: JsonProtocol): RegistrationReason {\n return protocol === \"RIPESTAT\" ? \"RIPESTAT_TIMEOUT\" : \"RDAP_TIMEOUT\";\n}\n\nasync function fetchJson(\n initialUrl: string,\n maximumBytes: number,\n protocol: JsonProtocol = \"RDAP\",\n): Promise<{ data: Record<string, unknown>; source: string }> {\n const label = jsonProtocolLabel(protocol);\n const timeoutReason = jsonProtocolTimeoutReason(protocol);\n let url = validateHttpsUrl(initialUrl);\n\n for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {\n let addresses: ResolvedAddress[];\n try {\n addresses = await resolvePublicHostname(url.hostname, true);\n } catch (error) {\n throw ensureRegistrationErrorSource(error, url.href);\n }\n const dispatcher = new Agent({\n connect: { lookup: pinnedLookup(addresses) },\n });\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n try {\n const response = (await undiciFetch(url, {\n headers: {\n accept: jsonProtocolAccept(protocol),\n \"user-agent\": \"mcp-dns-tools/registration-lookup\",\n },\n dispatcher,\n redirect: \"manual\",\n signal: controller.signal,\n })) as unknown as Response;\n\n if ([301, 302, 303, 307, 308].includes(response.status)) {\n const location = response.headers.get(\"location\");\n if (!location) {\n throw new RegistrationLookupError(\n `${label} redirect from ${url.hostname} has no location`,\n \"invalid-response\",\n );\n }\n if (redirects === MAX_REDIRECTS) {\n throw new RegistrationLookupError(\n `${label} redirect limit exceeded`,\n \"invalid-response\",\n );\n }\n await response.body?.cancel();\n url = validateHttpsUrl(new URL(location, url).href);\n continue;\n }\n\n const body = await readResponseBody(response, maximumBytes);\n if (response.status === 404) {\n throw new RegistrationLookupError(\n \"Registration data not found\",\n \"not-found\",\n url.href,\n );\n }\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n throw new RegistrationLookupError(\n `${label} service rate limited the request${retryAfter ? `; retry after ${retryAfter}` : \"\"}`,\n \"rate-limited\",\n );\n }\n if (!response.ok) {\n throw new RegistrationLookupError(\n `${label} service returned HTTP ${response.status}`,\n \"network\",\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new RegistrationLookupError(\n `${label} service ${url.hostname} returned invalid JSON`,\n \"invalid-response\",\n );\n }\n if (!isRecord(parsed)) {\n throw new RegistrationLookupError(\n `${label} service ${url.hostname} returned an invalid object`,\n \"invalid-response\",\n );\n }\n return { data: parsed, source: url.href };\n } catch (error) {\n if (controller.signal.aborted) {\n throw new RegistrationLookupError(\n `Request to ${url.hostname} timed out`,\n \"network\",\n url.href,\n timeoutReason,\n );\n }\n const sourcedError = ensureRegistrationErrorSource(error, url.href);\n if (sourcedError instanceof RegistrationLookupError) throw sourcedError;\n throw new RegistrationLookupError(\n `Request to ${url.hostname} failed: ${errorMessage(sourcedError)}`,\n \"network\",\n url.href,\n );\n } finally {\n clearTimeout(timeout);\n await dispatcher.close();\n }\n }\n\n throw new RegistrationLookupError(`${label} request failed`, \"network\");\n}\n\nasync function getBootstrap(url: string): Promise<BootstrapData> {\n const cached = bootstrapCache.get(url);\n if (cached && cached.expiresAt > Date.now()) return cached.data;\n\n const response = await fetchJson(url, MAX_BOOTSTRAP_BYTES);\n const services = response.data.services;\n if (!Array.isArray(services)) {\n throw new RegistrationLookupError(\n \"IANA RDAP bootstrap response has no services array\",\n \"invalid-response\",\n );\n }\n const data = { services };\n bootstrapCache.set(url, { data, expiresAt: Date.now() + BOOTSTRAP_TTL_MS });\n return data;\n}\n\nfunction bootstrapServices(\n data: BootstrapData,\n): { entries: string[]; urls: string[] }[] {\n const services: { entries: string[]; urls: string[] }[] = [];\n for (const service of data.services) {\n if (!Array.isArray(service) || service.length !== 2) continue;\n const entries = stringArray(service[0]).map((entry) => entry.toLowerCase());\n const urls = stringArray(service[1]).filter((url) =>\n url.startsWith(\"https://\"),\n );\n if (entries.length > 0 && urls.length > 0) services.push({ entries, urls });\n }\n return services;\n}\n\nfunction domainServiceUrls(data: BootstrapData, domain: string): string[] {\n let longestMatch = -1;\n let urls: string[] = [];\n for (const service of bootstrapServices(data)) {\n for (const entry of service.entries) {\n if (domain !== entry && !domain.endsWith(`.${entry}`)) continue;\n const labels = entry.split(\".\").length;\n if (labels > longestMatch) {\n longestMatch = labels;\n urls = [...service.urls];\n } else if (labels === longestMatch) {\n urls.push(...service.urls);\n }\n }\n }\n return [...new Set(urls)];\n}\n\nfunction ipServiceUrls(data: BootstrapData, ip: string): string[] {\n const family = net.isIP(ip);\n const type = family === 4 ? \"ipv4\" : \"ipv6\";\n let longestPrefix = -1;\n let urls: string[] = [];\n\n for (const service of bootstrapServices(data)) {\n for (const entry of service.entries) {\n const [network, rawPrefix] = entry.split(\"/\");\n const prefix = Number(rawPrefix);\n if (!network || !Number.isInteger(prefix) || net.isIP(network) !== family)\n continue;\n try {\n const block = new net.BlockList();\n block.addSubnet(network, prefix, type);\n if (!block.check(ip, type)) continue;\n } catch {\n continue;\n }\n if (prefix > longestPrefix) {\n longestPrefix = prefix;\n urls = [...service.urls];\n } else if (prefix === longestPrefix) {\n urls.push(...service.urls);\n }\n }\n }\n return [...new Set(urls)];\n}\n\nasync function queryFirstRdapService(\n baseUrls: string[],\n path: string,\n): Promise<RdapResponse> {\n let lastError: unknown;\n for (const baseUrl of baseUrls) {\n try {\n const base = validateHttpsUrl(baseUrl);\n if (!base.pathname.endsWith(\"/\")) base.pathname += \"/\";\n const queryUrl = new URL(path, base);\n return await fetchJson(queryUrl.href, MAX_RDAP_BYTES);\n } catch (error) {\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"not-found\"\n ) {\n throw error;\n }\n lastError = error;\n }\n }\n throw (\n lastError ??\n new RegistrationLookupError(\"No usable RDAP service\", \"unsupported\")\n );\n}\n\nfunction relatedRdapUrl(data: Record<string, unknown>): string | undefined {\n if (!Array.isArray(data.links)) return undefined;\n for (const value of data.links) {\n if (!isRecord(value) || value.rel !== \"related\") continue;\n const href = stringValue(value.href);\n const type = stringValue(value.type);\n if (href && type?.toLowerCase().includes(\"application/rdap+json\"))\n return href;\n }\n return undefined;\n}\n\nfunction eventLines(data: Record<string, unknown>): string[] {\n if (!Array.isArray(data.events)) return [];\n const labels: Record<string, string> = {\n registration: \"Registered\",\n expiration: \"Expires\",\n \"last changed\": \"Updated\",\n \"last update of RDAP database\": \"RDAP database updated\",\n };\n const lines: string[] = [];\n for (const event of data.events) {\n if (!isRecord(event)) continue;\n const action = stringValue(event.eventAction);\n const date = stringValue(event.eventDate);\n if (action && date) lines.push(`${labels[action] ?? action}: ${date}`);\n }\n return lines;\n}\n\nfunction vcardFields(entity: Record<string, unknown>): Map<string, string[]> {\n const fields = new Map<string, string[]>();\n if (!Array.isArray(entity.vcardArray) || !Array.isArray(entity.vcardArray[1]))\n return fields;\n for (const property of entity.vcardArray[1]) {\n if (!Array.isArray(property) || property.length < 4) continue;\n const name = stringValue(property[0])?.toLowerCase();\n const value = stringValue(property[3]);\n if (!name || !value) continue;\n fields.set(name, [...(fields.get(name) ?? []), value]);\n }\n return fields;\n}\n\nfunction entityLines(data: Record<string, unknown>): string[] {\n if (!Array.isArray(data.entities)) return [];\n const lines: string[] = [];\n const visit = (entity: unknown): void => {\n if (!isRecord(entity)) return;\n const roles = stringArray(entity.roles);\n const fields = vcardFields(entity);\n const name = fields.get(\"fn\")?.[0] ?? fields.get(\"org\")?.[0];\n const handle = stringValue(entity.handle);\n const identity = name ?? handle;\n if (identity) {\n const publicIds = Array.isArray(entity.publicIds)\n ? entity.publicIds\n .map((value) => {\n if (!isRecord(value)) return undefined;\n const type = stringValue(value.type);\n const identifier = stringValue(value.identifier);\n return type && identifier ? `${type} ${identifier}` : undefined;\n })\n .filter((value): value is string => value !== undefined)\n : [];\n const details = [\n ...publicIds,\n ...(fields.get(\"email\") ?? []).map((value) => `email ${value}`),\n ...(fields.get(\"tel\") ?? []).map((value) => `telephone ${value}`),\n ];\n lines.push(\n `Entity${roles.length > 0 ? ` (${roles.join(\", \")})` : \"\"}: ${identity}${details.length > 0 ? `; ${details.join(\"; \")}` : \"\"}`,\n );\n }\n if (Array.isArray(entity.entities)) entity.entities.forEach(visit);\n };\n data.entities.forEach(visit);\n return [...new Set(lines)];\n}\n\nfunction noticeTitles(data: Record<string, unknown>): string[] {\n if (!Array.isArray(data.notices)) return [];\n return data.notices\n .map((notice) => (isRecord(notice) ? stringValue(notice.title) : undefined))\n .filter((title): title is string => title !== undefined);\n}\n\nfunction formatDomainRdap(\n responses: RdapResponse[],\n requestedDomain: string,\n warnings: string[],\n): string {\n const data: Record<string, unknown> = Object.assign(\n {},\n ...responses\n .slice()\n .reverse()\n .map((response) => response.data),\n );\n data.entities = responses.flatMap((response) =>\n Array.isArray(response.data.entities) ? response.data.entities : [],\n );\n data.notices = responses.flatMap((response) =>\n Array.isArray(response.data.notices) ? response.data.notices : [],\n );\n data.events = responses.flatMap((response) =>\n Array.isArray(response.data.events) ? response.data.events : [],\n );\n const lines = [\n \"Protocol: RDAP\",\n ...responses.map((response) => `Source: ${response.source}`),\n `Domain: ${stringValue(data.unicodeName) ?? stringValue(data.ldhName) ?? requestedDomain}`,\n ];\n const handle = stringValue(data.handle);\n if (handle) lines.push(`Registry ID: ${handle}`);\n lines.push(...eventLines(data));\n const statuses = stringArray(data.status);\n if (statuses.length > 0) lines.push(`Status: ${statuses.join(\", \")}`);\n\n if (Array.isArray(data.nameservers)) {\n const nameservers = data.nameservers\n .map((value) =>\n isRecord(value)\n ? (stringValue(value.unicodeName) ?? stringValue(value.ldhName))\n : undefined,\n )\n .filter((value): value is string => value !== undefined);\n if (nameservers.length > 0)\n lines.push(`Nameservers: ${nameservers.join(\", \")}`);\n }\n if (isRecord(data.secureDNS)) {\n const signed = data.secureDNS.delegationSigned;\n if (typeof signed === \"boolean\")\n lines.push(`DNSSEC: ${signed ? \"signed\" : \"unsigned\"}`);\n }\n lines.push(...entityLines(data));\n const notices = noticeTitles(data);\n if (notices.length > 0) lines.push(`Notices: ${notices.join(\"; \")}`);\n lines.push(...warnings.map((warning) => `Warning: ${warning}`));\n return lines.join(\"\\n\");\n}\n\nfunction formatIpRdap(response: RdapResponse, ip: string): string {\n const { data } = response;\n const lines = [\"Protocol: RDAP\", `Source: ${response.source}`, `IP: ${ip}`];\n for (const [label, key] of [\n [\"Network\", \"name\"],\n [\"Handle\", \"handle\"],\n [\"Start address\", \"startAddress\"],\n [\"End address\", \"endAddress\"],\n [\"IP version\", \"ipVersion\"],\n [\"Type\", \"type\"],\n [\"Country\", \"country\"],\n [\"Parent handle\", \"parentHandle\"],\n ] as const) {\n const value = stringValue(data[key]);\n if (value) lines.push(`${label}: ${value}`);\n }\n const statuses = stringArray(data.status);\n if (statuses.length > 0) lines.push(`Status: ${statuses.join(\", \")}`);\n lines.push(...eventLines(data), ...entityLines(data));\n const notices = noticeTitles(data);\n if (notices.length > 0) lines.push(`Notices: ${notices.join(\"; \")}`);\n return lines.join(\"\\n\");\n}\n\nexport function normaliseRegistrationDomain(domain: string): string {\n const candidate = domain.trim().replace(/\\.$/, \"\");\n const containsControlCharacter = [...candidate].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || codePoint === 0x7f;\n });\n if (!candidate || containsControlCharacter) {\n throw new Error(\"Invalid domain\");\n }\n const ascii = domainToASCII(candidate).toLowerCase();\n if (!ascii || ascii.length > 253) throw new Error(\"Invalid domain\");\n const labels = ascii.split(\".\");\n if (\n labels.some(\n (label) =>\n label.length === 0 ||\n label.length > 63 ||\n !/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label),\n )\n ) {\n throw new Error(\"Invalid domain\");\n }\n return ascii;\n}\n\nfunction ianaWhoisDiscoveryQuery(domain: string): string {\n // IANA registry referrals are keyed by the DNS root TLD, not an effective\n // public suffix. For example, both example.co.uk and example.me.uk use uk.\n return domain.split(\".\").at(-1) ?? domain;\n}\n\nfunction parseWhoisEndpoint(\n value: string,\n allowWebScheme = false,\n): WhoisEndpoint {\n const candidate = value.includes(\"://\") ? value : `whois://${value}`;\n let url: URL;\n try {\n url = new URL(candidate);\n } catch {\n throw new RegistrationLookupError(\n `Invalid WHOIS referral: ${value}`,\n \"invalid-response\",\n undefined,\n \"REFERRAL_REJECTED\",\n );\n }\n const webScheme = url.protocol === \"http:\" || url.protocol === \"https:\";\n const port = webScheme ? 43 : url.port ? Number(url.port) : 43;\n if (\n (url.protocol !== \"whois:\" && !(allowWebScheme && webScheme)) ||\n !url.hostname ||\n url.username ||\n url.password ||\n (url.pathname && url.pathname !== \"/\") ||\n url.search ||\n url.hash ||\n (!webScheme && url.port && url.port !== \"43\")\n ) {\n throw new RegistrationLookupError(\n `Refusing unsafe WHOIS referral: ${value}`,\n \"security\",\n undefined,\n \"REFERRAL_REJECTED\",\n );\n }\n return { host: url.hostname.replace(/^\\[|\\]$/g, \"\").toLowerCase(), port };\n}\n\nfunction whoisReferral(response: string): WhoisEndpoint | undefined {\n for (const [pattern, allowWebScheme] of [\n [/^refer:[ \\t]*(\\S+)/im, false],\n [/^whois:[ \\t]*(\\S+)/im, false],\n [/^Registrar WHOIS Server:[ \\t]*(\\S+)/im, true],\n [/^ReferralServer:[ \\t]*(\\S+)/im, false],\n ] as const) {\n const match = response.match(pattern);\n if (match?.[1]) return parseWhoisEndpoint(match[1].trim(), allowWebScheme);\n }\n return undefined;\n}\n\nfunction inspectWhoisResponse(response: string): {\n notFound: boolean;\n warnings: RegistrationWarning[];\n} {\n const hasRegistrationData =\n /^(?:Domain Name|Domain|domain|NetRange|CIDR|inetnum|network|route):[ \\t]*\\S+/imu.test(\n response,\n );\n if (\n !hasRegistrationData &&\n /(?:rate limit|query limit|quota exceeded|too many quer(?:y|ies)|maximum number of quer(?:y|ies)|try again later)/iu.test(\n response,\n )\n ) {\n throw new RegistrationLookupError(\n \"WHOIS service rate limited the request\",\n \"rate-limited\",\n undefined,\n \"WHOIS_RATE_LIMITED\",\n );\n }\n if (\n !hasRegistrationData &&\n /(?:whois service (?:has been |is )?(?:retired|discontinued)|whois is no longer available)/iu.test(\n response,\n )\n ) {\n throw new RegistrationLookupError(\n \"WHOIS service reports that it has been retired\",\n \"unsupported\",\n undefined,\n \"WHOIS_SERVICE_RETIRED\",\n );\n }\n if (\n !hasRegistrationData &&\n /(?:web[- ]based whois|web whois|visit .{0,80}whois)/isu.test(response)\n ) {\n throw new RegistrationLookupError(\n \"Registry directs queries to a web-based WHOIS service\",\n \"unsupported\",\n undefined,\n \"WHOIS_WEB_ONLY\",\n );\n }\n if (\n !hasRegistrationData &&\n /(?:invalid query|malformed query|unsupported query|syntax error|^usage:)/imu.test(\n response,\n )\n ) {\n throw new RegistrationLookupError(\n \"WHOIS service rejected the query syntax\",\n \"invalid-response\",\n undefined,\n \"WHOIS_UNSUPPORTED_RESPONSE\",\n );\n }\n\n const warnings: RegistrationWarning[] = [];\n if (response.includes(\"\\uFFFD\")) {\n warnings.push({\n reason: \"WHOIS_INVALID_ENCODING\",\n detail: \"WHOIS response contains bytes that are not valid UTF-8\",\n });\n }\n return {\n notFound:\n !hasRegistrationData &&\n /(?:no match for|not found|no entries found|no object found)/iu.test(\n response,\n ),\n warnings,\n };\n}\n\nfunction whoisQueryValue(host: string, query: string): string {\n if (host === \"whois.jprs.jp\" && !query.endsWith(\"/e\")) return `${query}/e`;\n if (host === \"whois.denic.de\") return `-T dn,ace ${query}`;\n return query;\n}\n\nasync function whoisQuery(\n endpoint: WhoisEndpoint,\n query: string,\n): Promise<string> {\n const addresses = await resolvePublicHostname(endpoint.host, true);\n return await new Promise((resolve, reject) => {\n let settled = false;\n let total = 0;\n const chunks: Buffer[] = [];\n const timeoutError = (): RegistrationLookupError =>\n new RegistrationLookupError(\n \"WHOIS query timed out\",\n \"network\",\n undefined,\n \"WHOIS_TIMEOUT\",\n );\n const socket = net.createConnection(\n { ...endpoint, lookup: pinnedLookup(addresses) },\n () => {\n socket.write(`${whoisQueryValue(endpoint.host, query)}\\r\\n`);\n },\n );\n const deadline = setTimeout(\n () => socket.destroy(timeoutError()),\n REQUEST_TIMEOUT_MS,\n );\n const finish = (error?: Error): void => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n if (error) reject(error);\n else resolve(Buffer.concat(chunks).toString(\"utf-8\"));\n };\n socket.on(\"data\", (chunk: Buffer) => {\n total += chunk.byteLength;\n if (total > MAX_WHOIS_BYTES) {\n socket.destroy(\n new RegistrationLookupError(\n `WHOIS response exceeds ${MAX_WHOIS_BYTES} bytes`,\n \"invalid-response\",\n undefined,\n \"RESPONSE_TOO_LARGE\",\n ),\n );\n return;\n }\n chunks.push(chunk);\n });\n socket.on(\"end\", () => finish());\n socket.on(\"error\", (error) => finish(error));\n socket.setTimeout(REQUEST_TIMEOUT_MS, () => {\n socket.destroy(timeoutError());\n });\n });\n}\n\nasync function legacyWhois(\n query: string,\n discoveryQuery = query,\n): Promise<string> {\n let endpoint = { host: \"whois.iana.org\", port: 43 };\n const visited = new Set<string>();\n let response = \"\";\n const warnings: RegistrationWarning[] = [];\n\n for (let index = 0; index < MAX_WHOIS_QUERIES; index += 1) {\n const key = `${endpoint.host}:${endpoint.port}`;\n if (visited.has(key)) {\n throw new RegistrationLookupError(\n \"WHOIS referral loop detected\",\n \"invalid-response\",\n `whois://${endpoint.host}:43`,\n \"REFERRAL_LOOP\",\n );\n }\n visited.add(key);\n try {\n response = (\n await whoisQuery(endpoint, index === 0 ? discoveryQuery : query)\n ).trim();\n } catch (error) {\n throw new RegistrationLookupError(\n errorMessage(error),\n error instanceof RegistrationLookupError ? error.kind : \"network\",\n `whois://${endpoint.host}:43`,\n reasonForError(\"WHOIS\", error),\n );\n }\n\n let referral: WhoisEndpoint | undefined;\n try {\n referral = whoisReferral(response);\n } catch (error) {\n if (index === 0) throw error;\n warnings.push({\n reason: reasonForError(\"WHOIS\", error),\n detail: errorMessage(error),\n });\n break;\n }\n if (!referral) {\n if (index === 0) {\n throw new RegistrationLookupError(\n \"IANA does not advertise a WHOIS service for this query\",\n \"unsupported\",\n \"whois://whois.iana.org:43\",\n \"WHOIS_NOT_ADVERTISED\",\n );\n }\n break;\n }\n const referralKey = `${referral.host}:${referral.port}`;\n if (visited.has(referralKey)) {\n if (referralKey === key) break;\n throw new RegistrationLookupError(\n \"WHOIS referral loop detected\",\n \"invalid-response\",\n `whois://${endpoint.host}:43`,\n \"REFERRAL_LOOP\",\n );\n }\n if (index === MAX_WHOIS_QUERIES - 1) {\n warnings.push({\n reason: \"REFERRAL_LIMIT_REACHED\",\n detail: `WHOIS referral limit of ${MAX_WHOIS_QUERIES} queries reached`,\n });\n break;\n }\n try {\n await resolvePublicHostname(referral.host, true);\n } catch (error) {\n if (index === 0) throw error;\n warnings.push({\n reason: reasonForError(\"WHOIS\", error),\n detail: errorMessage(error),\n });\n break;\n }\n endpoint = referral;\n }\n\n if (!response)\n throw new RegistrationLookupError(\n \"No WHOIS data returned\",\n \"network\",\n `whois://${endpoint.host}:43`,\n \"WHOIS_EMPTY_RESPONSE\",\n );\n let inspection: ReturnType<typeof inspectWhoisResponse>;\n try {\n inspection = inspectWhoisResponse(response);\n } catch (error) {\n throw new RegistrationLookupError(\n errorMessage(error),\n error instanceof RegistrationLookupError\n ? error.kind\n : \"invalid-response\",\n `whois://${endpoint.host}:43`,\n reasonForError(\"WHOIS\", error),\n );\n }\n warnings.push(...inspection.warnings);\n return [\n \"Protocol: WHOIS\",\n `Source: whois://${endpoint.host}:43`,\n ...(inspection.notFound\n ? [\"Status: not registered or not found\", \"Reason: WHOIS_NOT_FOUND\"]\n : []),\n ...warnings.map((warning) => `Warning: ${warningText(warning)}`),\n \"\",\n response,\n ].join(\"\\n\");\n}\n\nasync function ripestatIpLookup(ip: string): Promise<string> {\n const url = new URL(RIPESTAT_WHOIS_ENDPOINT);\n url.searchParams.set(\"resource\", ip);\n url.searchParams.set(\"sourceapp\", RIPESTAT_SOURCE_APP);\n\n const response = await fetchJson(url.href, MAX_RDAP_BYTES, \"RIPESTAT\");\n\n const status = isRecord(response.data)\n ? stringValue(response.data.status)\n : undefined;\n if (status && status.toLowerCase() !== \"ok\") {\n const message = isRecord(response.data)\n ? stringValue(response.data.messages)\n : undefined;\n throw new RegistrationLookupError(\n `RIPEstat API returned error status ${status}${message ? `: ${message}` : \"\"}`,\n \"invalid-response\",\n url.href,\n \"RIPESTAT_INVALID_RESPONSE\",\n );\n }\n\n const topLevel = isRecord(response.data)\n ? (response.data.data as unknown)\n : undefined;\n const records = isRecord(topLevel)\n ? (topLevel.records as unknown)\n : undefined;\n if (\n !Array.isArray(records) ||\n records.length === 0 ||\n records.every((record) => !Array.isArray(record) || record.length === 0)\n ) {\n throw new RegistrationLookupError(\n \"No RIPEstat registration data found for this address\",\n \"not-found\",\n url.href,\n \"RIPESTAT_NOT_FOUND\",\n );\n }\n\n const lines: string[] = [];\n const seen = new Set<string>();\n for (const record of records as unknown[]) {\n if (!Array.isArray(record)) continue;\n for (const entry of record as unknown[]) {\n if (!isRecord(entry)) continue;\n const key = stringValue(entry.key);\n const value = stringValue(entry.value);\n if (!key || !value) continue;\n const line = `${key}: ${value}`;\n if (seen.has(line)) continue;\n seen.add(line);\n lines.push(line);\n }\n }\n\n return [\n \"Protocol: RIPEstat (secondary source; data may lag the RIR whois database)\",\n `Source: ${url.href}`,\n `IP: ${ip}`,\n ...lines,\n ].join(\"\\n\");\n}\n\nfunction fallbackReport(\n error: unknown,\n protocol: \"RDAP\" | \"WHOIS\",\n fallback: string,\n): string {\n const reason =\n error === undefined && protocol === \"RDAP\"\n ? (\"RDAP_NOT_AVAILABLE\" as RegistrationReason)\n : reasonForError(protocol, error);\n const source =\n error instanceof RegistrationLookupError && error.source\n ? ` at ${error.source}`\n : \"\";\n const detail =\n error === undefined ? \"RDAP was not attempted\" : errorMessage(error);\n return `${reason}${source}: ${detail}; used ${fallback}`;\n}\n\nfunction fallbackWarning(error: unknown): string {\n return fallbackReport(error, \"RDAP\", \"WHOIS fallback\");\n}\n\nexport async function domainRegistrationLookupResult(\n domain: string,\n): Promise<RegistrationLookupResult> {\n const normalised = normaliseRegistrationDomain(domain);\n let rdapError: unknown;\n try {\n const bootstrap = await getBootstrap(RDAP_DNS_BOOTSTRAP);\n const urls = domainServiceUrls(bootstrap, normalised);\n if (urls.length > 0) {\n try {\n const registry = await queryFirstRdapService(\n urls,\n `domain/${encodeURIComponent(normalised)}`,\n );\n const responses = [registry];\n const warnings: string[] = [];\n const related = relatedRdapUrl(registry.data);\n if (related) {\n try {\n responses.push(await fetchJson(related, MAX_RDAP_BYTES));\n } catch (error) {\n warnings.push(\n `${reasonForError(\"RDAP\", error)}: registrar RDAP lookup failed: ${errorMessage(error)}`,\n );\n }\n }\n return {\n text: formatDomainRdap(responses, normalised, warnings),\n failed: false,\n };\n } catch (error) {\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"not-found\"\n ) {\n return {\n text: `Protocol: RDAP\\nSource: ${error.source ?? \"authoritative RDAP service\"}\\nDomain: ${normalised}\\nStatus: not registered or not found\\nReason: RDAP_NOT_FOUND`,\n failed: false,\n };\n }\n rdapError = error;\n }\n } else {\n rdapError = new RegistrationLookupError(\n \"IANA has no RDAP bootstrap service for this TLD\",\n \"unsupported\",\n );\n }\n } catch (error) {\n rdapError = error;\n }\n\n try {\n const result = await legacyWhois(\n normalised,\n ianaWhoisDiscoveryQuery(normalised),\n );\n return {\n text: rdapError\n ? `${result}\\n\\nWarning: ${fallbackWarning(rdapError)}`\n : result,\n failed: false,\n };\n } catch (whoisError) {\n if (rdapError) {\n return {\n text: formatLookupFailure(\"Domain\", normalised, rdapError, whoisError),\n failed: true,\n };\n }\n return {\n text: formatLookupFailure(\n \"Domain\",\n normalised,\n new RegistrationLookupError(\n \"RDAP was not attempted\",\n \"unsupported\",\n undefined,\n \"RDAP_NOT_AVAILABLE\",\n ),\n whoisError,\n ),\n failed: true,\n };\n }\n}\n\nexport async function domainRegistrationLookup(\n domain: string,\n): Promise<string> {\n return (await domainRegistrationLookupResult(domain)).text;\n}\n\nexport async function ipRegistrationLookupResult(\n ip: string,\n): Promise<RegistrationLookupResult> {\n const family = net.isIP(ip);\n if (family === 0) throw new Error(\"Invalid IP address\");\n let rdapError: unknown;\n try {\n const bootstrap = await getBootstrap(\n family === 4 ? RDAP_IPV4_BOOTSTRAP : RDAP_IPV6_BOOTSTRAP,\n );\n const urls = ipServiceUrls(bootstrap, ip);\n if (urls.length > 0) {\n try {\n const response = await queryFirstRdapService(\n urls,\n `ip/${encodeURIComponent(ip)}`,\n );\n return { text: formatIpRdap(response, ip), failed: false };\n } catch (error) {\n if (\n error instanceof RegistrationLookupError &&\n error.kind === \"not-found\"\n ) {\n return {\n text: `Protocol: RDAP\\nSource: ${error.source ?? \"authoritative RDAP service\"}\\nIP: ${ip}\\nStatus: registration data not found\\nReason: RDAP_NOT_FOUND`,\n failed: false,\n };\n }\n rdapError = error;\n }\n } else {\n rdapError = new RegistrationLookupError(\n \"IANA has no RDAP bootstrap service for this address\",\n \"unsupported\",\n );\n }\n } catch (error) {\n rdapError = error;\n }\n\n try {\n const result = await legacyWhois(ip);\n return {\n text: rdapError\n ? `${result}\\n\\nWarning: ${fallbackWarning(rdapError)}`\n : result,\n failed: false,\n };\n } catch (whoisError) {\n try {\n const ripestat = await ripestatIpLookup(ip);\n const warnings = [\n `Warning: ${fallbackReport(rdapError, \"RDAP\", \"WHOIS and RIPEstat fallbacks\")}`,\n `Warning: ${fallbackReport(whoisError, \"WHOIS\", \"RIPEstat fallback\")}`,\n ].join(\"\\n\");\n return { text: `${ripestat}\\n\\n${warnings}`, failed: false };\n } catch (ripestatError) {\n const rdapErrorForReport =\n rdapError ??\n new RegistrationLookupError(\n \"RDAP was not attempted\",\n \"unsupported\",\n undefined,\n \"RDAP_NOT_AVAILABLE\",\n );\n return {\n text: formatLookupFailure(\n \"IP\",\n ip,\n rdapErrorForReport,\n whoisError,\n ripestatError,\n ),\n failed: true,\n };\n }\n }\n}\n\nexport async function ipRegistrationLookup(ip: string): Promise<string> {\n return (await ipRegistrationLookupResult(ip)).text;\n}\n","import {\n createServer,\n type IncomingMessage,\n type Server,\n type ServerResponse,\n} from \"node:http\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { createMcpServer } from \"./server.js\";\n\nexport interface HttpServerOptions {\n host: string;\n port: number;\n allowedHosts?: string[];\n}\n\nconst loopbackBindAddresses = new Set([\"127.0.0.1\", \"localhost\", \"::1\"]);\nconst loopbackHostnames = new Set([\"127.0.0.1\", \"localhost\", \"[::1]\"]);\nconst maxRequestBodyBytes = 1024 * 1024;\n\nclass HttpRequestError extends Error {\n constructor(\n message: string,\n readonly statusCode: number,\n readonly rpcCode: number,\n ) {\n super(message);\n }\n}\n\nfunction sendJson(\n response: ServerResponse,\n statusCode: number,\n body: unknown,\n): void {\n response.writeHead(statusCode, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"cache-control\": \"no-store\",\n });\n response.end(JSON.stringify(body));\n}\n\nfunction requestHostname(request: IncomingMessage): string | undefined {\n const host = request.headers.host;\n if (host === undefined) return undefined;\n\n try {\n return new URL(`http://${host}`).hostname;\n } catch {\n return undefined;\n }\n}\n\nfunction allowedHostnames(options: HttpServerOptions): Set<string> | undefined {\n if (options.allowedHosts !== undefined && options.allowedHosts.length > 0) {\n return new Set(options.allowedHosts);\n }\n if (loopbackBindAddresses.has(options.host)) {\n return loopbackHostnames;\n }\n return undefined;\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n const contentLength = request.headers[\"content-length\"];\n if (contentLength !== undefined) {\n const length = Number(contentLength);\n if (!Number.isSafeInteger(length) || length < 0) {\n throw new HttpRequestError(\"Invalid Content-Length\", 400, -32600);\n }\n if (length > maxRequestBodyBytes) {\n throw new HttpRequestError(\"Request body too large\", 413, -32600);\n }\n }\n\n const chunks: Buffer[] = [];\n let size = 0;\n await new Promise<void>((resolve, reject) => {\n const cleanup = () => {\n request.off(\"data\", onData);\n request.off(\"end\", onEnd);\n request.off(\"error\", onError);\n request.off(\"aborted\", onAborted);\n };\n const fail = (error: Error) => {\n request.pause();\n cleanup();\n reject(error);\n };\n const onData = (chunk: Buffer | string) => {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n size += buffer.byteLength;\n if (size > maxRequestBodyBytes) {\n fail(new HttpRequestError(\"Request body too large\", 413, -32600));\n return;\n }\n chunks.push(buffer);\n };\n const onEnd = () => {\n cleanup();\n resolve();\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n const onAborted = () => {\n fail(new HttpRequestError(\"Request body aborted\", 400, -32600));\n };\n\n request.on(\"data\", onData);\n request.once(\"end\", onEnd);\n request.once(\"error\", onError);\n request.once(\"aborted\", onAborted);\n });\n\n try {\n return JSON.parse(Buffer.concat(chunks, size).toString(\"utf8\")) as unknown;\n } catch {\n throw new HttpRequestError(\"Invalid JSON request body\", 400, -32700);\n }\n}\n\nasync function handleMcpRequest(\n request: IncomingMessage,\n response: ServerResponse,\n): Promise<void> {\n let parsedBody: unknown;\n try {\n parsedBody = await readJsonBody(request);\n } catch (error) {\n if (error instanceof HttpRequestError) {\n if (error.statusCode === 413) response.setHeader(\"connection\", \"close\");\n sendJson(response, error.statusCode, {\n jsonrpc: \"2.0\",\n error: { code: error.rpcCode, message: error.message },\n id: null,\n });\n return;\n }\n console.error(\"Failed to read HTTP MCP request:\", error);\n sendJson(response, 400, {\n jsonrpc: \"2.0\",\n error: { code: -32600, message: \"Failed to read request body\" },\n id: null,\n });\n return;\n }\n\n const server = createMcpServer();\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: true,\n });\n\n try {\n await server.connect(transport);\n await transport.handleRequest(request, response, parsedBody);\n } catch (error) {\n console.error(\"HTTP MCP request failed:\", error);\n if (!response.headersSent) {\n sendJson(response, 500, {\n jsonrpc: \"2.0\",\n error: { code: -32603, message: \"Internal server error\" },\n id: null,\n });\n } else if (!response.writableEnded) {\n response.end();\n }\n } finally {\n await Promise.allSettled([transport.close(), server.close()]);\n }\n}\n\nexport async function startHttpServer(\n options: HttpServerOptions,\n): Promise<Server> {\n const acceptedHosts = allowedHostnames(options);\n const httpServer = createServer((request, response) => {\n const pathname = new URL(request.url ?? \"/\", \"http://localhost\").pathname;\n\n if (pathname === \"/health\") {\n if (request.method !== \"GET\") {\n sendJson(response, 405, { error: \"Method not allowed\" });\n return;\n }\n sendJson(response, 200, { status: \"ok\" });\n return;\n }\n\n if (pathname !== \"/mcp\") {\n sendJson(response, 404, { error: \"Not found\" });\n return;\n }\n\n if (request.method !== \"POST\") {\n response.setHeader(\"allow\", \"POST\");\n sendJson(response, 405, {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Method not allowed\" },\n id: null,\n });\n return;\n }\n\n if (acceptedHosts !== undefined) {\n const hostname = requestHostname(request);\n if (hostname === undefined || !acceptedHosts.has(hostname)) {\n sendJson(response, 403, {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Invalid Host header\" },\n id: null,\n });\n return;\n }\n }\n\n void handleMcpRequest(request, response);\n });\n\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n httpServer.off(\"listening\", onListening);\n reject(error);\n };\n const onListening = () => {\n httpServer.off(\"error\", onError);\n resolve();\n };\n httpServer.once(\"error\", onError);\n httpServer.once(\"listening\", onListening);\n httpServer.listen(options.port, options.host);\n });\n\n return httpServer;\n}\n\nexport async function stopHttpServer(server: Server): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport {\n dnsLookup,\n reverseDns,\n resolveAll,\n checkNameservers,\n whoisLookupResult,\n ipWhoisResult,\n} from \"./dns.js\";\n\nconst recordTypeSchema = z\n .enum([\"A\", \"AAAA\", \"MX\", \"TXT\", \"CNAME\", \"NS\", \"SOA\", \"SRV\", \"CAA\", \"PTR\"])\n .default(\"A\");\n\nconst readOnlyAnnotations = {\n readOnlyHint: true,\n destructiveHint: false,\n};\n\nexport function createMcpServer(): McpServer {\n const server = new McpServer(\n {\n name: \"mcp-dns-tools\",\n version: packageJson.version,\n },\n {\n instructions:\n \"When the user names one DNS record type, call dns_lookup and pass that type, except for NS or nameserver-only requests, which must use check_nameservers. For CAA requests, call dns_lookup with type CAA. Use resolve_all only when the user asks for all records, multiple record types, a DNS overview, or a general investigation. Never use resolve_all for one named record type. Use whois for domain registration, registrar, registration status, or registration-date questions. Use ip_whois for IP allocation and network ownership questions.\",\n },\n );\n\n server.registerTool(\n \"dns_lookup\",\n {\n title: \"DNS record lookup\",\n description:\n \"Use this when the user requests one specific DNS record type, except for NS or nameserver requests, which must use check_nameservers. For CAA or certificate authority issuance questions, call this tool with type CAA. Supports A, AAAA, MX, TXT, CNAME, SOA, SRV, CAA, PTR, and NS for backwards compatibility. Do not use resolve_all when the user names one record type.\",\n inputSchema: {\n domain: z\n .string()\n .describe(\"Domain name to look up (e.g. example.com)\"),\n type: recordTypeSchema.describe(\n \"Specific record type to return: A, AAAA, MX, TXT, CNAME, NS, SOA, SRV, CAA, or PTR. Use CAA for certificate authority issuance policy.\",\n ),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain, type }) => {\n const result = await dnsLookup(domain, type);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"reverse_dns\",\n {\n title: \"Reverse DNS lookup\",\n description: \"Perform a reverse DNS (PTR) lookup on an IP address.\",\n inputSchema: {\n ip: z.string().describe(\"IP address (e.g. 8.8.8.8)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ ip }) => {\n const result = await reverseDns(ip);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"resolve_all\",\n {\n title: \"DNS overview\",\n description:\n \"Use this only when the user requests all common DNS records, multiple record types, a DNS overview, or a general domain investigation. Returns A, AAAA, MX, TXT, CAA, NS, and CNAME. Do not use this for one named record type.\",\n inputSchema: {\n domain: z\n .string()\n .describe(\"Domain name to resolve (e.g. example.com)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain }) => {\n const result = await resolveAll(domain);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"check_nameservers\",\n {\n title: \"Nameserver lookup\",\n description:\n \"Use this whenever the user requests NS records, nameservers, authoritative nameservers, or domain delegation nameservers.\",\n inputSchema: {\n domain: z.string().describe(\"Domain name (e.g. example.com)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain }) => {\n const result = await checkNameservers(domain);\n return { content: [{ type: \"text\" as const, text: result }] };\n },\n );\n\n server.registerTool(\n \"whois\",\n {\n title: \"Domain registration lookup\",\n description:\n \"Query authoritative domain registration data, including registrar, status, dates, nameservers, and DNSSEC. Uses IANA RDAP discovery over HTTPS and follows a registrar RDAP link when available, with bounded legacy WHOIS fallback for TLDs without working RDAP. Supports Unicode domain names. Failures identify each attempted protocol, endpoint, stable reason code, detail, and suggested next action.\",\n inputSchema: {\n domain: z\n .string()\n .describe(\"Domain name for registration lookup (e.g. example.com)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ domain }) => {\n const result = await whoisLookupResult(domain);\n return {\n content: [{ type: \"text\" as const, text: result.text }],\n isError: result.failed,\n };\n },\n );\n\n server.registerTool(\n \"ip_whois\",\n {\n title: \"IP registration lookup\",\n description:\n \"Query authoritative IPv4 or IPv6 allocation and network ownership data. Uses IANA RDAP bootstrap discovery over HTTPS, with bounded legacy WHOIS fallback to the appropriate Regional Internet Registry. When both fail, falls back to RIPEstat's secondary RIR whois data over HTTPS as a last resort. Failures identify each attempted protocol, endpoint, stable reason code, detail, and suggested next action.\",\n inputSchema: {\n ip: z\n .string()\n .describe(\"IP address (e.g. 8.8.8.8 or 2001:4860:4860::8888)\"),\n },\n annotations: readOnlyAnnotations,\n },\n async ({ ip }) => {\n const result = await ipWhoisResult(ip);\n return {\n content: [{ type: \"text\" as const, text: result.text }],\n isError: result.failed,\n };\n },\n );\n\n return server;\n}\n","{\n \"name\": \"@paulgit/mcp-dns-tools\",\n \"mcpName\": \"it.paulg/dns-tools\",\n \"version\": \"2.4.1\",\n \"description\": \"MCP server for DNS lookups, including CAA checks, reverse DNS, and RDAP-first domain or IP registration data with WHOIS fallback; zero auth, zero config\",\n \"type\": \"module\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"engines\": {\n \"node\": \">=24\"\n },\n \"bin\": {\n \"mcp-dns-tools\": \"dist/index.js\"\n },\n \"files\": [\n \"dist\",\n \"skills\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"lint\": \"eslint . && prettier --check .\",\n \"format\": \"prettier --write .\",\n \"audit:deps\": \"npm audit --omit=dev --audit-level=high\",\n \"prepack\": \"npm run build\",\n \"prepublishOnly\": \"npm run lint && npm run typecheck && npm test\",\n \"prepare\": \"husky\"\n },\n \"keywords\": [\n \"mcp\",\n \"mcp-server\",\n \"model-context-protocol\",\n \"dns\",\n \"whois\",\n \"domain\",\n \"network\",\n \"lookup\",\n \"nameserver\",\n \"caa\",\n \"tls\",\n \"certificate-authority\",\n \"ai\",\n \"llm\",\n \"claude\",\n \"cursor\"\n ],\n \"author\": \"Paul Git (https://code.paulg.it/paulgit)\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://code.paulg.it/paulgit/mcp-dns-tools.git\"\n },\n \"bugs\": {\n \"url\": \"https://code.paulg.it/paulgit/mcp-dns-tools/issues\"\n },\n \"homepage\": \"https://code.paulg.it/paulgit/mcp-dns-tools#readme\",\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.26.0\",\n \"undici\": \"^8.10.0\",\n \"zod\": \"^3.25.0\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.0\",\n \"@types/node\": \"^24.0.0\",\n \"eslint\": \"^10.0.0\",\n \"eslint-config-prettier\": \"^10.0.0\",\n \"husky\": \"^9.0.0\",\n \"lint-staged\": \"^17.0.0\",\n \"prettier\": \"^3.0.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.7.0\",\n \"typescript-eslint\": \"^8.0.0\",\n \"vitest\": \"^4.0.0\"\n },\n \"lint-staged\": {\n \"*.{ts,tsx,js}\": [\n \"eslint --fix\",\n \"prettier --write\"\n ],\n \"*.{json,md,yml,yaml}\": [\n \"prettier --write\"\n ]\n },\n \"allowScripts\": {\n \"esbuild@0.27.2\": true,\n \"fsevents@2.3.3\": true\n }\n}\n"],"mappings":"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","names":["dns","net","net","dns"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paulgit/mcp-dns-tools",
|
|
3
3
|
"mcpName": "it.paulg/dns-tools",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.4.1",
|
|
5
5
|
"description": "MCP server for DNS lookups, including CAA checks, reverse DNS, and RDAP-first domain or IP registration data with WHOIS fallback; zero auth, zero config",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|
|
@@ -64,17 +64,17 @@
|
|
|
64
64
|
"zod": "^3.25.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@eslint/js": "^
|
|
68
|
-
"@types/node": "^
|
|
69
|
-
"eslint": "^
|
|
67
|
+
"@eslint/js": "^10.0.0",
|
|
68
|
+
"@types/node": "^24.0.0",
|
|
69
|
+
"eslint": "^10.0.0",
|
|
70
70
|
"eslint-config-prettier": "^10.0.0",
|
|
71
71
|
"husky": "^9.0.0",
|
|
72
|
-
"lint-staged": "^
|
|
72
|
+
"lint-staged": "^17.0.0",
|
|
73
73
|
"prettier": "^3.0.0",
|
|
74
74
|
"tsup": "^8.0.0",
|
|
75
75
|
"typescript": "^5.7.0",
|
|
76
76
|
"typescript-eslint": "^8.0.0",
|
|
77
|
-
"vitest": "^
|
|
77
|
+
"vitest": "^4.0.0"
|
|
78
78
|
},
|
|
79
79
|
"lint-staged": {
|
|
80
80
|
"*.{ts,tsx,js}": [
|
|
@@ -26,7 +26,7 @@ Look up DNS records, inspect certificate issuance policy, perform reverse DNS, c
|
|
|
26
26
|
| `resolve_all` | Resolve common types for an overview; do not use for one named type |
|
|
27
27
|
| `check_nameservers` | Resolve NS, nameserver, authoritative nameserver, and delegation requests |
|
|
28
28
|
| `whois` | Query RDAP-first domain registration data, with WHOIS fallback |
|
|
29
|
-
| `ip_whois` | Query RDAP-first IP allocation data, with RIR WHOIS fallback
|
|
29
|
+
| `ip_whois` | Query RDAP-first IP allocation data, with RIR WHOIS and RIPEstat fallback |
|
|
30
30
|
|
|
31
31
|
## Workflow
|
|
32
32
|
|
|
@@ -39,7 +39,7 @@ Look up DNS records, inspect certificate issuance policy, perform reverse DNS, c
|
|
|
39
39
|
- `dns_lookup` with `type: "MX"` is the go-to for email delivery debugging
|
|
40
40
|
- `dns_lookup` with `type: "CAA"` shows which certificate authorities may issue certificates for a domain: `{ "domain": "example.com", "type": "CAA" }`
|
|
41
41
|
- `whois` uses IANA RDAP discovery over HTTPS, follows a registrar RDAP link when available, and falls back to bounded WHOIS referrals for TLDs without working RDAP
|
|
42
|
-
- `ip_whois` uses the IANA IPv4 or IPv6 RDAP bootstrap registry, with Regional Internet Registry WHOIS fallback
|
|
42
|
+
- `ip_whois` uses the IANA IPv4 or IPv6 RDAP bootstrap registry, with Regional Internet Registry WHOIS fallback; if both fail it queries RIPEstat's RIR whois data over HTTPS as a last resort, labelled as a secondary source that may lag the RIR database
|
|
43
43
|
- Authoritative RDAP `404 Not Found` responses are not replaced with potentially stale WHOIS data
|
|
44
44
|
- Failed registration lookups report each attempted protocol, endpoint, stable reason code, detail, and suggested next action
|
|
45
45
|
- No API keys or auth needed; uses Node.js built-in DNS, public RDAP services, and public WHOIS fallback services
|