plevinjs 0.1.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 ADDED
@@ -0,0 +1,283 @@
1
+ <div align="center">
2
+ <a href="https://www.npmjs.com/package/plevinjs">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tn3w/plevin/master/.github/title-dark.png">
5
+ <img src="https://raw.githubusercontent.com/tn3w/plevin/master/.github/title-light.png" width="320" alt="plevin">
6
+ </picture>
7
+ </a>
8
+
9
+ **Location, network and abuse information for any IP address in one offline file.**<br>
10
+ No API, no rate limit, no lookup leaving the machine — or the browser tab.
11
+
12
+ ![npm](https://img.shields.io/npm/v/plevinjs?color=1868f2)
13
+ ![Types](https://img.shields.io/badge/types-included-1868f2)
14
+ ![License](https://img.shields.io/badge/license-Apache--2.0-1868f2)
15
+ ![Fields](https://img.shields.io/badge/fields-98-6f42c1)
16
+ ![Boundaries](https://img.shields.io/badge/boundaries-2.6M-6f42c1)
17
+ ![Warm](https://img.shields.io/badge/warm%20lookups-4M%2Fs-2ea043)
18
+
19
+ </div>
20
+
21
+ ```bash
22
+ npm install plevinjs
23
+ ```
24
+
25
+ ```js
26
+ import { Plevin, open } from "plevinjs";
27
+
28
+ const db = await open("https://plevin.tn3w.dev/db/plevin.plv");
29
+ const found = db.lookup("1.1.1.1"); // string, number, bigint or packed bytes
30
+ ```
31
+
32
+ Always a `Result`, never `undefined`; it throws for anything that is not an address, and
33
+ a number reads as v6 only above `0xffffffff`, so `lookup(1)` is `0.0.0.1`.
34
+
35
+ ```js
36
+ found.place.city.name; // 'Brisbane'
37
+ found.place.city.region.name; // 'Queensland'
38
+ found.place.country.name; // 'Australia'
39
+ found.place.time.local; // '2026-08-13T23:27:58+10:00'
40
+
41
+ found.network.asn; // 13335
42
+ found.network.operator.brand; // 'Cloudflare'
43
+ found.network.cidr; // '1.1.1.0/24'
44
+
45
+ const exit = db.lookup("185.220.101.1");
46
+ exit.abuse.service; // 'tor_exit_node'
47
+ exit.abuse.risk; // 0.97
48
+ exit.abuse.is_tor_exit_node; // true
49
+ ```
50
+
51
+ Pure ESM with no dependencies, so it runs wherever fetch does: Node, Deno, Bun,
52
+ Cloudflare Workers, and any browser off a CDN.
53
+
54
+ ```html
55
+ <script type="module">
56
+ import { open } from "https://cdn.jsdelivr.net/npm/plevinjs";
57
+
58
+ const db = await open("https://plevin.tn3w.dev/db/plevin.plv");
59
+ document.title = db.lookup("8.8.8.8").place.country.flag;
60
+ </script>
61
+ ```
62
+
63
+ `https://esm.sh/plevinjs` serves the same thing. Every database is rehosted with open
64
+ CORS at [plevin.tn3w.dev/db](https://plevin.tn3w.dev/db/), because GitHub release
65
+ downloads send no CORS header.
66
+
67
+ ## Where the file comes from
68
+
69
+ | where it runs | how to open it |
70
+ | --- | --- |
71
+ | browser, worker | `await open(url)`, or `await open(response)` |
72
+ | Node, Deno, Bun | `import { openFile } from "plevinjs/node"`, then `await openFile(path)` |
73
+ | bytes you hold | `new Plevin(bytes)`, taking a `Uint8Array` |
74
+
75
+ `openFile()` reads `PLEVIN_DB` where no path is given. Nothing is downloaded for you
76
+ and nothing is cached for you: hand the same `Plevin` to every lookup and the file is
77
+ read once.
78
+
79
+ | file | size | carries |
80
+ | --- | --- | --- |
81
+ | `plevin.plv` | 16.9 MB | every field |
82
+ | `plevin.metro-place.plv` | 6.3 MB | city, region, postal, coordinates, metro |
83
+ | `plevin.abuse-network.plv` | 10.3 MB | ASN, operator, routing, abuse |
84
+ | `plevin.place-country-code.plv` | 423 KB | the country code |
85
+
86
+ ## Every field
87
+
88
+ <picture>
89
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tn3w/plevin/master/.github/fields-dark.png">
90
+ <img src="https://raw.githubusercontent.com/tn3w/plevin/master/.github/fields-light.png" width="840" alt="address to place, network and abuse">
91
+ </picture>
92
+
93
+ `found.place` is where the address is, `found.network` who announces it, `found.abuse`
94
+ what has been seen from it. Any of the three is `null` where the build carries none of
95
+ it, and every leaf is `null` rather than `""` or `0` where a source says nothing. The
96
+ shapes and the field names are the ones the
97
+ [Python package](https://github.com/tn3w/plevin/blob/master/python/README.md#every-field)
98
+ answers with, to the letter.
99
+
100
+ ```js
101
+ {
102
+ lat: -27.4675, lon: 153.0281, accuracy: 200, confidence: 36,
103
+ granularity: 'city',
104
+ city: {
105
+ id: 2174003, name: 'Brisbane', ascii: 'Brisbane', country: 'AU',
106
+ population: 2780063, elevation: 27, postal: '4000', postal_partial: null,
107
+ timezone: 'Australia/Brisbane', type: 'regional capital', capital: 'region',
108
+ region: { id: 2152274, code: '04', iso: 'AU-QLD', name: 'Queensland',
109
+ type: 'State' },
110
+ district: { id: 7839562, code: '31000', name: 'Brisbane' },
111
+ metro: null,
112
+ },
113
+ country: {
114
+ code: 'AU', name: 'Australia', official: null, common: null, iso3: 'AUS',
115
+ numeric: '036', flag: '🇦🇺', european_union: false, driving_side: 'left',
116
+ },
117
+ time: {
118
+ timezone: 'Australia/Brisbane', abbreviation: 'AEST',
119
+ local: '2026-08-13T19:20:00+10:00', utc_offset: '+10:00', is_dst: false,
120
+ dst_start: null, dst_end: null,
121
+ },
122
+ }
123
+ ```
124
+
125
+ `country` and `time` are derived, not stored: `country` out of an ISO 3166 table in the
126
+ package, `time` out of the runtime's own `Intl` zone data, so neither needs an install
127
+ and neither is a network call. Where the host's zone data is older or newer than the
128
+ one the Python package reads, a daylight boundary may move by a transition.
129
+
130
+ ```js
131
+ {
132
+ asn: 13335, handle: 'CLOUDFLARENET', prefix: 24, cidr: '1.1.1.0/24',
133
+ start: '1.1.1.0', end: '1.1.1.255', rpki: 'valid', roas: 1,
134
+ operator: {
135
+ company: 'Cloudflare, Inc.', brand: 'Cloudflare', domain: 'cloudflare.com',
136
+ website: 'https://www.cloudflare.com', category: 'content', tier: 2,
137
+ peering: 356, scope: 'Global', rir: 'arin', since: 2010,
138
+ street: '101 Townsend St', state: 'CA', postal: '94107-1934', country: 'US',
139
+ abuse_email: 'abuse@cloudflare.com', city: { name: 'San Francisco', ... },
140
+ },
141
+ carrier: { user_type: 'hosting', user_count: 19, mcc: null, mnc: null,
142
+ is_mobile: false },
143
+ }
144
+ ```
145
+
146
+ `cidr` is the announcement the address falls in, masked out of the address itself.
147
+ `rpki` is `valid`, `invalid` or `unknown` and `roas` how many ROAs agree. `brand` drops
148
+ the legal form and the words every network carries, so `GOOGLE` and `Google LLC` both
149
+ read `Google`.
150
+
151
+ ```js
152
+ db.lookup("185.220.101.1").abuse;
153
+ {
154
+ name: 'Tor', service: 'tor_exit_node', evidence: 'measured', risk: 0.97,
155
+ network_risk: null, last_seen_days: 1, is_anycast: false, is_satellite: false,
156
+ is_hosting_provider: true, is_proxy: false, is_public_proxy: false,
157
+ is_residential_proxy: false, is_anonymous_vpn: false, is_tor_exit_node: true,
158
+ is_private_relay: false, is_anonymous: true,
159
+ }
160
+ ```
161
+
162
+ `risk` is 0 to 1 for the address, `network_risk` the same for the whole ASN, `null`
163
+ where nothing has ever been seen — which is not a risk of zero.
164
+
165
+ ## What an address says on its own
166
+
167
+ Answered without the database, so they hold for every address:
168
+
169
+ ```js
170
+ const found = db.lookup("2606:4700::1111");
171
+ found.number; // 50543257672059871404715951523469725969n
172
+ found.compressed // '2606:4700::1111'
173
+ found.expanded; // '2606:4700:0000:0000:0000:0000:0000:1111'
174
+ found.arpa; // '1.1.1.1.0.0.….0.7.4.6.0.6.2.ip6.arpa'
175
+ ```
176
+
177
+ `number` is a `bigint` for v6 and a `number` for v4, so `JSON.stringify` needs a
178
+ replacer where you hand a v6 result on. Then `is_global` and `is_bogon`, `is_private`,
179
+ `is_loopback`, `is_multicast`, `is_reserved`, `is_link_local`, `is_unique_local`,
180
+ `is_documentation`, `is_shared` (100.64/10) and `is_benchmark` (198.18/15), bisected
181
+ out of the IANA special-purpose registries.
182
+
183
+ ```js
184
+ db.lookup("::ffff:8.8.8.8").tunnel; // 'ipv4-mapped'
185
+ db.lookup("::ffff:8.8.8.8").embedded_ipv4; // '8.8.8.8'
186
+ db.lookup("2002:808:808::1").is_6to4; // true
187
+ ```
188
+
189
+ `tunnel` is `ipv4-mapped`, `6to4`, `teredo`, `nat64` or `null`.
190
+
191
+ ## In a browser
192
+
193
+ No build step and no install: the package is plain ESM with no dependencies, so any npm
194
+ CDN serves it as it is.
195
+
196
+ ```html
197
+ <script type="module">
198
+ import { open } from "https://cdn.jsdelivr.net/npm/plevinjs";
199
+
200
+ const db = await open("https://plevin.tn3w.dev/db/plevin.plv");
201
+ document.title = db.lookup("1.1.1.1").place.country.flag;
202
+ </script>
203
+ ```
204
+
205
+ | | |
206
+ | --- | --- |
207
+ | `https://cdn.jsdelivr.net/npm/plevinjs` | the published files, as they are |
208
+ | `https://esm.sh/plevinjs` | the same, imports rewritten |
209
+ | `https://unpkg.com/plevinjs` | the same as jsDelivr |
210
+ | `https://plevin.tn3w.dev/plevin/` | the reader beside the databases |
211
+
212
+ Every module is fetched as published, `./reader.js` and all, so the browser loads the
213
+ ten it needs and nothing more. Pin a version for anything that ships:
214
+ `cdn.jsdelivr.net/npm/plevinjs@0.1.0`. `plevinjs/node` is the only entry that touches
215
+ Node, so a CDN import never reaches for `node:fs`.
216
+
217
+ 18 MB crosses the wire once, so keep it out of the critical path and out of the next
218
+ visit's way:
219
+
220
+ ```js
221
+ const store = await caches.open("plevin");
222
+ const url = "https://plevin.tn3w.dev/db/plevin.plv";
223
+ if (!(await store.match(url))) await store.add(url);
224
+
225
+ const held = await store.match(url);
226
+ const db = new Plevin(new Uint8Array(await held.arrayBuffer()));
227
+ ```
228
+
229
+ `plevin.place-country-code.plv` is 423 KB where the country code is all a page needs.
230
+ [The lookup page](https://plevin.tn3w.dev/) is the whole idea in one file of
231
+ plain JavaScript: it reads the database in the tab and calls out only for the visitor's
232
+ own address and for hostnames.
233
+
234
+ ## Speed
235
+
236
+ Measured on the full file, Node 26, one core:
237
+
238
+ | | |
239
+ | --- | --- |
240
+ | open | 14 ms, the header only |
241
+ | first answer | 44 ms, the blocks it lands in |
242
+ | repeats | 4,600,000/s |
243
+ | uniformly random v4 | 13,000/s cold, 200,000/s over the same log again |
244
+
245
+ Blocks decode on reach and stay decoded, so a real log lands between the two. Memory is
246
+ the file plus whatever it decoded, around 120 MB of heap with the whole world touched.
247
+
248
+ ## Zstandard
249
+
250
+ The file is Zstandard with trained dictionaries, which no runtime decompresses on its
251
+ own — `DecompressionStream` has no zstd and Node's `zlib` takes no dictionary. So the
252
+ package carries one, condensed from [fzstd](https://github.com/101arrowz/fzstd) (MIT)
253
+ with the dictionary support it leaves out, and verified block for block against
254
+ libzstd over the whole database.
255
+
256
+ ```js
257
+ import { decompress, loadDictionary } from "plevin/zstd";
258
+
259
+ decompress(frame); // one frame
260
+ decompress(frame, loadDictionary(trained)); // with a trained dictionary
261
+ ```
262
+
263
+ ## Development
264
+
265
+ ```bash
266
+ cd js
267
+ npm ci
268
+ npm test # node --test, no database needed for most of it
269
+ npm run lint # biome
270
+ npm run typecheck # tsc, strict
271
+ npm run build # dist/, ESM and .d.ts
272
+
273
+ node test/compare.ts ../plevin.plv sample.json # field for field against Python
274
+ node test/blocks.ts ../plevin.plv 100000 # every block against libzstd
275
+ ```
276
+
277
+ ## License
278
+
279
+ Apache 2.0, see [LICENSE](https://github.com/tn3w/plevin/blob/master/LICENSE). The
280
+ database carries the licenses of the sources it was built from, listed in
281
+ [`builder/README.md`](https://github.com/tn3w/plevin/blob/master/builder/README.md#sources).
282
+
283
+ <!-- brand: Noto Sans 800, wordmark bar #1868f2 place, #6f42c1 network, #2ea043 abuse; #7d8894 address, ink #0b1220 light, #f0f6fc dark -->
@@ -0,0 +1,28 @@
1
+ /** What an address is before any database is opened. */
2
+ export type Value = string | number | bigint | Uint8Array;
3
+ export declare const PRIVATE = 1;
4
+ export declare const LOOPBACK = 2;
5
+ export declare const MULTICAST = 4;
6
+ export declare const RESERVED = 8;
7
+ export declare const LINK_LOCAL = 16;
8
+ export declare const UNIQUE_LOCAL = 32;
9
+ export declare const DOCUMENTATION = 64;
10
+ export declare const SHARED = 128;
11
+ export declare const BENCHMARK = 256;
12
+ export declare const MAPPED = "ipv4-mapped";
13
+ export declare const SIXTOFOUR = "6to4";
14
+ export declare const TEREDO = "teredo";
15
+ export declare const NAT64 = "nat64";
16
+ /** An address however it is written; an integer reads as v6 only above 0xffffffff. */
17
+ export declare const parse: (value: Value) => [number | bigint, boolean];
18
+ /** How the address reads short and in full, and the name a resolver asks by. */
19
+ export declare const spelled: (value: number | bigint, wide: boolean) => [string, string, string];
20
+ /** An address as text: v4 from its octets, v6 through the shortening rules. */
21
+ export declare const written: (value: number | bigint, wide: boolean) => string;
22
+ /** What an address is where it is not the internet, bisected out of the table. */
23
+ export declare const purpose: (value: number | bigint, wide: boolean) => number;
24
+ /** The v4 address a v6 one carries, and the tunnel that puts it there. */
25
+ export declare const tunnel: (value: number | bigint, wide: boolean) => [string | null, string | null];
26
+ /** The announcement the address falls in, masked out of the address itself. */
27
+ export declare const span: (value: number | bigint, wide: boolean, prefix: number) => [string, string, string];
28
+ //# sourceMappingURL=address.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAE1D,eAAO,MAAM,OAAO,IAAI,CAAC;AACzB,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,eAAO,MAAM,YAAY,KAAK,CAAC;AAC/B,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,MAAM,MAAM,CAAC;AAC1B,eAAO,MAAM,SAAS,MAAM,CAAC;AAE7B,eAAO,MAAM,MAAM,gBAAgB,CAAC;AACpC,eAAO,MAAM,SAAS,SAAS,CAAC;AAChC,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,KAAK,UAAU,CAAC;AAuF7B,sFAAsF;AACtF,eAAO,MAAM,KAAK,UAAW,KAAK,KAAG,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CA6B7D,CAAC;AA2BF,gFAAgF;AAChF,eAAO,MAAM,OAAO,UACX,MAAM,GAAG,MAAM,QAChB,OAAO,KACZ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CA4BzB,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,OAAO,UAAW,MAAM,GAAG,MAAM,QAAQ,OAAO,KAAG,MACvC,CAAC;AAc1B,kFAAkF;AAClF,eAAO,MAAM,OAAO,UAAW,MAAM,GAAG,MAAM,QAAQ,OAAO,KAAG,MAa/D,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,MAAM,UACV,MAAM,GAAG,MAAM,QAChB,OAAO,KACZ,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAW/B,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,IAAI,UACR,MAAM,GAAG,MAAM,QAChB,OAAO,UACL,MAAM,KACb,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAOzB,CAAC"}
@@ -0,0 +1,242 @@
1
+ /** What an address is before any database is opened. */
2
+ export const PRIVATE = 1;
3
+ export const LOOPBACK = 2;
4
+ export const MULTICAST = 4;
5
+ export const RESERVED = 8;
6
+ export const LINK_LOCAL = 16;
7
+ export const UNIQUE_LOCAL = 32;
8
+ export const DOCUMENTATION = 64;
9
+ export const SHARED = 128;
10
+ export const BENCHMARK = 256;
11
+ export const MAPPED = "ipv4-mapped";
12
+ export const SIXTOFOUR = "6to4";
13
+ export const TEREDO = "teredo";
14
+ export const NAT64 = "nat64";
15
+ const V4_MAX = 0xffffffff;
16
+ const V6_MAX = (1n << 128n) - 1n;
17
+ const SPECIAL_V4 = [
18
+ ["0.0.0.0/8", RESERVED],
19
+ ["10.0.0.0/8", PRIVATE],
20
+ ["100.64.0.0/10", PRIVATE | SHARED],
21
+ ["127.0.0.0/8", PRIVATE | LOOPBACK],
22
+ ["169.254.0.0/16", PRIVATE | LINK_LOCAL],
23
+ ["172.16.0.0/12", PRIVATE],
24
+ ["192.0.0.0/24", RESERVED],
25
+ ["192.0.2.0/24", RESERVED | DOCUMENTATION],
26
+ ["192.88.99.0/24", RESERVED],
27
+ ["192.168.0.0/16", PRIVATE],
28
+ ["198.18.0.0/15", RESERVED | BENCHMARK],
29
+ ["198.51.100.0/24", RESERVED | DOCUMENTATION],
30
+ ["203.0.113.0/24", RESERVED | DOCUMENTATION],
31
+ ["224.0.0.0/4", MULTICAST],
32
+ ["240.0.0.0/4", RESERVED],
33
+ ];
34
+ const SPECIAL_V6 = [
35
+ ["::/128", RESERVED],
36
+ ["::1/128", PRIVATE | LOOPBACK],
37
+ ["::ffff:0:0/96", RESERVED],
38
+ ["64:ff9b::/96", RESERVED],
39
+ ["64:ff9b:1::/48", RESERVED],
40
+ ["100::/64", RESERVED],
41
+ ["2001::/23", RESERVED],
42
+ ["2001:db8::/32", RESERVED | DOCUMENTATION],
43
+ ["2002::/16", RESERVED],
44
+ ["3fff::/20", RESERVED | DOCUMENTATION],
45
+ ["fc00::/7", PRIVATE | UNIQUE_LOCAL],
46
+ ["fe80::/10", PRIVATE | LINK_LOCAL],
47
+ ["ff00::/8", MULTICAST],
48
+ ];
49
+ const OCTET = /^(0|[1-9][0-9]{0,2})$/;
50
+ const GROUP = /^[0-9a-fA-F]{1,4}$/;
51
+ const parseV4 = (text) => {
52
+ const parts = text.split(".");
53
+ if (parts.length !== 4)
54
+ return null;
55
+ let value = 0;
56
+ for (const part of parts) {
57
+ if (!OCTET.test(part))
58
+ return null;
59
+ const octet = Number(part);
60
+ if (octet > 255)
61
+ return null;
62
+ value = value * 256 + octet;
63
+ }
64
+ return value;
65
+ };
66
+ const groups = (text, expected) => {
67
+ if (text === "")
68
+ return [];
69
+ const parts = text.split(":");
70
+ const held = [];
71
+ for (let index = 0; index < parts.length; index += 1) {
72
+ const part = parts[index];
73
+ if (index === parts.length - 1 && part.includes(".")) {
74
+ const embedded = parseV4(part);
75
+ if (embedded === null)
76
+ return null;
77
+ held.push(embedded >>> 16, embedded & 0xffff);
78
+ continue;
79
+ }
80
+ if (!GROUP.test(part))
81
+ return null;
82
+ held.push(Number.parseInt(part, 16));
83
+ }
84
+ return held.length <= expected ? held : null;
85
+ };
86
+ const parseV6 = (text) => {
87
+ const sides = text.split("::");
88
+ if (sides.length > 2)
89
+ return null;
90
+ const head = groups(sides[0], 8);
91
+ const tail = sides.length === 2 ? groups(sides[1], 8) : [];
92
+ if (head === null || tail === null)
93
+ return null;
94
+ const held = head.length + tail.length;
95
+ if (sides.length === 1 ? held !== 8 : held > 7)
96
+ return null;
97
+ const all = [...head, ...Array(8 - held).fill(0), ...tail];
98
+ let value = 0n;
99
+ for (const group of all)
100
+ value = (value << 16n) | BigInt(group);
101
+ return value;
102
+ };
103
+ /** An address however it is written; an integer reads as v6 only above 0xffffffff. */
104
+ export const parse = (value) => {
105
+ if (typeof value === "string") {
106
+ if (value.includes(":")) {
107
+ const wide = parseV6(value);
108
+ if (wide === null)
109
+ throw new Error(`${value} is not an address`);
110
+ return [wide, true];
111
+ }
112
+ const narrow = parseV4(value);
113
+ if (narrow === null)
114
+ throw new Error(`${value} is not an address`);
115
+ return [narrow, false];
116
+ }
117
+ if (value instanceof Uint8Array) {
118
+ if (value.length === 4) {
119
+ return [
120
+ ((value[0] << 24) >>> 0) + (value[1] << 16) + (value[2] << 8) + value[3],
121
+ false,
122
+ ];
123
+ }
124
+ if (value.length !== 16)
125
+ throw new Error("packed addresses are 4 or 16 bytes");
126
+ let held = 0n;
127
+ for (const byte of value)
128
+ held = (held << 8n) | BigInt(byte);
129
+ return [held, true];
130
+ }
131
+ if (typeof value !== "bigint" && !Number.isInteger(value)) {
132
+ throw new Error(`${String(value)} is not an address`);
133
+ }
134
+ const number = typeof value === "bigint" ? value : BigInt(value);
135
+ if (number < 0n || number > V6_MAX)
136
+ throw new Error(`${value} is not an address`);
137
+ return number > BigInt(V4_MAX) ? [number, true] : [Number(number), false];
138
+ };
139
+ const hextets = (value) => Array.from({ length: 8 }, (_, index) => Number((value >> BigInt(112 - index * 16)) & 0xffffn));
140
+ const dotted = (value) => [24, 16, 8, 0].map((shift) => (value >>> shift) & 255).join(".");
141
+ const shortest = (parts, held) => {
142
+ let bestAt = -1;
143
+ let bestRun = 1;
144
+ let at = -1;
145
+ for (let index = 0; index <= held.length; index += 1) {
146
+ if (held[index] === 0 && at < 0)
147
+ at = index;
148
+ if ((held[index] !== 0 || index === held.length) && at >= 0) {
149
+ if (index - at > bestRun)
150
+ [bestAt, bestRun] = [at, index - at];
151
+ at = -1;
152
+ }
153
+ }
154
+ if (bestAt < 0)
155
+ return parts.join(":");
156
+ const head = parts.slice(0, bestAt).join(":");
157
+ const tail = parts.slice(bestAt + bestRun).join(":");
158
+ return `${head}::${tail}`;
159
+ };
160
+ /** How the address reads short and in full, and the name a resolver asks by. */
161
+ export const spelled = (value, wide) => {
162
+ if (!wide) {
163
+ const text = dotted(value);
164
+ const octets = text.split(".");
165
+ return [text, text, `${[...octets].reverse().join(".")}.in-addr.arpa`];
166
+ }
167
+ const held = hextets(value);
168
+ const nibbles = value.toString(16).padStart(32, "0");
169
+ const arpa = `${[...nibbles].reverse().join(".")}.ip6.arpa`;
170
+ const mapped = held.slice(0, 5).every((group) => group === 0) && held[5] === 0xffff;
171
+ if (mapped) {
172
+ const quad = dotted(Number(value & 0xffffffffn));
173
+ const parts = held.slice(0, 6).map((group) => group.toString(16));
174
+ const full = held.slice(0, 6).map((group) => group.toString(16).padStart(4, "0"));
175
+ return [
176
+ `${shortest(parts, held.slice(0, 6))}:${quad}`,
177
+ `${full.join(":")}:${quad}`,
178
+ arpa,
179
+ ];
180
+ }
181
+ return [
182
+ shortest(held.map((group) => group.toString(16)), held),
183
+ held.map((group) => group.toString(16).padStart(4, "0")).join(":"),
184
+ arpa,
185
+ ];
186
+ };
187
+ /** An address as text: v4 from its octets, v6 through the shortening rules. */
188
+ export const written = (value, wide) => spelled(value, wide)[0];
189
+ const table = (rows, wide) => rows
190
+ .map(([text, marks]) => {
191
+ const [network, bits] = text.split("/");
192
+ const first = BigInt(parse(network)[0]);
193
+ const spare = BigInt((wide ? 128 : 32) - Number(bits));
194
+ return [first, first + ((1n << spare) - 1n), marks];
195
+ })
196
+ .sort((left, right) => (left[0] < right[0] ? -1 : 1));
197
+ const SPECIAL = [table(SPECIAL_V4, false), table(SPECIAL_V6, true)];
198
+ /** What an address is where it is not the internet, bisected out of the table. */
199
+ export const purpose = (value, wide) => {
200
+ const rows = SPECIAL[wide ? 1 : 0];
201
+ const held = BigInt(value);
202
+ let low = 0;
203
+ let high = rows.length;
204
+ while (low < high) {
205
+ const middle = (low + high) >> 1;
206
+ if (rows[middle][0] <= held)
207
+ low = middle + 1;
208
+ else
209
+ high = middle;
210
+ }
211
+ const found = rows[low - 1];
212
+ if (found && held <= found[1])
213
+ return found[2];
214
+ return wide && held >> 125n !== 1n ? RESERVED : 0;
215
+ };
216
+ /** The v4 address a v6 one carries, and the tunnel that puts it there. */
217
+ export const tunnel = (value, wide) => {
218
+ if (!wide)
219
+ return [null, null];
220
+ const held = value;
221
+ const low = Number(held & 0xffffffffn);
222
+ if (held >> 32n === 0xffffn)
223
+ return [MAPPED, dotted(low)];
224
+ if (held >> 112n === 0x2002n) {
225
+ return [SIXTOFOUR, dotted(Number((held >> 80n) & 0xffffffffn))];
226
+ }
227
+ if (held >> 96n === 0x20010000n)
228
+ return [TEREDO, dotted(~low >>> 0)];
229
+ if (held >> 32n === 0x0064ff9bn << 64n)
230
+ return [NAT64, dotted(low)];
231
+ return [null, null];
232
+ };
233
+ /** The announcement the address falls in, masked out of the address itself. */
234
+ export const span = (value, wide, prefix) => {
235
+ const spare = BigInt((wide ? 128 : 32) - prefix);
236
+ const held = BigInt(value);
237
+ const first = (held >> spare) << spare;
238
+ const last = held | ((1n << spare) - 1n);
239
+ const start = written(wide ? first : Number(first), wide);
240
+ return [`${start}/${prefix}`, start, written(wide ? last : Number(last), wide)];
241
+ };
242
+ //# sourceMappingURL=address.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** ISO 3166 as one string: code, iso3, numeric, name and any official or common name. */
2
+ export declare const COUNTRIES: string[];
3
+ //# sourceMappingURL=countries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"countries.d.ts","sourceRoot":"","sources":["../src/countries.ts"],"names":[],"mappings":"AAAA,yFAAyF;AAEzF,eAAO,MAAM,SAAS,UA4PR,CAAC"}