rdapper 0.4.1 → 0.5.0
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 +11 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +31 -33
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -35,6 +35,16 @@ await isRegistered("example.com"); // => true
|
|
|
35
35
|
await isAvailable("likely-unregistered-thing-320485230458.com"); // => false
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
Normalize arbitrary input (domain or URL) to its registrable domain (eTLD+1):
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { toRegistrableDomain } from "rdapper";
|
|
42
|
+
|
|
43
|
+
toRegistrableDomain("https://sub.example.co.uk/page"); // => "example.co.uk"
|
|
44
|
+
toRegistrableDomain("spark-public.s3.amazonaws.com"); // => "amazonaws.com" (ICANN-only default)
|
|
45
|
+
toRegistrableDomain("192.168.0.1"); // => null
|
|
46
|
+
```
|
|
47
|
+
|
|
38
48
|
## API
|
|
39
49
|
|
|
40
50
|
- `lookupDomain(domain, options?) => Promise<LookupResult>`
|
|
@@ -181,6 +191,7 @@ Project layout:
|
|
|
181
191
|
- Some TLDs provide no RDAP service; `rdapOnly: true` will fail for them.
|
|
182
192
|
- Registries may throttle or block WHOIS; respect rate limits and usage policies.
|
|
183
193
|
- Field presence depends on source and privacy policies (e.g., redaction/withholding).
|
|
194
|
+
- Public suffix detection uses `tldts` with ICANN‑only defaults (Private section is ignored). If you need behavior closer to `psl` that considers private suffixes, see the `allowPrivateDomains` option in the `tldts` docs (rdapper currently sticks to ICANN‑only by default). See: [tldts migration notes](https://github.com/remusao/tldts#migrating-from-other-libraries).
|
|
184
195
|
|
|
185
196
|
## License
|
|
186
197
|
|
package/dist/index.d.ts
CHANGED
|
@@ -124,6 +124,13 @@ interface LookupResult {
|
|
|
124
124
|
}
|
|
125
125
|
type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
126
126
|
//#endregion
|
|
127
|
+
//#region src/lib/domain.d.ts
|
|
128
|
+
/**
|
|
129
|
+
* Normalize arbitrary input (domain or URL) to its registrable domain (eTLD+1).
|
|
130
|
+
* Returns null when the input is not a valid ICANN domain (e.g., invalid TLD, IPs).
|
|
131
|
+
*/
|
|
132
|
+
declare function toRegistrableDomain(input: string): string | null;
|
|
133
|
+
//#endregion
|
|
127
134
|
//#region src/index.d.ts
|
|
128
135
|
/**
|
|
129
136
|
* High-level lookup that prefers RDAP and falls back to WHOIS.
|
|
@@ -137,4 +144,4 @@ declare function isAvailable(domain: string, opts?: LookupOptions): Promise<bool
|
|
|
137
144
|
* Performs a lookup and resolves to a boolean. Rejects on lookup error. */
|
|
138
145
|
declare function isRegistered(domain: string, opts?: LookupOptions): Promise<boolean>;
|
|
139
146
|
//#endregion
|
|
140
|
-
export { Contact, DomainRecord, FetchLike, LookupOptions, LookupResult, LookupSource, Nameserver, RegistrarInfo, StatusEvent, isAvailable, isRegistered, lookupDomain };
|
|
147
|
+
export { Contact, DomainRecord, FetchLike, LookupOptions, LookupResult, LookupSource, Nameserver, RegistrarInfo, StatusEvent, isAvailable, isRegistered, lookupDomain, toRegistrableDomain };
|
package/dist/index.js
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { parse } from "tldts";
|
|
2
2
|
import { createConnection } from "node:net";
|
|
3
3
|
|
|
4
4
|
//#region src/lib/domain.ts
|
|
5
|
+
/**
|
|
6
|
+
* Parse a domain into its parts.
|
|
7
|
+
*/
|
|
5
8
|
function getDomainParts(domain) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
const labels = publicSuffix.split(".").filter(Boolean);
|
|
16
|
-
const tld = labels.length ? labels[labels.length - 1] : publicSuffix;
|
|
17
|
-
return {
|
|
18
|
-
publicSuffix,
|
|
19
|
-
tld
|
|
20
|
-
};
|
|
9
|
+
return parse(domain);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Basic domain validity check (hostname-like), not performing DNS or RDAP.
|
|
13
|
+
*/
|
|
14
|
+
function isLikelyDomain(value) {
|
|
15
|
+
const v = (value ?? "").trim();
|
|
16
|
+
return /^(?=.{1,253}$)(?:(?!-)[a-z0-9-]{1,63}(?<!-)\.)+(?!-)[a-z0-9-]{2,63}(?<!-)$/.test(v.toLowerCase());
|
|
21
17
|
}
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Normalize arbitrary input (domain or URL) to its registrable domain (eTLD+1).
|
|
20
|
+
* Returns null when the input is not a valid ICANN domain (e.g., invalid TLD, IPs).
|
|
21
|
+
*/
|
|
22
|
+
function toRegistrableDomain(input) {
|
|
23
|
+
const raw = (input ?? "").trim();
|
|
24
|
+
if (raw === "") return null;
|
|
25
|
+
const result = parse(raw);
|
|
26
|
+
if (result.isIp) return null;
|
|
27
|
+
if (!result.isIcann) return null;
|
|
28
|
+
const domain = result.domain ?? "";
|
|
29
|
+
if (domain === "") return null;
|
|
30
|
+
return domain.toLowerCase();
|
|
24
31
|
}
|
|
25
32
|
const WHOIS_AVAILABLE_PATTERNS = [
|
|
26
33
|
/\bno match\b/i,
|
|
@@ -977,7 +984,11 @@ async function lookupDomain(domain, opts) {
|
|
|
977
984
|
ok: false,
|
|
978
985
|
error: "Input does not look like a domain"
|
|
979
986
|
};
|
|
980
|
-
const { publicSuffix
|
|
987
|
+
const { publicSuffix: tld } = getDomainParts(domain);
|
|
988
|
+
if (!tld) return {
|
|
989
|
+
ok: false,
|
|
990
|
+
error: "Invalid TLD"
|
|
991
|
+
};
|
|
981
992
|
if (!opts?.whoisOnly) {
|
|
982
993
|
const bases = await getRdapBaseUrlsForTld(tld, opts);
|
|
983
994
|
const tried = [];
|
|
@@ -1008,19 +1019,6 @@ async function lookupDomain(domain, opts) {
|
|
|
1008
1019
|
};
|
|
1009
1020
|
}
|
|
1010
1021
|
const res = await followWhoisReferrals(whoisServer, domain, opts);
|
|
1011
|
-
if (publicSuffix.includes(".") && /no match|not found/i.test(res.text) && opts?.followWhoisReferral !== false) {
|
|
1012
|
-
const candidates = [];
|
|
1013
|
-
const ps = publicSuffix.toLowerCase();
|
|
1014
|
-
const exception = WHOIS_TLD_EXCEPTIONS[ps];
|
|
1015
|
-
if (exception) candidates.push(exception);
|
|
1016
|
-
for (const server of candidates) try {
|
|
1017
|
-
const alt = await whoisQuery(server, domain, opts);
|
|
1018
|
-
if (alt.text && !/error/i.test(alt.text)) return {
|
|
1019
|
-
ok: true,
|
|
1020
|
-
record: normalizeWhois(domain, tld, alt.text, alt.serverQueried, !!opts?.includeRaw)
|
|
1021
|
-
};
|
|
1022
|
-
} catch {}
|
|
1023
|
-
}
|
|
1024
1022
|
return {
|
|
1025
1023
|
ok: true,
|
|
1026
1024
|
record: normalizeWhois(domain, tld, res.text, res.serverQueried, !!opts?.includeRaw)
|
|
@@ -1048,4 +1046,4 @@ async function isRegistered(domain, opts) {
|
|
|
1048
1046
|
}
|
|
1049
1047
|
|
|
1050
1048
|
//#endregion
|
|
1051
|
-
export { isAvailable, isRegistered, lookupDomain };
|
|
1049
|
+
export { isAvailable, isRegistered, lookupDomain, toRegistrableDomain };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rdapper",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "🎩 RDAP/WHOIS fetcher, parser, and normalizer for Node",
|
|
6
6
|
"repository": {
|
|
@@ -39,14 +39,13 @@
|
|
|
39
39
|
"prepublishOnly": "npm run build"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"
|
|
42
|
+
"tldts": "7.0.17"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@biomejs/biome": "2.2.
|
|
46
|
-
"@types/node": "24.
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"typescript": "5.9.2",
|
|
45
|
+
"@biomejs/biome": "2.2.5",
|
|
46
|
+
"@types/node": "24.7.1",
|
|
47
|
+
"tsdown": "0.15.6",
|
|
48
|
+
"typescript": "5.9.3",
|
|
50
49
|
"vitest": "^3.2.4"
|
|
51
50
|
},
|
|
52
51
|
"engines": {
|