tldts-core 7.1.2 → 7.2.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/dist/cjs/index.js +128 -22
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/src/extract-hostname.js +55 -21
- package/dist/cjs/src/extract-hostname.js.map +1 -1
- package/dist/cjs/src/factory.js +10 -0
- package/dist/cjs/src/factory.js.map +1 -1
- package/dist/cjs/src/is-special-use.js +65 -0
- package/dist/cjs/src/is-special-use.js.map +1 -0
- package/dist/cjs/src/options.js +2 -1
- package/dist/cjs/src/options.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/es6/src/extract-hostname.js +55 -21
- package/dist/es6/src/extract-hostname.js.map +1 -1
- package/dist/es6/src/factory.js +10 -0
- package/dist/es6/src/factory.js.map +1 -1
- package/dist/es6/src/is-special-use.js +62 -0
- package/dist/es6/src/is-special-use.js.map +1 -0
- package/dist/es6/src/options.js +2 -1
- package/dist/es6/src/options.js.map +1 -1
- package/dist/es6/tsconfig.bundle.tsbuildinfo +1 -1
- package/dist/types/src/factory.d.ts +1 -0
- package/dist/types/src/is-special-use.d.ts +5 -0
- package/dist/types/src/options.d.ts +1 -0
- package/package.json +2 -2
- package/src/extract-hostname.ts +62 -25
- package/src/factory.ts +22 -3
- package/src/is-special-use.ts +65 -0
- package/src/options.ts +6 -0
package/src/factory.ts
CHANGED
|
@@ -8,6 +8,7 @@ import getDomain from './domain';
|
|
|
8
8
|
import getDomainWithoutSuffix from './domain-without-suffix';
|
|
9
9
|
import extractHostname from './extract-hostname';
|
|
10
10
|
import isIp from './is-ip';
|
|
11
|
+
import isSpecialUse from './is-special-use';
|
|
11
12
|
import isValidHostname from './is-valid';
|
|
12
13
|
import { IPublicSuffix, ISuffixLookupOptions } from './lookup/interface';
|
|
13
14
|
import { IOptions, setDefaults } from './options';
|
|
@@ -15,9 +16,10 @@ import getSubdomain from './subdomain';
|
|
|
15
16
|
|
|
16
17
|
export interface IResult {
|
|
17
18
|
// `hostname` is either a registered name (including but not limited to a
|
|
18
|
-
// hostname), or an IP address
|
|
19
|
-
//
|
|
20
|
-
//
|
|
19
|
+
// hostname), or an IP address, directly extracted from the input URL. IPv4
|
|
20
|
+
// addresses are in dot-decimal notation. IPv6 is returned without its
|
|
21
|
+
// surrounding brackets; both bracketed (in URLs, e.g. `http://[::1]/`) and
|
|
22
|
+
// bare unbracketed (e.g. `2a01:e35::1`) IPv6 literals are accepted.
|
|
21
23
|
hostname: string | null;
|
|
22
24
|
|
|
23
25
|
// Is `hostname` an IP? (IPv4 or IPv6)
|
|
@@ -32,6 +34,13 @@ export interface IResult {
|
|
|
32
34
|
// Specifies if `publicSuffix` comes from the ICANN or PRIVATE section of the list
|
|
33
35
|
isIcann: boolean | null;
|
|
34
36
|
isPrivate: boolean | null;
|
|
37
|
+
|
|
38
|
+
// Is `hostname` a special-use domain from the IANA registry (RFC 6761 et al.:
|
|
39
|
+
// e.g. `localhost`, `*.test`, `*.local`, `*.onion`, `home.arpa`)? `isIcann`/
|
|
40
|
+
// `isPrivate` do not identify these (most are not in the Public Suffix List;
|
|
41
|
+
// the few that are appear as ordinary ICANN suffixes). `null` unless the
|
|
42
|
+
// `detectSpecialUse` option is enabled (see is-special-use.ts).
|
|
43
|
+
isSpecialUse: boolean | null;
|
|
35
44
|
}
|
|
36
45
|
|
|
37
46
|
export function getEmptyResult(): IResult {
|
|
@@ -42,6 +51,7 @@ export function getEmptyResult(): IResult {
|
|
|
42
51
|
isIcann: null,
|
|
43
52
|
isIp: null,
|
|
44
53
|
isPrivate: null,
|
|
54
|
+
isSpecialUse: null,
|
|
45
55
|
publicSuffix: null,
|
|
46
56
|
subdomain: null,
|
|
47
57
|
};
|
|
@@ -54,6 +64,7 @@ export function resetResult(result: IResult): void {
|
|
|
54
64
|
result.isIcann = null;
|
|
55
65
|
result.isIp = null;
|
|
56
66
|
result.isPrivate = null;
|
|
67
|
+
result.isSpecialUse = null;
|
|
57
68
|
result.publicSuffix = null;
|
|
58
69
|
result.subdomain = null;
|
|
59
70
|
}
|
|
@@ -143,6 +154,14 @@ export function parseImpl(
|
|
|
143
154
|
return result;
|
|
144
155
|
}
|
|
145
156
|
|
|
157
|
+
// Flag special-use domains, only when opted in (`detectSpecialUse`) and only
|
|
158
|
+
// for the full `parse()` result (FLAG.ALL). Computed here, before the
|
|
159
|
+
// public-suffix/domain early-returns below, so single-label names like
|
|
160
|
+
// `localhost` (which have no registrable domain) are still flagged.
|
|
161
|
+
if (step === FLAG.ALL && options.detectSpecialUse) {
|
|
162
|
+
result.isSpecialUse = isSpecialUse(result.hostname);
|
|
163
|
+
}
|
|
164
|
+
|
|
146
165
|
// Extract public suffix
|
|
147
166
|
suffixLookup(result.hostname, options, result);
|
|
148
167
|
if (step === FLAG.PUBLIC_SUFFIX || result.publicSuffix === null) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Special-use domain names from the IANA "Special-Use Domain Names" registry:
|
|
3
|
+
* the authoritative list, created by RFC 6761 and maintained as new RFCs add to
|
|
4
|
+
* it: https://www.iana.org/assignments/special-use-domain-names/
|
|
5
|
+
* Snapshot: 2026-05-24. (RFC 6761 is not obsoleted; draft-hoffman-rfc6761bis
|
|
6
|
+
* proposes to retire its prose but keep this registry, so the registry is the
|
|
7
|
+
* source of truth; re-sync this list against it.)
|
|
8
|
+
*
|
|
9
|
+
* These names never correspond to a public registration, yet neither
|
|
10
|
+
* `isIcann` nor `isPrivate` marks one as special-use: most are absent from the
|
|
11
|
+
* Public Suffix List (so `a.test` looks like a registrable domain), and the
|
|
12
|
+
* few that are listed (`onion`, `home.arpa`) appear there as ordinary ICANN
|
|
13
|
+
* suffixes. `isSpecialUse` is the single signal that covers them all.
|
|
14
|
+
*
|
|
15
|
+
* Per the registry and RFC 6761 ("and any names falling within these domains"),
|
|
16
|
+
* the designation covers each listed name AND all of its sub-domains. DNS labels
|
|
17
|
+
* are case-insensitive (RFC 4343); `hostname` is expected to be already
|
|
18
|
+
* lower-cased and trailing-dot-stripped, as produced by `extractHostname`, the
|
|
19
|
+
* same normalization the Public-Suffix-List lookup relies on.
|
|
20
|
+
*
|
|
21
|
+
* Two groups of registry entries are intentionally excluded: the numeric
|
|
22
|
+
* reverse-DNS delegation zones (`10.in-addr.arpa`, the `*.ip6.arpa` ranges, …),
|
|
23
|
+
* which are reverse-DNS PTR zones rather than hostnames and whose parents
|
|
24
|
+
* (`in-addr.arpa`/`ip6.arpa`) are already in the Public Suffix List; and the
|
|
25
|
+
* deprecated `eap-noob.arpa` entry.
|
|
26
|
+
*/
|
|
27
|
+
const SPECIAL_USE_DOMAINS: readonly string[] = [
|
|
28
|
+
'test', // RFC 6761
|
|
29
|
+
'localhost', // RFC 6761
|
|
30
|
+
'invalid', // RFC 6761
|
|
31
|
+
'example', // RFC 6761
|
|
32
|
+
'example.com', // RFC 6761
|
|
33
|
+
'example.net', // RFC 6761
|
|
34
|
+
'example.org', // RFC 6761
|
|
35
|
+
'local', // RFC 6762 (mDNS)
|
|
36
|
+
'onion', // RFC 7686 (Tor)
|
|
37
|
+
'alt', // RFC 9476
|
|
38
|
+
'home.arpa', // RFC 8375
|
|
39
|
+
'ipv4only.arpa', // RFC 8880
|
|
40
|
+
'resolver.arpa', // RFC 9462
|
|
41
|
+
'service.arpa', // RFC 9665
|
|
42
|
+
'6tisch.arpa', // RFC 9031
|
|
43
|
+
'eap.arpa', // RFC 9965
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Return `true` if `hostname` is, or is a sub-domain of, a special-use domain
|
|
48
|
+
* (see the registry note above). Expects an already-normalized `hostname`.
|
|
49
|
+
*/
|
|
50
|
+
export default function isSpecialUse(hostname: string): boolean {
|
|
51
|
+
for (const name of SPECIAL_USE_DOMAINS) {
|
|
52
|
+
// Match on a label boundary: `hostname` is either exactly `name` or ends
|
|
53
|
+
// with `.name` (so `latest` is not matched by `test`, nor `myexample.com`
|
|
54
|
+
// by `example.com`).
|
|
55
|
+
if (
|
|
56
|
+
hostname.endsWith(name) &&
|
|
57
|
+
(hostname.length === name.length ||
|
|
58
|
+
hostname.charCodeAt(hostname.length - name.length - 1) === 46) /* '.' */
|
|
59
|
+
) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return false;
|
|
65
|
+
}
|
package/src/options.ts
CHANGED
|
@@ -2,6 +2,10 @@ export interface IOptions {
|
|
|
2
2
|
allowIcannDomains: boolean;
|
|
3
3
|
allowPrivateDomains: boolean;
|
|
4
4
|
detectIp: boolean;
|
|
5
|
+
// Detect RFC 6761 / IANA special-use domains and expose the result as
|
|
6
|
+
// `isSpecialUse` on `parse()`. Off by default so the common path stays
|
|
7
|
+
// allocation-free with no extra work; enable it to populate the field.
|
|
8
|
+
detectSpecialUse: boolean;
|
|
5
9
|
extractHostname: boolean;
|
|
6
10
|
mixedInputs: boolean;
|
|
7
11
|
validHosts: string[] | null;
|
|
@@ -12,6 +16,7 @@ function setDefaultsImpl({
|
|
|
12
16
|
allowIcannDomains = true,
|
|
13
17
|
allowPrivateDomains = false,
|
|
14
18
|
detectIp = true,
|
|
19
|
+
detectSpecialUse = false,
|
|
15
20
|
extractHostname = true,
|
|
16
21
|
mixedInputs = true,
|
|
17
22
|
validHosts = null,
|
|
@@ -21,6 +26,7 @@ function setDefaultsImpl({
|
|
|
21
26
|
allowIcannDomains,
|
|
22
27
|
allowPrivateDomains,
|
|
23
28
|
detectIp,
|
|
29
|
+
detectSpecialUse,
|
|
24
30
|
extractHostname,
|
|
25
31
|
mixedInputs,
|
|
26
32
|
validHosts,
|