plevinjs 0.2.0 → 0.2.2
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 +81 -16
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -0
- package/dist/compress.d.ts +5 -0
- package/dist/compress.d.ts.map +1 -0
- package/dist/compress.js +954 -0
- package/dist/compress.js.map +1 -0
- package/dist/countries.d.ts +1 -1
- package/dist/countries.d.ts.map +1 -1
- package/dist/countries.js +251 -250
- package/dist/countries.js.map +1 -1
- package/dist/derive.d.ts +1 -0
- package/dist/derive.d.ts.map +1 -1
- package/dist/derive.js +12 -6
- package/dist/derive.js.map +1 -1
- package/dist/estimate.d.ts +38 -0
- package/dist/estimate.d.ts.map +1 -0
- package/dist/estimate.js +263 -0
- package/dist/estimate.js.map +1 -0
- package/dist/extra.d.ts.map +1 -1
- package/dist/extra.js +12 -12
- package/dist/extra.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -6
- package/dist/index.js.map +1 -1
- package/dist/leaves.d.ts +30 -0
- package/dist/leaves.d.ts.map +1 -0
- package/dist/leaves.js +183 -0
- package/dist/leaves.js.map +1 -0
- package/dist/lzma.d.ts +18 -0
- package/dist/lzma.d.ts.map +1 -1
- package/dist/lzma.js +18 -18
- package/dist/lzma.js.map +1 -1
- package/dist/matcher.d.ts +25 -0
- package/dist/matcher.d.ts.map +1 -0
- package/dist/matcher.js +198 -0
- package/dist/matcher.js.map +1 -0
- package/dist/models.d.ts +8 -0
- package/dist/models.d.ts.map +1 -1
- package/dist/plevin.min.js +258 -257
- package/dist/reader.d.ts.map +1 -1
- package/dist/reader.js +13 -1
- package/dist/reader.js.map +1 -1
- package/dist/selection.d.ts +34 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +338 -0
- package/dist/selection.js.map +1 -0
- package/dist/slim.d.ts +21 -0
- package/dist/slim.d.ts.map +1 -0
- package/dist/slim.js +639 -0
- package/dist/slim.js.map +1 -0
- package/dist/slim.min.js +1 -0
- package/dist/stats.d.ts +61 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +368 -0
- package/dist/stats.js.map +1 -0
- package/dist/writer.d.ts +32 -0
- package/dist/writer.d.ts.map +1 -0
- package/dist/writer.js +325 -0
- package/dist/writer.js.map +1 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ No API, no rate limit, no lookup leaving the machine or the browser tab.
|
|
|
12
12
|
[](https://www.npmjs.com/package/plevinjs)
|
|
13
13
|
[](https://www.npmjs.com/package/plevinjs?activeTab=code)
|
|
14
14
|
[](https://github.com/tn3w/plevin/blob/master/LICENSE)
|
|
15
|
-
[](#fields)
|
|
16
16
|
[](#speed)
|
|
17
17
|
|
|
18
18
|
</div>
|
|
@@ -52,11 +52,11 @@ Open once, reuse for every lookup. Nothing is downloaded or cached for you.
|
|
|
52
52
|
|
|
53
53
|
| file | size | carries |
|
|
54
54
|
| ----------------------------------------------------- | ------- | ---------------------------------------- |
|
|
55
|
-
| `plevin.plv` |
|
|
56
|
-
| `plevin.metro-place.plv` |
|
|
57
|
-
| `plevin.network.plv` | 7.
|
|
58
|
-
| `plevin.abuse-level-abuse-provider-abuse-service.plv` |
|
|
59
|
-
| `plevin.place-country-code.plv` |
|
|
55
|
+
| `plevin.plv` | 18.7 MB | every field |
|
|
56
|
+
| `plevin.metro-place.plv` | 6.3 MB | city, region, postal, coordinates, metro |
|
|
57
|
+
| `plevin.network.plv` | 7.4 MB | ASN, operator, routing, registry |
|
|
58
|
+
| `plevin.abuse-level-abuse-provider-abuse-service.plv` | 4.1 MB | abuse level, service and provider |
|
|
59
|
+
| `plevin.place-country-code.plv` | 378 KB | country code |
|
|
60
60
|
|
|
61
61
|
All are served with open CORS from [plevin.tn3w.dev/db](https://plevin.tn3w.dev/db/);
|
|
62
62
|
GitHub release downloads send no CORS header.
|
|
@@ -82,8 +82,8 @@ No build step:
|
|
|
82
82
|
| `https://esm.sh/plevinjs` | the modules, imports rewritten |
|
|
83
83
|
| `https://plevin.tn3w.dev/plevin/plevin.min.js` | the bundle beside the databases |
|
|
84
84
|
|
|
85
|
-
- **Pin a version for production:** `cdn.jsdelivr.net/npm/plevinjs@0.2.
|
|
86
|
-
- **Pick the smallest build:** the country build is
|
|
85
|
+
- **Pin a version for production:** `cdn.jsdelivr.net/npm/plevinjs@0.2.2`.
|
|
86
|
+
- **Pick the smallest build:** the country build is 378 KB against 18.7 MB.
|
|
87
87
|
- **Cache the file** so it downloads once per visitor:
|
|
88
88
|
|
|
89
89
|
```js
|
|
@@ -119,7 +119,9 @@ found.place;
|
|
|
119
119
|
},
|
|
120
120
|
country: {
|
|
121
121
|
code: 'AU', name: 'Australia', official: null, common: null, iso3: 'AUS',
|
|
122
|
-
numeric: '036', flag: '🇦🇺',
|
|
122
|
+
numeric: '036', flag: '🇦🇺', currency: 'AUD', currency_name: 'Australian Dollar',
|
|
123
|
+
calling_code: '+61', languages: ['en'], european_union: false,
|
|
124
|
+
driving_side: 'left',
|
|
123
125
|
},
|
|
124
126
|
time: {
|
|
125
127
|
timezone: 'Australia/Brisbane', abbreviation: 'AEST',
|
|
@@ -131,7 +133,8 @@ found.place;
|
|
|
131
133
|
found.network;
|
|
132
134
|
{
|
|
133
135
|
asn: 13335, handle: 'CLOUDFLARENET', prefix: 24, cidr: '1.1.1.0/24',
|
|
134
|
-
start: '1.1.1.0', end: '1.1.1.255', rir: 'apnic',
|
|
136
|
+
start: '1.1.1.0', end: '1.1.1.255', rir: 'apnic', country: 'AU', since: 2011,
|
|
137
|
+
rpki: 'valid', roas: 1,
|
|
135
138
|
operator: {
|
|
136
139
|
company: 'Cloudflare, Inc.', brand: 'Cloudflare', domain: 'cloudflare.com',
|
|
137
140
|
website: 'https://www.cloudflare.com', category: 'content', tier: 2,
|
|
@@ -146,8 +149,8 @@ found.network;
|
|
|
146
149
|
db.lookup("185.220.101.1").abuse;
|
|
147
150
|
{
|
|
148
151
|
name: 'Tor', provider: 'Tor', service: 'tor_exit_node', evidence: 'measured',
|
|
149
|
-
level: 'high', risk: 0.99, network_risk: 0.86, last_seen_days: 1,
|
|
150
|
-
is_malicious: true, is_anycast: false, is_satellite: false,
|
|
152
|
+
threat: 'spam', level: 'high', risk: 0.99, network_risk: 0.86, last_seen_days: 1,
|
|
153
|
+
is_malicious: true, is_anycast: false, is_satellite: false, is_crawler: false,
|
|
151
154
|
is_hosting_provider: true, is_proxy: false, is_public_proxy: false,
|
|
152
155
|
is_residential_proxy: false, is_anonymous_vpn: false, is_tor_exit_node: true,
|
|
153
156
|
is_private_relay: false, is_anonymous: true,
|
|
@@ -156,9 +159,10 @@ db.lookup("185.220.101.1").abuse;
|
|
|
156
159
|
|
|
157
160
|
JavaScript specifics:
|
|
158
161
|
|
|
159
|
-
- `country` comes from
|
|
160
|
-
`
|
|
161
|
-
|
|
162
|
+
- `country` comes from a table in the package, generated from pycountry, Babel and
|
|
163
|
+
phonenumbers by [`test/countries.py`](test/countries.py), and `time` from the
|
|
164
|
+
runtime's `Intl` data, so neither needs an install or a network call. A different
|
|
165
|
+
zone database can move a daylight-saving boundary.
|
|
162
166
|
- `number` is a `bigint` for v6, so `JSON.stringify` needs a replacer.
|
|
163
167
|
|
|
164
168
|
Address fields (`compressed`, `expanded`, `arpa`, `is_*`, `tunnel`, `embedded_ipv4`,
|
|
@@ -252,7 +256,8 @@ of heap with the whole world touched.
|
|
|
252
256
|
## LZMA
|
|
253
257
|
|
|
254
258
|
Blocks are raw LZMA1, which neither `DecompressionStream` nor `zlib` reads, so the
|
|
255
|
-
package ships its own decoder, checked against liblzma on every block
|
|
259
|
+
package ships its own decoder, checked against liblzma on every block, and, for
|
|
260
|
+
[`slim`](#slim-databases), an encoder that writes the bytes liblzma writes.
|
|
256
261
|
|
|
257
262
|
```js
|
|
258
263
|
import { decompress } from "plevinjs/lzma";
|
|
@@ -260,6 +265,52 @@ import { decompress } from "plevinjs/lzma";
|
|
|
260
265
|
decompress(block, [3, 0, 0]); // tuning: literal context, literal position, match position bits
|
|
261
266
|
```
|
|
262
267
|
|
|
268
|
+
## Slim databases
|
|
269
|
+
|
|
270
|
+
Cut the builder's raw file down to the fields you use, in the browser or on a server.
|
|
271
|
+
It is the builder's selection pipeline in JavaScript, run on `plevin.raw`: the same
|
|
272
|
+
terms, columns, rows and boundaries merged, blocks re-encoded and compressed, so the
|
|
273
|
+
result opens like any other file.
|
|
274
|
+
|
|
275
|
+
```js
|
|
276
|
+
import { slim } from "plevinjs/slim";
|
|
277
|
+
|
|
278
|
+
const raw = new Uint8Array(await (await fetch(url)).arrayBuffer()); // plevin.raw
|
|
279
|
+
const small = slim(raw, "place.country.code+network.asn"); // 400 KB, not 18.7 MB
|
|
280
|
+
const db = new Plevin(small);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
npx plevinjs place+metro # reads plevin.raw, writes plevin.metro-place.plv
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
| terms | keeps |
|
|
288
|
+
| ---------------------- | --------------------------------------------------------- |
|
|
289
|
+
| `full` | every field the source holds |
|
|
290
|
+
| `place+metro` | every field under `place`, plus `metro`; join with `+` |
|
|
291
|
+
| `abuse.is_tor_exit_node` | one flag; rows narrowed to Tor exits only |
|
|
292
|
+
|
|
293
|
+
- **Raw in:** [`plevin.raw`](https://github.com/tn3w/plevin/releases/latest/download/plevin.raw)
|
|
294
|
+
(30 MB) is the world the builder cuts from. Slimmed files are not raw: they cannot be
|
|
295
|
+
cut again and `slim` throws on them.
|
|
296
|
+
- **Same as the builder:** byte for byte. The encoder is a port of liblzma's preset 9
|
|
297
|
+
(binary-tree matcher, optimal parse, range coder), checked on every block of the
|
|
298
|
+
release files; the same terms give the same file, `full` included. The build date
|
|
299
|
+
stays the raw file's.
|
|
300
|
+
- **Only what the source holds:** a term that matches nothing throws.
|
|
301
|
+
- **Size before building:** `estimate(stats, terms)` from `plevinjs/estimate` reads a
|
|
302
|
+
few hundred KB of counted facts (`new Slimmer(raw).stats()`, or the `stats.json`
|
|
303
|
+
beside the databases) and answers instantly, without decoding anything. Rates are fitted
|
|
304
|
+
to 172 builds; on 64 others it landed within 10% for four in five and within
|
|
305
|
+
about 2× at worst, tiny selections being the loosest. A build is exact.
|
|
306
|
+
- **Without code:** [plevin.tn3w.dev/#slim](https://plevin.tn3w.dev/#slim) picks the
|
|
307
|
+
fields, shows the size first and saves the file; it runs `slim` in a worker.
|
|
308
|
+
- **Out of the CDN bundle:** `plevinjs` and `plevin.min.js` never import it. Reach it at
|
|
309
|
+
`plevinjs/slim`, `https://esm.sh/plevinjs/slim` or
|
|
310
|
+
`https://cdn.jsdelivr.net/npm/plevinjs/dist/slim.min.js`.
|
|
311
|
+
- **Cost:** the full cut needs about 2 GB of heap and under two minutes; a country file
|
|
312
|
+
under 10 s. No native module is needed.
|
|
313
|
+
|
|
263
314
|
## Development
|
|
264
315
|
|
|
265
316
|
| module | job |
|
|
@@ -267,6 +318,15 @@ decompress(block, [3, 0, 0]); // tuning: literal context, literal position, ma
|
|
|
267
318
|
| `index.ts` | `Plevin`, `open`, result shaping |
|
|
268
319
|
| `reader.ts` | file format: sections, blocks, groups, bisection |
|
|
269
320
|
| `lzma.ts` | resumable LZMA1 decoder |
|
|
321
|
+
| `slim.ts` | `slim`: the raw file's rows, links and boundaries cut to a selection |
|
|
322
|
+
| `selection.ts` | terms, fields, columns, the builder's tables |
|
|
323
|
+
| `writer.ts` | blocks, tuning, header: the builder's `file.rs` |
|
|
324
|
+
| `compress.ts` | LZMA1 encoder, liblzma preset 9 step for step |
|
|
325
|
+
| `matcher.ts` | its binary-tree match finder |
|
|
326
|
+
| `estimate.ts` | `estimate`: a size from counted facts, no decoding |
|
|
327
|
+
| `leaves.ts` | what decides a boundary, which a selection keeps |
|
|
328
|
+
| `stats.ts` | `collect`: the counted facts `estimate` reads |
|
|
329
|
+
| `cli.ts` | `npx plevinjs` |
|
|
270
330
|
| `address.ts` | parsing, spelling, special ranges |
|
|
271
331
|
| `naming.ts` | DNS and own address |
|
|
272
332
|
| `extra.ts` | country and clock, from `countries.ts`/`zones.ts` |
|
|
@@ -281,8 +341,13 @@ npm run build # dist/ and the CDN bundle
|
|
|
281
341
|
|
|
282
342
|
node test/compare.ts ../plevin.plv sample.json # field for field against Python
|
|
283
343
|
node test/blocks.ts ../plevin.plv 100000 # every block against liblzma
|
|
344
|
+
node test/stats.ts ../plevin.raw stats.json # the facts `estimate` reads
|
|
284
345
|
```
|
|
285
346
|
|
|
347
|
+
`npm test` also splits `../plevin.raw` and compares each `plevin.*.plv` beside it, which
|
|
348
|
+
must come from the same builder run (`plevin-builder raw place+metro network ...`), and
|
|
349
|
+
`PLEVIN_RAW` / `PLEVIN_DB` point elsewhere. Files over 8 MB are skipped.
|
|
350
|
+
|
|
286
351
|
## License
|
|
287
352
|
|
|
288
353
|
Apache 2.0, see [LICENSE](https://github.com/tn3w/plevin/blob/master/LICENSE). The
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,qEAAqE"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** Cuts a database down from the shell: npx plevinjs place+metro. */
|
|
3
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { fileName, slim } from "./slim.js";
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const [input, terms, output] = args[0]?.endsWith(".raw") ? args : ["plevin.raw", ...args];
|
|
7
|
+
if (!terms) {
|
|
8
|
+
console.error("usage: npx plevinjs [plevin.raw] <terms> [output.plv]");
|
|
9
|
+
console.error("terms: full, or fields joined by +, e.g. place.country.code+network.asn");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const bytes = slim(new Uint8Array(await readFile(input)), terms);
|
|
13
|
+
const target = output ?? fileName(terms);
|
|
14
|
+
await writeFile(target, bytes);
|
|
15
|
+
console.log(`${target}: ${bytes.length} bytes`);
|
|
16
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,qEAAqE;AAErE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,CAAC;AAE1F,IAAI,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,CACX,yEAAyE,CAC1E,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACjE,MAAM,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,MAAM,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC/B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Raw LZMA1 to an end marker, step for step the encoder liblzma runs at preset 9. */
|
|
2
|
+
import { type Tuning } from "./lzma.ts";
|
|
3
|
+
/** One block as a raw stream, the way `lzma.ts` and liblzma read it. */
|
|
4
|
+
export declare const compress: (data: Uint8Array, tuning: Tuning) => Uint8Array;
|
|
5
|
+
//# sourceMappingURL=compress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAiBL,KAAK,MAAM,EACZ,MAAM,WAAW,CAAC;AA6pCnB,wEAAwE;AACxE,eAAO,MAAM,QAAQ,SAAU,UAAU,UAAU,MAAM,KAAG,UAG3D,CAAC"}
|