OverviewFilesCommitsIssuesDocsReleasesPeers

autobase-doctor commits / 6314ccf

Add multi-writer integration tests over Hyperswarm testnet
12 tests, 70 assertions covering: - One-way replication (adoption) - Two-way multi-writer (correct key = base.local.key) - Wrong key type (identity key rejected) - Reboot persistence (writers survive close+reopen) - Concurrent writes (linearization converges) - Disconnect + reconnect (offline writes merge) - Bogus key + correct key coexistence - Poison replication with drain loop patch Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6314ccf0d1426149680b9fa2d6d50bfa6cad29e3
by plankatron <fleeky@gmail.com> · 2026-03-27T16:05:50.000Z

Changed files (710) +64928 -0

docs/upstream-issue.md +64 -0
……@@ -0,0 +1,64 @@
1# autobase: host.addWriter() with unreachable key causes infinite hang in _drain()
2
3## the problem
4
5if an apply function calls `host.addWriter(key)` with a key that has no reachable hypercore behind it (wrong key type, unreplicated remote, typo, etc), the autobase enters an unrecoverable infinite loop on the next `update()` call.
6
7the loop is in `_drain()` at index.js:1838-1843:
8
9```javascript
10if (this._caughtup === false) {
11 if (!(await this._catchupApplyState())) {
12 await this._runForceFastForward()
13 }
14 continue
15}
16```
17
18what happens:
191. `_catchupApplyState()` calls `catchup()` which tries to load writer nodes
202. the writer core has no data (`core.length === 0`), so `w.update()` returns nothing
213. `catchup()` returns false
224. `_runForceFastForward()` runs but also fails (system core length is 0, so `ff._upgrade()` returns false at line 115)
235. `fastForwardFailedAt` is set to `Date.now()`
246. `continue` loops back to the top
257. `_caughtup` is still false, so we try again immediately
268. goto 1 — tight infinite loop, `update()` never resolves
27
28the `MIN_FF_WAIT` cooldown (5 minutes) exists but only guards `_queueFastForward()` and `_drainWithInterrupt()` — it's not checked in the catchup path at line 1838. so the loop bypasses the cooldown entirely.
29
30## how we hit it
31
32we have a p2p git forge (pear-git) that uses autobase for per-repo issue storage. during federation sync, a bug in our code passed an ed25519 server identity key to `host.addWriter()` instead of the actual hypercore writer core key. the key was valid (32 bytes), the op was appended to the log, `system.add()` persisted it — but no hypercore with that key exists anywhere. on every subsequent boot, the autobase replayed the poisoned op and hung.
33
34this corrupted 18 autobases across two servers. recovery required truncating writer cores, resetting system batch state, and clearing boot records. we've written tooling for this (autobase-doctor) but the root cause is the infinite loop in `_drain()`.
35
36## proposed fix
37
38respect `fastForwardFailedAt` in the catchup path — if fast-forward just failed, break out of the drain loop instead of retrying immediately:
39
40```javascript
41if (this._caughtup === false) {
42 if (!(await this._catchupApplyState())) {
43 if (this.fastForwardFailedAt > 0 && Date.now() - this.fastForwardFailedAt < MIN_FF_WAIT) {
44 break
45 }
46 await this._runForceFastForward()
47 }
48 continue
49}
50```
51
52this is a minimal change:
53- only triggers when catchup fails AND fast-forward recently failed
54- breaks out of `_drain()`, letting the next `update()` call retry after cooldown
55- normal operation is unaffected — healthy autobases never hit this path
56- autobases waiting for legitimate remote writers will retry on the next `update()` (triggered by replication events when the remote core arrives)
57
58we've tested this with autobase-test-helpers replication — all 4 scenarios pass: normal replication, safe apply with poisoned op, unsafe apply reopen, and poisoned op replicated to peer.
59
60## additional context
61
62`host.addWriter(key)` has no validation on the key — it accepts any 32-byte buffer, calls `system.add()` to persist it, then `_addWriter()` to create a writer. if the key doesn't correspond to a real hypercore, the damage is permanent: the op is in the append-only log, replays on every boot, and the system core caches the poisoned state.
63
64a secondary improvement would be for `host.addWriter()` to warn or throw if the core has no manifest after `writer.ready()`, but the drain loop fix is the critical one since it prevents the unrecoverable hang.
node_modules/.bin/brittle +1 -0
……@@ -0,0 +1 @@
1../brittle/bin/node.js
node_modules/.bin/brittle-bare +1 -0
……@@ -0,0 +1 @@
1../brittle/bin/bare.js
node_modules/.bin/brittle-node +1 -0
……@@ -0,0 +1 @@
1../brittle/bin/node.js
node_modules/.bin/brittle-pear +1 -0
……@@ -0,0 +1 @@
1../brittle/bin/pear.js
node_modules/.bin/hyperdht +1 -0
……@@ -0,0 +1 @@
1../hyperdht/bin.js
node_modules/.bin/hyperswarm-testnet +1 -0
……@@ -0,0 +1 @@
1../@hyperswarm/testnet/bin.js
node_modules/.package-lock.json +687 -0
……@@ -21,6 +21,58 @@
2121 "unslab": "^1.3.0"
2222 }
2323 },
24 "node_modules/@hyperswarm/testnet": {
25 "version": "3.1.4",
26 "resolved": "https://registry.npmjs.org/@hyperswarm/testnet/-/testnet-3.1.4.tgz",
27 "integrity": "sha512-Jw8JIZ9kdZ4R9jwJHsqctj5YeRqecw3aeCg2NS12HBXCqMioQIYzVqHs/8BWdOQCf34+BEXkwMQjba9CzaLwkg==",
28 "license": "Apache-2.0",
29 "dependencies": {
30 "hyperdht": "^6.6.0"
31 },
32 "bin": {
33 "hyperswarm-testnet": "bin.js"
34 }
35 },
36 "node_modules/@jridgewell/resolve-uri": {
37 "version": "3.1.2",
38 "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
39 "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
40 "license": "MIT",
41 "engines": {
42 "node": ">=6.0.0"
43 }
44 },
45 "node_modules/@jridgewell/sourcemap-codec": {
46 "version": "1.5.5",
47 "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
48 "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
49 "license": "MIT"
50 },
51 "node_modules/@jridgewell/trace-mapping": {
52 "version": "0.3.31",
53 "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
54 "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
55 "license": "MIT",
56 "dependencies": {
57 "@jridgewell/resolve-uri": "^3.1.0",
58 "@jridgewell/sourcemap-codec": "^1.4.14"
59 }
60 },
61 "node_modules/@types/istanbul-lib-coverage": {
62 "version": "2.0.6",
63 "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
64 "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
65 "license": "MIT"
66 },
67 "node_modules/adaptive-timeout": {
68 "version": "1.0.1",
69 "resolved": "https://registry.npmjs.org/adaptive-timeout/-/adaptive-timeout-1.0.1.tgz",
70 "integrity": "sha512-+seGiBtHqbnyZ0Quq/ZGxxwP66153WBABawa07/QeyuPFzbduPBjiGQAyCiriiLDzt3dkbMBskSlfqtRwblK8Q==",
71 "license": "Apache-2.0",
72 "dependencies": {
73 "xache": "^1.2.1"
74 }
75 },
2476 "node_modules/autobase": {
2577 "version": "7.27.3",
2678 "resolved": "https://registry.npmjs.org/autobase/-/autobase-7.27.3.tgz",
……@@ -51,6 +103,15 @@
51103 "tiny-buffer-map": "^1.1.1"
52104 }
53105 },
106 "node_modules/autobase-test-helpers": {
107 "version": "3.1.0",
108 "resolved": "https://registry.npmjs.org/autobase-test-helpers/-/autobase-test-helpers-3.1.0.tgz",
109 "integrity": "sha512-3Jk1nWEcMxYOtU6rt4ujpchLz0W/Uv7S6v0tea53wW9rZqwFzgffEYbufNak53/93DBbp3gwX+AgHdfHtpx4RQ==",
110 "license": "Apache-2.0",
111 "dependencies": {
112 "b4a": "^1.6.4"
113 }
114 },
54115 "node_modules/b4a": {
55116 "version": "1.8.0",
56117 "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
……@@ -115,6 +176,90 @@
115176 "bare-inspect": "^3.1.2"
116177 }
117178 },
179 "node_modules/bare-bundle": {
180 "version": "1.10.0",
181 "resolved": "https://registry.npmjs.org/bare-bundle/-/bare-bundle-1.10.0.tgz",
182 "integrity": "sha512-4LVlnJAHr00Hh6Vu6ZUJS38rcEtJT3b3vChXSsBsJ2mk1TN0lQ+gzd+Dw5L0aV7uqDZv84smuwW+O02X7PfDlw==",
183 "license": "Apache-2.0",
184 "peerDependencies": {
185 "bare-buffer": "*",
186 "bare-url": "*"
187 },
188 "peerDependenciesMeta": {
189 "bare-buffer": {
190 "optional": true
191 },
192 "bare-url": {
193 "optional": true
194 }
195 }
196 },
197 "node_modules/bare-cov": {
198 "version": "1.2.1",
199 "resolved": "https://registry.npmjs.org/bare-cov/-/bare-cov-1.2.1.tgz",
200 "integrity": "sha512-SHNqb/WG9udUEj8m5qGSehoUQ9o0Xzv8nrf4HIdmG+KNU/XdhPLhTP5VPrHnSAMAXhAzEB4Q+2IYZ0x9qPzN1g==",
201 "license": "Apache-2.0",
202 "dependencies": {
203 "bare-fs": "^4.1.2",
204 "bare-inspector": "^4.0.1",
205 "bare-path": "^3.0.0",
206 "bare-process": "^4.2.1",
207 "bare-url": "^2.1.5",
208 "bare-v8-to-istanbul": "^1.0.2",
209 "picomatch": "^4.0.2",
210 "which-runtime": "^1.2.1"
211 }
212 },
213 "node_modules/bare-crypto": {
214 "version": "1.13.4",
215 "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.13.4.tgz",
216 "integrity": "sha512-JiCZ5l2YOG1y8J7yy1BCAKTCZrPnHLb7pDRIdurBTOn5oIwBQDIv8iH5Pl2V85vzjl1NZXRfNY4HZLsE942jJA==",
217 "license": "Apache-2.0",
218 "dependencies": {
219 "bare-assert": "^1.2.0",
220 "bare-stream": "^2.6.3"
221 },
222 "peerDependencies": {
223 "bare-buffer": "*"
224 },
225 "peerDependenciesMeta": {
226 "bare-buffer": {
227 "optional": true
228 }
229 }
230 },
231 "node_modules/bare-debug-log": {
232 "version": "2.0.0",
233 "resolved": "https://registry.npmjs.org/bare-debug-log/-/bare-debug-log-2.0.0.tgz",
234 "integrity": "sha512-Vi42PkMQsNV9PUpx2Gl1hikshx5O9FzMJ6o9Nnopseg7qLBBK7Nl31d0RHcfwLEAfmcPApytpc0ZFfq68u22FQ==",
235 "license": "Apache-2.0",
236 "dependencies": {
237 "bare-os": "^3.0.1"
238 }
239 },
240 "node_modules/bare-dns": {
241 "version": "2.1.4",
242 "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz",
243 "integrity": "sha512-abwjHmpWqSRNB7V5615QxPH92L71AVzFm/kKTs8VYiNTAi2xVdonpv0BjJ0hwXLwomoW+xsSOPjW6PZPO14asg==",
244 "license": "Apache-2.0",
245 "engines": {
246 "bare": ">=1.7.0"
247 }
248 },
249 "node_modules/bare-encoding": {
250 "version": "1.0.3",
251 "resolved": "https://registry.npmjs.org/bare-encoding/-/bare-encoding-1.0.3.tgz",
252 "integrity": "sha512-Kqf+t/azs13lUeyK4Tb7ha4wdLRXKWCXQ8w1rVmt7KtoPCPdHD/Xwt7LBIsCSwwGglrcmblo5VOLa5avkJqULA==",
253 "license": "Apache-2.0",
254 "peerDependencies": {
255 "bare-buffer": "*"
256 },
257 "peerDependenciesMeta": {
258 "bare-buffer": {
259 "optional": true
260 }
261 }
262 },
118263 "node_modules/bare-env": {
119264 "version": "3.0.0",
120265 "resolved": "https://registry.npmjs.org/bare-env/-/bare-env-3.0.0.tgz",
……@@ -138,6 +283,15 @@
138283 }
139284 }
140285 },
286 "node_modules/bare-format": {
287 "version": "1.0.2",
288 "resolved": "https://registry.npmjs.org/bare-format/-/bare-format-1.0.2.tgz",
289 "integrity": "sha512-GswdhnOnP9QtwRbrf4wLApw5widkaLMsLe2XOs35fQD2YfEN1ApoGka+cZ7PfvzxMgfYXmMhj/2OGlVn5/Dxgw==",
290 "license": "Apache-2.0",
291 "dependencies": {
292 "bare-inspect": "^3.0.0"
293 }
294 },
141295 "node_modules/bare-fs": {
142296 "version": "4.5.6",
143297 "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.6.tgz",
……@@ -168,6 +322,47 @@
168322 "integrity": "sha512-VMb3tHo05gsnbu3OXTmkDiwTjMlOsbQmKoysKqKEyR09m77TuDrYFbj3Q5GGk10dAKsUHrnXmwCaeJqzVpB5ZA==",
169323 "license": "Apache-2.0"
170324 },
325 "node_modules/bare-http-parser": {
326 "version": "1.1.3",
327 "resolved": "https://registry.npmjs.org/bare-http-parser/-/bare-http-parser-1.1.3.tgz",
328 "integrity": "sha512-+dhVvQi6brHq14L/XHNRQ+TLuVE76VjRmMt61wVEtS+Od8xUslfMHWJN/ZjIIt3RtTG6vPuA+x9cOh7KrkBJsA==",
329 "license": "Apache-2.0"
330 },
331 "node_modules/bare-http1": {
332 "version": "4.5.5",
333 "resolved": "https://registry.npmjs.org/bare-http1/-/bare-http1-4.5.5.tgz",
334 "integrity": "sha512-ADITiRo0huP76JGMbv6Arsh9KehHqjEBoYcmjvAo67IY78+/9mV2MeKLLCkiJSFxA85T/m8cTaE44OwJQCcwdw==",
335 "license": "Apache-2.0",
336 "dependencies": {
337 "bare-events": "^2.6.0",
338 "bare-http-parser": "^1.1.1",
339 "bare-stream": "^2.10.0",
340 "bare-tcp": "^2.2.0"
341 },
342 "peerDependencies": {
343 "bare-buffer": "*",
344 "bare-url": "*"
345 },
346 "peerDependenciesMeta": {
347 "bare-buffer": {
348 "optional": true
349 },
350 "bare-url": {
351 "optional": true
352 }
353 }
354 },
355 "node_modules/bare-https": {
356 "version": "2.1.3",
357 "resolved": "https://registry.npmjs.org/bare-https/-/bare-https-2.1.3.tgz",
358 "integrity": "sha512-0TI/mJXQGYXmG7UUyWEG+KCJusayIAQLywUjFAskDoKuxfqVnGF+M/mTMrEV8J64DaIdU+5x761FvgmT7M68tA==",
359 "license": "Apache-2.0",
360 "dependencies": {
361 "bare-http1": "^4.4.0",
362 "bare-tcp": "^2.2.0",
363 "bare-tls": "^2.0.0"
364 }
365 },
171366 "node_modules/bare-inspect": {
172367 "version": "3.1.4",
173368 "resolved": "https://registry.npmjs.org/bare-inspect/-/bare-inspect-3.1.4.tgz",
……@@ -181,6 +376,71 @@
181376 "bare": ">=1.18.0"
182377 }
183378 },
379 "node_modules/bare-inspector": {
380 "version": "4.0.3",
381 "resolved": "https://registry.npmjs.org/bare-inspector/-/bare-inspector-4.0.3.tgz",
382 "integrity": "sha512-yYk6+7tTVKJKHOja5+QBn989ETv8oVsmwoH0nCM+QYC6w5MC03GC4aQNK+lipAZSz1EaAj42WZ8Wewjpy0L9TA==",
383 "license": "Apache-2.0",
384 "dependencies": {
385 "bare-events": "^2.1.0",
386 "bare-http1": "^4.0.0",
387 "bare-stream": "^2.0.0",
388 "bare-url": "^2.0.0",
389 "bare-ws": "^2.0.0"
390 },
391 "engines": {
392 "bare": ">=1.2.0"
393 },
394 "peerDependencies": {
395 "bare-tcp": "*"
396 },
397 "peerDependenciesMeta": {
398 "bare-tcp": {
399 "optional": true
400 }
401 }
402 },
403 "node_modules/bare-module": {
404 "version": "6.1.3",
405 "resolved": "https://registry.npmjs.org/bare-module/-/bare-module-6.1.3.tgz",
406 "integrity": "sha512-5XWsVHsvtWMH4tK4DQWgpNTV0t/sg3ZrAaQLIxrwjrS5+u8Q9vEgc/zQ4QaDPWDse/y/5h+d+YG1Q0JfSMt0zA==",
407 "license": "Apache-2.0",
408 "dependencies": {
409 "bare-bundle": "^1.3.0",
410 "bare-module-lexer": "^1.0.0",
411 "bare-module-resolve": "^1.8.0",
412 "bare-path": "^3.0.0",
413 "bare-url": "^2.0.1"
414 },
415 "engines": {
416 "bare": ">=1.23.0"
417 },
418 "peerDependencies": {
419 "bare-buffer": "*"
420 },
421 "peerDependenciesMeta": {
422 "bare-buffer": {
423 "optional": true
424 }
425 }
426 },
427 "node_modules/bare-module-lexer": {
428 "version": "1.4.7",
429 "resolved": "https://registry.npmjs.org/bare-module-lexer/-/bare-module-lexer-1.4.7.tgz",
430 "integrity": "sha512-0klU4eMsjh/wcxi8FdHmNom2j2F4kmkXOhyJFL9qTaSFp2lE3m6BtbKgMHY8R5miqC9r8/IfA8wzXnC5Os14WA==",
431 "license": "Apache-2.0",
432 "dependencies": {
433 "require-addon": "^1.0.2"
434 },
435 "peerDependencies": {
436 "bare-buffer": "*"
437 },
438 "peerDependenciesMeta": {
439 "bare-buffer": {
440 "optional": true
441 }
442 }
443 },
184444 "node_modules/bare-module-resolve": {
185445 "version": "1.12.1",
186446 "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz",
……@@ -198,6 +458,18 @@
198458 }
199459 }
200460 },
461 "node_modules/bare-net": {
462 "version": "2.3.1",
463 "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.1.tgz",
464 "integrity": "sha512-MypSqDKpDU2Xt7FIfazn5yGvRnV09gFcIPHGWstW0gxuzA4tucTcwJSZeos97C4F89vtU5oGwXDN/HrGN6Y4Jw==",
465 "license": "Apache-2.0",
466 "dependencies": {
467 "bare-events": "^2.2.2",
468 "bare-pipe": "^4.0.0",
469 "bare-stream": "^2.0.0",
470 "bare-tcp": "^2.0.0"
471 }
472 },
201473 "node_modules/bare-os": {
202474 "version": "3.8.0",
203475 "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.0.tgz",
……@@ -290,6 +562,67 @@
290562 }
291563 }
292564 },
565 "node_modules/bare-stylize": {
566 "version": "0.0.1",
567 "resolved": "https://registry.npmjs.org/bare-stylize/-/bare-stylize-0.0.1.tgz",
568 "integrity": "sha512-l3MjmIl476bWijYWf3RbE+osl4iuXSOMudzp0vAqzIK7gPgn/+G3oAxp8Oin9CFF911KBP0LO9kts8Ci8mGZaQ==",
569 "license": "Apache-2.0",
570 "dependencies": {
571 "bare-ansi-escapes": "^2.2.3",
572 "bare-process": "^4.2.1"
573 }
574 },
575 "node_modules/bare-subprocess": {
576 "version": "5.2.3",
577 "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-5.2.3.tgz",
578 "integrity": "sha512-07wwswlV7M3sC9IykbZRZ/jHAkrXFWVLqdBWGv1y0ojCimtRD9hGwxdHmR5FUFmDUZLNsBmTYJNQqgio5+A85Q==",
579 "license": "Apache-2.0",
580 "dependencies": {
581 "bare-env": "^3.0.0",
582 "bare-events": "^2.5.4",
583 "bare-os": "^3.0.1",
584 "bare-pipe": "^4.0.0",
585 "bare-url": "^2.2.2"
586 },
587 "engines": {
588 "bare": ">=1.7.0"
589 },
590 "peerDependencies": {
591 "bare-buffer": "*"
592 },
593 "peerDependenciesMeta": {
594 "bare-buffer": {
595 "optional": true
596 }
597 }
598 },
599 "node_modules/bare-tcp": {
600 "version": "2.2.7",
601 "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.2.7.tgz",
602 "integrity": "sha512-rjpqNQ2cOCkNo3NeYA/W4GTK3DRkl8sDHO3uos+AEswUjLC8XXMQF8WrJCSjlIowCbS6NUVxKE92X5RGXjyefg==",
603 "license": "Apache-2.0",
604 "dependencies": {
605 "bare-dns": "^2.0.4",
606 "bare-events": "^2.5.4",
607 "bare-stream": "^2.6.4"
608 },
609 "engines": {
610 "bare": ">=1.16.0"
611 }
612 },
613 "node_modules/bare-tls": {
614 "version": "2.2.1",
615 "resolved": "https://registry.npmjs.org/bare-tls/-/bare-tls-2.2.1.tgz",
616 "integrity": "sha512-hZ+ZqwrUO4dyH7/6WYkYWjgAFNJKjzwEYJiDaMnMs+eRleBDjQ3CvNZawpkw0Ar9jnM9NZK6+f6GqjkZ2FLGmQ==",
617 "license": "Apache-2.0",
618 "dependencies": {
619 "bare-net": "^2.0.1",
620 "bare-stream": "^2.6.4"
621 },
622 "engines": {
623 "bare": ">=1.7.0"
624 }
625 },
293626 "node_modules/bare-tty": {
294627 "version": "5.0.3",
295628 "resolved": "https://registry.npmjs.org/bare-tty/-/bare-tty-5.0.3.tgz",
……@@ -318,16 +651,137 @@
318651 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz",
319652 "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==",
320653 "license": "Apache-2.0",
654 "peer": true,
321655 "dependencies": {
322656 "bare-path": "^3.0.0"
323657 }
324658 },
659 "node_modules/bare-utils": {
660 "version": "1.6.0",
661 "resolved": "https://registry.npmjs.org/bare-utils/-/bare-utils-1.6.0.tgz",
662 "integrity": "sha512-WhQEIkkAxkSnW7u1QgrI0AfNm5JpMruETXeYsb5qnkBJ0TTfNKygZmsh6rkoHBANaV+C/7Jed7bJP9OmEHG7rQ==",
663 "license": "Apache-2.0",
664 "dependencies": {
665 "bare-debug-log": "^2.0.0",
666 "bare-encoding": "^1.0.0",
667 "bare-format": "^1.0.0",
668 "bare-inspect": "^3.0.0",
669 "bare-stylize": "^0.0.1",
670 "bare-type": "^1.0.6"
671 }
672 },
673 "node_modules/bare-v8-to-istanbul": {
674 "version": "1.0.2",
675 "resolved": "https://registry.npmjs.org/bare-v8-to-istanbul/-/bare-v8-to-istanbul-1.0.2.tgz",
676 "integrity": "sha512-CM0wPgyQtXTQ7h4q8NjbTZ/FH5he0Jkiwgpq0lFZZA5tkVZzmQ/9ul4R7E+cNlGZJIZlQZ9v4CwbgVaFG3zOAA==",
677 "license": "Apache-2.0",
678 "dependencies": {
679 "bare-assert": "^1.0.2",
680 "bare-fs": "^4.1.2",
681 "bare-module": "^6.1.2",
682 "bare-path": "^3.0.0",
683 "bare-process": "^4.2.0",
684 "bare-url": "^2.1.5",
685 "bare-utils": "^1.2.0",
686 "v8-to-istanbul": "^9.3.0",
687 "which-runtime": "^1.2.1"
688 }
689 },
690 "node_modules/bare-ws": {
691 "version": "2.1.0",
692 "resolved": "https://registry.npmjs.org/bare-ws/-/bare-ws-2.1.0.tgz",
693 "integrity": "sha512-2gEWlPK9iyBchACdIY6oQXgmDz3KLrChdwrPgmU3IVXOFTnxTqSUT27WE/+izd4QojHj/SsqDkQiD2HDvuTdAA==",
694 "license": "Apache-2.0",
695 "dependencies": {
696 "bare-crypto": "^1.2.0",
697 "bare-events": "^2.3.1",
698 "bare-http1": "^4.0.0",
699 "bare-https": "^2.0.0",
700 "bare-stream": "^2.1.2"
701 },
702 "peerDependencies": {
703 "bare-buffer": "*",
704 "bare-url": "*"
705 },
706 "peerDependenciesMeta": {
707 "bare-buffer": {
708 "optional": true
709 },
710 "bare-url": {
711 "optional": true
712 }
713 }
714 },
325715 "node_modules/big-sparse-array": {
326716 "version": "1.0.3",
327717 "resolved": "https://registry.npmjs.org/big-sparse-array/-/big-sparse-array-1.0.3.tgz",
328718 "integrity": "sha512-6RjV/3mSZORlMdpUaQ6rUSpG637cZm0//E54YYGtQg1c1O+AbZP8UTdJ/TchsDZcTVLmyWZcseBfp2HBeXUXOQ==",
329719 "license": "MIT"
330720 },
721 "node_modules/bits-to-bytes": {
722 "version": "1.3.0",
723 "resolved": "https://registry.npmjs.org/bits-to-bytes/-/bits-to-bytes-1.3.0.tgz",
724 "integrity": "sha512-OJoHTpFXS9bXHBCekGTByf3MqM8CGblBDIduKQeeVVeiU9dDWywSSirXIBYGgg3d1zbVuvnMa1vD4r6PA0kOKg==",
725 "license": "ISC",
726 "dependencies": {
727 "b4a": "^1.5.0"
728 }
729 },
730 "node_modules/blind-relay": {
731 "version": "1.4.0",
732 "resolved": "https://registry.npmjs.org/blind-relay/-/blind-relay-1.4.0.tgz",
733 "integrity": "sha512-6xt7fDfCs6eGmNNym6I9N42jmjcMQn2qwwOVnkP9ZnrkXFk6c4/tdO1xqRmDEzKzV8gigd+DVdCUG/RUYnen7Q==",
734 "license": "Apache-2.0",
735 "dependencies": {
736 "b4a": "^1.6.4",
737 "bare-events": "^2.2.0",
738 "bits-to-bytes": "^1.3.0",
739 "compact-encoding": "^2.12.0",
740 "compact-encoding-bitfield": "^1.0.0",
741 "protomux": "^3.5.1",
742 "sodium-universal": "^5.0.0",
743 "streamx": "^2.15.1"
744 }
745 },
746 "node_modules/bogon": {
747 "version": "1.2.0",
748 "resolved": "https://registry.npmjs.org/bogon/-/bogon-1.2.0.tgz",
749 "integrity": "sha512-FqOBr/1VMzCOsoJd+fzNUMarUYki2+TKt07A2+xaulsNx4r53iJ7MV5k0jbqg7W2U0CsLqxCZOrFibdG6h6HSg==",
750 "license": "MIT",
751 "dependencies": {
752 "compact-encoding": "^2.11.0",
753 "compact-encoding-net": "^1.2.0"
754 }
755 },
756 "node_modules/brittle": {
757 "version": "3.19.1",
758 "resolved": "https://registry.npmjs.org/brittle/-/brittle-3.19.1.tgz",
759 "integrity": "sha512-4Ted1Mt9o9B6oIA6ImJJCtB/Fv++ZO3IDNQgRcHOXWSYGRUidgxchaGrUBaRn+4mlneXrgInPkCPzi0jO8qKbA==",
760 "license": "Apache-2.0",
761 "dependencies": {
762 "b4a": "^1.6.0",
763 "bare-assert": "^1.0.2",
764 "bare-cov": "^1.1.0",
765 "bare-fs": "^4.1.6",
766 "bare-os": "^3.6.1",
767 "bare-path": "^3.0.0",
768 "bare-process": "^4.2.1",
769 "bare-subprocess": "^5.0.0",
770 "bare-url": "^2.1.6",
771 "error-stack-parser": "^2.1.4",
772 "globbie": "^1.0.2",
773 "paparam": "^1.6.2",
774 "same-object": "^1.0.2",
775 "test-tmp": "^1.4.0",
776 "tmatch": "^5.0.0"
777 },
778 "bin": {
779 "brittle": "bin/node.js",
780 "brittle-bare": "bin/bare.js",
781 "brittle-node": "bin/node.js",
782 "brittle-pear": "bin/pear.js"
783 }
784 },
331785 "node_modules/codecs": {
332786 "version": "3.1.0",
333787 "resolved": "https://registry.npmjs.org/codecs/-/codecs-3.1.0.tgz",
……@@ -346,6 +800,30 @@
346800 "b4a": "^1.3.0"
347801 }
348802 },
803 "node_modules/compact-encoding-bitfield": {
804 "version": "1.0.0",
805 "resolved": "https://registry.npmjs.org/compact-encoding-bitfield/-/compact-encoding-bitfield-1.0.0.tgz",
806 "integrity": "sha512-3nMVKUg+PF72UHfainmCL8uKvyWfxsjqOtUY+HiMPGLPCTjnwzoKfFAMo1Ad7nwTPdjBqtGK5b3BOFTFW4EBTg==",
807 "license": "ISC",
808 "dependencies": {
809 "compact-encoding": "^2.4.1"
810 }
811 },
812 "node_modules/compact-encoding-net": {
813 "version": "1.2.0",
814 "resolved": "https://registry.npmjs.org/compact-encoding-net/-/compact-encoding-net-1.2.0.tgz",
815 "integrity": "sha512-LVXpNpF7PGQeHRVVLGgYWzuVoYAaDZvKUsUxRioGfkotzvOh4AzoQF1HBH3zMNaSnx7gJXuUr3hkjnijaH/Eng==",
816 "license": "ISC",
817 "dependencies": {
818 "compact-encoding": "^2.4.1"
819 }
820 },
821 "node_modules/convert-source-map": {
822 "version": "2.0.0",
823 "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
824 "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
825 "license": "MIT"
826 },
349827 "node_modules/core-coupler": {
350828 "version": "2.0.0",
351829 "resolved": "https://registry.npmjs.org/core-coupler/-/core-coupler-2.0.0.tgz",
……@@ -391,6 +869,26 @@
391869 "ready-resource": "^1.2.0"
392870 }
393871 },
872 "node_modules/dht-rpc": {
873 "version": "6.26.3",
874 "resolved": "https://registry.npmjs.org/dht-rpc/-/dht-rpc-6.26.3.tgz",
875 "integrity": "sha512-KuLfRv/hecUHipQcTXHpVv4/N4Jhpww5sLdsrn3Edm5oHwzK9SgNV34hNt7a2aVZCOcG5SfP4AvcQ7pI+y9YNg==",
876 "license": "MIT",
877 "dependencies": {
878 "adaptive-timeout": "^1.0.1",
879 "b4a": "^1.6.1",
880 "bare-events": "^2.2.0",
881 "compact-encoding": "^2.11.0",
882 "compact-encoding-net": "^1.2.0",
883 "fast-fifo": "^1.1.0",
884 "kademlia-routing-table": "^1.0.1",
885 "nat-sampler": "^1.0.1",
886 "sodium-universal": "^5.0.0",
887 "streamx": "^2.13.2",
888 "time-ordered-set": "^2.0.0",
889 "udx-native": "^1.5.3"
890 }
891 },
394892 "node_modules/encryption-encoding": {
395893 "version": "1.0.3",
396894 "resolved": "https://registry.npmjs.org/encryption-encoding/-/encryption-encoding-1.0.3.tgz",
……@@ -400,6 +898,15 @@
400898 "hyperschema": "^1.19.0"
401899 }
402900 },
901 "node_modules/error-stack-parser": {
902 "version": "2.1.4",
903 "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
904 "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
905 "license": "MIT",
906 "dependencies": {
907 "stackframe": "^1.3.4"
908 }
909 },
403910 "node_modules/events-universal": {
404911 "version": "1.0.1",
405912 "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
……@@ -458,6 +965,18 @@
458965 "integrity": "sha512-IfTY0dKZM43ACyGvXkbG7De7WY7MxTS5VO6Juhe8oJKpCmrYYXoqp/cJMskkpi0k9H8wuXq0H+eI898/BCqvXg==",
459966 "license": "MIT"
460967 },
968 "node_modules/globbie": {
969 "version": "1.0.3",
970 "resolved": "https://registry.npmjs.org/globbie/-/globbie-1.0.3.tgz",
971 "integrity": "sha512-hcryJmKcftf82xfBWTWxuUITWIIoYO3ec104V17SMHGFl6VLbm1d1Ju9LX9L+jyJTwICpemX/dmPI/HGYoKr1A==",
972 "license": "Apache-2.0",
973 "dependencies": {
974 "bare-fs": "^4.1.2",
975 "bare-path": "^3.0.0",
976 "bare-process": "^4.2.1",
977 "picomatch": "^4.0.2"
978 }
979 },
461980 "node_modules/hyperbee": {
462981 "version": "2.27.3",
463982 "resolved": "https://registry.npmjs.org/hyperbee/-/hyperbee-2.27.3.tgz",
……@@ -558,6 +1077,35 @@
5581077 "streamx": "^2.21.1"
5591078 }
5601079 },
1080 "node_modules/hyperdht": {
1081 "version": "6.29.6",
1082 "resolved": "https://registry.npmjs.org/hyperdht/-/hyperdht-6.29.6.tgz",
1083 "integrity": "sha512-bMMtw02fhiALdsTVLNZ/VFmMZuEY8kxb0/Rprl6oYF4/TCS653i3FDjtJeRbqtnAzwAj6dVZ/EwhoNOSCFGaYQ==",
1084 "license": "MIT",
1085 "dependencies": {
1086 "@hyperswarm/secret-stream": "^6.6.2",
1087 "b4a": "^1.3.1",
1088 "bare-events": "^2.2.0",
1089 "blind-relay": "^1.3.0",
1090 "bogon": "^1.0.0",
1091 "compact-encoding": "^2.4.1",
1092 "dht-rpc": "^6.15.1",
1093 "hypercore-crypto": "^3.3.0",
1094 "hypercore-id-encoding": "^1.2.0",
1095 "noise-curve-ed": "^2.0.0",
1096 "noise-handshake": "^4.0.0",
1097 "record-cache": "^1.1.1",
1098 "safety-catch": "^1.0.1",
1099 "signal-promise": "^1.0.3",
1100 "sodium-universal": "^5.0.1",
1101 "streamx": "^2.16.1",
1102 "unslab": "^1.3.0",
1103 "xache": "^1.1.0"
1104 },
1105 "bin": {
1106 "hyperdht": "bin.js"
1107 }
1108 },
5611109 "node_modules/hyperschema": {
5621110 "version": "1.20.1",
5631111 "resolved": "https://registry.npmjs.org/hyperschema/-/hyperschema-1.20.1.tgz",
……@@ -570,6 +1118,21 @@
5701118 "generate-string": "^1.0.1"
5711119 }
5721120 },
1121 "node_modules/hyperswarm": {
1122 "version": "4.17.0",
1123 "resolved": "https://registry.npmjs.org/hyperswarm/-/hyperswarm-4.17.0.tgz",
1124 "integrity": "sha512-oe86sK961Ueg7rvDN/veFwG8xH+Iv6vObPhGDkPJcDVxk/NduW41ZhAcVDnHzRbm7S0eLU7WaDUvehOYoKSpRQ==",
1125 "license": "MIT",
1126 "dependencies": {
1127 "b4a": "^1.3.1",
1128 "bare-events": "^2.2.0",
1129 "hyperdht": "^6.21.0",
1130 "safety-catch": "^1.0.2",
1131 "shuffled-priority-queue": "^2.1.0",
1132 "streamx": "^2.22.1",
1133 "unslab": "^1.3.0"
1134 }
1135 },
5731136 "node_modules/index-encoder": {
5741137 "version": "3.5.0",
5751138 "resolved": "https://registry.npmjs.org/index-encoder/-/index-encoder-3.5.0.tgz",
……@@ -594,6 +1157,15 @@
5941157 "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
5951158 "license": "MIT"
5961159 },
1160 "node_modules/kademlia-routing-table": {
1161 "version": "1.0.6",
1162 "resolved": "https://registry.npmjs.org/kademlia-routing-table/-/kademlia-routing-table-1.0.6.tgz",
1163 "integrity": "sha512-Ve6jwIlUCYvUzBnXnzVRHDZCFgXURW9gmF3r7n05kZs/2rNbLHXwGdcq0qIaSwdmJCvtosgR4JensnVU65hzNQ==",
1164 "license": "MIT",
1165 "dependencies": {
1166 "bare-events": "^2.2.0"
1167 }
1168 },
5971169 "node_modules/mutexify": {
5981170 "version": "1.4.0",
5991171 "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.4.0.tgz",
……@@ -609,6 +1181,12 @@
6091181 "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==",
6101182 "license": "ISC"
6111183 },
1184 "node_modules/nat-sampler": {
1185 "version": "1.0.1",
1186 "resolved": "https://registry.npmjs.org/nat-sampler/-/nat-sampler-1.0.1.tgz",
1187 "integrity": "sha512-yQvyNN7xbqR8crTKk3U8gRgpcV1Az+vfCEijiHu9oHHsnIl8n3x+yXNHl42M6L3czGynAVoOT9TqBfS87gDdcw==",
1188 "license": "MIT"
1189 },
6121190 "node_modules/noise-curve-ed": {
6131191 "version": "2.1.0",
6141192 "resolved": "https://registry.npmjs.org/noise-curve-ed/-/noise-curve-ed-2.1.0.tgz",
……@@ -637,6 +1215,18 @@
6371215 "integrity": "sha512-viyQI64VIja0Za3njIzhoEP8ZVkgPowhZPuG0E96NwBfYJ6ZIyrrlhWGtFPkdN7eYLl2L8CTWL+wla0evm1KKQ==",
6381216 "license": "Apache-2.0"
6391217 },
1218 "node_modules/picomatch": {
1219 "version": "4.0.4",
1220 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
1221 "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
1222 "license": "MIT",
1223 "engines": {
1224 "node": ">=12"
1225 },
1226 "funding": {
1227 "url": "https://github.com/sponsors/jonschlinkert"
1228 }
1229 },
6401230 "node_modules/protocol-buffers-encodings": {
6411231 "version": "1.2.0",
6421232 "resolved": "https://registry.npmjs.org/protocol-buffers-encodings/-/protocol-buffers-encodings-1.2.0.tgz",
……@@ -723,6 +1313,15 @@
7231313 "bare-events": "^2.2.0"
7241314 }
7251315 },
1316 "node_modules/record-cache": {
1317 "version": "1.2.0",
1318 "resolved": "https://registry.npmjs.org/record-cache/-/record-cache-1.2.0.tgz",
1319 "integrity": "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw==",
1320 "license": "MIT",
1321 "dependencies": {
1322 "b4a": "^1.3.1"
1323 }
1324 },
7261325 "node_modules/refcounter": {
7271326 "version": "1.0.0",
7281327 "resolved": "https://registry.npmjs.org/refcounter/-/refcounter-1.0.0.tgz",
……@@ -777,12 +1376,27 @@
7771376 "integrity": "sha512-Zq+J1TefpoEq/HTUabo0YXX5MNvttjWYODGohgPBO2jfko8Wqx3JYMgE823szDFVamdH5PlpByvfiWScTdSYDA==",
7781377 "license": "MIT"
7791378 },
1379 "node_modules/same-object": {
1380 "version": "1.0.2",
1381 "resolved": "https://registry.npmjs.org/same-object/-/same-object-1.0.2.tgz",
1382 "integrity": "sha512-csHWhvUsLbIOHDM/nP+KHWM+BLPsIzWkFa8HbzaI0G7BqKXgx+7FJpKTGgLXyz5amfdY2OVBcmXTqYOMEk04og==",
1383 "license": "MIT"
1384 },
7801385 "node_modules/scope-lock": {
7811386 "version": "1.2.4",
7821387 "resolved": "https://registry.npmjs.org/scope-lock/-/scope-lock-1.2.4.tgz",
7831388 "integrity": "sha512-BpSd8VCuCxW9ZitcdIC/vjs3gMaP9bRBL5nkHcyfX2VrS52n13/rHuBA2xJ/S/4DPuRdAO/Bk8pWd8eD/gHCIA==",
7841389 "license": "Apache-2.0"
7851390 },
1391 "node_modules/shuffled-priority-queue": {
1392 "version": "2.1.0",
1393 "resolved": "https://registry.npmjs.org/shuffled-priority-queue/-/shuffled-priority-queue-2.1.0.tgz",
1394 "integrity": "sha512-xhdh7fHyMsr0m/w2kDfRJuBFRS96b9l8ZPNWGaQ+PMvnUnZ/Eh+gJJ9NsHBd7P9k0399WYlCLzsy18EaMfyadA==",
1395 "license": "MIT",
1396 "dependencies": {
1397 "unordered-set": "^2.0.1"
1398 }
1399 },
7861400 "node_modules/signal-promise": {
7871401 "version": "1.0.3",
7881402 "resolved": "https://registry.npmjs.org/signal-promise/-/signal-promise-1.0.3.tgz",
……@@ -862,6 +1476,12 @@
8621476 }
8631477 }
8641478 },
1479 "node_modules/stackframe": {
1480 "version": "1.3.4",
1481 "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
1482 "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
1483 "license": "MIT"
1484 },
8651485 "node_modules/streamx": {
8661486 "version": "2.25.0",
8671487 "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz",
……@@ -892,6 +1512,17 @@
8921512 "streamx": "^2.12.5"
8931513 }
8941514 },
1515 "node_modules/test-tmp": {
1516 "version": "1.4.0",
1517 "resolved": "https://registry.npmjs.org/test-tmp/-/test-tmp-1.4.0.tgz",
1518 "integrity": "sha512-GVggxGg+jXqP2Wbju50JVLo+9E+nIOPPyWqgr63EbOnNItIKu1cEbJpTWAJeflnyGqXOtcMI7ijHRp88GUkfDA==",
1519 "license": "MIT",
1520 "dependencies": {
1521 "bare-fs": "^4.0.1",
1522 "bare-os": "^3.3.0",
1523 "bare-path": "^3.0.0"
1524 }
1525 },
8951526 "node_modules/text-decoder": {
8961527 "version": "1.2.7",
8971528 "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
……@@ -901,6 +1532,12 @@
9011532 "b4a": "^1.6.4"
9021533 }
9031534 },
1535 "node_modules/time-ordered-set": {
1536 "version": "2.0.1",
1537 "resolved": "https://registry.npmjs.org/time-ordered-set/-/time-ordered-set-2.0.1.tgz",
1538 "integrity": "sha512-VJEKmgSN2UiOLB8BpN8Sh2b9LGMHTP5OPrQRpnKjvOheOyzk0mufbjzjKTIG2gO4A+Y+vDJ+0TcLbpUmMLsg8A==",
1539 "license": "MIT"
1540 },
9041541 "node_modules/timeout-refresh": {
9051542 "version": "2.0.1",
9061543 "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-2.0.1.tgz",
……@@ -916,6 +1553,36 @@
9161553 "b4a": "^1.6.0"
9171554 }
9181555 },
1556 "node_modules/tmatch": {
1557 "version": "5.0.0",
1558 "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-5.0.0.tgz",
1559 "integrity": "sha512-Ib9OtBkpHn07tXP04SlN1SYRxFgTk6wSM2EBmjjxug4u5RXPRVLkdFJSS1PmrQidaSB8Lru9nRtViQBsbxzE5Q==",
1560 "license": "ISC",
1561 "engines": {
1562 "node": ">=8"
1563 }
1564 },
1565 "node_modules/udx-native": {
1566 "version": "1.19.2",
1567 "resolved": "https://registry.npmjs.org/udx-native/-/udx-native-1.19.2.tgz",
1568 "integrity": "sha512-RNYh+UhfryCsF5hE2ZOuIqcZ+qdipXK3UsarwxWJwsUQZFE3ybwz0mPjwb5ev1PMBcjFahWiepS/q0wwL51c2g==",
1569 "license": "Apache-2.0",
1570 "dependencies": {
1571 "b4a": "^1.5.0",
1572 "bare-events": "^2.2.0",
1573 "require-addon": "^1.1.0",
1574 "streamx": "^2.22.0"
1575 },
1576 "engines": {
1577 "bare": ">=1.17.4"
1578 }
1579 },
1580 "node_modules/unordered-set": {
1581 "version": "2.0.1",
1582 "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz",
1583 "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==",
1584 "license": "MIT"
1585 },
9191586 "node_modules/unslab": {
9201587 "version": "1.3.0",
9211588 "resolved": "https://registry.npmjs.org/unslab/-/unslab-1.3.0.tgz",
……@@ -925,6 +1592,20 @@
9251592 "b4a": "^1.6.6"
9261593 }
9271594 },
1595 "node_modules/v8-to-istanbul": {
1596 "version": "9.3.0",
1597 "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
1598 "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
1599 "license": "ISC",
1600 "dependencies": {
1601 "@jridgewell/trace-mapping": "^0.3.12",
1602 "@types/istanbul-lib-coverage": "^2.0.1",
1603 "convert-source-map": "^2.0.0"
1604 },
1605 "engines": {
1606 "node": ">=10.12.0"
1607 }
1608 },
9281609 "node_modules/varint": {
9291610 "version": "5.0.0",
9301611 "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
……@@ -937,6 +1618,12 @@
9371618 "integrity": "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw==",
9381619 "license": "Apache-2.0"
9391620 },
1621 "node_modules/xache": {
1622 "version": "1.2.1",
1623 "resolved": "https://registry.npmjs.org/xache/-/xache-1.2.1.tgz",
1624 "integrity": "sha512-igRS6jPreJ54ABdzhh4mCDXcz+XMaWO2q1ABRV2yWYuk29jlp8VT7UBdCqNkX7rpYBbXsebVVKkwIuYZjyZNqA==",
1625 "license": "MIT"
1626 },
9401627 "node_modules/z32": {
9411628 "version": "1.1.0",
9421629 "resolved": "https://registry.npmjs.org/z32/-/z32-1.1.0.tgz",
node_modules/@hyperswarm/testnet/.github/workflows/test-node.yml +23 -0
……@@ -0,0 +1,23 @@
1name: Build Status
2on:
3 push:
4 branches:
5 - main
6 pull_request:
7 branches:
8 - main
9jobs:
10 build:
11 strategy:
12 matrix:
13 node-version: [lts/*]
14 os: [ubuntu-latest, macos-latest, windows-latest]
15 runs-on: ${{ matrix.os }}
16 steps:
17 - uses: actions/checkout@v2
18 - name: Use Node.js ${{ matrix.node-version }}
19 uses: actions/setup-node@v2
20 with:
21 node-version: ${{ matrix.node-version }}
22 - run: npm install
23 - run: npm test
node_modules/@hyperswarm/testnet/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/@hyperswarm/testnet/NOTICE +13 -0
……@@ -0,0 +1,13 @@
1Copyright 2023 Contributors
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
node_modules/@hyperswarm/testnet/README.md +51 -0
……@@ -0,0 +1,51 @@
1# @hyperswarm/testnet
2
3Small module to help you spin up a local Hyperswarm testnet.
4
5```
6npm install @hyperswarm/testnet
7```
8
9Use this if you want to use the swarm in tests, etc.
10
11## Usage
12
13``` js
14const createTestnet = require('@hyperswarm/testnet')
15
16const testnet = await createTestnet(10) // create a local testnet with 10 dht nodes
17```
18
19## API
20
21#### `const testnet = await createTestnet(size = 10, [options])`
22
23Create a new testnet. `size` is how many DHT nodes you want in it. Options include:
24
25```js
26{
27 port: preferredLocalPort, // defaults to ANY (0)
28 host: preferredLocalHost, // defaults to 127.0.0.1
29 teardown // optional async teardown helper ie, t.teardown in brittle/tap etc
30}
31```
32
33#### `testnet.nodes`
34
35An array of nodes in the testnet.
36
37#### `testnet.bootstrap`
38
39An array of bootstrap addresses of the testnet.
40
41#### `const node = testnet.createNode([options])`
42
43Create an additional ephemeral node and add it to the testnet. Options are the same as [`new DHT()`](https://github.com/holepunchto/hyperdht#const-node--new-dhtoptions).
44
45#### `for (const node of testnet)`
46
47Iterate over the nodes of the testnet.
48
49## License
50
51Apache-2.0
node_modules/@hyperswarm/testnet/bin.js +25 -0
……@@ -0,0 +1,25 @@
1#!/usr/bin/env node
2
3const testnet = require('@hyperswarm/testnet')
4
5const size = Number(arg('--size', '-s') || 30)
6const host = arg('--host', '-h') || '127.0.0.1'
7
8testnet(size, { host, port: 49736 }).then(function ({ nodes, bootstrap }) {
9 console.log('Running a testnet of ' + nodes.length + ' nodes')
10 console.log('Bootstrap:', bootstrap)
11})
12
13function arg (name, short) {
14 for (let i = 2; i < process.argv.length; i++) {
15 const arg = process.argv[i]
16
17 if (arg === name || arg === short) {
18 return process.argv[i + 1]
19 }
20 if (arg.startsWith(name + '=')) {
21 return arg.slice(name.length + 1)
22 }
23 }
24 return ''
25}
node_modules/@hyperswarm/testnet/index.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require('hyperdht/testnet')
node_modules/@hyperswarm/testnet/package.json +29 -0
……@@ -0,0 +1,29 @@
1{
2 "name": "@hyperswarm/testnet",
3 "version": "3.1.4",
4 "description": "Small module to help you spin up a local Hyperswarm testnet",
5 "main": "index.js",
6 "bin": {
7 "hyperswarm-testnet": "./bin.js"
8 },
9 "dependencies": {
10 "hyperdht": "^6.6.0"
11 },
12 "devDependencies": {
13 "brittle": "^3.0.0",
14 "standard": "^17.0.0"
15 },
16 "scripts": {
17 "test": "standard && brittle test.mjs"
18 },
19 "repository": {
20 "type": "git",
21 "url": "https://github.com/holepunchto/hyperswarm-testnet.git"
22 },
23 "author": "Mathias Buus (@mafintosh)",
24 "license": "Apache-2.0",
25 "bugs": {
26 "url": "https://github.com/holepunchto/hyperswarm-testnet/issues"
27 },
28 "homepage": "https://github.com/holepunchto/hyperswarm-testnet"
29}
node_modules/@hyperswarm/testnet/test.mjs +23 -0
……@@ -0,0 +1,23 @@
1import test from 'brittle'
2import createTestnet from './index.js'
3
4test('basic', async (t) => {
5 const testnet = await createTestnet(3, t.teardown)
6
7 t.is(testnet.nodes.length, 3, 'has 3 nodes')
8 t.alike(testnet.nodes, [...testnet], 'can iterate nodes')
9})
10
11test('createNode + createServer', async (t) => {
12 t.comment('should not cause request timeouts')
13
14 const testnet = await createTestnet(3, t.teardown)
15
16 const a = testnet.createNode()
17 await a.ready()
18
19 const server = a.createServer()
20 await server.listen()
21
22 t.pass()
23})
node_modules/@jridgewell/resolve-uri/LICENSE +19 -0
……@@ -0,0 +1,19 @@
1Copyright 2019 Justin Ridgewell <jridgewell@google.com>
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
node_modules/@jridgewell/resolve-uri/README.md +40 -0
……@@ -0,0 +1,40 @@
1# @jridgewell/resolve-uri
2
3> Resolve a URI relative to an optional base URI
4
5Resolve any combination of absolute URIs, protocol-realtive URIs, absolute paths, or relative paths.
6
7## Installation
8
9```sh
10npm install @jridgewell/resolve-uri
11```
12
13## Usage
14
15```typescript
16function resolve(input: string, base?: string): string;
17```
18
19```js
20import resolve from '@jridgewell/resolve-uri';
21
22resolve('foo', 'https://example.com'); // => 'https://example.com/foo'
23```
24
25| Input | Base | Resolution | Explanation |
26|-----------------------|-------------------------|--------------------------------|--------------------------------------------------------------|
27| `https://example.com` | _any_ | `https://example.com/` | Input is normalized only |
28| `//example.com` | `https://base.com/` | `https://example.com/` | Input inherits the base's protocol |
29| `//example.com` | _rest_ | `//example.com/` | Input is normalized only |
30| `/example` | `https://base.com/` | `https://base.com/example` | Input inherits the base's origin |
31| `/example` | `//base.com/` | `//base.com/example` | Input inherits the base's host and remains protocol relative |
32| `/example` | _rest_ | `/example` | Input is normalized only |
33| `example` | `https://base.com/dir/` | `https://base.com/dir/example` | Input is joined with the base |
34| `example` | `https://base.com/file` | `https://base.com/example` | Input is joined with the base without its file |
35| `example` | `//base.com/dir/` | `//base.com/dir/example` | Input is joined with the base's last directory |
36| `example` | `//base.com/file` | `//base.com/example` | Input is joined with the base without its file |
37| `example` | `/base/dir/` | `/base/dir/example` | Input is joined with the base's last directory |
38| `example` | `/base/file` | `/base/example` | Input is joined with the base without its file |
39| `example` | `base/dir/` | `base/dir/example` | Input is joined with the base's last directory |
40| `example` | `base/file` | `base/example` | Input is joined with the base without its file |
node_modules/@jridgewell/resolve-uri/dist/resolve-uri.mjs +232 -0
……@@ -0,0 +1,232 @@
1// Matches the scheme of a URL, eg "http://"
2const schemeRegex = /^[\w+.-]+:\/\//;
3/**
4 * Matches the parts of a URL:
5 * 1. Scheme, including ":", guaranteed.
6 * 2. User/password, including "@", optional.
7 * 3. Host, guaranteed.
8 * 4. Port, including ":", optional.
9 * 5. Path, including "/", optional.
10 * 6. Query, including "?", optional.
11 * 7. Hash, including "#", optional.
12 */
13const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
14/**
15 * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
16 * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
17 *
18 * 1. Host, optional.
19 * 2. Path, which may include "/", guaranteed.
20 * 3. Query, including "?", optional.
21 * 4. Hash, including "#", optional.
22 */
23const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
24function isAbsoluteUrl(input) {
25 return schemeRegex.test(input);
26}
27function isSchemeRelativeUrl(input) {
28 return input.startsWith('//');
29}
30function isAbsolutePath(input) {
31 return input.startsWith('/');
32}
33function isFileUrl(input) {
34 return input.startsWith('file:');
35}
36function isRelative(input) {
37 return /^[.?#]/.test(input);
38}
39function parseAbsoluteUrl(input) {
40 const match = urlRegex.exec(input);
41 return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || '');
42}
43function parseFileUrl(input) {
44 const match = fileRegex.exec(input);
45 const path = match[2];
46 return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || '');
47}
48function makeUrl(scheme, user, host, port, path, query, hash) {
49 return {
50 scheme,
51 user,
52 host,
53 port,
54 path,
55 query,
56 hash,
57 type: 7 /* Absolute */,
58 };
59}
60function parseUrl(input) {
61 if (isSchemeRelativeUrl(input)) {
62 const url = parseAbsoluteUrl('http:' + input);
63 url.scheme = '';
64 url.type = 6 /* SchemeRelative */;
65 return url;
66 }
67 if (isAbsolutePath(input)) {
68 const url = parseAbsoluteUrl('http://foo.com' + input);
69 url.scheme = '';
70 url.host = '';
71 url.type = 5 /* AbsolutePath */;
72 return url;
73 }
74 if (isFileUrl(input))
75 return parseFileUrl(input);
76 if (isAbsoluteUrl(input))
77 return parseAbsoluteUrl(input);
78 const url = parseAbsoluteUrl('http://foo.com/' + input);
79 url.scheme = '';
80 url.host = '';
81 url.type = input
82 ? input.startsWith('?')
83 ? 3 /* Query */
84 : input.startsWith('#')
85 ? 2 /* Hash */
86 : 4 /* RelativePath */
87 : 1 /* Empty */;
88 return url;
89}
90function stripPathFilename(path) {
91 // If a path ends with a parent directory "..", then it's a relative path with excess parent
92 // paths. It's not a file, so we can't strip it.
93 if (path.endsWith('/..'))
94 return path;
95 const index = path.lastIndexOf('/');
96 return path.slice(0, index + 1);
97}
98function mergePaths(url, base) {
99 normalizePath(base, base.type);
100 // If the path is just a "/", then it was an empty path to begin with (remember, we're a relative
101 // path).
102 if (url.path === '/') {
103 url.path = base.path;
104 }
105 else {
106 // Resolution happens relative to the base path's directory, not the file.
107 url.path = stripPathFilename(base.path) + url.path;
108 }
109}
110/**
111 * The path can have empty directories "//", unneeded parents "foo/..", or current directory
112 * "foo/.". We need to normalize to a standard representation.
113 */
114function normalizePath(url, type) {
115 const rel = type <= 4 /* RelativePath */;
116 const pieces = url.path.split('/');
117 // We need to preserve the first piece always, so that we output a leading slash. The item at
118 // pieces[0] is an empty string.
119 let pointer = 1;
120 // Positive is the number of real directories we've output, used for popping a parent directory.
121 // Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
122 let positive = 0;
123 // We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
124 // generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
125 // real directory, we won't need to append, unless the other conditions happen again.
126 let addTrailingSlash = false;
127 for (let i = 1; i < pieces.length; i++) {
128 const piece = pieces[i];
129 // An empty directory, could be a trailing slash, or just a double "//" in the path.
130 if (!piece) {
131 addTrailingSlash = true;
132 continue;
133 }
134 // If we encounter a real directory, then we don't need to append anymore.
135 addTrailingSlash = false;
136 // A current directory, which we can always drop.
137 if (piece === '.')
138 continue;
139 // A parent directory, we need to see if there are any real directories we can pop. Else, we
140 // have an excess of parents, and we'll need to keep the "..".
141 if (piece === '..') {
142 if (positive) {
143 addTrailingSlash = true;
144 positive--;
145 pointer--;
146 }
147 else if (rel) {
148 // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
149 // URL, protocol relative URL, or an absolute path, we don't need to keep excess.
150 pieces[pointer++] = piece;
151 }
152 continue;
153 }
154 // We've encountered a real directory. Move it to the next insertion pointer, which accounts for
155 // any popped or dropped directories.
156 pieces[pointer++] = piece;
157 positive++;
158 }
159 let path = '';
160 for (let i = 1; i < pointer; i++) {
161 path += '/' + pieces[i];
162 }
163 if (!path || (addTrailingSlash && !path.endsWith('/..'))) {
164 path += '/';
165 }
166 url.path = path;
167}
168/**
169 * Attempts to resolve `input` URL/path relative to `base`.
170 */
171function resolve(input, base) {
172 if (!input && !base)
173 return '';
174 const url = parseUrl(input);
175 let inputType = url.type;
176 if (base && inputType !== 7 /* Absolute */) {
177 const baseUrl = parseUrl(base);
178 const baseType = baseUrl.type;
179 switch (inputType) {
180 case 1 /* Empty */:
181 url.hash = baseUrl.hash;
182 // fall through
183 case 2 /* Hash */:
184 url.query = baseUrl.query;
185 // fall through
186 case 3 /* Query */:
187 case 4 /* RelativePath */:
188 mergePaths(url, baseUrl);
189 // fall through
190 case 5 /* AbsolutePath */:
191 // The host, user, and port are joined, you can't copy one without the others.
192 url.user = baseUrl.user;
193 url.host = baseUrl.host;
194 url.port = baseUrl.port;
195 // fall through
196 case 6 /* SchemeRelative */:
197 // The input doesn't have a schema at least, so we need to copy at least that over.
198 url.scheme = baseUrl.scheme;
199 }
200 if (baseType > inputType)
201 inputType = baseType;
202 }
203 normalizePath(url, inputType);
204 const queryHash = url.query + url.hash;
205 switch (inputType) {
206 // This is impossible, because of the empty checks at the start of the function.
207 // case UrlType.Empty:
208 case 2 /* Hash */:
209 case 3 /* Query */:
210 return queryHash;
211 case 4 /* RelativePath */: {
212 // The first char is always a "/", and we need it to be relative.
213 const path = url.path.slice(1);
214 if (!path)
215 return queryHash || '.';
216 if (isRelative(base || input) && !isRelative(path)) {
217 // If base started with a leading ".", or there is no base and input started with a ".",
218 // then we need to ensure that the relative path starts with a ".". We don't know if
219 // relative starts with a "..", though, so check before prepending.
220 return './' + path + queryHash;
221 }
222 return path + queryHash;
223 }
224 case 5 /* AbsolutePath */:
225 return url.path + queryHash;
226 default:
227 return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;
228 }
229}
230
231export { resolve as default };
232//# sourceMappingURL=resolve-uri.mjs.map
node_modules/@jridgewell/resolve-uri/dist/resolve-uri.mjs.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"resolve-uri.mjs","sources":["../src/resolve-uri.ts"],"sourcesContent":["// Matches the scheme of a URL, eg \"http://\"\nconst schemeRegex = /^[\\w+.-]+:\\/\\//;\n\n/**\n * Matches the parts of a URL:\n * 1. Scheme, including \":\", guaranteed.\n * 2. User/password, including \"@\", optional.\n * 3. Host, guaranteed.\n * 4. Port, including \":\", optional.\n * 5. Path, including \"/\", optional.\n * 6. Query, including \"?\", optional.\n * 7. Hash, including \"#\", optional.\n */\nconst urlRegex = /^([\\w+.-]+:)\\/\\/([^@/#?]*@)?([^:/#?]*)(:\\d+)?(\\/[^#?]*)?(\\?[^#]*)?(#.*)?/;\n\n/**\n * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start\n * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).\n *\n * 1. Host, optional.\n * 2. Path, which may include \"/\", guaranteed.\n * 3. Query, including \"?\", optional.\n * 4. Hash, including \"#\", optional.\n */\nconst fileRegex = /^file:(?:\\/\\/((?![a-z]:)[^/#?]*)?)?(\\/?[^#?]*)(\\?[^#]*)?(#.*)?/i;\n\ntype Url = {\n scheme: string;\n user: string;\n host: string;\n port: string;\n path: string;\n query: string;\n hash: string;\n type: UrlType;\n};\n\nconst enum UrlType {\n Empty = 1,\n Hash = 2,\n Query = 3,\n RelativePath = 4,\n AbsolutePath = 5,\n SchemeRelative = 6,\n Absolute = 7,\n}\n\nfunction isAbsoluteUrl(input: string): boolean {\n return schemeRegex.test(input);\n}\n\nfunction isSchemeRelativeUrl(input: string): boolean {\n return input.startsWith('//');\n}\n\nfunction isAbsolutePath(input: string): boolean {\n return input.startsWith('/');\n}\n\nfunction isFileUrl(input: string): boolean {\n return input.startsWith('file:');\n}\n\nfunction isRelative(input: string): boolean {\n return /^[.?#]/.test(input);\n}\n\nfunction parseAbsoluteUrl(input: string): Url {\n const match = urlRegex.exec(input)!;\n return makeUrl(\n match[1],\n match[2] || '',\n match[3],\n match[4] || '',\n match[5] || '/',\n match[6] || '',\n match[7] || '',\n );\n}\n\nfunction parseFileUrl(input: string): Url {\n const match = fileRegex.exec(input)!;\n const path = match[2];\n return makeUrl(\n 'file:',\n '',\n match[1] || '',\n '',\n isAbsolutePath(path) ? path : '/' + path,\n match[3] || '',\n match[4] || '',\n );\n}\n\nfunction makeUrl(\n scheme: string,\n user: string,\n host: string,\n port: string,\n path: string,\n query: string,\n hash: string,\n): Url {\n return {\n scheme,\n user,\n host,\n port,\n path,\n query,\n hash,\n type: UrlType.Absolute,\n };\n}\n\nfunction parseUrl(input: string): Url {\n if (isSchemeRelativeUrl(input)) {\n const url = parseAbsoluteUrl('http:' + input);\n url.scheme = '';\n url.type = UrlType.SchemeRelative;\n return url;\n }\n\n if (isAbsolutePath(input)) {\n const url = parseAbsoluteUrl('http://foo.com' + input);\n url.scheme = '';\n url.host = '';\n url.type = UrlType.AbsolutePath;\n return url;\n }\n\n if (isFileUrl(input)) return parseFileUrl(input);\n\n if (isAbsoluteUrl(input)) return parseAbsoluteUrl(input);\n\n const url = parseAbsoluteUrl('http://foo.com/' + input);\n url.scheme = '';\n url.host = '';\n url.type = input\n ? input.startsWith('?')\n ? UrlType.Query\n : input.startsWith('#')\n ? UrlType.Hash\n : UrlType.RelativePath\n : UrlType.Empty;\n return url;\n}\n\nfunction stripPathFilename(path: string): string {\n // If a path ends with a parent directory \"..\", then it's a relative path with excess parent\n // paths. It's not a file, so we can't strip it.\n if (path.endsWith('/..')) return path;\n const index = path.lastIndexOf('/');\n return path.slice(0, index + 1);\n}\n\nfunction mergePaths(url: Url, base: Url) {\n normalizePath(base, base.type);\n\n // If the path is just a \"/\", then it was an empty path to begin with (remember, we're a relative\n // path).\n if (url.path === '/') {\n url.path = base.path;\n } else {\n // Resolution happens relative to the base path's directory, not the file.\n url.path = stripPathFilename(base.path) + url.path;\n }\n}\n\n/**\n * The path can have empty directories \"//\", unneeded parents \"foo/..\", or current directory\n * \"foo/.\". We need to normalize to a standard representation.\n */\nfunction normalizePath(url: Url, type: UrlType) {\n const rel = type <= UrlType.RelativePath;\n const pieces = url.path.split('/');\n\n // We need to preserve the first piece always, so that we output a leading slash. The item at\n // pieces[0] is an empty string.\n let pointer = 1;\n\n // Positive is the number of real directories we've output, used for popping a parent directory.\n // Eg, \"foo/bar/..\" will have a positive 2, and we can decrement to be left with just \"foo\".\n let positive = 0;\n\n // We need to keep a trailing slash if we encounter an empty directory (eg, splitting \"foo/\" will\n // generate `[\"foo\", \"\"]` pieces). And, if we pop a parent directory. But once we encounter a\n // real directory, we won't need to append, unless the other conditions happen again.\n let addTrailingSlash = false;\n\n for (let i = 1; i < pieces.length; i++) {\n const piece = pieces[i];\n\n // An empty directory, could be a trailing slash, or just a double \"//\" in the path.\n if (!piece) {\n addTrailingSlash = true;\n continue;\n }\n\n // If we encounter a real directory, then we don't need to append anymore.\n addTrailingSlash = false;\n\n // A current directory, which we can always drop.\n if (piece === '.') continue;\n\n // A parent directory, we need to see if there are any real directories we can pop. Else, we\n // have an excess of parents, and we'll need to keep the \"..\".\n if (piece === '..') {\n if (positive) {\n addTrailingSlash = true;\n positive--;\n pointer--;\n } else if (rel) {\n // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute\n // URL, protocol relative URL, or an absolute path, we don't need to keep excess.\n pieces[pointer++] = piece;\n }\n continue;\n }\n\n // We've encountered a real directory. Move it to the next insertion pointer, which accounts for\n // any popped or dropped directories.\n pieces[pointer++] = piece;\n positive++;\n }\n\n let path = '';\n for (let i = 1; i < pointer; i++) {\n path += '/' + pieces[i];\n }\n if (!path || (addTrailingSlash && !path.endsWith('/..'))) {\n path += '/';\n }\n url.path = path;\n}\n\n/**\n * Attempts to resolve `input` URL/path relative to `base`.\n */\nexport default function resolve(input: string, base: string | undefined): string {\n if (!input && !base) return '';\n\n const url = parseUrl(input);\n let inputType = url.type;\n\n if (base && inputType !== UrlType.Absolute) {\n const baseUrl = parseUrl(base);\n const baseType = baseUrl.type;\n\n switch (inputType) {\n case UrlType.Empty:\n url.hash = baseUrl.hash;\n // fall through\n\n case UrlType.Hash:\n url.query = baseUrl.query;\n // fall through\n\n case UrlType.Query:\n case UrlType.RelativePath:\n mergePaths(url, baseUrl);\n // fall through\n\n case UrlType.AbsolutePath:\n // The host, user, and port are joined, you can't copy one without the others.\n url.user = baseUrl.user;\n url.host = baseUrl.host;\n url.port = baseUrl.port;\n // fall through\n\n case UrlType.SchemeRelative:\n // The input doesn't have a schema at least, so we need to copy at least that over.\n url.scheme = baseUrl.scheme;\n }\n if (baseType > inputType) inputType = baseType;\n }\n\n normalizePath(url, inputType);\n\n const queryHash = url.query + url.hash;\n switch (inputType) {\n // This is impossible, because of the empty checks at the start of the function.\n // case UrlType.Empty:\n\n case UrlType.Hash:\n case UrlType.Query:\n return queryHash;\n\n case UrlType.RelativePath: {\n // The first char is always a \"/\", and we need it to be relative.\n const path = url.path.slice(1);\n\n if (!path) return queryHash || '.';\n\n if (isRelative(base || input) && !isRelative(path)) {\n // If base started with a leading \".\", or there is no base and input started with a \".\",\n // then we need to ensure that the relative path starts with a \".\". We don't know if\n // relative starts with a \"..\", though, so check before prepending.\n return './' + path + queryHash;\n }\n\n return path + queryHash;\n }\n\n case UrlType.AbsolutePath:\n return url.path + queryHash;\n\n default:\n return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;\n }\n}\n"],"names":[],"mappings":"AAAA;AACA,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAErC;;;;;;;;;;AAUA,MAAM,QAAQ,GAAG,0EAA0E,CAAC;AAE5F;;;;;;;;;AASA,MAAM,SAAS,GAAG,iEAAiE,CAAC;AAuBpF,SAAS,aAAa,CAAC,KAAa;IAClC,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC;IACpC,OAAO,OAAO,CACZ,KAAK,CAAC,CAAC,CAAC,EACR,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,EACR,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,EACf,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CACf,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,OAAO,OAAO,CACZ,OAAO,EACP,EAAE,EACF,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,EAAE,EACF,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,EACxC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CACf,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CACd,MAAc,EACd,IAAY,EACZ,IAAY,EACZ,IAAY,EACZ,IAAY,EACZ,KAAa,EACb,IAAY;IAEZ,OAAO;QACL,MAAM;QACN,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,KAAK;QACL,IAAI;QACJ,IAAI;KACL,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa;IAC7B,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE;QAC9B,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC;QAC9C,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,0BAA0B;QAClC,OAAO,GAAG,CAAC;KACZ;IAED,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE;QACzB,MAAM,GAAG,GAAG,gBAAgB,CAAC,gBAAgB,GAAG,KAAK,CAAC,CAAC;QACvD,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,IAAI,wBAAwB;QAChC,OAAO,GAAG,CAAC;KACZ;IAED,IAAI,SAAS,CAAC,KAAK,CAAC;QAAE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAEjD,IAAI,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEzD,MAAM,GAAG,GAAG,gBAAgB,CAAC,iBAAiB,GAAG,KAAK,CAAC,CAAC;IACxD,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,GAAG,CAAC,IAAI,GAAG,KAAK;UACZ,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;;cAEnB,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;;;wBAGT;IAClB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;;;IAGrC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,UAAU,CAAC,GAAQ,EAAE,IAAS;IACrC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;;;IAI/B,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE;QACpB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;KACtB;SAAM;;QAEL,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;KACpD;AACH,CAAC;AAED;;;;AAIA,SAAS,aAAa,CAAC,GAAQ,EAAE,IAAa;IAC5C,MAAM,GAAG,GAAG,IAAI,yBAAyB;IACzC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;;;IAInC,IAAI,OAAO,GAAG,CAAC,CAAC;;;IAIhB,IAAI,QAAQ,GAAG,CAAC,CAAC;;;;IAKjB,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;;QAGxB,IAAI,CAAC,KAAK,EAAE;YACV,gBAAgB,GAAG,IAAI,CAAC;YACxB,SAAS;SACV;;QAGD,gBAAgB,GAAG,KAAK,CAAC;;QAGzB,IAAI,KAAK,KAAK,GAAG;YAAE,SAAS;;;QAI5B,IAAI,KAAK,KAAK,IAAI,EAAE;YAClB,IAAI,QAAQ,EAAE;gBACZ,gBAAgB,GAAG,IAAI,CAAC;gBACxB,QAAQ,EAAE,CAAC;gBACX,OAAO,EAAE,CAAC;aACX;iBAAM,IAAI,GAAG,EAAE;;;gBAGd,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;aAC3B;YACD,SAAS;SACV;;;QAID,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;QAC1B,QAAQ,EAAE,CAAC;KACZ;IAED,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE;QAChC,IAAI,IAAI,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;KACzB;IACD,IAAI,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE;QACxD,IAAI,IAAI,GAAG,CAAC;KACb;IACD,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;AAClB,CAAC;AAED;;;SAGwB,OAAO,CAAC,KAAa,EAAE,IAAwB;IACrE,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAE/B,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC;IAEzB,IAAI,IAAI,IAAI,SAAS,uBAAuB;QAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;QAE9B,QAAQ,SAAS;YACf;gBACE,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;;YAG1B;gBACE,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;;YAG5B,mBAAmB;YACnB;gBACE,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;;YAG3B;;gBAEE,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;gBACxB,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;gBACxB,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;;YAG1B;;gBAEE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;SAC/B;QACD,IAAI,QAAQ,GAAG,SAAS;YAAE,SAAS,GAAG,QAAQ,CAAC;KAChD;IAED,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAE9B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;IACvC,QAAQ,SAAS;;;QAIf,kBAAkB;QAClB;YACE,OAAO,SAAS,CAAC;QAEnB,2BAA2B;;YAEzB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAE/B,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,IAAI,GAAG,CAAC;YAEnC,IAAI,UAAU,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;;;;gBAIlD,OAAO,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;aAChC;YAED,OAAO,IAAI,GAAG,SAAS,CAAC;SACzB;QAED;YACE,OAAO,GAAG,CAAC,IAAI,GAAG,SAAS,CAAC;QAE9B;YACE,OAAO,GAAG,CAAC,MAAM,GAAG,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,SAAS,CAAC;KACpF;AACH;;;;"}
node_modules/@jridgewell/resolve-uri/dist/resolve-uri.umd.js +240 -0
……@@ -0,0 +1,240 @@
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 typeof define === 'function' && define.amd ? define(factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.resolveURI = factory());
5})(this, (function () { 'use strict';
6
7 // Matches the scheme of a URL, eg "http://"
8 const schemeRegex = /^[\w+.-]+:\/\//;
9 /**
10 * Matches the parts of a URL:
11 * 1. Scheme, including ":", guaranteed.
12 * 2. User/password, including "@", optional.
13 * 3. Host, guaranteed.
14 * 4. Port, including ":", optional.
15 * 5. Path, including "/", optional.
16 * 6. Query, including "?", optional.
17 * 7. Hash, including "#", optional.
18 */
19 const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
20 /**
21 * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
22 * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
23 *
24 * 1. Host, optional.
25 * 2. Path, which may include "/", guaranteed.
26 * 3. Query, including "?", optional.
27 * 4. Hash, including "#", optional.
28 */
29 const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
30 function isAbsoluteUrl(input) {
31 return schemeRegex.test(input);
32 }
33 function isSchemeRelativeUrl(input) {
34 return input.startsWith('//');
35 }
36 function isAbsolutePath(input) {
37 return input.startsWith('/');
38 }
39 function isFileUrl(input) {
40 return input.startsWith('file:');
41 }
42 function isRelative(input) {
43 return /^[.?#]/.test(input);
44 }
45 function parseAbsoluteUrl(input) {
46 const match = urlRegex.exec(input);
47 return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || '');
48 }
49 function parseFileUrl(input) {
50 const match = fileRegex.exec(input);
51 const path = match[2];
52 return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || '');
53 }
54 function makeUrl(scheme, user, host, port, path, query, hash) {
55 return {
56 scheme,
57 user,
58 host,
59 port,
60 path,
61 query,
62 hash,
63 type: 7 /* Absolute */,
64 };
65 }
66 function parseUrl(input) {
67 if (isSchemeRelativeUrl(input)) {
68 const url = parseAbsoluteUrl('http:' + input);
69 url.scheme = '';
70 url.type = 6 /* SchemeRelative */;
71 return url;
72 }
73 if (isAbsolutePath(input)) {
74 const url = parseAbsoluteUrl('http://foo.com' + input);
75 url.scheme = '';
76 url.host = '';
77 url.type = 5 /* AbsolutePath */;
78 return url;
79 }
80 if (isFileUrl(input))
81 return parseFileUrl(input);
82 if (isAbsoluteUrl(input))
83 return parseAbsoluteUrl(input);
84 const url = parseAbsoluteUrl('http://foo.com/' + input);
85 url.scheme = '';
86 url.host = '';
87 url.type = input
88 ? input.startsWith('?')
89 ? 3 /* Query */
90 : input.startsWith('#')
91 ? 2 /* Hash */
92 : 4 /* RelativePath */
93 : 1 /* Empty */;
94 return url;
95 }
96 function stripPathFilename(path) {
97 // If a path ends with a parent directory "..", then it's a relative path with excess parent
98 // paths. It's not a file, so we can't strip it.
99 if (path.endsWith('/..'))
100 return path;
101 const index = path.lastIndexOf('/');
102 return path.slice(0, index + 1);
103 }
104 function mergePaths(url, base) {
105 normalizePath(base, base.type);
106 // If the path is just a "/", then it was an empty path to begin with (remember, we're a relative
107 // path).
108 if (url.path === '/') {
109 url.path = base.path;
110 }
111 else {
112 // Resolution happens relative to the base path's directory, not the file.
113 url.path = stripPathFilename(base.path) + url.path;
114 }
115 }
116 /**
117 * The path can have empty directories "//", unneeded parents "foo/..", or current directory
118 * "foo/.". We need to normalize to a standard representation.
119 */
120 function normalizePath(url, type) {
121 const rel = type <= 4 /* RelativePath */;
122 const pieces = url.path.split('/');
123 // We need to preserve the first piece always, so that we output a leading slash. The item at
124 // pieces[0] is an empty string.
125 let pointer = 1;
126 // Positive is the number of real directories we've output, used for popping a parent directory.
127 // Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
128 let positive = 0;
129 // We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
130 // generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
131 // real directory, we won't need to append, unless the other conditions happen again.
132 let addTrailingSlash = false;
133 for (let i = 1; i < pieces.length; i++) {
134 const piece = pieces[i];
135 // An empty directory, could be a trailing slash, or just a double "//" in the path.
136 if (!piece) {
137 addTrailingSlash = true;
138 continue;
139 }
140 // If we encounter a real directory, then we don't need to append anymore.
141 addTrailingSlash = false;
142 // A current directory, which we can always drop.
143 if (piece === '.')
144 continue;
145 // A parent directory, we need to see if there are any real directories we can pop. Else, we
146 // have an excess of parents, and we'll need to keep the "..".
147 if (piece === '..') {
148 if (positive) {
149 addTrailingSlash = true;
150 positive--;
151 pointer--;
152 }
153 else if (rel) {
154 // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
155 // URL, protocol relative URL, or an absolute path, we don't need to keep excess.
156 pieces[pointer++] = piece;
157 }
158 continue;
159 }
160 // We've encountered a real directory. Move it to the next insertion pointer, which accounts for
161 // any popped or dropped directories.
162 pieces[pointer++] = piece;
163 positive++;
164 }
165 let path = '';
166 for (let i = 1; i < pointer; i++) {
167 path += '/' + pieces[i];
168 }
169 if (!path || (addTrailingSlash && !path.endsWith('/..'))) {
170 path += '/';
171 }
172 url.path = path;
173 }
174 /**
175 * Attempts to resolve `input` URL/path relative to `base`.
176 */
177 function resolve(input, base) {
178 if (!input && !base)
179 return '';
180 const url = parseUrl(input);
181 let inputType = url.type;
182 if (base && inputType !== 7 /* Absolute */) {
183 const baseUrl = parseUrl(base);
184 const baseType = baseUrl.type;
185 switch (inputType) {
186 case 1 /* Empty */:
187 url.hash = baseUrl.hash;
188 // fall through
189 case 2 /* Hash */:
190 url.query = baseUrl.query;
191 // fall through
192 case 3 /* Query */:
193 case 4 /* RelativePath */:
194 mergePaths(url, baseUrl);
195 // fall through
196 case 5 /* AbsolutePath */:
197 // The host, user, and port are joined, you can't copy one without the others.
198 url.user = baseUrl.user;
199 url.host = baseUrl.host;
200 url.port = baseUrl.port;
201 // fall through
202 case 6 /* SchemeRelative */:
203 // The input doesn't have a schema at least, so we need to copy at least that over.
204 url.scheme = baseUrl.scheme;
205 }
206 if (baseType > inputType)
207 inputType = baseType;
208 }
209 normalizePath(url, inputType);
210 const queryHash = url.query + url.hash;
211 switch (inputType) {
212 // This is impossible, because of the empty checks at the start of the function.
213 // case UrlType.Empty:
214 case 2 /* Hash */:
215 case 3 /* Query */:
216 return queryHash;
217 case 4 /* RelativePath */: {
218 // The first char is always a "/", and we need it to be relative.
219 const path = url.path.slice(1);
220 if (!path)
221 return queryHash || '.';
222 if (isRelative(base || input) && !isRelative(path)) {
223 // If base started with a leading ".", or there is no base and input started with a ".",
224 // then we need to ensure that the relative path starts with a ".". We don't know if
225 // relative starts with a "..", though, so check before prepending.
226 return './' + path + queryHash;
227 }
228 return path + queryHash;
229 }
230 case 5 /* AbsolutePath */:
231 return url.path + queryHash;
232 default:
233 return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;
234 }
235 }
236
237 return resolve;
238
239}));
240//# sourceMappingURL=resolve-uri.umd.js.map
node_modules/@jridgewell/resolve-uri/dist/resolve-uri.umd.js.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"resolve-uri.umd.js","sources":["../src/resolve-uri.ts"],"sourcesContent":["// Matches the scheme of a URL, eg \"http://\"\nconst schemeRegex = /^[\\w+.-]+:\\/\\//;\n\n/**\n * Matches the parts of a URL:\n * 1. Scheme, including \":\", guaranteed.\n * 2. User/password, including \"@\", optional.\n * 3. Host, guaranteed.\n * 4. Port, including \":\", optional.\n * 5. Path, including \"/\", optional.\n * 6. Query, including \"?\", optional.\n * 7. Hash, including \"#\", optional.\n */\nconst urlRegex = /^([\\w+.-]+:)\\/\\/([^@/#?]*@)?([^:/#?]*)(:\\d+)?(\\/[^#?]*)?(\\?[^#]*)?(#.*)?/;\n\n/**\n * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start\n * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).\n *\n * 1. Host, optional.\n * 2. Path, which may include \"/\", guaranteed.\n * 3. Query, including \"?\", optional.\n * 4. Hash, including \"#\", optional.\n */\nconst fileRegex = /^file:(?:\\/\\/((?![a-z]:)[^/#?]*)?)?(\\/?[^#?]*)(\\?[^#]*)?(#.*)?/i;\n\ntype Url = {\n scheme: string;\n user: string;\n host: string;\n port: string;\n path: string;\n query: string;\n hash: string;\n type: UrlType;\n};\n\nconst enum UrlType {\n Empty = 1,\n Hash = 2,\n Query = 3,\n RelativePath = 4,\n AbsolutePath = 5,\n SchemeRelative = 6,\n Absolute = 7,\n}\n\nfunction isAbsoluteUrl(input: string): boolean {\n return schemeRegex.test(input);\n}\n\nfunction isSchemeRelativeUrl(input: string): boolean {\n return input.startsWith('//');\n}\n\nfunction isAbsolutePath(input: string): boolean {\n return input.startsWith('/');\n}\n\nfunction isFileUrl(input: string): boolean {\n return input.startsWith('file:');\n}\n\nfunction isRelative(input: string): boolean {\n return /^[.?#]/.test(input);\n}\n\nfunction parseAbsoluteUrl(input: string): Url {\n const match = urlRegex.exec(input)!;\n return makeUrl(\n match[1],\n match[2] || '',\n match[3],\n match[4] || '',\n match[5] || '/',\n match[6] || '',\n match[7] || '',\n );\n}\n\nfunction parseFileUrl(input: string): Url {\n const match = fileRegex.exec(input)!;\n const path = match[2];\n return makeUrl(\n 'file:',\n '',\n match[1] || '',\n '',\n isAbsolutePath(path) ? path : '/' + path,\n match[3] || '',\n match[4] || '',\n );\n}\n\nfunction makeUrl(\n scheme: string,\n user: string,\n host: string,\n port: string,\n path: string,\n query: string,\n hash: string,\n): Url {\n return {\n scheme,\n user,\n host,\n port,\n path,\n query,\n hash,\n type: UrlType.Absolute,\n };\n}\n\nfunction parseUrl(input: string): Url {\n if (isSchemeRelativeUrl(input)) {\n const url = parseAbsoluteUrl('http:' + input);\n url.scheme = '';\n url.type = UrlType.SchemeRelative;\n return url;\n }\n\n if (isAbsolutePath(input)) {\n const url = parseAbsoluteUrl('http://foo.com' + input);\n url.scheme = '';\n url.host = '';\n url.type = UrlType.AbsolutePath;\n return url;\n }\n\n if (isFileUrl(input)) return parseFileUrl(input);\n\n if (isAbsoluteUrl(input)) return parseAbsoluteUrl(input);\n\n const url = parseAbsoluteUrl('http://foo.com/' + input);\n url.scheme = '';\n url.host = '';\n url.type = input\n ? input.startsWith('?')\n ? UrlType.Query\n : input.startsWith('#')\n ? UrlType.Hash\n : UrlType.RelativePath\n : UrlType.Empty;\n return url;\n}\n\nfunction stripPathFilename(path: string): string {\n // If a path ends with a parent directory \"..\", then it's a relative path with excess parent\n // paths. It's not a file, so we can't strip it.\n if (path.endsWith('/..')) return path;\n const index = path.lastIndexOf('/');\n return path.slice(0, index + 1);\n}\n\nfunction mergePaths(url: Url, base: Url) {\n normalizePath(base, base.type);\n\n // If the path is just a \"/\", then it was an empty path to begin with (remember, we're a relative\n // path).\n if (url.path === '/') {\n url.path = base.path;\n } else {\n // Resolution happens relative to the base path's directory, not the file.\n url.path = stripPathFilename(base.path) + url.path;\n }\n}\n\n/**\n * The path can have empty directories \"//\", unneeded parents \"foo/..\", or current directory\n * \"foo/.\". We need to normalize to a standard representation.\n */\nfunction normalizePath(url: Url, type: UrlType) {\n const rel = type <= UrlType.RelativePath;\n const pieces = url.path.split('/');\n\n // We need to preserve the first piece always, so that we output a leading slash. The item at\n // pieces[0] is an empty string.\n let pointer = 1;\n\n // Positive is the number of real directories we've output, used for popping a parent directory.\n // Eg, \"foo/bar/..\" will have a positive 2, and we can decrement to be left with just \"foo\".\n let positive = 0;\n\n // We need to keep a trailing slash if we encounter an empty directory (eg, splitting \"foo/\" will\n // generate `[\"foo\", \"\"]` pieces). And, if we pop a parent directory. But once we encounter a\n // real directory, we won't need to append, unless the other conditions happen again.\n let addTrailingSlash = false;\n\n for (let i = 1; i < pieces.length; i++) {\n const piece = pieces[i];\n\n // An empty directory, could be a trailing slash, or just a double \"//\" in the path.\n if (!piece) {\n addTrailingSlash = true;\n continue;\n }\n\n // If we encounter a real directory, then we don't need to append anymore.\n addTrailingSlash = false;\n\n // A current directory, which we can always drop.\n if (piece === '.') continue;\n\n // A parent directory, we need to see if there are any real directories we can pop. Else, we\n // have an excess of parents, and we'll need to keep the \"..\".\n if (piece === '..') {\n if (positive) {\n addTrailingSlash = true;\n positive--;\n pointer--;\n } else if (rel) {\n // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute\n // URL, protocol relative URL, or an absolute path, we don't need to keep excess.\n pieces[pointer++] = piece;\n }\n continue;\n }\n\n // We've encountered a real directory. Move it to the next insertion pointer, which accounts for\n // any popped or dropped directories.\n pieces[pointer++] = piece;\n positive++;\n }\n\n let path = '';\n for (let i = 1; i < pointer; i++) {\n path += '/' + pieces[i];\n }\n if (!path || (addTrailingSlash && !path.endsWith('/..'))) {\n path += '/';\n }\n url.path = path;\n}\n\n/**\n * Attempts to resolve `input` URL/path relative to `base`.\n */\nexport default function resolve(input: string, base: string | undefined): string {\n if (!input && !base) return '';\n\n const url = parseUrl(input);\n let inputType = url.type;\n\n if (base && inputType !== UrlType.Absolute) {\n const baseUrl = parseUrl(base);\n const baseType = baseUrl.type;\n\n switch (inputType) {\n case UrlType.Empty:\n url.hash = baseUrl.hash;\n // fall through\n\n case UrlType.Hash:\n url.query = baseUrl.query;\n // fall through\n\n case UrlType.Query:\n case UrlType.RelativePath:\n mergePaths(url, baseUrl);\n // fall through\n\n case UrlType.AbsolutePath:\n // The host, user, and port are joined, you can't copy one without the others.\n url.user = baseUrl.user;\n url.host = baseUrl.host;\n url.port = baseUrl.port;\n // fall through\n\n case UrlType.SchemeRelative:\n // The input doesn't have a schema at least, so we need to copy at least that over.\n url.scheme = baseUrl.scheme;\n }\n if (baseType > inputType) inputType = baseType;\n }\n\n normalizePath(url, inputType);\n\n const queryHash = url.query + url.hash;\n switch (inputType) {\n // This is impossible, because of the empty checks at the start of the function.\n // case UrlType.Empty:\n\n case UrlType.Hash:\n case UrlType.Query:\n return queryHash;\n\n case UrlType.RelativePath: {\n // The first char is always a \"/\", and we need it to be relative.\n const path = url.path.slice(1);\n\n if (!path) return queryHash || '.';\n\n if (isRelative(base || input) && !isRelative(path)) {\n // If base started with a leading \".\", or there is no base and input started with a \".\",\n // then we need to ensure that the relative path starts with a \".\". We don't know if\n // relative starts with a \"..\", though, so check before prepending.\n return './' + path + queryHash;\n }\n\n return path + queryHash;\n }\n\n case UrlType.AbsolutePath:\n return url.path + queryHash;\n\n default:\n return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;\n }\n}\n"],"names":[],"mappings":";;;;;;IAAA;IACA,MAAM,WAAW,GAAG,gBAAgB,CAAC;IAErC;;;;;;;;;;IAUA,MAAM,QAAQ,GAAG,0EAA0E,CAAC;IAE5F;;;;;;;;;IASA,MAAM,SAAS,GAAG,iEAAiE,CAAC;IAuBpF,SAAS,aAAa,CAAC,KAAa;QAClC,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,SAAS,mBAAmB,CAAC,KAAa;QACxC,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,SAAS,cAAc,CAAC,KAAa;QACnC,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,SAAS,SAAS,CAAC,KAAa;QAC9B,OAAO,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,SAAS,UAAU,CAAC,KAAa;QAC/B,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,SAAS,gBAAgB,CAAC,KAAa;QACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC;QACpC,OAAO,OAAO,CACZ,KAAK,CAAC,CAAC,CAAC,EACR,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,EACR,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,EACf,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CACf,CAAC;IACJ,CAAC;IAED,SAAS,YAAY,CAAC,KAAa;QACjC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,OAAO,OAAO,CACZ,OAAO,EACP,EAAE,EACF,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,EAAE,EACF,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,EACxC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EACd,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CACf,CAAC;IACJ,CAAC;IAED,SAAS,OAAO,CACd,MAAc,EACd,IAAY,EACZ,IAAY,EACZ,IAAY,EACZ,IAAY,EACZ,KAAa,EACb,IAAY;QAEZ,OAAO;YACL,MAAM;YACN,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,KAAK;YACL,IAAI;YACJ,IAAI;SACL,CAAC;IACJ,CAAC;IAED,SAAS,QAAQ,CAAC,KAAa;QAC7B,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE;YAC9B,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC;YAC9C,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,0BAA0B;YAClC,OAAO,GAAG,CAAC;SACZ;QAED,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE;YACzB,MAAM,GAAG,GAAG,gBAAgB,CAAC,gBAAgB,GAAG,KAAK,CAAC,CAAC;YACvD,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,IAAI,wBAAwB;YAChC,OAAO,GAAG,CAAC;SACZ;QAED,IAAI,SAAS,CAAC,KAAK,CAAC;YAAE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;QAEjD,IAAI,aAAa,CAAC,KAAK,CAAC;YAAE,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAEzD,MAAM,GAAG,GAAG,gBAAgB,CAAC,iBAAiB,GAAG,KAAK,CAAC,CAAC;QACxD,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,IAAI,GAAG,KAAK;cACZ,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;;kBAEnB,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;;;4BAGT;QAClB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,SAAS,iBAAiB,CAAC,IAAY;;;QAGrC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,SAAS,UAAU,CAAC,GAAQ,EAAE,IAAS;QACrC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;;;QAI/B,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE;YACpB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;SACtB;aAAM;;YAEL,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;SACpD;IACH,CAAC;IAED;;;;IAIA,SAAS,aAAa,CAAC,GAAQ,EAAE,IAAa;QAC5C,MAAM,GAAG,GAAG,IAAI,yBAAyB;QACzC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;;;QAInC,IAAI,OAAO,GAAG,CAAC,CAAC;;;QAIhB,IAAI,QAAQ,GAAG,CAAC,CAAC;;;;QAKjB,IAAI,gBAAgB,GAAG,KAAK,CAAC;QAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;;YAGxB,IAAI,CAAC,KAAK,EAAE;gBACV,gBAAgB,GAAG,IAAI,CAAC;gBACxB,SAAS;aACV;;YAGD,gBAAgB,GAAG,KAAK,CAAC;;YAGzB,IAAI,KAAK,KAAK,GAAG;gBAAE,SAAS;;;YAI5B,IAAI,KAAK,KAAK,IAAI,EAAE;gBAClB,IAAI,QAAQ,EAAE;oBACZ,gBAAgB,GAAG,IAAI,CAAC;oBACxB,QAAQ,EAAE,CAAC;oBACX,OAAO,EAAE,CAAC;iBACX;qBAAM,IAAI,GAAG,EAAE;;;oBAGd,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;iBAC3B;gBACD,SAAS;aACV;;;YAID,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;YAC1B,QAAQ,EAAE,CAAC;SACZ;QAED,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE;YAChC,IAAI,IAAI,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;SACzB;QACD,IAAI,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE;YACxD,IAAI,IAAI,GAAG,CAAC;SACb;QACD,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;IAED;;;aAGwB,OAAO,CAAC,KAAa,EAAE,IAAwB;QACrE,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QAE/B,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC;QAEzB,IAAI,IAAI,IAAI,SAAS,uBAAuB;YAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YAE9B,QAAQ,SAAS;gBACf;oBACE,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;;gBAG1B;oBACE,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;;gBAG5B,mBAAmB;gBACnB;oBACE,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;;gBAG3B;;oBAEE,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;oBACxB,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;oBACxB,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;;gBAG1B;;oBAEE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;aAC/B;YACD,IAAI,QAAQ,GAAG,SAAS;gBAAE,SAAS,GAAG,QAAQ,CAAC;SAChD;QAED,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAE9B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;QACvC,QAAQ,SAAS;;;YAIf,kBAAkB;YAClB;gBACE,OAAO,SAAS,CAAC;YAEnB,2BAA2B;;gBAEzB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAE/B,IAAI,CAAC,IAAI;oBAAE,OAAO,SAAS,IAAI,GAAG,CAAC;gBAEnC,IAAI,UAAU,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;;;;oBAIlD,OAAO,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;iBAChC;gBAED,OAAO,IAAI,GAAG,SAAS,CAAC;aACzB;YAED;gBACE,OAAO,GAAG,CAAC,IAAI,GAAG,SAAS,CAAC;YAE9B;gBACE,OAAO,GAAG,CAAC,MAAM,GAAG,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,SAAS,CAAC;SACpF;IACH;;;;;;;;"}
node_modules/@jridgewell/resolve-uri/dist/types/resolve-uri.d.ts +4 -0
……@@ -0,0 +1,4 @@
1/**
2 * Attempts to resolve `input` URL/path relative to `base`.
3 */
4export default function resolve(input: string, base: string | undefined): string;
node_modules/@jridgewell/resolve-uri/package.json +69 -0
……@@ -0,0 +1,69 @@
1{
2 "name": "@jridgewell/resolve-uri",
3 "version": "3.1.2",
4 "description": "Resolve a URI relative to an optional base URI",
5 "keywords": [
6 "resolve",
7 "uri",
8 "url",
9 "path"
10 ],
11 "author": "Justin Ridgewell <justin@ridgewell.name>",
12 "license": "MIT",
13 "repository": "https://github.com/jridgewell/resolve-uri",
14 "main": "dist/resolve-uri.umd.js",
15 "module": "dist/resolve-uri.mjs",
16 "types": "dist/types/resolve-uri.d.ts",
17 "exports": {
18 ".": [
19 {
20 "types": "./dist/types/resolve-uri.d.ts",
21 "browser": "./dist/resolve-uri.umd.js",
22 "require": "./dist/resolve-uri.umd.js",
23 "import": "./dist/resolve-uri.mjs"
24 },
25 "./dist/resolve-uri.umd.js"
26 ],
27 "./package.json": "./package.json"
28 },
29 "files": [
30 "dist"
31 ],
32 "engines": {
33 "node": ">=6.0.0"
34 },
35 "scripts": {
36 "prebuild": "rm -rf dist",
37 "build": "run-s -n build:*",
38 "build:rollup": "rollup -c rollup.config.js",
39 "build:ts": "tsc --project tsconfig.build.json",
40 "lint": "run-s -n lint:*",
41 "lint:prettier": "npm run test:lint:prettier -- --write",
42 "lint:ts": "npm run test:lint:ts -- --fix",
43 "pretest": "run-s build:rollup",
44 "test": "run-s -n test:lint test:only",
45 "test:debug": "mocha --inspect-brk",
46 "test:lint": "run-s -n test:lint:*",
47 "test:lint:prettier": "prettier --check '{src,test}/**/*.ts'",
48 "test:lint:ts": "eslint '{src,test}/**/*.ts'",
49 "test:only": "mocha",
50 "test:coverage": "c8 mocha",
51 "test:watch": "mocha --watch",
52 "prepublishOnly": "npm run preversion",
53 "preversion": "run-s test build"
54 },
55 "devDependencies": {
56 "@jridgewell/resolve-uri-latest": "npm:@jridgewell/resolve-uri@*",
57 "@rollup/plugin-typescript": "8.3.0",
58 "@typescript-eslint/eslint-plugin": "5.10.0",
59 "@typescript-eslint/parser": "5.10.0",
60 "c8": "7.11.0",
61 "eslint": "8.7.0",
62 "eslint-config-prettier": "8.3.0",
63 "mocha": "9.2.0",
64 "npm-run-all": "4.1.5",
65 "prettier": "2.5.1",
66 "rollup": "2.66.0",
67 "typescript": "4.5.5"
68 }
69}
node_modules/@jridgewell/sourcemap-codec/LICENSE +19 -0
……@@ -0,0 +1,19 @@
1Copyright 2024 Justin Ridgewell <justin@ridgewell.name>
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
node_modules/@jridgewell/sourcemap-codec/README.md +264 -0
……@@ -0,0 +1,264 @@
1# @jridgewell/sourcemap-codec
2
3Encode/decode the `mappings` property of a [sourcemap](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit).
4
5
6## Why?
7
8Sourcemaps are difficult to generate and manipulate, because the `mappings` property – the part that actually links the generated code back to the original source – is encoded using an obscure method called [Variable-length quantity](https://en.wikipedia.org/wiki/Variable-length_quantity). On top of that, each segment in the mapping contains offsets rather than absolute indices, which means that you can't look at a segment in isolation – you have to understand the whole sourcemap.
9
10This package makes the process slightly easier.
11
12
13## Installation
14
15```bash
16npm install @jridgewell/sourcemap-codec
17```
18
19
20## Usage
21
22```js
23import { encode, decode } from '@jridgewell/sourcemap-codec';
24
25var decoded = decode( ';EAEEA,EAAE,EAAC,CAAE;ECQY,UACC' );
26
27assert.deepEqual( decoded, [
28 // the first line (of the generated code) has no mappings,
29 // as shown by the starting semi-colon (which separates lines)
30 [],
31
32 // the second line contains four (comma-separated) segments
33 [
34 // segments are encoded as you'd expect:
35 // [ generatedCodeColumn, sourceIndex, sourceCodeLine, sourceCodeColumn, nameIndex ]
36
37 // i.e. the first segment begins at column 2, and maps back to the second column
38 // of the second line (both zero-based) of the 0th source, and uses the 0th
39 // name in the `map.names` array
40 [ 2, 0, 2, 2, 0 ],
41
42 // the remaining segments are 4-length rather than 5-length,
43 // because they don't map a name
44 [ 4, 0, 2, 4 ],
45 [ 6, 0, 2, 5 ],
46 [ 7, 0, 2, 7 ]
47 ],
48
49 // the final line contains two segments
50 [
51 [ 2, 1, 10, 19 ],
52 [ 12, 1, 11, 20 ]
53 ]
54]);
55
56var encoded = encode( decoded );
57assert.equal( encoded, ';EAEEA,EAAE,EAAC,CAAE;ECQY,UACC' );
58```
59
60## Benchmarks
61
62```
63node v20.10.0
64
65amp.js.map - 45120 segments
66
67Decode Memory Usage:
68local code 5815135 bytes
69@jridgewell/sourcemap-codec 1.4.15 5868160 bytes
70sourcemap-codec 5492584 bytes
71source-map-0.6.1 13569984 bytes
72source-map-0.8.0 6390584 bytes
73chrome dev tools 8011136 bytes
74Smallest memory usage is sourcemap-codec
75
76Decode speed:
77decode: local code x 492 ops/sec ±1.22% (90 runs sampled)
78decode: @jridgewell/sourcemap-codec 1.4.15 x 499 ops/sec ±1.16% (89 runs sampled)
79decode: sourcemap-codec x 376 ops/sec ±1.66% (89 runs sampled)
80decode: source-map-0.6.1 x 34.99 ops/sec ±0.94% (48 runs sampled)
81decode: source-map-0.8.0 x 351 ops/sec ±0.07% (95 runs sampled)
82chrome dev tools x 165 ops/sec ±0.91% (86 runs sampled)
83Fastest is decode: @jridgewell/sourcemap-codec 1.4.15
84
85Encode Memory Usage:
86local code 444248 bytes
87@jridgewell/sourcemap-codec 1.4.15 623024 bytes
88sourcemap-codec 8696280 bytes
89source-map-0.6.1 8745176 bytes
90source-map-0.8.0 8736624 bytes
91Smallest memory usage is local code
92
93Encode speed:
94encode: local code x 796 ops/sec ±0.11% (97 runs sampled)
95encode: @jridgewell/sourcemap-codec 1.4.15 x 795 ops/sec ±0.25% (98 runs sampled)
96encode: sourcemap-codec x 231 ops/sec ±0.83% (86 runs sampled)
97encode: source-map-0.6.1 x 166 ops/sec ±0.57% (86 runs sampled)
98encode: source-map-0.8.0 x 203 ops/sec ±0.45% (88 runs sampled)
99Fastest is encode: local code,encode: @jridgewell/sourcemap-codec 1.4.15
100
101
102***
103
104
105babel.min.js.map - 347793 segments
106
107Decode Memory Usage:
108local code 35424960 bytes
109@jridgewell/sourcemap-codec 1.4.15 35424696 bytes
110sourcemap-codec 36033464 bytes
111source-map-0.6.1 62253704 bytes
112source-map-0.8.0 43843920 bytes
113chrome dev tools 45111400 bytes
114Smallest memory usage is @jridgewell/sourcemap-codec 1.4.15
115
116Decode speed:
117decode: local code x 38.18 ops/sec ±5.44% (52 runs sampled)
118decode: @jridgewell/sourcemap-codec 1.4.15 x 38.36 ops/sec ±5.02% (52 runs sampled)
119decode: sourcemap-codec x 34.05 ops/sec ±4.45% (47 runs sampled)
120decode: source-map-0.6.1 x 4.31 ops/sec ±2.76% (15 runs sampled)
121decode: source-map-0.8.0 x 55.60 ops/sec ±0.13% (73 runs sampled)
122chrome dev tools x 16.94 ops/sec ±3.78% (46 runs sampled)
123Fastest is decode: source-map-0.8.0
124
125Encode Memory Usage:
126local code 2606016 bytes
127@jridgewell/sourcemap-codec 1.4.15 2626440 bytes
128sourcemap-codec 21152576 bytes
129source-map-0.6.1 25023928 bytes
130source-map-0.8.0 25256448 bytes
131Smallest memory usage is local code
132
133Encode speed:
134encode: local code x 127 ops/sec ±0.18% (83 runs sampled)
135encode: @jridgewell/sourcemap-codec 1.4.15 x 128 ops/sec ±0.26% (83 runs sampled)
136encode: sourcemap-codec x 29.31 ops/sec ±2.55% (53 runs sampled)
137encode: source-map-0.6.1 x 18.85 ops/sec ±3.19% (36 runs sampled)
138encode: source-map-0.8.0 x 19.34 ops/sec ±1.97% (36 runs sampled)
139Fastest is encode: @jridgewell/sourcemap-codec 1.4.15
140
141
142***
143
144
145preact.js.map - 1992 segments
146
147Decode Memory Usage:
148local code 261696 bytes
149@jridgewell/sourcemap-codec 1.4.15 244296 bytes
150sourcemap-codec 302816 bytes
151source-map-0.6.1 939176 bytes
152source-map-0.8.0 336 bytes
153chrome dev tools 587368 bytes
154Smallest memory usage is source-map-0.8.0
155
156Decode speed:
157decode: local code x 17,782 ops/sec ±0.32% (97 runs sampled)
158decode: @jridgewell/sourcemap-codec 1.4.15 x 17,863 ops/sec ±0.40% (100 runs sampled)
159decode: sourcemap-codec x 12,453 ops/sec ±0.27% (101 runs sampled)
160decode: source-map-0.6.1 x 1,288 ops/sec ±1.05% (96 runs sampled)
161decode: source-map-0.8.0 x 9,289 ops/sec ±0.27% (101 runs sampled)
162chrome dev tools x 4,769 ops/sec ±0.18% (100 runs sampled)
163Fastest is decode: @jridgewell/sourcemap-codec 1.4.15
164
165Encode Memory Usage:
166local code 262944 bytes
167@jridgewell/sourcemap-codec 1.4.15 25544 bytes
168sourcemap-codec 323048 bytes
169source-map-0.6.1 507808 bytes
170source-map-0.8.0 507480 bytes
171Smallest memory usage is @jridgewell/sourcemap-codec 1.4.15
172
173Encode speed:
174encode: local code x 24,207 ops/sec ±0.79% (95 runs sampled)
175encode: @jridgewell/sourcemap-codec 1.4.15 x 24,288 ops/sec ±0.48% (96 runs sampled)
176encode: sourcemap-codec x 6,761 ops/sec ±0.21% (100 runs sampled)
177encode: source-map-0.6.1 x 5,374 ops/sec ±0.17% (99 runs sampled)
178encode: source-map-0.8.0 x 5,633 ops/sec ±0.32% (99 runs sampled)
179Fastest is encode: @jridgewell/sourcemap-codec 1.4.15,encode: local code
180
181
182***
183
184
185react.js.map - 5726 segments
186
187Decode Memory Usage:
188local code 678816 bytes
189@jridgewell/sourcemap-codec 1.4.15 678816 bytes
190sourcemap-codec 816400 bytes
191source-map-0.6.1 2288864 bytes
192source-map-0.8.0 721360 bytes
193chrome dev tools 1012512 bytes
194Smallest memory usage is local code
195
196Decode speed:
197decode: local code x 6,178 ops/sec ±0.19% (98 runs sampled)
198decode: @jridgewell/sourcemap-codec 1.4.15 x 6,261 ops/sec ±0.22% (100 runs sampled)
199decode: sourcemap-codec x 4,472 ops/sec ±0.90% (99 runs sampled)
200decode: source-map-0.6.1 x 449 ops/sec ±0.31% (95 runs sampled)
201decode: source-map-0.8.0 x 3,219 ops/sec ±0.13% (100 runs sampled)
202chrome dev tools x 1,743 ops/sec ±0.20% (99 runs sampled)
203Fastest is decode: @jridgewell/sourcemap-codec 1.4.15
204
205Encode Memory Usage:
206local code 140960 bytes
207@jridgewell/sourcemap-codec 1.4.15 159808 bytes
208sourcemap-codec 969304 bytes
209source-map-0.6.1 930520 bytes
210source-map-0.8.0 930248 bytes
211Smallest memory usage is local code
212
213Encode speed:
214encode: local code x 8,013 ops/sec ±0.19% (100 runs sampled)
215encode: @jridgewell/sourcemap-codec 1.4.15 x 7,989 ops/sec ±0.20% (101 runs sampled)
216encode: sourcemap-codec x 2,472 ops/sec ±0.21% (99 runs sampled)
217encode: source-map-0.6.1 x 2,200 ops/sec ±0.17% (99 runs sampled)
218encode: source-map-0.8.0 x 2,220 ops/sec ±0.37% (99 runs sampled)
219Fastest is encode: local code
220
221
222***
223
224
225vscode.map - 2141001 segments
226
227Decode Memory Usage:
228local code 198955264 bytes
229@jridgewell/sourcemap-codec 1.4.15 199175352 bytes
230sourcemap-codec 199102688 bytes
231source-map-0.6.1 386323432 bytes
232source-map-0.8.0 244116432 bytes
233chrome dev tools 293734280 bytes
234Smallest memory usage is local code
235
236Decode speed:
237decode: local code x 3.90 ops/sec ±22.21% (15 runs sampled)
238decode: @jridgewell/sourcemap-codec 1.4.15 x 3.95 ops/sec ±23.53% (15 runs sampled)
239decode: sourcemap-codec x 3.82 ops/sec ±17.94% (14 runs sampled)
240decode: source-map-0.6.1 x 0.61 ops/sec ±7.81% (6 runs sampled)
241decode: source-map-0.8.0 x 9.54 ops/sec ±0.28% (28 runs sampled)
242chrome dev tools x 2.18 ops/sec ±10.58% (10 runs sampled)
243Fastest is decode: source-map-0.8.0
244
245Encode Memory Usage:
246local code 13509880 bytes
247@jridgewell/sourcemap-codec 1.4.15 13537648 bytes
248sourcemap-codec 32540104 bytes
249source-map-0.6.1 127531040 bytes
250source-map-0.8.0 127535312 bytes
251Smallest memory usage is local code
252
253Encode speed:
254encode: local code x 20.10 ops/sec ±0.19% (38 runs sampled)
255encode: @jridgewell/sourcemap-codec 1.4.15 x 20.26 ops/sec ±0.32% (38 runs sampled)
256encode: sourcemap-codec x 5.44 ops/sec ±1.64% (18 runs sampled)
257encode: source-map-0.6.1 x 2.30 ops/sec ±4.79% (10 runs sampled)
258encode: source-map-0.8.0 x 2.46 ops/sec ±6.53% (10 runs sampled)
259Fastest is encode: @jridgewell/sourcemap-codec 1.4.15
260```
261
262# License
263
264MIT
node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs +423 -0
……@@ -0,0 +1,423 @@
1// src/vlq.ts
2var comma = ",".charCodeAt(0);
3var semicolon = ";".charCodeAt(0);
4var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5var intToChar = new Uint8Array(64);
6var charToInt = new Uint8Array(128);
7for (let i = 0; i < chars.length; i++) {
8 const c = chars.charCodeAt(i);
9 intToChar[i] = c;
10 charToInt[c] = i;
11}
12function decodeInteger(reader, relative) {
13 let value = 0;
14 let shift = 0;
15 let integer = 0;
16 do {
17 const c = reader.next();
18 integer = charToInt[c];
19 value |= (integer & 31) << shift;
20 shift += 5;
21 } while (integer & 32);
22 const shouldNegate = value & 1;
23 value >>>= 1;
24 if (shouldNegate) {
25 value = -2147483648 | -value;
26 }
27 return relative + value;
28}
29function encodeInteger(builder, num, relative) {
30 let delta = num - relative;
31 delta = delta < 0 ? -delta << 1 | 1 : delta << 1;
32 do {
33 let clamped = delta & 31;
34 delta >>>= 5;
35 if (delta > 0) clamped |= 32;
36 builder.write(intToChar[clamped]);
37 } while (delta > 0);
38 return num;
39}
40function hasMoreVlq(reader, max) {
41 if (reader.pos >= max) return false;
42 return reader.peek() !== comma;
43}
44
45// src/strings.ts
46var bufLength = 1024 * 16;
47var td = typeof TextDecoder !== "undefined" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== "undefined" ? {
48 decode(buf) {
49 const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);
50 return out.toString();
51 }
52} : {
53 decode(buf) {
54 let out = "";
55 for (let i = 0; i < buf.length; i++) {
56 out += String.fromCharCode(buf[i]);
57 }
58 return out;
59 }
60};
61var StringWriter = class {
62 constructor() {
63 this.pos = 0;
64 this.out = "";
65 this.buffer = new Uint8Array(bufLength);
66 }
67 write(v) {
68 const { buffer } = this;
69 buffer[this.pos++] = v;
70 if (this.pos === bufLength) {
71 this.out += td.decode(buffer);
72 this.pos = 0;
73 }
74 }
75 flush() {
76 const { buffer, out, pos } = this;
77 return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
78 }
79};
80var StringReader = class {
81 constructor(buffer) {
82 this.pos = 0;
83 this.buffer = buffer;
84 }
85 next() {
86 return this.buffer.charCodeAt(this.pos++);
87 }
88 peek() {
89 return this.buffer.charCodeAt(this.pos);
90 }
91 indexOf(char) {
92 const { buffer, pos } = this;
93 const idx = buffer.indexOf(char, pos);
94 return idx === -1 ? buffer.length : idx;
95 }
96};
97
98// src/scopes.ts
99var EMPTY = [];
100function decodeOriginalScopes(input) {
101 const { length } = input;
102 const reader = new StringReader(input);
103 const scopes = [];
104 const stack = [];
105 let line = 0;
106 for (; reader.pos < length; reader.pos++) {
107 line = decodeInteger(reader, line);
108 const column = decodeInteger(reader, 0);
109 if (!hasMoreVlq(reader, length)) {
110 const last = stack.pop();
111 last[2] = line;
112 last[3] = column;
113 continue;
114 }
115 const kind = decodeInteger(reader, 0);
116 const fields = decodeInteger(reader, 0);
117 const hasName = fields & 1;
118 const scope = hasName ? [line, column, 0, 0, kind, decodeInteger(reader, 0)] : [line, column, 0, 0, kind];
119 let vars = EMPTY;
120 if (hasMoreVlq(reader, length)) {
121 vars = [];
122 do {
123 const varsIndex = decodeInteger(reader, 0);
124 vars.push(varsIndex);
125 } while (hasMoreVlq(reader, length));
126 }
127 scope.vars = vars;
128 scopes.push(scope);
129 stack.push(scope);
130 }
131 return scopes;
132}
133function encodeOriginalScopes(scopes) {
134 const writer = new StringWriter();
135 for (let i = 0; i < scopes.length; ) {
136 i = _encodeOriginalScopes(scopes, i, writer, [0]);
137 }
138 return writer.flush();
139}
140function _encodeOriginalScopes(scopes, index, writer, state) {
141 const scope = scopes[index];
142 const { 0: startLine, 1: startColumn, 2: endLine, 3: endColumn, 4: kind, vars } = scope;
143 if (index > 0) writer.write(comma);
144 state[0] = encodeInteger(writer, startLine, state[0]);
145 encodeInteger(writer, startColumn, 0);
146 encodeInteger(writer, kind, 0);
147 const fields = scope.length === 6 ? 1 : 0;
148 encodeInteger(writer, fields, 0);
149 if (scope.length === 6) encodeInteger(writer, scope[5], 0);
150 for (const v of vars) {
151 encodeInteger(writer, v, 0);
152 }
153 for (index++; index < scopes.length; ) {
154 const next = scopes[index];
155 const { 0: l, 1: c } = next;
156 if (l > endLine || l === endLine && c >= endColumn) {
157 break;
158 }
159 index = _encodeOriginalScopes(scopes, index, writer, state);
160 }
161 writer.write(comma);
162 state[0] = encodeInteger(writer, endLine, state[0]);
163 encodeInteger(writer, endColumn, 0);
164 return index;
165}
166function decodeGeneratedRanges(input) {
167 const { length } = input;
168 const reader = new StringReader(input);
169 const ranges = [];
170 const stack = [];
171 let genLine = 0;
172 let definitionSourcesIndex = 0;
173 let definitionScopeIndex = 0;
174 let callsiteSourcesIndex = 0;
175 let callsiteLine = 0;
176 let callsiteColumn = 0;
177 let bindingLine = 0;
178 let bindingColumn = 0;
179 do {
180 const semi = reader.indexOf(";");
181 let genColumn = 0;
182 for (; reader.pos < semi; reader.pos++) {
183 genColumn = decodeInteger(reader, genColumn);
184 if (!hasMoreVlq(reader, semi)) {
185 const last = stack.pop();
186 last[2] = genLine;
187 last[3] = genColumn;
188 continue;
189 }
190 const fields = decodeInteger(reader, 0);
191 const hasDefinition = fields & 1;
192 const hasCallsite = fields & 2;
193 const hasScope = fields & 4;
194 let callsite = null;
195 let bindings = EMPTY;
196 let range;
197 if (hasDefinition) {
198 const defSourcesIndex = decodeInteger(reader, definitionSourcesIndex);
199 definitionScopeIndex = decodeInteger(
200 reader,
201 definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0
202 );
203 definitionSourcesIndex = defSourcesIndex;
204 range = [genLine, genColumn, 0, 0, defSourcesIndex, definitionScopeIndex];
205 } else {
206 range = [genLine, genColumn, 0, 0];
207 }
208 range.isScope = !!hasScope;
209 if (hasCallsite) {
210 const prevCsi = callsiteSourcesIndex;
211 const prevLine = callsiteLine;
212 callsiteSourcesIndex = decodeInteger(reader, callsiteSourcesIndex);
213 const sameSource = prevCsi === callsiteSourcesIndex;
214 callsiteLine = decodeInteger(reader, sameSource ? callsiteLine : 0);
215 callsiteColumn = decodeInteger(
216 reader,
217 sameSource && prevLine === callsiteLine ? callsiteColumn : 0
218 );
219 callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];
220 }
221 range.callsite = callsite;
222 if (hasMoreVlq(reader, semi)) {
223 bindings = [];
224 do {
225 bindingLine = genLine;
226 bindingColumn = genColumn;
227 const expressionsCount = decodeInteger(reader, 0);
228 let expressionRanges;
229 if (expressionsCount < -1) {
230 expressionRanges = [[decodeInteger(reader, 0)]];
231 for (let i = -1; i > expressionsCount; i--) {
232 const prevBl = bindingLine;
233 bindingLine = decodeInteger(reader, bindingLine);
234 bindingColumn = decodeInteger(reader, bindingLine === prevBl ? bindingColumn : 0);
235 const expression = decodeInteger(reader, 0);
236 expressionRanges.push([expression, bindingLine, bindingColumn]);
237 }
238 } else {
239 expressionRanges = [[expressionsCount]];
240 }
241 bindings.push(expressionRanges);
242 } while (hasMoreVlq(reader, semi));
243 }
244 range.bindings = bindings;
245 ranges.push(range);
246 stack.push(range);
247 }
248 genLine++;
249 reader.pos = semi + 1;
250 } while (reader.pos < length);
251 return ranges;
252}
253function encodeGeneratedRanges(ranges) {
254 if (ranges.length === 0) return "";
255 const writer = new StringWriter();
256 for (let i = 0; i < ranges.length; ) {
257 i = _encodeGeneratedRanges(ranges, i, writer, [0, 0, 0, 0, 0, 0, 0]);
258 }
259 return writer.flush();
260}
261function _encodeGeneratedRanges(ranges, index, writer, state) {
262 const range = ranges[index];
263 const {
264 0: startLine,
265 1: startColumn,
266 2: endLine,
267 3: endColumn,
268 isScope,
269 callsite,
270 bindings
271 } = range;
272 if (state[0] < startLine) {
273 catchupLine(writer, state[0], startLine);
274 state[0] = startLine;
275 state[1] = 0;
276 } else if (index > 0) {
277 writer.write(comma);
278 }
279 state[1] = encodeInteger(writer, range[1], state[1]);
280 const fields = (range.length === 6 ? 1 : 0) | (callsite ? 2 : 0) | (isScope ? 4 : 0);
281 encodeInteger(writer, fields, 0);
282 if (range.length === 6) {
283 const { 4: sourcesIndex, 5: scopesIndex } = range;
284 if (sourcesIndex !== state[2]) {
285 state[3] = 0;
286 }
287 state[2] = encodeInteger(writer, sourcesIndex, state[2]);
288 state[3] = encodeInteger(writer, scopesIndex, state[3]);
289 }
290 if (callsite) {
291 const { 0: sourcesIndex, 1: callLine, 2: callColumn } = range.callsite;
292 if (sourcesIndex !== state[4]) {
293 state[5] = 0;
294 state[6] = 0;
295 } else if (callLine !== state[5]) {
296 state[6] = 0;
297 }
298 state[4] = encodeInteger(writer, sourcesIndex, state[4]);
299 state[5] = encodeInteger(writer, callLine, state[5]);
300 state[6] = encodeInteger(writer, callColumn, state[6]);
301 }
302 if (bindings) {
303 for (const binding of bindings) {
304 if (binding.length > 1) encodeInteger(writer, -binding.length, 0);
305 const expression = binding[0][0];
306 encodeInteger(writer, expression, 0);
307 let bindingStartLine = startLine;
308 let bindingStartColumn = startColumn;
309 for (let i = 1; i < binding.length; i++) {
310 const expRange = binding[i];
311 bindingStartLine = encodeInteger(writer, expRange[1], bindingStartLine);
312 bindingStartColumn = encodeInteger(writer, expRange[2], bindingStartColumn);
313 encodeInteger(writer, expRange[0], 0);
314 }
315 }
316 }
317 for (index++; index < ranges.length; ) {
318 const next = ranges[index];
319 const { 0: l, 1: c } = next;
320 if (l > endLine || l === endLine && c >= endColumn) {
321 break;
322 }
323 index = _encodeGeneratedRanges(ranges, index, writer, state);
324 }
325 if (state[0] < endLine) {
326 catchupLine(writer, state[0], endLine);
327 state[0] = endLine;
328 state[1] = 0;
329 } else {
330 writer.write(comma);
331 }
332 state[1] = encodeInteger(writer, endColumn, state[1]);
333 return index;
334}
335function catchupLine(writer, lastLine, line) {
336 do {
337 writer.write(semicolon);
338 } while (++lastLine < line);
339}
340
341// src/sourcemap-codec.ts
342function decode(mappings) {
343 const { length } = mappings;
344 const reader = new StringReader(mappings);
345 const decoded = [];
346 let genColumn = 0;
347 let sourcesIndex = 0;
348 let sourceLine = 0;
349 let sourceColumn = 0;
350 let namesIndex = 0;
351 do {
352 const semi = reader.indexOf(";");
353 const line = [];
354 let sorted = true;
355 let lastCol = 0;
356 genColumn = 0;
357 while (reader.pos < semi) {
358 let seg;
359 genColumn = decodeInteger(reader, genColumn);
360 if (genColumn < lastCol) sorted = false;
361 lastCol = genColumn;
362 if (hasMoreVlq(reader, semi)) {
363 sourcesIndex = decodeInteger(reader, sourcesIndex);
364 sourceLine = decodeInteger(reader, sourceLine);
365 sourceColumn = decodeInteger(reader, sourceColumn);
366 if (hasMoreVlq(reader, semi)) {
367 namesIndex = decodeInteger(reader, namesIndex);
368 seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];
369 } else {
370 seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];
371 }
372 } else {
373 seg = [genColumn];
374 }
375 line.push(seg);
376 reader.pos++;
377 }
378 if (!sorted) sort(line);
379 decoded.push(line);
380 reader.pos = semi + 1;
381 } while (reader.pos <= length);
382 return decoded;
383}
384function sort(line) {
385 line.sort(sortComparator);
386}
387function sortComparator(a, b) {
388 return a[0] - b[0];
389}
390function encode(decoded) {
391 const writer = new StringWriter();
392 let sourcesIndex = 0;
393 let sourceLine = 0;
394 let sourceColumn = 0;
395 let namesIndex = 0;
396 for (let i = 0; i < decoded.length; i++) {
397 const line = decoded[i];
398 if (i > 0) writer.write(semicolon);
399 if (line.length === 0) continue;
400 let genColumn = 0;
401 for (let j = 0; j < line.length; j++) {
402 const segment = line[j];
403 if (j > 0) writer.write(comma);
404 genColumn = encodeInteger(writer, segment[0], genColumn);
405 if (segment.length === 1) continue;
406 sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
407 sourceLine = encodeInteger(writer, segment[2], sourceLine);
408 sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
409 if (segment.length === 4) continue;
410 namesIndex = encodeInteger(writer, segment[4], namesIndex);
411 }
412 }
413 return writer.flush();
414}
415export {
416 decode,
417 decodeGeneratedRanges,
418 decodeOriginalScopes,
419 encode,
420 encodeGeneratedRanges,
421 encodeOriginalScopes
422};
423//# sourceMappingURL=sourcemap-codec.mjs.map
node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs.map +6 -0
……@@ -0,0 +1,6 @@
1{
2 "version": 3,
3 "sources": ["../src/vlq.ts", "../src/strings.ts", "../src/scopes.ts", "../src/sourcemap-codec.ts"],
4 "mappings": ";AAEO,IAAM,QAAQ,IAAI,WAAW,CAAC;AAC9B,IAAM,YAAY,IAAI,WAAW,CAAC;AAEzC,IAAM,QAAQ;AACd,IAAM,YAAY,IAAI,WAAW,EAAE;AACnC,IAAM,YAAY,IAAI,WAAW,GAAG;AAEpC,SAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAM,IAAI,MAAM,WAAW,CAAC;AAC5B,YAAU,CAAC,IAAI;AACf,YAAU,CAAC,IAAI;AACjB;AAEO,SAAS,cAAc,QAAsB,UAA0B;AAC5E,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,UAAU;AAEd,KAAG;AACD,UAAM,IAAI,OAAO,KAAK;AACtB,cAAU,UAAU,CAAC;AACrB,cAAU,UAAU,OAAO;AAC3B,aAAS;AAAA,EACX,SAAS,UAAU;AAEnB,QAAM,eAAe,QAAQ;AAC7B,aAAW;AAEX,MAAI,cAAc;AAChB,YAAQ,cAAc,CAAC;AAAA,EACzB;AAEA,SAAO,WAAW;AACpB;AAEO,SAAS,cAAc,SAAuB,KAAa,UAA0B;AAC1F,MAAI,QAAQ,MAAM;AAElB,UAAQ,QAAQ,IAAK,CAAC,SAAS,IAAK,IAAI,SAAS;AACjD,KAAG;AACD,QAAI,UAAU,QAAQ;AACtB,eAAW;AACX,QAAI,QAAQ,EAAG,YAAW;AAC1B,YAAQ,MAAM,UAAU,OAAO,CAAC;AAAA,EAClC,SAAS,QAAQ;AAEjB,SAAO;AACT;AAEO,SAAS,WAAW,QAAsB,KAAa;AAC5D,MAAI,OAAO,OAAO,IAAK,QAAO;AAC9B,SAAO,OAAO,KAAK,MAAM;AAC3B;;;ACtDA,IAAM,YAAY,OAAO;AAGzB,IAAM,KACJ,OAAO,gBAAgB,cACH,oBAAI,YAAY,IAChC,OAAO,WAAW,cAChB;AAAA,EACE,OAAO,KAAyB;AAC9B,UAAM,MAAM,OAAO,KAAK,IAAI,QAAQ,IAAI,YAAY,IAAI,UAAU;AAClE,WAAO,IAAI,SAAS;AAAA,EACtB;AACF,IACA;AAAA,EACE,OAAO,KAAyB;AAC9B,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,aAAO,OAAO,aAAa,IAAI,CAAC,CAAC;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AACF;AAED,IAAM,eAAN,MAAmB;AAAA,EAAnB;AACL,eAAM;AACN,SAAQ,MAAM;AACd,SAAQ,SAAS,IAAI,WAAW,SAAS;AAAA;AAAA,EAEzC,MAAM,GAAiB;AACrB,UAAM,EAAE,OAAO,IAAI;AACnB,WAAO,KAAK,KAAK,IAAI;AACrB,QAAI,KAAK,QAAQ,WAAW;AAC1B,WAAK,OAAO,GAAG,OAAO,MAAM;AAC5B,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,QAAgB;AACd,UAAM,EAAE,QAAQ,KAAK,IAAI,IAAI;AAC7B,WAAO,MAAM,IAAI,MAAM,GAAG,OAAO,OAAO,SAAS,GAAG,GAAG,CAAC,IAAI;AAAA,EAC9D;AACF;AAEO,IAAM,eAAN,MAAmB;AAAA,EAIxB,YAAY,QAAgB;AAH5B,eAAM;AAIJ,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AAAA,EAC1C;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,OAAO,WAAW,KAAK,GAAG;AAAA,EACxC;AAAA,EAEA,QAAQ,MAAsB;AAC5B,UAAM,EAAE,QAAQ,IAAI,IAAI;AACxB,UAAM,MAAM,OAAO,QAAQ,MAAM,GAAG;AACpC,WAAO,QAAQ,KAAK,OAAO,SAAS;AAAA,EACtC;AACF;;;AC7DA,IAAM,QAAe,CAAC;AA+Bf,SAAS,qBAAqB,OAAgC;AACnE,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,IAAI,aAAa,KAAK;AACrC,QAAM,SAA0B,CAAC;AACjC,QAAM,QAAyB,CAAC;AAChC,MAAI,OAAO;AAEX,SAAO,OAAO,MAAM,QAAQ,OAAO,OAAO;AACxC,WAAO,cAAc,QAAQ,IAAI;AACjC,UAAM,SAAS,cAAc,QAAQ,CAAC;AAEtC,QAAI,CAAC,WAAW,QAAQ,MAAM,GAAG;AAC/B,YAAM,OAAO,MAAM,IAAI;AACvB,WAAK,CAAC,IAAI;AACV,WAAK,CAAC,IAAI;AACV;AAAA,IACF;AAEA,UAAM,OAAO,cAAc,QAAQ,CAAC;AACpC,UAAM,SAAS,cAAc,QAAQ,CAAC;AACtC,UAAM,UAAU,SAAS;AAEzB,UAAM,QACJ,UAAU,CAAC,MAAM,QAAQ,GAAG,GAAG,MAAM,cAAc,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,QAAQ,GAAG,GAAG,IAAI;AAG5F,QAAI,OAAc;AAClB,QAAI,WAAW,QAAQ,MAAM,GAAG;AAC9B,aAAO,CAAC;AACR,SAAG;AACD,cAAM,YAAY,cAAc,QAAQ,CAAC;AACzC,aAAK,KAAK,SAAS;AAAA,MACrB,SAAS,WAAW,QAAQ,MAAM;AAAA,IACpC;AACA,UAAM,OAAO;AAEb,WAAO,KAAK,KAAK;AACjB,UAAM,KAAK,KAAK;AAAA,EAClB;AAEA,SAAO;AACT;AAEO,SAAS,qBAAqB,QAAiC;AACpE,QAAM,SAAS,IAAI,aAAa;AAEhC,WAAS,IAAI,GAAG,IAAI,OAAO,UAAU;AACnC,QAAI,sBAAsB,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC;AAAA,EAClD;AAEA,SAAO,OAAO,MAAM;AACtB;AAEA,SAAS,sBACP,QACA,OACA,QACA,OAGQ;AACR,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM,EAAE,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,KAAK,IAAI;AAElF,MAAI,QAAQ,EAAG,QAAO,MAAM,KAAK;AAEjC,QAAM,CAAC,IAAI,cAAc,QAAQ,WAAW,MAAM,CAAC,CAAC;AACpD,gBAAc,QAAQ,aAAa,CAAC;AACpC,gBAAc,QAAQ,MAAM,CAAC;AAE7B,QAAM,SAAS,MAAM,WAAW,IAAI,IAAS;AAC7C,gBAAc,QAAQ,QAAQ,CAAC;AAC/B,MAAI,MAAM,WAAW,EAAG,eAAc,QAAQ,MAAM,CAAC,GAAG,CAAC;AAEzD,aAAW,KAAK,MAAM;AACpB,kBAAc,QAAQ,GAAG,CAAC;AAAA,EAC5B;AAEA,OAAK,SAAS,QAAQ,OAAO,UAAU;AACrC,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AACvB,QAAI,IAAI,WAAY,MAAM,WAAW,KAAK,WAAY;AACpD;AAAA,IACF;AACA,YAAQ,sBAAsB,QAAQ,OAAO,QAAQ,KAAK;AAAA,EAC5D;AAEA,SAAO,MAAM,KAAK;AAClB,QAAM,CAAC,IAAI,cAAc,QAAQ,SAAS,MAAM,CAAC,CAAC;AAClD,gBAAc,QAAQ,WAAW,CAAC;AAElC,SAAO;AACT;AAEO,SAAS,sBAAsB,OAAiC;AACrE,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,IAAI,aAAa,KAAK;AACrC,QAAM,SAA2B,CAAC;AAClC,QAAM,QAA0B,CAAC;AAEjC,MAAI,UAAU;AACd,MAAI,yBAAyB;AAC7B,MAAI,uBAAuB;AAC3B,MAAI,uBAAuB;AAC3B,MAAI,eAAe;AACnB,MAAI,iBAAiB;AACrB,MAAI,cAAc;AAClB,MAAI,gBAAgB;AAEpB,KAAG;AACD,UAAM,OAAO,OAAO,QAAQ,GAAG;AAC/B,QAAI,YAAY;AAEhB,WAAO,OAAO,MAAM,MAAM,OAAO,OAAO;AACtC,kBAAY,cAAc,QAAQ,SAAS;AAE3C,UAAI,CAAC,WAAW,QAAQ,IAAI,GAAG;AAC7B,cAAM,OAAO,MAAM,IAAI;AACvB,aAAK,CAAC,IAAI;AACV,aAAK,CAAC,IAAI;AACV;AAAA,MACF;AAEA,YAAM,SAAS,cAAc,QAAQ,CAAC;AACtC,YAAM,gBAAgB,SAAS;AAC/B,YAAM,cAAc,SAAS;AAC7B,YAAM,WAAW,SAAS;AAE1B,UAAI,WAA4B;AAChC,UAAI,WAAsB;AAC1B,UAAI;AACJ,UAAI,eAAe;AACjB,cAAM,kBAAkB,cAAc,QAAQ,sBAAsB;AACpE,+BAAuB;AAAA,UACrB;AAAA,UACA,2BAA2B,kBAAkB,uBAAuB;AAAA,QACtE;AAEA,iCAAyB;AACzB,gBAAQ,CAAC,SAAS,WAAW,GAAG,GAAG,iBAAiB,oBAAoB;AAAA,MAC1E,OAAO;AACL,gBAAQ,CAAC,SAAS,WAAW,GAAG,CAAC;AAAA,MACnC;AAEA,YAAM,UAAU,CAAC,CAAC;AAElB,UAAI,aAAa;AACf,cAAM,UAAU;AAChB,cAAM,WAAW;AACjB,+BAAuB,cAAc,QAAQ,oBAAoB;AACjE,cAAM,aAAa,YAAY;AAC/B,uBAAe,cAAc,QAAQ,aAAa,eAAe,CAAC;AAClE,yBAAiB;AAAA,UACf;AAAA,UACA,cAAc,aAAa,eAAe,iBAAiB;AAAA,QAC7D;AAEA,mBAAW,CAAC,sBAAsB,cAAc,cAAc;AAAA,MAChE;AACA,YAAM,WAAW;AAEjB,UAAI,WAAW,QAAQ,IAAI,GAAG;AAC5B,mBAAW,CAAC;AACZ,WAAG;AACD,wBAAc;AACd,0BAAgB;AAChB,gBAAM,mBAAmB,cAAc,QAAQ,CAAC;AAChD,cAAI;AACJ,cAAI,mBAAmB,IAAI;AACzB,+BAAmB,CAAC,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC;AAC9C,qBAAS,IAAI,IAAI,IAAI,kBAAkB,KAAK;AAC1C,oBAAM,SAAS;AACf,4BAAc,cAAc,QAAQ,WAAW;AAC/C,8BAAgB,cAAc,QAAQ,gBAAgB,SAAS,gBAAgB,CAAC;AAChF,oBAAM,aAAa,cAAc,QAAQ,CAAC;AAC1C,+BAAiB,KAAK,CAAC,YAAY,aAAa,aAAa,CAAC;AAAA,YAChE;AAAA,UACF,OAAO;AACL,+BAAmB,CAAC,CAAC,gBAAgB,CAAC;AAAA,UACxC;AACA,mBAAS,KAAK,gBAAgB;AAAA,QAChC,SAAS,WAAW,QAAQ,IAAI;AAAA,MAClC;AACA,YAAM,WAAW;AAEjB,aAAO,KAAK,KAAK;AACjB,YAAM,KAAK,KAAK;AAAA,IAClB;AAEA;AACA,WAAO,MAAM,OAAO;AAAA,EACtB,SAAS,OAAO,MAAM;AAEtB,SAAO;AACT;AAEO,SAAS,sBAAsB,QAAkC;AACtE,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAM,SAAS,IAAI,aAAa;AAEhC,WAAS,IAAI,GAAG,IAAI,OAAO,UAAU;AACnC,QAAI,uBAAuB,QAAQ,GAAG,QAAQ,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,EACrE;AAEA,SAAO,OAAO,MAAM;AACtB;AAEA,SAAS,uBACP,QACA,OACA,QACA,OASQ;AACR,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM;AAAA,IACJ,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,MAAM,CAAC,IAAI,WAAW;AACxB,gBAAY,QAAQ,MAAM,CAAC,GAAG,SAAS;AACvC,UAAM,CAAC,IAAI;AACX,UAAM,CAAC,IAAI;AAAA,EACb,WAAW,QAAQ,GAAG;AACpB,WAAO,MAAM,KAAK;AAAA,EACpB;AAEA,QAAM,CAAC,IAAI,cAAc,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAEnD,QAAM,UACH,MAAM,WAAW,IAAI,IAAS,MAAM,WAAW,IAAS,MAAM,UAAU,IAAS;AACpF,gBAAc,QAAQ,QAAQ,CAAC;AAE/B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,EAAE,GAAG,cAAc,GAAG,YAAY,IAAI;AAC5C,QAAI,iBAAiB,MAAM,CAAC,GAAG;AAC7B,YAAM,CAAC,IAAI;AAAA,IACb;AACA,UAAM,CAAC,IAAI,cAAc,QAAQ,cAAc,MAAM,CAAC,CAAC;AACvD,UAAM,CAAC,IAAI,cAAc,QAAQ,aAAa,MAAM,CAAC,CAAC;AAAA,EACxD;AAEA,MAAI,UAAU;AACZ,UAAM,EAAE,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,IAAI,MAAM;AAC9D,QAAI,iBAAiB,MAAM,CAAC,GAAG;AAC7B,YAAM,CAAC,IAAI;AACX,YAAM,CAAC,IAAI;AAAA,IACb,WAAW,aAAa,MAAM,CAAC,GAAG;AAChC,YAAM,CAAC,IAAI;AAAA,IACb;AACA,UAAM,CAAC,IAAI,cAAc,QAAQ,cAAc,MAAM,CAAC,CAAC;AACvD,UAAM,CAAC,IAAI,cAAc,QAAQ,UAAU,MAAM,CAAC,CAAC;AACnD,UAAM,CAAC,IAAI,cAAc,QAAQ,YAAY,MAAM,CAAC,CAAC;AAAA,EACvD;AAEA,MAAI,UAAU;AACZ,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,SAAS,EAAG,eAAc,QAAQ,CAAC,QAAQ,QAAQ,CAAC;AAChE,YAAM,aAAa,QAAQ,CAAC,EAAE,CAAC;AAC/B,oBAAc,QAAQ,YAAY,CAAC;AACnC,UAAI,mBAAmB;AACvB,UAAI,qBAAqB;AACzB,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,cAAM,WAAW,QAAQ,CAAC;AAC1B,2BAAmB,cAAc,QAAQ,SAAS,CAAC,GAAI,gBAAgB;AACvE,6BAAqB,cAAc,QAAQ,SAAS,CAAC,GAAI,kBAAkB;AAC3E,sBAAc,QAAQ,SAAS,CAAC,GAAI,CAAC;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,OAAK,SAAS,QAAQ,OAAO,UAAU;AACrC,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AACvB,QAAI,IAAI,WAAY,MAAM,WAAW,KAAK,WAAY;AACpD;AAAA,IACF;AACA,YAAQ,uBAAuB,QAAQ,OAAO,QAAQ,KAAK;AAAA,EAC7D;AAEA,MAAI,MAAM,CAAC,IAAI,SAAS;AACtB,gBAAY,QAAQ,MAAM,CAAC,GAAG,OAAO;AACrC,UAAM,CAAC,IAAI;AACX,UAAM,CAAC,IAAI;AAAA,EACb,OAAO;AACL,WAAO,MAAM,KAAK;AAAA,EACpB;AACA,QAAM,CAAC,IAAI,cAAc,QAAQ,WAAW,MAAM,CAAC,CAAC;AAEpD,SAAO;AACT;AAEA,SAAS,YAAY,QAAsB,UAAkB,MAAc;AACzE,KAAG;AACD,WAAO,MAAM,SAAS;AAAA,EACxB,SAAS,EAAE,WAAW;AACxB;;;ACtUO,SAAS,OAAO,UAAqC;AAC1D,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,IAAI,aAAa,QAAQ;AACxC,QAAM,UAA6B,CAAC;AACpC,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,MAAI,aAAa;AAEjB,KAAG;AACD,UAAM,OAAO,OAAO,QAAQ,GAAG;AAC/B,UAAM,OAAsB,CAAC;AAC7B,QAAI,SAAS;AACb,QAAI,UAAU;AACd,gBAAY;AAEZ,WAAO,OAAO,MAAM,MAAM;AACxB,UAAI;AAEJ,kBAAY,cAAc,QAAQ,SAAS;AAC3C,UAAI,YAAY,QAAS,UAAS;AAClC,gBAAU;AAEV,UAAI,WAAW,QAAQ,IAAI,GAAG;AAC5B,uBAAe,cAAc,QAAQ,YAAY;AACjD,qBAAa,cAAc,QAAQ,UAAU;AAC7C,uBAAe,cAAc,QAAQ,YAAY;AAEjD,YAAI,WAAW,QAAQ,IAAI,GAAG;AAC5B,uBAAa,cAAc,QAAQ,UAAU;AAC7C,gBAAM,CAAC,WAAW,cAAc,YAAY,cAAc,UAAU;AAAA,QACtE,OAAO;AACL,gBAAM,CAAC,WAAW,cAAc,YAAY,YAAY;AAAA,QAC1D;AAAA,MACF,OAAO;AACL,cAAM,CAAC,SAAS;AAAA,MAClB;AAEA,WAAK,KAAK,GAAG;AACb,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,OAAQ,MAAK,IAAI;AACtB,YAAQ,KAAK,IAAI;AACjB,WAAO,MAAM,OAAO;AAAA,EACtB,SAAS,OAAO,OAAO;AAEvB,SAAO;AACT;AAEA,SAAS,KAAK,MAA0B;AACtC,OAAK,KAAK,cAAc;AAC1B;AAEA,SAAS,eAAe,GAAqB,GAA6B;AACxE,SAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AACnB;AAIO,SAAS,OAAO,SAA8C;AACnE,QAAM,SAAS,IAAI,aAAa;AAChC,MAAI,eAAe;AACnB,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,MAAI,aAAa;AAEjB,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,CAAC;AACtB,QAAI,IAAI,EAAG,QAAO,MAAM,SAAS;AACjC,QAAI,KAAK,WAAW,EAAG;AAEvB,QAAI,YAAY;AAEhB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,UAAU,KAAK,CAAC;AACtB,UAAI,IAAI,EAAG,QAAO,MAAM,KAAK;AAE7B,kBAAY,cAAc,QAAQ,QAAQ,CAAC,GAAG,SAAS;AAEvD,UAAI,QAAQ,WAAW,EAAG;AAC1B,qBAAe,cAAc,QAAQ,QAAQ,CAAC,GAAG,YAAY;AAC7D,mBAAa,cAAc,QAAQ,QAAQ,CAAC,GAAG,UAAU;AACzD,qBAAe,cAAc,QAAQ,QAAQ,CAAC,GAAG,YAAY;AAE7D,UAAI,QAAQ,WAAW,EAAG;AAC1B,mBAAa,cAAc,QAAQ,QAAQ,CAAC,GAAG,UAAU;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO,OAAO,MAAM;AACtB;",
5 "names": []
6}
node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.umd.js +464 -0
……@@ -0,0 +1,464 @@
1(function (global, factory) {
2 if (typeof exports === 'object' && typeof module !== 'undefined') {
3 factory(module);
4 module.exports = def(module);
5 } else if (typeof define === 'function' && define.amd) {
6 define(['module'], function(mod) {
7 factory.apply(this, arguments);
8 mod.exports = def(mod);
9 });
10 } else {
11 const mod = { exports: {} };
12 factory(mod);
13 global = typeof globalThis !== 'undefined' ? globalThis : global || self;
14 global.sourcemapCodec = def(mod);
15 }
16 function def(m) { return 'default' in m.exports ? m.exports.default : m.exports; }
17})(this, (function (module) {
18"use strict";
19var __defProp = Object.defineProperty;
20var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
21var __getOwnPropNames = Object.getOwnPropertyNames;
22var __hasOwnProp = Object.prototype.hasOwnProperty;
23var __export = (target, all) => {
24 for (var name in all)
25 __defProp(target, name, { get: all[name], enumerable: true });
26};
27var __copyProps = (to, from, except, desc) => {
28 if (from && typeof from === "object" || typeof from === "function") {
29 for (let key of __getOwnPropNames(from))
30 if (!__hasOwnProp.call(to, key) && key !== except)
31 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
32 }
33 return to;
34};
35var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
37// src/sourcemap-codec.ts
38var sourcemap_codec_exports = {};
39__export(sourcemap_codec_exports, {
40 decode: () => decode,
41 decodeGeneratedRanges: () => decodeGeneratedRanges,
42 decodeOriginalScopes: () => decodeOriginalScopes,
43 encode: () => encode,
44 encodeGeneratedRanges: () => encodeGeneratedRanges,
45 encodeOriginalScopes: () => encodeOriginalScopes
46});
47module.exports = __toCommonJS(sourcemap_codec_exports);
48
49// src/vlq.ts
50var comma = ",".charCodeAt(0);
51var semicolon = ";".charCodeAt(0);
52var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
53var intToChar = new Uint8Array(64);
54var charToInt = new Uint8Array(128);
55for (let i = 0; i < chars.length; i++) {
56 const c = chars.charCodeAt(i);
57 intToChar[i] = c;
58 charToInt[c] = i;
59}
60function decodeInteger(reader, relative) {
61 let value = 0;
62 let shift = 0;
63 let integer = 0;
64 do {
65 const c = reader.next();
66 integer = charToInt[c];
67 value |= (integer & 31) << shift;
68 shift += 5;
69 } while (integer & 32);
70 const shouldNegate = value & 1;
71 value >>>= 1;
72 if (shouldNegate) {
73 value = -2147483648 | -value;
74 }
75 return relative + value;
76}
77function encodeInteger(builder, num, relative) {
78 let delta = num - relative;
79 delta = delta < 0 ? -delta << 1 | 1 : delta << 1;
80 do {
81 let clamped = delta & 31;
82 delta >>>= 5;
83 if (delta > 0) clamped |= 32;
84 builder.write(intToChar[clamped]);
85 } while (delta > 0);
86 return num;
87}
88function hasMoreVlq(reader, max) {
89 if (reader.pos >= max) return false;
90 return reader.peek() !== comma;
91}
92
93// src/strings.ts
94var bufLength = 1024 * 16;
95var td = typeof TextDecoder !== "undefined" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== "undefined" ? {
96 decode(buf) {
97 const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);
98 return out.toString();
99 }
100} : {
101 decode(buf) {
102 let out = "";
103 for (let i = 0; i < buf.length; i++) {
104 out += String.fromCharCode(buf[i]);
105 }
106 return out;
107 }
108};
109var StringWriter = class {
110 constructor() {
111 this.pos = 0;
112 this.out = "";
113 this.buffer = new Uint8Array(bufLength);
114 }
115 write(v) {
116 const { buffer } = this;
117 buffer[this.pos++] = v;
118 if (this.pos === bufLength) {
119 this.out += td.decode(buffer);
120 this.pos = 0;
121 }
122 }
123 flush() {
124 const { buffer, out, pos } = this;
125 return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
126 }
127};
128var StringReader = class {
129 constructor(buffer) {
130 this.pos = 0;
131 this.buffer = buffer;
132 }
133 next() {
134 return this.buffer.charCodeAt(this.pos++);
135 }
136 peek() {
137 return this.buffer.charCodeAt(this.pos);
138 }
139 indexOf(char) {
140 const { buffer, pos } = this;
141 const idx = buffer.indexOf(char, pos);
142 return idx === -1 ? buffer.length : idx;
143 }
144};
145
146// src/scopes.ts
147var EMPTY = [];
148function decodeOriginalScopes(input) {
149 const { length } = input;
150 const reader = new StringReader(input);
151 const scopes = [];
152 const stack = [];
153 let line = 0;
154 for (; reader.pos < length; reader.pos++) {
155 line = decodeInteger(reader, line);
156 const column = decodeInteger(reader, 0);
157 if (!hasMoreVlq(reader, length)) {
158 const last = stack.pop();
159 last[2] = line;
160 last[3] = column;
161 continue;
162 }
163 const kind = decodeInteger(reader, 0);
164 const fields = decodeInteger(reader, 0);
165 const hasName = fields & 1;
166 const scope = hasName ? [line, column, 0, 0, kind, decodeInteger(reader, 0)] : [line, column, 0, 0, kind];
167 let vars = EMPTY;
168 if (hasMoreVlq(reader, length)) {
169 vars = [];
170 do {
171 const varsIndex = decodeInteger(reader, 0);
172 vars.push(varsIndex);
173 } while (hasMoreVlq(reader, length));
174 }
175 scope.vars = vars;
176 scopes.push(scope);
177 stack.push(scope);
178 }
179 return scopes;
180}
181function encodeOriginalScopes(scopes) {
182 const writer = new StringWriter();
183 for (let i = 0; i < scopes.length; ) {
184 i = _encodeOriginalScopes(scopes, i, writer, [0]);
185 }
186 return writer.flush();
187}
188function _encodeOriginalScopes(scopes, index, writer, state) {
189 const scope = scopes[index];
190 const { 0: startLine, 1: startColumn, 2: endLine, 3: endColumn, 4: kind, vars } = scope;
191 if (index > 0) writer.write(comma);
192 state[0] = encodeInteger(writer, startLine, state[0]);
193 encodeInteger(writer, startColumn, 0);
194 encodeInteger(writer, kind, 0);
195 const fields = scope.length === 6 ? 1 : 0;
196 encodeInteger(writer, fields, 0);
197 if (scope.length === 6) encodeInteger(writer, scope[5], 0);
198 for (const v of vars) {
199 encodeInteger(writer, v, 0);
200 }
201 for (index++; index < scopes.length; ) {
202 const next = scopes[index];
203 const { 0: l, 1: c } = next;
204 if (l > endLine || l === endLine && c >= endColumn) {
205 break;
206 }
207 index = _encodeOriginalScopes(scopes, index, writer, state);
208 }
209 writer.write(comma);
210 state[0] = encodeInteger(writer, endLine, state[0]);
211 encodeInteger(writer, endColumn, 0);
212 return index;
213}
214function decodeGeneratedRanges(input) {
215 const { length } = input;
216 const reader = new StringReader(input);
217 const ranges = [];
218 const stack = [];
219 let genLine = 0;
220 let definitionSourcesIndex = 0;
221 let definitionScopeIndex = 0;
222 let callsiteSourcesIndex = 0;
223 let callsiteLine = 0;
224 let callsiteColumn = 0;
225 let bindingLine = 0;
226 let bindingColumn = 0;
227 do {
228 const semi = reader.indexOf(";");
229 let genColumn = 0;
230 for (; reader.pos < semi; reader.pos++) {
231 genColumn = decodeInteger(reader, genColumn);
232 if (!hasMoreVlq(reader, semi)) {
233 const last = stack.pop();
234 last[2] = genLine;
235 last[3] = genColumn;
236 continue;
237 }
238 const fields = decodeInteger(reader, 0);
239 const hasDefinition = fields & 1;
240 const hasCallsite = fields & 2;
241 const hasScope = fields & 4;
242 let callsite = null;
243 let bindings = EMPTY;
244 let range;
245 if (hasDefinition) {
246 const defSourcesIndex = decodeInteger(reader, definitionSourcesIndex);
247 definitionScopeIndex = decodeInteger(
248 reader,
249 definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0
250 );
251 definitionSourcesIndex = defSourcesIndex;
252 range = [genLine, genColumn, 0, 0, defSourcesIndex, definitionScopeIndex];
253 } else {
254 range = [genLine, genColumn, 0, 0];
255 }
256 range.isScope = !!hasScope;
257 if (hasCallsite) {
258 const prevCsi = callsiteSourcesIndex;
259 const prevLine = callsiteLine;
260 callsiteSourcesIndex = decodeInteger(reader, callsiteSourcesIndex);
261 const sameSource = prevCsi === callsiteSourcesIndex;
262 callsiteLine = decodeInteger(reader, sameSource ? callsiteLine : 0);
263 callsiteColumn = decodeInteger(
264 reader,
265 sameSource && prevLine === callsiteLine ? callsiteColumn : 0
266 );
267 callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];
268 }
269 range.callsite = callsite;
270 if (hasMoreVlq(reader, semi)) {
271 bindings = [];
272 do {
273 bindingLine = genLine;
274 bindingColumn = genColumn;
275 const expressionsCount = decodeInteger(reader, 0);
276 let expressionRanges;
277 if (expressionsCount < -1) {
278 expressionRanges = [[decodeInteger(reader, 0)]];
279 for (let i = -1; i > expressionsCount; i--) {
280 const prevBl = bindingLine;
281 bindingLine = decodeInteger(reader, bindingLine);
282 bindingColumn = decodeInteger(reader, bindingLine === prevBl ? bindingColumn : 0);
283 const expression = decodeInteger(reader, 0);
284 expressionRanges.push([expression, bindingLine, bindingColumn]);
285 }
286 } else {
287 expressionRanges = [[expressionsCount]];
288 }
289 bindings.push(expressionRanges);
290 } while (hasMoreVlq(reader, semi));
291 }
292 range.bindings = bindings;
293 ranges.push(range);
294 stack.push(range);
295 }
296 genLine++;
297 reader.pos = semi + 1;
298 } while (reader.pos < length);
299 return ranges;
300}
301function encodeGeneratedRanges(ranges) {
302 if (ranges.length === 0) return "";
303 const writer = new StringWriter();
304 for (let i = 0; i < ranges.length; ) {
305 i = _encodeGeneratedRanges(ranges, i, writer, [0, 0, 0, 0, 0, 0, 0]);
306 }
307 return writer.flush();
308}
309function _encodeGeneratedRanges(ranges, index, writer, state) {
310 const range = ranges[index];
311 const {
312 0: startLine,
313 1: startColumn,
314 2: endLine,
315 3: endColumn,
316 isScope,
317 callsite,
318 bindings
319 } = range;
320 if (state[0] < startLine) {
321 catchupLine(writer, state[0], startLine);
322 state[0] = startLine;
323 state[1] = 0;
324 } else if (index > 0) {
325 writer.write(comma);
326 }
327 state[1] = encodeInteger(writer, range[1], state[1]);
328 const fields = (range.length === 6 ? 1 : 0) | (callsite ? 2 : 0) | (isScope ? 4 : 0);
329 encodeInteger(writer, fields, 0);
330 if (range.length === 6) {
331 const { 4: sourcesIndex, 5: scopesIndex } = range;
332 if (sourcesIndex !== state[2]) {
333 state[3] = 0;
334 }
335 state[2] = encodeInteger(writer, sourcesIndex, state[2]);
336 state[3] = encodeInteger(writer, scopesIndex, state[3]);
337 }
338 if (callsite) {
339 const { 0: sourcesIndex, 1: callLine, 2: callColumn } = range.callsite;
340 if (sourcesIndex !== state[4]) {
341 state[5] = 0;
342 state[6] = 0;
343 } else if (callLine !== state[5]) {
344 state[6] = 0;
345 }
346 state[4] = encodeInteger(writer, sourcesIndex, state[4]);
347 state[5] = encodeInteger(writer, callLine, state[5]);
348 state[6] = encodeInteger(writer, callColumn, state[6]);
349 }
350 if (bindings) {
351 for (const binding of bindings) {
352 if (binding.length > 1) encodeInteger(writer, -binding.length, 0);
353 const expression = binding[0][0];
354 encodeInteger(writer, expression, 0);
355 let bindingStartLine = startLine;
356 let bindingStartColumn = startColumn;
357 for (let i = 1; i < binding.length; i++) {
358 const expRange = binding[i];
359 bindingStartLine = encodeInteger(writer, expRange[1], bindingStartLine);
360 bindingStartColumn = encodeInteger(writer, expRange[2], bindingStartColumn);
361 encodeInteger(writer, expRange[0], 0);
362 }
363 }
364 }
365 for (index++; index < ranges.length; ) {
366 const next = ranges[index];
367 const { 0: l, 1: c } = next;
368 if (l > endLine || l === endLine && c >= endColumn) {
369 break;
370 }
371 index = _encodeGeneratedRanges(ranges, index, writer, state);
372 }
373 if (state[0] < endLine) {
374 catchupLine(writer, state[0], endLine);
375 state[0] = endLine;
376 state[1] = 0;
377 } else {
378 writer.write(comma);
379 }
380 state[1] = encodeInteger(writer, endColumn, state[1]);
381 return index;
382}
383function catchupLine(writer, lastLine, line) {
384 do {
385 writer.write(semicolon);
386 } while (++lastLine < line);
387}
388
389// src/sourcemap-codec.ts
390function decode(mappings) {
391 const { length } = mappings;
392 const reader = new StringReader(mappings);
393 const decoded = [];
394 let genColumn = 0;
395 let sourcesIndex = 0;
396 let sourceLine = 0;
397 let sourceColumn = 0;
398 let namesIndex = 0;
399 do {
400 const semi = reader.indexOf(";");
401 const line = [];
402 let sorted = true;
403 let lastCol = 0;
404 genColumn = 0;
405 while (reader.pos < semi) {
406 let seg;
407 genColumn = decodeInteger(reader, genColumn);
408 if (genColumn < lastCol) sorted = false;
409 lastCol = genColumn;
410 if (hasMoreVlq(reader, semi)) {
411 sourcesIndex = decodeInteger(reader, sourcesIndex);
412 sourceLine = decodeInteger(reader, sourceLine);
413 sourceColumn = decodeInteger(reader, sourceColumn);
414 if (hasMoreVlq(reader, semi)) {
415 namesIndex = decodeInteger(reader, namesIndex);
416 seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];
417 } else {
418 seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];
419 }
420 } else {
421 seg = [genColumn];
422 }
423 line.push(seg);
424 reader.pos++;
425 }
426 if (!sorted) sort(line);
427 decoded.push(line);
428 reader.pos = semi + 1;
429 } while (reader.pos <= length);
430 return decoded;
431}
432function sort(line) {
433 line.sort(sortComparator);
434}
435function sortComparator(a, b) {
436 return a[0] - b[0];
437}
438function encode(decoded) {
439 const writer = new StringWriter();
440 let sourcesIndex = 0;
441 let sourceLine = 0;
442 let sourceColumn = 0;
443 let namesIndex = 0;
444 for (let i = 0; i < decoded.length; i++) {
445 const line = decoded[i];
446 if (i > 0) writer.write(semicolon);
447 if (line.length === 0) continue;
448 let genColumn = 0;
449 for (let j = 0; j < line.length; j++) {
450 const segment = line[j];
451 if (j > 0) writer.write(comma);
452 genColumn = encodeInteger(writer, segment[0], genColumn);
453 if (segment.length === 1) continue;
454 sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
455 sourceLine = encodeInteger(writer, segment[2], sourceLine);
456 sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
457 if (segment.length === 4) continue;
458 namesIndex = encodeInteger(writer, segment[4], namesIndex);
459 }
460 }
461 return writer.flush();
462}
463}));
464//# sourceMappingURL=sourcemap-codec.umd.js.map
node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.umd.js.map +6 -0
……@@ -0,0 +1,6 @@
1{
2 "version": 3,
3 "sources": ["../src/sourcemap-codec.ts", "../src/vlq.ts", "../src/strings.ts", "../src/scopes.ts"],
4 "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,QAAQ,IAAI,WAAW,CAAC;AAC9B,IAAM,YAAY,IAAI,WAAW,CAAC;AAEzC,IAAM,QAAQ;AACd,IAAM,YAAY,IAAI,WAAW,EAAE;AACnC,IAAM,YAAY,IAAI,WAAW,GAAG;AAEpC,SAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAM,IAAI,MAAM,WAAW,CAAC;AAC5B,YAAU,CAAC,IAAI;AACf,YAAU,CAAC,IAAI;AACjB;AAEO,SAAS,cAAc,QAAsB,UAA0B;AAC5E,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,UAAU;AAEd,KAAG;AACD,UAAM,IAAI,OAAO,KAAK;AACtB,cAAU,UAAU,CAAC;AACrB,cAAU,UAAU,OAAO;AAC3B,aAAS;AAAA,EACX,SAAS,UAAU;AAEnB,QAAM,eAAe,QAAQ;AAC7B,aAAW;AAEX,MAAI,cAAc;AAChB,YAAQ,cAAc,CAAC;AAAA,EACzB;AAEA,SAAO,WAAW;AACpB;AAEO,SAAS,cAAc,SAAuB,KAAa,UAA0B;AAC1F,MAAI,QAAQ,MAAM;AAElB,UAAQ,QAAQ,IAAK,CAAC,SAAS,IAAK,IAAI,SAAS;AACjD,KAAG;AACD,QAAI,UAAU,QAAQ;AACtB,eAAW;AACX,QAAI,QAAQ,EAAG,YAAW;AAC1B,YAAQ,MAAM,UAAU,OAAO,CAAC;AAAA,EAClC,SAAS,QAAQ;AAEjB,SAAO;AACT;AAEO,SAAS,WAAW,QAAsB,KAAa;AAC5D,MAAI,OAAO,OAAO,IAAK,QAAO;AAC9B,SAAO,OAAO,KAAK,MAAM;AAC3B;;;ACtDA,IAAM,YAAY,OAAO;AAGzB,IAAM,KACJ,OAAO,gBAAgB,cACH,oBAAI,YAAY,IAChC,OAAO,WAAW,cAChB;AAAA,EACE,OAAO,KAAyB;AAC9B,UAAM,MAAM,OAAO,KAAK,IAAI,QAAQ,IAAI,YAAY,IAAI,UAAU;AAClE,WAAO,IAAI,SAAS;AAAA,EACtB;AACF,IACA;AAAA,EACE,OAAO,KAAyB;AAC9B,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,aAAO,OAAO,aAAa,IAAI,CAAC,CAAC;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AACF;AAED,IAAM,eAAN,MAAmB;AAAA,EAAnB;AACL,eAAM;AACN,SAAQ,MAAM;AACd,SAAQ,SAAS,IAAI,WAAW,SAAS;AAAA;AAAA,EAEzC,MAAM,GAAiB;AACrB,UAAM,EAAE,OAAO,IAAI;AACnB,WAAO,KAAK,KAAK,IAAI;AACrB,QAAI,KAAK,QAAQ,WAAW;AAC1B,WAAK,OAAO,GAAG,OAAO,MAAM;AAC5B,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,QAAgB;AACd,UAAM,EAAE,QAAQ,KAAK,IAAI,IAAI;AAC7B,WAAO,MAAM,IAAI,MAAM,GAAG,OAAO,OAAO,SAAS,GAAG,GAAG,CAAC,IAAI;AAAA,EAC9D;AACF;AAEO,IAAM,eAAN,MAAmB;AAAA,EAIxB,YAAY,QAAgB;AAH5B,eAAM;AAIJ,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AAAA,EAC1C;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,OAAO,WAAW,KAAK,GAAG;AAAA,EACxC;AAAA,EAEA,QAAQ,MAAsB;AAC5B,UAAM,EAAE,QAAQ,IAAI,IAAI;AACxB,UAAM,MAAM,OAAO,QAAQ,MAAM,GAAG;AACpC,WAAO,QAAQ,KAAK,OAAO,SAAS;AAAA,EACtC;AACF;;;AC7DA,IAAM,QAAe,CAAC;AA+Bf,SAAS,qBAAqB,OAAgC;AACnE,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,IAAI,aAAa,KAAK;AACrC,QAAM,SAA0B,CAAC;AACjC,QAAM,QAAyB,CAAC;AAChC,MAAI,OAAO;AAEX,SAAO,OAAO,MAAM,QAAQ,OAAO,OAAO;AACxC,WAAO,cAAc,QAAQ,IAAI;AACjC,UAAM,SAAS,cAAc,QAAQ,CAAC;AAEtC,QAAI,CAAC,WAAW,QAAQ,MAAM,GAAG;AAC/B,YAAM,OAAO,MAAM,IAAI;AACvB,WAAK,CAAC,IAAI;AACV,WAAK,CAAC,IAAI;AACV;AAAA,IACF;AAEA,UAAM,OAAO,cAAc,QAAQ,CAAC;AACpC,UAAM,SAAS,cAAc,QAAQ,CAAC;AACtC,UAAM,UAAU,SAAS;AAEzB,UAAM,QACJ,UAAU,CAAC,MAAM,QAAQ,GAAG,GAAG,MAAM,cAAc,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,QAAQ,GAAG,GAAG,IAAI;AAG5F,QAAI,OAAc;AAClB,QAAI,WAAW,QAAQ,MAAM,GAAG;AAC9B,aAAO,CAAC;AACR,SAAG;AACD,cAAM,YAAY,cAAc,QAAQ,CAAC;AACzC,aAAK,KAAK,SAAS;AAAA,MACrB,SAAS,WAAW,QAAQ,MAAM;AAAA,IACpC;AACA,UAAM,OAAO;AAEb,WAAO,KAAK,KAAK;AACjB,UAAM,KAAK,KAAK;AAAA,EAClB;AAEA,SAAO;AACT;AAEO,SAAS,qBAAqB,QAAiC;AACpE,QAAM,SAAS,IAAI,aAAa;AAEhC,WAAS,IAAI,GAAG,IAAI,OAAO,UAAU;AACnC,QAAI,sBAAsB,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC;AAAA,EAClD;AAEA,SAAO,OAAO,MAAM;AACtB;AAEA,SAAS,sBACP,QACA,OACA,QACA,OAGQ;AACR,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM,EAAE,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,KAAK,IAAI;AAElF,MAAI,QAAQ,EAAG,QAAO,MAAM,KAAK;AAEjC,QAAM,CAAC,IAAI,cAAc,QAAQ,WAAW,MAAM,CAAC,CAAC;AACpD,gBAAc,QAAQ,aAAa,CAAC;AACpC,gBAAc,QAAQ,MAAM,CAAC;AAE7B,QAAM,SAAS,MAAM,WAAW,IAAI,IAAS;AAC7C,gBAAc,QAAQ,QAAQ,CAAC;AAC/B,MAAI,MAAM,WAAW,EAAG,eAAc,QAAQ,MAAM,CAAC,GAAG,CAAC;AAEzD,aAAW,KAAK,MAAM;AACpB,kBAAc,QAAQ,GAAG,CAAC;AAAA,EAC5B;AAEA,OAAK,SAAS,QAAQ,OAAO,UAAU;AACrC,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AACvB,QAAI,IAAI,WAAY,MAAM,WAAW,KAAK,WAAY;AACpD;AAAA,IACF;AACA,YAAQ,sBAAsB,QAAQ,OAAO,QAAQ,KAAK;AAAA,EAC5D;AAEA,SAAO,MAAM,KAAK;AAClB,QAAM,CAAC,IAAI,cAAc,QAAQ,SAAS,MAAM,CAAC,CAAC;AAClD,gBAAc,QAAQ,WAAW,CAAC;AAElC,SAAO;AACT;AAEO,SAAS,sBAAsB,OAAiC;AACrE,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,IAAI,aAAa,KAAK;AACrC,QAAM,SAA2B,CAAC;AAClC,QAAM,QAA0B,CAAC;AAEjC,MAAI,UAAU;AACd,MAAI,yBAAyB;AAC7B,MAAI,uBAAuB;AAC3B,MAAI,uBAAuB;AAC3B,MAAI,eAAe;AACnB,MAAI,iBAAiB;AACrB,MAAI,cAAc;AAClB,MAAI,gBAAgB;AAEpB,KAAG;AACD,UAAM,OAAO,OAAO,QAAQ,GAAG;AAC/B,QAAI,YAAY;AAEhB,WAAO,OAAO,MAAM,MAAM,OAAO,OAAO;AACtC,kBAAY,cAAc,QAAQ,SAAS;AAE3C,UAAI,CAAC,WAAW,QAAQ,IAAI,GAAG;AAC7B,cAAM,OAAO,MAAM,IAAI;AACvB,aAAK,CAAC,IAAI;AACV,aAAK,CAAC,IAAI;AACV;AAAA,MACF;AAEA,YAAM,SAAS,cAAc,QAAQ,CAAC;AACtC,YAAM,gBAAgB,SAAS;AAC/B,YAAM,cAAc,SAAS;AAC7B,YAAM,WAAW,SAAS;AAE1B,UAAI,WAA4B;AAChC,UAAI,WAAsB;AAC1B,UAAI;AACJ,UAAI,eAAe;AACjB,cAAM,kBAAkB,cAAc,QAAQ,sBAAsB;AACpE,+BAAuB;AAAA,UACrB;AAAA,UACA,2BAA2B,kBAAkB,uBAAuB;AAAA,QACtE;AAEA,iCAAyB;AACzB,gBAAQ,CAAC,SAAS,WAAW,GAAG,GAAG,iBAAiB,oBAAoB;AAAA,MAC1E,OAAO;AACL,gBAAQ,CAAC,SAAS,WAAW,GAAG,CAAC;AAAA,MACnC;AAEA,YAAM,UAAU,CAAC,CAAC;AAElB,UAAI,aAAa;AACf,cAAM,UAAU;AAChB,cAAM,WAAW;AACjB,+BAAuB,cAAc,QAAQ,oBAAoB;AACjE,cAAM,aAAa,YAAY;AAC/B,uBAAe,cAAc,QAAQ,aAAa,eAAe,CAAC;AAClE,yBAAiB;AAAA,UACf;AAAA,UACA,cAAc,aAAa,eAAe,iBAAiB;AAAA,QAC7D;AAEA,mBAAW,CAAC,sBAAsB,cAAc,cAAc;AAAA,MAChE;AACA,YAAM,WAAW;AAEjB,UAAI,WAAW,QAAQ,IAAI,GAAG;AAC5B,mBAAW,CAAC;AACZ,WAAG;AACD,wBAAc;AACd,0BAAgB;AAChB,gBAAM,mBAAmB,cAAc,QAAQ,CAAC;AAChD,cAAI;AACJ,cAAI,mBAAmB,IAAI;AACzB,+BAAmB,CAAC,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC;AAC9C,qBAAS,IAAI,IAAI,IAAI,kBAAkB,KAAK;AAC1C,oBAAM,SAAS;AACf,4BAAc,cAAc,QAAQ,WAAW;AAC/C,8BAAgB,cAAc,QAAQ,gBAAgB,SAAS,gBAAgB,CAAC;AAChF,oBAAM,aAAa,cAAc,QAAQ,CAAC;AAC1C,+BAAiB,KAAK,CAAC,YAAY,aAAa,aAAa,CAAC;AAAA,YAChE;AAAA,UACF,OAAO;AACL,+BAAmB,CAAC,CAAC,gBAAgB,CAAC;AAAA,UACxC;AACA,mBAAS,KAAK,gBAAgB;AAAA,QAChC,SAAS,WAAW,QAAQ,IAAI;AAAA,MAClC;AACA,YAAM,WAAW;AAEjB,aAAO,KAAK,KAAK;AACjB,YAAM,KAAK,KAAK;AAAA,IAClB;AAEA;AACA,WAAO,MAAM,OAAO;AAAA,EACtB,SAAS,OAAO,MAAM;AAEtB,SAAO;AACT;AAEO,SAAS,sBAAsB,QAAkC;AACtE,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAM,SAAS,IAAI,aAAa;AAEhC,WAAS,IAAI,GAAG,IAAI,OAAO,UAAU;AACnC,QAAI,uBAAuB,QAAQ,GAAG,QAAQ,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;AAAA,EACrE;AAEA,SAAO,OAAO,MAAM;AACtB;AAEA,SAAS,uBACP,QACA,OACA,QACA,OASQ;AACR,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM;AAAA,IACJ,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,MAAM,CAAC,IAAI,WAAW;AACxB,gBAAY,QAAQ,MAAM,CAAC,GAAG,SAAS;AACvC,UAAM,CAAC,IAAI;AACX,UAAM,CAAC,IAAI;AAAA,EACb,WAAW,QAAQ,GAAG;AACpB,WAAO,MAAM,KAAK;AAAA,EACpB;AAEA,QAAM,CAAC,IAAI,cAAc,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAEnD,QAAM,UACH,MAAM,WAAW,IAAI,IAAS,MAAM,WAAW,IAAS,MAAM,UAAU,IAAS;AACpF,gBAAc,QAAQ,QAAQ,CAAC;AAE/B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,EAAE,GAAG,cAAc,GAAG,YAAY,IAAI;AAC5C,QAAI,iBAAiB,MAAM,CAAC,GAAG;AAC7B,YAAM,CAAC,IAAI;AAAA,IACb;AACA,UAAM,CAAC,IAAI,cAAc,QAAQ,cAAc,MAAM,CAAC,CAAC;AACvD,UAAM,CAAC,IAAI,cAAc,QAAQ,aAAa,MAAM,CAAC,CAAC;AAAA,EACxD;AAEA,MAAI,UAAU;AACZ,UAAM,EAAE,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,IAAI,MAAM;AAC9D,QAAI,iBAAiB,MAAM,CAAC,GAAG;AAC7B,YAAM,CAAC,IAAI;AACX,YAAM,CAAC,IAAI;AAAA,IACb,WAAW,aAAa,MAAM,CAAC,GAAG;AAChC,YAAM,CAAC,IAAI;AAAA,IACb;AACA,UAAM,CAAC,IAAI,cAAc,QAAQ,cAAc,MAAM,CAAC,CAAC;AACvD,UAAM,CAAC,IAAI,cAAc,QAAQ,UAAU,MAAM,CAAC,CAAC;AACnD,UAAM,CAAC,IAAI,cAAc,QAAQ,YAAY,MAAM,CAAC,CAAC;AAAA,EACvD;AAEA,MAAI,UAAU;AACZ,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,SAAS,EAAG,eAAc,QAAQ,CAAC,QAAQ,QAAQ,CAAC;AAChE,YAAM,aAAa,QAAQ,CAAC,EAAE,CAAC;AAC/B,oBAAc,QAAQ,YAAY,CAAC;AACnC,UAAI,mBAAmB;AACvB,UAAI,qBAAqB;AACzB,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,cAAM,WAAW,QAAQ,CAAC;AAC1B,2BAAmB,cAAc,QAAQ,SAAS,CAAC,GAAI,gBAAgB;AACvE,6BAAqB,cAAc,QAAQ,SAAS,CAAC,GAAI,kBAAkB;AAC3E,sBAAc,QAAQ,SAAS,CAAC,GAAI,CAAC;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,OAAK,SAAS,QAAQ,OAAO,UAAU;AACrC,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AACvB,QAAI,IAAI,WAAY,MAAM,WAAW,KAAK,WAAY;AACpD;AAAA,IACF;AACA,YAAQ,uBAAuB,QAAQ,OAAO,QAAQ,KAAK;AAAA,EAC7D;AAEA,MAAI,MAAM,CAAC,IAAI,SAAS;AACtB,gBAAY,QAAQ,MAAM,CAAC,GAAG,OAAO;AACrC,UAAM,CAAC,IAAI;AACX,UAAM,CAAC,IAAI;AAAA,EACb,OAAO;AACL,WAAO,MAAM,KAAK;AAAA,EACpB;AACA,QAAM,CAAC,IAAI,cAAc,QAAQ,WAAW,MAAM,CAAC,CAAC;AAEpD,SAAO;AACT;AAEA,SAAS,YAAY,QAAsB,UAAkB,MAAc;AACzE,KAAG;AACD,WAAO,MAAM,SAAS;AAAA,EACxB,SAAS,EAAE,WAAW;AACxB;;;AHtUO,SAAS,OAAO,UAAqC;AAC1D,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,SAAS,IAAI,aAAa,QAAQ;AACxC,QAAM,UAA6B,CAAC;AACpC,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,MAAI,aAAa;AAEjB,KAAG;AACD,UAAM,OAAO,OAAO,QAAQ,GAAG;AAC/B,UAAM,OAAsB,CAAC;AAC7B,QAAI,SAAS;AACb,QAAI,UAAU;AACd,gBAAY;AAEZ,WAAO,OAAO,MAAM,MAAM;AACxB,UAAI;AAEJ,kBAAY,cAAc,QAAQ,SAAS;AAC3C,UAAI,YAAY,QAAS,UAAS;AAClC,gBAAU;AAEV,UAAI,WAAW,QAAQ,IAAI,GAAG;AAC5B,uBAAe,cAAc,QAAQ,YAAY;AACjD,qBAAa,cAAc,QAAQ,UAAU;AAC7C,uBAAe,cAAc,QAAQ,YAAY;AAEjD,YAAI,WAAW,QAAQ,IAAI,GAAG;AAC5B,uBAAa,cAAc,QAAQ,UAAU;AAC7C,gBAAM,CAAC,WAAW,cAAc,YAAY,cAAc,UAAU;AAAA,QACtE,OAAO;AACL,gBAAM,CAAC,WAAW,cAAc,YAAY,YAAY;AAAA,QAC1D;AAAA,MACF,OAAO;AACL,cAAM,CAAC,SAAS;AAAA,MAClB;AAEA,WAAK,KAAK,GAAG;AACb,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,OAAQ,MAAK,IAAI;AACtB,YAAQ,KAAK,IAAI;AACjB,WAAO,MAAM,OAAO;AAAA,EACtB,SAAS,OAAO,OAAO;AAEvB,SAAO;AACT;AAEA,SAAS,KAAK,MAA0B;AACtC,OAAK,KAAK,cAAc;AAC1B;AAEA,SAAS,eAAe,GAAqB,GAA6B;AACxE,SAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AACnB;AAIO,SAAS,OAAO,SAA8C;AACnE,QAAM,SAAS,IAAI,aAAa;AAChC,MAAI,eAAe;AACnB,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,MAAI,aAAa;AAEjB,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,CAAC;AACtB,QAAI,IAAI,EAAG,QAAO,MAAM,SAAS;AACjC,QAAI,KAAK,WAAW,EAAG;AAEvB,QAAI,YAAY;AAEhB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,UAAU,KAAK,CAAC;AACtB,UAAI,IAAI,EAAG,QAAO,MAAM,KAAK;AAE7B,kBAAY,cAAc,QAAQ,QAAQ,CAAC,GAAG,SAAS;AAEvD,UAAI,QAAQ,WAAW,EAAG;AAC1B,qBAAe,cAAc,QAAQ,QAAQ,CAAC,GAAG,YAAY;AAC7D,mBAAa,cAAc,QAAQ,QAAQ,CAAC,GAAG,UAAU;AACzD,qBAAe,cAAc,QAAQ,QAAQ,CAAC,GAAG,YAAY;AAE7D,UAAI,QAAQ,WAAW,EAAG;AAC1B,mBAAa,cAAc,QAAQ,QAAQ,CAAC,GAAG,UAAU;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO,OAAO,MAAM;AACtB;",
5 "names": []
6}
node_modules/@jridgewell/sourcemap-codec/package.json +63 -0
……@@ -0,0 +1,63 @@
1{
2 "name": "@jridgewell/sourcemap-codec",
3 "version": "1.5.5",
4 "description": "Encode/decode sourcemap mappings",
5 "keywords": [
6 "sourcemap",
7 "vlq"
8 ],
9 "main": "dist/sourcemap-codec.umd.js",
10 "module": "dist/sourcemap-codec.mjs",
11 "types": "types/sourcemap-codec.d.cts",
12 "files": [
13 "dist",
14 "src",
15 "types"
16 ],
17 "exports": {
18 ".": [
19 {
20 "import": {
21 "types": "./types/sourcemap-codec.d.mts",
22 "default": "./dist/sourcemap-codec.mjs"
23 },
24 "default": {
25 "types": "./types/sourcemap-codec.d.cts",
26 "default": "./dist/sourcemap-codec.umd.js"
27 }
28 },
29 "./dist/sourcemap-codec.umd.js"
30 ],
31 "./package.json": "./package.json"
32 },
33 "scripts": {
34 "benchmark": "run-s build:code benchmark:*",
35 "benchmark:install": "cd benchmark && npm install",
36 "benchmark:only": "node --expose-gc benchmark/index.js",
37 "build": "run-s -n build:code build:types",
38 "build:code": "node ../../esbuild.mjs sourcemap-codec.ts",
39 "build:types": "run-s build:types:force build:types:emit build:types:mts",
40 "build:types:force": "rimraf tsconfig.build.tsbuildinfo",
41 "build:types:emit": "tsc --project tsconfig.build.json",
42 "build:types:mts": "node ../../mts-types.mjs",
43 "clean": "run-s -n clean:code clean:types",
44 "clean:code": "tsc --build --clean tsconfig.build.json",
45 "clean:types": "rimraf dist types",
46 "test": "run-s -n test:types test:only test:format",
47 "test:format": "prettier --check '{src,test}/**/*.ts'",
48 "test:only": "mocha",
49 "test:types": "eslint '{src,test}/**/*.ts'",
50 "lint": "run-s -n lint:types lint:format",
51 "lint:format": "npm run test:format -- --write",
52 "lint:types": "npm run test:types -- --fix",
53 "prepublishOnly": "npm run-s -n build test"
54 },
55 "homepage": "https://github.com/jridgewell/sourcemaps/tree/main/packages/sourcemap-codec",
56 "repository": {
57 "type": "git",
58 "url": "git+https://github.com/jridgewell/sourcemaps.git",
59 "directory": "packages/sourcemap-codec"
60 },
61 "author": "Justin Ridgewell <justin@ridgewell.name>",
62 "license": "MIT"
63}
node_modules/@jridgewell/sourcemap-codec/src/scopes.ts +345 -0
……@@ -0,0 +1,345 @@
1import { StringReader, StringWriter } from './strings';
2import { comma, decodeInteger, encodeInteger, hasMoreVlq, semicolon } from './vlq';
3
4const EMPTY: any[] = [];
5
6type Line = number;
7type Column = number;
8type Kind = number;
9type Name = number;
10type Var = number;
11type SourcesIndex = number;
12type ScopesIndex = number;
13
14type Mix<A, B, O> = (A & O) | (B & O);
15
16export type OriginalScope = Mix<
17 [Line, Column, Line, Column, Kind],
18 [Line, Column, Line, Column, Kind, Name],
19 { vars: Var[] }
20>;
21
22export type GeneratedRange = Mix<
23 [Line, Column, Line, Column],
24 [Line, Column, Line, Column, SourcesIndex, ScopesIndex],
25 {
26 callsite: CallSite | null;
27 bindings: Binding[];
28 isScope: boolean;
29 }
30>;
31export type CallSite = [SourcesIndex, Line, Column];
32type Binding = BindingExpressionRange[];
33export type BindingExpressionRange = [Name] | [Name, Line, Column];
34
35export function decodeOriginalScopes(input: string): OriginalScope[] {
36 const { length } = input;
37 const reader = new StringReader(input);
38 const scopes: OriginalScope[] = [];
39 const stack: OriginalScope[] = [];
40 let line = 0;
41
42 for (; reader.pos < length; reader.pos++) {
43 line = decodeInteger(reader, line);
44 const column = decodeInteger(reader, 0);
45
46 if (!hasMoreVlq(reader, length)) {
47 const last = stack.pop()!;
48 last[2] = line;
49 last[3] = column;
50 continue;
51 }
52
53 const kind = decodeInteger(reader, 0);
54 const fields = decodeInteger(reader, 0);
55 const hasName = fields & 0b0001;
56
57 const scope: OriginalScope = (
58 hasName ? [line, column, 0, 0, kind, decodeInteger(reader, 0)] : [line, column, 0, 0, kind]
59 ) as OriginalScope;
60
61 let vars: Var[] = EMPTY;
62 if (hasMoreVlq(reader, length)) {
63 vars = [];
64 do {
65 const varsIndex = decodeInteger(reader, 0);
66 vars.push(varsIndex);
67 } while (hasMoreVlq(reader, length));
68 }
69 scope.vars = vars;
70
71 scopes.push(scope);
72 stack.push(scope);
73 }
74
75 return scopes;
76}
77
78export function encodeOriginalScopes(scopes: OriginalScope[]): string {
79 const writer = new StringWriter();
80
81 for (let i = 0; i < scopes.length; ) {
82 i = _encodeOriginalScopes(scopes, i, writer, [0]);
83 }
84
85 return writer.flush();
86}
87
88function _encodeOriginalScopes(
89 scopes: OriginalScope[],
90 index: number,
91 writer: StringWriter,
92 state: [
93 number, // GenColumn
94 ],
95): number {
96 const scope = scopes[index];
97 const { 0: startLine, 1: startColumn, 2: endLine, 3: endColumn, 4: kind, vars } = scope;
98
99 if (index > 0) writer.write(comma);
100
101 state[0] = encodeInteger(writer, startLine, state[0]);
102 encodeInteger(writer, startColumn, 0);
103 encodeInteger(writer, kind, 0);
104
105 const fields = scope.length === 6 ? 0b0001 : 0;
106 encodeInteger(writer, fields, 0);
107 if (scope.length === 6) encodeInteger(writer, scope[5], 0);
108
109 for (const v of vars) {
110 encodeInteger(writer, v, 0);
111 }
112
113 for (index++; index < scopes.length; ) {
114 const next = scopes[index];
115 const { 0: l, 1: c } = next;
116 if (l > endLine || (l === endLine && c >= endColumn)) {
117 break;
118 }
119 index = _encodeOriginalScopes(scopes, index, writer, state);
120 }
121
122 writer.write(comma);
123 state[0] = encodeInteger(writer, endLine, state[0]);
124 encodeInteger(writer, endColumn, 0);
125
126 return index;
127}
128
129export function decodeGeneratedRanges(input: string): GeneratedRange[] {
130 const { length } = input;
131 const reader = new StringReader(input);
132 const ranges: GeneratedRange[] = [];
133 const stack: GeneratedRange[] = [];
134
135 let genLine = 0;
136 let definitionSourcesIndex = 0;
137 let definitionScopeIndex = 0;
138 let callsiteSourcesIndex = 0;
139 let callsiteLine = 0;
140 let callsiteColumn = 0;
141 let bindingLine = 0;
142 let bindingColumn = 0;
143
144 do {
145 const semi = reader.indexOf(';');
146 let genColumn = 0;
147
148 for (; reader.pos < semi; reader.pos++) {
149 genColumn = decodeInteger(reader, genColumn);
150
151 if (!hasMoreVlq(reader, semi)) {
152 const last = stack.pop()!;
153 last[2] = genLine;
154 last[3] = genColumn;
155 continue;
156 }
157
158 const fields = decodeInteger(reader, 0);
159 const hasDefinition = fields & 0b0001;
160 const hasCallsite = fields & 0b0010;
161 const hasScope = fields & 0b0100;
162
163 let callsite: CallSite | null = null;
164 let bindings: Binding[] = EMPTY;
165 let range: GeneratedRange;
166 if (hasDefinition) {
167 const defSourcesIndex = decodeInteger(reader, definitionSourcesIndex);
168 definitionScopeIndex = decodeInteger(
169 reader,
170 definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0,
171 );
172
173 definitionSourcesIndex = defSourcesIndex;
174 range = [genLine, genColumn, 0, 0, defSourcesIndex, definitionScopeIndex] as GeneratedRange;
175 } else {
176 range = [genLine, genColumn, 0, 0] as GeneratedRange;
177 }
178
179 range.isScope = !!hasScope;
180
181 if (hasCallsite) {
182 const prevCsi = callsiteSourcesIndex;
183 const prevLine = callsiteLine;
184 callsiteSourcesIndex = decodeInteger(reader, callsiteSourcesIndex);
185 const sameSource = prevCsi === callsiteSourcesIndex;
186 callsiteLine = decodeInteger(reader, sameSource ? callsiteLine : 0);
187 callsiteColumn = decodeInteger(
188 reader,
189 sameSource && prevLine === callsiteLine ? callsiteColumn : 0,
190 );
191
192 callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];
193 }
194 range.callsite = callsite;
195
196 if (hasMoreVlq(reader, semi)) {
197 bindings = [];
198 do {
199 bindingLine = genLine;
200 bindingColumn = genColumn;
201 const expressionsCount = decodeInteger(reader, 0);
202 let expressionRanges: BindingExpressionRange[];
203 if (expressionsCount < -1) {
204 expressionRanges = [[decodeInteger(reader, 0)]];
205 for (let i = -1; i > expressionsCount; i--) {
206 const prevBl = bindingLine;
207 bindingLine = decodeInteger(reader, bindingLine);
208 bindingColumn = decodeInteger(reader, bindingLine === prevBl ? bindingColumn : 0);
209 const expression = decodeInteger(reader, 0);
210 expressionRanges.push([expression, bindingLine, bindingColumn]);
211 }
212 } else {
213 expressionRanges = [[expressionsCount]];
214 }
215 bindings.push(expressionRanges);
216 } while (hasMoreVlq(reader, semi));
217 }
218 range.bindings = bindings;
219
220 ranges.push(range);
221 stack.push(range);
222 }
223
224 genLine++;
225 reader.pos = semi + 1;
226 } while (reader.pos < length);
227
228 return ranges;
229}
230
231export function encodeGeneratedRanges(ranges: GeneratedRange[]): string {
232 if (ranges.length === 0) return '';
233
234 const writer = new StringWriter();
235
236 for (let i = 0; i < ranges.length; ) {
237 i = _encodeGeneratedRanges(ranges, i, writer, [0, 0, 0, 0, 0, 0, 0]);
238 }
239
240 return writer.flush();
241}
242
243function _encodeGeneratedRanges(
244 ranges: GeneratedRange[],
245 index: number,
246 writer: StringWriter,
247 state: [
248 number, // GenLine
249 number, // GenColumn
250 number, // DefSourcesIndex
251 number, // DefScopesIndex
252 number, // CallSourcesIndex
253 number, // CallLine
254 number, // CallColumn
255 ],
256): number {
257 const range = ranges[index];
258 const {
259 0: startLine,
260 1: startColumn,
261 2: endLine,
262 3: endColumn,
263 isScope,
264 callsite,
265 bindings,
266 } = range;
267
268 if (state[0] < startLine) {
269 catchupLine(writer, state[0], startLine);
270 state[0] = startLine;
271 state[1] = 0;
272 } else if (index > 0) {
273 writer.write(comma);
274 }
275
276 state[1] = encodeInteger(writer, range[1], state[1]);
277
278 const fields =
279 (range.length === 6 ? 0b0001 : 0) | (callsite ? 0b0010 : 0) | (isScope ? 0b0100 : 0);
280 encodeInteger(writer, fields, 0);
281
282 if (range.length === 6) {
283 const { 4: sourcesIndex, 5: scopesIndex } = range;
284 if (sourcesIndex !== state[2]) {
285 state[3] = 0;
286 }
287 state[2] = encodeInteger(writer, sourcesIndex, state[2]);
288 state[3] = encodeInteger(writer, scopesIndex, state[3]);
289 }
290
291 if (callsite) {
292 const { 0: sourcesIndex, 1: callLine, 2: callColumn } = range.callsite!;
293 if (sourcesIndex !== state[4]) {
294 state[5] = 0;
295 state[6] = 0;
296 } else if (callLine !== state[5]) {
297 state[6] = 0;
298 }
299 state[4] = encodeInteger(writer, sourcesIndex, state[4]);
300 state[5] = encodeInteger(writer, callLine, state[5]);
301 state[6] = encodeInteger(writer, callColumn, state[6]);
302 }
303
304 if (bindings) {
305 for (const binding of bindings) {
306 if (binding.length > 1) encodeInteger(writer, -binding.length, 0);
307 const expression = binding[0][0];
308 encodeInteger(writer, expression, 0);
309 let bindingStartLine = startLine;
310 let bindingStartColumn = startColumn;
311 for (let i = 1; i < binding.length; i++) {
312 const expRange = binding[i];
313 bindingStartLine = encodeInteger(writer, expRange[1]!, bindingStartLine);
314 bindingStartColumn = encodeInteger(writer, expRange[2]!, bindingStartColumn);
315 encodeInteger(writer, expRange[0]!, 0);
316 }
317 }
318 }
319
320 for (index++; index < ranges.length; ) {
321 const next = ranges[index];
322 const { 0: l, 1: c } = next;
323 if (l > endLine || (l === endLine && c >= endColumn)) {
324 break;
325 }
326 index = _encodeGeneratedRanges(ranges, index, writer, state);
327 }
328
329 if (state[0] < endLine) {
330 catchupLine(writer, state[0], endLine);
331 state[0] = endLine;
332 state[1] = 0;
333 } else {
334 writer.write(comma);
335 }
336 state[1] = encodeInteger(writer, endColumn, state[1]);
337
338 return index;
339}
340
341function catchupLine(writer: StringWriter, lastLine: number, line: number) {
342 do {
343 writer.write(semicolon);
344 } while (++lastLine < line);
345}
node_modules/@jridgewell/sourcemap-codec/src/sourcemap-codec.ts +111 -0
……@@ -0,0 +1,111 @@
1import { comma, decodeInteger, encodeInteger, hasMoreVlq, semicolon } from './vlq';
2import { StringWriter, StringReader } from './strings';
3
4export {
5 decodeOriginalScopes,
6 encodeOriginalScopes,
7 decodeGeneratedRanges,
8 encodeGeneratedRanges,
9} from './scopes';
10export type { OriginalScope, GeneratedRange, CallSite, BindingExpressionRange } from './scopes';
11
12export type SourceMapSegment =
13 | [number]
14 | [number, number, number, number]
15 | [number, number, number, number, number];
16export type SourceMapLine = SourceMapSegment[];
17export type SourceMapMappings = SourceMapLine[];
18
19export function decode(mappings: string): SourceMapMappings {
20 const { length } = mappings;
21 const reader = new StringReader(mappings);
22 const decoded: SourceMapMappings = [];
23 let genColumn = 0;
24 let sourcesIndex = 0;
25 let sourceLine = 0;
26 let sourceColumn = 0;
27 let namesIndex = 0;
28
29 do {
30 const semi = reader.indexOf(';');
31 const line: SourceMapLine = [];
32 let sorted = true;
33 let lastCol = 0;
34 genColumn = 0;
35
36 while (reader.pos < semi) {
37 let seg: SourceMapSegment;
38
39 genColumn = decodeInteger(reader, genColumn);
40 if (genColumn < lastCol) sorted = false;
41 lastCol = genColumn;
42
43 if (hasMoreVlq(reader, semi)) {
44 sourcesIndex = decodeInteger(reader, sourcesIndex);
45 sourceLine = decodeInteger(reader, sourceLine);
46 sourceColumn = decodeInteger(reader, sourceColumn);
47
48 if (hasMoreVlq(reader, semi)) {
49 namesIndex = decodeInteger(reader, namesIndex);
50 seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];
51 } else {
52 seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];
53 }
54 } else {
55 seg = [genColumn];
56 }
57
58 line.push(seg);
59 reader.pos++;
60 }
61
62 if (!sorted) sort(line);
63 decoded.push(line);
64 reader.pos = semi + 1;
65 } while (reader.pos <= length);
66
67 return decoded;
68}
69
70function sort(line: SourceMapSegment[]) {
71 line.sort(sortComparator);
72}
73
74function sortComparator(a: SourceMapSegment, b: SourceMapSegment): number {
75 return a[0] - b[0];
76}
77
78export function encode(decoded: SourceMapMappings): string;
79export function encode(decoded: Readonly<SourceMapMappings>): string;
80export function encode(decoded: Readonly<SourceMapMappings>): string {
81 const writer = new StringWriter();
82 let sourcesIndex = 0;
83 let sourceLine = 0;
84 let sourceColumn = 0;
85 let namesIndex = 0;
86
87 for (let i = 0; i < decoded.length; i++) {
88 const line = decoded[i];
89 if (i > 0) writer.write(semicolon);
90 if (line.length === 0) continue;
91
92 let genColumn = 0;
93
94 for (let j = 0; j < line.length; j++) {
95 const segment = line[j];
96 if (j > 0) writer.write(comma);
97
98 genColumn = encodeInteger(writer, segment[0], genColumn);
99
100 if (segment.length === 1) continue;
101 sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
102 sourceLine = encodeInteger(writer, segment[2], sourceLine);
103 sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
104
105 if (segment.length === 4) continue;
106 namesIndex = encodeInteger(writer, segment[4], namesIndex);
107 }
108 }
109
110 return writer.flush();
111}
node_modules/@jridgewell/sourcemap-codec/src/strings.ts +65 -0
……@@ -0,0 +1,65 @@
1const bufLength = 1024 * 16;
2
3// Provide a fallback for older environments.
4const td =
5 typeof TextDecoder !== 'undefined'
6 ? /* #__PURE__ */ new TextDecoder()
7 : typeof Buffer !== 'undefined'
8 ? {
9 decode(buf: Uint8Array): string {
10 const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);
11 return out.toString();
12 },
13 }
14 : {
15 decode(buf: Uint8Array): string {
16 let out = '';
17 for (let i = 0; i < buf.length; i++) {
18 out += String.fromCharCode(buf[i]);
19 }
20 return out;
21 },
22 };
23
24export class StringWriter {
25 pos = 0;
26 private out = '';
27 private buffer = new Uint8Array(bufLength);
28
29 write(v: number): void {
30 const { buffer } = this;
31 buffer[this.pos++] = v;
32 if (this.pos === bufLength) {
33 this.out += td.decode(buffer);
34 this.pos = 0;
35 }
36 }
37
38 flush(): string {
39 const { buffer, out, pos } = this;
40 return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
41 }
42}
43
44export class StringReader {
45 pos = 0;
46 declare private buffer: string;
47
48 constructor(buffer: string) {
49 this.buffer = buffer;
50 }
51
52 next(): number {
53 return this.buffer.charCodeAt(this.pos++);
54 }
55
56 peek(): number {
57 return this.buffer.charCodeAt(this.pos);
58 }
59
60 indexOf(char: string): number {
61 const { buffer, pos } = this;
62 const idx = buffer.indexOf(char, pos);
63 return idx === -1 ? buffer.length : idx;
64 }
65}
node_modules/@jridgewell/sourcemap-codec/src/vlq.ts +55 -0
……@@ -0,0 +1,55 @@
1import type { StringReader, StringWriter } from './strings';
2
3export const comma = ','.charCodeAt(0);
4export const semicolon = ';'.charCodeAt(0);
5
6const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
7const intToChar = new Uint8Array(64); // 64 possible chars.
8const charToInt = new Uint8Array(128); // z is 122 in ASCII
9
10for (let i = 0; i < chars.length; i++) {
11 const c = chars.charCodeAt(i);
12 intToChar[i] = c;
13 charToInt[c] = i;
14}
15
16export function decodeInteger(reader: StringReader, relative: number): number {
17 let value = 0;
18 let shift = 0;
19 let integer = 0;
20
21 do {
22 const c = reader.next();
23 integer = charToInt[c];
24 value |= (integer & 31) << shift;
25 shift += 5;
26 } while (integer & 32);
27
28 const shouldNegate = value & 1;
29 value >>>= 1;
30
31 if (shouldNegate) {
32 value = -0x80000000 | -value;
33 }
34
35 return relative + value;
36}
37
38export function encodeInteger(builder: StringWriter, num: number, relative: number): number {
39 let delta = num - relative;
40
41 delta = delta < 0 ? (-delta << 1) | 1 : delta << 1;
42 do {
43 let clamped = delta & 0b011111;
44 delta >>>= 5;
45 if (delta > 0) clamped |= 0b100000;
46 builder.write(intToChar[clamped]);
47 } while (delta > 0);
48
49 return num;
50}
51
52export function hasMoreVlq(reader: StringReader, max: number) {
53 if (reader.pos >= max) return false;
54 return reader.peek() !== comma;
55}
node_modules/@jridgewell/sourcemap-codec/types/scopes.d.cts +50 -0
……@@ -0,0 +1,50 @@
1type Line = number;
2type Column = number;
3type Kind = number;
4type Name = number;
5type Var = number;
6type SourcesIndex = number;
7type ScopesIndex = number;
8type Mix<A, B, O> = (A & O) | (B & O);
9export type OriginalScope = Mix<[
10 Line,
11 Column,
12 Line,
13 Column,
14 Kind
15], [
16 Line,
17 Column,
18 Line,
19 Column,
20 Kind,
21 Name
22], {
23 vars: Var[];
24}>;
25export type GeneratedRange = Mix<[
26 Line,
27 Column,
28 Line,
29 Column
30], [
31 Line,
32 Column,
33 Line,
34 Column,
35 SourcesIndex,
36 ScopesIndex
37], {
38 callsite: CallSite | null;
39 bindings: Binding[];
40 isScope: boolean;
41}>;
42export type CallSite = [SourcesIndex, Line, Column];
43type Binding = BindingExpressionRange[];
44export type BindingExpressionRange = [Name] | [Name, Line, Column];
45export declare function decodeOriginalScopes(input: string): OriginalScope[];
46export declare function encodeOriginalScopes(scopes: OriginalScope[]): string;
47export declare function decodeGeneratedRanges(input: string): GeneratedRange[];
48export declare function encodeGeneratedRanges(ranges: GeneratedRange[]): string;
49export {};
50//# sourceMappingURL=scopes.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/scopes.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAKA,KAAK,IAAI,GAAG,MAAM,CAAC;AACnB,KAAK,MAAM,GAAG,MAAM,CAAC;AACrB,KAAK,IAAI,GAAG,MAAM,CAAC;AACnB,KAAK,IAAI,GAAG,MAAM,CAAC;AACnB,KAAK,GAAG,GAAG,MAAM,CAAC;AAClB,KAAK,YAAY,GAAG,MAAM,CAAC;AAC3B,KAAK,WAAW,GAAG,MAAM,CAAC;AAE1B,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG,GAAG,CAC7B;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;IAAE,IAAI;CAAC,EAClC;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,IAAI;CAAC,EACxC;IAAE,IAAI,EAAE,GAAG,EAAE,CAAA;CAAE,CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,GAAG,CAC9B;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;CAAC,EAC5B;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;IAAE,YAAY;IAAE,WAAW;CAAC,EACvD;IACE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB,CACF,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACpD,KAAK,OAAO,GAAG,sBAAsB,EAAE,CAAC;AACxC,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAEnE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,CAyCnE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAQpE;AA2CD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,EAAE,CAoGrE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAUtE"}
node_modules/@jridgewell/sourcemap-codec/types/scopes.d.mts +50 -0
……@@ -0,0 +1,50 @@
1type Line = number;
2type Column = number;
3type Kind = number;
4type Name = number;
5type Var = number;
6type SourcesIndex = number;
7type ScopesIndex = number;
8type Mix<A, B, O> = (A & O) | (B & O);
9export type OriginalScope = Mix<[
10 Line,
11 Column,
12 Line,
13 Column,
14 Kind
15], [
16 Line,
17 Column,
18 Line,
19 Column,
20 Kind,
21 Name
22], {
23 vars: Var[];
24}>;
25export type GeneratedRange = Mix<[
26 Line,
27 Column,
28 Line,
29 Column
30], [
31 Line,
32 Column,
33 Line,
34 Column,
35 SourcesIndex,
36 ScopesIndex
37], {
38 callsite: CallSite | null;
39 bindings: Binding[];
40 isScope: boolean;
41}>;
42export type CallSite = [SourcesIndex, Line, Column];
43type Binding = BindingExpressionRange[];
44export type BindingExpressionRange = [Name] | [Name, Line, Column];
45export declare function decodeOriginalScopes(input: string): OriginalScope[];
46export declare function encodeOriginalScopes(scopes: OriginalScope[]): string;
47export declare function decodeGeneratedRanges(input: string): GeneratedRange[];
48export declare function encodeGeneratedRanges(ranges: GeneratedRange[]): string;
49export {};
50//# sourceMappingURL=scopes.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/scopes.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAKA,KAAK,IAAI,GAAG,MAAM,CAAC;AACnB,KAAK,MAAM,GAAG,MAAM,CAAC;AACrB,KAAK,IAAI,GAAG,MAAM,CAAC;AACnB,KAAK,IAAI,GAAG,MAAM,CAAC;AACnB,KAAK,GAAG,GAAG,MAAM,CAAC;AAClB,KAAK,YAAY,GAAG,MAAM,CAAC;AAC3B,KAAK,WAAW,GAAG,MAAM,CAAC;AAE1B,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG,GAAG,CAC7B;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;IAAE,IAAI;CAAC,EAClC;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,IAAI;CAAC,EACxC;IAAE,IAAI,EAAE,GAAG,EAAE,CAAA;CAAE,CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,GAAG,CAC9B;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;CAAC,EAC5B;IAAC,IAAI;IAAE,MAAM;IAAE,IAAI;IAAE,MAAM;IAAE,YAAY;IAAE,WAAW;CAAC,EACvD;IACE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB,CACF,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACpD,KAAK,OAAO,GAAG,sBAAsB,EAAE,CAAC;AACxC,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAEnE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,CAyCnE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAQpE;AA2CD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,EAAE,CAoGrE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAUtE"}
node_modules/@jridgewell/sourcemap-codec/types/sourcemap-codec.d.cts +9 -0
……@@ -0,0 +1,9 @@
1export { decodeOriginalScopes, encodeOriginalScopes, decodeGeneratedRanges, encodeGeneratedRanges, } from './scopes.cts';
2export type { OriginalScope, GeneratedRange, CallSite, BindingExpressionRange } from './scopes.cts';
3export type SourceMapSegment = [number] | [number, number, number, number] | [number, number, number, number, number];
4export type SourceMapLine = SourceMapSegment[];
5export type SourceMapMappings = SourceMapLine[];
6export declare function decode(mappings: string): SourceMapMappings;
7export declare function encode(decoded: SourceMapMappings): string;
8export declare function encode(decoded: Readonly<SourceMapMappings>): string;
9//# sourceMappingURL=sourcemap-codec.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/sourcemap-codec.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"sourcemap-codec.d.ts","sourceRoot":"","sources":["../src/sourcemap-codec.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAEhG,MAAM,MAAM,gBAAgB,GACxB,CAAC,MAAM,CAAC,GACR,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAChC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC7C,MAAM,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,aAAa,EAAE,CAAC;AAEhD,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAiD1D;AAUD,wBAAgB,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAAC;AAC3D,wBAAgB,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,MAAM,CAAC"}
node_modules/@jridgewell/sourcemap-codec/types/sourcemap-codec.d.mts +9 -0
……@@ -0,0 +1,9 @@
1export { decodeOriginalScopes, encodeOriginalScopes, decodeGeneratedRanges, encodeGeneratedRanges, } from './scopes.mts';
2export type { OriginalScope, GeneratedRange, CallSite, BindingExpressionRange } from './scopes.mts';
3export type SourceMapSegment = [number] | [number, number, number, number] | [number, number, number, number, number];
4export type SourceMapLine = SourceMapSegment[];
5export type SourceMapMappings = SourceMapLine[];
6export declare function decode(mappings: string): SourceMapMappings;
7export declare function encode(decoded: SourceMapMappings): string;
8export declare function encode(decoded: Readonly<SourceMapMappings>): string;
9//# sourceMappingURL=sourcemap-codec.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/sourcemap-codec.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"sourcemap-codec.d.ts","sourceRoot":"","sources":["../src/sourcemap-codec.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAEhG,MAAM,MAAM,gBAAgB,GACxB,CAAC,MAAM,CAAC,GACR,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAChC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC7C,MAAM,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,aAAa,EAAE,CAAC;AAEhD,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAiD1D;AAUD,wBAAgB,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAAC;AAC3D,wBAAgB,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,MAAM,CAAC"}
node_modules/@jridgewell/sourcemap-codec/types/strings.d.cts +16 -0
……@@ -0,0 +1,16 @@
1export declare class StringWriter {
2 pos: number;
3 private out;
4 private buffer;
5 write(v: number): void;
6 flush(): string;
7}
8export declare class StringReader {
9 pos: number;
10 private buffer;
11 constructor(buffer: string);
12 next(): number;
13 peek(): number;
14 indexOf(char: string): number;
15}
16//# sourceMappingURL=strings.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/strings.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../src/strings.ts"],"names":[],"mappings":"AAuBA,qBAAa,YAAY;IACvB,GAAG,SAAK;IACR,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAA6B;IAE3C,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAStB,KAAK,IAAI,MAAM;CAIhB;AAED,qBAAa,YAAY;IACvB,GAAG,SAAK;IACR,QAAgB,MAAM,CAAS;gBAEnB,MAAM,EAAE,MAAM;IAI1B,IAAI,IAAI,MAAM;IAId,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAK9B"}
node_modules/@jridgewell/sourcemap-codec/types/strings.d.mts +16 -0
……@@ -0,0 +1,16 @@
1export declare class StringWriter {
2 pos: number;
3 private out;
4 private buffer;
5 write(v: number): void;
6 flush(): string;
7}
8export declare class StringReader {
9 pos: number;
10 private buffer;
11 constructor(buffer: string);
12 next(): number;
13 peek(): number;
14 indexOf(char: string): number;
15}
16//# sourceMappingURL=strings.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/strings.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../src/strings.ts"],"names":[],"mappings":"AAuBA,qBAAa,YAAY;IACvB,GAAG,SAAK;IACR,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAA6B;IAE3C,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAStB,KAAK,IAAI,MAAM;CAIhB;AAED,qBAAa,YAAY;IACvB,GAAG,SAAK;IACR,QAAgB,MAAM,CAAS;gBAEnB,MAAM,EAAE,MAAM;IAI1B,IAAI,IAAI,MAAM;IAId,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAK9B"}
node_modules/@jridgewell/sourcemap-codec/types/vlq.d.cts +7 -0
……@@ -0,0 +1,7 @@
1import type { StringReader, StringWriter } from './strings.cts';
2export declare const comma: number;
3export declare const semicolon: number;
4export declare function decodeInteger(reader: StringReader, relative: number): number;
5export declare function encodeInteger(builder: StringWriter, num: number, relative: number): number;
6export declare function hasMoreVlq(reader: StringReader, max: number): boolean;
7//# sourceMappingURL=vlq.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/vlq.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"vlq.d.ts","sourceRoot":"","sources":["../src/vlq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE5D,eAAO,MAAM,KAAK,QAAoB,CAAC;AACvC,eAAO,MAAM,SAAS,QAAoB,CAAC;AAY3C,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoB5E;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY1F;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,WAG3D"}
node_modules/@jridgewell/sourcemap-codec/types/vlq.d.mts +7 -0
……@@ -0,0 +1,7 @@
1import type { StringReader, StringWriter } from './strings.mts';
2export declare const comma: number;
3export declare const semicolon: number;
4export declare function decodeInteger(reader: StringReader, relative: number): number;
5export declare function encodeInteger(builder: StringWriter, num: number, relative: number): number;
6export declare function hasMoreVlq(reader: StringReader, max: number): boolean;
7//# sourceMappingURL=vlq.d.ts.map
node_modules/@jridgewell/sourcemap-codec/types/vlq.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"vlq.d.ts","sourceRoot":"","sources":["../src/vlq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE5D,eAAO,MAAM,KAAK,QAAoB,CAAC;AACvC,eAAO,MAAM,SAAS,QAAoB,CAAC;AAY3C,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoB5E;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY1F;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,WAG3D"}
node_modules/@jridgewell/trace-mapping/LICENSE +19 -0
……@@ -0,0 +1,19 @@
1Copyright 2024 Justin Ridgewell <justin@ridgewell.name>
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
node_modules/@jridgewell/trace-mapping/README.md +348 -0
……@@ -0,0 +1,348 @@
1# @jridgewell/trace-mapping
2
3> Trace the original position through a source map
4
5`trace-mapping` allows you to take the line and column of an output file and trace it to the
6original location in the source file through a source map.
7
8You may already be familiar with the [`source-map`][source-map] package's `SourceMapConsumer`. This
9provides the same `originalPositionFor` and `generatedPositionFor` API, without requiring WASM.
10
11## Installation
12
13```sh
14npm install @jridgewell/trace-mapping
15```
16
17## Usage
18
19```typescript
20import {
21 TraceMap,
22 originalPositionFor,
23 generatedPositionFor,
24 sourceContentFor,
25 isIgnored,
26} from '@jridgewell/trace-mapping';
27
28const tracer = new TraceMap({
29 version: 3,
30 sources: ['input.js'],
31 sourcesContent: ['content of input.js'],
32 names: ['foo'],
33 mappings: 'KAyCIA',
34 ignoreList: [],
35});
36
37// Lines start at line 1, columns at column 0.
38const traced = originalPositionFor(tracer, { line: 1, column: 5 });
39assert.deepEqual(traced, {
40 source: 'input.js',
41 line: 42,
42 column: 4,
43 name: 'foo',
44});
45
46const content = sourceContentFor(tracer, traced.source);
47assert.strictEqual(content, 'content for input.js');
48
49const generated = generatedPositionFor(tracer, {
50 source: 'input.js',
51 line: 42,
52 column: 4,
53});
54assert.deepEqual(generated, {
55 line: 1,
56 column: 5,
57});
58
59const ignored = isIgnored(tracer, 'input.js');
60assert.equal(ignored, false);
61```
62
63We also provide a lower level API to get the actual segment that matches our line and column. Unlike
64`originalPositionFor`, `traceSegment` uses a 0-base for `line`:
65
66```typescript
67import { traceSegment } from '@jridgewell/trace-mapping';
68
69// line is 0-base.
70const traced = traceSegment(tracer, /* line */ 0, /* column */ 5);
71
72// Segments are [outputColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex]
73// Again, line is 0-base and so is sourceLine
74assert.deepEqual(traced, [5, 0, 41, 4, 0]);
75```
76
77### SectionedSourceMaps
78
79The sourcemap spec defines a special `sections` field that's designed to handle concatenation of
80output code with associated sourcemaps. This type of sourcemap is rarely used (no major build tool
81produces it), but if you are hand coding a concatenation you may need it. We provide an `AnyMap`
82helper that can receive either a regular sourcemap or a `SectionedSourceMap` and returns a
83`TraceMap` instance:
84
85```typescript
86import { AnyMap } from '@jridgewell/trace-mapping';
87const fooOutput = 'foo';
88const barOutput = 'bar';
89const output = [fooOutput, barOutput].join('\n');
90
91const sectioned = new AnyMap({
92 version: 3,
93 sections: [
94 {
95 // 0-base line and column
96 offset: { line: 0, column: 0 },
97 // fooOutput's sourcemap
98 map: {
99 version: 3,
100 sources: ['foo.js'],
101 names: ['foo'],
102 mappings: 'AAAAA',
103 },
104 },
105 {
106 // barOutput's sourcemap will not affect the first line, only the second
107 offset: { line: 1, column: 0 },
108 map: {
109 version: 3,
110 sources: ['bar.js'],
111 names: ['bar'],
112 mappings: 'AAAAA',
113 },
114 },
115 ],
116});
117
118const traced = originalPositionFor(sectioned, {
119 line: 2,
120 column: 0,
121});
122
123assert.deepEqual(traced, {
124 source: 'bar.js',
125 line: 1,
126 column: 0,
127 name: 'bar',
128});
129```
130
131## Benchmarks
132
133```
134node v20.10.0
135
136amp.js.map - 45120 segments
137
138Memory Usage:
139trace-mapping decoded 414164 bytes
140trace-mapping encoded 6274352 bytes
141source-map-js 10968904 bytes
142source-map-0.6.1 17587160 bytes
143source-map-0.8.0 8812155 bytes
144Chrome dev tools 8672912 bytes
145Smallest memory usage is trace-mapping decoded
146
147Init speed:
148trace-mapping: decoded JSON input x 205 ops/sec ±0.19% (88 runs sampled)
149trace-mapping: encoded JSON input x 405 ops/sec ±1.47% (88 runs sampled)
150trace-mapping: decoded Object input x 4,645 ops/sec ±0.15% (98 runs sampled)
151trace-mapping: encoded Object input x 458 ops/sec ±1.63% (91 runs sampled)
152source-map-js: encoded Object input x 75.48 ops/sec ±1.64% (67 runs sampled)
153source-map-0.6.1: encoded Object input x 39.37 ops/sec ±1.44% (53 runs sampled)
154Chrome dev tools: encoded Object input x 150 ops/sec ±1.76% (79 runs sampled)
155Fastest is trace-mapping: decoded Object input
156
157Trace speed (random):
158trace-mapping: decoded originalPositionFor x 44,946 ops/sec ±0.16% (99 runs sampled)
159trace-mapping: encoded originalPositionFor x 37,995 ops/sec ±1.81% (89 runs sampled)
160source-map-js: encoded originalPositionFor x 9,230 ops/sec ±1.36% (93 runs sampled)
161source-map-0.6.1: encoded originalPositionFor x 8,057 ops/sec ±0.84% (96 runs sampled)
162source-map-0.8.0: encoded originalPositionFor x 28,198 ops/sec ±1.12% (91 runs sampled)
163Chrome dev tools: encoded originalPositionFor x 46,276 ops/sec ±1.35% (95 runs sampled)
164Fastest is Chrome dev tools: encoded originalPositionFor
165
166Trace speed (ascending):
167trace-mapping: decoded originalPositionFor x 204,406 ops/sec ±0.19% (97 runs sampled)
168trace-mapping: encoded originalPositionFor x 196,695 ops/sec ±0.24% (99 runs sampled)
169source-map-js: encoded originalPositionFor x 11,948 ops/sec ±0.94% (99 runs sampled)
170source-map-0.6.1: encoded originalPositionFor x 10,730 ops/sec ±0.36% (100 runs sampled)
171source-map-0.8.0: encoded originalPositionFor x 51,427 ops/sec ±0.21% (98 runs sampled)
172Chrome dev tools: encoded originalPositionFor x 162,615 ops/sec ±0.18% (98 runs sampled)
173Fastest is trace-mapping: decoded originalPositionFor
174
175
176***
177
178
179babel.min.js.map - 347793 segments
180
181Memory Usage:
182trace-mapping decoded 18504 bytes
183trace-mapping encoded 35428008 bytes
184source-map-js 51676808 bytes
185source-map-0.6.1 63367136 bytes
186source-map-0.8.0 43158400 bytes
187Chrome dev tools 50721552 bytes
188Smallest memory usage is trace-mapping decoded
189
190Init speed:
191trace-mapping: decoded JSON input x 17.82 ops/sec ±6.35% (35 runs sampled)
192trace-mapping: encoded JSON input x 31.57 ops/sec ±7.50% (43 runs sampled)
193trace-mapping: decoded Object input x 867 ops/sec ±0.74% (94 runs sampled)
194trace-mapping: encoded Object input x 33.83 ops/sec ±7.66% (46 runs sampled)
195source-map-js: encoded Object input x 6.58 ops/sec ±3.31% (20 runs sampled)
196source-map-0.6.1: encoded Object input x 4.23 ops/sec ±3.43% (15 runs sampled)
197Chrome dev tools: encoded Object input x 22.14 ops/sec ±3.79% (41 runs sampled)
198Fastest is trace-mapping: decoded Object input
199
200Trace speed (random):
201trace-mapping: decoded originalPositionFor x 78,234 ops/sec ±1.48% (29 runs sampled)
202trace-mapping: encoded originalPositionFor x 60,761 ops/sec ±1.35% (21 runs sampled)
203source-map-js: encoded originalPositionFor x 51,448 ops/sec ±2.17% (89 runs sampled)
204source-map-0.6.1: encoded originalPositionFor x 47,221 ops/sec ±1.99% (15 runs sampled)
205source-map-0.8.0: encoded originalPositionFor x 84,002 ops/sec ±1.45% (27 runs sampled)
206Chrome dev tools: encoded originalPositionFor x 106,457 ops/sec ±1.38% (37 runs sampled)
207Fastest is Chrome dev tools: encoded originalPositionFor
208
209Trace speed (ascending):
210trace-mapping: decoded originalPositionFor x 930,943 ops/sec ±0.25% (99 runs sampled)
211trace-mapping: encoded originalPositionFor x 843,545 ops/sec ±0.34% (97 runs sampled)
212source-map-js: encoded originalPositionFor x 114,510 ops/sec ±1.37% (36 runs sampled)
213source-map-0.6.1: encoded originalPositionFor x 87,412 ops/sec ±0.72% (92 runs sampled)
214source-map-0.8.0: encoded originalPositionFor x 197,709 ops/sec ±0.89% (59 runs sampled)
215Chrome dev tools: encoded originalPositionFor x 688,983 ops/sec ±0.33% (98 runs sampled)
216Fastest is trace-mapping: decoded originalPositionFor
217
218
219***
220
221
222preact.js.map - 1992 segments
223
224Memory Usage:
225trace-mapping decoded 33136 bytes
226trace-mapping encoded 254240 bytes
227source-map-js 837488 bytes
228source-map-0.6.1 961928 bytes
229source-map-0.8.0 54384 bytes
230Chrome dev tools 709680 bytes
231Smallest memory usage is trace-mapping decoded
232
233Init speed:
234trace-mapping: decoded JSON input x 3,709 ops/sec ±0.13% (99 runs sampled)
235trace-mapping: encoded JSON input x 6,447 ops/sec ±0.22% (101 runs sampled)
236trace-mapping: decoded Object input x 83,062 ops/sec ±0.23% (100 runs sampled)
237trace-mapping: encoded Object input x 14,980 ops/sec ±0.28% (100 runs sampled)
238source-map-js: encoded Object input x 2,544 ops/sec ±0.16% (99 runs sampled)
239source-map-0.6.1: encoded Object input x 1,221 ops/sec ±0.37% (97 runs sampled)
240Chrome dev tools: encoded Object input x 4,241 ops/sec ±0.39% (93 runs sampled)
241Fastest is trace-mapping: decoded Object input
242
243Trace speed (random):
244trace-mapping: decoded originalPositionFor x 91,028 ops/sec ±0.14% (94 runs sampled)
245trace-mapping: encoded originalPositionFor x 84,348 ops/sec ±0.26% (98 runs sampled)
246source-map-js: encoded originalPositionFor x 26,998 ops/sec ±0.23% (98 runs sampled)
247source-map-0.6.1: encoded originalPositionFor x 18,049 ops/sec ±0.26% (100 runs sampled)
248source-map-0.8.0: encoded originalPositionFor x 41,916 ops/sec ±0.28% (98 runs sampled)
249Chrome dev tools: encoded originalPositionFor x 88,616 ops/sec ±0.14% (98 runs sampled)
250Fastest is trace-mapping: decoded originalPositionFor
251
252Trace speed (ascending):
253trace-mapping: decoded originalPositionFor x 319,960 ops/sec ±0.16% (100 runs sampled)
254trace-mapping: encoded originalPositionFor x 302,153 ops/sec ±0.18% (100 runs sampled)
255source-map-js: encoded originalPositionFor x 35,574 ops/sec ±0.19% (100 runs sampled)
256source-map-0.6.1: encoded originalPositionFor x 19,943 ops/sec ±0.12% (101 runs sampled)
257source-map-0.8.0: encoded originalPositionFor x 54,648 ops/sec ±0.20% (99 runs sampled)
258Chrome dev tools: encoded originalPositionFor x 278,319 ops/sec ±0.17% (102 runs sampled)
259Fastest is trace-mapping: decoded originalPositionFor
260
261
262***
263
264
265react.js.map - 5726 segments
266
267Memory Usage:
268trace-mapping decoded 10872 bytes
269trace-mapping encoded 681512 bytes
270source-map-js 2563944 bytes
271source-map-0.6.1 2150864 bytes
272source-map-0.8.0 88680 bytes
273Chrome dev tools 1149576 bytes
274Smallest memory usage is trace-mapping decoded
275
276Init speed:
277trace-mapping: decoded JSON input x 1,887 ops/sec ±0.28% (99 runs sampled)
278trace-mapping: encoded JSON input x 4,749 ops/sec ±0.48% (97 runs sampled)
279trace-mapping: decoded Object input x 74,236 ops/sec ±0.11% (99 runs sampled)
280trace-mapping: encoded Object input x 5,752 ops/sec ±0.38% (100 runs sampled)
281source-map-js: encoded Object input x 806 ops/sec ±0.19% (97 runs sampled)
282source-map-0.6.1: encoded Object input x 418 ops/sec ±0.33% (94 runs sampled)
283Chrome dev tools: encoded Object input x 1,524 ops/sec ±0.57% (92 runs sampled)
284Fastest is trace-mapping: decoded Object input
285
286Trace speed (random):
287trace-mapping: decoded originalPositionFor x 620,201 ops/sec ±0.33% (96 runs sampled)
288trace-mapping: encoded originalPositionFor x 579,548 ops/sec ±0.35% (97 runs sampled)
289source-map-js: encoded originalPositionFor x 230,983 ops/sec ±0.62% (54 runs sampled)
290source-map-0.6.1: encoded originalPositionFor x 158,145 ops/sec ±0.80% (46 runs sampled)
291source-map-0.8.0: encoded originalPositionFor x 343,801 ops/sec ±0.55% (96 runs sampled)
292Chrome dev tools: encoded originalPositionFor x 659,649 ops/sec ±0.49% (98 runs sampled)
293Fastest is Chrome dev tools: encoded originalPositionFor
294
295Trace speed (ascending):
296trace-mapping: decoded originalPositionFor x 2,368,079 ops/sec ±0.32% (98 runs sampled)
297trace-mapping: encoded originalPositionFor x 2,134,039 ops/sec ±2.72% (87 runs sampled)
298source-map-js: encoded originalPositionFor x 290,120 ops/sec ±2.49% (82 runs sampled)
299source-map-0.6.1: encoded originalPositionFor x 187,613 ops/sec ±0.86% (49 runs sampled)
300source-map-0.8.0: encoded originalPositionFor x 479,569 ops/sec ±0.65% (96 runs sampled)
301Chrome dev tools: encoded originalPositionFor x 2,048,414 ops/sec ±0.24% (98 runs sampled)
302Fastest is trace-mapping: decoded originalPositionFor
303
304
305***
306
307
308vscode.map - 2141001 segments
309
310Memory Usage:
311trace-mapping decoded 5206584 bytes
312trace-mapping encoded 208370336 bytes
313source-map-js 278493008 bytes
314source-map-0.6.1 391564048 bytes
315source-map-0.8.0 257508787 bytes
316Chrome dev tools 291053000 bytes
317Smallest memory usage is trace-mapping decoded
318
319Init speed:
320trace-mapping: decoded JSON input x 1.63 ops/sec ±33.88% (9 runs sampled)
321trace-mapping: encoded JSON input x 3.29 ops/sec ±36.13% (13 runs sampled)
322trace-mapping: decoded Object input x 103 ops/sec ±0.93% (77 runs sampled)
323trace-mapping: encoded Object input x 5.42 ops/sec ±28.54% (19 runs sampled)
324source-map-js: encoded Object input x 1.07 ops/sec ±13.84% (7 runs sampled)
325source-map-0.6.1: encoded Object input x 0.60 ops/sec ±2.43% (6 runs sampled)
326Chrome dev tools: encoded Object input x 2.61 ops/sec ±22.00% (11 runs sampled)
327Fastest is trace-mapping: decoded Object input
328
329Trace speed (random):
330trace-mapping: decoded originalPositionFor x 257,019 ops/sec ±0.97% (93 runs sampled)
331trace-mapping: encoded originalPositionFor x 179,163 ops/sec ±0.83% (92 runs sampled)
332source-map-js: encoded originalPositionFor x 73,337 ops/sec ±1.35% (87 runs sampled)
333source-map-0.6.1: encoded originalPositionFor x 38,797 ops/sec ±1.66% (88 runs sampled)
334source-map-0.8.0: encoded originalPositionFor x 107,758 ops/sec ±1.94% (45 runs sampled)
335Chrome dev tools: encoded originalPositionFor x 188,550 ops/sec ±1.85% (79 runs sampled)
336Fastest is trace-mapping: decoded originalPositionFor
337
338Trace speed (ascending):
339trace-mapping: decoded originalPositionFor x 447,621 ops/sec ±3.64% (94 runs sampled)
340trace-mapping: encoded originalPositionFor x 323,698 ops/sec ±5.20% (88 runs sampled)
341source-map-js: encoded originalPositionFor x 78,387 ops/sec ±1.69% (89 runs sampled)
342source-map-0.6.1: encoded originalPositionFor x 41,016 ops/sec ±3.01% (25 runs sampled)
343source-map-0.8.0: encoded originalPositionFor x 124,204 ops/sec ±0.90% (92 runs sampled)
344Chrome dev tools: encoded originalPositionFor x 230,087 ops/sec ±2.61% (93 runs sampled)
345Fastest is trace-mapping: decoded originalPositionFor
346```
347
348[source-map]: https://www.npmjs.com/package/source-map
node_modules/@jridgewell/trace-mapping/dist/trace-mapping.mjs +493 -0
……@@ -0,0 +1,493 @@
1// src/trace-mapping.ts
2import { encode, decode } from "@jridgewell/sourcemap-codec";
3
4// src/resolve.ts
5import resolveUri from "@jridgewell/resolve-uri";
6
7// src/strip-filename.ts
8function stripFilename(path) {
9 if (!path) return "";
10 const index = path.lastIndexOf("/");
11 return path.slice(0, index + 1);
12}
13
14// src/resolve.ts
15function resolver(mapUrl, sourceRoot) {
16 const from = stripFilename(mapUrl);
17 const prefix = sourceRoot ? sourceRoot + "/" : "";
18 return (source) => resolveUri(prefix + (source || ""), from);
19}
20
21// src/sourcemap-segment.ts
22var COLUMN = 0;
23var SOURCES_INDEX = 1;
24var SOURCE_LINE = 2;
25var SOURCE_COLUMN = 3;
26var NAMES_INDEX = 4;
27var REV_GENERATED_LINE = 1;
28var REV_GENERATED_COLUMN = 2;
29
30// src/sort.ts
31function maybeSort(mappings, owned) {
32 const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
33 if (unsortedIndex === mappings.length) return mappings;
34 if (!owned) mappings = mappings.slice();
35 for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
36 mappings[i] = sortSegments(mappings[i], owned);
37 }
38 return mappings;
39}
40function nextUnsortedSegmentLine(mappings, start) {
41 for (let i = start; i < mappings.length; i++) {
42 if (!isSorted(mappings[i])) return i;
43 }
44 return mappings.length;
45}
46function isSorted(line) {
47 for (let j = 1; j < line.length; j++) {
48 if (line[j][COLUMN] < line[j - 1][COLUMN]) {
49 return false;
50 }
51 }
52 return true;
53}
54function sortSegments(line, owned) {
55 if (!owned) line = line.slice();
56 return line.sort(sortComparator);
57}
58function sortComparator(a, b) {
59 return a[COLUMN] - b[COLUMN];
60}
61
62// src/by-source.ts
63function buildBySources(decoded, memos) {
64 const sources = memos.map(() => []);
65 for (let i = 0; i < decoded.length; i++) {
66 const line = decoded[i];
67 for (let j = 0; j < line.length; j++) {
68 const seg = line[j];
69 if (seg.length === 1) continue;
70 const sourceIndex2 = seg[SOURCES_INDEX];
71 const sourceLine = seg[SOURCE_LINE];
72 const sourceColumn = seg[SOURCE_COLUMN];
73 const source = sources[sourceIndex2];
74 const segs = source[sourceLine] || (source[sourceLine] = []);
75 segs.push([sourceColumn, i, seg[COLUMN]]);
76 }
77 }
78 for (let i = 0; i < sources.length; i++) {
79 const source = sources[i];
80 for (let j = 0; j < source.length; j++) {
81 const line = source[j];
82 if (line) line.sort(sortComparator);
83 }
84 }
85 return sources;
86}
87
88// src/binary-search.ts
89var found = false;
90function binarySearch(haystack, needle, low, high) {
91 while (low <= high) {
92 const mid = low + (high - low >> 1);
93 const cmp = haystack[mid][COLUMN] - needle;
94 if (cmp === 0) {
95 found = true;
96 return mid;
97 }
98 if (cmp < 0) {
99 low = mid + 1;
100 } else {
101 high = mid - 1;
102 }
103 }
104 found = false;
105 return low - 1;
106}
107function upperBound(haystack, needle, index) {
108 for (let i = index + 1; i < haystack.length; index = i++) {
109 if (haystack[i][COLUMN] !== needle) break;
110 }
111 return index;
112}
113function lowerBound(haystack, needle, index) {
114 for (let i = index - 1; i >= 0; index = i--) {
115 if (haystack[i][COLUMN] !== needle) break;
116 }
117 return index;
118}
119function memoizedState() {
120 return {
121 lastKey: -1,
122 lastNeedle: -1,
123 lastIndex: -1
124 };
125}
126function memoizedBinarySearch(haystack, needle, state, key) {
127 const { lastKey, lastNeedle, lastIndex } = state;
128 let low = 0;
129 let high = haystack.length - 1;
130 if (key === lastKey) {
131 if (needle === lastNeedle) {
132 found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
133 return lastIndex;
134 }
135 if (needle >= lastNeedle) {
136 low = lastIndex === -1 ? 0 : lastIndex;
137 } else {
138 high = lastIndex;
139 }
140 }
141 state.lastKey = key;
142 state.lastNeedle = needle;
143 return state.lastIndex = binarySearch(haystack, needle, low, high);
144}
145
146// src/types.ts
147function parse(map) {
148 return typeof map === "string" ? JSON.parse(map) : map;
149}
150
151// src/flatten-map.ts
152var FlattenMap = function(map, mapUrl) {
153 const parsed = parse(map);
154 if (!("sections" in parsed)) {
155 return new TraceMap(parsed, mapUrl);
156 }
157 const mappings = [];
158 const sources = [];
159 const sourcesContent = [];
160 const names = [];
161 const ignoreList = [];
162 recurse(
163 parsed,
164 mapUrl,
165 mappings,
166 sources,
167 sourcesContent,
168 names,
169 ignoreList,
170 0,
171 0,
172 Infinity,
173 Infinity
174 );
175 const joined = {
176 version: 3,
177 file: parsed.file,
178 names,
179 sources,
180 sourcesContent,
181 mappings,
182 ignoreList
183 };
184 return presortedDecodedMap(joined);
185};
186function recurse(input, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
187 const { sections } = input;
188 for (let i = 0; i < sections.length; i++) {
189 const { map, offset } = sections[i];
190 let sl = stopLine;
191 let sc = stopColumn;
192 if (i + 1 < sections.length) {
193 const nextOffset = sections[i + 1].offset;
194 sl = Math.min(stopLine, lineOffset + nextOffset.line);
195 if (sl === stopLine) {
196 sc = Math.min(stopColumn, columnOffset + nextOffset.column);
197 } else if (sl < stopLine) {
198 sc = columnOffset + nextOffset.column;
199 }
200 }
201 addSection(
202 map,
203 mapUrl,
204 mappings,
205 sources,
206 sourcesContent,
207 names,
208 ignoreList,
209 lineOffset + offset.line,
210 columnOffset + offset.column,
211 sl,
212 sc
213 );
214 }
215}
216function addSection(input, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
217 const parsed = parse(input);
218 if ("sections" in parsed) return recurse(...arguments);
219 const map = new TraceMap(parsed, mapUrl);
220 const sourcesOffset = sources.length;
221 const namesOffset = names.length;
222 const decoded = decodedMappings(map);
223 const { resolvedSources, sourcesContent: contents, ignoreList: ignores } = map;
224 append(sources, resolvedSources);
225 append(names, map.names);
226 if (contents) append(sourcesContent, contents);
227 else for (let i = 0; i < resolvedSources.length; i++) sourcesContent.push(null);
228 if (ignores) for (let i = 0; i < ignores.length; i++) ignoreList.push(ignores[i] + sourcesOffset);
229 for (let i = 0; i < decoded.length; i++) {
230 const lineI = lineOffset + i;
231 if (lineI > stopLine) return;
232 const out = getLine(mappings, lineI);
233 const cOffset = i === 0 ? columnOffset : 0;
234 const line = decoded[i];
235 for (let j = 0; j < line.length; j++) {
236 const seg = line[j];
237 const column = cOffset + seg[COLUMN];
238 if (lineI === stopLine && column >= stopColumn) return;
239 if (seg.length === 1) {
240 out.push([column]);
241 continue;
242 }
243 const sourcesIndex = sourcesOffset + seg[SOURCES_INDEX];
244 const sourceLine = seg[SOURCE_LINE];
245 const sourceColumn = seg[SOURCE_COLUMN];
246 out.push(
247 seg.length === 4 ? [column, sourcesIndex, sourceLine, sourceColumn] : [column, sourcesIndex, sourceLine, sourceColumn, namesOffset + seg[NAMES_INDEX]]
248 );
249 }
250 }
251}
252function append(arr, other) {
253 for (let i = 0; i < other.length; i++) arr.push(other[i]);
254}
255function getLine(arr, index) {
256 for (let i = arr.length; i <= index; i++) arr[i] = [];
257 return arr[index];
258}
259
260// src/trace-mapping.ts
261var LINE_GTR_ZERO = "`line` must be greater than 0 (lines start at line 1)";
262var COL_GTR_EQ_ZERO = "`column` must be greater than or equal to 0 (columns start at column 0)";
263var LEAST_UPPER_BOUND = -1;
264var GREATEST_LOWER_BOUND = 1;
265var TraceMap = class {
266 constructor(map, mapUrl) {
267 const isString = typeof map === "string";
268 if (!isString && map._decodedMemo) return map;
269 const parsed = parse(map);
270 const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
271 this.version = version;
272 this.file = file;
273 this.names = names || [];
274 this.sourceRoot = sourceRoot;
275 this.sources = sources;
276 this.sourcesContent = sourcesContent;
277 this.ignoreList = parsed.ignoreList || parsed.x_google_ignoreList || void 0;
278 const resolve = resolver(mapUrl, sourceRoot);
279 this.resolvedSources = sources.map(resolve);
280 const { mappings } = parsed;
281 if (typeof mappings === "string") {
282 this._encoded = mappings;
283 this._decoded = void 0;
284 } else if (Array.isArray(mappings)) {
285 this._encoded = void 0;
286 this._decoded = maybeSort(mappings, isString);
287 } else if (parsed.sections) {
288 throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`);
289 } else {
290 throw new Error(`invalid source map: ${JSON.stringify(parsed)}`);
291 }
292 this._decodedMemo = memoizedState();
293 this._bySources = void 0;
294 this._bySourceMemos = void 0;
295 }
296};
297function cast(map) {
298 return map;
299}
300function encodedMappings(map) {
301 var _a, _b;
302 return (_b = (_a = cast(map))._encoded) != null ? _b : _a._encoded = encode(cast(map)._decoded);
303}
304function decodedMappings(map) {
305 var _a;
306 return (_a = cast(map))._decoded || (_a._decoded = decode(cast(map)._encoded));
307}
308function traceSegment(map, line, column) {
309 const decoded = decodedMappings(map);
310 if (line >= decoded.length) return null;
311 const segments = decoded[line];
312 const index = traceSegmentInternal(
313 segments,
314 cast(map)._decodedMemo,
315 line,
316 column,
317 GREATEST_LOWER_BOUND
318 );
319 return index === -1 ? null : segments[index];
320}
321function originalPositionFor(map, needle) {
322 let { line, column, bias } = needle;
323 line--;
324 if (line < 0) throw new Error(LINE_GTR_ZERO);
325 if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
326 const decoded = decodedMappings(map);
327 if (line >= decoded.length) return OMapping(null, null, null, null);
328 const segments = decoded[line];
329 const index = traceSegmentInternal(
330 segments,
331 cast(map)._decodedMemo,
332 line,
333 column,
334 bias || GREATEST_LOWER_BOUND
335 );
336 if (index === -1) return OMapping(null, null, null, null);
337 const segment = segments[index];
338 if (segment.length === 1) return OMapping(null, null, null, null);
339 const { names, resolvedSources } = map;
340 return OMapping(
341 resolvedSources[segment[SOURCES_INDEX]],
342 segment[SOURCE_LINE] + 1,
343 segment[SOURCE_COLUMN],
344 segment.length === 5 ? names[segment[NAMES_INDEX]] : null
345 );
346}
347function generatedPositionFor(map, needle) {
348 const { source, line, column, bias } = needle;
349 return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
350}
351function allGeneratedPositionsFor(map, needle) {
352 const { source, line, column, bias } = needle;
353 return generatedPosition(map, source, line, column, bias || LEAST_UPPER_BOUND, true);
354}
355function eachMapping(map, cb) {
356 const decoded = decodedMappings(map);
357 const { names, resolvedSources } = map;
358 for (let i = 0; i < decoded.length; i++) {
359 const line = decoded[i];
360 for (let j = 0; j < line.length; j++) {
361 const seg = line[j];
362 const generatedLine = i + 1;
363 const generatedColumn = seg[0];
364 let source = null;
365 let originalLine = null;
366 let originalColumn = null;
367 let name = null;
368 if (seg.length !== 1) {
369 source = resolvedSources[seg[1]];
370 originalLine = seg[2] + 1;
371 originalColumn = seg[3];
372 }
373 if (seg.length === 5) name = names[seg[4]];
374 cb({
375 generatedLine,
376 generatedColumn,
377 source,
378 originalLine,
379 originalColumn,
380 name
381 });
382 }
383 }
384}
385function sourceIndex(map, source) {
386 const { sources, resolvedSources } = map;
387 let index = sources.indexOf(source);
388 if (index === -1) index = resolvedSources.indexOf(source);
389 return index;
390}
391function sourceContentFor(map, source) {
392 const { sourcesContent } = map;
393 if (sourcesContent == null) return null;
394 const index = sourceIndex(map, source);
395 return index === -1 ? null : sourcesContent[index];
396}
397function isIgnored(map, source) {
398 const { ignoreList } = map;
399 if (ignoreList == null) return false;
400 const index = sourceIndex(map, source);
401 return index === -1 ? false : ignoreList.includes(index);
402}
403function presortedDecodedMap(map, mapUrl) {
404 const tracer = new TraceMap(clone(map, []), mapUrl);
405 cast(tracer)._decoded = map.mappings;
406 return tracer;
407}
408function decodedMap(map) {
409 return clone(map, decodedMappings(map));
410}
411function encodedMap(map) {
412 return clone(map, encodedMappings(map));
413}
414function clone(map, mappings) {
415 return {
416 version: map.version,
417 file: map.file,
418 names: map.names,
419 sourceRoot: map.sourceRoot,
420 sources: map.sources,
421 sourcesContent: map.sourcesContent,
422 mappings,
423 ignoreList: map.ignoreList || map.x_google_ignoreList
424 };
425}
426function OMapping(source, line, column, name) {
427 return { source, line, column, name };
428}
429function GMapping(line, column) {
430 return { line, column };
431}
432function traceSegmentInternal(segments, memo, line, column, bias) {
433 let index = memoizedBinarySearch(segments, column, memo, line);
434 if (found) {
435 index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
436 } else if (bias === LEAST_UPPER_BOUND) index++;
437 if (index === -1 || index === segments.length) return -1;
438 return index;
439}
440function sliceGeneratedPositions(segments, memo, line, column, bias) {
441 let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND);
442 if (!found && bias === LEAST_UPPER_BOUND) min++;
443 if (min === -1 || min === segments.length) return [];
444 const matchedColumn = found ? column : segments[min][COLUMN];
445 if (!found) min = lowerBound(segments, matchedColumn, min);
446 const max = upperBound(segments, matchedColumn, min);
447 const result = [];
448 for (; min <= max; min++) {
449 const segment = segments[min];
450 result.push(GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]));
451 }
452 return result;
453}
454function generatedPosition(map, source, line, column, bias, all) {
455 var _a, _b;
456 line--;
457 if (line < 0) throw new Error(LINE_GTR_ZERO);
458 if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
459 const { sources, resolvedSources } = map;
460 let sourceIndex2 = sources.indexOf(source);
461 if (sourceIndex2 === -1) sourceIndex2 = resolvedSources.indexOf(source);
462 if (sourceIndex2 === -1) return all ? [] : GMapping(null, null);
463 const bySourceMemos = (_a = cast(map))._bySourceMemos || (_a._bySourceMemos = sources.map(memoizedState));
464 const generated = (_b = cast(map))._bySources || (_b._bySources = buildBySources(decodedMappings(map), bySourceMemos));
465 const segments = generated[sourceIndex2][line];
466 if (segments == null) return all ? [] : GMapping(null, null);
467 const memo = bySourceMemos[sourceIndex2];
468 if (all) return sliceGeneratedPositions(segments, memo, line, column, bias);
469 const index = traceSegmentInternal(segments, memo, line, column, bias);
470 if (index === -1) return GMapping(null, null);
471 const segment = segments[index];
472 return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
473}
474export {
475 FlattenMap as AnyMap,
476 FlattenMap,
477 GREATEST_LOWER_BOUND,
478 LEAST_UPPER_BOUND,
479 TraceMap,
480 allGeneratedPositionsFor,
481 decodedMap,
482 decodedMappings,
483 eachMapping,
484 encodedMap,
485 encodedMappings,
486 generatedPositionFor,
487 isIgnored,
488 originalPositionFor,
489 presortedDecodedMap,
490 sourceContentFor,
491 traceSegment
492};
493//# sourceMappingURL=trace-mapping.mjs.map
node_modules/@jridgewell/trace-mapping/dist/trace-mapping.mjs.map +6 -0
……@@ -0,0 +1,6 @@
1{
2 "version": 3,
3 "sources": ["../src/trace-mapping.ts", "../src/resolve.ts", "../src/strip-filename.ts", "../src/sourcemap-segment.ts", "../src/sort.ts", "../src/by-source.ts", "../src/binary-search.ts", "../src/types.ts", "../src/flatten-map.ts"],
4 "mappings": ";AAAA,SAAS,QAAQ,cAAc;;;ACA/B,OAAO,gBAAgB;;;ACGR,SAAR,cAA+B,MAAyC;AAC7E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QAAQ,KAAK,YAAY,GAAG;AAClC,SAAO,KAAK,MAAM,GAAG,QAAQ,CAAC;AAChC;;;ADHe,SAAR,SACL,QACA,YACS;AACT,QAAM,OAAO,cAAc,MAAM;AAIjC,QAAM,SAAS,aAAa,aAAa,MAAM;AAE/C,SAAO,CAAC,WAAW,WAAW,UAAU,UAAU,KAAK,IAAI;AAC7D;;;AEAO,IAAM,SAAS;AACf,IAAM,gBAAgB;AACtB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAEpB,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;;;AClBrB,SAAR,UACL,UACA,OACsB;AACtB,QAAM,gBAAgB,wBAAwB,UAAU,CAAC;AACzD,MAAI,kBAAkB,SAAS,OAAQ,QAAO;AAI9C,MAAI,CAAC,MAAO,YAAW,SAAS,MAAM;AAEtC,WAAS,IAAI,eAAe,IAAI,SAAS,QAAQ,IAAI,wBAAwB,UAAU,IAAI,CAAC,GAAG;AAC7F,aAAS,CAAC,IAAI,aAAa,SAAS,CAAC,GAAG,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,UAAgC,OAAuB;AACtF,WAAS,IAAI,OAAO,IAAI,SAAS,QAAQ,KAAK;AAC5C,QAAI,CAAC,SAAS,SAAS,CAAC,CAAC,EAAG,QAAO;AAAA,EACrC;AACA,SAAO,SAAS;AAClB;AAEA,SAAS,SAAS,MAAmC;AACnD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,EAAE,MAAM,GAAG;AACzC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAA0B,OAAoC;AAClF,MAAI,CAAC,MAAO,QAAO,KAAK,MAAM;AAC9B,SAAO,KAAK,KAAK,cAAc;AACjC;AAEO,SAAS,eAA4D,GAAM,GAAc;AAC9F,SAAO,EAAE,MAAM,IAAI,EAAE,MAAM;AAC7B;;;ACnCe,SAAR,eACL,SACA,OACU;AACV,QAAM,UAAoB,MAAM,IAAI,MAAM,CAAC,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,CAAC;AACtB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,IAAI,WAAW,EAAG;AAEtB,YAAMA,eAAc,IAAI,aAAa;AACrC,YAAM,aAAa,IAAI,WAAW;AAClC,YAAM,eAAe,IAAI,aAAa;AAEtC,YAAM,SAAS,QAAQA,YAAW;AAClC,YAAM,OAAQ,4CAAuB,CAAC;AACtC,WAAK,KAAK,CAAC,cAAc,GAAG,IAAI,MAAM,CAAC,CAAC;AAAA,IAC1C;AAAA,EACF;AAEA,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,SAAS,QAAQ,CAAC;AACxB,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,OAAO,OAAO,CAAC;AACrB,UAAI,KAAM,MAAK,KAAK,cAAc;AAAA,IACpC;AAAA,EACF;AAEA,SAAO;AACT;;;AC/BO,IAAI,QAAQ;AAkBZ,SAAS,aACd,UACA,QACA,KACA,MACQ;AACR,SAAO,OAAO,MAAM;AAClB,UAAM,MAAM,OAAQ,OAAO,OAAQ;AACnC,UAAM,MAAM,SAAS,GAAG,EAAE,MAAM,IAAI;AAEpC,QAAI,QAAQ,GAAG;AACb,cAAQ;AACR,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,GAAG;AACX,YAAM,MAAM;AAAA,IACd,OAAO;AACL,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,UAAQ;AACR,SAAO,MAAM;AACf;AAEO,SAAS,WACd,UACA,QACA,OACQ;AACR,WAAS,IAAI,QAAQ,GAAG,IAAI,SAAS,QAAQ,QAAQ,KAAK;AACxD,QAAI,SAAS,CAAC,EAAE,MAAM,MAAM,OAAQ;AAAA,EACtC;AACA,SAAO;AACT;AAEO,SAAS,WACd,UACA,QACA,OACQ;AACR,WAAS,IAAI,QAAQ,GAAG,KAAK,GAAG,QAAQ,KAAK;AAC3C,QAAI,SAAS,CAAC,EAAE,MAAM,MAAM,OAAQ;AAAA,EACtC;AACA,SAAO;AACT;AAEO,SAAS,gBAA2B;AACzC,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AACF;AAMO,SAAS,qBACd,UACA,QACA,OACA,KACQ;AACR,QAAM,EAAE,SAAS,YAAY,UAAU,IAAI;AAE3C,MAAI,MAAM;AACV,MAAI,OAAO,SAAS,SAAS;AAC7B,MAAI,QAAQ,SAAS;AACnB,QAAI,WAAW,YAAY;AACzB,cAAQ,cAAc,MAAM,SAAS,SAAS,EAAE,MAAM,MAAM;AAC5D,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,YAAY;AAExB,YAAM,cAAc,KAAK,IAAI;AAAA,IAC/B,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,UAAU;AAChB,QAAM,aAAa;AAEnB,SAAQ,MAAM,YAAY,aAAa,UAAU,QAAQ,KAAK,IAAI;AACpE;;;ACHO,SAAS,MAAS,KAA4B;AACnD,SAAO,OAAO,QAAQ,WAAW,KAAK,MAAM,GAAG,IAAK;AACtD;;;ACvFO,IAAM,aAAyB,SAAU,KAAK,QAAQ;AAC3D,QAAM,SAAS,MAAM,GAA8B;AAEnD,MAAI,EAAE,cAAc,SAAS;AAC3B,WAAO,IAAI,SAAS,QAA2D,MAAM;AAAA,EACvF;AAEA,QAAM,WAAiC,CAAC;AACxC,QAAM,UAAoB,CAAC;AAC3B,QAAM,iBAAoC,CAAC;AAC3C,QAAM,QAAkB,CAAC;AACzB,QAAM,aAAuB,CAAC;AAE9B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,SAA2B;AAAA,IAC/B,SAAS;AAAA,IACT,MAAM,OAAO;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,oBAAoB,MAAM;AACnC;AAEA,SAAS,QACP,OACA,QACA,UACA,SACA,gBACA,OACA,YACA,YACA,cACA,UACA,YACA;AACA,QAAM,EAAE,SAAS,IAAI;AACrB,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,EAAE,KAAK,OAAO,IAAI,SAAS,CAAC;AAElC,QAAI,KAAK;AACT,QAAI,KAAK;AACT,QAAI,IAAI,IAAI,SAAS,QAAQ;AAC3B,YAAM,aAAa,SAAS,IAAI,CAAC,EAAE;AACnC,WAAK,KAAK,IAAI,UAAU,aAAa,WAAW,IAAI;AAEpD,UAAI,OAAO,UAAU;AACnB,aAAK,KAAK,IAAI,YAAY,eAAe,WAAW,MAAM;AAAA,MAC5D,WAAW,KAAK,UAAU;AACxB,aAAK,eAAe,WAAW;AAAA,MACjC;AAAA,IACF;AAEA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,OAAO;AAAA,MACpB,eAAe,OAAO;AAAA,MACtB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,WACP,OACA,QACA,UACA,SACA,gBACA,OACA,YACA,YACA,cACA,UACA,YACA;AACA,QAAM,SAAS,MAAM,KAAK;AAC1B,MAAI,cAAc,OAAQ,QAAO,QAAQ,GAAI,SAAmD;AAEhG,QAAM,MAAM,IAAI,SAAS,QAAQ,MAAM;AACvC,QAAM,gBAAgB,QAAQ;AAC9B,QAAM,cAAc,MAAM;AAC1B,QAAM,UAAU,gBAAgB,GAAG;AACnC,QAAM,EAAE,iBAAiB,gBAAgB,UAAU,YAAY,QAAQ,IAAI;AAE3E,SAAO,SAAS,eAAe;AAC/B,SAAO,OAAO,IAAI,KAAK;AAEvB,MAAI,SAAU,QAAO,gBAAgB,QAAQ;AAAA,MACxC,UAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,IAAK,gBAAe,KAAK,IAAI;AAE9E,MAAI,QAAS,UAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAAK,YAAW,KAAK,QAAQ,CAAC,IAAI,aAAa;AAEhG,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,QAAQ,aAAa;AAM3B,QAAI,QAAQ,SAAU;AAItB,UAAM,MAAM,QAAQ,UAAU,KAAK;AAGnC,UAAM,UAAU,MAAM,IAAI,eAAe;AAEzC,UAAM,OAAO,QAAQ,CAAC;AACtB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,SAAS,UAAU,IAAI,MAAM;AAInC,UAAI,UAAU,YAAY,UAAU,WAAY;AAEhD,UAAI,IAAI,WAAW,GAAG;AACpB,YAAI,KAAK,CAAC,MAAM,CAAC;AACjB;AAAA,MACF;AAEA,YAAM,eAAe,gBAAgB,IAAI,aAAa;AACtD,YAAM,aAAa,IAAI,WAAW;AAClC,YAAM,eAAe,IAAI,aAAa;AACtC,UAAI;AAAA,QACF,IAAI,WAAW,IACX,CAAC,QAAQ,cAAc,YAAY,YAAY,IAC/C,CAAC,QAAQ,cAAc,YAAY,cAAc,cAAc,IAAI,WAAW,CAAC;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,OAAU,KAAU,OAAY;AACvC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,KAAI,KAAK,MAAM,CAAC,CAAC;AAC1D;AAEA,SAAS,QAAW,KAAY,OAAoB;AAClD,WAAS,IAAI,IAAI,QAAQ,KAAK,OAAO,IAAK,KAAI,CAAC,IAAI,CAAC;AACpD,SAAO,IAAI,KAAK;AAClB;;;ARhHA,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AAEjB,IAAM,oBAAoB;AAC1B,IAAM,uBAAuB;AAI7B,IAAM,WAAN,MAAoC;AAAA,EAkBzC,YAAY,KAAyB,QAAwB;AAC3D,UAAM,WAAW,OAAO,QAAQ;AAChC,QAAI,CAAC,YAAa,IAAyC,aAAc,QAAO;AAEhF,UAAM,SAAS,MAAM,GAAwC;AAE7D,UAAM,EAAE,SAAS,MAAM,OAAO,YAAY,SAAS,eAAe,IAAI;AACtE,SAAK,UAAU;AACf,SAAK,OAAO;AACZ,SAAK,QAAQ,SAAS,CAAC;AACvB,SAAK,aAAa;AAClB,SAAK,UAAU;AACf,SAAK,iBAAiB;AACtB,SAAK,aAAa,OAAO,cAAe,OAAkB,uBAAuB;AAEjF,UAAM,UAAU,SAAS,QAAQ,UAAU;AAC3C,SAAK,kBAAkB,QAAQ,IAAI,OAAO;AAE1C,UAAM,EAAE,SAAS,IAAI;AACrB,QAAI,OAAO,aAAa,UAAU;AAChC,WAAK,WAAW;AAChB,WAAK,WAAW;AAAA,IAClB,WAAW,MAAM,QAAQ,QAAQ,GAAG;AAClC,WAAK,WAAW;AAChB,WAAK,WAAW,UAAU,UAAU,QAAQ;AAAA,IAC9C,WAAY,OAAyC,UAAU;AAC7D,YAAM,IAAI,MAAM,4EAA4E;AAAA,IAC9F,OAAO;AACL,YAAM,IAAI,MAAM,uBAAuB,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,IACjE;AAEA,SAAK,eAAe,cAAc;AAClC,SAAK,aAAa;AAClB,SAAK,iBAAiB;AAAA,EACxB;AACF;AAMA,SAAS,KAAK,KAAyB;AACrC,SAAO;AACT;AAKO,SAAS,gBAAgB,KAA6C;AAzJ7E;AA0JE,UAAQ,gBAAK,GAAG,GAAE,aAAV,eAAU,WAAa,OAAO,KAAK,GAAG,EAAE,QAAS;AAC3D;AAKO,SAAS,gBAAgB,KAAuD;AAhKvF;AAiKE,UAAQ,UAAK,GAAG,GAAE,aAAV,GAAU,WAAa,OAAO,KAAK,GAAG,EAAE,QAAS;AAC3D;AAMO,SAAS,aACd,KACA,MACA,QACmC;AACnC,QAAM,UAAU,gBAAgB,GAAG;AAInC,MAAI,QAAQ,QAAQ,OAAQ,QAAO;AAEnC,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,KAAK,GAAG,EAAE;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,UAAU,KAAK,OAAO,SAAS,KAAK;AAC7C;AAOO,SAAS,oBACd,KACA,QAC0C;AAC1C,MAAI,EAAE,MAAM,QAAQ,KAAK,IAAI;AAC7B;AACA,MAAI,OAAO,EAAG,OAAM,IAAI,MAAM,aAAa;AAC3C,MAAI,SAAS,EAAG,OAAM,IAAI,MAAM,eAAe;AAE/C,QAAM,UAAU,gBAAgB,GAAG;AAInC,MAAI,QAAQ,QAAQ,OAAQ,QAAO,SAAS,MAAM,MAAM,MAAM,IAAI;AAElE,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,KAAK,GAAG,EAAE;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,EACV;AAEA,MAAI,UAAU,GAAI,QAAO,SAAS,MAAM,MAAM,MAAM,IAAI;AAExD,QAAM,UAAU,SAAS,KAAK;AAC9B,MAAI,QAAQ,WAAW,EAAG,QAAO,SAAS,MAAM,MAAM,MAAM,IAAI;AAEhE,QAAM,EAAE,OAAO,gBAAgB,IAAI;AACnC,SAAO;AAAA,IACL,gBAAgB,QAAQ,aAAa,CAAC;AAAA,IACtC,QAAQ,WAAW,IAAI;AAAA,IACvB,QAAQ,aAAa;AAAA,IACrB,QAAQ,WAAW,IAAI,MAAM,QAAQ,WAAW,CAAC,IAAI;AAAA,EACvD;AACF;AAKO,SAAS,qBACd,KACA,QAC4C;AAC5C,QAAM,EAAE,QAAQ,MAAM,QAAQ,KAAK,IAAI;AACvC,SAAO,kBAAkB,KAAK,QAAQ,MAAM,QAAQ,QAAQ,sBAAsB,KAAK;AACzF;AAKO,SAAS,yBAAyB,KAAe,QAA0C;AAChG,QAAM,EAAE,QAAQ,MAAM,QAAQ,KAAK,IAAI;AAEvC,SAAO,kBAAkB,KAAK,QAAQ,MAAM,QAAQ,QAAQ,mBAAmB,IAAI;AACrF;AAKO,SAAS,YAAY,KAAe,IAA0C;AACnF,QAAM,UAAU,gBAAgB,GAAG;AACnC,QAAM,EAAE,OAAO,gBAAgB,IAAI;AAEnC,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,CAAC;AACtB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAElB,YAAM,gBAAgB,IAAI;AAC1B,YAAM,kBAAkB,IAAI,CAAC;AAC7B,UAAI,SAAS;AACb,UAAI,eAAe;AACnB,UAAI,iBAAiB;AACrB,UAAI,OAAO;AACX,UAAI,IAAI,WAAW,GAAG;AACpB,iBAAS,gBAAgB,IAAI,CAAC,CAAC;AAC/B,uBAAe,IAAI,CAAC,IAAI;AACxB,yBAAiB,IAAI,CAAC;AAAA,MACxB;AACA,UAAI,IAAI,WAAW,EAAG,QAAO,MAAM,IAAI,CAAC,CAAC;AAEzC,SAAG;AAAA,QACD;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAgB;AAAA,IAClB;AAAA,EACF;AACF;AAEA,SAAS,YAAY,KAAe,QAAwB;AAC1D,QAAM,EAAE,SAAS,gBAAgB,IAAI;AACrC,MAAI,QAAQ,QAAQ,QAAQ,MAAM;AAClC,MAAI,UAAU,GAAI,SAAQ,gBAAgB,QAAQ,MAAM;AACxD,SAAO;AACT;AAKO,SAAS,iBAAiB,KAAe,QAA+B;AAC7E,QAAM,EAAE,eAAe,IAAI;AAC3B,MAAI,kBAAkB,KAAM,QAAO;AACnC,QAAM,QAAQ,YAAY,KAAK,MAAM;AACrC,SAAO,UAAU,KAAK,OAAO,eAAe,KAAK;AACnD;AAKO,SAAS,UAAU,KAAe,QAAyB;AAChE,QAAM,EAAE,WAAW,IAAI;AACvB,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,QAAQ,YAAY,KAAK,MAAM;AACrC,SAAO,UAAU,KAAK,QAAQ,WAAW,SAAS,KAAK;AACzD;AAMO,SAAS,oBAAoB,KAAuB,QAA2B;AACpF,QAAM,SAAS,IAAI,SAAS,MAAM,KAAK,CAAC,CAAC,GAAG,MAAM;AAClD,OAAK,MAAM,EAAE,WAAW,IAAI;AAC5B,SAAO;AACT;AAMO,SAAS,WACd,KACkF;AAClF,SAAO,MAAM,KAAK,gBAAgB,GAAG,CAAC;AACxC;AAMO,SAAS,WAAW,KAAiC;AAC1D,SAAO,MAAM,KAAK,gBAAgB,GAAG,CAAC;AACxC;AAEA,SAAS,MACP,KACA,UACwD;AACxD,SAAO;AAAA,IACL,SAAS,IAAI;AAAA,IACb,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,YAAY,IAAI;AAAA,IAChB,SAAS,IAAI;AAAA,IACb,gBAAgB,IAAI;AAAA,IACpB;AAAA,IACA,YAAY,IAAI,cAAe,IAAe;AAAA,EAChD;AACF;AASA,SAAS,SACP,QACA,MACA,QACA,MAC0C;AAC1C,SAAO,EAAE,QAAQ,MAAM,QAAQ,KAAK;AACtC;AAIA,SAAS,SACP,MACA,QAC4C;AAC5C,SAAO,EAAE,MAAM,OAAO;AACxB;AAgBA,SAAS,qBACP,UACA,MACA,MACA,QACA,MACQ;AACR,MAAI,QAAQ,qBAAqB,UAAU,QAAQ,MAAM,IAAI;AAC7D,MAAI,OAAS;AACX,aAAS,SAAS,oBAAoB,aAAa,YAAY,UAAU,QAAQ,KAAK;AAAA,EACxF,WAAW,SAAS,kBAAmB;AAEvC,MAAI,UAAU,MAAM,UAAU,SAAS,OAAQ,QAAO;AACtD,SAAO;AACT;AAEA,SAAS,wBACP,UACA,MACA,MACA,QACA,MACoB;AACpB,MAAI,MAAM,qBAAqB,UAAU,MAAM,MAAM,QAAQ,oBAAoB;AAQjF,MAAI,CAAC,SAAW,SAAS,kBAAmB;AAE5C,MAAI,QAAQ,MAAM,QAAQ,SAAS,OAAQ,QAAO,CAAC;AAKnD,QAAM,gBAAgB,QAAU,SAAS,SAAS,GAAG,EAAE,MAAM;AAG7D,MAAI,CAAC,MAAS,OAAM,WAAW,UAAU,eAAe,GAAG;AAC3D,QAAM,MAAM,WAAW,UAAU,eAAe,GAAG;AAEnD,QAAM,SAAS,CAAC;AAChB,SAAO,OAAO,KAAK,OAAO;AACxB,UAAM,UAAU,SAAS,GAAG;AAC5B,WAAO,KAAK,SAAS,QAAQ,kBAAkB,IAAI,GAAG,QAAQ,oBAAoB,CAAC,CAAC;AAAA,EACtF;AACA,SAAO;AACT;AAkBA,SAAS,kBACP,KACA,QACA,MACA,QACA,MACA,KACiE;AA5dnE;AA6dE;AACA,MAAI,OAAO,EAAG,OAAM,IAAI,MAAM,aAAa;AAC3C,MAAI,SAAS,EAAG,OAAM,IAAI,MAAM,eAAe;AAE/C,QAAM,EAAE,SAAS,gBAAgB,IAAI;AACrC,MAAIC,eAAc,QAAQ,QAAQ,MAAM;AACxC,MAAIA,iBAAgB,GAAI,CAAAA,eAAc,gBAAgB,QAAQ,MAAM;AACpE,MAAIA,iBAAgB,GAAI,QAAO,MAAM,CAAC,IAAI,SAAS,MAAM,IAAI;AAE7D,QAAM,iBAAiB,UAAK,GAAG,GAAE,mBAAV,GAAU,iBAAmB,QAAQ,IAAI,aAAa;AAC7E,QAAM,aAAa,UAAK,GAAG,GAAE,eAAV,GAAU,aAAe,eAAe,gBAAgB,GAAG,GAAG,aAAa;AAE9F,QAAM,WAAW,UAAUA,YAAW,EAAE,IAAI;AAC5C,MAAI,YAAY,KAAM,QAAO,MAAM,CAAC,IAAI,SAAS,MAAM,IAAI;AAE3D,QAAM,OAAO,cAAcA,YAAW;AAEtC,MAAI,IAAK,QAAO,wBAAwB,UAAU,MAAM,MAAM,QAAQ,IAAI;AAE1E,QAAM,QAAQ,qBAAqB,UAAU,MAAM,MAAM,QAAQ,IAAI;AACrE,MAAI,UAAU,GAAI,QAAO,SAAS,MAAM,IAAI;AAE5C,QAAM,UAAU,SAAS,KAAK;AAC9B,SAAO,SAAS,QAAQ,kBAAkB,IAAI,GAAG,QAAQ,oBAAoB,CAAC;AAChF;",
5 "names": ["sourceIndex", "sourceIndex"]
6}
node_modules/@jridgewell/trace-mapping/dist/trace-mapping.umd.js +559 -0
……@@ -0,0 +1,559 @@
1(function (global, factory) {
2 if (typeof exports === 'object' && typeof module !== 'undefined') {
3 factory(module, require('@jridgewell/resolve-uri'), require('@jridgewell/sourcemap-codec'));
4 module.exports = def(module);
5 } else if (typeof define === 'function' && define.amd) {
6 define(['module', '@jridgewell/resolve-uri', '@jridgewell/sourcemap-codec'], function(mod) {
7 factory.apply(this, arguments);
8 mod.exports = def(mod);
9 });
10 } else {
11 const mod = { exports: {} };
12 factory(mod, global.resolveURI, global.sourcemapCodec);
13 global = typeof globalThis !== 'undefined' ? globalThis : global || self;
14 global.traceMapping = def(mod);
15 }
16 function def(m) { return 'default' in m.exports ? m.exports.default : m.exports; }
17})(this, (function (module, require_resolveURI, require_sourcemapCodec) {
18"use strict";
19var __create = Object.create;
20var __defProp = Object.defineProperty;
21var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
22var __getOwnPropNames = Object.getOwnPropertyNames;
23var __getProtoOf = Object.getPrototypeOf;
24var __hasOwnProp = Object.prototype.hasOwnProperty;
25var __commonJS = (cb, mod) => function __require() {
26 return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
27};
28var __export = (target, all) => {
29 for (var name in all)
30 __defProp(target, name, { get: all[name], enumerable: true });
31};
32var __copyProps = (to, from, except, desc) => {
33 if (from && typeof from === "object" || typeof from === "function") {
34 for (let key of __getOwnPropNames(from))
35 if (!__hasOwnProp.call(to, key) && key !== except)
36 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
37 }
38 return to;
39};
40var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
41 // If the importer is in node compatibility mode or this is not an ESM
42 // file that has been converted to a CommonJS file using a Babel-
43 // compatible transform (i.e. "__esModule" has not been set), then set
44 // "default" to the CommonJS "module.exports" for node compatibility.
45 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
46 mod
47));
48var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
49
50// umd:@jridgewell/sourcemap-codec
51var require_sourcemap_codec = __commonJS({
52 "umd:@jridgewell/sourcemap-codec"(exports, module2) {
53 module2.exports = require_sourcemapCodec;
54 }
55});
56
57// umd:@jridgewell/resolve-uri
58var require_resolve_uri = __commonJS({
59 "umd:@jridgewell/resolve-uri"(exports, module2) {
60 module2.exports = require_resolveURI;
61 }
62});
63
64// src/trace-mapping.ts
65var trace_mapping_exports = {};
66__export(trace_mapping_exports, {
67 AnyMap: () => FlattenMap,
68 FlattenMap: () => FlattenMap,
69 GREATEST_LOWER_BOUND: () => GREATEST_LOWER_BOUND,
70 LEAST_UPPER_BOUND: () => LEAST_UPPER_BOUND,
71 TraceMap: () => TraceMap,
72 allGeneratedPositionsFor: () => allGeneratedPositionsFor,
73 decodedMap: () => decodedMap,
74 decodedMappings: () => decodedMappings,
75 eachMapping: () => eachMapping,
76 encodedMap: () => encodedMap,
77 encodedMappings: () => encodedMappings,
78 generatedPositionFor: () => generatedPositionFor,
79 isIgnored: () => isIgnored,
80 originalPositionFor: () => originalPositionFor,
81 presortedDecodedMap: () => presortedDecodedMap,
82 sourceContentFor: () => sourceContentFor,
83 traceSegment: () => traceSegment
84});
85module.exports = __toCommonJS(trace_mapping_exports);
86var import_sourcemap_codec = __toESM(require_sourcemap_codec());
87
88// src/resolve.ts
89var import_resolve_uri = __toESM(require_resolve_uri());
90
91// src/strip-filename.ts
92function stripFilename(path) {
93 if (!path) return "";
94 const index = path.lastIndexOf("/");
95 return path.slice(0, index + 1);
96}
97
98// src/resolve.ts
99function resolver(mapUrl, sourceRoot) {
100 const from = stripFilename(mapUrl);
101 const prefix = sourceRoot ? sourceRoot + "/" : "";
102 return (source) => (0, import_resolve_uri.default)(prefix + (source || ""), from);
103}
104
105// src/sourcemap-segment.ts
106var COLUMN = 0;
107var SOURCES_INDEX = 1;
108var SOURCE_LINE = 2;
109var SOURCE_COLUMN = 3;
110var NAMES_INDEX = 4;
111var REV_GENERATED_LINE = 1;
112var REV_GENERATED_COLUMN = 2;
113
114// src/sort.ts
115function maybeSort(mappings, owned) {
116 const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
117 if (unsortedIndex === mappings.length) return mappings;
118 if (!owned) mappings = mappings.slice();
119 for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
120 mappings[i] = sortSegments(mappings[i], owned);
121 }
122 return mappings;
123}
124function nextUnsortedSegmentLine(mappings, start) {
125 for (let i = start; i < mappings.length; i++) {
126 if (!isSorted(mappings[i])) return i;
127 }
128 return mappings.length;
129}
130function isSorted(line) {
131 for (let j = 1; j < line.length; j++) {
132 if (line[j][COLUMN] < line[j - 1][COLUMN]) {
133 return false;
134 }
135 }
136 return true;
137}
138function sortSegments(line, owned) {
139 if (!owned) line = line.slice();
140 return line.sort(sortComparator);
141}
142function sortComparator(a, b) {
143 return a[COLUMN] - b[COLUMN];
144}
145
146// src/by-source.ts
147function buildBySources(decoded, memos) {
148 const sources = memos.map(() => []);
149 for (let i = 0; i < decoded.length; i++) {
150 const line = decoded[i];
151 for (let j = 0; j < line.length; j++) {
152 const seg = line[j];
153 if (seg.length === 1) continue;
154 const sourceIndex2 = seg[SOURCES_INDEX];
155 const sourceLine = seg[SOURCE_LINE];
156 const sourceColumn = seg[SOURCE_COLUMN];
157 const source = sources[sourceIndex2];
158 const segs = source[sourceLine] || (source[sourceLine] = []);
159 segs.push([sourceColumn, i, seg[COLUMN]]);
160 }
161 }
162 for (let i = 0; i < sources.length; i++) {
163 const source = sources[i];
164 for (let j = 0; j < source.length; j++) {
165 const line = source[j];
166 if (line) line.sort(sortComparator);
167 }
168 }
169 return sources;
170}
171
172// src/binary-search.ts
173var found = false;
174function binarySearch(haystack, needle, low, high) {
175 while (low <= high) {
176 const mid = low + (high - low >> 1);
177 const cmp = haystack[mid][COLUMN] - needle;
178 if (cmp === 0) {
179 found = true;
180 return mid;
181 }
182 if (cmp < 0) {
183 low = mid + 1;
184 } else {
185 high = mid - 1;
186 }
187 }
188 found = false;
189 return low - 1;
190}
191function upperBound(haystack, needle, index) {
192 for (let i = index + 1; i < haystack.length; index = i++) {
193 if (haystack[i][COLUMN] !== needle) break;
194 }
195 return index;
196}
197function lowerBound(haystack, needle, index) {
198 for (let i = index - 1; i >= 0; index = i--) {
199 if (haystack[i][COLUMN] !== needle) break;
200 }
201 return index;
202}
203function memoizedState() {
204 return {
205 lastKey: -1,
206 lastNeedle: -1,
207 lastIndex: -1
208 };
209}
210function memoizedBinarySearch(haystack, needle, state, key) {
211 const { lastKey, lastNeedle, lastIndex } = state;
212 let low = 0;
213 let high = haystack.length - 1;
214 if (key === lastKey) {
215 if (needle === lastNeedle) {
216 found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
217 return lastIndex;
218 }
219 if (needle >= lastNeedle) {
220 low = lastIndex === -1 ? 0 : lastIndex;
221 } else {
222 high = lastIndex;
223 }
224 }
225 state.lastKey = key;
226 state.lastNeedle = needle;
227 return state.lastIndex = binarySearch(haystack, needle, low, high);
228}
229
230// src/types.ts
231function parse(map) {
232 return typeof map === "string" ? JSON.parse(map) : map;
233}
234
235// src/flatten-map.ts
236var FlattenMap = function(map, mapUrl) {
237 const parsed = parse(map);
238 if (!("sections" in parsed)) {
239 return new TraceMap(parsed, mapUrl);
240 }
241 const mappings = [];
242 const sources = [];
243 const sourcesContent = [];
244 const names = [];
245 const ignoreList = [];
246 recurse(
247 parsed,
248 mapUrl,
249 mappings,
250 sources,
251 sourcesContent,
252 names,
253 ignoreList,
254 0,
255 0,
256 Infinity,
257 Infinity
258 );
259 const joined = {
260 version: 3,
261 file: parsed.file,
262 names,
263 sources,
264 sourcesContent,
265 mappings,
266 ignoreList
267 };
268 return presortedDecodedMap(joined);
269};
270function recurse(input, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
271 const { sections } = input;
272 for (let i = 0; i < sections.length; i++) {
273 const { map, offset } = sections[i];
274 let sl = stopLine;
275 let sc = stopColumn;
276 if (i + 1 < sections.length) {
277 const nextOffset = sections[i + 1].offset;
278 sl = Math.min(stopLine, lineOffset + nextOffset.line);
279 if (sl === stopLine) {
280 sc = Math.min(stopColumn, columnOffset + nextOffset.column);
281 } else if (sl < stopLine) {
282 sc = columnOffset + nextOffset.column;
283 }
284 }
285 addSection(
286 map,
287 mapUrl,
288 mappings,
289 sources,
290 sourcesContent,
291 names,
292 ignoreList,
293 lineOffset + offset.line,
294 columnOffset + offset.column,
295 sl,
296 sc
297 );
298 }
299}
300function addSection(input, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
301 const parsed = parse(input);
302 if ("sections" in parsed) return recurse(...arguments);
303 const map = new TraceMap(parsed, mapUrl);
304 const sourcesOffset = sources.length;
305 const namesOffset = names.length;
306 const decoded = decodedMappings(map);
307 const { resolvedSources, sourcesContent: contents, ignoreList: ignores } = map;
308 append(sources, resolvedSources);
309 append(names, map.names);
310 if (contents) append(sourcesContent, contents);
311 else for (let i = 0; i < resolvedSources.length; i++) sourcesContent.push(null);
312 if (ignores) for (let i = 0; i < ignores.length; i++) ignoreList.push(ignores[i] + sourcesOffset);
313 for (let i = 0; i < decoded.length; i++) {
314 const lineI = lineOffset + i;
315 if (lineI > stopLine) return;
316 const out = getLine(mappings, lineI);
317 const cOffset = i === 0 ? columnOffset : 0;
318 const line = decoded[i];
319 for (let j = 0; j < line.length; j++) {
320 const seg = line[j];
321 const column = cOffset + seg[COLUMN];
322 if (lineI === stopLine && column >= stopColumn) return;
323 if (seg.length === 1) {
324 out.push([column]);
325 continue;
326 }
327 const sourcesIndex = sourcesOffset + seg[SOURCES_INDEX];
328 const sourceLine = seg[SOURCE_LINE];
329 const sourceColumn = seg[SOURCE_COLUMN];
330 out.push(
331 seg.length === 4 ? [column, sourcesIndex, sourceLine, sourceColumn] : [column, sourcesIndex, sourceLine, sourceColumn, namesOffset + seg[NAMES_INDEX]]
332 );
333 }
334 }
335}
336function append(arr, other) {
337 for (let i = 0; i < other.length; i++) arr.push(other[i]);
338}
339function getLine(arr, index) {
340 for (let i = arr.length; i <= index; i++) arr[i] = [];
341 return arr[index];
342}
343
344// src/trace-mapping.ts
345var LINE_GTR_ZERO = "`line` must be greater than 0 (lines start at line 1)";
346var COL_GTR_EQ_ZERO = "`column` must be greater than or equal to 0 (columns start at column 0)";
347var LEAST_UPPER_BOUND = -1;
348var GREATEST_LOWER_BOUND = 1;
349var TraceMap = class {
350 constructor(map, mapUrl) {
351 const isString = typeof map === "string";
352 if (!isString && map._decodedMemo) return map;
353 const parsed = parse(map);
354 const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
355 this.version = version;
356 this.file = file;
357 this.names = names || [];
358 this.sourceRoot = sourceRoot;
359 this.sources = sources;
360 this.sourcesContent = sourcesContent;
361 this.ignoreList = parsed.ignoreList || parsed.x_google_ignoreList || void 0;
362 const resolve = resolver(mapUrl, sourceRoot);
363 this.resolvedSources = sources.map(resolve);
364 const { mappings } = parsed;
365 if (typeof mappings === "string") {
366 this._encoded = mappings;
367 this._decoded = void 0;
368 } else if (Array.isArray(mappings)) {
369 this._encoded = void 0;
370 this._decoded = maybeSort(mappings, isString);
371 } else if (parsed.sections) {
372 throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`);
373 } else {
374 throw new Error(`invalid source map: ${JSON.stringify(parsed)}`);
375 }
376 this._decodedMemo = memoizedState();
377 this._bySources = void 0;
378 this._bySourceMemos = void 0;
379 }
380};
381function cast(map) {
382 return map;
383}
384function encodedMappings(map) {
385 var _a, _b;
386 return (_b = (_a = cast(map))._encoded) != null ? _b : _a._encoded = (0, import_sourcemap_codec.encode)(cast(map)._decoded);
387}
388function decodedMappings(map) {
389 var _a;
390 return (_a = cast(map))._decoded || (_a._decoded = (0, import_sourcemap_codec.decode)(cast(map)._encoded));
391}
392function traceSegment(map, line, column) {
393 const decoded = decodedMappings(map);
394 if (line >= decoded.length) return null;
395 const segments = decoded[line];
396 const index = traceSegmentInternal(
397 segments,
398 cast(map)._decodedMemo,
399 line,
400 column,
401 GREATEST_LOWER_BOUND
402 );
403 return index === -1 ? null : segments[index];
404}
405function originalPositionFor(map, needle) {
406 let { line, column, bias } = needle;
407 line--;
408 if (line < 0) throw new Error(LINE_GTR_ZERO);
409 if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
410 const decoded = decodedMappings(map);
411 if (line >= decoded.length) return OMapping(null, null, null, null);
412 const segments = decoded[line];
413 const index = traceSegmentInternal(
414 segments,
415 cast(map)._decodedMemo,
416 line,
417 column,
418 bias || GREATEST_LOWER_BOUND
419 );
420 if (index === -1) return OMapping(null, null, null, null);
421 const segment = segments[index];
422 if (segment.length === 1) return OMapping(null, null, null, null);
423 const { names, resolvedSources } = map;
424 return OMapping(
425 resolvedSources[segment[SOURCES_INDEX]],
426 segment[SOURCE_LINE] + 1,
427 segment[SOURCE_COLUMN],
428 segment.length === 5 ? names[segment[NAMES_INDEX]] : null
429 );
430}
431function generatedPositionFor(map, needle) {
432 const { source, line, column, bias } = needle;
433 return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
434}
435function allGeneratedPositionsFor(map, needle) {
436 const { source, line, column, bias } = needle;
437 return generatedPosition(map, source, line, column, bias || LEAST_UPPER_BOUND, true);
438}
439function eachMapping(map, cb) {
440 const decoded = decodedMappings(map);
441 const { names, resolvedSources } = map;
442 for (let i = 0; i < decoded.length; i++) {
443 const line = decoded[i];
444 for (let j = 0; j < line.length; j++) {
445 const seg = line[j];
446 const generatedLine = i + 1;
447 const generatedColumn = seg[0];
448 let source = null;
449 let originalLine = null;
450 let originalColumn = null;
451 let name = null;
452 if (seg.length !== 1) {
453 source = resolvedSources[seg[1]];
454 originalLine = seg[2] + 1;
455 originalColumn = seg[3];
456 }
457 if (seg.length === 5) name = names[seg[4]];
458 cb({
459 generatedLine,
460 generatedColumn,
461 source,
462 originalLine,
463 originalColumn,
464 name
465 });
466 }
467 }
468}
469function sourceIndex(map, source) {
470 const { sources, resolvedSources } = map;
471 let index = sources.indexOf(source);
472 if (index === -1) index = resolvedSources.indexOf(source);
473 return index;
474}
475function sourceContentFor(map, source) {
476 const { sourcesContent } = map;
477 if (sourcesContent == null) return null;
478 const index = sourceIndex(map, source);
479 return index === -1 ? null : sourcesContent[index];
480}
481function isIgnored(map, source) {
482 const { ignoreList } = map;
483 if (ignoreList == null) return false;
484 const index = sourceIndex(map, source);
485 return index === -1 ? false : ignoreList.includes(index);
486}
487function presortedDecodedMap(map, mapUrl) {
488 const tracer = new TraceMap(clone(map, []), mapUrl);
489 cast(tracer)._decoded = map.mappings;
490 return tracer;
491}
492function decodedMap(map) {
493 return clone(map, decodedMappings(map));
494}
495function encodedMap(map) {
496 return clone(map, encodedMappings(map));
497}
498function clone(map, mappings) {
499 return {
500 version: map.version,
501 file: map.file,
502 names: map.names,
503 sourceRoot: map.sourceRoot,
504 sources: map.sources,
505 sourcesContent: map.sourcesContent,
506 mappings,
507 ignoreList: map.ignoreList || map.x_google_ignoreList
508 };
509}
510function OMapping(source, line, column, name) {
511 return { source, line, column, name };
512}
513function GMapping(line, column) {
514 return { line, column };
515}
516function traceSegmentInternal(segments, memo, line, column, bias) {
517 let index = memoizedBinarySearch(segments, column, memo, line);
518 if (found) {
519 index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
520 } else if (bias === LEAST_UPPER_BOUND) index++;
521 if (index === -1 || index === segments.length) return -1;
522 return index;
523}
524function sliceGeneratedPositions(segments, memo, line, column, bias) {
525 let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND);
526 if (!found && bias === LEAST_UPPER_BOUND) min++;
527 if (min === -1 || min === segments.length) return [];
528 const matchedColumn = found ? column : segments[min][COLUMN];
529 if (!found) min = lowerBound(segments, matchedColumn, min);
530 const max = upperBound(segments, matchedColumn, min);
531 const result = [];
532 for (; min <= max; min++) {
533 const segment = segments[min];
534 result.push(GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]));
535 }
536 return result;
537}
538function generatedPosition(map, source, line, column, bias, all) {
539 var _a, _b;
540 line--;
541 if (line < 0) throw new Error(LINE_GTR_ZERO);
542 if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
543 const { sources, resolvedSources } = map;
544 let sourceIndex2 = sources.indexOf(source);
545 if (sourceIndex2 === -1) sourceIndex2 = resolvedSources.indexOf(source);
546 if (sourceIndex2 === -1) return all ? [] : GMapping(null, null);
547 const bySourceMemos = (_a = cast(map))._bySourceMemos || (_a._bySourceMemos = sources.map(memoizedState));
548 const generated = (_b = cast(map))._bySources || (_b._bySources = buildBySources(decodedMappings(map), bySourceMemos));
549 const segments = generated[sourceIndex2][line];
550 if (segments == null) return all ? [] : GMapping(null, null);
551 const memo = bySourceMemos[sourceIndex2];
552 if (all) return sliceGeneratedPositions(segments, memo, line, column, bias);
553 const index = traceSegmentInternal(segments, memo, line, column, bias);
554 if (index === -1) return GMapping(null, null);
555 const segment = segments[index];
556 return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
557}
558}));
559//# sourceMappingURL=trace-mapping.umd.js.map
node_modules/@jridgewell/trace-mapping/dist/trace-mapping.umd.js.map +6 -0
……@@ -0,0 +1,6 @@
1{
2 "version": 3,
3 "sources": ["umd:@jridgewell/sourcemap-codec", "umd:@jridgewell/resolve-uri", "../src/trace-mapping.ts", "../src/resolve.ts", "../src/strip-filename.ts", "../src/sourcemap-segment.ts", "../src/sort.ts", "../src/by-source.ts", "../src/binary-search.ts", "../src/types.ts", "../src/flatten-map.ts"],
4 "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,6CAAAA,SAAA;AAAA,IAAAA,QAAO,UAAU;AAAA;AAAA;;;ACAjB;AAAA,yCAAAC,SAAA;AAAA,IAAAA,QAAO,UAAU;AAAA;AAAA;;;ACAjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAA+B;;;ACA/B,yBAAuB;;;ACGR,SAAR,cAA+B,MAAyC;AAC7E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QAAQ,KAAK,YAAY,GAAG;AAClC,SAAO,KAAK,MAAM,GAAG,QAAQ,CAAC;AAChC;;;ADHe,SAAR,SACL,QACA,YACS;AACT,QAAM,OAAO,cAAc,MAAM;AAIjC,QAAM,SAAS,aAAa,aAAa,MAAM;AAE/C,SAAO,CAAC,eAAW,mBAAAC,SAAW,UAAU,UAAU,KAAK,IAAI;AAC7D;;;AEAO,IAAM,SAAS;AACf,IAAM,gBAAgB;AACtB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAEpB,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;;;AClBrB,SAAR,UACL,UACA,OACsB;AACtB,QAAM,gBAAgB,wBAAwB,UAAU,CAAC;AACzD,MAAI,kBAAkB,SAAS,OAAQ,QAAO;AAI9C,MAAI,CAAC,MAAO,YAAW,SAAS,MAAM;AAEtC,WAAS,IAAI,eAAe,IAAI,SAAS,QAAQ,IAAI,wBAAwB,UAAU,IAAI,CAAC,GAAG;AAC7F,aAAS,CAAC,IAAI,aAAa,SAAS,CAAC,GAAG,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,UAAgC,OAAuB;AACtF,WAAS,IAAI,OAAO,IAAI,SAAS,QAAQ,KAAK;AAC5C,QAAI,CAAC,SAAS,SAAS,CAAC,CAAC,EAAG,QAAO;AAAA,EACrC;AACA,SAAO,SAAS;AAClB;AAEA,SAAS,SAAS,MAAmC;AACnD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,EAAE,MAAM,GAAG;AACzC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAA0B,OAAoC;AAClF,MAAI,CAAC,MAAO,QAAO,KAAK,MAAM;AAC9B,SAAO,KAAK,KAAK,cAAc;AACjC;AAEO,SAAS,eAA4D,GAAM,GAAc;AAC9F,SAAO,EAAE,MAAM,IAAI,EAAE,MAAM;AAC7B;;;ACnCe,SAAR,eACL,SACA,OACU;AACV,QAAM,UAAoB,MAAM,IAAI,MAAM,CAAC,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,CAAC;AACtB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,IAAI,WAAW,EAAG;AAEtB,YAAMC,eAAc,IAAI,aAAa;AACrC,YAAM,aAAa,IAAI,WAAW;AAClC,YAAM,eAAe,IAAI,aAAa;AAEtC,YAAM,SAAS,QAAQA,YAAW;AAClC,YAAM,OAAQ,4CAAuB,CAAC;AACtC,WAAK,KAAK,CAAC,cAAc,GAAG,IAAI,MAAM,CAAC,CAAC;AAAA,IAC1C;AAAA,EACF;AAEA,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,SAAS,QAAQ,CAAC;AACxB,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,OAAO,OAAO,CAAC;AACrB,UAAI,KAAM,MAAK,KAAK,cAAc;AAAA,IACpC;AAAA,EACF;AAEA,SAAO;AACT;;;AC/BO,IAAI,QAAQ;AAkBZ,SAAS,aACd,UACA,QACA,KACA,MACQ;AACR,SAAO,OAAO,MAAM;AAClB,UAAM,MAAM,OAAQ,OAAO,OAAQ;AACnC,UAAM,MAAM,SAAS,GAAG,EAAE,MAAM,IAAI;AAEpC,QAAI,QAAQ,GAAG;AACb,cAAQ;AACR,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,GAAG;AACX,YAAM,MAAM;AAAA,IACd,OAAO;AACL,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,UAAQ;AACR,SAAO,MAAM;AACf;AAEO,SAAS,WACd,UACA,QACA,OACQ;AACR,WAAS,IAAI,QAAQ,GAAG,IAAI,SAAS,QAAQ,QAAQ,KAAK;AACxD,QAAI,SAAS,CAAC,EAAE,MAAM,MAAM,OAAQ;AAAA,EACtC;AACA,SAAO;AACT;AAEO,SAAS,WACd,UACA,QACA,OACQ;AACR,WAAS,IAAI,QAAQ,GAAG,KAAK,GAAG,QAAQ,KAAK;AAC3C,QAAI,SAAS,CAAC,EAAE,MAAM,MAAM,OAAQ;AAAA,EACtC;AACA,SAAO;AACT;AAEO,SAAS,gBAA2B;AACzC,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AACF;AAMO,SAAS,qBACd,UACA,QACA,OACA,KACQ;AACR,QAAM,EAAE,SAAS,YAAY,UAAU,IAAI;AAE3C,MAAI,MAAM;AACV,MAAI,OAAO,SAAS,SAAS;AAC7B,MAAI,QAAQ,SAAS;AACnB,QAAI,WAAW,YAAY;AACzB,cAAQ,cAAc,MAAM,SAAS,SAAS,EAAE,MAAM,MAAM;AAC5D,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,YAAY;AAExB,YAAM,cAAc,KAAK,IAAI;AAAA,IAC/B,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,UAAU;AAChB,QAAM,aAAa;AAEnB,SAAQ,MAAM,YAAY,aAAa,UAAU,QAAQ,KAAK,IAAI;AACpE;;;ACHO,SAAS,MAAS,KAA4B;AACnD,SAAO,OAAO,QAAQ,WAAW,KAAK,MAAM,GAAG,IAAK;AACtD;;;ACvFO,IAAM,aAAyB,SAAU,KAAK,QAAQ;AAC3D,QAAM,SAAS,MAAM,GAA8B;AAEnD,MAAI,EAAE,cAAc,SAAS;AAC3B,WAAO,IAAI,SAAS,QAA2D,MAAM;AAAA,EACvF;AAEA,QAAM,WAAiC,CAAC;AACxC,QAAM,UAAoB,CAAC;AAC3B,QAAM,iBAAoC,CAAC;AAC3C,QAAM,QAAkB,CAAC;AACzB,QAAM,aAAuB,CAAC;AAE9B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,SAA2B;AAAA,IAC/B,SAAS;AAAA,IACT,MAAM,OAAO;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,oBAAoB,MAAM;AACnC;AAEA,SAAS,QACP,OACA,QACA,UACA,SACA,gBACA,OACA,YACA,YACA,cACA,UACA,YACA;AACA,QAAM,EAAE,SAAS,IAAI;AACrB,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,EAAE,KAAK,OAAO,IAAI,SAAS,CAAC;AAElC,QAAI,KAAK;AACT,QAAI,KAAK;AACT,QAAI,IAAI,IAAI,SAAS,QAAQ;AAC3B,YAAM,aAAa,SAAS,IAAI,CAAC,EAAE;AACnC,WAAK,KAAK,IAAI,UAAU,aAAa,WAAW,IAAI;AAEpD,UAAI,OAAO,UAAU;AACnB,aAAK,KAAK,IAAI,YAAY,eAAe,WAAW,MAAM;AAAA,MAC5D,WAAW,KAAK,UAAU;AACxB,aAAK,eAAe,WAAW;AAAA,MACjC;AAAA,IACF;AAEA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,OAAO;AAAA,MACpB,eAAe,OAAO;AAAA,MACtB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,WACP,OACA,QACA,UACA,SACA,gBACA,OACA,YACA,YACA,cACA,UACA,YACA;AACA,QAAM,SAAS,MAAM,KAAK;AAC1B,MAAI,cAAc,OAAQ,QAAO,QAAQ,GAAI,SAAmD;AAEhG,QAAM,MAAM,IAAI,SAAS,QAAQ,MAAM;AACvC,QAAM,gBAAgB,QAAQ;AAC9B,QAAM,cAAc,MAAM;AAC1B,QAAM,UAAU,gBAAgB,GAAG;AACnC,QAAM,EAAE,iBAAiB,gBAAgB,UAAU,YAAY,QAAQ,IAAI;AAE3E,SAAO,SAAS,eAAe;AAC/B,SAAO,OAAO,IAAI,KAAK;AAEvB,MAAI,SAAU,QAAO,gBAAgB,QAAQ;AAAA,MACxC,UAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,IAAK,gBAAe,KAAK,IAAI;AAE9E,MAAI,QAAS,UAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAAK,YAAW,KAAK,QAAQ,CAAC,IAAI,aAAa;AAEhG,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,QAAQ,aAAa;AAM3B,QAAI,QAAQ,SAAU;AAItB,UAAM,MAAM,QAAQ,UAAU,KAAK;AAGnC,UAAM,UAAU,MAAM,IAAI,eAAe;AAEzC,UAAM,OAAO,QAAQ,CAAC;AACtB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,SAAS,UAAU,IAAI,MAAM;AAInC,UAAI,UAAU,YAAY,UAAU,WAAY;AAEhD,UAAI,IAAI,WAAW,GAAG;AACpB,YAAI,KAAK,CAAC,MAAM,CAAC;AACjB;AAAA,MACF;AAEA,YAAM,eAAe,gBAAgB,IAAI,aAAa;AACtD,YAAM,aAAa,IAAI,WAAW;AAClC,YAAM,eAAe,IAAI,aAAa;AACtC,UAAI;AAAA,QACF,IAAI,WAAW,IACX,CAAC,QAAQ,cAAc,YAAY,YAAY,IAC/C,CAAC,QAAQ,cAAc,YAAY,cAAc,cAAc,IAAI,WAAW,CAAC;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,OAAU,KAAU,OAAY;AACvC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,KAAI,KAAK,MAAM,CAAC,CAAC;AAC1D;AAEA,SAAS,QAAW,KAAY,OAAoB;AAClD,WAAS,IAAI,IAAI,QAAQ,KAAK,OAAO,IAAK,KAAI,CAAC,IAAI,CAAC;AACpD,SAAO,IAAI,KAAK;AAClB;;;ARhHA,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AAEjB,IAAM,oBAAoB;AAC1B,IAAM,uBAAuB;AAI7B,IAAM,WAAN,MAAoC;AAAA,EAkBzC,YAAY,KAAyB,QAAwB;AAC3D,UAAM,WAAW,OAAO,QAAQ;AAChC,QAAI,CAAC,YAAa,IAAyC,aAAc,QAAO;AAEhF,UAAM,SAAS,MAAM,GAAwC;AAE7D,UAAM,EAAE,SAAS,MAAM,OAAO,YAAY,SAAS,eAAe,IAAI;AACtE,SAAK,UAAU;AACf,SAAK,OAAO;AACZ,SAAK,QAAQ,SAAS,CAAC;AACvB,SAAK,aAAa;AAClB,SAAK,UAAU;AACf,SAAK,iBAAiB;AACtB,SAAK,aAAa,OAAO,cAAe,OAAkB,uBAAuB;AAEjF,UAAM,UAAU,SAAS,QAAQ,UAAU;AAC3C,SAAK,kBAAkB,QAAQ,IAAI,OAAO;AAE1C,UAAM,EAAE,SAAS,IAAI;AACrB,QAAI,OAAO,aAAa,UAAU;AAChC,WAAK,WAAW;AAChB,WAAK,WAAW;AAAA,IAClB,WAAW,MAAM,QAAQ,QAAQ,GAAG;AAClC,WAAK,WAAW;AAChB,WAAK,WAAW,UAAU,UAAU,QAAQ;AAAA,IAC9C,WAAY,OAAyC,UAAU;AAC7D,YAAM,IAAI,MAAM,4EAA4E;AAAA,IAC9F,OAAO;AACL,YAAM,IAAI,MAAM,uBAAuB,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,IACjE;AAEA,SAAK,eAAe,cAAc;AAClC,SAAK,aAAa;AAClB,SAAK,iBAAiB;AAAA,EACxB;AACF;AAMA,SAAS,KAAK,KAAyB;AACrC,SAAO;AACT;AAKO,SAAS,gBAAgB,KAA6C;AAzJ7E;AA0JE,UAAQ,gBAAK,GAAG,GAAE,aAAV,eAAU,eAAa,+BAAO,KAAK,GAAG,EAAE,QAAS;AAC3D;AAKO,SAAS,gBAAgB,KAAuD;AAhKvF;AAiKE,UAAQ,UAAK,GAAG,GAAE,aAAV,GAAU,eAAa,+BAAO,KAAK,GAAG,EAAE,QAAS;AAC3D;AAMO,SAAS,aACd,KACA,MACA,QACmC;AACnC,QAAM,UAAU,gBAAgB,GAAG;AAInC,MAAI,QAAQ,QAAQ,OAAQ,QAAO;AAEnC,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,KAAK,GAAG,EAAE;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,UAAU,KAAK,OAAO,SAAS,KAAK;AAC7C;AAOO,SAAS,oBACd,KACA,QAC0C;AAC1C,MAAI,EAAE,MAAM,QAAQ,KAAK,IAAI;AAC7B;AACA,MAAI,OAAO,EAAG,OAAM,IAAI,MAAM,aAAa;AAC3C,MAAI,SAAS,EAAG,OAAM,IAAI,MAAM,eAAe;AAE/C,QAAM,UAAU,gBAAgB,GAAG;AAInC,MAAI,QAAQ,QAAQ,OAAQ,QAAO,SAAS,MAAM,MAAM,MAAM,IAAI;AAElE,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,KAAK,GAAG,EAAE;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,EACV;AAEA,MAAI,UAAU,GAAI,QAAO,SAAS,MAAM,MAAM,MAAM,IAAI;AAExD,QAAM,UAAU,SAAS,KAAK;AAC9B,MAAI,QAAQ,WAAW,EAAG,QAAO,SAAS,MAAM,MAAM,MAAM,IAAI;AAEhE,QAAM,EAAE,OAAO,gBAAgB,IAAI;AACnC,SAAO;AAAA,IACL,gBAAgB,QAAQ,aAAa,CAAC;AAAA,IACtC,QAAQ,WAAW,IAAI;AAAA,IACvB,QAAQ,aAAa;AAAA,IACrB,QAAQ,WAAW,IAAI,MAAM,QAAQ,WAAW,CAAC,IAAI;AAAA,EACvD;AACF;AAKO,SAAS,qBACd,KACA,QAC4C;AAC5C,QAAM,EAAE,QAAQ,MAAM,QAAQ,KAAK,IAAI;AACvC,SAAO,kBAAkB,KAAK,QAAQ,MAAM,QAAQ,QAAQ,sBAAsB,KAAK;AACzF;AAKO,SAAS,yBAAyB,KAAe,QAA0C;AAChG,QAAM,EAAE,QAAQ,MAAM,QAAQ,KAAK,IAAI;AAEvC,SAAO,kBAAkB,KAAK,QAAQ,MAAM,QAAQ,QAAQ,mBAAmB,IAAI;AACrF;AAKO,SAAS,YAAY,KAAe,IAA0C;AACnF,QAAM,UAAU,gBAAgB,GAAG;AACnC,QAAM,EAAE,OAAO,gBAAgB,IAAI;AAEnC,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,CAAC;AACtB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAElB,YAAM,gBAAgB,IAAI;AAC1B,YAAM,kBAAkB,IAAI,CAAC;AAC7B,UAAI,SAAS;AACb,UAAI,eAAe;AACnB,UAAI,iBAAiB;AACrB,UAAI,OAAO;AACX,UAAI,IAAI,WAAW,GAAG;AACpB,iBAAS,gBAAgB,IAAI,CAAC,CAAC;AAC/B,uBAAe,IAAI,CAAC,IAAI;AACxB,yBAAiB,IAAI,CAAC;AAAA,MACxB;AACA,UAAI,IAAI,WAAW,EAAG,QAAO,MAAM,IAAI,CAAC,CAAC;AAEzC,SAAG;AAAA,QACD;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAgB;AAAA,IAClB;AAAA,EACF;AACF;AAEA,SAAS,YAAY,KAAe,QAAwB;AAC1D,QAAM,EAAE,SAAS,gBAAgB,IAAI;AACrC,MAAI,QAAQ,QAAQ,QAAQ,MAAM;AAClC,MAAI,UAAU,GAAI,SAAQ,gBAAgB,QAAQ,MAAM;AACxD,SAAO;AACT;AAKO,SAAS,iBAAiB,KAAe,QAA+B;AAC7E,QAAM,EAAE,eAAe,IAAI;AAC3B,MAAI,kBAAkB,KAAM,QAAO;AACnC,QAAM,QAAQ,YAAY,KAAK,MAAM;AACrC,SAAO,UAAU,KAAK,OAAO,eAAe,KAAK;AACnD;AAKO,SAAS,UAAU,KAAe,QAAyB;AAChE,QAAM,EAAE,WAAW,IAAI;AACvB,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,QAAQ,YAAY,KAAK,MAAM;AACrC,SAAO,UAAU,KAAK,QAAQ,WAAW,SAAS,KAAK;AACzD;AAMO,SAAS,oBAAoB,KAAuB,QAA2B;AACpF,QAAM,SAAS,IAAI,SAAS,MAAM,KAAK,CAAC,CAAC,GAAG,MAAM;AAClD,OAAK,MAAM,EAAE,WAAW,IAAI;AAC5B,SAAO;AACT;AAMO,SAAS,WACd,KACkF;AAClF,SAAO,MAAM,KAAK,gBAAgB,GAAG,CAAC;AACxC;AAMO,SAAS,WAAW,KAAiC;AAC1D,SAAO,MAAM,KAAK,gBAAgB,GAAG,CAAC;AACxC;AAEA,SAAS,MACP,KACA,UACwD;AACxD,SAAO;AAAA,IACL,SAAS,IAAI;AAAA,IACb,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,YAAY,IAAI;AAAA,IAChB,SAAS,IAAI;AAAA,IACb,gBAAgB,IAAI;AAAA,IACpB;AAAA,IACA,YAAY,IAAI,cAAe,IAAe;AAAA,EAChD;AACF;AASA,SAAS,SACP,QACA,MACA,QACA,MAC0C;AAC1C,SAAO,EAAE,QAAQ,MAAM,QAAQ,KAAK;AACtC;AAIA,SAAS,SACP,MACA,QAC4C;AAC5C,SAAO,EAAE,MAAM,OAAO;AACxB;AAgBA,SAAS,qBACP,UACA,MACA,MACA,QACA,MACQ;AACR,MAAI,QAAQ,qBAAqB,UAAU,QAAQ,MAAM,IAAI;AAC7D,MAAI,OAAS;AACX,aAAS,SAAS,oBAAoB,aAAa,YAAY,UAAU,QAAQ,KAAK;AAAA,EACxF,WAAW,SAAS,kBAAmB;AAEvC,MAAI,UAAU,MAAM,UAAU,SAAS,OAAQ,QAAO;AACtD,SAAO;AACT;AAEA,SAAS,wBACP,UACA,MACA,MACA,QACA,MACoB;AACpB,MAAI,MAAM,qBAAqB,UAAU,MAAM,MAAM,QAAQ,oBAAoB;AAQjF,MAAI,CAAC,SAAW,SAAS,kBAAmB;AAE5C,MAAI,QAAQ,MAAM,QAAQ,SAAS,OAAQ,QAAO,CAAC;AAKnD,QAAM,gBAAgB,QAAU,SAAS,SAAS,GAAG,EAAE,MAAM;AAG7D,MAAI,CAAC,MAAS,OAAM,WAAW,UAAU,eAAe,GAAG;AAC3D,QAAM,MAAM,WAAW,UAAU,eAAe,GAAG;AAEnD,QAAM,SAAS,CAAC;AAChB,SAAO,OAAO,KAAK,OAAO;AACxB,UAAM,UAAU,SAAS,GAAG;AAC5B,WAAO,KAAK,SAAS,QAAQ,kBAAkB,IAAI,GAAG,QAAQ,oBAAoB,CAAC,CAAC;AAAA,EACtF;AACA,SAAO;AACT;AAkBA,SAAS,kBACP,KACA,QACA,MACA,QACA,MACA,KACiE;AA5dnE;AA6dE;AACA,MAAI,OAAO,EAAG,OAAM,IAAI,MAAM,aAAa;AAC3C,MAAI,SAAS,EAAG,OAAM,IAAI,MAAM,eAAe;AAE/C,QAAM,EAAE,SAAS,gBAAgB,IAAI;AACrC,MAAIC,eAAc,QAAQ,QAAQ,MAAM;AACxC,MAAIA,iBAAgB,GAAI,CAAAA,eAAc,gBAAgB,QAAQ,MAAM;AACpE,MAAIA,iBAAgB,GAAI,QAAO,MAAM,CAAC,IAAI,SAAS,MAAM,IAAI;AAE7D,QAAM,iBAAiB,UAAK,GAAG,GAAE,mBAAV,GAAU,iBAAmB,QAAQ,IAAI,aAAa;AAC7E,QAAM,aAAa,UAAK,GAAG,GAAE,eAAV,GAAU,aAAe,eAAe,gBAAgB,GAAG,GAAG,aAAa;AAE9F,QAAM,WAAW,UAAUA,YAAW,EAAE,IAAI;AAC5C,MAAI,YAAY,KAAM,QAAO,MAAM,CAAC,IAAI,SAAS,MAAM,IAAI;AAE3D,QAAM,OAAO,cAAcA,YAAW;AAEtC,MAAI,IAAK,QAAO,wBAAwB,UAAU,MAAM,MAAM,QAAQ,IAAI;AAE1E,QAAM,QAAQ,qBAAqB,UAAU,MAAM,MAAM,QAAQ,IAAI;AACrE,MAAI,UAAU,GAAI,QAAO,SAAS,MAAM,IAAI;AAE5C,QAAM,UAAU,SAAS,KAAK;AAC9B,SAAO,SAAS,QAAQ,kBAAkB,IAAI,GAAG,QAAQ,oBAAoB,CAAC;AAChF;",
5 "names": ["module", "module", "resolveUri", "sourceIndex", "sourceIndex"]
6}
node_modules/@jridgewell/trace-mapping/package.json +67 -0
……@@ -0,0 +1,67 @@
1{
2 "name": "@jridgewell/trace-mapping",
3 "version": "0.3.31",
4 "description": "Trace the original position through a source map",
5 "keywords": [
6 "source",
7 "map"
8 ],
9 "main": "dist/trace-mapping.umd.js",
10 "module": "dist/trace-mapping.mjs",
11 "types": "types/trace-mapping.d.cts",
12 "files": [
13 "dist",
14 "src",
15 "types"
16 ],
17 "exports": {
18 ".": [
19 {
20 "import": {
21 "types": "./types/trace-mapping.d.mts",
22 "default": "./dist/trace-mapping.mjs"
23 },
24 "default": {
25 "types": "./types/trace-mapping.d.cts",
26 "default": "./dist/trace-mapping.umd.js"
27 }
28 },
29 "./dist/trace-mapping.umd.js"
30 ],
31 "./package.json": "./package.json"
32 },
33 "scripts": {
34 "benchmark": "run-s build:code benchmark:*",
35 "benchmark:install": "cd benchmark && npm install",
36 "benchmark:only": "node --expose-gc benchmark/index.mjs",
37 "build": "run-s -n build:code build:types",
38 "build:code": "node ../../esbuild.mjs trace-mapping.ts",
39 "build:types": "run-s build:types:force build:types:emit build:types:mts",
40 "build:types:force": "rimraf tsconfig.build.tsbuildinfo",
41 "build:types:emit": "tsc --project tsconfig.build.json",
42 "build:types:mts": "node ../../mts-types.mjs",
43 "clean": "run-s -n clean:code clean:types",
44 "clean:code": "tsc --build --clean tsconfig.build.json",
45 "clean:types": "rimraf dist types",
46 "test": "run-s -n test:types test:only test:format",
47 "test:format": "prettier --check '{src,test}/**/*.ts'",
48 "test:only": "mocha",
49 "test:types": "eslint '{src,test}/**/*.ts'",
50 "lint": "run-s -n lint:types lint:format",
51 "lint:format": "npm run test:format -- --write",
52 "lint:types": "npm run test:types -- --fix",
53 "prepublishOnly": "npm run-s -n build test"
54 },
55 "homepage": "https://github.com/jridgewell/sourcemaps/tree/main/packages/trace-mapping",
56 "repository": {
57 "type": "git",
58 "url": "git+https://github.com/jridgewell/sourcemaps.git",
59 "directory": "packages/trace-mapping"
60 },
61 "author": "Justin Ridgewell <justin@ridgewell.name>",
62 "license": "MIT",
63 "dependencies": {
64 "@jridgewell/resolve-uri": "^3.1.0",
65 "@jridgewell/sourcemap-codec": "^1.4.14"
66 }
67}
node_modules/@jridgewell/trace-mapping/src/binary-search.ts +115 -0
……@@ -0,0 +1,115 @@
1import type { SourceMapSegment, ReverseSegment } from './sourcemap-segment';
2import { COLUMN } from './sourcemap-segment';
3
4export type MemoState = {
5 lastKey: number;
6 lastNeedle: number;
7 lastIndex: number;
8};
9
10export let found = false;
11
12/**
13 * A binary search implementation that returns the index if a match is found.
14 * If no match is found, then the left-index (the index associated with the item that comes just
15 * before the desired index) is returned. To maintain proper sort order, a splice would happen at
16 * the next index:
17 *
18 * ```js
19 * const array = [1, 3];
20 * const needle = 2;
21 * const index = binarySearch(array, needle, (item, needle) => item - needle);
22 *
23 * assert.equal(index, 0);
24 * array.splice(index + 1, 0, needle);
25 * assert.deepEqual(array, [1, 2, 3]);
26 * ```
27 */
28export function binarySearch(
29 haystack: SourceMapSegment[] | ReverseSegment[],
30 needle: number,
31 low: number,
32 high: number,
33): number {
34 while (low <= high) {
35 const mid = low + ((high - low) >> 1);
36 const cmp = haystack[mid][COLUMN] - needle;
37
38 if (cmp === 0) {
39 found = true;
40 return mid;
41 }
42
43 if (cmp < 0) {
44 low = mid + 1;
45 } else {
46 high = mid - 1;
47 }
48 }
49
50 found = false;
51 return low - 1;
52}
53
54export function upperBound(
55 haystack: SourceMapSegment[] | ReverseSegment[],
56 needle: number,
57 index: number,
58): number {
59 for (let i = index + 1; i < haystack.length; index = i++) {
60 if (haystack[i][COLUMN] !== needle) break;
61 }
62 return index;
63}
64
65export function lowerBound(
66 haystack: SourceMapSegment[] | ReverseSegment[],
67 needle: number,
68 index: number,
69): number {
70 for (let i = index - 1; i >= 0; index = i--) {
71 if (haystack[i][COLUMN] !== needle) break;
72 }
73 return index;
74}
75
76export function memoizedState(): MemoState {
77 return {
78 lastKey: -1,
79 lastNeedle: -1,
80 lastIndex: -1,
81 };
82}
83
84/**
85 * This overly complicated beast is just to record the last tested line/column and the resulting
86 * index, allowing us to skip a few tests if mappings are monotonically increasing.
87 */
88export function memoizedBinarySearch(
89 haystack: SourceMapSegment[] | ReverseSegment[],
90 needle: number,
91 state: MemoState,
92 key: number,
93): number {
94 const { lastKey, lastNeedle, lastIndex } = state;
95
96 let low = 0;
97 let high = haystack.length - 1;
98 if (key === lastKey) {
99 if (needle === lastNeedle) {
100 found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
101 return lastIndex;
102 }
103
104 if (needle >= lastNeedle) {
105 // lastIndex may be -1 if the previous needle was not found.
106 low = lastIndex === -1 ? 0 : lastIndex;
107 } else {
108 high = lastIndex;
109 }
110 }
111 state.lastKey = key;
112 state.lastNeedle = needle;
113
114 return (state.lastIndex = binarySearch(haystack, needle, low, high));
115}
node_modules/@jridgewell/trace-mapping/src/by-source.ts +41 -0
……@@ -0,0 +1,41 @@
1import { COLUMN, SOURCES_INDEX, SOURCE_LINE, SOURCE_COLUMN } from './sourcemap-segment';
2import { sortComparator } from './sort';
3
4import type { ReverseSegment, SourceMapSegment } from './sourcemap-segment';
5
6export type Source = ReverseSegment[][];
7
8// Rebuilds the original source files, with mappings that are ordered by source line/column instead
9// of generated line/column.
10export default function buildBySources(
11 decoded: readonly SourceMapSegment[][],
12 memos: unknown[],
13): Source[] {
14 const sources: Source[] = memos.map(() => []);
15
16 for (let i = 0; i < decoded.length; i++) {
17 const line = decoded[i];
18 for (let j = 0; j < line.length; j++) {
19 const seg = line[j];
20 if (seg.length === 1) continue;
21
22 const sourceIndex = seg[SOURCES_INDEX];
23 const sourceLine = seg[SOURCE_LINE];
24 const sourceColumn = seg[SOURCE_COLUMN];
25
26 const source = sources[sourceIndex];
27 const segs = (source[sourceLine] ||= []);
28 segs.push([sourceColumn, i, seg[COLUMN]]);
29 }
30 }
31
32 for (let i = 0; i < sources.length; i++) {
33 const source = sources[i];
34 for (let j = 0; j < source.length; j++) {
35 const line = source[j];
36 if (line) line.sort(sortComparator);
37 }
38 }
39
40 return sources;
41}
node_modules/@jridgewell/trace-mapping/src/flatten-map.ts +192 -0
……@@ -0,0 +1,192 @@
1import { TraceMap, presortedDecodedMap, decodedMappings } from './trace-mapping';
2import {
3 COLUMN,
4 SOURCES_INDEX,
5 SOURCE_LINE,
6 SOURCE_COLUMN,
7 NAMES_INDEX,
8} from './sourcemap-segment';
9import { parse } from './types';
10
11import type {
12 DecodedSourceMap,
13 DecodedSourceMapXInput,
14 EncodedSourceMapXInput,
15 SectionedSourceMapXInput,
16 SectionedSourceMapInput,
17 SectionXInput,
18 Ro,
19} from './types';
20import type { SourceMapSegment } from './sourcemap-segment';
21
22type FlattenMap = {
23 new (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
24 (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
25};
26
27export const FlattenMap: FlattenMap = function (map, mapUrl) {
28 const parsed = parse(map as SectionedSourceMapInput);
29
30 if (!('sections' in parsed)) {
31 return new TraceMap(parsed as DecodedSourceMapXInput | EncodedSourceMapXInput, mapUrl);
32 }
33
34 const mappings: SourceMapSegment[][] = [];
35 const sources: string[] = [];
36 const sourcesContent: (string | null)[] = [];
37 const names: string[] = [];
38 const ignoreList: number[] = [];
39
40 recurse(
41 parsed,
42 mapUrl,
43 mappings,
44 sources,
45 sourcesContent,
46 names,
47 ignoreList,
48 0,
49 0,
50 Infinity,
51 Infinity,
52 );
53
54 const joined: DecodedSourceMap = {
55 version: 3,
56 file: parsed.file,
57 names,
58 sources,
59 sourcesContent,
60 mappings,
61 ignoreList,
62 };
63
64 return presortedDecodedMap(joined);
65} as FlattenMap;
66
67function recurse(
68 input: SectionedSourceMapXInput,
69 mapUrl: string | null | undefined,
70 mappings: SourceMapSegment[][],
71 sources: string[],
72 sourcesContent: (string | null)[],
73 names: string[],
74 ignoreList: number[],
75 lineOffset: number,
76 columnOffset: number,
77 stopLine: number,
78 stopColumn: number,
79) {
80 const { sections } = input;
81 for (let i = 0; i < sections.length; i++) {
82 const { map, offset } = sections[i];
83
84 let sl = stopLine;
85 let sc = stopColumn;
86 if (i + 1 < sections.length) {
87 const nextOffset = sections[i + 1].offset;
88 sl = Math.min(stopLine, lineOffset + nextOffset.line);
89
90 if (sl === stopLine) {
91 sc = Math.min(stopColumn, columnOffset + nextOffset.column);
92 } else if (sl < stopLine) {
93 sc = columnOffset + nextOffset.column;
94 }
95 }
96
97 addSection(
98 map,
99 mapUrl,
100 mappings,
101 sources,
102 sourcesContent,
103 names,
104 ignoreList,
105 lineOffset + offset.line,
106 columnOffset + offset.column,
107 sl,
108 sc,
109 );
110 }
111}
112
113function addSection(
114 input: SectionXInput['map'],
115 mapUrl: string | null | undefined,
116 mappings: SourceMapSegment[][],
117 sources: string[],
118 sourcesContent: (string | null)[],
119 names: string[],
120 ignoreList: number[],
121 lineOffset: number,
122 columnOffset: number,
123 stopLine: number,
124 stopColumn: number,
125) {
126 const parsed = parse(input);
127 if ('sections' in parsed) return recurse(...(arguments as unknown as Parameters<typeof recurse>));
128
129 const map = new TraceMap(parsed, mapUrl);
130 const sourcesOffset = sources.length;
131 const namesOffset = names.length;
132 const decoded = decodedMappings(map);
133 const { resolvedSources, sourcesContent: contents, ignoreList: ignores } = map;
134
135 append(sources, resolvedSources);
136 append(names, map.names);
137
138 if (contents) append(sourcesContent, contents);
139 else for (let i = 0; i < resolvedSources.length; i++) sourcesContent.push(null);
140
141 if (ignores) for (let i = 0; i < ignores.length; i++) ignoreList.push(ignores[i] + sourcesOffset);
142
143 for (let i = 0; i < decoded.length; i++) {
144 const lineI = lineOffset + i;
145
146 // We can only add so many lines before we step into the range that the next section's map
147 // controls. When we get to the last line, then we'll start checking the segments to see if
148 // they've crossed into the column range. But it may not have any columns that overstep, so we
149 // still need to check that we don't overstep lines, too.
150 if (lineI > stopLine) return;
151
152 // The out line may already exist in mappings (if we're continuing the line started by a
153 // previous section). Or, we may have jumped ahead several lines to start this section.
154 const out = getLine(mappings, lineI);
155 // On the 0th loop, the section's column offset shifts us forward. On all other lines (since the
156 // map can be multiple lines), it doesn't.
157 const cOffset = i === 0 ? columnOffset : 0;
158
159 const line = decoded[i];
160 for (let j = 0; j < line.length; j++) {
161 const seg = line[j];
162 const column = cOffset + seg[COLUMN];
163
164 // If this segment steps into the column range that the next section's map controls, we need
165 // to stop early.
166 if (lineI === stopLine && column >= stopColumn) return;
167
168 if (seg.length === 1) {
169 out.push([column]);
170 continue;
171 }
172
173 const sourcesIndex = sourcesOffset + seg[SOURCES_INDEX];
174 const sourceLine = seg[SOURCE_LINE];
175 const sourceColumn = seg[SOURCE_COLUMN];
176 out.push(
177 seg.length === 4
178 ? [column, sourcesIndex, sourceLine, sourceColumn]
179 : [column, sourcesIndex, sourceLine, sourceColumn, namesOffset + seg[NAMES_INDEX]],
180 );
181 }
182 }
183}
184
185function append<T>(arr: T[], other: T[]) {
186 for (let i = 0; i < other.length; i++) arr.push(other[i]);
187}
188
189function getLine<T>(arr: T[][], index: number): T[] {
190 for (let i = arr.length; i <= index; i++) arr[i] = [];
191 return arr[index];
192}
node_modules/@jridgewell/trace-mapping/src/resolve.ts +16 -0
……@@ -0,0 +1,16 @@
1import resolveUri from '@jridgewell/resolve-uri';
2import stripFilename from './strip-filename';
3
4type Resolve = (source: string | null) => string;
5export default function resolver(
6 mapUrl: string | null | undefined,
7 sourceRoot: string | undefined,
8): Resolve {
9 const from = stripFilename(mapUrl);
10 // The sourceRoot is always treated as a directory, if it's not empty.
11 // https://github.com/mozilla/source-map/blob/8cb3ee57/lib/util.js#L327
12 // https://github.com/chromium/chromium/blob/da4adbb3/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js#L400-L401
13 const prefix = sourceRoot ? sourceRoot + '/' : '';
14
15 return (source) => resolveUri(prefix + (source || ''), from);
16}
node_modules/@jridgewell/trace-mapping/src/sort.ts +45 -0
……@@ -0,0 +1,45 @@
1import { COLUMN } from './sourcemap-segment';
2
3import type { ReverseSegment, SourceMapSegment } from './sourcemap-segment';
4
5export default function maybeSort(
6 mappings: SourceMapSegment[][],
7 owned: boolean,
8): SourceMapSegment[][] {
9 const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
10 if (unsortedIndex === mappings.length) return mappings;
11
12 // If we own the array (meaning we parsed it from JSON), then we're free to directly mutate it. If
13 // not, we do not want to modify the consumer's input array.
14 if (!owned) mappings = mappings.slice();
15
16 for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
17 mappings[i] = sortSegments(mappings[i], owned);
18 }
19 return mappings;
20}
21
22function nextUnsortedSegmentLine(mappings: SourceMapSegment[][], start: number): number {
23 for (let i = start; i < mappings.length; i++) {
24 if (!isSorted(mappings[i])) return i;
25 }
26 return mappings.length;
27}
28
29function isSorted(line: SourceMapSegment[]): boolean {
30 for (let j = 1; j < line.length; j++) {
31 if (line[j][COLUMN] < line[j - 1][COLUMN]) {
32 return false;
33 }
34 }
35 return true;
36}
37
38function sortSegments(line: SourceMapSegment[], owned: boolean): SourceMapSegment[] {
39 if (!owned) line = line.slice();
40 return line.sort(sortComparator);
41}
42
43export function sortComparator<T extends SourceMapSegment | ReverseSegment>(a: T, b: T): number {
44 return a[COLUMN] - b[COLUMN];
45}
node_modules/@jridgewell/trace-mapping/src/sourcemap-segment.ts +23 -0
……@@ -0,0 +1,23 @@
1type GeneratedColumn = number;
2type SourcesIndex = number;
3type SourceLine = number;
4type SourceColumn = number;
5type NamesIndex = number;
6
7type GeneratedLine = number;
8
9export type SourceMapSegment =
10 | [GeneratedColumn]
11 | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn]
12 | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
13
14export type ReverseSegment = [SourceColumn, GeneratedLine, GeneratedColumn];
15
16export const COLUMN = 0;
17export const SOURCES_INDEX = 1;
18export const SOURCE_LINE = 2;
19export const SOURCE_COLUMN = 3;
20export const NAMES_INDEX = 4;
21
22export const REV_GENERATED_LINE = 1;
23export const REV_GENERATED_COLUMN = 2;
node_modules/@jridgewell/trace-mapping/src/strip-filename.ts +8 -0
……@@ -0,0 +1,8 @@
1/**
2 * Removes everything after the last "/", but leaves the slash.
3 */
4export default function stripFilename(path: string | undefined | null): string {
5 if (!path) return '';
6 const index = path.lastIndexOf('/');
7 return path.slice(0, index + 1);
8}
node_modules/@jridgewell/trace-mapping/src/trace-mapping.ts +502 -0
……@@ -0,0 +1,502 @@
1import { encode, decode } from '@jridgewell/sourcemap-codec';
2
3import resolver from './resolve';
4import maybeSort from './sort';
5import buildBySources from './by-source';
6import {
7 memoizedState,
8 memoizedBinarySearch,
9 upperBound,
10 lowerBound,
11 found as bsFound,
12} from './binary-search';
13import {
14 COLUMN,
15 SOURCES_INDEX,
16 SOURCE_LINE,
17 SOURCE_COLUMN,
18 NAMES_INDEX,
19 REV_GENERATED_LINE,
20 REV_GENERATED_COLUMN,
21} from './sourcemap-segment';
22import { parse } from './types';
23
24import type { SourceMapSegment, ReverseSegment } from './sourcemap-segment';
25import type {
26 SourceMapV3,
27 DecodedSourceMap,
28 EncodedSourceMap,
29 InvalidOriginalMapping,
30 OriginalMapping,
31 InvalidGeneratedMapping,
32 GeneratedMapping,
33 SourceMapInput,
34 Needle,
35 SourceNeedle,
36 SourceMap,
37 EachMapping,
38 Bias,
39 XInput,
40 SectionedSourceMap,
41 Ro,
42} from './types';
43import type { Source } from './by-source';
44import type { MemoState } from './binary-search';
45
46export type { SourceMapSegment } from './sourcemap-segment';
47export type {
48 SourceMap,
49 DecodedSourceMap,
50 EncodedSourceMap,
51 Section,
52 SectionedSourceMap,
53 SourceMapV3,
54 Bias,
55 EachMapping,
56 GeneratedMapping,
57 InvalidGeneratedMapping,
58 InvalidOriginalMapping,
59 Needle,
60 OriginalMapping,
61 OriginalMapping as Mapping,
62 SectionedSourceMapInput,
63 SourceMapInput,
64 SourceNeedle,
65 XInput,
66 EncodedSourceMapXInput,
67 DecodedSourceMapXInput,
68 SectionedSourceMapXInput,
69 SectionXInput,
70} from './types';
71
72interface PublicMap {
73 _encoded: TraceMap['_encoded'];
74 _decoded: TraceMap['_decoded'];
75 _decodedMemo: TraceMap['_decodedMemo'];
76 _bySources: TraceMap['_bySources'];
77 _bySourceMemos: TraceMap['_bySourceMemos'];
78}
79
80const LINE_GTR_ZERO = '`line` must be greater than 0 (lines start at line 1)';
81const COL_GTR_EQ_ZERO = '`column` must be greater than or equal to 0 (columns start at column 0)';
82
83export const LEAST_UPPER_BOUND = -1;
84export const GREATEST_LOWER_BOUND = 1;
85
86export { FlattenMap, FlattenMap as AnyMap } from './flatten-map';
87
88export class TraceMap implements SourceMap {
89 declare version: SourceMapV3['version'];
90 declare file: SourceMapV3['file'];
91 declare names: SourceMapV3['names'];
92 declare sourceRoot: SourceMapV3['sourceRoot'];
93 declare sources: SourceMapV3['sources'];
94 declare sourcesContent: SourceMapV3['sourcesContent'];
95 declare ignoreList: SourceMapV3['ignoreList'];
96
97 declare resolvedSources: string[];
98 declare private _encoded: string | undefined;
99
100 declare private _decoded: SourceMapSegment[][] | undefined;
101 declare private _decodedMemo: MemoState;
102
103 declare private _bySources: Source[] | undefined;
104 declare private _bySourceMemos: MemoState[] | undefined;
105
106 constructor(map: Ro<SourceMapInput>, mapUrl?: string | null) {
107 const isString = typeof map === 'string';
108 if (!isString && (map as unknown as { _decodedMemo: any })._decodedMemo) return map as TraceMap;
109
110 const parsed = parse(map as Exclude<SourceMapInput, TraceMap>);
111
112 const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
113 this.version = version;
114 this.file = file;
115 this.names = names || [];
116 this.sourceRoot = sourceRoot;
117 this.sources = sources;
118 this.sourcesContent = sourcesContent;
119 this.ignoreList = parsed.ignoreList || (parsed as XInput).x_google_ignoreList || undefined;
120
121 const resolve = resolver(mapUrl, sourceRoot);
122 this.resolvedSources = sources.map(resolve);
123
124 const { mappings } = parsed;
125 if (typeof mappings === 'string') {
126 this._encoded = mappings;
127 this._decoded = undefined;
128 } else if (Array.isArray(mappings)) {
129 this._encoded = undefined;
130 this._decoded = maybeSort(mappings, isString);
131 } else if ((parsed as unknown as SectionedSourceMap).sections) {
132 throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`);
133 } else {
134 throw new Error(`invalid source map: ${JSON.stringify(parsed)}`);
135 }
136
137 this._decodedMemo = memoizedState();
138 this._bySources = undefined;
139 this._bySourceMemos = undefined;
140 }
141}
142
143/**
144 * Typescript doesn't allow friend access to private fields, so this just casts the map into a type
145 * with public access modifiers.
146 */
147function cast(map: unknown): PublicMap {
148 return map as any;
149}
150
151/**
152 * Returns the encoded (VLQ string) form of the SourceMap's mappings field.
153 */
154export function encodedMappings(map: TraceMap): EncodedSourceMap['mappings'] {
155 return (cast(map)._encoded ??= encode(cast(map)._decoded!));
156}
157
158/**
159 * Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
160 */
161export function decodedMappings(map: TraceMap): Readonly<DecodedSourceMap['mappings']> {
162 return (cast(map)._decoded ||= decode(cast(map)._encoded!));
163}
164
165/**
166 * A low-level API to find the segment associated with a generated line/column (think, from a
167 * stack trace). Line and column here are 0-based, unlike `originalPositionFor`.
168 */
169export function traceSegment(
170 map: TraceMap,
171 line: number,
172 column: number,
173): Readonly<SourceMapSegment> | null {
174 const decoded = decodedMappings(map);
175
176 // It's common for parent source maps to have pointers to lines that have no
177 // mapping (like a "//# sourceMappingURL=") at the end of the child file.
178 if (line >= decoded.length) return null;
179
180 const segments = decoded[line];
181 const index = traceSegmentInternal(
182 segments,
183 cast(map)._decodedMemo,
184 line,
185 column,
186 GREATEST_LOWER_BOUND,
187 );
188
189 return index === -1 ? null : segments[index];
190}
191
192/**
193 * A higher-level API to find the source/line/column associated with a generated line/column
194 * (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
195 * `source-map` library.
196 */
197export function originalPositionFor(
198 map: TraceMap,
199 needle: Needle,
200): OriginalMapping | InvalidOriginalMapping {
201 let { line, column, bias } = needle;
202 line--;
203 if (line < 0) throw new Error(LINE_GTR_ZERO);
204 if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
205
206 const decoded = decodedMappings(map);
207
208 // It's common for parent source maps to have pointers to lines that have no
209 // mapping (like a "//# sourceMappingURL=") at the end of the child file.
210 if (line >= decoded.length) return OMapping(null, null, null, null);
211
212 const segments = decoded[line];
213 const index = traceSegmentInternal(
214 segments,
215 cast(map)._decodedMemo,
216 line,
217 column,
218 bias || GREATEST_LOWER_BOUND,
219 );
220
221 if (index === -1) return OMapping(null, null, null, null);
222
223 const segment = segments[index];
224 if (segment.length === 1) return OMapping(null, null, null, null);
225
226 const { names, resolvedSources } = map;
227 return OMapping(
228 resolvedSources[segment[SOURCES_INDEX]],
229 segment[SOURCE_LINE] + 1,
230 segment[SOURCE_COLUMN],
231 segment.length === 5 ? names[segment[NAMES_INDEX]] : null,
232 );
233}
234
235/**
236 * Finds the generated line/column position of the provided source/line/column source position.
237 */
238export function generatedPositionFor(
239 map: TraceMap,
240 needle: SourceNeedle,
241): GeneratedMapping | InvalidGeneratedMapping {
242 const { source, line, column, bias } = needle;
243 return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
244}
245
246/**
247 * Finds all generated line/column positions of the provided source/line/column source position.
248 */
249export function allGeneratedPositionsFor(map: TraceMap, needle: SourceNeedle): GeneratedMapping[] {
250 const { source, line, column, bias } = needle;
251 // SourceMapConsumer uses LEAST_UPPER_BOUND for some reason, so we follow suit.
252 return generatedPosition(map, source, line, column, bias || LEAST_UPPER_BOUND, true);
253}
254
255/**
256 * Iterates each mapping in generated position order.
257 */
258export function eachMapping(map: TraceMap, cb: (mapping: EachMapping) => void): void {
259 const decoded = decodedMappings(map);
260 const { names, resolvedSources } = map;
261
262 for (let i = 0; i < decoded.length; i++) {
263 const line = decoded[i];
264 for (let j = 0; j < line.length; j++) {
265 const seg = line[j];
266
267 const generatedLine = i + 1;
268 const generatedColumn = seg[0];
269 let source = null;
270 let originalLine = null;
271 let originalColumn = null;
272 let name = null;
273 if (seg.length !== 1) {
274 source = resolvedSources[seg[1]];
275 originalLine = seg[2] + 1;
276 originalColumn = seg[3];
277 }
278 if (seg.length === 5) name = names[seg[4]];
279
280 cb({
281 generatedLine,
282 generatedColumn,
283 source,
284 originalLine,
285 originalColumn,
286 name,
287 } as EachMapping);
288 }
289 }
290}
291
292function sourceIndex(map: TraceMap, source: string): number {
293 const { sources, resolvedSources } = map;
294 let index = sources.indexOf(source);
295 if (index === -1) index = resolvedSources.indexOf(source);
296 return index;
297}
298
299/**
300 * Retrieves the source content for a particular source, if its found. Returns null if not.
301 */
302export function sourceContentFor(map: TraceMap, source: string): string | null {
303 const { sourcesContent } = map;
304 if (sourcesContent == null) return null;
305 const index = sourceIndex(map, source);
306 return index === -1 ? null : sourcesContent[index];
307}
308
309/**
310 * Determines if the source is marked to ignore by the source map.
311 */
312export function isIgnored(map: TraceMap, source: string): boolean {
313 const { ignoreList } = map;
314 if (ignoreList == null) return false;
315 const index = sourceIndex(map, source);
316 return index === -1 ? false : ignoreList.includes(index);
317}
318
319/**
320 * A helper that skips sorting of the input map's mappings array, which can be expensive for larger
321 * maps.
322 */
323export function presortedDecodedMap(map: DecodedSourceMap, mapUrl?: string): TraceMap {
324 const tracer = new TraceMap(clone(map, []), mapUrl);
325 cast(tracer)._decoded = map.mappings;
326 return tracer;
327}
328
329/**
330 * Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
331 * a sourcemap, or to JSON.stringify.
332 */
333export function decodedMap(
334 map: TraceMap,
335): Omit<DecodedSourceMap, 'mappings'> & { mappings: readonly SourceMapSegment[][] } {
336 return clone(map, decodedMappings(map));
337}
338
339/**
340 * Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
341 * a sourcemap, or to JSON.stringify.
342 */
343export function encodedMap(map: TraceMap): EncodedSourceMap {
344 return clone(map, encodedMappings(map));
345}
346
347function clone<T extends string | readonly SourceMapSegment[][]>(
348 map: TraceMap | DecodedSourceMap,
349 mappings: T,
350): T extends string ? EncodedSourceMap : DecodedSourceMap {
351 return {
352 version: map.version,
353 file: map.file,
354 names: map.names,
355 sourceRoot: map.sourceRoot,
356 sources: map.sources,
357 sourcesContent: map.sourcesContent,
358 mappings,
359 ignoreList: map.ignoreList || (map as XInput).x_google_ignoreList,
360 } as any;
361}
362
363function OMapping(source: null, line: null, column: null, name: null): InvalidOriginalMapping;
364function OMapping(
365 source: string,
366 line: number,
367 column: number,
368 name: string | null,
369): OriginalMapping;
370function OMapping(
371 source: string | null,
372 line: number | null,
373 column: number | null,
374 name: string | null,
375): OriginalMapping | InvalidOriginalMapping {
376 return { source, line, column, name } as any;
377}
378
379function GMapping(line: null, column: null): InvalidGeneratedMapping;
380function GMapping(line: number, column: number): GeneratedMapping;
381function GMapping(
382 line: number | null,
383 column: number | null,
384): GeneratedMapping | InvalidGeneratedMapping {
385 return { line, column } as any;
386}
387
388function traceSegmentInternal(
389 segments: SourceMapSegment[],
390 memo: MemoState,
391 line: number,
392 column: number,
393 bias: Bias,
394): number;
395function traceSegmentInternal(
396 segments: ReverseSegment[],
397 memo: MemoState,
398 line: number,
399 column: number,
400 bias: Bias,
401): number;
402function traceSegmentInternal(
403 segments: SourceMapSegment[] | ReverseSegment[],
404 memo: MemoState,
405 line: number,
406 column: number,
407 bias: Bias,
408): number {
409 let index = memoizedBinarySearch(segments, column, memo, line);
410 if (bsFound) {
411 index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
412 } else if (bias === LEAST_UPPER_BOUND) index++;
413
414 if (index === -1 || index === segments.length) return -1;
415 return index;
416}
417
418function sliceGeneratedPositions(
419 segments: ReverseSegment[],
420 memo: MemoState,
421 line: number,
422 column: number,
423 bias: Bias,
424): GeneratedMapping[] {
425 let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND);
426
427 // We ignored the bias when tracing the segment so that we're guarnateed to find the first (in
428 // insertion order) segment that matched. Even if we did respect the bias when tracing, we would
429 // still need to call `lowerBound()` to find the first segment, which is slower than just looking
430 // for the GREATEST_LOWER_BOUND to begin with. The only difference that matters for us is when the
431 // binary search didn't match, in which case GREATEST_LOWER_BOUND just needs to increment to
432 // match LEAST_UPPER_BOUND.
433 if (!bsFound && bias === LEAST_UPPER_BOUND) min++;
434
435 if (min === -1 || min === segments.length) return [];
436
437 // We may have found the segment that started at an earlier column. If this is the case, then we
438 // need to slice all generated segments that match _that_ column, because all such segments span
439 // to our desired column.
440 const matchedColumn = bsFound ? column : segments[min][COLUMN];
441
442 // The binary search is not guaranteed to find the lower bound when a match wasn't found.
443 if (!bsFound) min = lowerBound(segments, matchedColumn, min);
444 const max = upperBound(segments, matchedColumn, min);
445
446 const result = [];
447 for (; min <= max; min++) {
448 const segment = segments[min];
449 result.push(GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]));
450 }
451 return result;
452}
453
454function generatedPosition(
455 map: TraceMap,
456 source: string,
457 line: number,
458 column: number,
459 bias: Bias,
460 all: false,
461): GeneratedMapping | InvalidGeneratedMapping;
462function generatedPosition(
463 map: TraceMap,
464 source: string,
465 line: number,
466 column: number,
467 bias: Bias,
468 all: true,
469): GeneratedMapping[];
470function generatedPosition(
471 map: TraceMap,
472 source: string,
473 line: number,
474 column: number,
475 bias: Bias,
476 all: boolean,
477): GeneratedMapping | InvalidGeneratedMapping | GeneratedMapping[] {
478 line--;
479 if (line < 0) throw new Error(LINE_GTR_ZERO);
480 if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
481
482 const { sources, resolvedSources } = map;
483 let sourceIndex = sources.indexOf(source);
484 if (sourceIndex === -1) sourceIndex = resolvedSources.indexOf(source);
485 if (sourceIndex === -1) return all ? [] : GMapping(null, null);
486
487 const bySourceMemos = (cast(map)._bySourceMemos ||= sources.map(memoizedState));
488 const generated = (cast(map)._bySources ||= buildBySources(decodedMappings(map), bySourceMemos));
489
490 const segments = generated[sourceIndex][line];
491 if (segments == null) return all ? [] : GMapping(null, null);
492
493 const memo = bySourceMemos[sourceIndex];
494
495 if (all) return sliceGeneratedPositions(segments, memo, line, column, bias);
496
497 const index = traceSegmentInternal(segments, memo, line, column, bias);
498 if (index === -1) return GMapping(null, null);
499
500 const segment = segments[index];
501 return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
502}
node_modules/@jridgewell/trace-mapping/src/types.ts +114 -0
……@@ -0,0 +1,114 @@
1import type { SourceMapSegment } from './sourcemap-segment';
2import type { GREATEST_LOWER_BOUND, LEAST_UPPER_BOUND, TraceMap } from './trace-mapping';
3
4export interface SourceMapV3 {
5 file?: string | null;
6 names: string[];
7 sourceRoot?: string;
8 sources: (string | null)[];
9 sourcesContent?: (string | null)[];
10 version: 3;
11 ignoreList?: number[];
12}
13
14export interface EncodedSourceMap extends SourceMapV3 {
15 mappings: string;
16}
17
18export interface DecodedSourceMap extends SourceMapV3 {
19 mappings: SourceMapSegment[][];
20}
21
22export interface Section {
23 offset: { line: number; column: number };
24 map: EncodedSourceMap | DecodedSourceMap | SectionedSourceMap;
25}
26
27export interface SectionedSourceMap {
28 file?: string | null;
29 sections: Section[];
30 version: 3;
31}
32
33export type OriginalMapping = {
34 source: string | null;
35 line: number;
36 column: number;
37 name: string | null;
38};
39
40export type InvalidOriginalMapping = {
41 source: null;
42 line: null;
43 column: null;
44 name: null;
45};
46
47export type GeneratedMapping = {
48 line: number;
49 column: number;
50};
51export type InvalidGeneratedMapping = {
52 line: null;
53 column: null;
54};
55
56export type Bias = typeof GREATEST_LOWER_BOUND | typeof LEAST_UPPER_BOUND;
57
58export type XInput = { x_google_ignoreList?: SourceMapV3['ignoreList'] };
59export type EncodedSourceMapXInput = EncodedSourceMap & XInput;
60export type DecodedSourceMapXInput = DecodedSourceMap & XInput;
61export type SectionedSourceMapXInput = Omit<SectionedSourceMap, 'sections'> & {
62 sections: SectionXInput[];
63};
64export type SectionXInput = Omit<Section, 'map'> & {
65 map: SectionedSourceMapInput;
66};
67
68export type SourceMapInput = string | EncodedSourceMapXInput | DecodedSourceMapXInput | TraceMap;
69export type SectionedSourceMapInput = SourceMapInput | SectionedSourceMapXInput;
70
71export type Needle = { line: number; column: number; bias?: Bias };
72export type SourceNeedle = { source: string; line: number; column: number; bias?: Bias };
73
74export type EachMapping =
75 | {
76 generatedLine: number;
77 generatedColumn: number;
78 source: null;
79 originalLine: null;
80 originalColumn: null;
81 name: null;
82 }
83 | {
84 generatedLine: number;
85 generatedColumn: number;
86 source: string | null;
87 originalLine: number;
88 originalColumn: number;
89 name: string | null;
90 };
91
92export abstract class SourceMap {
93 declare version: SourceMapV3['version'];
94 declare file: SourceMapV3['file'];
95 declare names: SourceMapV3['names'];
96 declare sourceRoot: SourceMapV3['sourceRoot'];
97 declare sources: SourceMapV3['sources'];
98 declare sourcesContent: SourceMapV3['sourcesContent'];
99 declare resolvedSources: SourceMapV3['sources'];
100 declare ignoreList: SourceMapV3['ignoreList'];
101}
102
103export type Ro<T> =
104 T extends Array<infer V>
105 ? V[] | Readonly<V[]> | RoArray<V> | Readonly<RoArray<V>>
106 : T extends object
107 ? T | Readonly<T> | RoObject<T> | Readonly<RoObject<T>>
108 : T;
109type RoArray<T> = Ro<T>[];
110type RoObject<T> = { [K in keyof T]: T[K] | Ro<T[K]> };
111
112export function parse<T>(map: T): Exclude<T, string> {
113 return typeof map === 'string' ? JSON.parse(map) : (map as Exclude<T, string>);
114}
node_modules/@jridgewell/trace-mapping/types/binary-search.d.cts +33 -0
……@@ -0,0 +1,33 @@
1import type { SourceMapSegment, ReverseSegment } from './sourcemap-segment.cts';
2export type MemoState = {
3 lastKey: number;
4 lastNeedle: number;
5 lastIndex: number;
6};
7export declare let found: boolean;
8/**
9 * A binary search implementation that returns the index if a match is found.
10 * If no match is found, then the left-index (the index associated with the item that comes just
11 * before the desired index) is returned. To maintain proper sort order, a splice would happen at
12 * the next index:
13 *
14 * ```js
15 * const array = [1, 3];
16 * const needle = 2;
17 * const index = binarySearch(array, needle, (item, needle) => item - needle);
18 *
19 * assert.equal(index, 0);
20 * array.splice(index + 1, 0, needle);
21 * assert.deepEqual(array, [1, 2, 3]);
22 * ```
23 */
24export declare function binarySearch(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, low: number, high: number): number;
25export declare function upperBound(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, index: number): number;
26export declare function lowerBound(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, index: number): number;
27export declare function memoizedState(): MemoState;
28/**
29 * This overly complicated beast is just to record the last tested line/column and the resulting
30 * index, allowing us to skip a few tests if mappings are monotonically increasing.
31 */
32export declare function memoizedBinarySearch(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, state: MemoState, key: number): number;
33//# sourceMappingURL=binary-search.d.ts.map
node_modules/@jridgewell/trace-mapping/types/binary-search.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"binary-search.d.ts","sourceRoot":"","sources":["../src/binary-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG5E,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,eAAO,IAAI,KAAK,SAAQ,CAAC;AAEzB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,MAAM,CAmBR;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,MAAM,CAKR;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,MAAM,CAKR;AAED,wBAAgB,aAAa,IAAI,SAAS,CAMzC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,MAAM,GACV,MAAM,CAsBR"}
node_modules/@jridgewell/trace-mapping/types/binary-search.d.mts +33 -0
……@@ -0,0 +1,33 @@
1import type { SourceMapSegment, ReverseSegment } from './sourcemap-segment.mts';
2export type MemoState = {
3 lastKey: number;
4 lastNeedle: number;
5 lastIndex: number;
6};
7export declare let found: boolean;
8/**
9 * A binary search implementation that returns the index if a match is found.
10 * If no match is found, then the left-index (the index associated with the item that comes just
11 * before the desired index) is returned. To maintain proper sort order, a splice would happen at
12 * the next index:
13 *
14 * ```js
15 * const array = [1, 3];
16 * const needle = 2;
17 * const index = binarySearch(array, needle, (item, needle) => item - needle);
18 *
19 * assert.equal(index, 0);
20 * array.splice(index + 1, 0, needle);
21 * assert.deepEqual(array, [1, 2, 3]);
22 * ```
23 */
24export declare function binarySearch(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, low: number, high: number): number;
25export declare function upperBound(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, index: number): number;
26export declare function lowerBound(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, index: number): number;
27export declare function memoizedState(): MemoState;
28/**
29 * This overly complicated beast is just to record the last tested line/column and the resulting
30 * index, allowing us to skip a few tests if mappings are monotonically increasing.
31 */
32export declare function memoizedBinarySearch(haystack: SourceMapSegment[] | ReverseSegment[], needle: number, state: MemoState, key: number): number;
33//# sourceMappingURL=binary-search.d.ts.map
node_modules/@jridgewell/trace-mapping/types/binary-search.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"binary-search.d.ts","sourceRoot":"","sources":["../src/binary-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG5E,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,eAAO,IAAI,KAAK,SAAQ,CAAC;AAEzB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,MAAM,CAmBR;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,MAAM,CAKR;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,MAAM,CAKR;AAED,wBAAgB,aAAa,IAAI,SAAS,CAMzC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,EAC/C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,MAAM,GACV,MAAM,CAsBR"}
node_modules/@jridgewell/trace-mapping/types/by-source.d.cts +4 -0
……@@ -0,0 +1,4 @@
1import type { ReverseSegment, SourceMapSegment } from './sourcemap-segment.cts';
2export type Source = ReverseSegment[][];
3export = function buildBySources(decoded: readonly SourceMapSegment[][], memos: unknown[]): Source[];
4//# sourceMappingURL=by-source.d.ts.map
node_modules/@jridgewell/trace-mapping/types/by-source.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"by-source.d.ts","sourceRoot":"","sources":["../src/by-source.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,MAAM,MAAM,GAAG,cAAc,EAAE,EAAE,CAAC;AAIxC,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EAAE,EACtC,KAAK,EAAE,OAAO,EAAE,GACf,MAAM,EAAE,CA4BV"}
node_modules/@jridgewell/trace-mapping/types/by-source.d.mts +4 -0
……@@ -0,0 +1,4 @@
1import type { ReverseSegment, SourceMapSegment } from './sourcemap-segment.mts';
2export type Source = ReverseSegment[][];
3export default function buildBySources(decoded: readonly SourceMapSegment[][], memos: unknown[]): Source[];
4//# sourceMappingURL=by-source.d.ts.map
node_modules/@jridgewell/trace-mapping/types/by-source.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"by-source.d.ts","sourceRoot":"","sources":["../src/by-source.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,MAAM,MAAM,GAAG,cAAc,EAAE,EAAE,CAAC;AAIxC,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EAAE,EACtC,KAAK,EAAE,OAAO,EAAE,GACf,MAAM,EAAE,CA4BV"}
node_modules/@jridgewell/trace-mapping/types/flatten-map.d.cts +9 -0
……@@ -0,0 +1,9 @@
1import { TraceMap } from './trace-mapping.cts';
2import type { SectionedSourceMapInput, Ro } from './types.cts';
3type FlattenMap = {
4 new (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
5 (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
6};
7export declare const FlattenMap: FlattenMap;
8export {};
9//# sourceMappingURL=flatten-map.d.ts.map
node_modules/@jridgewell/trace-mapping/types/flatten-map.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"flatten-map.d.ts","sourceRoot":"","sources":["../src/flatten-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAwC,MAAM,iBAAiB,CAAC;AAUjF,OAAO,KAAK,EAKV,uBAAuB,EAEvB,EAAE,EACH,MAAM,SAAS,CAAC;AAGjB,KAAK,UAAU,GAAG;IAChB,KAAK,GAAG,EAAE,EAAE,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC;IACzE,CAAC,GAAG,EAAE,EAAE,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC;CACtE,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,UAsCV,CAAC"}
node_modules/@jridgewell/trace-mapping/types/flatten-map.d.mts +9 -0
……@@ -0,0 +1,9 @@
1import { TraceMap } from './trace-mapping.mts';
2import type { SectionedSourceMapInput, Ro } from './types.mts';
3type FlattenMap = {
4 new (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
5 (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
6};
7export declare const FlattenMap: FlattenMap;
8export {};
9//# sourceMappingURL=flatten-map.d.ts.map
node_modules/@jridgewell/trace-mapping/types/flatten-map.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"flatten-map.d.ts","sourceRoot":"","sources":["../src/flatten-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAwC,MAAM,iBAAiB,CAAC;AAUjF,OAAO,KAAK,EAKV,uBAAuB,EAEvB,EAAE,EACH,MAAM,SAAS,CAAC;AAGjB,KAAK,UAAU,GAAG;IAChB,KAAK,GAAG,EAAE,EAAE,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC;IACzE,CAAC,GAAG,EAAE,EAAE,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC;CACtE,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,UAsCV,CAAC"}
node_modules/@jridgewell/trace-mapping/types/resolve.d.cts +4 -0
……@@ -0,0 +1,4 @@
1type Resolve = (source: string | null) => string;
2export = function resolver(mapUrl: string | null | undefined, sourceRoot: string | undefined): Resolve;
3export {};
4//# sourceMappingURL=resolve.d.ts.map
node_modules/@jridgewell/trace-mapping/types/resolve.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAGA,KAAK,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC;AACjD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAQT"}
node_modules/@jridgewell/trace-mapping/types/resolve.d.mts +4 -0
……@@ -0,0 +1,4 @@
1type Resolve = (source: string | null) => string;
2export default function resolver(mapUrl: string | null | undefined, sourceRoot: string | undefined): Resolve;
3export {};
4//# sourceMappingURL=resolve.d.ts.map
node_modules/@jridgewell/trace-mapping/types/resolve.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAGA,KAAK,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC;AACjD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAQT"}
node_modules/@jridgewell/trace-mapping/types/sort.d.cts +4 -0
……@@ -0,0 +1,4 @@
1import type { ReverseSegment, SourceMapSegment } from './sourcemap-segment.cts';
2export = function maybeSort(mappings: SourceMapSegment[][], owned: boolean): SourceMapSegment[][];
3export declare function sortComparator<T extends SourceMapSegment | ReverseSegment>(a: T, b: T): number;
4//# sourceMappingURL=sort.d.ts.map
node_modules/@jridgewell/trace-mapping/types/sort.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../src/sort.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,gBAAgB,EAAE,EAAE,EAC9B,KAAK,EAAE,OAAO,GACb,gBAAgB,EAAE,EAAE,CAYtB;AAuBD,wBAAgB,cAAc,CAAC,CAAC,SAAS,gBAAgB,GAAG,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,MAAM,CAE9F"}
node_modules/@jridgewell/trace-mapping/types/sort.d.mts +4 -0
……@@ -0,0 +1,4 @@
1import type { ReverseSegment, SourceMapSegment } from './sourcemap-segment.mts';
2export default function maybeSort(mappings: SourceMapSegment[][], owned: boolean): SourceMapSegment[][];
3export declare function sortComparator<T extends SourceMapSegment | ReverseSegment>(a: T, b: T): number;
4//# sourceMappingURL=sort.d.ts.map
node_modules/@jridgewell/trace-mapping/types/sort.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../src/sort.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,gBAAgB,EAAE,EAAE,EAC9B,KAAK,EAAE,OAAO,GACb,gBAAgB,EAAE,EAAE,CAYtB;AAuBD,wBAAgB,cAAc,CAAC,CAAC,SAAS,gBAAgB,GAAG,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,MAAM,CAE9F"}
node_modules/@jridgewell/trace-mapping/types/sourcemap-segment.d.cts +17 -0
……@@ -0,0 +1,17 @@
1type GeneratedColumn = number;
2type SourcesIndex = number;
3type SourceLine = number;
4type SourceColumn = number;
5type NamesIndex = number;
6type GeneratedLine = number;
7export type SourceMapSegment = [GeneratedColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
8export type ReverseSegment = [SourceColumn, GeneratedLine, GeneratedColumn];
9export declare const COLUMN = 0;
10export declare const SOURCES_INDEX = 1;
11export declare const SOURCE_LINE = 2;
12export declare const SOURCE_COLUMN = 3;
13export declare const NAMES_INDEX = 4;
14export declare const REV_GENERATED_LINE = 1;
15export declare const REV_GENERATED_COLUMN = 2;
16export {};
17//# sourceMappingURL=sourcemap-segment.d.ts.map
node_modules/@jridgewell/trace-mapping/types/sourcemap-segment.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"sourcemap-segment.d.ts","sourceRoot":"","sources":["../src/sourcemap-segment.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG,MAAM,CAAC;AAC9B,KAAK,YAAY,GAAG,MAAM,CAAC;AAC3B,KAAK,UAAU,GAAG,MAAM,CAAC;AACzB,KAAK,YAAY,GAAG,MAAM,CAAC;AAC3B,KAAK,UAAU,GAAG,MAAM,CAAC;AAEzB,KAAK,aAAa,GAAG,MAAM,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GACxB,CAAC,eAAe,CAAC,GACjB,CAAC,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,CAAC,GACzD,CAAC,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;AAE1E,MAAM,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC;AAE5E,eAAO,MAAM,MAAM,IAAI,CAAC;AACxB,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,oBAAoB,IAAI,CAAC"}
node_modules/@jridgewell/trace-mapping/types/sourcemap-segment.d.mts +17 -0
……@@ -0,0 +1,17 @@
1type GeneratedColumn = number;
2type SourcesIndex = number;
3type SourceLine = number;
4type SourceColumn = number;
5type NamesIndex = number;
6type GeneratedLine = number;
7export type SourceMapSegment = [GeneratedColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
8export type ReverseSegment = [SourceColumn, GeneratedLine, GeneratedColumn];
9export declare const COLUMN = 0;
10export declare const SOURCES_INDEX = 1;
11export declare const SOURCE_LINE = 2;
12export declare const SOURCE_COLUMN = 3;
13export declare const NAMES_INDEX = 4;
14export declare const REV_GENERATED_LINE = 1;
15export declare const REV_GENERATED_COLUMN = 2;
16export {};
17//# sourceMappingURL=sourcemap-segment.d.ts.map
node_modules/@jridgewell/trace-mapping/types/sourcemap-segment.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"sourcemap-segment.d.ts","sourceRoot":"","sources":["../src/sourcemap-segment.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG,MAAM,CAAC;AAC9B,KAAK,YAAY,GAAG,MAAM,CAAC;AAC3B,KAAK,UAAU,GAAG,MAAM,CAAC;AACzB,KAAK,YAAY,GAAG,MAAM,CAAC;AAC3B,KAAK,UAAU,GAAG,MAAM,CAAC;AAEzB,KAAK,aAAa,GAAG,MAAM,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GACxB,CAAC,eAAe,CAAC,GACjB,CAAC,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,CAAC,GACzD,CAAC,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;AAE1E,MAAM,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC;AAE5E,eAAO,MAAM,MAAM,IAAI,CAAC;AACxB,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,oBAAoB,IAAI,CAAC"}
node_modules/@jridgewell/trace-mapping/types/strip-filename.d.cts +5 -0
……@@ -0,0 +1,5 @@
1/**
2 * Removes everything after the last "/", but leaves the slash.
3 */
4export = function stripFilename(path: string | undefined | null): string;
5//# sourceMappingURL=strip-filename.d.ts.map
node_modules/@jridgewell/trace-mapping/types/strip-filename.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"strip-filename.d.ts","sourceRoot":"","sources":["../src/strip-filename.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAI7E"}
node_modules/@jridgewell/trace-mapping/types/strip-filename.d.mts +5 -0
……@@ -0,0 +1,5 @@
1/**
2 * Removes everything after the last "/", but leaves the slash.
3 */
4export default function stripFilename(path: string | undefined | null): string;
5//# sourceMappingURL=strip-filename.d.ts.map
node_modules/@jridgewell/trace-mapping/types/strip-filename.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"strip-filename.d.ts","sourceRoot":"","sources":["../src/strip-filename.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAI7E"}
node_modules/@jridgewell/trace-mapping/types/trace-mapping.d.cts +80 -0
……@@ -0,0 +1,80 @@
1import type { SourceMapSegment } from './sourcemap-segment.cts';
2import type { SourceMapV3, DecodedSourceMap, EncodedSourceMap, InvalidOriginalMapping, OriginalMapping, InvalidGeneratedMapping, GeneratedMapping, SourceMapInput, Needle, SourceNeedle, SourceMap, EachMapping, Ro } from './types.cts';
3export type { SourceMapSegment } from './sourcemap-segment.cts';
4export type { SourceMap, DecodedSourceMap, EncodedSourceMap, Section, SectionedSourceMap, SourceMapV3, Bias, EachMapping, GeneratedMapping, InvalidGeneratedMapping, InvalidOriginalMapping, Needle, OriginalMapping, OriginalMapping as Mapping, SectionedSourceMapInput, SourceMapInput, SourceNeedle, XInput, EncodedSourceMapXInput, DecodedSourceMapXInput, SectionedSourceMapXInput, SectionXInput, } from './types.cts';
5export declare const LEAST_UPPER_BOUND = -1;
6export declare const GREATEST_LOWER_BOUND = 1;
7export { FlattenMap, FlattenMap as AnyMap } from './flatten-map.cts';
8export declare class TraceMap implements SourceMap {
9 version: SourceMapV3['version'];
10 file: SourceMapV3['file'];
11 names: SourceMapV3['names'];
12 sourceRoot: SourceMapV3['sourceRoot'];
13 sources: SourceMapV3['sources'];
14 sourcesContent: SourceMapV3['sourcesContent'];
15 ignoreList: SourceMapV3['ignoreList'];
16 resolvedSources: string[];
17 private _encoded;
18 private _decoded;
19 private _decodedMemo;
20 private _bySources;
21 private _bySourceMemos;
22 constructor(map: Ro<SourceMapInput>, mapUrl?: string | null);
23}
24/**
25 * Returns the encoded (VLQ string) form of the SourceMap's mappings field.
26 */
27export declare function encodedMappings(map: TraceMap): EncodedSourceMap['mappings'];
28/**
29 * Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
30 */
31export declare function decodedMappings(map: TraceMap): Readonly<DecodedSourceMap['mappings']>;
32/**
33 * A low-level API to find the segment associated with a generated line/column (think, from a
34 * stack trace). Line and column here are 0-based, unlike `originalPositionFor`.
35 */
36export declare function traceSegment(map: TraceMap, line: number, column: number): Readonly<SourceMapSegment> | null;
37/**
38 * A higher-level API to find the source/line/column associated with a generated line/column
39 * (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
40 * `source-map` library.
41 */
42export declare function originalPositionFor(map: TraceMap, needle: Needle): OriginalMapping | InvalidOriginalMapping;
43/**
44 * Finds the generated line/column position of the provided source/line/column source position.
45 */
46export declare function generatedPositionFor(map: TraceMap, needle: SourceNeedle): GeneratedMapping | InvalidGeneratedMapping;
47/**
48 * Finds all generated line/column positions of the provided source/line/column source position.
49 */
50export declare function allGeneratedPositionsFor(map: TraceMap, needle: SourceNeedle): GeneratedMapping[];
51/**
52 * Iterates each mapping in generated position order.
53 */
54export declare function eachMapping(map: TraceMap, cb: (mapping: EachMapping) => void): void;
55/**
56 * Retrieves the source content for a particular source, if its found. Returns null if not.
57 */
58export declare function sourceContentFor(map: TraceMap, source: string): string | null;
59/**
60 * Determines if the source is marked to ignore by the source map.
61 */
62export declare function isIgnored(map: TraceMap, source: string): boolean;
63/**
64 * A helper that skips sorting of the input map's mappings array, which can be expensive for larger
65 * maps.
66 */
67export declare function presortedDecodedMap(map: DecodedSourceMap, mapUrl?: string): TraceMap;
68/**
69 * Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
70 * a sourcemap, or to JSON.stringify.
71 */
72export declare function decodedMap(map: TraceMap): Omit<DecodedSourceMap, 'mappings'> & {
73 mappings: readonly SourceMapSegment[][];
74};
75/**
76 * Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
77 * a sourcemap, or to JSON.stringify.
78 */
79export declare function encodedMap(map: TraceMap): EncodedSourceMap;
80//# sourceMappingURL=trace-mapping.d.ts.map
node_modules/@jridgewell/trace-mapping/types/trace-mapping.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"trace-mapping.d.ts","sourceRoot":"","sources":["../src/trace-mapping.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,EACd,MAAM,EACN,YAAY,EACZ,SAAS,EACT,WAAW,EAIX,EAAE,EACH,MAAM,SAAS,CAAC;AAIjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,WAAW,EACX,IAAI,EACJ,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,MAAM,EACN,eAAe,EACf,eAAe,IAAI,OAAO,EAC1B,uBAAuB,EACvB,cAAc,EACd,YAAY,EACZ,MAAM,EACN,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,aAAa,GACd,MAAM,SAAS,CAAC;AAajB,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,UAAU,IAAI,MAAM,EAAE,MAAM,eAAe,CAAC;AAEjE,qBAAa,QAAS,YAAW,SAAS;IAChC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IACtC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC9C,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAEtC,eAAe,EAAE,MAAM,EAAE,CAAC;IAClC,QAAgB,QAAQ,CAAqB;IAE7C,QAAgB,QAAQ,CAAmC;IAC3D,QAAgB,YAAY,CAAY;IAExC,QAAgB,UAAU,CAAuB;IACjD,QAAgB,cAAc,CAA0B;gBAE5C,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;CAmC5D;AAUD;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAE3E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,QAAQ,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAErF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAiBnC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,MAAM,GACb,eAAe,GAAG,sBAAsB,CAiC1C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,YAAY,GACnB,gBAAgB,GAAG,uBAAuB,CAG5C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE,CAIhG;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,CAgCnF;AASD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7E;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKhE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAIpF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,QAAQ,GACZ,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,EAAE,SAAS,gBAAgB,EAAE,EAAE,CAAA;CAAE,CAElF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,QAAQ,GAAG,gBAAgB,CAE1D"}
node_modules/@jridgewell/trace-mapping/types/trace-mapping.d.mts +80 -0
……@@ -0,0 +1,80 @@
1import type { SourceMapSegment } from './sourcemap-segment.mts';
2import type { SourceMapV3, DecodedSourceMap, EncodedSourceMap, InvalidOriginalMapping, OriginalMapping, InvalidGeneratedMapping, GeneratedMapping, SourceMapInput, Needle, SourceNeedle, SourceMap, EachMapping, Ro } from './types.mts';
3export type { SourceMapSegment } from './sourcemap-segment.mts';
4export type { SourceMap, DecodedSourceMap, EncodedSourceMap, Section, SectionedSourceMap, SourceMapV3, Bias, EachMapping, GeneratedMapping, InvalidGeneratedMapping, InvalidOriginalMapping, Needle, OriginalMapping, OriginalMapping as Mapping, SectionedSourceMapInput, SourceMapInput, SourceNeedle, XInput, EncodedSourceMapXInput, DecodedSourceMapXInput, SectionedSourceMapXInput, SectionXInput, } from './types.mts';
5export declare const LEAST_UPPER_BOUND = -1;
6export declare const GREATEST_LOWER_BOUND = 1;
7export { FlattenMap, FlattenMap as AnyMap } from './flatten-map.mts';
8export declare class TraceMap implements SourceMap {
9 version: SourceMapV3['version'];
10 file: SourceMapV3['file'];
11 names: SourceMapV3['names'];
12 sourceRoot: SourceMapV3['sourceRoot'];
13 sources: SourceMapV3['sources'];
14 sourcesContent: SourceMapV3['sourcesContent'];
15 ignoreList: SourceMapV3['ignoreList'];
16 resolvedSources: string[];
17 private _encoded;
18 private _decoded;
19 private _decodedMemo;
20 private _bySources;
21 private _bySourceMemos;
22 constructor(map: Ro<SourceMapInput>, mapUrl?: string | null);
23}
24/**
25 * Returns the encoded (VLQ string) form of the SourceMap's mappings field.
26 */
27export declare function encodedMappings(map: TraceMap): EncodedSourceMap['mappings'];
28/**
29 * Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
30 */
31export declare function decodedMappings(map: TraceMap): Readonly<DecodedSourceMap['mappings']>;
32/**
33 * A low-level API to find the segment associated with a generated line/column (think, from a
34 * stack trace). Line and column here are 0-based, unlike `originalPositionFor`.
35 */
36export declare function traceSegment(map: TraceMap, line: number, column: number): Readonly<SourceMapSegment> | null;
37/**
38 * A higher-level API to find the source/line/column associated with a generated line/column
39 * (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
40 * `source-map` library.
41 */
42export declare function originalPositionFor(map: TraceMap, needle: Needle): OriginalMapping | InvalidOriginalMapping;
43/**
44 * Finds the generated line/column position of the provided source/line/column source position.
45 */
46export declare function generatedPositionFor(map: TraceMap, needle: SourceNeedle): GeneratedMapping | InvalidGeneratedMapping;
47/**
48 * Finds all generated line/column positions of the provided source/line/column source position.
49 */
50export declare function allGeneratedPositionsFor(map: TraceMap, needle: SourceNeedle): GeneratedMapping[];
51/**
52 * Iterates each mapping in generated position order.
53 */
54export declare function eachMapping(map: TraceMap, cb: (mapping: EachMapping) => void): void;
55/**
56 * Retrieves the source content for a particular source, if its found. Returns null if not.
57 */
58export declare function sourceContentFor(map: TraceMap, source: string): string | null;
59/**
60 * Determines if the source is marked to ignore by the source map.
61 */
62export declare function isIgnored(map: TraceMap, source: string): boolean;
63/**
64 * A helper that skips sorting of the input map's mappings array, which can be expensive for larger
65 * maps.
66 */
67export declare function presortedDecodedMap(map: DecodedSourceMap, mapUrl?: string): TraceMap;
68/**
69 * Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
70 * a sourcemap, or to JSON.stringify.
71 */
72export declare function decodedMap(map: TraceMap): Omit<DecodedSourceMap, 'mappings'> & {
73 mappings: readonly SourceMapSegment[][];
74};
75/**
76 * Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
77 * a sourcemap, or to JSON.stringify.
78 */
79export declare function encodedMap(map: TraceMap): EncodedSourceMap;
80//# sourceMappingURL=trace-mapping.d.ts.map
node_modules/@jridgewell/trace-mapping/types/trace-mapping.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"trace-mapping.d.ts","sourceRoot":"","sources":["../src/trace-mapping.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,EACd,MAAM,EACN,YAAY,EACZ,SAAS,EACT,WAAW,EAIX,EAAE,EACH,MAAM,SAAS,CAAC;AAIjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,WAAW,EACX,IAAI,EACJ,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,MAAM,EACN,eAAe,EACf,eAAe,IAAI,OAAO,EAC1B,uBAAuB,EACvB,cAAc,EACd,YAAY,EACZ,MAAM,EACN,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,aAAa,GACd,MAAM,SAAS,CAAC;AAajB,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,UAAU,IAAI,MAAM,EAAE,MAAM,eAAe,CAAC;AAEjE,qBAAa,QAAS,YAAW,SAAS;IAChC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IACtC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC9C,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAEtC,eAAe,EAAE,MAAM,EAAE,CAAC;IAClC,QAAgB,QAAQ,CAAqB;IAE7C,QAAgB,QAAQ,CAAmC;IAC3D,QAAgB,YAAY,CAAY;IAExC,QAAgB,UAAU,CAAuB;IACjD,QAAgB,cAAc,CAA0B;gBAE5C,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;CAmC5D;AAUD;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAE3E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,QAAQ,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAErF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAiBnC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,MAAM,GACb,eAAe,GAAG,sBAAsB,CAiC1C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,YAAY,GACnB,gBAAgB,GAAG,uBAAuB,CAG5C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE,CAIhG;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,CAgCnF;AASD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7E;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKhE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAIpF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,QAAQ,GACZ,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,EAAE,SAAS,gBAAgB,EAAE,EAAE,CAAA;CAAE,CAElF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,QAAQ,GAAG,gBAAgB,CAE1D"}
node_modules/@jridgewell/trace-mapping/types/types.d.cts +107 -0
……@@ -0,0 +1,107 @@
1import type { SourceMapSegment } from './sourcemap-segment.cts';
2import type { GREATEST_LOWER_BOUND, LEAST_UPPER_BOUND, TraceMap } from './trace-mapping.cts';
3export interface SourceMapV3 {
4 file?: string | null;
5 names: string[];
6 sourceRoot?: string;
7 sources: (string | null)[];
8 sourcesContent?: (string | null)[];
9 version: 3;
10 ignoreList?: number[];
11}
12export interface EncodedSourceMap extends SourceMapV3 {
13 mappings: string;
14}
15export interface DecodedSourceMap extends SourceMapV3 {
16 mappings: SourceMapSegment[][];
17}
18export interface Section {
19 offset: {
20 line: number;
21 column: number;
22 };
23 map: EncodedSourceMap | DecodedSourceMap | SectionedSourceMap;
24}
25export interface SectionedSourceMap {
26 file?: string | null;
27 sections: Section[];
28 version: 3;
29}
30export type OriginalMapping = {
31 source: string | null;
32 line: number;
33 column: number;
34 name: string | null;
35};
36export type InvalidOriginalMapping = {
37 source: null;
38 line: null;
39 column: null;
40 name: null;
41};
42export type GeneratedMapping = {
43 line: number;
44 column: number;
45};
46export type InvalidGeneratedMapping = {
47 line: null;
48 column: null;
49};
50export type Bias = typeof GREATEST_LOWER_BOUND | typeof LEAST_UPPER_BOUND;
51export type XInput = {
52 x_google_ignoreList?: SourceMapV3['ignoreList'];
53};
54export type EncodedSourceMapXInput = EncodedSourceMap & XInput;
55export type DecodedSourceMapXInput = DecodedSourceMap & XInput;
56export type SectionedSourceMapXInput = Omit<SectionedSourceMap, 'sections'> & {
57 sections: SectionXInput[];
58};
59export type SectionXInput = Omit<Section, 'map'> & {
60 map: SectionedSourceMapInput;
61};
62export type SourceMapInput = string | EncodedSourceMapXInput | DecodedSourceMapXInput | TraceMap;
63export type SectionedSourceMapInput = SourceMapInput | SectionedSourceMapXInput;
64export type Needle = {
65 line: number;
66 column: number;
67 bias?: Bias;
68};
69export type SourceNeedle = {
70 source: string;
71 line: number;
72 column: number;
73 bias?: Bias;
74};
75export type EachMapping = {
76 generatedLine: number;
77 generatedColumn: number;
78 source: null;
79 originalLine: null;
80 originalColumn: null;
81 name: null;
82} | {
83 generatedLine: number;
84 generatedColumn: number;
85 source: string | null;
86 originalLine: number;
87 originalColumn: number;
88 name: string | null;
89};
90export declare abstract class SourceMap {
91 version: SourceMapV3['version'];
92 file: SourceMapV3['file'];
93 names: SourceMapV3['names'];
94 sourceRoot: SourceMapV3['sourceRoot'];
95 sources: SourceMapV3['sources'];
96 sourcesContent: SourceMapV3['sourcesContent'];
97 resolvedSources: SourceMapV3['sources'];
98 ignoreList: SourceMapV3['ignoreList'];
99}
100export type Ro<T> = T extends Array<infer V> ? V[] | Readonly<V[]> | RoArray<V> | Readonly<RoArray<V>> : T extends object ? T | Readonly<T> | RoObject<T> | Readonly<RoObject<T>> : T;
101type RoArray<T> = Ro<T>[];
102type RoObject<T> = {
103 [K in keyof T]: T[K] | Ro<T[K]>;
104};
105export declare function parse<T>(map: T): Exclude<T, string>;
106export {};
107//# sourceMappingURL=types.d.ts.map
node_modules/@jridgewell/trace-mapping/types/types.d.cts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEzF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,QAAQ,EAAE,gBAAgB,EAAE,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,GAAG,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;CAC/D;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,IAAI,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,IAAI,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,IAAI,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG,OAAO,oBAAoB,GAAG,OAAO,iBAAiB,CAAC;AAE1E,MAAM,MAAM,MAAM,GAAG;IAAE,mBAAmB,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAA;CAAE,CAAC;AACzE,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,GAAG,MAAM,CAAC;AAC/D,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,GAAG,MAAM,CAAC;AAC/D,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAAG;IAC5E,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG;IACjD,GAAG,EAAE,uBAAuB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,sBAAsB,GAAG,sBAAsB,GAAG,QAAQ,CAAC;AACjG,MAAM,MAAM,uBAAuB,GAAG,cAAc,GAAG,wBAAwB,CAAC;AAEhF,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AACnE,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAEzF,MAAM,MAAM,WAAW,GACnB;IACE,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,IAAI,CAAC;IACb,YAAY,EAAE,IAAI,CAAC;IACnB,cAAc,EAAE,IAAI,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;CACZ,GACD;IACE,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEN,8BAAsB,SAAS;IACrB,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IACtC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC9C,eAAe,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACxC,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;CAC/C;AAED,MAAM,MAAM,EAAE,CAAC,CAAC,IACd,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GACpB,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACvD,CAAC,SAAS,MAAM,GACd,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GACrD,CAAC,CAAC;AACV,KAAK,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1B,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAEvD,wBAAgB,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAEnD"}
node_modules/@jridgewell/trace-mapping/types/types.d.mts +107 -0
……@@ -0,0 +1,107 @@
1import type { SourceMapSegment } from './sourcemap-segment.mts';
2import type { GREATEST_LOWER_BOUND, LEAST_UPPER_BOUND, TraceMap } from './trace-mapping.mts';
3export interface SourceMapV3 {
4 file?: string | null;
5 names: string[];
6 sourceRoot?: string;
7 sources: (string | null)[];
8 sourcesContent?: (string | null)[];
9 version: 3;
10 ignoreList?: number[];
11}
12export interface EncodedSourceMap extends SourceMapV3 {
13 mappings: string;
14}
15export interface DecodedSourceMap extends SourceMapV3 {
16 mappings: SourceMapSegment[][];
17}
18export interface Section {
19 offset: {
20 line: number;
21 column: number;
22 };
23 map: EncodedSourceMap | DecodedSourceMap | SectionedSourceMap;
24}
25export interface SectionedSourceMap {
26 file?: string | null;
27 sections: Section[];
28 version: 3;
29}
30export type OriginalMapping = {
31 source: string | null;
32 line: number;
33 column: number;
34 name: string | null;
35};
36export type InvalidOriginalMapping = {
37 source: null;
38 line: null;
39 column: null;
40 name: null;
41};
42export type GeneratedMapping = {
43 line: number;
44 column: number;
45};
46export type InvalidGeneratedMapping = {
47 line: null;
48 column: null;
49};
50export type Bias = typeof GREATEST_LOWER_BOUND | typeof LEAST_UPPER_BOUND;
51export type XInput = {
52 x_google_ignoreList?: SourceMapV3['ignoreList'];
53};
54export type EncodedSourceMapXInput = EncodedSourceMap & XInput;
55export type DecodedSourceMapXInput = DecodedSourceMap & XInput;
56export type SectionedSourceMapXInput = Omit<SectionedSourceMap, 'sections'> & {
57 sections: SectionXInput[];
58};
59export type SectionXInput = Omit<Section, 'map'> & {
60 map: SectionedSourceMapInput;
61};
62export type SourceMapInput = string | EncodedSourceMapXInput | DecodedSourceMapXInput | TraceMap;
63export type SectionedSourceMapInput = SourceMapInput | SectionedSourceMapXInput;
64export type Needle = {
65 line: number;
66 column: number;
67 bias?: Bias;
68};
69export type SourceNeedle = {
70 source: string;
71 line: number;
72 column: number;
73 bias?: Bias;
74};
75export type EachMapping = {
76 generatedLine: number;
77 generatedColumn: number;
78 source: null;
79 originalLine: null;
80 originalColumn: null;
81 name: null;
82} | {
83 generatedLine: number;
84 generatedColumn: number;
85 source: string | null;
86 originalLine: number;
87 originalColumn: number;
88 name: string | null;
89};
90export declare abstract class SourceMap {
91 version: SourceMapV3['version'];
92 file: SourceMapV3['file'];
93 names: SourceMapV3['names'];
94 sourceRoot: SourceMapV3['sourceRoot'];
95 sources: SourceMapV3['sources'];
96 sourcesContent: SourceMapV3['sourcesContent'];
97 resolvedSources: SourceMapV3['sources'];
98 ignoreList: SourceMapV3['ignoreList'];
99}
100export type Ro<T> = T extends Array<infer V> ? V[] | Readonly<V[]> | RoArray<V> | Readonly<RoArray<V>> : T extends object ? T | Readonly<T> | RoObject<T> | Readonly<RoObject<T>> : T;
101type RoArray<T> = Ro<T>[];
102type RoObject<T> = {
103 [K in keyof T]: T[K] | Ro<T[K]>;
104};
105export declare function parse<T>(map: T): Exclude<T, string>;
106export {};
107//# sourceMappingURL=types.d.ts.map
node_modules/@jridgewell/trace-mapping/types/types.d.mts.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEzF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,QAAQ,EAAE,gBAAgB,EAAE,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,GAAG,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;CAC/D;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,IAAI,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,IAAI,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,IAAI,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG,OAAO,oBAAoB,GAAG,OAAO,iBAAiB,CAAC;AAE1E,MAAM,MAAM,MAAM,GAAG;IAAE,mBAAmB,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAA;CAAE,CAAC;AACzE,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,GAAG,MAAM,CAAC;AAC/D,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,GAAG,MAAM,CAAC;AAC/D,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAAG;IAC5E,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG;IACjD,GAAG,EAAE,uBAAuB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,sBAAsB,GAAG,sBAAsB,GAAG,QAAQ,CAAC;AACjG,MAAM,MAAM,uBAAuB,GAAG,cAAc,GAAG,wBAAwB,CAAC;AAEhF,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AACnE,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAEzF,MAAM,MAAM,WAAW,GACnB;IACE,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,IAAI,CAAC;IACb,YAAY,EAAE,IAAI,CAAC;IACnB,cAAc,EAAE,IAAI,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;CACZ,GACD;IACE,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEN,8BAAsB,SAAS;IACrB,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IACtC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC9C,eAAe,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACxC,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;CAC/C;AAED,MAAM,MAAM,EAAE,CAAC,CAAC,IACd,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GACpB,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACvD,CAAC,SAAS,MAAM,GACd,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GACrD,CAAC,CAAC;AACV,KAAK,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1B,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAEvD,wBAAgB,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAEnD"}
node_modules/@types/istanbul-lib-coverage/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1 MIT License
2
3 Copyright (c) Microsoft Corporation.
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE
node_modules/@types/istanbul-lib-coverage/README.md +15 -0
……@@ -0,0 +1,15 @@
1# Installation
2> `npm install --save @types/istanbul-lib-coverage`
3
4# Summary
5This package contains type definitions for istanbul-lib-coverage (https://istanbul.js.org).
6
7# Details
8Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/istanbul-lib-coverage.
9
10### Additional Details
11 * Last updated: Tue, 07 Nov 2023 03:09:37 GMT
12 * Dependencies: none
13
14# Credits
15These definitions were written by [Jason Cheatham](https://github.com/jason0x43).
node_modules/@types/istanbul-lib-coverage/index.d.ts +111 -0
……@@ -0,0 +1,111 @@
1export interface CoverageSummaryData {
2 lines: Totals;
3 statements: Totals;
4 branches: Totals;
5 functions: Totals;
6}
7
8export class CoverageSummary {
9 constructor(data: CoverageSummary | CoverageSummaryData);
10 merge(obj: CoverageSummary): CoverageSummary;
11 toJSON(): CoverageSummaryData;
12 isEmpty(): boolean;
13 data: CoverageSummaryData;
14 lines: Totals;
15 statements: Totals;
16 branches: Totals;
17 functions: Totals;
18}
19
20export interface CoverageMapData {
21 [key: string]: FileCoverage | FileCoverageData;
22}
23
24export class CoverageMap {
25 constructor(data: CoverageMapData | CoverageMap);
26 addFileCoverage(pathOrObject: string | FileCoverage | FileCoverageData): void;
27 files(): string[];
28 fileCoverageFor(filename: string): FileCoverage;
29 filter(callback: (key: string) => boolean): void;
30 getCoverageSummary(): CoverageSummary;
31 merge(data: CoverageMapData | CoverageMap): void;
32 toJSON(): CoverageMapData;
33 data: CoverageMapData;
34}
35
36export interface Location {
37 line: number;
38 column: number;
39}
40
41export interface Range {
42 start: Location;
43 end: Location;
44}
45
46export interface BranchMapping {
47 loc: Range;
48 type: string;
49 locations: Range[];
50 line: number;
51}
52
53export interface FunctionMapping {
54 name: string;
55 decl: Range;
56 loc: Range;
57 line: number;
58}
59
60export interface FileCoverageData {
61 path: string;
62 statementMap: { [key: string]: Range };
63 fnMap: { [key: string]: FunctionMapping };
64 branchMap: { [key: string]: BranchMapping };
65 s: { [key: string]: number };
66 f: { [key: string]: number };
67 b: { [key: string]: number[] };
68}
69
70export interface Totals {
71 total: number;
72 covered: number;
73 skipped: number;
74 pct: number;
75}
76
77export interface Coverage {
78 covered: number;
79 total: number;
80 coverage: number;
81}
82
83export class FileCoverage implements FileCoverageData {
84 constructor(data: string | FileCoverage | FileCoverageData);
85 merge(other: FileCoverageData): void;
86 getBranchCoverageByLine(): { [line: number]: Coverage };
87 getLineCoverage(): { [line: number]: number };
88 getUncoveredLines(): number[];
89 resetHits(): void;
90 computeBranchTotals(): Totals;
91 computeSimpleTotals(): Totals;
92 toSummary(): CoverageSummary;
93 toJSON(): object;
94
95 data: FileCoverageData;
96 path: string;
97 statementMap: { [key: string]: Range };
98 fnMap: { [key: string]: FunctionMapping };
99 branchMap: { [key: string]: BranchMapping };
100 s: { [key: string]: number };
101 f: { [key: string]: number };
102 b: { [key: string]: number[] };
103}
104
105export const classes: {
106 FileCoverage: FileCoverage;
107};
108
109export function createCoverageMap(data?: CoverageMap | CoverageMapData): CoverageMap;
110export function createCoverageSummary(obj?: CoverageSummary | CoverageSummaryData): CoverageSummary;
111export function createFileCoverage(pathOrObject: string | FileCoverage | FileCoverageData): FileCoverage;
node_modules/@types/istanbul-lib-coverage/package.json +25 -0
……@@ -0,0 +1,25 @@
1{
2 "name": "@types/istanbul-lib-coverage",
3 "version": "2.0.6",
4 "description": "TypeScript definitions for istanbul-lib-coverage",
5 "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/istanbul-lib-coverage",
6 "license": "MIT",
7 "contributors": [
8 {
9 "name": "Jason Cheatham",
10 "githubUsername": "jason0x43",
11 "url": "https://github.com/jason0x43"
12 }
13 ],
14 "main": "",
15 "types": "index.d.ts",
16 "repository": {
17 "type": "git",
18 "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git",
19 "directory": "types/istanbul-lib-coverage"
20 },
21 "scripts": {},
22 "dependencies": {},
23 "typesPublisherContentHash": "36c823c8b3f66dab91254b0f7299de71768ad8836bfbfcaa062409dd86fbbd61",
24 "typeScriptVersion": "4.5"
25}
node_modules/adaptive-timeout/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/adaptive-timeout/README.md +88 -0
……@@ -0,0 +1,88 @@
1# adaptive-timeout
2
3Adaptive timeout calculation with EWMA-based tracking and fallback strategies.
4
5## Install
6
7```
8npm install adaptive-timeout
9```
10
11## Usage
12
13```js
14const AdaptiveTimeout = require('adaptive-timeout')
15
16const timeouts = new AdaptiveTimeout()
17
18// Record a sample when you get a response
19timeouts.put('10.0.0.1:8080', 150)
20
21// Get timeout for next request (attempt 1, 2, 3...)
22timeouts.get('10.0.0.1:8080', 1) // adaptive based on recorded samples
23timeouts.get('unknown-peer', 1) // uses fallback strategy
24```
25
26## API
27
28#### `const timeouts = new AdaptiveTimeout([options])`
29
30Create a new instance.
31
32Options:
33
34- `maxSize` - max cache entries (default: `65536`)
35- `maxAge` - entry TTL in ms (default: `600000` / 10 minutes)
36- `fallback` - timeout sequence for unknown keys (default: `[500, 750, 1000, 1500, 2000]`)
37- `min` - minimum timeout for known keys (default: `300`)
38- `max` - maximum timeout for known keys (default: `5000`)
39- `jitter` - random jitter range in ms (default: `256`)
40
41#### `timeouts.put(key, value)`
42
43Record a sample. Updates the exponentially weighted moving average.
44
45Returns `{ avg, variance }`.
46
47#### `timeouts.get(key, [attempt])`
48
49Get a timeout value.
50
51For known keys: calculates adaptive timeout with linear backoff based on attempt number.
52
53For unknown keys: returns value from fallback sequence based on attempt number.
54
55#### `timeouts.getValue(key)`
56
57Get raw stats for a key. Returns `{ avg, variance }` or `null`.
58
59#### `timeouts.has(key)`
60
61Check if a key exists.
62
63#### `timeouts.delete(key)`
64
65Remove a key.
66
67#### `timeouts.clear()`
68
69Remove all entries.
70
71#### `timeouts.size`
72
73Number of entries.
74
75## How it works
76
77Uses TCP-style EWMA (exponentially weighted moving average) to track values:
78
79- `avg` blends 87.5% old + 12.5% new sample
80- `variance` blends 75% old + 25% new deviation
81
82Timeout for known keys: `(avg + 2 * variance) * attempt + jitter`
83
84Unknown keys use an aggressive fallback sequence to probe quickly.
85
86## License
87
88Apache 2.0
node_modules/adaptive-timeout/index.d.ts +58 -0
……@@ -0,0 +1,58 @@
1declare module '@holepunchto/adaptive-timeout' {
2 interface AdaptiveTimeoutOptions {
3 maxSize?: number
4 maxAge?: number
5 fallback?: number[]
6 min?: number
7 max?: number
8 jitter?: number
9 }
10
11 interface Stats {
12 avg: number
13 variance: number
14 }
15
16 declare class AdaptiveTimeout {
17 constructor(opts?: AdaptiveTimeoutOptions)
18
19 getValue(key: string): Stats | null
20 put(key: string, value: number): Stats
21 get(key: string, attempt?: number): number
22 has(key: string): boolean
23 delete(key: string): boolean
24 clear(): void
25
26 // Default - aggressive ramp
27 static TimeoutAggressive: string[]
28
29 // Linear - steady increase
30 static TimeoutLinear: string[]
31
32 // Exponential - slow start, rapid backoff
33 static TimeoutExponential: string[]
34
35 // Gentle - conservative, patient
36 static TimeoutGentle: string[]
37
38 // Fast - rapid fire retries
39 static TimeoutFast: string[]
40
41 // U-shape - long, short, long
42 static TimeoutUShape: string[]
43
44 // Inverse U - short, long, short
45 static TimeoutInverseU: string[]
46
47 // Sawtooth - alternating fast/slow
48 static TimeoutSawtooth: string[]
49
50 // Plateau - quick ramp then steady
51 static TimeoutPlateau: string[]
52
53 // Logarithmic - diminishing increases
54 static TimeoutLogarithmic: string[]
55 }
56
57 export = AdaptiveTimeout
58}
node_modules/adaptive-timeout/index.js +93 -0
……@@ -0,0 +1,93 @@
1const Cache = require('xache')
2
3module.exports = class AdaptiveTimeout {
4 constructor(opts = {}) {
5 this._cache = new Cache({
6 maxSize: opts.maxSize || 65536,
7 maxAge: opts.maxAge || 10 * 60 * 1000 // 10 minutes
8 })
9 this._fallback = opts.fallback || AdaptiveTimeout.TimeoutExponential
10 this._min = opts.min ?? 300
11 this._max = opts.max || 4000
12 this._jitter = opts.jitter ?? 256
13 }
14
15 // Default - aggressive ramp
16 static TimeoutAggressive = [500, 750, 1000, 1500, 2000]
17
18 // Linear - steady increase
19 static TimeoutLinear = [500, 1000, 1500, 2000, 2500]
20
21 // Exponential - slow start, rapid backoff
22 static TimeoutExponential = [250, 500, 1000, 2000, 4000]
23
24 // Gentle - conservative, patient
25 static TimeoutGentle = [1000, 1250, 1500, 1750, 2000]
26
27 // Fast - rapid fire retries
28 static TimeoutFast = [200, 400, 600, 800, 1000]
29
30 // U-shape - long, short, long
31 static TimeoutUShape = [1500, 750, 500, 750, 1500]
32
33 // Inverse U - short, long, short
34 static TimeoutInverseU = [500, 1000, 1500, 1000, 500]
35
36 // Sawtooth - alternating fast/slow
37 static TimeoutSawtooth = [500, 1500, 500, 1500, 500]
38
39 // Plateau - quick ramp then steady
40 static TimeoutPlateau = [500, 1000, 2000, 2000, 2000]
41
42 // Logarithmic - diminishing increases
43 static TimeoutLogarithmic = [500, 1000, 1300, 1500, 1600]
44
45 getValue(key) {
46 return this._cache.get(key)
47 }
48
49 put(key, value) {
50 let p = this._cache.get(key)
51
52 if (!p) {
53 p = { avg: value, variance: value >> 1 }
54 } else {
55 // blend 75% old + 25% new deviation
56 p.variance += (Math.abs(p.avg - value) - p.variance) >> 2
57 // blend 87.5% old + 12.5% new sample
58 p.avg += (value - p.avg) >> 3
59 }
60
61 this._cache.set(key, p)
62
63 return p
64 }
65
66 get(key, attempt = 1) {
67 const p = this._cache.get(key)
68 const jitter = (Math.random() * this._jitter) | 0
69
70 if (p) {
71 // known - use adaptive with linear backoff
72 const base = p.avg + (p.variance << 1)
73 const backoff = base * attempt
74 return Math.min(Math.max(backoff + jitter, this._min), this._max)
75 } else {
76 // unknown - use aggressive fallback
77 const base = this._fallback[Math.min(attempt - 1, this._fallback.length - 1)]
78 return base + jitter
79 }
80 }
81
82 has(key) {
83 return this._cache.has(key)
84 }
85
86 delete(key) {
87 return this._cache.delete(key)
88 }
89
90 clear() {
91 this._cache.clear()
92 }
93}
node_modules/adaptive-timeout/package.json +42 -0
……@@ -0,0 +1,42 @@
1{
2 "name": "adaptive-timeout",
3 "version": "1.0.1",
4 "description": "adaptive-timeout",
5 "main": "index.js",
6 "exports": {
7 "./package": "./package.json",
8 ".": {
9 "types": "./index.d.ts",
10 "default": "./index.js"
11 }
12 },
13 "files": [
14 "package.json",
15 "index.js",
16 "index.d.ts"
17 ],
18 "devDependencies": {
19 "brittle": "^3.19.0",
20 "lunte": "^1.2.0",
21 "prettier": "^3.6.2",
22 "prettier-config-holepunch": "^2.0.0"
23 },
24 "scripts": {
25 "format": "prettier . --write",
26 "test": "prettier . --check && lunte && brittle-bare test/index.js",
27 "lint": "lunte"
28 },
29 "repository": {
30 "type": "git",
31 "url": "https://github.com/holepunchto/adaptive-timeout.git"
32 },
33 "author": "Holepunch Inc",
34 "license": "Apache-2.0",
35 "bugs": {
36 "url": "https://github.com/holepunchto/adaptive-timeout/issues"
37 },
38 "homepage": "https://github.com/holepunchto/adaptive-timeout",
39 "dependencies": {
40 "xache": "^1.2.1"
41 }
42}
node_modules/autobase-test-helpers/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/autobase-test-helpers/NOTICE +13 -0
……@@ -0,0 +1,13 @@
1Copyright 2023 Holepunch Inc
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
node_modules/autobase-test-helpers/README.md +19 -0
……@@ -0,0 +1,19 @@
1# autobase-test-helpers
2
3Helpers when writing tests for an Autobased application
4
5```
6npm install autobase-test-helpers
7```
8
9## Usage
10
11``` js
12const { sync } = require('autobase-test-helpers')
13
14await sync(bases) // expects replication to have been set up
15```
16
17## License
18
19MIT
node_modules/autobase-test-helpers/index.js +149 -0
……@@ -0,0 +1,149 @@
1const b4a = require('b4a')
2
3module.exports = {
4 eventFlush,
5 replicate,
6 sync,
7 synced,
8 replicateAndSync
9}
10
11function eventFlush () {
12 return new Promise(resolve => setImmediate(resolve))
13}
14
15async function replicateAndSync (bases, opts) {
16 const done = replicate(bases)
17 await sync(bases, opts)
18 await done()
19}
20
21async function sync (bases, { checkHash = true } = {}) {
22 for (const base of bases) {
23 await base.update()
24 }
25
26 if (bases.length === 1) return
27
28 return new Promise((resolve, reject) => {
29 let done = false
30 let checks = 0
31
32 for (const base of bases) {
33 base.on('update', check)
34 base.on('error', shutdown)
35 }
36
37 check()
38
39 async function check () {
40 checks++
41 for (const base of bases) {
42 if (base.interrupted) return shutdown(new Error('base was interrupted, reason at base.interrupted'))
43 }
44 if (!(await same(checkHash))) return mbShutdown()
45 for (const base of bases) {
46 await base.update()
47 }
48 if (!(await same(checkHash))) return mbShutdown()
49 shutdown()
50 }
51
52 function mbShutdown () {
53 if (done) return shutdown()
54 checks--
55 }
56
57 async function same (checkHash) {
58 return synced(bases) && await sameHash(bases, checkHash)
59 }
60
61 function shutdown (err) {
62 checks--
63 done = true
64 if (checks !== 0 && !err) return
65
66 for (const base of bases) {
67 base.off('update', check)
68 base.off('error', shutdown)
69 }
70
71 if (err) reject(err)
72 else resolve()
73 }
74 })
75}
76
77async function sameHash (bases, check) {
78 if (!check) return true
79 const first = bases[0]
80 const h1 = await first.hash()
81 for (let i = 1; i < bases.length; i++) {
82 if (bases[i].signedLength !== first.signedLength) return false
83 const h2 = await bases[i].hash()
84 if (!b4a.equals(h1, h2)) return false
85 }
86 return true
87}
88
89function synced (bases) {
90 const first = bases[0]
91 for (let i = 1; i < bases.length; i++) {
92 if (!same(first, bases[i])) return false
93 }
94 return true
95}
96
97function same (a, b) {
98 if (a.updating || b.updating) return false
99
100 const h1 = a.heads()
101 const h2 = b.heads()
102
103 if (h1.length !== h2.length) return false
104
105 for (let i = 0; i < h1.length; i++) {
106 const h1i = h1[i]
107 const h2i = h2[i]
108
109 if (!b4a.equals(h1i.key, h2i.key)) return false
110 if (h1i.length !== h2i.length) return false
111 }
112
113 return true
114}
115
116function replicate (bases) {
117 const streams = []
118 const missing = bases.slice()
119
120 while (missing.length) {
121 const a = missing.pop()
122
123 for (const b of missing) {
124 const s1 = a.replicate(true)
125 const s2 = b.replicate(false)
126
127 s1.on('error', (err) => {
128 if (err.code) console.log('autobase replicate error:', err.stack)
129 })
130 s2.on('error', (err) => {
131 if (err.code) console.log('autobase replicate error:', err.stack)
132 })
133
134 s1.pipe(s2).pipe(s1)
135
136 streams.push(s1)
137 streams.push(s2)
138 }
139 }
140
141 return close
142
143 function close () {
144 return Promise.all(streams.map(s => {
145 s.destroy()
146 return new Promise(resolve => s.on('close', resolve))
147 }))
148 }
149}
node_modules/autobase-test-helpers/package.json +19 -0
……@@ -0,0 +1,19 @@
1{
2 "name": "autobase-test-helpers",
3 "version": "3.1.0",
4 "description": "Helpers when writing tests for an Autobased application",
5 "main": "index.js",
6 "dependencies": {
7 "b4a": "^1.6.4"
8 },
9 "repository": {
10 "type": "git",
11 "url": "git+https://github.com/holepunchto/autobase-test-helpers.git"
12 },
13 "author": "Holepunch",
14 "license": "Apache-2.0",
15 "bugs": {
16 "url": "https://github.com/holepunchto/autobase-test-helpers/issues"
17 },
18 "homepage": "https://github.com/holepunchto/autobase-test-helpers"
19}
node_modules/bare-bundle/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-bundle/README.md +47 -0
……@@ -0,0 +1,47 @@
1# bare-bundle
2
3Application bundle format for JavaScript, inspired by <https://github.com/electron/asar>.
4
5```
6npm i bare-bundle
7```
8
9## Format
10
11```
12[#!hashbang]
13<header length><header><...files>
14```
15
16The header length is an integer literal denoting the total length of the header. The header itself is a JSON string literal of header length bytes and has the following format:
17
18```js
19{
20 "version": 0,
21 "id": null | "<string>",
22 "main": null | "<url>",
23 "imports": {
24 "<from>": "<to>"
25 },
26 "resolutions": {
27 "<url>": "<imports>"
28 },
29 "addons": ["<url>"],
30 "assets": ["<url>"],
31 "files": {
32 "<url>": {
33 "offset": number,
34 "length": number,
35 "mode": number
36 }
37 }
38}
39```
40
41For each `<url>` in `files`, `offset` provides the byte offset to the file **after** the header and `length` provides the byte length of the file.
42
43The bundle may optionally be prefixed with a hashbang, `#!`, for use with script interpreters. The hashbang is ignored during parsing.
44
45## License
46
47Apache-2.0
node_modules/bare-bundle/index.d.ts +86 -0
……@@ -0,0 +1,86 @@
1import Buffer from 'bare-buffer'
2import URL from 'bare-url'
3
4interface MemoryFileOptions {
5 executable?: boolean
6 mode?: number
7}
8
9interface MemoryFile {
10 mode(): number
11 read(): Buffer
12 size(): number
13}
14
15declare class MemoryFile {
16 constructor(data: string | Buffer, opts?: MemoryFileOptions)
17}
18
19interface BundleOptions {
20 File?: typeof MemoryFile
21}
22
23type RecursiveStringObject = { [key: string]: string | RecursiveStringObject }
24
25interface BundleWriteOptions {
26 addon?: boolean
27 alias?: string
28 asset?: boolean
29 executable?: boolean
30 imports?: RecursiveStringObject
31 main?: boolean
32 mode?: number
33}
34
35interface BundleMountOptions {
36 conditions?: { [condition: string]: string | URL }
37}
38
39interface BundleToBufferOptions {
40 indent?: number
41 shared?: boolean
42}
43
44interface Bundle extends Iterable<[key: string, read: Buffer, mode: number]> {
45 readonly files: Record<string, MemoryFile>
46 readonly version: number
47
48 addons: string[]
49 assets: string[]
50 id: string | null
51 imports: RecursiveStringObject
52 main: string | null
53 resolutions: RecursiveStringObject
54
55 empty(): boolean
56 keys(): string[]
57 exists(key: string): boolean
58 mode(key: string): number
59 read(key: string): Buffer
60 write(key: string, data: string, opts?: BundleWriteOptions): this
61 mount(root: string | URL, opts?: BundleMountOptions): Bundle
62 unmount(root: string | URL, opts?: BundleMountOptions): Bundle
63 toBuffer(opts?: BundleToBufferOptions): Buffer
64}
65
66declare class Bundle {
67 static readonly version: number
68
69 constructor(opts?: BundleOptions)
70}
71
72declare namespace Bundle {
73 export {
74 type MemoryFile,
75 type MemoryFileOptions,
76 type BundleOptions,
77 type BundleWriteOptions,
78 type BundleMountOptions,
79 type BundleToBufferOptions
80 }
81
82 export function isBundle(value: unknown): value is Bundle
83 export function from(value: string | Buffer | Bundle): Bundle
84}
85
86export = Bundle
node_modules/bare-bundle/index.js +592 -0
……@@ -0,0 +1,592 @@
1const errors = require('./lib/errors')
2
3const kind = Symbol.for('bare.bundle.kind')
4
5class MemoryFile {
6 constructor(data, opts = {}) {
7 const { executable = false, mode = executable ? 0o755 : 0o644 } = opts
8
9 this._data = typeof data === 'string' ? Buffer.from(data) : data
10 this._mode = mode
11 }
12
13 size() {
14 return this._data.byteLength
15 }
16
17 mode() {
18 return this._mode
19 }
20
21 read() {
22 return this._data
23 }
24
25 inspect() {
26 return {
27 __proto__: { constructor: MemoryFile },
28
29 data: this._data,
30 mode: this._mode.toString(8)
31 }
32 }
33
34 [Symbol.for('bare.inspect')]() {
35 return this.inspect()
36 }
37
38 [Symbol.for('nodejs.util.inspect.custom')]() {
39 return this.inspect()
40 }
41}
42
43module.exports = exports = class Bundle {
44 static get [kind]() {
45 return 0 // Compatibility version
46 }
47
48 static get version() {
49 return 0
50 }
51
52 constructor(opts = {}) {
53 const { File = MemoryFile } = opts
54
55 this._File = File
56 this._id = null
57 this._main = null
58 this._imports = {}
59 this._resolutions = {}
60 this._addons = []
61 this._assets = []
62 this._files = new Map()
63 }
64
65 get [kind]() {
66 return Bundle[kind]
67 }
68
69 get version() {
70 return Bundle.version
71 }
72
73 get id() {
74 return this._id
75 }
76
77 set id(value) {
78 if (typeof value !== 'string' && value !== null) {
79 throw new TypeError(`ID must be a string or null. Received type ${typeof value} (${value})`)
80 }
81
82 this._id = value
83 }
84
85 get main() {
86 return this._main
87 }
88
89 set main(value) {
90 if (typeof value !== 'string' && value !== null) {
91 throw new TypeError(`Main must be a string or null. Received type ${typeof value} (${value})`)
92 }
93
94 this._main = value
95 }
96
97 get imports() {
98 return this._imports
99 }
100
101 set imports(value) {
102 this._imports = cloneImportsMap(value)
103 }
104
105 get resolutions() {
106 return this._resolutions
107 }
108
109 set resolutions(value) {
110 this._resolutions = cloneResolutionsMap(value)
111 }
112
113 get addons() {
114 return this._addons
115 }
116
117 set addons(value) {
118 this._addons = cloneFilesList(value, 'Addons')
119 }
120
121 get assets() {
122 return this._assets
123 }
124
125 set assets(value) {
126 this._assets = cloneFilesList(value, 'Assets')
127 }
128
129 get files() {
130 return Object.fromEntries(this._files.entries())
131 }
132
133 *[Symbol.iterator]() {
134 for (const [key, file] of this._files) {
135 yield [key, file.read(), file.mode()]
136 }
137 }
138
139 empty() {
140 return this._files.size === 0
141 }
142
143 keys() {
144 return this._files.keys()
145 }
146
147 exists(key) {
148 return this._files.has(key)
149 }
150
151 size(key) {
152 const file = this._files.get(key) || null
153 if (file === null) return 0
154 return file.size()
155 }
156
157 mode(key) {
158 const file = this._files.get(key) || null
159 if (file === null) return 0
160 return file.mode()
161 }
162
163 read(key) {
164 const file = this._files.get(key) || null
165 if (file === null) return null
166 return file.read()
167 }
168
169 write(key, data, opts = {}) {
170 if (typeof key !== 'string') {
171 throw new TypeError(`File path must be a string. Received type ${typeof key} (${key})`)
172 }
173
174 const { main = false, alias = null, imports = null, addon = false, asset = false } = opts
175
176 this._files.set(key, new MemoryFile(data, opts))
177
178 if (main) this._main = key
179 if (alias) this._imports[alias] = key
180 if (imports) this._resolutions[key] = cloneImportsMap(imports)
181 if (addon) this._addons.push(key)
182 if (asset) this._assets.push(key)
183
184 return this
185 }
186
187 mount(root, opts = {}) {
188 const bundle = new Bundle()
189
190 // Go through the private API properties as we're operating on already
191 // validated values.
192
193 bundle._File = this._File
194 bundle._id = this._id
195
196 if (this._main) bundle._main = mountSpecifier(this._main, root)
197
198 bundle._imports = transformImportsMap(this._imports, root, null, opts, mountSpecifier)
199 bundle._resolutions = transformResolutionsMap(this._resolutions, root, opts, mountSpecifier)
200
201 for (const [key, file] of this._files) {
202 bundle._files.set(mountSpecifier(key, root), file)
203 }
204
205 bundle._addons = transformFilesList(this._addons, root, mountSpecifier)
206 bundle._assets = transformFilesList(this._assets, root, mountSpecifier)
207
208 return bundle
209 }
210
211 unmount(root, opts = {}) {
212 const bundle = new Bundle()
213
214 // Go through the private API properties as we're operating on already
215 // validated values.
216
217 bundle._File = this._File
218 bundle._id = this._id
219
220 if (this._main) bundle._main = unmountSpecifier(this._main, root)
221
222 bundle._imports = transformImportsMap(this._imports, root, null, opts, unmountSpecifier)
223 bundle._resolutions = transformResolutionsMap(this._resolutions, root, opts, unmountSpecifier)
224
225 for (const [key, file] of this._files) {
226 bundle._files.set(unmountSpecifier(key, root), file)
227 }
228
229 bundle._addons = transformFilesList(this._addons, root, unmountSpecifier)
230 bundle._assets = transformFilesList(this._assets, root, unmountSpecifier)
231
232 return bundle
233 }
234
235 toBuffer(opts = {}) {
236 const { indent = 0, shared = false } = opts
237
238 const header = {
239 version: Bundle.version,
240 id: this._id,
241 main: this._main,
242 imports: cloneImportsMap(this._imports),
243 resolutions: cloneResolutionsMap(this._resolutions),
244 addons: cloneFilesList(this._addons, 'Addons'),
245 assets: cloneFilesList(this._assets, 'Assets'),
246 files: {}
247 }
248
249 const keys = [...this._files.keys()].sort()
250
251 let offset = 0
252
253 for (const key of keys) {
254 const length = this.size(key)
255
256 header.files[key] = { offset, length, mode: this.mode(key) }
257 offset += length
258 }
259
260 const json = Buffer.from(`\n${JSON.stringify(header, null, indent)}\n`)
261
262 const length = Buffer.from(json.byteLength.toString(10))
263
264 const total = length.byteLength + json.byteLength + offset
265
266 const storage = shared ? new SharedArrayBuffer(total) : new ArrayBuffer(total)
267
268 const buffer = Buffer.from(storage)
269
270 offset = 0
271
272 buffer.set(length, offset)
273 offset += length.byteLength
274
275 buffer.set(json, offset)
276 offset += json.byteLength
277
278 for (const key of keys) {
279 buffer.set(this.read(key), offset)
280 offset += this.size(key)
281 }
282
283 return buffer
284 }
285
286 inspect() {
287 return {
288 __proto__: { constructor: Bundle },
289
290 version: this.version,
291 id: this.id,
292 main: this.main,
293 imports: this.imports,
294 resolutions: this.resolutions,
295 addons: this.addons,
296 assets: this.assets,
297 files: this.files
298 }
299 }
300
301 [Symbol.for('bare.inspect')]() {
302 return this.inspect()
303 }
304
305 [Symbol.for('nodejs.util.inspect.custom')]() {
306 return this.inspect()
307 }
308}
309
310const Bundle = exports
311
312exports.errors = errors
313
314exports.isBundle = function isBundle(value) {
315 if (value instanceof Bundle) return true
316
317 return typeof value === 'object' && value !== null && value[kind] === Bundle[kind]
318}
319
320exports.from = function from(value) {
321 // from(string)
322 if (typeof value === 'string') return fromString(value)
323
324 // from(buffer)
325 if (Buffer.isBuffer(value)) return fromBuffer(value)
326
327 // from(bundle)
328 return value
329}
330
331function fromString(string) {
332 return fromBuffer(Buffer.from(string))
333}
334
335function fromBuffer(buffer) {
336 if (buffer[0] === 0x23 /* # */ && buffer[1] === 0x21 /* ! */) {
337 let end = 2
338
339 while (buffer[end] !== 0xa /* \n */) end++
340
341 buffer = buffer.subarray(end + 1)
342 }
343
344 let end = 0
345
346 while (isDecimal(buffer[end])) end++
347
348 const len = parseInt(buffer.toString('utf8', 0, end), 10)
349
350 let header
351 try {
352 header = JSON.parse(buffer.toString('utf8', end, end + len))
353 } catch (err) {
354 throw errors.INVALID_BUNDLE_HEADER('Invalid bundle header', err)
355 }
356
357 const bundle = new Bundle()
358
359 // Go through the public API setters to ensure that the header fields are
360 // validated.
361
362 if (header.id) bundle.id = header.id
363 if (header.main) bundle.main = header.main
364 if (header.imports) bundle.imports = header.imports
365 if (header.resolutions) bundle.resolutions = header.resolutions
366 if (header.addons) bundle.addons = header.addons
367 if (header.assets) bundle.assets = header.assets
368
369 let offset = end + len
370
371 for (const [file, info] of Object.entries(header.files)) {
372 bundle.write(file, buffer.subarray(offset, offset + info.length), {
373 mode: info.mode || 0o644
374 })
375
376 offset += info.length
377 }
378
379 return bundle
380}
381
382function isDecimal(c) {
383 return c >= 0x30 && c <= 0x39
384}
385
386function compareKeys([a], [b]) {
387 return a > b ? 1 : a < b ? -1 : 0
388}
389
390function cloneImportsMap(value) {
391 if (typeof value === 'object' && value !== null) {
392 const imports = {}
393
394 for (const entry of Object.entries(value).sort(compareKeys)) {
395 imports[entry[0]] = cloneImportsMapEntry(entry[1])
396 }
397
398 return imports
399 }
400
401 throw new TypeError(`Imports map must be an object. Received type ${typeof value} (${value})`)
402}
403
404function cloneImportsMapEntry(value) {
405 if (typeof value === 'string') return value
406
407 if (typeof value === 'object' && value !== null) {
408 const imports = {}
409
410 for (const entry of Object.entries(value)) {
411 imports[entry[0]] = cloneImportsMapEntry(entry[1])
412 }
413
414 return imports
415 }
416
417 throw new TypeError(
418 `Imports map entry must be a string or object. Received type ${typeof value} (${value})`
419 )
420}
421
422function cloneResolutionsMap(value) {
423 if (typeof value === 'object' && value !== null) {
424 const resolutions = {}
425
426 for (const entry of Object.entries(value).sort(compareKeys)) {
427 resolutions[entry[0]] = cloneImportsMap(entry[1])
428 }
429
430 return resolutions
431 }
432
433 throw new TypeError(`Resolutions map must be an object. Received type ${typeof value} (${value})`)
434}
435
436function cloneFilesList(value, name) {
437 if (Array.isArray(value)) {
438 const files = []
439
440 for (const entry of value) {
441 if (typeof entry !== 'string') {
442 throw new TypeError(
443 `${name} entry must be a string. Received type ${typeof entry} (${entry})`
444 )
445 }
446
447 files.push(entry)
448 }
449
450 return files.sort()
451 }
452
453 throw new TypeError(`${name} list must be an array. Received type ${typeof value} (${value})`)
454}
455
456function transformImportsMap(value, root, conditionalRoot, opts, fn) {
457 const { conditions = {} } = opts
458
459 const imports = {}
460
461 for (const entry of Object.entries(value)) {
462 const condition = entry[0]
463
464 imports[condition] = transformImportsMapEntry(
465 entry[1],
466 root,
467 conditionalRoot || conditions[condition],
468 opts,
469 fn
470 )
471 }
472
473 return imports
474}
475
476function transformImportsMapEntry(value, root, conditionalRoot, opts, fn) {
477 const { conditions = {} } = opts
478
479 if (typeof value === 'string') {
480 return fn(value, conditionalRoot || conditions.default || root)
481 }
482
483 return transformImportsMap(value, root, conditionalRoot, opts, fn)
484}
485
486function transformResolutionsMap(value, root, opts, fn) {
487 const resolutions = {}
488
489 for (const entry of Object.entries(value)) {
490 resolutions[fn(entry[0], root)] = transformImportsMap(entry[1], root, null, opts, fn)
491 }
492
493 return resolutions
494}
495
496function transformFilesList(value, root, fn) {
497 const files = []
498
499 for (const entry of value) {
500 files.push(fn(entry, root))
501 }
502
503 return files
504}
505
506function mountSpecifier(specifier, root) {
507 if (startsWithWindowsDriveLetter(specifier)) {
508 specifier = '/' + specifier
509 }
510
511 if (specifier[0] === '/' || specifier[0] === '\\') {
512 specifier = '.' + specifier
513 }
514
515 if (specifier.startsWith('./') || specifier.startsWith('.\\')) {
516 return new URL(specifier, root).href
517 }
518
519 return specifier
520}
521
522function unmountSpecifier(specifier, root) {
523 specifier = new URL(specifier)
524
525 if (typeof root === 'string') root = new URL(root)
526
527 if (
528 specifier.protocol !== root.protocol ||
529 specifier.host !== root.host ||
530 specifier.port !== root.port
531 ) {
532 return specifier.href
533 }
534
535 const specifierPath = splitPath(specifier.pathname)
536 const rootPath = splitPath(root.pathname)
537
538 while (specifierPath.length > 0 && rootPath[0] === specifierPath[0]) {
539 specifierPath.shift()
540 rootPath.shift()
541 }
542
543 rootPath.fill('..')
544
545 return '/' + rootPath.concat(specifierPath).join('/')
546}
547
548function splitPath(path) {
549 const parts = path.split('/')
550
551 if (!parts[0]) parts.shift()
552 if (!parts[parts.length - 1]) parts.pop()
553
554 return parts
555}
556
557// https://infra.spec.whatwg.org/#ascii-upper-alpha
558function isASCIIUpperAlpha(c) {
559 return c >= 0x41 && c <= 0x5a
560}
561
562// https://infra.spec.whatwg.org/#ascii-lower-alpha
563function isASCIILowerAlpha(c) {
564 return c >= 0x61 && c <= 0x7a
565}
566
567// https://infra.spec.whatwg.org/#ascii-alpha
568function isASCIIAlpha(c) {
569 return isASCIIUpperAlpha(c) || isASCIILowerAlpha(c)
570}
571
572// https://url.spec.whatwg.org/#windows-drive-letter
573function isWindowsDriveLetter(input) {
574 return (
575 input.length >= 2 &&
576 isASCIIAlpha(input.charCodeAt(0)) &&
577 (input.charCodeAt(1) === 0x3a || input.charCodeAt(1) === 0x7c)
578 )
579}
580
581// https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
582function startsWithWindowsDriveLetter(input) {
583 return (
584 input.length >= 2 &&
585 isWindowsDriveLetter(input) &&
586 (input.length === 2 ||
587 input.charCodeAt(2) === 0x2f ||
588 input.charCodeAt(2) === 0x5c ||
589 input.charCodeAt(2) === 0x3f ||
590 input.charCodeAt(2) === 0x23)
591 )
592}
node_modules/bare-bundle/lib/errors.js +20 -0
……@@ -0,0 +1,20 @@
1module.exports = class BundleError extends Error {
2 constructor(msg, fn = BundleError, opts = {}) {
3 const { cause, code = fn.name } = opts
4
5 super(`${code}: ${msg}`, { cause })
6 this.code = code
7
8 if (Error.captureStackTrace) {
9 Error.captureStackTrace(this, fn)
10 }
11 }
12
13 get name() {
14 return 'BundleError'
15 }
16
17 static INVALID_BUNDLE_HEADER(msg, cause) {
18 return new BundleError(msg, BundleError.INVALID_BUNDLE_HEADER, { cause })
19 }
20}
node_modules/bare-bundle/package.json +49 -0
……@@ -0,0 +1,49 @@
1{
2 "name": "bare-bundle",
3 "version": "1.10.0",
4 "description": "Application bundle format for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json"
11 },
12 "files": [
13 "index.js",
14 "index.d.ts",
15 "lib"
16 ],
17 "scripts": {
18 "test": "prettier . --check && bare test.js"
19 },
20 "repository": {
21 "type": "git",
22 "url": "git+https://github.com/holepunchto/bare-bundle.git"
23 },
24 "author": "Holepunch",
25 "license": "Apache-2.0",
26 "bugs": {
27 "url": "https://github.com/holepunchto/bare-bundle/issues"
28 },
29 "homepage": "https://github.com/holepunchto/bare-bundle#readme",
30 "devDependencies": {
31 "bare-buffer": "^3.0.2",
32 "bare-url": "^2.1.3",
33 "brittle": "^3.1.1",
34 "prettier": "^3.4.2",
35 "prettier-config-holepunch": "^2.0.0"
36 },
37 "peerDependencies": {
38 "bare-buffer": "*",
39 "bare-url": "*"
40 },
41 "peerDependenciesMeta": {
42 "bare-buffer": {
43 "optional": true
44 },
45 "bare-url": {
46 "optional": true
47 }
48 }
49}
node_modules/bare-cov/LICENSE +202 -0
……@@ -0,0 +1,202 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
202
node_modules/bare-cov/README.md +38 -0
……@@ -0,0 +1,38 @@
1# bare-cov
2
3Run tests with coverage
4
5### Installation
6
7```
8npm i bare-cov
9```
10
11### Usage
12
13```js
14// Record coverage until current process ends and then generate reports
15require('bare-cov')(options)
16```
17
18### Options
19
20#### reporters
21
22Coverage reporter(s) to use (default: `['text', 'json']`)
23
24#### reporterOptions
25
26Options to pass to each reporter keyed by reporter (default: `{}`)
27
28#### dir
29
30Directory to write coverage reports to (default: `coverage`)
31
32#### skipRawDump
33
34Skip saving of raw v8 coverage data to disk (default: `false`)
35
36# License
37
38Apache-2.0
node_modules/bare-cov/index.js +45 -0
……@@ -0,0 +1,45 @@
1'use strict'
2
3const { isBare } = require('which-runtime')
4const { Session } = require('inspector')
5const fs = require('fs')
6const path = require('path')
7const Transformer = require('./lib/transformer')
8const process = require('process')
9
10module.exports = async function setupCoverage(opts = {}) {
11 const cwd = process.cwd()
12 const dir = path.resolve(opts.dir ?? 'coverage')
13 const session = new Session()
14 session.connect()
15
16 const sessionPost = (...args) =>
17 new Promise((resolve, reject) =>
18 session.post(...args, (err, result) => (err ? reject(err) : resolve(result)))
19 )
20
21 await sessionPost('Profiler.enable')
22 await sessionPost('Profiler.startPreciseCoverage', {
23 callCount: true,
24 detailed: true
25 })
26
27 process.once('beforeExit', async () => {
28 const v8Report = await sessionPost('Profiler.takePreciseCoverage')
29 isBare ? session.destroy() : session.disconnect()
30
31 if (opts.skipRawDump !== true) {
32 if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
33 fs.writeFileSync(path.join(dir, 'v8-coverage.json'), JSON.stringify(v8Report))
34 }
35
36 const reporters = Array.isArray(opts.reporters) ? opts.reporters : ['text', 'json']
37
38 const transformer = new Transformer({ ...opts, cwd })
39 const coverageMap = await transformer.transformToCoverageMap(v8Report)
40 if (reporters.includes('json')) {
41 fs.writeFileSync(path.join(dir, 'coverage-final.json'), JSON.stringify(coverageMap))
42 }
43 if (reporters.includes('text')) transformer.report(coverageMap)
44 })
45}
node_modules/bare-cov/lib/merge.js +118 -0
……@@ -0,0 +1,118 @@
1// Based on https://github.com/istanbuljs/istanbuljs/blob/main/packages/istanbul-lib-coverage/lib/file-coverage.js
2const isLineColumn = (o) => typeof o?.line === 'number' && typeof o?.column === 'number'
3const isLoc = (o) => isLineColumn(o?.start) && isLineColumn(o.end)
4const getLoc = (o) => (isLoc(o) ? o : isLoc(o.loc) ? o.loc : null)
5
6function findNearestContainer(coverageRecord, targetRecordMap) {
7 const loc = getLoc(coverageRecord)
8 if (!loc) return null
9
10 let container = { nearest: null, distance: null, key: null }
11 for (const [key, [, targetCoverageRecord]] of Object.entries(targetRecordMap)) {
12 const tLoc = getLoc(targetCoverageRecord)
13 if (!tLoc) continue
14
15 const distance = [
16 loc.start.line - tLoc.start.line,
17 loc.start.column - tLoc.start.column,
18 tLoc.end.line - loc.end.line,
19 tLoc.end.column - loc.end.column
20 ]
21 if (
22 distance[0] < 0 ||
23 distance[2] < 0 ||
24 (distance[0] === 0 && distance[1] < 0) ||
25 (distance[2] === 0 && distance[3] < 0)
26 )
27 continue
28 if (container.nearest === null) {
29 container = { nearest: targetCoverageRecord, distance, key }
30 continue
31 }
32
33 const closerBefore =
34 distance[0] < container.distance[0] ||
35 (distance[0] === 0 && distance[1] < container.distance[1])
36 const closerAfter =
37 distance[2] < container.distance[2] ||
38 (distance[2] === 0 && distance[3] < container.distance[3])
39 if (closerBefore || closerAfter) container = { nearest: targetCoverageRecord, distance, key }
40 }
41 return container.key
42}
43
44function addContainedHits(hits, coverageRecord, sourceRecord) {
45 const container = findNearestContainer(coverageRecord, sourceRecord)
46 return container ? addHits(hits, sourceRecord[container][0]) : hits
47}
48
49function addHits(a, b) {
50 if (typeof a === 'number' && typeof b === 'number') return a + b
51
52 if (Array.isArray(a) && Array.isArray(b)) {
53 if (a.length >= b.length) return a.map((hits, i) => hits + (b[i] || 0))
54 return b.map((hits, i) => hits + (a[i] || 0))
55 }
56
57 return null
58}
59
60function toHitMap(hits, map, toKey) {
61 return Object.entries(hits).reduce((acc, [id, value]) => {
62 const coverageRecord = map[id]
63 if (coverageRecord) acc[toKey(coverageRecord)] = [value, coverageRecord]
64 return acc
65 }, {})
66}
67
68function mergeHitMaps(a, b) {
69 const mergedRecords = {}
70 for (const [key, [hits, record]] of Object.entries(a)) {
71 const matchingValue = b[key]
72 const newHits = matchingValue
73 ? addHits(hits, matchingValue[0])
74 : addContainedHits(hits, record, b)
75 mergedRecords[key] = [newHits, record]
76 }
77
78 for (const [key, [hits, record]] of Object.entries(b)) {
79 if (mergedRecords[key]) continue
80 const newHits = addContainedHits(hits, record, a)
81 mergedRecords[key] = [newHits, record]
82 }
83
84 return Object.values(mergedRecords).reduce(
85 (acc, [hits, record], index) => {
86 acc.hits[index] = hits
87 acc.map[index] = record
88 return acc
89 },
90 { hits: {}, map: {} }
91 )
92}
93
94function mergeCoverages(a, b) {
95 const merged = { ...a }
96
97 const toKey = ({ start, end }) => `${start.line}|${start.column}|${end.line}|${end.column}`
98 ;({ hits: merged.s, map: merged.statementMap } = mergeHitMaps(
99 toHitMap(a.s, a.statementMap, toKey),
100 toHitMap(b.s, b.statementMap, toKey)
101 ))
102
103 const toKeyFn = ({ loc }) => toKey(loc)
104 ;({ hits: merged.f, map: merged.fnMap } = mergeHitMaps(
105 toHitMap(a.f, a.fnMap, toKeyFn),
106 toHitMap(b.f, b.fnMap, toKeyFn)
107 ))
108
109 const toKeyBranch = ({ locations }) => toKey(locations[0])
110 ;({ hits: merged.b, map: merged.branchMap } = mergeHitMaps(
111 toHitMap(a.b, a.branchMap, toKeyBranch),
112 toHitMap(b.b, b.branchMap, toKeyBranch)
113 ))
114
115 return merged
116}
117
118module.exports = mergeCoverages
node_modules/bare-cov/lib/report.js +215 -0
……@@ -0,0 +1,215 @@
1const path = require('path')
2const process = require('process')
3
4// TODO: colorize output if available
5
6const PERCENT_WIDTH = 9
7const DIR_INDENT = 1
8const FILE_INDENT = 2
9const TERMINAL_WIDTH = process?.stdout?.columns ?? 80
10const STATIC_WIDTH = PERCENT_WIDTH * 4 + 6 // 4 percent columns + 5 separators and 1 branch col space
11const MIN_NAME_WIDTH = 5
12const MIN_UNCOVERED_WIDTH = 17
13
14function findCommonPath(paths) {
15 const getCommon = (a, b) => {
16 let i = 0
17 while (i < a.length && i < b.length && a[i] === b[i]) i++
18 return a.slice(0, i)
19 }
20
21 if (!paths || paths.length === 0) return []
22
23 const splitPaths = paths.map((p) => p.split(path.sep))
24 return splitPaths.slice(1).reduce((acc, path) => {
25 return getCommon(acc, path)
26 }, splitPaths[0])
27}
28
29function truncate(str, width, right = false, delimiter = null) {
30 if (str.length <= width) return str
31 let truncateAt = right ? str.length - width + 1 : width - 1
32 if (delimiter) {
33 const nextSeparatorIndex = right
34 ? str.indexOf(delimiter, truncateAt)
35 : str.lastIndexOf(delimiter, truncateAt - 1)
36 if (nextSeparatorIndex === -1) return '…'
37 truncateAt = right ? nextSeparatorIndex : nextSeparatorIndex + 1
38 }
39 return right ? '…' + str.slice(truncateAt) : str.slice(0, truncateAt) + '…'
40}
41
42function toPercent(covered, total) {
43 if (total === 0 || covered === total) return '100'
44 if (covered === 0) return '0'
45 return ((covered / total) * 100).toFixed(2)
46}
47
48function ntimes(n, str) {
49 return Array(n).fill(str).join('')
50}
51
52function pad(str, width, right) {
53 if (str.length >= width) return str
54 const fill = ntimes(width - str.length, ' ')
55 return right ? str + fill : fill + str
56}
57
58function rowSeparator(nameWidth, uncoveredWidth) {
59 const name = ntimes(nameWidth, '-')
60 const uncovered = ntimes(uncoveredWidth, '-')
61 const percent = ntimes(PERCENT_WIDTH, '-')
62 const branch = ntimes(PERCENT_WIDTH + 1, '-')
63 return [name, percent, branch, percent, percent, uncovered].join('|')
64}
65
66function printHeader(nameWidth, uncoveredWidth) {
67 const name = pad('File', nameWidth, true)
68 const unc = pad(truncate('Uncovered Line #s', uncoveredWidth - 1), uncoveredWidth - 1, true)
69
70 console.log(`${name}| % Stmts | % Branch | % Funcs | % Lines | ${unc}`)
71}
72
73function printRow(fileSummary, fileName, nameWidth, uncoveredWidth) {
74 const statements = toPercent(fileSummary.covered.statements, fileSummary.total.statements)
75 const branches = toPercent(fileSummary.covered.branches, fileSummary.total.branches)
76 const functions = toPercent(fileSummary.covered.functions, fileSummary.total.functions)
77 const lines = toPercent(fileSummary.covered.lines, fileSummary.total.lines)
78
79 const uncoveredLines = fileSummary?.uncovered?.normalizedLines
80 ? fileSummary.uncovered.normalizedLines
81 : ' '
82
83 console.log(
84 [
85 pad(` ${truncate(fileName, nameWidth - 2)} `, nameWidth, true),
86 pad(` ${statements} `, PERCENT_WIDTH),
87 pad(` ${branches} `, PERCENT_WIDTH + 1),
88 pad(` ${functions} `, PERCENT_WIDTH),
89 pad(` ${lines} `, PERCENT_WIDTH),
90 pad(` ${truncate(uncoveredLines, uncoveredWidth - 2, true, ',')} `, uncoveredWidth, true)
91 ].join('|')
92 )
93}
94
95function deriveWidths(groupedSummaries) {
96 let nameWidth = MIN_NAME_WIDTH
97 let uncoveredWidth = MIN_UNCOVERED_WIDTH
98
99 for (const [dirName, dirSummary] of Object.entries(groupedSummaries)) {
100 if (dirName.length + DIR_INDENT > nameWidth) nameWidth = dirName.length + DIR_INDENT
101
102 for (const [fileName, fileSummary] of Object.entries(dirSummary.files)) {
103 const normalizedLines = fileSummary.uncovered?.normalizedLines
104 if (fileName.length + FILE_INDENT > nameWidth) nameWidth = fileName.length + FILE_INDENT
105 if (normalizedLines && normalizedLines.length > uncoveredWidth)
106 uncoveredWidth = normalizedLines.length
107 }
108 }
109
110 // Add left/right space padding
111 nameWidth += 2
112 uncoveredWidth += 2
113
114 if (nameWidth + uncoveredWidth + STATIC_WIDTH > TERMINAL_WIDTH) {
115 const availableWidth = TERMINAL_WIDTH - STATIC_WIDTH
116 nameWidth = Math.floor(availableWidth / 2)
117 uncoveredWidth = availableWidth - nameWidth
118 }
119
120 return { nameWidth, uncoveredWidth }
121}
122
123function normalizeUncoveredLines(uncoveredLines) {
124 if (!uncoveredLines || uncoveredLines.length === 0) return ''
125
126 const lines = uncoveredLines.map((line) => Number(line)).sort((a, b) => a - b)
127 const ranges = []
128 let start = lines[0]
129 let end = start
130
131 for (let i = 1; i < lines.length; i++) {
132 if (lines[i] === end + 1) {
133 end = lines[i]
134 continue
135 }
136
137 ranges.push(start === end ? `${start}` : `${start}-${end}`)
138 start = lines[i]
139 end = start
140 }
141 ranges.push(start === end ? `${start}` : `${start}-${end}`)
142
143 return ranges.join(',')
144}
145
146function addCoverages(a, b) {
147 a.covered.statements += b.covered.statements
148 a.covered.branches += b.covered.branches
149 a.covered.functions += b.covered.functions
150 a.covered.lines += b.covered.lines
151
152 a.total.statements += b.total.statements
153 a.total.branches += b.total.branches
154 a.total.functions += b.total.functions
155 a.total.lines += b.total.lines
156}
157
158function groupByDirectory(fileSummaries) {
159 const commonPath = findCommonPath(Object.keys(fileSummaries)).join(path.sep)
160 const commonDir = path.basename(commonPath)
161
162 const directories = {}
163 for (const [filePath, summary] of Object.entries(fileSummaries)) {
164 const relativePath = path.relative(commonPath, filePath).replace(/^\.\//g, '')
165 const pathName = path.join(commonDir, relativePath)
166 const directory = path.dirname(pathName)
167 const file = path.basename(pathName)
168 if (!directories[directory]) {
169 directories[directory] = {
170 files: {},
171 coverage: {
172 total: { statements: 0, branches: 0, functions: 0, lines: 0 },
173 covered: { statements: 0, branches: 0, functions: 0, lines: 0 }
174 }
175 }
176 }
177
178 directories[directory].files[file] = summary
179
180 addCoverages(directories[directory].coverage, summary)
181 }
182
183 return directories
184}
185
186function printBody(grouped, nameWidth, uncoveredWidth) {
187 for (const [dirName, dirSummary] of Object.entries(grouped)) {
188 printRow(dirSummary.coverage, `${ntimes(DIR_INDENT, ' ')}${dirName}`, nameWidth, uncoveredWidth)
189 for (const [fileName, fileSummary] of Object.entries(dirSummary.files)) {
190 printRow(fileSummary, `${ntimes(FILE_INDENT, ' ')}${fileName}`, nameWidth, uncoveredWidth)
191 }
192 }
193}
194
195module.exports = function reportCoverage({ summary, fileSummaries }) {
196 Object.values(fileSummaries).forEach((fileSummary) => {
197 fileSummary.uncovered.normalizedLines = normalizeUncoveredLines(fileSummary.uncovered.lines)
198 })
199
200 const grouped = groupByDirectory(fileSummaries)
201
202 const { nameWidth, uncoveredWidth } = deriveWidths(grouped)
203
204 const separator = rowSeparator(nameWidth, uncoveredWidth)
205 const printSeparator = () => console.log(separator)
206
207 printSeparator()
208 printHeader(nameWidth, uncoveredWidth)
209 printSeparator()
210
211 printRow(summary, 'All files', nameWidth, uncoveredWidth)
212 printBody(grouped, nameWidth, uncoveredWidth)
213
214 printSeparator()
215}
node_modules/bare-cov/lib/summarize.js +75 -0
……@@ -0,0 +1,75 @@
1function summarizeFileCoverage(file) {
2 const summary = {
3 total: { statements: 0, branches: 0, functions: 0, lines: 0 },
4 covered: { statements: 0, branches: 0, functions: 0, lines: 0 },
5 uncovered: { lines: [] }
6 }
7
8 if (file.s) {
9 const statements = Object.values(file.s)
10 summary.total.statements = statements.length
11 summary.covered.statements = statements.filter((hitCount) => hitCount > 0).length
12 }
13
14 if (file.b) {
15 for (const branch of Object.values(file.b)) {
16 summary.total.branches += branch.length
17 summary.covered.branches += branch.filter((hitCount) => hitCount > 0).length
18 }
19 }
20
21 if (file.f) {
22 const functions = Object.values(file.f)
23 summary.total.functions = functions.length
24 summary.covered.functions = functions.filter((hitCount) => hitCount > 0).length
25 }
26
27 let lineCoverage = file.l
28 if (!lineCoverage && file.s && file.statementMap) {
29 lineCoverage = {}
30 for (const [statementId, hitCount] of Object.entries(file.s)) {
31 const statementInfo = file.statementMap[statementId]
32 if (!statementInfo) continue
33
34 const { line } = statementInfo.start
35 const lastCount = lineCoverage[line]
36 if (lastCount === undefined || lastCount < hitCount) lineCoverage[line] = hitCount
37 }
38 }
39
40 const lines = Object.entries(lineCoverage)
41 summary.total.lines = lines.length
42 for (const [line, hitCount] of lines) {
43 if (hitCount > 0) summary.covered.lines++
44 else summary.uncovered.lines.push(line)
45 }
46
47 return summary
48}
49
50module.exports = function summarizeCoverage(coverageData) {
51 const summary = {
52 total: { statements: 0, branches: 0, functions: 0, lines: 0 },
53 covered: { statements: 0, branches: 0, functions: 0, lines: 0 }
54 }
55
56 const fileSummaries = {}
57
58 for (const [filename, file] of Object.entries(coverageData)) {
59 const fileSummary = (fileSummaries[filename] = summarizeFileCoverage(file))
60
61 summary.total.statements += fileSummary.total.statements
62 summary.covered.statements += fileSummary.covered.statements
63 summary.total.branches += fileSummary.total.branches
64 summary.covered.branches += fileSummary.covered.branches
65 summary.total.functions += fileSummary.total.functions
66 summary.covered.functions += fileSummary.covered.functions
67 summary.total.lines += fileSummary.total.lines
68 summary.covered.lines += fileSummary.covered.lines
69 }
70
71 return {
72 summary,
73 fileSummaries
74 }
75}
node_modules/bare-cov/lib/test-exclude.js +112 -0
……@@ -0,0 +1,112 @@
1const { isWindows } = require('which-runtime')
2const path = require('path')
3const process = require('process')
4const picomatch = require('picomatch')
5
6const DEFAULT_EXCLUDES = [
7 'coverage/**',
8 'packages/*/test{,s}/**',
9 '**/*.d.ts',
10 'test{,s}/**',
11 'test{,-*}.{js,cjs,mjs,ts,tsx,jsx}',
12 '**/*{.,-}test.{js,cjs,mjs,ts,tsx,jsx}',
13 '**/__tests__/**',
14 '**/{ava,babel,nyc}.config.{js,cjs,mjs}',
15 '**/jest.config.{js,cjs,mjs,ts}',
16 '**/{karma,rollup,webpack}.config.js',
17 '**/.{eslint,mocha}rc.{js,cjs}'
18]
19
20const DEFAULT_EXTENSIONS = ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx']
21
22function isOutsideDir(dir, filename) {
23 return isWindows
24 ? !path.resolve(dir, filename).startsWith(path.resolve(dir) + path.sep)
25 : /^\.\./.test(path.relative(dir, filename))
26}
27
28// Based off https://github.com/istanbuljs/test-exclude/blob/master/index.js with glob-related code removed and minimatch replaced with picomatch
29class TestExclude {
30 constructor(opts = {}) {
31 this.cwd = opts.cwd ?? process.cwd()
32 this.include = opts.include ?? []
33 this.exclude = opts.exclude ?? DEFAULT_EXCLUDES
34 this.extension = opts.extension ?? DEFAULT_EXTENSIONS
35 this.excludeNodeModules = opts.excludeNodeModules || true
36 this.relativePath = opts.relativePath || true
37
38 if (typeof this.include === 'string') this.include = [this.include]
39 if (typeof this.exclude === 'string') this.exclude = [this.exclude]
40
41 if (typeof this.extension === 'string') this.extension = [this.extension]
42 else if (this.extension.length === 0) this.extension = false
43
44 if (this.include && this.include.length > 0)
45 this.include = prepGlobPatterns([].concat(this.include))
46 else this.include = false
47
48 if (this.excludeNodeModules && !this.exclude.includes('**/node_modules/**'))
49 this.exclude = this.exclude.concat('**/node_modules/**')
50
51 this.exclude = prepGlobPatterns([].concat(this.exclude))
52
53 this.handleNegation()
54 }
55
56 /* handle the special case of negative globs
57 * (!**foo/bar); we create a new this.excludeNegated set
58 * of rules, which is applied after excludes and we
59 * move excluded include rules into this.excludes.
60 */
61 handleNegation() {
62 const noNeg = (e) => e.charAt(0) !== '!'
63 const onlyNeg = (e) => e.charAt(0) === '!'
64 const stripNeg = (e) => e.slice(1)
65
66 if (Array.isArray(this.include)) {
67 const includeNegated = this.include.filter(onlyNeg).map(stripNeg)
68 this.exclude.push(...prepGlobPatterns(includeNegated))
69 this.include = this.include.filter(noNeg)
70 }
71
72 this.excludeNegated = this.exclude.filter(onlyNeg).map(stripNeg)
73 this.exclude = this.exclude.filter(noNeg)
74 this.excludeNegated = prepGlobPatterns(this.excludeNegated)
75 }
76
77 shouldInstrument(filename, relFile) {
78 if (this.extension && !this.extension.some((ext) => filename.endsWith(ext))) return false
79
80 let pathToCheck = filename
81
82 if (this.relativePath) {
83 relFile = relFile || path.relative(this.cwd, filename)
84
85 // Don't instrument files that are outside of the current working directory.
86 if (isOutsideDir(this.cwd, filename)) return false
87
88 pathToCheck = relFile.replace(/^\.[\\/]/, '') // remove leading './' or '.\'.
89 }
90
91 const dot = { dot: true, windows: isWindows }
92 const matches = (pattern) => picomatch.isMatch(pathToCheck, pattern, dot)
93 return (
94 (!this.include || this.include.some(matches)) &&
95 (!this.exclude.some(matches) || this.excludeNegated.some(matches))
96 )
97 }
98}
99
100function prepGlobPatterns(patterns) {
101 return patterns.reduce((result, pattern) => {
102 // Allow gitignore style of directory exclusion
103 if (!/\/\*\*$/.test(pattern)) result = result.concat(pattern.replace(/\/$/, '') + '/**')
104
105 // Any rules of the form **/foo.js, should also match foo.js.
106 if (/^\*\*\//.test(pattern)) result = result.concat(pattern.replace(/^\*\*\//, ''))
107
108 return result.concat(pattern)
109 }, [])
110}
111
112module.exports = TestExclude
node_modules/bare-cov/lib/transformer.js +66 -0
……@@ -0,0 +1,66 @@
1'use strict'
2
3const { isAbsolute } = require('path')
4const { fileURLToPath } = require('url')
5const v8ToIstanbul = require('bare-v8-to-istanbul')
6const TestExclude = require('./test-exclude')
7const summarize = require('./summarize')
8const report = require('./report')
9const merge = require('./merge')
10
11class Transformer {
12 constructor(opts = {}) {
13 this.includeRelative = opts.includeRelative ?? false
14 this.exclude = new TestExclude({ cwd: opts.cwd })
15 this.includedUrlCache = new Map()
16 }
17
18 normalizeUrl(v8ReportResult) {
19 if (/^node:/.test(v8ReportResult.url)) {
20 v8ReportResult.url = `${v8ReportResult.url.replace(/^node:/, '')}.js`
21 }
22
23 if (/^file:\/\//.test(v8ReportResult.url)) {
24 v8ReportResult.url = fileURLToPath(v8ReportResult.url)
25 }
26
27 return v8ReportResult
28 }
29
30 isResultUrlIncluded(url) {
31 const cacheResult = this.includedUrlCache.get(url)
32 if (cacheResult !== undefined) return cacheResult
33
34 const result = (this.includeRelative || isAbsolute(url)) && this.exclude.shouldInstrument(url)
35 this.includedUrlCache.set(url, result)
36 return result
37 }
38
39 async transformToCoverageMap(rawV8Report) {
40 const v8Report = {
41 result: rawV8Report.result
42 .map((v8ReportResult) => this.normalizeUrl(v8ReportResult))
43 .filter((v8ReportResult) => this.isResultUrlIncluded(v8ReportResult.url))
44 }
45
46 const coverages = {}
47 for (const v8ReportResult of v8Report.result) {
48 const converter = v8ToIstanbul(v8ReportResult.url)
49 await converter.load()
50 converter.applyCoverage(v8ReportResult.functions)
51 const converted = converter.toIstanbul()
52
53 for (const [path, coverage] of Object.entries(converted)) {
54 coverages[path] = coverages[path] ? merge(coverages[path], coverage) : coverage
55 }
56 }
57
58 return coverages
59 }
60
61 report(coverage) {
62 report(summarize(coverage))
63 }
64}
65
66module.exports = Transformer
node_modules/bare-cov/package.json +68 -0
……@@ -0,0 +1,68 @@
1{
2 "name": "bare-cov",
3 "version": "1.2.1",
4 "description": "Generate coverage reports using Bare and Node.js",
5 "main": "index.js",
6 "scripts": {
7 "test": "node test",
8 "test:bare": "bare test",
9 "format": "prettier --write .",
10 "format:check": "prettier --check ."
11 },
12 "repository": {
13 "type": "git",
14 "url": "git+https://github.com/holepunchto/bare-cov.git"
15 },
16 "keywords": [
17 "bare",
18 "coverage",
19 "node",
20 "pear"
21 ],
22 "author": "Holepunch",
23 "license": "Apache-2.0",
24 "bugs": {
25 "url": "https://github.com/holepunchto/bare-cov/issues"
26 },
27 "homepage": "https://github.com/holepunchto/bare-cov#readme",
28 "imports": {
29 "fs": {
30 "bare": "bare-fs"
31 },
32 "path": {
33 "bare": "bare-path"
34 },
35 "process": {
36 "bare": "bare-process"
37 },
38 "url": {
39 "bare": "bare-url"
40 },
41 "inspector": {
42 "bare": "bare-inspector"
43 },
44 "child_process": {
45 "bare": "bare-subprocess"
46 }
47 },
48 "dependencies": {
49 "bare-fs": "^4.1.2",
50 "bare-inspector": "^4.0.1",
51 "bare-path": "^3.0.0",
52 "bare-process": "^4.2.1",
53 "bare-url": "^2.1.5",
54 "bare-v8-to-istanbul": "^1.0.2",
55 "picomatch": "^4.0.2",
56 "which-runtime": "^1.2.1"
57 },
58 "devDependencies": {
59 "bare-subprocess": "^5.0.3",
60 "brittle": "^3.13.1",
61 "prettier": "^3.6.2",
62 "prettier-config-holepunch": "^2.0.0"
63 },
64 "files": [
65 "index.js",
66 "lib"
67 ]
68}
node_modules/bare-crypto/CMakeLists.txt +35 -0
……@@ -0,0 +1,35 @@
1cmake_minimum_required(VERSION 4.0)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4find_package(cmake-fetch REQUIRED PATHS node_modules/cmake-fetch)
5
6project(bare_crypto C CXX)
7
8bare_target(target)
9
10if(target MATCHES "win32")
11 add_definitions(-DWIN32_LEAN_AND_MEAN)
12endif()
13
14if(target MATCHES "win32-x64")
15 enable_language(ASM_NASM)
16else()
17 enable_language(ASM)
18endif()
19
20fetch_package("github:google/boringssl#0.20260211.0")
21
22add_bare_module(bare_crypto)
23
24target_sources(
25 ${bare_crypto}
26 PRIVATE
27 binding.c
28)
29
30target_link_libraries(
31 ${bare_crypto}
32 PUBLIC
33 ssl
34 decrepit
35)
node_modules/bare-crypto/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-crypto/README.md +98 -0
……@@ -0,0 +1,98 @@
1# bare-crypto
2
3Cryptographic primitives for JavaScript.
4
5```
6npm i bare-crypto
7```
8
9## Usage
10
11```js
12const crypto = require('bare-crypto')
13
14const hash = crypto.createHash('sha256')
15
16hash.update('Hello, world!')
17
18const digest = hash.digest('hex')
19
20console.log(digest)
21```
22
23## API
24
25#### `const hash = createHash(algorithm[, options])`
26
27Create a new `Hash` instance with the specified algorithm and options. The options are passed to [`new Transform()`](https://github.com/mafintosh/streamx#ts--new-streamtransformoptions).
28
29#### `const hmac = createHmac(algorithm, key[, options])`
30
31Create a new `Hmac` instance with the specified algorithm, key, and options. The options are passed to [`new Transform()`](https://github.com/mafintosh/streamx#ts--new-streamtransformoptions).
32
33#### `const cipher = createCipheriv(algorithm, key, iv[, options])`
34
35Create a new `Cipheriv` instance using the specified algorithm, key, and initialization vector (`iv`). The options are passed to [`new Transform()`](https://github.com/mafintosh/streamx#ts--new-streamtransformoptions).
36
37#### `const decipher = createDecipheriv(algorithm, key, iv[, options])`
38
39Create a new `Decipheriv` instance using the specified algorithm, key, and initialization vector (`iv`). The options are passed to [`new Transform()`](https://github.com/mafintosh/streamx#ts--new-streamtransformoptions).
40
41#### `const buffer = randomBytes(size)`
42
43Generate cryptographically secure random bytes.
44
45#### `randomBytes(size, callback)`
46
47Generate cryptographically secure random bytes. The callback signature is `callback(err, buffer)`.
48
49#### `buffer = randomFill(buffer[, offset][, size])`
50
51Fill a buffer with cryptographically secure random bytes.
52
53#### `randomFill(buffer[, offset][, size], callback)`
54
55Fill a buffer with cryptographically secure random bytes. The callback signature is `callback(err, buffer)`
56
57#### `const buffer = pbkdf2(password, salt, iterations, keylen, digest)`
58
59Derive a key from a password and salt using the specified digest algorithm and number of iterations.
60
61#### `pbkdf2(password, salt, iterations, keylen, digest, callback)`
62
63Derive a key from a password and salt using the specified digest algorithm and number of iterations. The callback signature is `callback(err, buffer)`.
64
65#### `constants.hash`
66
67The supported hash algorithms.
68
69| Constant | Description |
70| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
71| `MD5` | A widely-used 128-bit hash function, now considered insecure due to vulnerabilities to collision attacks. Still fast but not recommended for security-sensitive purposes. |
72| `SHA1` | A 160-bit hash function, stronger than MD5 but also broken by collision attacks. Deprecated for most cryptographic uses due to security vulnerabilities. |
73| `SHA256` | Part of the SHA-2 family, this 256-bit hash function is widely used and considered secure for most applications. Slower than MD5 and SHA1 but much more secure. |
74| `SHA512` | Another member of the SHA-2 family, this 512-bit hash function offers greater security than SHA256 but is slower and produces larger hashes. Suitable for high-security environments. |
75| `BLAKE2B256` | A fast, secure alternative to SHA-2 designed for efficiency, producing a 256-bit hash. It is optimized for performance while maintaining strong cryptographic security. |
76
77#### `constants.cipher`
78
79The supported symmetric cipher algorithms.
80
81| Constant | Description |
82| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
83| `AES128ECB` | AES with a 128-bit key in ECB (Electronic Codebook) mode. Fast but insecure due to deterministic encryption of identical plaintext blocks. Not recommended. |
84| `AES128CBC` | AES with a 128-bit key in CBC (Cipher Block Chaining) mode. Provides better security than ECB by chaining blocks, but requires an IV and is slower. |
85| `AES128CTR` | AES with a 128-bit key in CTR (Counter) mode. A secure and parallelizable mode that turns a block cipher into a stream cipher. Requires a nonce/IV. |
86| `AES128OFB` | AES with a 128-bit key in OFB (Output Feedback) mode. Converts AES into a stream cipher; less common than CTR and more sensitive to IV reuse. |
87| `AES256ECB` | AES with a 256-bit key in ECB mode. Inherits the weaknesses of ECB; not suitable for encrypting more than a block at a time securely. |
88| `AES256CBC` | AES with a 256-bit key in CBC mode. Commonly used and reasonably secure with proper IV and padding management. |
89| `AES256CTR` | AES with a 256-bit key in CTR mode. Offers high performance and strong security if nonces are never reused. |
90| `AES256OFB` | AES with a 256-bit key in OFB mode. Like CTR, it turns AES into a stream cipher but with different feedback mechanics; less commonly used. |
91| `AES128GCM` | AES with a 128-bit key in GCM (Galois/Counter Mode). Provides authenticated encryption with associated data (AEAD). Fast and secure with proper nonce usage. |
92| `AES256GCM` | AES with a 256-bit key in GCM mode. Offers strong authenticated encryption; commonly used in TLS and secure messaging. |
93| `CHACHA20POLY1305` | A modern AEAD cipher combining the ChaCha20 stream cipher and Poly1305 MAC. Fast and secure, especially efficient on devices without AES hardware support. |
94| `XCHACHA20POLY1305` | An extended variant of ChaCha20-Poly1305 that supports longer nonces (192-bit). Improves nonce reuse resistance and is easier to use safely. |
95
96## License
97
98Apache-2.0
node_modules/bare-crypto/binding.c +1509 -0
……@@ -0,0 +1,1509 @@
1#include <assert.h>
2#include <bare.h>
3#include <js.h>
4#include <openssl/bytestring.h>
5#include <openssl/cipher.h>
6#include <openssl/curve25519.h>
7#include <openssl/digest.h>
8#include <openssl/evp.h>
9#include <openssl/hmac.h>
10#include <openssl/mem.h>
11#include <openssl/rand.h>
12#include <openssl/ripemd.h>
13#include <stddef.h>
14
15enum {
16 // Digests
17 bare_crypto_md5 = 1,
18 bare_crypto_sha1,
19 bare_crypto_sha256,
20 bare_crypto_sha384,
21 bare_crypto_sha512,
22 bare_crypto_blake2b256,
23 bare_crypto_ripemd160,
24
25 // Unauthenticated ciphers
26 bare_crypto_aes_128_ecb,
27 bare_crypto_aes_128_cbc,
28 bare_crypto_aes_128_ctr,
29 bare_crypto_aes_128_ofb,
30 bare_crypto_aes_256_ecb,
31 bare_crypto_aes_256_cbc,
32 bare_crypto_aes_256_ctr,
33 bare_crypto_aes_256_ofb,
34
35 // Authenticated ciphers
36 bare_crypto_aes_128_gcm,
37 bare_crypto_aes_256_gcm,
38 bare_crypto_chacha20_poly1305,
39 bare_crypto_xchacha20_poly1305,
40
41 // Signature algorithms
42 bare_crypto_ed25519,
43};
44
45typedef struct {
46 EVP_MD_CTX context;
47} bare_crypto_digest_t;
48
49typedef struct {
50 RIPEMD160_CTX context;
51} bare_crypto_ripemd160_t;
52
53typedef struct {
54 HMAC_CTX context;
55} bare_crypto_hmac_t;
56
57typedef struct {
58 EVP_CIPHER_CTX context;
59} bare_crypto_cipher_t;
60
61typedef struct {
62 EVP_AEAD_CTX context;
63} bare_crypto_aead_t;
64
65static inline const EVP_MD *
66bare_crypto__to_digest(js_env_t *env, int type) {
67 int err;
68
69 switch (type) {
70#define V(algorithm) \
71 case bare_crypto_##algorithm: \
72 return EVP_##algorithm();
73
74 V(md5)
75 V(sha1)
76 V(sha256)
77 V(sha384)
78 V(sha512)
79 V(blake2b256)
80#undef V
81
82 default:
83 err = js_throw_error(env, NULL, "Unknown digest algorithm");
84 assert(err == 0);
85
86 return NULL;
87 }
88}
89
90static inline const EVP_CIPHER *
91bare_crypto__to_cipher(js_env_t *env, int type) {
92 int err;
93
94 switch (type) {
95#define V(algorithm) \
96 case bare_crypto_##algorithm: \
97 return EVP_##algorithm();
98
99 V(aes_128_ecb)
100 V(aes_128_cbc)
101 V(aes_128_ctr)
102 V(aes_128_ofb)
103 V(aes_256_ecb)
104 V(aes_256_cbc)
105 V(aes_256_ctr)
106 V(aes_256_ofb)
107#undef V
108
109 default:
110 err = js_throw_error(env, NULL, "Unknown cipher algorithm");
111 assert(err == 0);
112
113 return NULL;
114 }
115}
116
117static inline const EVP_AEAD *
118bare_crypto__to_aead(js_env_t *env, int type) {
119 int err;
120
121 switch (type) {
122#define V(algorithm) \
123 case bare_crypto_##algorithm: \
124 return EVP_aead_##algorithm();
125
126 V(aes_128_gcm)
127 V(aes_256_gcm)
128 V(chacha20_poly1305)
129 V(xchacha20_poly1305)
130#undef V
131
132 default:
133 err = js_throw_error(env, NULL, "Unknown cipher algorithm");
134 assert(err == 0);
135
136 return NULL;
137 }
138}
139
140static js_value_t *
141bare_crypto_digest_init(js_env_t *env, js_callback_info_t *info) {
142 int err;
143
144 size_t argc = 1;
145 js_value_t *argv[1];
146
147 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
148 assert(err == 0);
149
150 assert(argc == 1);
151
152 uint32_t type;
153 err = js_get_value_uint32(env, argv[0], &type);
154 assert(err == 0);
155
156 js_value_t *handle;
157
158 bare_crypto_digest_t *digest;
159 err = js_create_arraybuffer(env, sizeof(bare_crypto_digest_t), (void **) &digest, &handle);
160 assert(err == 0);
161
162 const EVP_MD *algorithm = bare_crypto__to_digest(env, type);
163
164 if (algorithm == NULL) return NULL;
165
166 EVP_MD_CTX_init(&digest->context);
167
168 err = EVP_DigestInit(&digest->context, algorithm);
169 assert(err == 1);
170
171 return handle;
172}
173
174static js_value_t *
175bare_crypto_digest_update(js_env_t *env, js_callback_info_t *info) {
176 int err;
177
178 size_t argc = 4;
179 js_value_t *argv[4];
180
181 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
182 assert(err == 0);
183
184 assert(argc == 4);
185
186 bare_crypto_digest_t *digest;
187 err = js_get_arraybuffer_info(env, argv[0], (void **) &digest, NULL);
188 assert(err == 0);
189
190 void *data;
191 err = js_get_arraybuffer_info(env, argv[1], &data, NULL);
192 assert(err == 0);
193
194 int64_t offset;
195 err = js_get_value_int64(env, argv[2], &offset);
196 assert(err == 0);
197
198 int64_t len;
199 err = js_get_value_int64(env, argv[3], &len);
200 assert(err == 0);
201
202 err = EVP_DigestUpdate(&digest->context, &data[offset], len);
203 assert(err == 1);
204
205 return NULL;
206}
207
208static js_value_t *
209bare_crypto_digest_final(js_env_t *env, js_callback_info_t *info) {
210 int err;
211
212 size_t argc = 1;
213 js_value_t *argv[1];
214
215 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
216 assert(err == 0);
217
218 assert(argc == 1);
219
220 bare_crypto_digest_t *digest;
221 err = js_get_arraybuffer_info(env, argv[0], (void **) &digest, NULL);
222 assert(err == 0);
223
224 js_value_t *result;
225
226 size_t len = EVP_MD_CTX_size(&digest->context);
227
228 uint8_t *out;
229 err = js_create_arraybuffer(env, len, (void **) &out, &result);
230 assert(err == 0);
231
232 err = EVP_DigestFinal(&digest->context, out, NULL);
233 assert(err == 1);
234
235 return result;
236}
237
238static js_value_t *
239bare_crypto_ripemd160_init(js_env_t *env, js_callback_info_t *info) {
240 int err;
241
242 js_value_t *handle;
243
244 bare_crypto_ripemd160_t *ripemd160;
245 err = js_create_arraybuffer(env, sizeof(bare_crypto_ripemd160_t), (void **) &ripemd160, &handle);
246 assert(err == 0);
247
248 RIPEMD160_Init(&ripemd160->context);
249
250 return handle;
251}
252
253static js_value_t *
254bare_crypto_ripemd160_update(js_env_t *env, js_callback_info_t *info) {
255 int err;
256
257 size_t argc = 4;
258 js_value_t *argv[4];
259
260 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
261 assert(err == 0);
262
263 assert(argc == 4);
264
265 bare_crypto_ripemd160_t *ripemd160;
266 err = js_get_arraybuffer_info(env, argv[0], (void **) &ripemd160, NULL);
267 assert(err == 0);
268
269 void *data;
270 err = js_get_arraybuffer_info(env, argv[1], &data, NULL);
271 assert(err == 0);
272
273 int64_t offset;
274 err = js_get_value_int64(env, argv[2], &offset);
275 assert(err == 0);
276
277 int64_t len;
278 err = js_get_value_int64(env, argv[3], &len);
279 assert(err == 0);
280
281 err = RIPEMD160_Update(&ripemd160->context, &data[offset], len);
282 assert(err == 1);
283
284 return NULL;
285}
286
287static js_value_t *
288bare_crypto_ripemd160_final(js_env_t *env, js_callback_info_t *info) {
289 int err;
290
291 size_t argc = 1;
292 js_value_t *argv[1];
293
294 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
295 assert(err == 0);
296
297 assert(argc == 1);
298
299 bare_crypto_ripemd160_t *ripemd160;
300 err = js_get_arraybuffer_info(env, argv[0], (void **) &ripemd160, NULL);
301 assert(err == 0);
302
303 js_value_t *result;
304
305 uint8_t *out;
306 err = js_create_arraybuffer(env, RIPEMD160_DIGEST_LENGTH, (void **) &out, &result);
307 assert(err == 0);
308
309 err = RIPEMD160_Final(out, &ripemd160->context);
310 assert(err == 1);
311
312 return result;
313}
314
315static js_value_t *
316bare_crypto_hmac_init(js_env_t *env, js_callback_info_t *info) {
317 int err;
318
319 size_t argc = 4;
320 js_value_t *argv[4];
321
322 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
323 assert(err == 0);
324
325 assert(argc == 4);
326
327 uint32_t type;
328 err = js_get_value_uint32(env, argv[0], &type);
329 assert(err == 0);
330
331 char *key;
332 err = js_get_arraybuffer_info(env, argv[1], (void **) &key, NULL);
333 assert(err == 0);
334
335 int64_t offset;
336 err = js_get_value_int64(env, argv[2], &offset);
337 assert(err == 0);
338
339 int64_t len;
340 err = js_get_value_int64(env, argv[3], &len);
341 assert(err == 0);
342
343 js_value_t *handle;
344
345 bare_crypto_hmac_t *hmac;
346 err = js_create_arraybuffer(env, sizeof(bare_crypto_hmac_t), (void **) &hmac, &handle);
347 assert(err == 0);
348
349 const EVP_MD *algorithm = bare_crypto__to_digest(env, type);
350
351 if (algorithm == NULL) return NULL;
352
353 HMAC_CTX_init(&hmac->context);
354
355 err = HMAC_Init_ex(&hmac->context, &key[offset], len, algorithm, NULL);
356 assert(err == 1);
357
358 return handle;
359}
360
361static js_value_t *
362bare_crypto_hmac_update(js_env_t *env, js_callback_info_t *info) {
363 int err;
364
365 size_t argc = 4;
366 js_value_t *argv[4];
367
368 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
369 assert(err == 0);
370
371 assert(argc == 4);
372
373 bare_crypto_hmac_t *hmac;
374 err = js_get_arraybuffer_info(env, argv[0], (void **) &hmac, NULL);
375 assert(err == 0);
376
377 void *data;
378 err = js_get_arraybuffer_info(env, argv[1], &data, NULL);
379 assert(err == 0);
380
381 int64_t offset;
382 err = js_get_value_int64(env, argv[2], &offset);
383 assert(err == 0);
384
385 int64_t len;
386 err = js_get_value_int64(env, argv[3], &len);
387 assert(err == 0);
388
389 err = HMAC_Update(&hmac->context, &data[offset], len);
390 assert(err == 1);
391
392 return NULL;
393}
394
395static js_value_t *
396bare_crypto_hmac_final(js_env_t *env, js_callback_info_t *info) {
397 int err;
398
399 size_t argc = 1;
400 js_value_t *argv[1];
401
402 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
403 assert(err == 0);
404
405 assert(argc == 1);
406
407 bare_crypto_hmac_t *hmac;
408 err = js_get_arraybuffer_info(env, argv[0], (void **) &hmac, NULL);
409 assert(err == 0);
410
411 js_value_t *result;
412
413 size_t len = HMAC_size(&hmac->context);
414
415 uint8_t *digest;
416 err = js_create_arraybuffer(env, len, (void **) &digest, &result);
417 assert(err == 0);
418
419 err = HMAC_Final(&hmac->context, digest, NULL);
420 assert(err == 1);
421
422 return result;
423}
424
425static js_value_t *
426bare_crypto_cipher_key_length(js_env_t *env, js_callback_info_t *info) {
427 int err;
428
429 size_t argc = 1;
430 js_value_t *argv[1];
431
432 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
433 assert(err == 0);
434
435 assert(argc == 1);
436
437 uint32_t type;
438 err = js_get_value_uint32(env, argv[0], &type);
439 assert(err == 0);
440
441 const EVP_CIPHER *algorithm = bare_crypto__to_cipher(env, type);
442
443 if (algorithm == NULL) return NULL;
444
445 js_value_t *result;
446 err = js_create_uint32(env, EVP_CIPHER_key_length(algorithm), &result);
447 assert(err == 0);
448
449 return result;
450}
451
452static js_value_t *
453bare_crypto_cipher_iv_length(js_env_t *env, js_callback_info_t *info) {
454 int err;
455
456 size_t argc = 1;
457 js_value_t *argv[1];
458
459 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
460 assert(err == 0);
461
462 assert(argc == 1);
463
464 uint32_t type;
465 err = js_get_value_uint32(env, argv[0], &type);
466 assert(err == 0);
467
468 const EVP_CIPHER *algorithm = bare_crypto__to_cipher(env, type);
469
470 if (algorithm == NULL) return NULL;
471
472 js_value_t *result;
473 err = js_create_uint32(env, EVP_CIPHER_iv_length(algorithm), &result);
474 assert(err == 0);
475
476 return result;
477}
478
479static js_value_t *
480bare_crypto_cipher_block_size(js_env_t *env, js_callback_info_t *info) {
481 int err;
482
483 size_t argc = 1;
484 js_value_t *argv[1];
485
486 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
487 assert(err == 0);
488
489 assert(argc == 1);
490
491 bare_crypto_cipher_t *cipher;
492 err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
493 assert(err == 0);
494
495 js_value_t *result;
496 err = js_create_uint32(env, EVP_CIPHER_CTX_block_size(&cipher->context), &result);
497 assert(err == 0);
498
499 return result;
500}
501
502static js_value_t *
503bare_crypto_cipher_init(js_env_t *env, js_callback_info_t *info) {
504 int err;
505
506 size_t argc = 8;
507 js_value_t *argv[8];
508
509 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
510 assert(err == 0);
511
512 assert(argc == 8);
513
514 uint32_t type;
515 err = js_get_value_uint32(env, argv[0], &type);
516 assert(err == 0);
517
518 uint8_t *key;
519 err = js_get_arraybuffer_info(env, argv[1], (void **) &key, NULL);
520 assert(err == 0);
521
522 int64_t key_offset;
523 err = js_get_value_int64(env, argv[2], &key_offset);
524 assert(err == 0);
525
526 int64_t key_len;
527 err = js_get_value_int64(env, argv[3], &key_len);
528 assert(err == 0);
529
530 uint8_t *iv;
531 err = js_get_arraybuffer_info(env, argv[4], (void **) &iv, NULL);
532 assert(err == 0);
533
534 int64_t iv_offset;
535 err = js_get_value_int64(env, argv[5], &iv_offset);
536 assert(err == 0);
537
538 int64_t iv_len;
539 err = js_get_value_int64(env, argv[6], &iv_len);
540 assert(err == 0);
541
542 bool encrypt;
543 err = js_get_value_bool(env, argv[7], &encrypt);
544 assert(err == 0);
545
546 js_value_t *handle;
547
548 bare_crypto_cipher_t *cipher;
549 err = js_create_arraybuffer(env, sizeof(bare_crypto_cipher_t), (void **) &cipher, &handle);
550 assert(err == 0);
551
552 const EVP_CIPHER *algorithm = bare_crypto__to_cipher(env, type);
553
554 if (algorithm == NULL) return NULL;
555
556 err = EVP_CipherInit(&cipher->context, algorithm, &key[key_offset], &iv[iv_offset], encrypt);
557 assert(err == 1);
558
559 return handle;
560}
561
562static js_value_t *
563bare_crypto_cipher_update(js_env_t *env, js_callback_info_t *info) {
564 int err;
565
566 size_t argc = 5;
567 js_value_t *argv[5];
568
569 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
570 assert(err == 0);
571
572 assert(argc == 5);
573
574 bare_crypto_cipher_t *cipher;
575 err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
576 assert(err == 0);
577
578 uint8_t *data;
579 err = js_get_arraybuffer_info(env, argv[1], (void **) &data, NULL);
580 assert(err == 0);
581
582 int64_t offset;
583 err = js_get_value_int64(env, argv[2], &offset);
584 assert(err == 0);
585
586 int64_t len;
587 err = js_get_value_int64(env, argv[3], &len);
588 assert(err == 0);
589
590 uint8_t *out;
591 err = js_get_arraybuffer_info(env, argv[4], (void **) &out, NULL);
592 assert(err == 0);
593
594 int written;
595 err = EVP_CipherUpdate(&cipher->context, out, &written, &data[offset], len);
596
597 if (err != 1) {
598 err = js_throw_error(env, NULL, "Cipher update failed");
599 assert(err == 0);
600
601 return NULL;
602 }
603
604 js_value_t *result;
605 err = js_create_int32(env, written, &result);
606 assert(err == 0);
607
608 return result;
609}
610
611static js_value_t *
612bare_crypto_cipher_final(js_env_t *env, js_callback_info_t *info) {
613 int err;
614
615 size_t argc = 2;
616 js_value_t *argv[2];
617
618 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
619 assert(err == 0);
620
621 assert(argc == 2);
622
623 bare_crypto_cipher_t *cipher;
624 err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
625 assert(err == 0);
626
627 uint8_t *out;
628 err = js_get_arraybuffer_info(env, argv[1], (void **) &out, NULL);
629 assert(err == 0);
630
631 int written;
632 err = EVP_CipherFinal(&cipher->context, out, &written);
633
634 EVP_CIPHER_CTX_cleanup(&cipher->context);
635
636 if (err != 1) {
637 err = js_throw_error(env, NULL, "Cipher finalisation failed");
638 assert(err == 0);
639
640 return NULL;
641 }
642
643 js_value_t *result;
644 err = js_create_int32(env, written, &result);
645 assert(err == 0);
646
647 return result;
648}
649
650static js_value_t *
651bare_crypto_cipher_set_padding(js_env_t *env, js_callback_info_t *info) {
652 int err;
653
654 size_t argc = 2;
655 js_value_t *argv[2];
656
657 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
658 assert(err == 0);
659
660 assert(argc == 2);
661
662 bare_crypto_cipher_t *cipher;
663 err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
664 assert(err == 0);
665
666 bool pad;
667 err = js_get_value_bool(env, argv[1], &pad);
668 assert(err == 0);
669
670 err = EVP_CIPHER_CTX_set_padding(&cipher->context, pad);
671 assert(err == 1);
672
673 return NULL;
674}
675
676static js_value_t *
677bare_crypto_aead_key_length(js_env_t *env, js_callback_info_t *info) {
678 int err;
679
680 size_t argc = 1;
681 js_value_t *argv[1];
682
683 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
684 assert(err == 0);
685
686 assert(argc == 1);
687
688 uint32_t type;
689 err = js_get_value_uint32(env, argv[0], &type);
690 assert(err == 0);
691
692 const EVP_AEAD *algorithm = bare_crypto__to_aead(env, type);
693
694 if (algorithm == NULL) return NULL;
695
696 js_value_t *result;
697 err = js_create_int64(env, EVP_AEAD_key_length(algorithm), &result);
698 assert(err == 0);
699
700 return result;
701}
702
703static js_value_t *
704bare_crypto_aead_nonce_length(js_env_t *env, js_callback_info_t *info) {
705 int err;
706
707 size_t argc = 1;
708 js_value_t *argv[1];
709
710 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
711 assert(err == 0);
712
713 assert(argc == 1);
714
715 uint32_t type;
716 err = js_get_value_uint32(env, argv[0], &type);
717 assert(err == 0);
718
719 const EVP_AEAD *algorithm = bare_crypto__to_aead(env, type);
720
721 if (algorithm == NULL) return NULL;
722
723 js_value_t *result;
724 err = js_create_int64(env, EVP_AEAD_nonce_length(algorithm), &result);
725 assert(err == 0);
726
727 return result;
728}
729
730static js_value_t *
731bare_crypto_aead_max_overhead(js_env_t *env, js_callback_info_t *info) {
732 int err;
733
734 size_t argc = 1;
735 js_value_t *argv[1];
736
737 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
738 assert(err == 0);
739
740 assert(argc == 1);
741
742 bare_crypto_aead_t *aead;
743 err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
744 assert(err == 0);
745
746 js_value_t *result;
747 err = js_create_int64(env, EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(&aead->context)), &result);
748 assert(err == 0);
749
750 return result;
751}
752
753static js_value_t *
754bare_crypto_aead_max_tag_length(js_env_t *env, js_callback_info_t *info) {
755 int err;
756
757 size_t argc = 1;
758 js_value_t *argv[1];
759
760 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
761 assert(err == 0);
762
763 assert(argc == 1);
764
765 bare_crypto_aead_t *aead;
766 err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
767 assert(err == 0);
768
769 js_value_t *result;
770 err = js_create_int64(env, EVP_AEAD_max_tag_len(EVP_AEAD_CTX_aead(&aead->context)), &result);
771 assert(err == 0);
772
773 return result;
774}
775
776static js_value_t *
777bare_crypto_aead_init(js_env_t *env, js_callback_info_t *info) {
778 int err;
779
780 size_t argc = 5;
781 js_value_t *argv[5];
782
783 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
784 assert(err == 0);
785
786 assert(argc == 5);
787
788 uint32_t type;
789 err = js_get_value_uint32(env, argv[0], &type);
790 assert(err == 0);
791
792 uint8_t *key;
793 err = js_get_arraybuffer_info(env, argv[1], (void **) &key, NULL);
794 assert(err == 0);
795
796 int64_t key_offset;
797 err = js_get_value_int64(env, argv[2], &key_offset);
798 assert(err == 0);
799
800 int64_t key_len;
801 err = js_get_value_int64(env, argv[3], &key_len);
802 assert(err == 0);
803
804 int64_t tag_len;
805 err = js_get_value_int64(env, argv[4], &tag_len);
806 assert(err == 0);
807
808 js_value_t *handle;
809
810 bare_crypto_aead_t *aead;
811 err = js_create_arraybuffer(env, sizeof(bare_crypto_aead_t), (void **) &aead, &handle);
812 assert(err == 0);
813
814 const EVP_AEAD *algorithm = bare_crypto__to_aead(env, type);
815
816 if (algorithm == NULL) return NULL;
817
818 err = EVP_AEAD_CTX_init(&aead->context, algorithm, &key[key_offset], key_len, tag_len, NULL);
819 assert(err == 1);
820
821 return handle;
822}
823
824static js_value_t *
825bare_crypto_aead_seal(js_env_t *env, js_callback_info_t *info) {
826 int err;
827
828 size_t argc = 11;
829 js_value_t *argv[11];
830
831 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
832 assert(err == 0);
833
834 assert(argc == 11);
835
836 bare_crypto_aead_t *aead;
837 err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
838 assert(err == 0);
839
840 uint8_t *data;
841 err = js_get_arraybuffer_info(env, argv[1], (void **) &data, NULL);
842 assert(err == 0);
843
844 int64_t data_offset;
845 err = js_get_value_int64(env, argv[2], &data_offset);
846 assert(err == 0);
847
848 int64_t data_len;
849 err = js_get_value_int64(env, argv[3], &data_len);
850 assert(err == 0);
851
852 uint8_t *nonce;
853 err = js_get_arraybuffer_info(env, argv[4], (void **) &nonce, NULL);
854 assert(err == 0);
855
856 int64_t nonce_offset;
857 err = js_get_value_int64(env, argv[5], &nonce_offset);
858 assert(err == 0);
859
860 int64_t nonce_len;
861 err = js_get_value_int64(env, argv[6], &nonce_len);
862 assert(err == 0);
863
864 uint8_t *ad;
865 err = js_get_arraybuffer_info(env, argv[7], (void **) &ad, NULL);
866 assert(err == 0);
867
868 int64_t ad_offset;
869 err = js_get_value_int64(env, argv[8], &ad_offset);
870 assert(err == 0);
871
872 int64_t ad_len;
873 err = js_get_value_int64(env, argv[9], &ad_len);
874 assert(err == 0);
875
876 size_t out_len;
877 uint8_t *out;
878 err = js_get_arraybuffer_info(env, argv[10], (void **) &out, &out_len);
879 assert(err == 0);
880
881 size_t written;
882 err = EVP_AEAD_CTX_seal(
883 &aead->context,
884 out,
885 &written,
886 out_len,
887 &nonce[nonce_offset],
888 nonce_len,
889 &data[data_offset],
890 data_len,
891 ad_len ? &ad[ad_offset] : NULL,
892 ad_len
893 );
894
895 EVP_AEAD_CTX_cleanup(&aead->context);
896
897 if (err != 1) {
898 err = js_throw_error(env, NULL, "Encryption failed");
899 assert(err == 0);
900 }
901
902 js_value_t *result;
903 err = js_create_int32(env, written, &result);
904 assert(err == 0);
905
906 return result;
907}
908
909static js_value_t *
910bare_crypto_aead_open(js_env_t *env, js_callback_info_t *info) {
911 int err;
912
913 size_t argc = 11;
914 js_value_t *argv[11];
915
916 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
917 assert(err == 0);
918
919 assert(argc == 11);
920
921 bare_crypto_aead_t *aead;
922 err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
923 assert(err == 0);
924
925 uint8_t *data;
926 err = js_get_arraybuffer_info(env, argv[1], (void **) &data, NULL);
927 assert(err == 0);
928
929 int64_t data_offset;
930 err = js_get_value_int64(env, argv[2], &data_offset);
931 assert(err == 0);
932
933 int64_t data_len;
934 err = js_get_value_int64(env, argv[3], &data_len);
935 assert(err == 0);
936
937 uint8_t *nonce;
938 err = js_get_arraybuffer_info(env, argv[4], (void **) &nonce, NULL);
939 assert(err == 0);
940
941 int64_t nonce_offset;
942 err = js_get_value_int64(env, argv[5], &nonce_offset);
943 assert(err == 0);
944
945 int64_t nonce_len;
946 err = js_get_value_int64(env, argv[6], &nonce_len);
947 assert(err == 0);
948
949 uint8_t *ad;
950 err = js_get_arraybuffer_info(env, argv[7], (void **) &ad, NULL);
951 assert(err == 0);
952
953 int64_t ad_offset;
954 err = js_get_value_int64(env, argv[8], &ad_offset);
955 assert(err == 0);
956
957 int64_t ad_len;
958 err = js_get_value_int64(env, argv[9], &ad_len);
959 assert(err == 0);
960
961 size_t out_len;
962 uint8_t *out;
963 err = js_get_arraybuffer_info(env, argv[10], (void **) &out, &out_len);
964 assert(err == 0);
965
966 size_t written;
967 err = EVP_AEAD_CTX_open(
968 &aead->context,
969 out,
970 &written,
971 out_len,
972 &nonce[nonce_offset],
973 nonce_len,
974 &data[data_offset],
975 data_len,
976 ad_len ? &ad[ad_offset] : NULL,
977 ad_len
978 );
979
980 EVP_AEAD_CTX_cleanup(&aead->context);
981
982 if (err != 1) {
983 err = js_throw_error(env, NULL, "Decryption failed");
984 assert(err == 0);
985 }
986
987 js_value_t *result;
988 err = js_create_int32(env, written, &result);
989 assert(err == 0);
990
991 return result;
992}
993
994static js_value_t *
995bare_crypto_ed25519_generate_keypair(js_env_t *env, js_callback_info_t *info) {
996 int err;
997
998 js_value_t *result;
999 err = js_create_object(env, &result);
1000 assert(err == 0);
1001
1002 js_value_t *handle;
1003
1004 uint8_t *public_key;
1005 err = js_create_arraybuffer(env, ED25519_PUBLIC_KEY_LEN, (void **) &public_key, &handle);
1006 assert(err == 0);
1007
1008 err = js_set_named_property(env, result, "publicKey", handle);
1009 assert(err == 0);
1010
1011 uint8_t *private_key;
1012 err = js_create_arraybuffer(env, ED25519_PRIVATE_KEY_LEN, (void **) &private_key, &handle);
1013 assert(err == 0);
1014
1015 err = js_set_named_property(env, result, "privateKey", handle);
1016 assert(err == 0);
1017
1018 ED25519_keypair(public_key, private_key);
1019
1020 return result;
1021}
1022
1023static js_value_t *
1024bare_crypto_ed25519_sign(js_env_t *env, js_callback_info_t *info) {
1025 int err;
1026
1027 size_t argc = 4;
1028 js_value_t *argv[4];
1029
1030 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1031 assert(err == 0);
1032
1033 assert(argc == 4);
1034
1035 uint8_t *data;
1036 err = js_get_arraybuffer_info(env, argv[0], (void **) &data, NULL);
1037 assert(err == 0);
1038
1039 uint32_t offset;
1040 err = js_get_value_uint32(env, argv[1], &offset);
1041 assert(err == 0);
1042
1043 uint32_t len;
1044 err = js_get_value_uint32(env, argv[2], &len);
1045 assert(err == 0);
1046
1047 uint8_t *private_key;
1048 err = js_get_arraybuffer_info(env, argv[3], (void **) &private_key, NULL);
1049 assert(err == 0);
1050
1051 js_value_t *handle;
1052
1053 uint8_t *signature;
1054 err = js_create_arraybuffer(env, ED25519_SIGNATURE_LEN, (void **) &signature, &handle);
1055 assert(err == 0);
1056
1057 err = ED25519_sign(signature, &data[offset], len, private_key);
1058 assert(err == 1);
1059
1060 return handle;
1061}
1062
1063static js_value_t *
1064bare_crypto_ed25519_verify(js_env_t *env, js_callback_info_t *info) {
1065 int err;
1066
1067 size_t argc = 6;
1068 js_value_t *argv[6];
1069
1070 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1071 assert(err == 0);
1072
1073 assert(argc == 6);
1074
1075 uint8_t *data;
1076 err = js_get_arraybuffer_info(env, argv[0], (void **) &data, NULL);
1077 assert(err == 0);
1078
1079 uint32_t data_offset;
1080 err = js_get_value_uint32(env, argv[1], &data_offset);
1081 assert(err == 0);
1082
1083 uint32_t data_len;
1084 err = js_get_value_uint32(env, argv[2], &data_len);
1085 assert(err == 0);
1086
1087 uint8_t *signature;
1088 err = js_get_arraybuffer_info(env, argv[3], (void **) &signature, NULL);
1089 assert(err == 0);
1090
1091 uint32_t signature_offset;
1092 err = js_get_value_uint32(env, argv[4], &signature_offset);
1093 assert(err == 0);
1094
1095 uint8_t *public_key;
1096 err = js_get_arraybuffer_info(env, argv[5], (void **) &public_key, NULL);
1097 assert(err == 0);
1098
1099 js_value_t *result;
1100 err = js_get_boolean(env, ED25519_verify(&data[data_offset], data_len, &signature[signature_offset], public_key), &result);
1101 assert(err == 0);
1102
1103 return result;
1104}
1105
1106static js_value_t *
1107bare_crypto_ed25519_to_spki(js_env_t *env, js_callback_info_t *info) {
1108 int err;
1109
1110 size_t argc = 1;
1111 js_value_t *argv[1];
1112
1113 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1114 assert(err == 0);
1115
1116 assert(argc == 1);
1117
1118 uint8_t *public_key;
1119 err = js_get_arraybuffer_info(env, argv[0], (void **) &public_key, NULL);
1120 assert(err == 0);
1121
1122 EVP_PKEY *pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, public_key, 32);
1123
1124 CBB bytes;
1125 err = CBB_init(&bytes, 0);
1126 assert(err == 1);
1127
1128 err = EVP_marshal_public_key(&bytes, pkey);
1129 assert(err == 1);
1130
1131 EVP_PKEY_free(pkey);
1132
1133 uint8_t *der;
1134 size_t len;
1135 err = CBB_finish(&bytes, &der, &len);
1136 assert(err == 1);
1137
1138 js_value_t *handle;
1139
1140 void *data;
1141 err = js_create_arraybuffer(env, len, &data, &handle);
1142 assert(err == 0);
1143
1144 memcpy(data, der, len);
1145
1146 OPENSSL_free(der);
1147
1148 return handle;
1149}
1150
1151static js_value_t *
1152bare_crypto_ed25519_from_spki(js_env_t *env, js_callback_info_t *info) {
1153 int err;
1154
1155 size_t argc = 3;
1156 js_value_t *argv[3];
1157
1158 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1159 assert(err == 0);
1160
1161 assert(argc == 3);
1162
1163 uint8_t *der;
1164 err = js_get_arraybuffer_info(env, argv[0], (void **) &der, NULL);
1165 assert(err == 0);
1166
1167 uint32_t offset;
1168 err = js_get_value_uint32(env, argv[1], &offset);
1169 assert(err == 0);
1170
1171 uint32_t len;
1172 err = js_get_value_uint32(env, argv[2], &len);
1173 assert(err == 0);
1174
1175 CBS bytes;
1176 CBS_init(&bytes, &der[offset], len);
1177
1178 EVP_PKEY *pkey = EVP_parse_public_key(&bytes);
1179
1180 if (pkey == NULL) {
1181 err = js_throw_error(env, NULL, "Invalid input");
1182 assert(err == 0);
1183
1184 return NULL;
1185 }
1186
1187 js_value_t *handle;
1188
1189 uint8_t *public_key;
1190 err = js_create_arraybuffer(env, ED25519_PUBLIC_KEY_LEN, (void **) &public_key, &handle);
1191 assert(err == 0);
1192
1193 size_t written = ED25519_PUBLIC_KEY_LEN;
1194 err = EVP_PKEY_get_raw_public_key(pkey, public_key, &written);
1195
1196 EVP_PKEY_free(pkey);
1197
1198 if (err != 1) {
1199 err = js_throw_error(env, NULL, "Invalid input");
1200 assert(err == 0);
1201
1202 return NULL;
1203 }
1204
1205 return handle;
1206}
1207
1208static js_value_t *
1209bare_crypto_ed25519_to_pkcs8(js_env_t *env, js_callback_info_t *info) {
1210 int err;
1211
1212 size_t argc = 1;
1213 js_value_t *argv[1];
1214
1215 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1216 assert(err == 0);
1217
1218 assert(argc == 1);
1219
1220 uint8_t *private_key;
1221 err = js_get_arraybuffer_info(env, argv[0], (void **) &private_key, NULL);
1222 assert(err == 0);
1223
1224 EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, private_key, 32);
1225
1226 CBB bytes;
1227 err = CBB_init(&bytes, 0);
1228 assert(err == 1);
1229
1230 err = EVP_marshal_private_key(&bytes, pkey);
1231 assert(err == 1);
1232
1233 EVP_PKEY_free(pkey);
1234
1235 uint8_t *der;
1236 size_t len;
1237 err = CBB_finish(&bytes, &der, &len);
1238 assert(err == 1);
1239
1240 js_value_t *handle;
1241
1242 void *data;
1243 err = js_create_arraybuffer(env, len, &data, &handle);
1244 assert(err == 0);
1245
1246 memcpy(data, der, len);
1247
1248 OPENSSL_free(der);
1249
1250 return handle;
1251}
1252
1253static js_value_t *
1254bare_crypto_ed25519_from_pkcs8(js_env_t *env, js_callback_info_t *info) {
1255 int err;
1256
1257 size_t argc = 3;
1258 js_value_t *argv[3];
1259
1260 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1261 assert(err == 0);
1262
1263 assert(argc == 3);
1264
1265 uint8_t *der;
1266 err = js_get_arraybuffer_info(env, argv[0], (void **) &der, NULL);
1267 assert(err == 0);
1268
1269 uint32_t offset;
1270 err = js_get_value_uint32(env, argv[1], &offset);
1271 assert(err == 0);
1272
1273 uint32_t len;
1274 err = js_get_value_uint32(env, argv[2], &len);
1275 assert(err == 0);
1276
1277 CBS bytes;
1278 CBS_init(&bytes, &der[offset], len);
1279
1280 EVP_PKEY *pkey = EVP_parse_private_key(&bytes);
1281
1282 if (pkey == NULL) {
1283 err = js_throw_error(env, NULL, "Invalid input");
1284 assert(err == 0);
1285
1286 return NULL;
1287 }
1288
1289 js_value_t *handle;
1290
1291 uint8_t *private_key;
1292 err = js_create_arraybuffer(env, ED25519_PRIVATE_KEY_LEN, (void **) &private_key, &handle);
1293 assert(err == 0);
1294
1295 size_t written = ED25519_PRIVATE_KEY_LEN;
1296 err = EVP_PKEY_get_raw_private_key(pkey, private_key, &written);
1297
1298 if (err != 1) {
1299 EVP_PKEY_free(pkey);
1300
1301 err = js_throw_error(env, NULL, "Invalid input");
1302 assert(err == 0);
1303
1304 return NULL;
1305 }
1306
1307 written = ED25519_PUBLIC_KEY_LEN;
1308 err = EVP_PKEY_get_raw_public_key(pkey, &private_key[32], &written);
1309
1310 EVP_PKEY_free(pkey);
1311
1312 if (err != 1) {
1313 err = js_throw_error(env, NULL, "Invalid input");
1314 assert(err == 0);
1315
1316 return NULL;
1317 }
1318
1319 return handle;
1320}
1321
1322static js_value_t *
1323bare_crypto_random_fill(js_env_t *env, js_callback_info_t *info) {
1324 int err;
1325
1326 size_t argc = 3;
1327 js_value_t *argv[3];
1328
1329 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1330 assert(err == 0);
1331
1332 assert(argc == 3);
1333
1334 uint8_t *data;
1335 err = js_get_arraybuffer_info(env, argv[0], (void **) &data, NULL);
1336 assert(err == 0);
1337
1338 uint32_t offset;
1339 err = js_get_value_uint32(env, argv[1], &offset);
1340 assert(err == 0);
1341
1342 uint32_t len;
1343 err = js_get_value_uint32(env, argv[2], &len);
1344 assert(err == 0);
1345
1346 err = RAND_bytes(&data[offset], len);
1347 assert(err == 1);
1348
1349 return NULL;
1350}
1351
1352static js_value_t *
1353bare_crypto_pbkdf2(js_env_t *env, js_callback_info_t *info) {
1354 int err;
1355
1356 size_t argc = 9;
1357 js_value_t *argv[9];
1358
1359 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1360 assert(err == 0);
1361
1362 assert(argc == 9);
1363
1364 char *password;
1365 err = js_get_arraybuffer_info(env, argv[0], (void **) &password, NULL);
1366 assert(err == 0);
1367
1368 int64_t password_offset;
1369 err = js_get_value_int64(env, argv[1], &password_offset);
1370 assert(err == 0);
1371
1372 int64_t password_len;
1373 err = js_get_value_int64(env, argv[2], &password_len);
1374 assert(err == 0);
1375
1376 uint8_t *salt;
1377 err = js_get_arraybuffer_info(env, argv[3], (void **) &salt, NULL);
1378 assert(err == 0);
1379
1380 int64_t salt_offset;
1381 err = js_get_value_int64(env, argv[4], &salt_offset);
1382 assert(err == 0);
1383
1384 int64_t salt_len;
1385 err = js_get_value_int64(env, argv[5], &salt_len);
1386 assert(err == 0);
1387
1388 uint32_t iterations;
1389 err = js_get_value_uint32(env, argv[6], &iterations);
1390 assert(err == 0);
1391
1392 uint32_t type;
1393 err = js_get_value_uint32(env, argv[7], &type);
1394 assert(err == 0);
1395
1396 int64_t key_len;
1397 err = js_get_value_int64(env, argv[8], &key_len);
1398 assert(err == 0);
1399
1400 js_value_t *handle;
1401
1402 uint8_t *out;
1403 err = js_create_arraybuffer(env, key_len, (void **) &out, &handle);
1404 assert(err == 0);
1405
1406 const EVP_MD *algorithm = bare_crypto__to_digest(env, type);
1407
1408 if (algorithm == NULL) return NULL;
1409
1410 err = PKCS5_PBKDF2_HMAC(&password[password_offset], password_len, &salt[salt_offset], salt_len, iterations, algorithm, key_len, out);
1411 assert(err == 1);
1412
1413 return handle;
1414}
1415
1416static js_value_t *
1417bare_crypto_exports(js_env_t *env, js_value_t *exports) {
1418 int err;
1419
1420#define V(name, fn) \
1421 { \
1422 js_value_t *val; \
1423 err = js_create_function(env, name, -1, fn, NULL, &val); \
1424 assert(err == 0); \
1425 err = js_set_named_property(env, exports, name, val); \
1426 assert(err == 0); \
1427 }
1428
1429 V("digestInit", bare_crypto_digest_init)
1430 V("digestUpdate", bare_crypto_digest_update)
1431 V("digestFinal", bare_crypto_digest_final)
1432
1433 V("ripemd160Init", bare_crypto_ripemd160_init)
1434 V("ripemd160Update", bare_crypto_ripemd160_update)
1435 V("ripemd160Final", bare_crypto_ripemd160_final)
1436
1437 V("hmacInit", bare_crypto_hmac_init)
1438 V("hmacUpdate", bare_crypto_hmac_update)
1439 V("hmacFinal", bare_crypto_hmac_final)
1440
1441 V("cipherKeyLength", bare_crypto_cipher_key_length)
1442 V("cipherIVLength", bare_crypto_cipher_iv_length)
1443 V("cipherBlockSize", bare_crypto_cipher_block_size)
1444 V("cipherInit", bare_crypto_cipher_init)
1445 V("cipherUpdate", bare_crypto_cipher_update)
1446 V("cipherFinal", bare_crypto_cipher_final)
1447 V("cipherSetPadding", bare_crypto_cipher_set_padding)
1448
1449 V("aeadKeyLength", bare_crypto_aead_key_length)
1450 V("aeadNonceLength", bare_crypto_aead_nonce_length)
1451 V("aeadMaxOverhead", bare_crypto_aead_max_overhead)
1452 V("aeadMaxTagLength", bare_crypto_aead_max_tag_length)
1453 V("aeadInit", bare_crypto_aead_init)
1454 V("aeadSeal", bare_crypto_aead_seal)
1455 V("aeadOpen", bare_crypto_aead_open)
1456
1457 V("ed25519GenerateKeypair", bare_crypto_ed25519_generate_keypair)
1458 V("ed25519Sign", bare_crypto_ed25519_sign)
1459 V("ed25519Verify", bare_crypto_ed25519_verify)
1460 V("ed25519ToSPKI", bare_crypto_ed25519_to_spki)
1461 V("ed25519FromSPKI", bare_crypto_ed25519_from_spki)
1462 V("ed25519ToPKCS8", bare_crypto_ed25519_to_pkcs8)
1463 V("ed25519FromPKCS8", bare_crypto_ed25519_from_pkcs8)
1464
1465 V("randomFill", bare_crypto_random_fill)
1466
1467 V("pbkdf2", bare_crypto_pbkdf2);
1468#undef V
1469
1470#define V(name, n) \
1471 { \
1472 js_value_t *val; \
1473 err = js_create_uint32(env, n, &val); \
1474 assert(err == 0); \
1475 err = js_set_named_property(env, exports, name, val); \
1476 assert(err == 0); \
1477 }
1478
1479 // Digest algorithms
1480 V("MD5", bare_crypto_md5)
1481 V("SHA1", bare_crypto_sha1)
1482 V("SHA256", bare_crypto_sha256)
1483 V("SHA384", bare_crypto_sha384)
1484 V("SHA512", bare_crypto_sha512)
1485 V("BLAKE2B256", bare_crypto_blake2b256)
1486 V("RIPEMD160", bare_crypto_ripemd160)
1487
1488 // Cipher algorithms
1489 V("AES128ECB", bare_crypto_aes_128_ecb)
1490 V("AES128CBC", bare_crypto_aes_128_cbc)
1491 V("AES128CTR", bare_crypto_aes_128_ctr)
1492 V("AES128OFB", bare_crypto_aes_128_ofb)
1493 V("AES256ECB", bare_crypto_aes_256_ecb)
1494 V("AES256CBC", bare_crypto_aes_256_cbc)
1495 V("AES256CTR", bare_crypto_aes_256_ctr)
1496 V("AES256OFB", bare_crypto_aes_256_ofb)
1497 V("AES128GCM", bare_crypto_aes_128_gcm)
1498 V("AES256GCM", bare_crypto_aes_256_gcm)
1499 V("CHACHA20POLY1305", bare_crypto_chacha20_poly1305)
1500 V("XCHACHA20POLY1305", bare_crypto_xchacha20_poly1305)
1501
1502 // Signature algorithms
1503 V("ED25519", bare_crypto_ed25519)
1504#undef V
1505
1506 return exports;
1507}
1508
1509BARE_MODULE(bare_crypto, bare_crypto_exports)
node_modules/bare-crypto/binding.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon()
node_modules/bare-crypto/global.d.ts +7 -0
……@@ -0,0 +1,7 @@
1export * as crypto from './web'
2
3type Crypto = typeof crypto
4
5declare global {
6 const crypto: Crypto
7}
node_modules/bare-crypto/global.js +6 -0
……@@ -0,0 +1,6 @@
1const crypto = require('./web')
2
3global.crypto = crypto
4global.Crypto = crypto.Crypto
5global.CryptoKey = crypto.CryptoKey
6global.SubtleCrypto = crypto.SubtleCrypto
node_modules/bare-crypto/index.d.ts +69 -0
……@@ -0,0 +1,69 @@
1import { TransformOptions } from 'bare-stream'
2import Buffer from 'bare-buffer'
3import constants from './lib/constants'
4import Hash, { type HashAlgorithm } from './lib/hash'
5import Hmac from './lib/hmac'
6import { Cipheriv, Decipheriv, type CipherAlgorithm } from './lib/cipher'
7import { randomBytes, randomFill, randomUUID } from './lib/random'
8import pbkdf2 from './lib/pbkdf2'
9import { generateKeyPair } from './lib/key'
10import { sign, verify } from './lib/signature'
11import web from './web'
12
13declare function createHash(algorithm: HashAlgorithm | number, opts?: TransformOptions<Hash>): Hash
14
15declare function createHmac(
16 algorithm: HashAlgorithm | number,
17 key: string | Buffer,
18 opts?: TransformOptions<Hmac>
19): Hmac
20
21declare function createCipheriv(
22 algorithm: CipherAlgorithm | number,
23 key: string | Buffer,
24 iv: string | Buffer,
25 opts?: TransformOptions<Cipheriv>
26): Cipheriv
27
28declare function createDecipheriv(
29 algorithm: CipherAlgorithm | number,
30 key: string | Buffer,
31 iv: string | Buffer,
32 opts?: TransformOptions<Cipheriv>
33): Decipheriv
34
35declare function randomFillSync<B extends ArrayBuffer | ArrayBufferView>(
36 buffer: B,
37 offset?: number,
38 size?: number
39): B
40
41declare function pbkdf2Sync(
42 password: string | ArrayBufferView,
43 salt: string | ArrayBufferView,
44 iterations: number,
45 keylen: number,
46 digest: HashAlgorithm | number
47): Buffer
48
49export {
50 constants,
51 Hash,
52 createHash,
53 Hmac,
54 createHmac,
55 Cipheriv,
56 createCipheriv,
57 Decipheriv,
58 createDecipheriv,
59 randomBytes,
60 randomFill,
61 randomUUID,
62 randomFillSync,
63 pbkdf2,
64 pbkdf2Sync,
65 generateKeyPair,
66 sign,
67 verify,
68 web as webcrypto
69}
node_modules/bare-crypto/index.js +61 -0
……@@ -0,0 +1,61 @@
1const constants = require('./lib/constants')
2const Hash = require('./lib/hash')
3const Hmac = require('./lib/hmac')
4const { Cipheriv, Decipheriv } = require('./lib/cipher')
5const { randomBytes, randomFill, randomUUID } = require('./lib/random')
6const pbkdf2 = require('./lib/pbkdf2')
7const { generateKeyPair } = require('./lib/key')
8const { sign, verify } = require('./lib/signature')
9
10exports.constants = constants
11
12exports.Hash = Hash
13
14exports.createHash = function createHash(algorithm, opts) {
15 return new Hash(algorithm, opts)
16}
17
18exports.Hmac = Hmac
19
20exports.createHmac = function createHmac(algorithm, key, opts) {
21 return new Hmac(algorithm, key, opts)
22}
23
24exports.Cipheriv = Cipheriv
25
26exports.createCipheriv = function createCipheriv(algorithm, key, iv, opts) {
27 return new Cipheriv(algorithm, key, iv, opts)
28}
29
30exports.Decipheriv = Decipheriv
31
32exports.createDecipheriv = function createDecipheriv(algorithm, key, iv, opts) {
33 return new Decipheriv(algorithm, key, iv, opts)
34}
35
36exports.randomBytes = randomBytes
37
38exports.randomFill = randomFill
39
40// For Node.js compatibility
41exports.randomFillSync = function randomFillSync(buffer, offset, size) {
42 return exports.randomFill(buffer, offset, size)
43}
44
45exports.randomUUID = randomUUID
46
47exports.pbkdf2 = pbkdf2
48
49// For Node.js compatibility
50exports.pbkdf2Sync = function pbkdf2Sync(password, salt, iterations, keylen, digest) {
51 return exports.pbkdf2(password, salt, iterations, keylen, digest)
52}
53
54exports.generateKeyPair = generateKeyPair
55
56exports.sign = sign
57
58exports.verify = verify
59
60// For Node.js compatibility
61exports.webcrypto = require('./web')
node_modules/bare-crypto/lib/cipher.d.ts +62 -0
……@@ -0,0 +1,62 @@
1import { Transform, TransformOptions } from 'bare-stream'
2import Buffer, { BufferEncoding } from 'bare-buffer'
3
4export type CipherAlgorithm =
5 | 'aes-128-cbc'
6 | 'aes-128-ctr'
7 | 'aes-128-ecb'
8 | 'aes-128-gcm'
9 | 'aes-128-ofb'
10 | 'aes-256-cbc'
11 | 'aes-256-ctr'
12 | 'aes-256-ecb'
13 | 'aes-256-gcm'
14 | 'aes-256-ofb'
15 | 'chacha20-poly1305'
16 | 'xchacha20-poly1305'
17
18export class Cipheriv extends Transform {
19 constructor(
20 algorithm: CipherAlgorithm | number,
21 key: string | Buffer,
22 iv: string | Buffer,
23 opts?: TransformOptions<Cipheriv>
24 )
25
26 update(
27 data: string | Buffer,
28 inputEncoding?: BufferEncoding,
29 outputEncoding?: BufferEncoding
30 ): string | Buffer
31
32 final(outputEncoding?: BufferEncoding): string | Buffer
33
34 setAutoPadding(pad: unknown): this
35
36 setAAD(buffer: string | Buffer, opts?: { encoding?: BufferEncoding }): this
37
38 getAuthTag(): Buffer
39}
40
41export class Decipheriv extends Transform {
42 constructor(
43 algorithm: CipherAlgorithm | number,
44 key: string | Buffer,
45 iv: string | Buffer,
46 opts?: TransformOptions<Cipheriv>
47 )
48
49 update(
50 data: string | Buffer,
51 inputEncoding?: BufferEncoding,
52 outputEncoding?: BufferEncoding
53 ): string | Buffer
54
55 final(outputEncoding?: BufferEncoding): string | Buffer
56
57 setAutoPadding(pad: boolean): this
58
59 setAAD(buffer: string | Buffer, opts?: { encoding?: BufferEncoding }): this
60
61 setAuthTag(authTag: string | Buffer, encoding?: BufferEncoding): this
62}
node_modules/bare-crypto/lib/cipher.js +372 -0
……@@ -0,0 +1,372 @@
1const { Transform } = require('bare-stream')
2const assert = require('bare-assert')
3const binding = require('../binding')
4const constants = require('./constants')
5
6const {
7 cipher: {
8 AES128ECB,
9 AES128CBC,
10 AES128CTR,
11 AES128OFB,
12 AES256ECB,
13 AES256CBC,
14 AES256CTR,
15 AES256OFB,
16 AES128GCM,
17 AES256GCM,
18 CHACHA20POLY1305,
19 XCHACHA20POLY1305
20 }
21} = constants
22
23class CryptoCipher {
24 constructor(algorithm, key, iv, encrypt, opts = {}) {
25 const { encoding = 'utf8' } = opts
26
27 if (typeof key === 'string') key = Buffer.from(key, encoding)
28 if (typeof iv === 'string') iv = Buffer.from(iv, encoding)
29
30 assert(ArrayBuffer.isView(key))
31 assert(ArrayBuffer.isView(iv))
32
33 if (key.byteLength !== binding.cipherKeyLength(algorithm)) {
34 throw new RangeError('Invalid key length')
35 }
36
37 if (iv.byteLength < binding.cipherIVLength(algorithm)) {
38 throw new RangeError('Invalid iv length')
39 }
40
41 this._handle = binding.cipherInit(
42 algorithm,
43 key.buffer,
44 key.byteOffset,
45 key.byteLength,
46 iv.buffer,
47 iv.byteOffset,
48 iv.byteLength,
49 encrypt
50 )
51 }
52
53 update(data, inputEncoding = 'utf8', outputEncoding) {
54 if (this._handle === null) {
55 throw new Error('Cipher has already been finalized')
56 }
57
58 if (typeof data === 'string') data = Buffer.from(data, inputEncoding)
59
60 assert(ArrayBuffer.isView(data))
61
62 const out = new ArrayBuffer(data.byteLength + binding.cipherBlockSize(this._handle))
63
64 const written = binding.cipherUpdate(
65 this._handle,
66 data.buffer,
67 data.byteOffset,
68 data.byteLength,
69 out
70 )
71
72 const result = Buffer.from(out, 0, written)
73
74 return outputEncoding ? result.toString(outputEncoding) : result
75 }
76
77 final(outputEncoding) {
78 if (this._handle === null) {
79 throw new Error('Cipher has already been finalized')
80 }
81
82 const out = new ArrayBuffer(binding.cipherBlockSize(this._handle))
83
84 const written = binding.cipherFinal(this._handle, out)
85
86 this._handle = null
87
88 const result = Buffer.from(out, 0, written)
89
90 return outputEncoding ? result.toString(outputEncoding) : result
91 }
92
93 setAutoPadding(pad) {
94 if (this._handle === null) {
95 throw new Error('Cipher has already been finalized')
96 }
97
98 binding.cipherSetPadding(this._handle, pad)
99 }
100}
101
102class CryptoAuthenticatedCipher {
103 constructor(algorithm, key, nonce, opts = {}) {
104 const { encoding = 'utf8', authTagLength = 16 } = opts
105
106 if (typeof key === 'string') key = Buffer.from(key, encoding)
107 if (typeof nonce === 'string') nonce = Buffer.from(nonce, encoding)
108
109 assert(ArrayBuffer.isView(key))
110 assert(ArrayBuffer.isView(nonce))
111
112 if (key.byteLength !== binding.aeadKeyLength(algorithm)) {
113 throw new RangeError('Invalid key length')
114 }
115
116 if (nonce.byteLength < binding.aeadNonceLength(algorithm)) {
117 throw new RangeError('Invalid nonce length')
118 }
119
120 this._buffer = []
121 this._nonce = nonce
122 this._authTag = null
123 this._authTagLength = authTagLength
124 this._additionalData = null
125
126 this._handle = binding.aeadInit(
127 algorithm,
128 key.buffer,
129 key.byteOffset,
130 key.byteLength,
131 authTagLength
132 )
133 }
134
135 update(data, inputEncoding = 'utf8', outputEncoding) {
136 if (typeof data === 'string') data = Buffer.from(data, inputEncoding)
137
138 assert(ArrayBuffer.isView(data))
139
140 this._buffer.push(data)
141
142 return outputEncoding ? '' : Buffer.alloc(0)
143 }
144
145 setAAD(buffer, opts = {}) {
146 const { encoding = 'utf8' } = opts
147
148 if (typeof buffer === 'string') buffer = Buffer.from(buffer, encoding)
149
150 assert(ArrayBuffer.isView(buffer))
151
152 this._additionalData = buffer
153 }
154
155 getAuthTag() {
156 return this._authTag
157 }
158
159 setAuthTag(authTag, encoding) {
160 if (typeof authTag === 'string') authTag = Buffer.from(authTag, encoding)
161
162 assert(ArrayBuffer.isView(authTag))
163
164 this._authTag = authTag
165 }
166}
167
168class CryptoAuthenticatedSeal extends CryptoAuthenticatedCipher {
169 final(outputEncoding) {
170 if (this._handle === null) {
171 throw new Error('Cipher has already been finalized')
172 }
173
174 const data = this._buffer.length === 1 ? this._buffer[0] : Buffer.concat(this._buffer)
175
176 const nonce = this._nonce
177 const ad = this._additionalData || Buffer.alloc(0)
178
179 const out = new ArrayBuffer(data.byteLength + binding.aeadMaxOverhead(this._handle))
180
181 const written = binding.aeadSeal(
182 this._handle,
183 data.buffer,
184 data.byteOffset,
185 data.byteLength,
186 nonce.buffer,
187 nonce.byteOffset,
188 nonce.byteLength,
189 ad.buffer,
190 ad.byteOffset,
191 ad.byteLength,
192 out
193 )
194
195 this._handle = null
196
197 const cipherLength = written - this._authTagLength
198
199 this._authTag = Buffer.from(out, cipherLength)
200
201 const result = Buffer.from(out, 0, cipherLength)
202
203 return outputEncoding ? result.toString(outputEncoding) : result
204 }
205}
206
207class CryptoAuthenticatedOpen extends CryptoAuthenticatedCipher {
208 final(outputEncoding) {
209 if (this._handle === null) {
210 throw new Error('Decipher has already been finalized')
211 }
212
213 this._buffer.push(this._authTag)
214
215 const data = Buffer.concat(this._buffer)
216
217 const nonce = this._nonce
218 const ad = this._additionalData || Buffer.alloc(0)
219
220 const out = new ArrayBuffer(data.byteLength)
221
222 const written = binding.aeadOpen(
223 this._handle,
224 data.buffer,
225 data.byteOffset,
226 data.byteLength,
227 nonce.buffer,
228 nonce.byteOffset,
229 nonce.byteLength,
230 ad.buffer,
231 ad.byteOffset,
232 ad.byteLength,
233 out
234 )
235
236 this._handle = null
237
238 const result = Buffer.from(out, 0, written)
239
240 return outputEncoding ? result.toString(outputEncoding) : result
241 }
242}
243
244exports.Cipheriv = class CryptoCipheriv extends Transform {
245 constructor(algorithm, key, iv, opts = {}) {
246 super(opts)
247
248 algorithm = constants.toCipher(algorithm)
249
250 switch (algorithm) {
251 case AES128ECB:
252 case AES128CBC:
253 case AES128CTR:
254 case AES128OFB:
255 case AES256ECB:
256 case AES256CBC:
257 case AES256CTR:
258 case AES256OFB:
259 this._cipher = new CryptoCipher(algorithm, key, iv, true, opts)
260 break
261
262 case AES128GCM:
263 case AES256GCM:
264 case CHACHA20POLY1305:
265 case XCHACHA20POLY1305:
266 this._cipher = new CryptoAuthenticatedSeal(algorithm, key, iv, opts)
267 break
268 }
269 }
270
271 update(data, inputEncoding, outputEncoding) {
272 return this._cipher.update(data, inputEncoding, outputEncoding)
273 }
274
275 final(outputEncoding) {
276 return this._cipher.final(outputEncoding)
277 }
278
279 setAutoPadding(pad) {
280 this._cipher.setAutoPadding(pad)
281
282 return this
283 }
284
285 setAAD(buffer, opts) {
286 this._cipher.setAAD(buffer, opts)
287
288 return this
289 }
290
291 getAuthTag() {
292 return this._cipher.getAuthTag()
293 }
294
295 _transform(data, encoding, cb) {
296 this.push(this.update(data))
297
298 cb(null)
299 }
300
301 _flush(cb) {
302 this.push(this.final())
303
304 cb(null)
305 }
306}
307
308exports.Decipheriv = class CryptoDeipheriv extends Transform {
309 constructor(algorithm, key, iv, opts = {}) {
310 super(opts)
311
312 algorithm = constants.toCipher(algorithm)
313
314 switch (algorithm) {
315 case AES128ECB:
316 case AES128CBC:
317 case AES128CTR:
318 case AES128OFB:
319 case AES256ECB:
320 case AES256CBC:
321 case AES256CTR:
322 case AES256OFB:
323 this._cipher = new CryptoCipher(algorithm, key, iv, false, opts)
324 break
325
326 case AES128GCM:
327 case AES256GCM:
328 case CHACHA20POLY1305:
329 case XCHACHA20POLY1305:
330 this._cipher = new CryptoAuthenticatedOpen(algorithm, key, iv, opts)
331 break
332 }
333 }
334
335 update(data, inputEncoding, outputEncoding) {
336 return this._cipher.update(data, inputEncoding, outputEncoding)
337 }
338
339 final(outputEncoding) {
340 return this._cipher.final(outputEncoding)
341 }
342
343 setAutoPadding(pad) {
344 this._cipher.setAutoPadding(pad)
345
346 return this
347 }
348
349 setAAD(buffer, opts) {
350 this._cipher.setAAD(buffer, opts)
351
352 return this
353 }
354
355 setAuthTag(authTag, encoding) {
356 this._cipher.setAuthTag(authTag, encoding)
357
358 return this
359 }
360
361 _transform(data, encoding, cb) {
362 this.push(this.update(data))
363
364 cb(null)
365 }
366
367 _flush(cb) {
368 this.push(this.final())
369
370 cb(null)
371 }
372}
node_modules/bare-crypto/lib/constants.d.ts +12 -0
……@@ -0,0 +1,12 @@
1import { type HashAlgorithm } from './hash'
2import { type SignatureAlgorithm } from './signature'
3import { type CipherAlgorithm } from './cipher'
4
5declare const constants: {
6 hash: Record<HashAlgorithm, number>
7 signature: Record<SignatureAlgorithm, number>
8 cipher: Record<CipherAlgorithm, number>
9 keyType: Record<SignatureAlgorithm, number>
10}
11
12export = constants
node_modules/bare-crypto/lib/constants.js +99 -0
……@@ -0,0 +1,99 @@
1const { fail } = require('bare-assert')
2const binding = require('../binding')
3const errors = require('./errors')
4
5module.exports = exports = {
6 hash: {
7 MD5: binding.MD5,
8 SHA1: binding.SHA1,
9 SHA256: binding.SHA256,
10 SHA384: binding.SHA384,
11 SHA512: binding.SHA512,
12 BLAKE2B256: binding.BLAKE2B256,
13 RIPEMD160: binding.RIPEMD160
14 },
15 signature: {
16 ED25519: binding.ED25519
17 },
18 cipher: {
19 AES128ECB: binding.AES128ECB,
20 AES128CBC: binding.AES128CBC,
21 AES128CTR: binding.AES128CTR,
22 AES128OFB: binding.AES128OFB,
23 AES256ECB: binding.AES256ECB,
24 AES256CBC: binding.AES256CBC,
25 AES256CTR: binding.AES256CTR,
26 AES256OFB: binding.AES256OFB,
27 AES128GCM: binding.AES128GCM,
28 AES256GCM: binding.AES256GCM,
29 CHACHA20POLY1305: binding.CHACHA20POLY1305,
30 XCHACHA20POLY1305: binding.XCHACHA20POLY1305
31 },
32 keyType: {
33 ED25519: binding.ED25519
34 }
35}
36
37exports.toHash = function toHash(hash) {
38 if (typeof hash === 'number' && !isNaN(hash)) return hash
39
40 if (typeof hash === 'string') {
41 hash = hash.replace(/-/g, '')
42
43 if (hash in exports.hash === false) {
44 hash = hash.toUpperCase()
45
46 if (hash in exports.hash === false) {
47 throw errors.UNKNOWN_HASH(`Unknown hash '${hash}'`)
48 }
49 }
50
51 return exports.hash[hash]
52 }
53
54 fail(`Hash must be a number or string. Received ${isNaN(hash) ? 'NaN' : typeof hash} (${hash})`)
55}
56
57exports.toCipher = function toCiper(cipher) {
58 if (typeof cipher === 'number' && !isNaN(cipher)) return cipher
59
60 if (typeof cipher === 'string') {
61 cipher = cipher.replace(/-/g, '')
62
63 if (cipher in exports.cipher === false) {
64 cipher = cipher.toUpperCase()
65
66 if (cipher in exports.cipher === false) {
67 throw errors.UNKNOWN_CIPHER(`Unknown cipher '${cipher}'`)
68 }
69 }
70
71 return exports.cipher[cipher]
72 }
73
74 fail(
75 `Cipher must be a number or string. Received ${isNaN(cipher) ? 'NaN' : typeof cipher} (${cipher})`
76 )
77}
78
79exports.toKeyType = function toKeyType(type) {
80 if (typeof type === 'number' && !isNaN(type)) return type
81
82 if (typeof type === 'string') {
83 type = type.replace(/-/g, '')
84
85 if (type in exports.keyType === false) {
86 type = type.toUpperCase()
87
88 if (type in exports.keyType === false) {
89 throw errors.UNKNOWN_KEY_TYPE(`Unknown key type '${type}'`)
90 }
91 }
92
93 return exports.keyType[type]
94 }
95
96 fail(
97 `Key type must be a number or string. Received ${isNaN(type) ? 'NaN' : typeof type} (${type})`
98 )
99}
node_modules/bare-crypto/lib/errors.d.ts +11 -0
……@@ -0,0 +1,11 @@
1declare class CryptoError extends Error {
2 static UNKNOWN_HASH(msg: string): CryptoError
3 static UNKNOWN_CIPHER(msg: string): CryptoError
4 static UNKNOWN_KEY_TYPE(msg: string): CryptoError
5 static INVALID_ACCESS(msg: string): CryptoError
6 static INVALID_DATA(msg: string): CryptoError
7 static OPERATION_ERROR(msg: string): CryptoError
8 static NOT_SUPPORTED(msg: string): CryptoError
9}
10
11export = CryptoError
node_modules/bare-crypto/lib/errors.js +42 -0
……@@ -0,0 +1,42 @@
1module.exports = class CryptoError extends Error {
2 constructor(msg, fn = CryptoError, code = fn.name) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'CryptoError'
13 }
14
15 static UNKNOWN_HASH(msg) {
16 return new CryptoError(msg, CryptoError.UNKNOWN_HASH)
17 }
18
19 static UNKNOWN_CIPHER(msg) {
20 return new CryptoError(msg, CryptoError.UNKNOWN_CIPHER)
21 }
22
23 static UNKNOWN_KEY_TYPE(msg) {
24 return new CryptoError(msg, CryptoError.UNKNOWN_KEY_TYPE)
25 }
26
27 static INVALID_ACCESS(msg) {
28 return new CryptoError(msg, CryptoError.INVALID_ACCESS)
29 }
30
31 static INVALID_DATA(msg) {
32 return new CryptoError(msg, CryptoError.INVALID_DATA)
33 }
34
35 static OPERATION_ERROR(msg) {
36 return new CryptoError(msg, CryptoError.OPERATION_ERROR)
37 }
38
39 static NOT_SUPPORTED(msg) {
40 return new CryptoError(msg, CryptoError.NOT_SUPPORTED)
41 }
42}
node_modules/bare-crypto/lib/hash.d.ts +20 -0
……@@ -0,0 +1,20 @@
1import { Transform, TransformOptions } from 'bare-stream'
2import Buffer, { BufferEncoding } from 'bare-buffer'
3
4type HashAlgorithm = 'md5' | 'sha-1' | 'sha-256' | 'sha-512' | 'blake2b-256' | 'ripemd-160'
5
6declare class CryptoHash extends Transform {
7 constructor(algorithm: HashAlgorithm | number, opts?: TransformOptions<CryptoHash>)
8
9 update(data: string, encoding?: BufferEncoding): this
10 update(data: Buffer, encoding?: 'buffer'): this
11
12 digest(encoding: BufferEncoding): string
13 digest(): Buffer
14}
15
16declare namespace CryptoHash {
17 export { type HashAlgorithm }
18}
19
20export = CryptoHash
node_modules/bare-crypto/lib/hash.js +102 -0
……@@ -0,0 +1,102 @@
1const { Transform } = require('bare-stream')
2const assert = require('bare-assert')
3const binding = require('../binding')
4const constants = require('./constants')
5
6const {
7 hash: { RIPEMD160 }
8} = constants
9
10class CryptoDigest {
11 constructor(algorithm) {
12 this._handle = binding.digestInit(algorithm)
13 }
14
15 update(data) {
16 if (this._handle === null) {
17 throw new Error('Digest has already been finalized')
18 }
19
20 binding.digestUpdate(this._handle, data.buffer, data.byteOffset, data.byteLength)
21 }
22
23 final() {
24 if (this._handle === null) {
25 throw new Error('Digest has already been finalized')
26 }
27
28 const result = Buffer.from(binding.digestFinal(this._handle))
29 this._handle = null
30 return result
31 }
32}
33
34class CryptoRIPEMD160Digest {
35 constructor() {
36 this._handle = binding.ripemd160Init()
37 }
38
39 update(data) {
40 if (this._handle === null) {
41 throw new Error('Digest has already been finalized')
42 }
43
44 binding.ripemd160Update(this._handle, data.buffer, data.byteOffset, data.byteLength)
45 }
46
47 final() {
48 if (this._handle === null) {
49 throw new Error('Digest has already been finalized')
50 }
51
52 const result = Buffer.from(binding.ripemd160Final(this._handle))
53 this._handle = null
54 return result
55 }
56}
57
58module.exports = class CryptoHash extends Transform {
59 constructor(algorithm, opts = {}) {
60 super(opts)
61
62 algorithm = constants.toHash(algorithm)
63
64 switch (algorithm) {
65 case RIPEMD160:
66 this._digest = new CryptoRIPEMD160Digest()
67 break
68
69 default:
70 this._digest = new CryptoDigest(algorithm)
71 break
72 }
73 }
74
75 update(data, encoding = 'utf8') {
76 if (typeof data === 'string') data = Buffer.from(data, encoding)
77
78 assert(ArrayBuffer.isView(data))
79
80 this._digest.update(data)
81
82 return this
83 }
84
85 digest(encoding) {
86 const digest = this._digest.final()
87
88 return encoding && encoding !== 'buffer' ? digest.toString(encoding) : digest
89 }
90
91 _transform(data, encoding, cb) {
92 this.update(data)
93
94 cb(null)
95 }
96
97 _flush(cb) {
98 this.push(this.digest())
99
100 cb(null)
101 }
102}
node_modules/bare-crypto/lib/hmac.d.ts +19 -0
……@@ -0,0 +1,19 @@
1import { Transform, TransformOptions } from 'bare-stream'
2import Buffer, { BufferEncoding } from 'bare-buffer'
3import { type HashAlgorithm } from './hash'
4
5declare class CryptoHmac extends Transform {
6 constructor(
7 algorithm: HashAlgorithm | number,
8 key: string | Buffer,
9 opts?: TransformOptions<CryptoHmac>
10 )
11
12 update(data: string, encoding?: BufferEncoding): this
13 update(data: Buffer, encoding?: 'buffer'): this
14
15 digest(encoding: BufferEncoding): string
16 digest(): Buffer
17}
18
19export = CryptoHmac
node_modules/bare-crypto/lib/hmac.js +60 -0
……@@ -0,0 +1,60 @@
1const { Transform } = require('bare-stream')
2const assert = require('bare-assert')
3const binding = require('../binding')
4const constants = require('./constants')
5
6module.exports = class CryptoHmac extends Transform {
7 constructor(algorithm, key, opts = {}) {
8 super(opts)
9
10 const { encoding = 'utf8' } = opts
11
12 if (typeof key === 'string') key = Buffer.from(key, encoding)
13
14 assert(ArrayBuffer.isView(key))
15
16 this._handle = binding.hmacInit(
17 constants.toHash(algorithm),
18 key.buffer,
19 key.byteOffset,
20 key.byteLength
21 )
22 }
23
24 update(data, encoding = 'utf8') {
25 if (this._handle === null) {
26 throw new Error('Hmac has already been finalized')
27 }
28
29 if (typeof data === 'string') data = Buffer.from(data, encoding)
30
31 assert(ArrayBuffer.isView(data))
32
33 binding.hmacUpdate(this._handle, data.buffer, data.byteOffset, data.byteLength)
34
35 return this
36 }
37
38 digest(encoding) {
39 if (this._handle === null) {
40 throw new Error('Hmac has already been finalized')
41 }
42
43 const digest = Buffer.from(binding.hmacFinal(this._handle))
44 this._handle = null
45
46 return encoding && encoding !== 'buffer' ? digest.toString(encoding) : digest
47 }
48
49 _transform(data, encoding, cb) {
50 this.update(data)
51
52 cb(null)
53 }
54
55 _flush(cb) {
56 this.push(this.digest())
57
58 cb(null)
59 }
60}
node_modules/bare-crypto/lib/key.d.ts +27 -0
……@@ -0,0 +1,27 @@
1import { type SignatureAlgorithm } from './signature'
2
3declare class CryptoKey {}
4
5declare class CryptoEd25519Key extends CryptoKey {
6 readonly asymmetricKeyType: 'ed25519'
7}
8
9declare class CryptoEd25519PublicKey extends CryptoEd25519Key {
10 readonly type: 'public'
11}
12
13declare class CryptoEd25519PrivateKey extends CryptoEd25519Key {
14 readonly type: 'private'
15}
16
17declare function generateKeyPair(type: SignatureAlgorithm | Lowercase<SignatureAlgorithm>): {
18 publicKey: CryptoKey
19 privateKey: CryptoKey
20}
21
22export {
23 CryptoKey as Key,
24 CryptoEd25519PublicKey as Ed25519PublicKey,
25 CryptoEd25519PrivateKey as Ed25519PrivateKey,
26 generateKeyPair
27}
node_modules/bare-crypto/lib/key.js +57 -0
……@@ -0,0 +1,57 @@
1const binding = require('../binding')
2const constants = require('./constants')
3
4const {
5 keyType: { ED25519 }
6} = constants
7
8class CryptoKey {
9 constructor(keyType) {
10 this._keyType = keyType
11 }
12}
13
14exports.Key = CryptoKey
15
16class CryptoEd25519Key extends CryptoKey {
17 constructor(key) {
18 super(ED25519)
19
20 this._key = key
21 }
22
23 get asymmetricKeyType() {
24 return 'ed25519'
25 }
26}
27
28class CryptoEd25519PublicKey extends CryptoEd25519Key {
29 get type() {
30 return 'public'
31 }
32}
33
34exports.Ed25519PublicKey = CryptoEd25519PublicKey
35
36class CryptoEd25519PrivateKey extends CryptoEd25519Key {
37 get type() {
38 return 'private'
39 }
40}
41
42exports.Ed25519PrivateKey = CryptoEd25519PrivateKey
43
44exports.generateKeyPair = function generateKeyPair(type, opts = {}) {
45 type = constants.toKeyType(type)
46
47 switch (type) {
48 case ED25519: {
49 const { publicKey, privateKey } = binding.ed25519GenerateKeypair()
50
51 return {
52 publicKey: new CryptoEd25519PublicKey(publicKey),
53 privateKey: new CryptoEd25519PrivateKey(privateKey)
54 }
55 }
56 }
57}
node_modules/bare-crypto/lib/pbkdf2.d.ts +21 -0
……@@ -0,0 +1,21 @@
1import Buffer from 'bare-buffer'
2import { type HashAlgorithm } from './hash'
3
4declare function pbkdf2(
5 password: string | ArrayBuffer | ArrayBufferView,
6 salt: string | ArrayBuffer | ArrayBufferView,
7 iterations: number,
8 keylen: number,
9 digest: HashAlgorithm | number
10): Buffer
11
12declare function pbkdf2(
13 password: string | ArrayBuffer | ArrayBufferView,
14 salt: string | ArrayBuffer | ArrayBufferView,
15 iterations: number,
16 keylen: number,
17 digest: HashAlgorithm | number,
18 callback: (err: Error | null, buffer: Buffer) => void
19): void
20
21export = pbkdf2
node_modules/bare-crypto/lib/pbkdf2.js +35 -0
……@@ -0,0 +1,35 @@
1const assert = require('bare-assert')
2const binding = require('../binding')
3const constants = require('./constants')
4
5module.exports = function pbkdf2(password, salt, iterations, keylen, digest, cb) {
6 if (iterations <= 0) {
7 throw new RangeError('iterations is out of range')
8 }
9
10 assert(typeof iterations === 'number' && !isNaN(iterations))
11 assert(typeof keylen === 'number' && !isNaN(keylen))
12
13 if (typeof password === 'string') password = Buffer.from(password)
14 if (typeof salt === 'string') salt = Buffer.from(salt)
15
16 assert(ArrayBuffer.isView(password))
17 assert(ArrayBuffer.isView(salt))
18
19 const buffer = Buffer.from(
20 binding.pbkdf2(
21 password.buffer,
22 password.byteOffset,
23 password.byteLength,
24 salt.buffer,
25 salt.byteOffset,
26 salt.byteLength,
27 iterations,
28 constants.toHash(digest),
29 keylen
30 )
31 )
32
33 if (cb) queueMicrotask(() => cb(null, buffer))
34 else return buffer
35}
node_modules/bare-crypto/lib/random.d.ts +34 -0
……@@ -0,0 +1,34 @@
1import Buffer from 'bare-buffer'
2
3export function randomBytes(size: number): Buffer
4
5export function randomBytes(
6 size: number,
7 callback: (err: Error | null, buffer: Buffer) => void
8): void
9
10export function randomFill<B extends ArrayBuffer | ArrayBufferView>(
11 buffer: B,
12 offset?: number,
13 size?: number
14): B
15
16export function randomFill<B extends ArrayBuffer | ArrayBufferView>(
17 buffer: B,
18 callback: (err: Error | null, buffer: B) => void
19): void
20
21export function randomFill<B extends ArrayBuffer | ArrayBufferView>(
22 buffer: B,
23 offset: number,
24 callback: (err: Error | null, buffer: B) => void
25): void
26
27export function randomFill<B extends ArrayBuffer | ArrayBufferView>(
28 buffer: B,
29 offset: number,
30 size: number,
31 callback: (err: Error | null, buffer: B) => void
32): void
33
34export function randomUUID(): string
node_modules/bare-crypto/lib/random.js +78 -0
……@@ -0,0 +1,78 @@
1const assert = require('bare-assert')
2const binding = require('../binding')
3
4exports.randomBytes = function randomBytes(size, cb) {
5 assert(typeof size === 'number' && !isNaN(size))
6
7 const buffer = Buffer.allocUnsafe(size)
8 exports.randomFill(buffer)
9 if (cb) queueMicrotask(() => cb(null, buffer))
10 else return buffer
11}
12
13exports.randomFill = function randomFill(buffer, offset, size, cb) {
14 if (typeof offset === 'function') {
15 cb = offset
16 offset = undefined
17 } else if (typeof size === 'function') {
18 cb = size
19 size = undefined
20 }
21
22 assert(buffer instanceof ArrayBuffer || ArrayBuffer.isView(buffer))
23 assert(size === undefined || (typeof size === 'number' && !isNaN(size)))
24 assert(offset === undefined || (typeof offset === 'number' && !isNaN(offset)))
25
26 const elementSize = buffer.BYTES_PER_ELEMENT || 1
27
28 if (offset === undefined) offset = 0
29 else offset *= elementSize
30
31 if (size === undefined) size = buffer.byteLength - offset
32 else size *= elementSize
33
34 if (offset < 0 || offset > buffer.byteLength) {
35 throw new RangeError('offset is out of range')
36 }
37
38 if (size < 0 || size > buffer.byteLength) {
39 throw new RangeError('size is out of range')
40 }
41
42 if (offset + size > buffer.byteLength) {
43 throw new RangeError('offset + size is out of range')
44 }
45
46 let arraybuffer
47
48 if (ArrayBuffer.isView(buffer)) {
49 offset += buffer.byteOffset
50 arraybuffer = buffer.buffer
51 } else {
52 arraybuffer = buffer
53 }
54
55 binding.randomFill(arraybuffer, offset, size)
56
57 if (cb) queueMicrotask(() => cb(null, buffer))
58 else return buffer
59}
60
61exports.randomUUID = function randomUUID() {
62 const uuid = exports.randomBytes(16)
63
64 uuid[6] = (uuid[6] >>> 4) | 0b01000000
65 uuid[8] = (uuid[8] >>> 2) | 0b10000000
66
67 return (
68 uuid.subarray(0, 4).toString('hex') +
69 '-' +
70 uuid.subarray(4, 6).toString('hex') +
71 '-' +
72 uuid.subarray(6, 8).toString('hex') +
73 '-' +
74 uuid.subarray(8, 10).toString('hex') +
75 '-' +
76 uuid.subarray(10, 16).toString('hex')
77 )
78}
node_modules/bare-crypto/lib/signature.d.ts +13 -0
……@@ -0,0 +1,13 @@
1import Buffer from 'bare-buffer'
2import { Key as CryptoKey } from './key'
3
4export type SignatureAlgorithm = 'ed25519'
5
6export function sign(algorithm: null, data: ArrayBuffer | ArrayBufferView, key: CryptoKey): Buffer
7
8export function verify(
9 algorithm: null,
10 data: ArrayBuffer | ArrayBufferView,
11 key: CryptoKey,
12 signature: Buffer
13): boolean
node_modules/bare-crypto/lib/signature.js +61 -0
……@@ -0,0 +1,61 @@
1const assert = require('bare-assert')
2const binding = require('../binding')
3const { Key } = require('./key')
4const constants = require('./constants')
5
6const {
7 keyType: { ED25519 }
8} = constants
9
10exports.sign = function sign(algorithm, data, key) {
11 assert(data instanceof ArrayBuffer || ArrayBuffer.isView(data))
12
13 if (ArrayBuffer.isView(data)) {
14 data = Buffer.coerce(data)
15 } else {
16 data = Buffer.from(data)
17 }
18
19 assert(key instanceof Key)
20
21 switch (key._keyType) {
22 case ED25519:
23 return Buffer.from(
24 binding.ed25519Sign(data.buffer, data.byteOffset, data.byteLength, key._key)
25 )
26 }
27}
28
29exports.verify = function verify(algorithm, data, key, signature) {
30 assert(data instanceof ArrayBuffer || ArrayBuffer.isView(data))
31
32 if (ArrayBuffer.isView(data)) {
33 data = Buffer.coerce(data)
34 } else {
35 data = Buffer.from(data)
36 }
37
38 assert(signature instanceof ArrayBuffer || ArrayBuffer.isView(signature))
39
40 if (ArrayBuffer.isView(signature)) {
41 signature = Buffer.coerce(signature)
42 } else {
43 signature = Buffer.from(signature)
44 }
45
46 assert(key instanceof Key)
47
48 switch (key._keyType) {
49 case ED25519:
50 assert(signature.byteLength === 64)
51
52 return binding.ed25519Verify(
53 data.buffer,
54 data.byteOffset,
55 data.byteLength,
56 signature.buffer,
57 signature.byteOffset,
58 key._key
59 )
60 }
61}
node_modules/bare-crypto/lib/web/algorithm/ed25519.js +252 -0
……@@ -0,0 +1,252 @@
1const crypto = require('../../..')
2const binding = require('../../../binding')
3const errors = require('../../errors')
4const { Ed25519PublicKey, Ed25519PrivateKey } = require('../../key')
5const CryptoKey = require('../crypto-key')
6
7// https://w3c.github.io/webcrypto/#ed25519
8
9// https://w3c.github.io/webcrypto/#ed25519-operations-sign
10exports.sign = function sign(algorithm, key, data) {
11 if (key.type !== 'private') {
12 throw errors.INVALID_ACCESS('Must pass private key for Ed25519 signing')
13 }
14
15 const signature = crypto.sign(null, data, key._handle)
16
17 return signature.buffer.slice(0, signature.byteLength)
18}
19
20// https://w3c.github.io/webcrypto/#ed25519-operations-verify
21exports.verify = function verify(algorithm, key, signature, data) {
22 if (key.type !== 'public') {
23 throw errors.INVALID_ACCESS('Must pass public key for Ed25519 verification')
24 }
25
26 return crypto.verify(null, data, key._handle, signature)
27}
28
29// https://w3c.github.io/webcrypto/#ed25519-operations-generate-key
30exports.generateKey = function generateKey(algorithm, extractable, usages) {
31 for (const usage of usages) {
32 if (usage !== 'sign' && usage !== 'verify') {
33 throw new SyntaxError(
34 `Usage '${usage}' cannot be used for the Ed25519 generateKey() operation`
35 )
36 }
37 }
38
39 const keys = crypto.generateKeyPair('ed25519')
40
41 algorithm = { name: 'Ed25519' }
42
43 return {
44 publicKey: new CryptoKey('public', true, algorithm, ['verify'], keys.publicKey),
45 privateKey: new CryptoKey('private', extractable, algorithm, ['sign'], keys.privateKey)
46 }
47}
48
49// https://w3c.github.io/webcrypto/#ed25519-operations-import-key
50exports.importKey = function importKey(format, keyData, algorithm, extractable, usages) {
51 switch (format) {
52 case 'spki':
53 for (const usage of usages) {
54 if (usage !== 'verify') {
55 throw new SyntaxError(
56 `Usage '${usage}' cannot be used for the Ed25519 importKey() operation`
57 )
58 }
59 }
60
61 keyData = binding.ed25519FromSPKI(keyData.buffer, keyData.byteOffset, keyData.byteLength)
62
63 return new CryptoKey(
64 'public',
65 extractable,
66 {
67 name: 'Ed25519'
68 },
69 usages,
70 new Ed25519PublicKey(keyData)
71 )
72 case 'pkcs8':
73 for (const usage of usages) {
74 if (usage !== 'sign') {
75 throw new SyntaxError(
76 `Usage '${usage}' cannot be used for the Ed25519 importKey() operation`
77 )
78 }
79 }
80
81 keyData = binding.ed25519FromPKCS8(keyData.buffer, keyData.byteOffset, keyData.byteLength)
82
83 return new CryptoKey(
84 'private',
85 extractable,
86 {
87 name: 'Ed25519'
88 },
89 usages,
90 new Ed25519PrivateKey(keyData)
91 )
92 case 'raw':
93 for (const usage of usages) {
94 if (usage !== 'verify') {
95 throw new SyntaxError(
96 `Usage '${usage}' cannot be used for the Ed25519 importKey() operation`
97 )
98 }
99 }
100
101 if (keyData.byteLength * 8 !== 256) {
102 throw errors.INVALID_DATA('Key must be 256 bits')
103 }
104
105 return new CryptoKey(
106 'public',
107 extractable,
108 {
109 name: 'Ed25519'
110 },
111 usages,
112 new Ed25519PublicKey(keyData.buffer)
113 )
114 case 'jwk':
115 const jwk = keyData
116
117 if ('d' in jwk) {
118 if (usages.some((usage) => usage !== 'sign')) {
119 throw new SyntaxError('JWK must be valid for signing')
120 }
121 } else {
122 if (usages.some((usage) => usage !== 'verify')) {
123 throw new SyntaxError('JWK must be valid for verification')
124 }
125 }
126
127 if (jwk.kty !== 'OKP') {
128 throw errors.INVALID_DATA('JWK key must be an octet key-pair')
129 }
130
131 if (jwk.crv !== 'Ed25519') {
132 throw errors.INVALID_DATA('JWK must use the Ed25519 curve')
133 }
134
135 if ('alg' in jwk && jwk.alg !== 'Ed25519' && jwk.alg !== 'EdDSA') {
136 throw errors.INVALID_DATA('JWK must use the Ed25519 curve')
137 }
138
139 if (usages.length && 'use' in jwk && jwk.use !== 'sig') {
140 throw errors.INVALID_DATA('JWK cannot be used for signatures')
141 }
142
143 if ('ext' in jwk && jwk.ext !== extractable && extractable) {
144 throw errors.INVALID_DATA('JWK is not extractable')
145 }
146
147 if ('d' in jwk) {
148 const key = Buffer.concat([
149 Buffer.from(jwk.d, 'base64url'),
150 Buffer.from(jwk.x, 'base64url')
151 ])
152
153 if (key.byteLength * 8 !== 512) {
154 throw errors.INVALID_DATA('Key must be 512 bits')
155 }
156
157 return new CryptoKey(
158 'private',
159 extractable,
160 {
161 name: 'Ed25519'
162 },
163 usages,
164 new Ed25519PrivateKey(key.buffer)
165 )
166 }
167
168 const key = Buffer.from(jwk.x, 'base64url')
169
170 if (key.byteLength * 8 !== 256) {
171 throw errors.INVALID_DATA('Key must be 256 bits')
172 }
173
174 return new CryptoKey(
175 'public',
176 extractable,
177 {
178 name: 'Ed25519'
179 },
180 usages,
181 new Ed25519PublicKey(key.buffer)
182 )
183 default:
184 throw errors.NOT_SUPPORTED(
185 `Format '${format}' cannot be used for the Ed25519 importKey() operation`
186 )
187 }
188}
189
190// https://w3c.github.io/webcrypto/#ed25519-operations-export-key
191exports.exportKey = function exportKey(format, key) {
192 const data = key._handle
193
194 switch (format) {
195 case 'spki':
196 if (key.type !== 'public') {
197 throw errors.INVALID_ACCESS(
198 `Key of type '${key.type}' cannot be used for the Ed25519 exportKey() operation`
199 )
200 }
201
202 return binding.ed25519ToSPKI(data._key)
203 case 'pkcs8':
204 if (key.type !== 'private') {
205 throw errors.INVALID_ACCESS(
206 `Key of type '${key.type}' cannot be used for the Ed25519 exportKey() operation`
207 )
208 }
209
210 return binding.ed25519ToPKCS8(data._key)
211 case 'raw': {
212 if (key.type !== 'public') {
213 throw errors.INVALID_ACCESS(
214 `Key of type '${key.type}' cannot be used for the Ed25519 exportKey() operation`
215 )
216 }
217
218 return data._key.slice()
219 }
220 case 'jwk': {
221 const buffer = Buffer.from(data._key)
222
223 if (key.type === 'private') {
224 const d = buffer.subarray(0, 32).toString('base64url')
225 const x = buffer.subarray(32).toString('base64url')
226
227 return {
228 kty: 'OKP',
229 alg: 'Ed25519',
230 crv: 'Ed25519',
231 x,
232 d,
233 key_ops: key.usages,
234 ext: key.extractable
235 }
236 }
237
238 return {
239 kty: 'OKP',
240 alg: 'Ed25519',
241 crv: 'Ed25519',
242 x: buffer.toString('base64url'),
243 key_ops: key.usages,
244 ext: key.extractable
245 }
246 }
247 default:
248 throw errors.NOT_SUPPORTED(
249 `Format '${format}' cannot be used for the HMAC exportKey() operation`
250 )
251 }
252}
node_modules/bare-crypto/lib/web/algorithm/hmac.js +191 -0
……@@ -0,0 +1,191 @@
1const crypto = require('../../..')
2const errors = require('../../errors')
3const CryptoKey = require('../crypto-key')
4
5// https://w3c.github.io/webcrypto/#hmac
6
7// https://w3c.github.io/webcrypto/#hmac-operations-sign
8exports.sign = function sign(algorithm, key, data) {
9 const digest = crypto.createHmac(key.algorithm.hash.name, key._handle).update(data).digest()
10
11 return digest.buffer.slice(0, digest.byteLength)
12}
13
14// https://w3c.github.io/webcrypto/#hmac-operations-verify
15exports.verify = function verify(algorithm, key, signature, data) {
16 const digest = crypto.createHmac(key.algorithm.hash.name, key._handle).update(data).digest()
17
18 if (ArrayBuffer.isView(signature)) {
19 signature = Buffer.coerce(signature)
20 } else {
21 signature = Buffer.from(signature)
22 }
23
24 return signature.equals(digest)
25}
26
27// https://w3c.github.io/webcrypto/#hmac-operations-generate-key
28exports.generateKey = function generateKey(algorithm, extractable, usages) {
29 for (const usage of usages) {
30 if (usage !== 'sign' && usage !== 'verify') {
31 throw new SyntaxError(`Usage '${usage}' cannot be used for the HMAC generateKey() operation`)
32 }
33 }
34
35 const { length = exports.getKeyLength(algorithm) } = algorithm.length
36
37 let hash = algorithm.hash
38
39 if (typeof hash === 'string') hash = { name: hash }
40
41 const key = crypto.createHmac(hash.name, crypto.randomBytes(length)).digest()
42
43 return new CryptoKey(
44 'secret',
45 extractable,
46 {
47 name: 'HMAC',
48 length,
49 hash: {
50 name: hash.name.toUpperCase()
51 }
52 },
53 usages,
54 key
55 )
56}
57
58// https://w3c.github.io/webcrypto/#hmac-operations-import-key
59exports.importKey = function importKey(format, keyData, algorithm, extractable, usages) {
60 for (const usage of usages) {
61 if (usage !== 'sign' && usage !== 'verify') {
62 throw new SyntaxError(`Invalid usage ${usage}`)
63 }
64 }
65
66 let hash = algorithm.hash
67
68 if (typeof hash === 'string') hash = { name: hash }
69
70 let data
71
72 switch (format) {
73 case 'raw':
74 data = keyData
75 break
76 case 'jwk':
77 const jwk = keyData
78
79 if (jwk.kty !== 'oct') {
80 throw errors.INVALID_DATA('JWK key must be an octet sequence')
81 }
82
83 data = Buffer.from(jwk.k, 'base64url')
84
85 switch (hash.name.toLowerCase()) {
86 case 'sha-1':
87 if (jwk.alg === 'HS1') break
88 else throw errors.INVALID_DATA('Invalid JWK key algorithm')
89 case 'sha-256':
90 if (jwk.alg === 'HS256') break
91 else throw errors.INVALID_DATA('Invalid JWK key algorithm')
92 case 'sha-384':
93 if (jwk.alg === 'HS384') break
94 else throw errors.INVALID_DATA('Invalid JWK key algorithm')
95 case 'sha-512':
96 if (jwk.alg === 'HS512') break
97 else throw errors.INVALID_DATA('Invalid JWK key algorithm')
98 }
99
100 if (usages.length && 'use' in jwk && jwk.use !== 'sign') {
101 throw errors.INVALID_DATA('JWK cannot be used for signing')
102 }
103
104 if ('ext' in jwk && jwk.ext !== extractable && extractable) {
105 throw errors.INVALID_DATA('JWK is not extractable')
106 }
107 break
108 default:
109 throw errors.NOT_SUPPORTED(
110 `Format '${format}' cannot be used for the HMAC importKey() operation`
111 )
112 }
113
114 const length = data.byteLength * 8
115
116 if (length === 0) {
117 throw errors.INVALID_DATA('Key cannot be empty')
118 }
119
120 return new CryptoKey(
121 'secret',
122 extractable,
123 {
124 name: 'HMAC',
125 length,
126 hash: {
127 name: hash.name.toUpperCase()
128 }
129 },
130 usages,
131 data
132 )
133}
134
135// https://w3c.github.io/webcrypto/#hmac-operations-export-key
136exports.exportKey = function exportKey(format, key) {
137 const data = key._handle
138
139 switch (format) {
140 case 'raw':
141 return data.buffer.slice(0, data.byteLength)
142 case 'jwk': {
143 const jwk = {
144 kty: 'oct',
145 k: data.toString('base64url'),
146 alg: null,
147 key_ops: key.usages,
148 ext: key.extractable
149 }
150
151 switch (key.algorithm.hash.name) {
152 case 'SHA-1':
153 jwk.alg = 'HS1'
154 break
155 case 'SHA-256':
156 jwk.alg = 'HS256'
157 break
158 case 'SHA-384':
159 jwk.alg = 'HS384'
160 break
161 case 'SHA-512':
162 jwk.alg = 'HS512'
163 break
164 }
165
166 return jwk
167 }
168 default:
169 throw errors.NOT_SUPPORTED(
170 `Format '${format}' cannot be used for the HMAC exportKey() operation`
171 )
172 }
173}
174
175// https://w3c.github.io/webcrypto/#hmac-operations-get-key-length
176exports.getKeyLength = function getKeyLength(algorithm) {
177 const { length, hash } = algorithm
178
179 if (length === undefined) {
180 if (hash === 'SHA-1' || hash === 'SHA-256') return 512
181 if (hash === 'SHA-512') return 1024
182
183 throw errors.OPERATION_ERROR(`Invalid hash '${hash}'`)
184 }
185
186 if (length === 0) {
187 throw errors.OPERATION_ERROR(`Invalid length ${length}`)
188 }
189
190 return length
191}
node_modules/bare-crypto/lib/web/algorithm/pbkdf2.js +63 -0
……@@ -0,0 +1,63 @@
1const crypto = require('../../..')
2const errors = require('../../errors')
3const CryptoKey = require('../crypto-key')
4
5// https://w3c.github.io/webcrypto/#pbkdf2
6
7// https://w3c.github.io/webcrypto/#pbkdf2-operations-derive-bits
8exports.deriveBits = function deriveBits(algorithm, key, length) {
9 if (length === undefined || length % 8) {
10 throw errors.OPERATION_ERROR('Length must be multiple of 8')
11 }
12
13 if (algorithm.iterations === 0) {
14 throw errors.OPERATION_ERROR('Iterations must be non-0')
15 }
16
17 if (length === 0) {
18 return new ArrayBuffer(0)
19 }
20
21 let hash = algorithm.hash
22
23 if (typeof hash === 'string') hash = { name: hash }
24
25 const result = crypto.pbkdf2(
26 key._handle,
27 algorithm.salt,
28 algorithm.iterations,
29 length / 8,
30 hash.name
31 )
32
33 return result.buffer
34}
35
36// https://w3c.github.io/webcrypto/#pbkdf2-operations-import-key
37exports.importKey = function importKey(format, keyData, algorithm, extractable, usages) {
38 if (format !== 'raw') {
39 throw errors.NOT_SUPPORTED(
40 `Format '${format}' cannot be used for the PBKDF2 importKey() operation`
41 )
42 }
43
44 for (const usage of usages) {
45 if (usage !== 'deriveKey' && usage !== 'deriveBits') {
46 throw new SyntaxError(`Invalid usage ${usage}`)
47 }
48 }
49
50 if (extractable) {
51 throw new SyntaxError('Extractable must be false')
52 }
53
54 return new CryptoKey(
55 'secret',
56 extractable,
57 {
58 name: 'PBKDF2'
59 },
60 usages,
61 keyData
62 )
63}
node_modules/bare-crypto/lib/web/algorithm/sha.js +10 -0
……@@ -0,0 +1,10 @@
1const crypto = require('../../..')
2
3// https://w3c.github.io/webcrypto/#sha
4
5// https://w3c.github.io/webcrypto/#sha-operations-digest
6exports.digest = function digest(name, data) {
7 const digest = crypto.createHash(name).update(data).digest()
8
9 return digest.buffer.slice(0, digest.byteLength)
10}
node_modules/bare-crypto/lib/web/crypto-key.js +41 -0
……@@ -0,0 +1,41 @@
1// https://w3c.github.io/webcrypto/#cryptokey-interface
2module.exports = class CryptoKey {
3 constructor(type, extractable, algorithm, usages, handle = null) {
4 this._type = type
5 this._extractable = extractable
6 this._algorithm = algorithm
7 this._usages = usages
8 this._handle = handle
9 }
10
11 // https://w3c.github.io/webcrypto/#dom-cryptokey-type
12 get type() {
13 return this._type
14 }
15
16 // https://w3c.github.io/webcrypto/#dom-cryptokey-extractable
17 get extractable() {
18 return this._extractable
19 }
20
21 // https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm
22 get algorithm() {
23 return this._algorithm
24 }
25
26 // https://w3c.github.io/webcrypto/#dom-cryptokey-usages
27 get usages() {
28 return this._usages
29 }
30
31 [Symbol.for('bare.inspect')]() {
32 return {
33 __proto__: { constructor: CryptoKey },
34
35 type: this.type,
36 extractable: this.extractable,
37 algorithm: this.algorithm,
38 usages: this.usages
39 }
40 }
41}
node_modules/bare-crypto/package.json +69 -0
……@@ -0,0 +1,69 @@
1{
2 "name": "bare-crypto",
3 "version": "1.13.4",
4 "description": "Cryptographic primitives for JavaScript",
5 "exports": {
6 "./package": "./package.json",
7 ".": {
8 "types": "./index.d.ts",
9 "default": "./index.js"
10 },
11 "./web": {
12 "types": "./web.d.ts",
13 "default": "./web.js"
14 },
15 "./global": {
16 "types": "./global.d.ts",
17 "default": "./global.js"
18 },
19 "./constants": "./lib/constants.js",
20 "./errors": "./lib/errors.js"
21 },
22 "files": [
23 "index.js",
24 "index.d.ts",
25 "web.js",
26 "web.d.ts",
27 "global.js",
28 "global.d.ts",
29 "binding.c",
30 "binding.js",
31 "CMakeLists.txt",
32 "lib",
33 "prebuilds"
34 ],
35 "addon": true,
36 "scripts": {
37 "test": "prettier . --check && bare test.js"
38 },
39 "repository": {
40 "type": "git",
41 "url": "git+https://github.com/holepunchto/bare-crypto.git"
42 },
43 "author": "Holepunch",
44 "license": "Apache-2.0",
45 "bugs": {
46 "url": "https://github.com/holepunchto/bare-crypto/issues"
47 },
48 "homepage": "https://github.com/holepunchto/bare-crypto#readme",
49 "dependencies": {
50 "bare-assert": "^1.2.0",
51 "bare-stream": "^2.6.3"
52 },
53 "devDependencies": {
54 "bare-buffer": "^3.0.1",
55 "brittle": "^3.5.0",
56 "cmake-bare": "^1.1.6",
57 "cmake-fetch": "^1.0.0",
58 "prettier": "^3.4.2",
59 "prettier-config-holepunch": "^2.0.0"
60 },
61 "peerDependencies": {
62 "bare-buffer": "*"
63 },
64 "peerDependenciesMeta": {
65 "bare-buffer": {
66 "optional": true
67 }
68 }
69}
node_modules/bare-crypto/prebuilds/android-arm/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/android-arm64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/android-ia32/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/android-x64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/darwin-arm64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/darwin-x64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/ios-arm64-simulator/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/ios-arm64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/ios-x64-simulator/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/linux-arm64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/linux-x64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/win32-arm64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/prebuilds/win32-x64/bare-crypto.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-crypto/web.d.ts +1 -0
……@@ -0,0 +1 @@
1export function getRandomValues<B extends ArrayBuffer | ArrayBufferView>(array: B): B
node_modules/bare-crypto/web.js +234 -0
……@@ -0,0 +1,234 @@
1const crypto = require('.')
2const errors = require('./lib/errors')
3const CryptoKey = require('./lib/web/crypto-key')
4const hmac = require('./lib/web/algorithm/hmac')
5const pbkdf2 = require('./lib/web/algorithm/pbkdf2')
6const ed25519 = require('./lib/web/algorithm/ed25519')
7const sha = require('./lib/web/algorithm/sha')
8
9exports.CryptoKey = CryptoKey
10
11// https://w3c.github.io/webcrypto/#Crypto-method-getRandomValues
12exports.getRandomValues = function getRandomValues(array) {
13 return crypto.randomFillSync(array)
14}
15
16// https://w3c.github.io/webcrypto/#dfn-Crypto-method-randomUUID
17exports.randomUUID = crypto.randomUUID
18
19// https://w3c.github.io/webcrypto/#subtlecrypto-interface
20exports.SubtleCrypto = class SubtleCrypto {
21 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-generateKey
22 async generateKey(algorithm, extractable, usages) {
23 if (typeof algorithm === 'string') algorithm = { name: algorithm }
24
25 switch (algorithm.name.toLowerCase()) {
26 case 'hmac':
27 return hmac.generateKey(algorithm, extractable, usages)
28 case 'ed25519':
29 return ed25519.generateKey(algorithm, extractable, usages)
30 default:
31 throw errors.NOT_SUPPORTED(
32 `Algorithm '${algorithm.name}' does not support the generateKey() operation`
33 )
34 }
35 }
36
37 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey
38 async importKey(format, keyData, algorithm, extractable, usages) {
39 if (typeof algorithm === 'string') algorithm = { name: algorithm }
40
41 switch (format) {
42 case 'raw':
43 case 'pkcs8':
44 case 'spki':
45 if (ArrayBuffer.isView(keyData)) {
46 keyData = Buffer.from(keyData)
47 } else {
48 keyData = Buffer.from(keyData.slice())
49 }
50 break
51 }
52
53 switch (algorithm.name.toLowerCase()) {
54 case 'hmac':
55 return hmac.importKey(format, keyData, algorithm, extractable, usages)
56 case 'ed25519':
57 return ed25519.importKey(format, keyData, algorithm, extractable, usages)
58 case 'pbkdf2':
59 return pbkdf2.importKey(format, keyData, algorithm, extractable, usages)
60 default:
61 throw errors.NOT_SUPPORTED(
62 `Algorithm '${algorithm.name}' does not support the importKey() operation`
63 )
64 }
65 }
66
67 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-exportKey
68 async exportKey(format, key) {
69 if (!key.extractable) {
70 throw errors.INVALID_ACCESS('Key is not extractable')
71 }
72
73 switch (key.algorithm.name.toLowerCase()) {
74 case 'hmac':
75 return hmac.exportKey(format, key)
76 case 'ed25519':
77 return ed25519.exportKey(format, key)
78 default:
79 throw errors.NOT_SUPPORTED(
80 `Algorithm '${key.algorithm.name}' does not support the exportKey() operation`
81 )
82 }
83 }
84
85 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-sign
86 async sign(algorithm, key, data) {
87 if (typeof algorithm === 'string') algorithm = { name: algorithm }
88
89 if (algorithm.name.toLowerCase() !== key.algorithm.name.toLowerCase()) {
90 throw errors.INVALID_ACCESS(`Algorithm '${algorithm.name}' does not match key'`)
91 }
92
93 if (!key.usages.includes('sign')) {
94 throw errors.INVALID_ACCESS('Key cannot be used for signing')
95 }
96
97 switch (algorithm.name.toLowerCase()) {
98 case 'hmac':
99 return hmac.sign(algorithm, key, data)
100 case 'ed25519':
101 return ed25519.sign(algorithm, key, data)
102 default:
103 throw errors.NOT_SUPPORTED(
104 `Algorithm '${algorithm.name}' does not support the sign() operation`
105 )
106 }
107 }
108
109 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-verify
110 async verify(algorithm, key, signature, data) {
111 if (typeof algorithm === 'string') algorithm = { name: algorithm }
112
113 if (algorithm.name.toLowerCase() !== key.algorithm.name.toLowerCase()) {
114 throw errors.INVALID_ACCESS(`Algorithm '${algorithm.name}' does not match key'`)
115 }
116
117 if (!key.usages.includes('verify')) {
118 throw errors.INVALID_ACCESS('Key cannot be used for verification')
119 }
120
121 switch (algorithm.name.toLowerCase()) {
122 case 'hmac':
123 return hmac.verify(algorithm, key, signature, data)
124 case 'ed25519':
125 return ed25519.verify(algorithm, key, signature, data)
126 default:
127 throw errors.NOT_SUPPORTED(
128 `Algorithm '${algorithm.name}' does not support the verify() operation`
129 )
130 }
131 }
132
133 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits
134 async deriveBits(algorithm, key, length) {
135 if (typeof algorithm === 'string') algorithm = { name: algorithm }
136
137 if (algorithm.name.toLowerCase() !== key.algorithm.name.toLowerCase()) {
138 throw errors.INVALID_ACCESS(`Algorithm '${algorithm.name}' does not match key'`)
139 }
140
141 if (!key.usages.includes('deriveBits')) {
142 throw errors.INVALID_ACCESS('Key cannot be used to derive bits')
143 }
144
145 switch (algorithm.name.toLowerCase()) {
146 case 'pbkdf2':
147 return pbkdf2.deriveBits(algorithm, key, length)
148 default:
149 throw errors.NOT_SUPPORTED(
150 `Algorithm '${algorithm.name}' does not support the deriveBits() operation`
151 )
152 }
153 }
154
155 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey
156 async deriveKey(algorithm, baseKey, derivedKeyType, extractable, usages) {
157 if (typeof algorithm === 'string') algorithm = { name: algorithm }
158
159 if (typeof derivedKeyType === 'string') {
160 derivedKeyType = { name: derivedKeyType }
161 }
162
163 if (algorithm.name.toLowerCase() !== baseKey.algorithm.name.toLowerCase()) {
164 throw errors.INVALID_ACCESS(`Algorithm '${algorithm.name}' does not match key'`)
165 }
166
167 if (!baseKey.usages.includes('deriveKey')) {
168 throw errors.INVALID_ACCESS('Key cannot be used to derive key')
169 }
170
171 let length
172
173 switch (derivedKeyType.name.toLowerCase()) {
174 case 'hmac':
175 length = hmac.getKeyLength(derivedKeyType)
176 break
177 default:
178 throw errors.NOT_SUPPORTED(
179 `Algorithm '${derivedKeyType.name}' does not support the getKeyLength() operation`
180 )
181 }
182
183 let secret
184
185 switch (algorithm.name.toLowerCase()) {
186 case 'pbkdf2':
187 secret = pbkdf2.deriveBits(algorithm, baseKey, length)
188 break
189 default:
190 throw errors.NOT_SUPPORTED(
191 `Algorithm '${algorithm.name}' does not support the deriveBits() operation`
192 )
193 }
194
195 return this.importKey('raw', secret, derivedKeyType, extractable, usages)
196 }
197
198 // https://w3c.github.io/webcrypto/#SubtleCrypto-method-digest
199 async digest(algorithm, data) {
200 if (typeof algorithm === 'string') algorithm = { name: algorithm }
201
202 switch (algorithm.name.toLowerCase()) {
203 case 'sha-1':
204 return sha.digest(crypto.constants.hash.SHA1, data)
205 case 'sha-256':
206 return sha.digest(crypto.constants.hash.SHA256, data)
207 case 'sha-384':
208 return sha.digest(crypto.constants.hash.SHA384, data)
209 case 'sha-512':
210 return sha.digest(crypto.constants.hash.SHA512, data)
211 default:
212 throw errors.NOT_SUPPORTED(
213 `Algorithm '${algorithm.name}' does not support the digest() operation`
214 )
215 }
216 }
217}
218
219exports.subtle = new exports.SubtleCrypto()
220
221// https://w3c.github.io/webcrypto/#crypto-interface
222exports.Crypto = class Crypto {
223 get subtle() {
224 return exports.subtle
225 }
226
227 getRandomValues(array) {
228 return exports.getRandomValues(array)
229 }
230
231 randomUUID() {
232 return exports.randomUUID()
233 }
234}
node_modules/bare-debug-log/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-debug-log/README.md +24 -0
……@@ -0,0 +1,24 @@
1# bare-debug-log
2
3Simple debug log for JavaScript.
4
5```
6npm i bare-debug-log
7```
8
9## Usage
10
11```js
12const log = require('bare-debug-log')('foo')
13
14log('hello from foo [%d]', 123)
15```
16
17```sh
18$ BARE_DEBUG=foo bare index.js
19FOO 3245: hello from foo [123]
20```
21
22## License
23
24Apache-2.0
node_modules/bare-debug-log/index.js +23 -0
……@@ -0,0 +1,23 @@
1const os = require('bare-os')
2
3const pid = os.pid()
4const env = os.getEnv('BARE_DEBUG') || os.getEnv('NODE_DEBUG') || ''
5
6const test = new RegExp(
7 `^${env.replace(/[|\\{}()[\]^$+?.]/g, '\\$&').replace(/\*/g, '.*').replace(/,/g, '$|^')}$`,
8 'i'
9)
10
11module.exports = function debug (section) {
12 section = section.toUpperCase()
13
14 const enabled = test.test(section)
15
16 function debug (...args) {
17 if (enabled) console.error('%s %s:', section, pid, ...args)
18 }
19
20 debug.enabled = enabled
21
22 return debug
23}
node_modules/bare-debug-log/package.json +31 -0
……@@ -0,0 +1,31 @@
1{
2 "name": "bare-debug-log",
3 "version": "2.0.0",
4 "description": "Simple debug log for JavaScript",
5 "exports": {
6 ".": "./index.js",
7 "./package": "./package.json"
8 },
9 "files": [
10 "index.js"
11 ],
12 "scripts": {
13 "test": "standard"
14 },
15 "repository": {
16 "type": "git",
17 "url": "git+https://github.com/holepunchto/bare-debug-log.git"
18 },
19 "author": "Holepunch",
20 "license": "Apache-2.0",
21 "bugs": {
22 "url": "https://github.com/holepunchto/bare-debug-log/issues"
23 },
24 "homepage": "https://github.com/holepunchto/bare-debug-log#readme",
25 "dependencies": {
26 "bare-os": "^3.0.1"
27 },
28 "devDependencies": {
29 "standard": "^17.0.0"
30 }
31}
node_modules/bare-dns/CMakeLists.txt +31 -0
……@@ -0,0 +1,31 @@
1cmake_minimum_required(VERSION 3.31)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4find_package(cmake-fetch REQUIRED PATHS node_modules/cmake-fetch)
5
6project(bare_dns C)
7
8set(CARES_STATIC ON CACHE BOOL "Build the static c-ares library" FORCE)
9set(CARES_STATIC_PIC ON CACHE BOOL "Enable PIC for the static c-ares library" FORCE)
10set(CARES_SHARED OFF CACHE BOOL "Build the shared c-ares library" FORCE)
11set(CARES_INSTALL OFF CACHE BOOL "Enable c-ares installation scripts" FORCE)
12set(CARES_BUILD_TOOLS OFF CACHE BOOL "Build the c-ares utility tools" FORCE)
13
14fetch_package("github:c-ares/c-ares@1.34.4")
15fetch_package("github:holepunchto/libintrusive#3903632")
16
17add_bare_module(bare_dns)
18
19target_sources(
20 ${bare_dns}
21 PRIVATE
22 binding.c
23)
24
25target_link_libraries(
26 ${bare_dns}
27 PUBLIC
28 intrusive
29 PRIVATE
30 c-ares::cares
31)
node_modules/bare-dns/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-dns/README.md +21 -0
……@@ -0,0 +1,21 @@
1# bare-dns
2
3Domain name resolution for JavaScript.
4
5```
6npm i bare-dns
7```
8
9## Usage
10
11```js
12const dns = require('bare-dns')
13
14dns.lookup('github.com', (err, address, family) => {
15 console.log(address, family)
16})
17```
18
19## License
20
21Apache-2.0
node_modules/bare-dns/binding.c +607 -0
……@@ -0,0 +1,607 @@
1#include <ares.h>
2#include <assert.h>
3#include <bare.h>
4#include <intrusive.h>
5#include <intrusive/list.h>
6#include <js.h>
7#include <stddef.h>
8#include <stdlib.h>
9#include <string.h>
10#include <utf.h>
11#include <uv.h>
12
13typedef struct {
14 uv_getaddrinfo_t handle;
15
16 js_env_t *env;
17 js_ref_t *ctx;
18 js_ref_t *cb;
19
20 bool all;
21 bool exiting;
22
23 js_deferred_teardown_t *teardown;
24} bare_dns_lookup_t;
25
26typedef struct {
27 ares_channel channel;
28 intrusive_list_t tasks;
29
30 bool exiting;
31
32 js_env_t *env;
33 js_deferred_teardown_t *teardown;
34} bare_dns_resolver_t;
35
36typedef struct {
37 bare_dns_resolver_t *resolver;
38
39 ares_socket_t socket;
40 uv_poll_t poll;
41
42 intrusive_list_node_t node;
43} bare_dns_resolve_task_t;
44
45typedef struct {
46 bare_dns_resolver_t *resolver;
47
48 js_env_t *env;
49 js_ref_t *ctx;
50 js_ref_t *cb;
51} bare_dns_resolve_req_t;
52
53static uv_once_t bare_dns__init_guard = UV_ONCE_INIT;
54
55static void
56bare_dns__on_lookup(uv_getaddrinfo_t *handle, int status, struct addrinfo *res) {
57 int err;
58
59 bare_dns_lookup_t *req = (bare_dns_lookup_t *) handle;
60
61 js_deferred_teardown_t *teardown = req->teardown;
62
63 js_env_t *env = req->env;
64
65 js_handle_scope_t *scope;
66 err = js_open_handle_scope(env, &scope);
67 assert(err == 0);
68
69 js_value_t *ctx;
70 err = js_get_reference_value(env, req->ctx, &ctx);
71 assert(err == 0);
72
73 js_value_t *cb;
74 err = js_get_reference_value(env, req->cb, &cb);
75 assert(err == 0);
76
77 err = js_delete_reference(env, req->cb);
78 assert(err == 0);
79
80 err = js_delete_reference(env, req->ctx);
81 assert(err == 0);
82
83 js_value_t *args[2];
84
85 if (status < 0) {
86 js_value_t *code;
87 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(status), -1, &code);
88 assert(err == 0);
89
90 js_value_t *message;
91 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(status), -1, &message);
92 assert(err == 0);
93
94 err = js_create_error(env, code, message, &args[0]);
95 assert(err == 0);
96
97 err = js_get_null(env, &args[1]);
98 assert(err == 0);
99 } else {
100 err = js_get_null(env, &args[0]);
101 assert(err == 0);
102
103 js_value_t *result;
104 err = js_create_array(env, &result);
105 assert(err == 0);
106
107 uint32_t i = 0;
108
109 for (struct addrinfo *next = res; next != NULL; next = next->ai_next) {
110 assert(next->ai_socktype == SOCK_STREAM);
111
112 int family;
113
114 char ip[INET6_ADDRSTRLEN];
115
116 if (next->ai_family == AF_INET) {
117 family = 4;
118 err = uv_ip4_name((struct sockaddr_in *) next->ai_addr, ip, sizeof(ip));
119 } else if (next->ai_family == AF_INET6) {
120 family = 6;
121 err = uv_ip6_name((struct sockaddr_in6 *) next->ai_addr, ip, sizeof(ip));
122 } else {
123 continue;
124 }
125
126 assert(err == 0);
127
128 js_value_t *address;
129 err = js_create_object(env, &address);
130 assert(err == 0);
131
132 err = js_set_element(env, result, i++, address);
133 assert(err == 0);
134
135 js_value_t *value;
136
137 err = js_create_string_utf8(env, (utf8_t *) ip, -1, &value);
138 assert(err == 0);
139
140 err = js_set_named_property(env, address, "address", value);
141 assert(err == 0);
142
143 err = js_create_uint32(env, family, &value);
144 assert(err == 0);
145
146 err = js_set_named_property(env, address, "family", value);
147 assert(err == 0);
148
149 if (!req->all) break;
150 }
151
152 if (i > 0) args[1] = result;
153 else {
154 js_value_t *code;
155 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(UV_EAI_NODATA), -1, &code);
156 assert(err == 0);
157
158 js_value_t *message;
159 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(UV_EAI_NODATA), -1, &message);
160 assert(err == 0);
161
162 err = js_create_error(env, code, message, &args[0]);
163 assert(err == 0);
164
165 err = js_get_null(env, &args[1]);
166 assert(err == 0);
167 }
168 }
169
170 uv_freeaddrinfo(res);
171
172 if (!req->exiting) js_call_function(env, ctx, cb, 2, args, NULL);
173
174 err = js_close_handle_scope(env, scope);
175 assert(err == 0);
176
177 err = js_finish_deferred_teardown_callback(teardown);
178 assert(err == 0);
179}
180
181static void
182bare_dns__on_lookup_teardown(js_deferred_teardown_t *handle, void *data) {
183 bare_dns_lookup_t *req = (bare_dns_lookup_t *) data;
184
185 req->exiting = true;
186
187 uv_cancel((uv_req_t *) &req->handle);
188}
189
190static js_value_t *
191bare_dns_lookup(js_env_t *env, js_callback_info_t *info) {
192 int err;
193
194 size_t argc = 5;
195 js_value_t *argv[5];
196
197 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
198 assert(err == 0);
199
200 assert(argc == 5);
201
202 size_t len;
203 err = js_get_value_string_utf8(env, argv[0], NULL, 0, &len);
204 assert(err == 0);
205
206 len += 1 /* NULL */;
207
208 utf8_t *hostname = malloc(len);
209 err = js_get_value_string_utf8(env, argv[0], hostname, len, NULL);
210 assert(err == 0);
211
212 uint32_t family;
213 err = js_get_value_uint32(env, argv[1], &family);
214 assert(err == 0);
215
216 bool all;
217 err = js_get_value_bool(env, argv[2], &all);
218 assert(err == 0);
219
220 struct addrinfo hints = {
221 .ai_family = family == 4
222 ? AF_INET
223 : family == 6 ? AF_INET6
224 : AF_UNSPEC,
225 .ai_socktype = SOCK_STREAM,
226 .ai_flags = 0,
227 };
228
229 js_value_t *handle;
230
231 bare_dns_lookup_t *req;
232 err = js_create_arraybuffer(env, sizeof(bare_dns_lookup_t), (void **) &req, &handle);
233 assert(err == 0);
234
235 req->env = env;
236 req->all = all;
237 req->exiting = false;
238
239 err = js_create_reference(env, argv[3], 1, &req->ctx);
240 assert(err == 0);
241
242 err = js_create_reference(env, argv[4], 1, &req->cb);
243 assert(err == 0);
244
245 uv_loop_t *loop;
246 err = js_get_env_loop(env, &loop);
247 assert(err == 0);
248
249 err = uv_getaddrinfo(loop, &req->handle, bare_dns__on_lookup, (const char *) hostname, NULL, &hints);
250
251 free(hostname);
252
253 if (err < 0) {
254 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
255 assert(err == 0);
256
257 return NULL;
258 }
259
260 err = js_add_deferred_teardown_callback(env, bare_dns__on_lookup_teardown, (void *) req, &req->teardown);
261 assert(err == 0);
262
263 return handle;
264}
265
266static void
267bare_dns__on_poll_close(uv_handle_t *handle) {
268 int err;
269
270 uv_poll_t *poll = (uv_poll_t *) handle;
271
272 bare_dns_resolve_task_t *task = intrusive_entry(poll, bare_dns_resolve_task_t, poll);
273
274 bare_dns_resolver_t *resolver = task->resolver;
275
276 intrusive_list_remove(&resolver->tasks, &task->node);
277
278 free(task);
279
280 if (resolver->exiting && intrusive_list_empty(&resolver->tasks)) {
281 ares_destroy(resolver->channel);
282
283 err = js_finish_deferred_teardown_callback(resolver->teardown);
284 assert(err == 0);
285 }
286}
287
288static void
289bare_dns__on_poll_update(uv_poll_t *poll, int status, int events) {
290 assert(status == 0);
291
292 bare_dns_resolve_task_t *task = intrusive_entry(poll, bare_dns_resolve_task_t, poll);
293
294 ares_process_fd(
295 task->resolver->channel,
296 events & UV_READABLE ? task->socket : ARES_SOCKET_BAD,
297 events & UV_WRITABLE ? task->socket : ARES_SOCKET_BAD
298 );
299}
300
301static void
302bare_dns__on_resolver_teardown(js_deferred_teardown_t *handle, void *data) {
303 int err;
304
305 bare_dns_resolver_t *resolver = (bare_dns_resolver_t *) data;
306
307 if (resolver->exiting) return;
308
309 resolver->exiting = true;
310
311 if (intrusive_list_empty(&resolver->tasks)) {
312 ares_destroy(resolver->channel);
313
314 err = js_finish_deferred_teardown_callback(resolver->teardown);
315 assert(err == 0);
316 } else {
317 intrusive_list_for_each(next, &resolver->tasks) {
318 bare_dns_resolve_task_t *task = intrusive_entry(next, bare_dns_resolve_task_t, node);
319
320 uv_close((uv_handle_t *) &task->poll, bare_dns__on_poll_close);
321 }
322 }
323}
324
325static void
326bare_dns__on_socket_change(void *data, ares_socket_t socket, int read, int write) {
327 int err;
328
329 bare_dns_resolver_t *resolver = (bare_dns_resolver_t *) data;
330
331 if (resolver->exiting) return;
332
333 bare_dns_resolve_task_t *task = NULL;
334
335 intrusive_list_for_each(next, &resolver->tasks) {
336 bare_dns_resolve_task_t *candidate = intrusive_entry(next, bare_dns_resolve_task_t, node);
337
338 if (candidate->socket == socket) {
339 task = candidate;
340 break;
341 }
342 }
343
344 if (task == NULL) {
345 task = malloc(sizeof(bare_dns_resolve_task_t));
346
347 task->resolver = resolver;
348 task->socket = socket;
349
350 intrusive_list_append(&resolver->tasks, &task->node);
351 }
352
353 if (read || write) {
354 uv_loop_t *loop;
355 err = js_get_env_loop(resolver->env, &loop);
356 assert(err == 0);
357
358 err = uv_poll_init_socket(loop, &task->poll, task->socket);
359 assert(err == 0);
360
361 int events = (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0);
362
363 err = uv_poll_start(&task->poll, events, bare_dns__on_poll_update);
364 assert(err == 0);
365 } else {
366 uv_close((uv_handle_t *) &task->poll, bare_dns__on_poll_close);
367 }
368}
369
370static js_value_t *
371bare_dns_init_resolver(js_env_t *env, js_callback_info_t *info) {
372 int err;
373
374 js_value_t *handle;
375
376 bare_dns_resolver_t *resolver;
377 err = js_create_arraybuffer(env, sizeof(bare_dns_resolver_t), (void **) &resolver, &handle);
378 assert(err == 0);
379
380 intrusive_list_init(&resolver->tasks);
381
382 struct ares_options opts;
383 opts.sock_state_cb = bare_dns__on_socket_change;
384 opts.sock_state_cb_data = resolver;
385
386 err = ares_init_options(&resolver->channel, &opts, ARES_OPT_SOCK_STATE_CB);
387
388 if (err != ARES_SUCCESS) {
389 err = js_throw_error(env, NULL, ares_strerror(err));
390 assert(err == 0);
391
392 return NULL;
393 }
394
395 resolver->env = env;
396
397 err = js_add_deferred_teardown_callback(env, bare_dns__on_resolver_teardown, (void *) resolver, &resolver->teardown);
398 assert(err == 0);
399
400 return handle;
401}
402
403static js_value_t *
404bare_dns_destroy_resolver(js_env_t *env, js_callback_info_t *info) {
405 int err;
406
407 size_t argc = 1;
408 js_value_t *argv[1];
409
410 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
411 assert(err == 0);
412
413 assert(argc == 1);
414
415 bare_dns_resolver_t *resolver;
416 err = js_get_arraybuffer_info(env, argv[0], (void **) &resolver, NULL);
417 assert(err == 0);
418
419 if (resolver->exiting) return NULL;
420
421 resolver->exiting = true;
422
423 if (intrusive_list_empty(&resolver->tasks)) {
424 ares_destroy(resolver->channel);
425
426 err = js_finish_deferred_teardown_callback(resolver->teardown);
427 assert(err == 0);
428 } else {
429 intrusive_list_for_each(next, &resolver->tasks) {
430 bare_dns_resolve_task_t *task = intrusive_entry(next, bare_dns_resolve_task_t, node);
431
432 uv_close((uv_handle_t *) &task->poll, bare_dns__on_poll_close);
433 }
434 }
435
436 return NULL;
437}
438
439static void
440bare_dns__on_resolve_txt(void *data, ares_status_t status, size_t timeouts, const ares_dns_record_t *dnsrec) {
441 int err;
442
443 bare_dns_resolve_req_t *req = (bare_dns_resolve_req_t *) data;
444
445 if (req->resolver->exiting) return;
446
447 js_env_t *env = req->env;
448
449 js_handle_scope_t *scope;
450 err = js_open_handle_scope(env, &scope);
451 assert(err == 0);
452
453 js_value_t *ctx;
454 err = js_get_reference_value(env, req->ctx, &ctx);
455 assert(err == 0);
456
457 js_value_t *cb;
458 err = js_get_reference_value(env, req->cb, &cb);
459 assert(err == 0);
460
461 err = js_delete_reference(env, req->cb);
462 assert(err == 0);
463
464 err = js_delete_reference(env, req->ctx);
465 assert(err == 0);
466
467 js_value_t *args[2];
468
469 if (status == ARES_SUCCESS) {
470 err = js_get_null(env, &args[0]);
471 assert(err == 0);
472
473 js_value_t *result;
474 err = js_create_array(env, &result);
475 assert(err == 0);
476
477 for (size_t i = 0, n = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i < n; i++) {
478 const ares_dns_rr_t *rr = ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i);
479
480 if (ares_dns_rr_get_type(rr) != ARES_REC_TYPE_TXT) continue;
481
482 js_value_t *record;
483 err = js_create_array(env, &record);
484 assert(err == 0);
485
486 err = js_set_element(env, result, (uint32_t) i, record);
487 assert(err == 0);
488
489 for (size_t i = 0, n = ares_dns_rr_get_abin_cnt(rr, ARES_RR_TXT_DATA); i < n; i++) {
490 size_t len;
491
492 const uint8_t *data = ares_dns_rr_get_abin(rr, ARES_RR_TXT_DATA, i, &len);
493
494 js_value_t *chunk;
495 err = js_create_string_utf8(env, (const utf8_t *) data, len, &chunk);
496 assert(err == 0);
497
498 err = js_set_element(env, record, (uint32_t) i, chunk);
499 assert(err == 0);
500 }
501 }
502
503 args[1] = result;
504 } else {
505 js_value_t *message;
506 err = js_create_string_utf8(env, (utf8_t *) ares_strerror(status), -1, &message);
507 assert(err == 0);
508
509 err = js_create_error(env, NULL, message, &args[0]);
510 assert(err == 0);
511
512 err = js_get_null(env, &args[1]);
513 assert(err == 0);
514 }
515
516 js_call_function(env, ctx, cb, 2, args, NULL);
517
518 err = js_close_handle_scope(env, scope);
519 assert(err == 0);
520}
521
522static js_value_t *
523bare_dns_resolve_txt(js_env_t *env, js_callback_info_t *info) {
524 int err;
525
526 size_t argc = 4;
527 js_value_t *argv[4];
528
529 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
530 assert(err == 0);
531
532 assert(argc == 4);
533
534 bare_dns_resolver_t *resolver;
535 err = js_get_arraybuffer_info(env, argv[0], (void **) &resolver, NULL);
536 assert(err == 0);
537
538 size_t len;
539 err = js_get_value_string_utf8(env, argv[1], NULL, 0, &len);
540 assert(err == 0);
541
542 len += 1 /* NULL */;
543
544 utf8_t *hostname = malloc(len);
545 err = js_get_value_string_utf8(env, argv[1], hostname, len, NULL);
546 assert(err == 0);
547
548 js_value_t *handle;
549
550 bare_dns_resolve_req_t *req;
551 err = js_create_arraybuffer(env, sizeof(bare_dns_resolve_req_t), (void **) &req, &handle);
552 assert(err == 0);
553
554 req->resolver = resolver;
555 req->env = env;
556
557 err = js_create_reference(env, argv[2], 1, &req->cb);
558 assert(err == 0);
559
560 err = js_create_reference(env, argv[3], 1, &req->ctx);
561 assert(err == 0);
562
563 err = ares_query_dnsrec(req->resolver->channel, (char *) hostname, ARES_CLASS_IN, ARES_REC_TYPE_TXT, bare_dns__on_resolve_txt, req, NULL);
564
565 free(hostname);
566
567 if (err != ARES_SUCCESS) {
568 err = js_throw_error(env, NULL, ares_strerror(err));
569 assert(err == 0);
570
571 return NULL;
572 }
573
574 return NULL;
575}
576
577static void
578bare_dns__on_init(void) {
579 ares_library_init(ARES_LIB_INIT_ALL);
580}
581
582static js_value_t *
583bare_dns_exports(js_env_t *env, js_value_t *exports) {
584 uv_once(&bare_dns__init_guard, bare_dns__on_init);
585
586 int err;
587
588#define V(name, fn) \
589 { \
590 js_value_t *val; \
591 err = js_create_function(env, name, -1, fn, NULL, &val); \
592 assert(err == 0); \
593 err = js_set_named_property(env, exports, name, val); \
594 assert(err == 0); \
595 }
596
597 V("lookup", bare_dns_lookup)
598
599 V("initResolver", bare_dns_init_resolver)
600 V("destroyResolver", bare_dns_destroy_resolver)
601 V("resolveTxt", bare_dns_resolve_txt)
602#undef V
603
604 return exports;
605}
606
607BARE_MODULE(bare_dns, bare_dns_exports)
node_modules/bare-dns/binding.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon()
node_modules/bare-dns/index.d.ts +55 -0
……@@ -0,0 +1,55 @@
1type IPFamily = 4 | 6
2
3interface LookupOptions {
4 family?: `IPv${IPFamily}` | IPFamily | 0
5 hints?: number
6 all?: boolean
7}
8
9declare class DNSResolver {
10 resolveTxt(
11 hostname: string,
12 cb: (err: Error | null, records: string[][]) => void
13 ): void
14
15 destroy(): void
16}
17
18declare namespace dns {
19 export function lookup(
20 hostname: string,
21 cb: (
22 err: Error | null,
23 address: string | null,
24 family: IPFamily | 0
25 ) => void
26 ): void
27
28 export function lookup(
29 hostname: string,
30 opts: LookupOptions & { all?: false },
31 cb: (
32 err: Error | null,
33 address: string | null,
34 family: IPFamily | 0
35 ) => void
36 ): void
37
38 export function lookup(
39 hostname: string,
40 opts: LookupOptions & { all: true },
41 cb: (
42 err: Error | null,
43 addresses: { address: string; family: IPFamily }[] | null
44 ) => void
45 ): void
46
47 export function resolveTxt(
48 hostname: string,
49 cb: (err: Error | null, records: string[][]) => void
50 ): void
51
52 export { type IPFamily, type LookupOptions, DNSResolver as Resolver }
53}
54
55export = dns
node_modules/bare-dns/index.js +77 -0
……@@ -0,0 +1,77 @@
1const binding = require('./binding')
2
3exports.Resolver = class DNSResolver {
4 constructor() {
5 this._handle = binding.initResolver()
6 }
7
8 resolveTxt(hostname, cb = noop) {
9 binding.resolveTxt(this._handle, hostname, cb, this)
10 }
11
12 destroy() {
13 binding.destroyResolver(this._handle)
14 this._handle = null
15 }
16
17 static global = new this()
18}
19
20function onlookup(err, addresses) {
21 const req = this
22
23 if (err) return req.cb(err, null, 0)
24
25 const { address, family } = addresses[0]
26
27 return req.cb(null, address, family)
28}
29
30function onlookupall(err, addresses) {
31 const req = this
32
33 if (err) return req.cb(err, null)
34
35 return req.cb(null, addresses)
36}
37
38exports.lookup = function lookup(hostname, opts = {}, cb) {
39 if (typeof opts === 'function') {
40 cb = opts
41 opts = {}
42 }
43
44 let { family = 0, all = false } = opts
45
46 if (typeof family === 'string') {
47 switch (family) {
48 case 'IPv4':
49 family = 4
50 break
51 case 'IPv6':
52 family = 6
53 break
54 default:
55 family = 0
56 }
57 }
58
59 const req = {
60 cb,
61 handle: null
62 }
63
64 req.handle = binding.lookup(
65 hostname,
66 family || 0,
67 all,
68 req,
69 all ? onlookupall : onlookup
70 )
71}
72
73exports.resolveTxt = function resolveTxt(hostname, cb) {
74 exports.Resolver.global.resolveTxt(hostname, cb)
75}
76
77function noop() {}
node_modules/bare-dns/package.json +45 -0
……@@ -0,0 +1,45 @@
1{
2 "name": "bare-dns",
3 "version": "2.1.4",
4 "description": "Domain name resolution for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json"
11 },
12 "files": [
13 "index.js",
14 "index.d.ts",
15 "binding.c",
16 "binding.js",
17 "CMakeLists.txt",
18 "lib",
19 "prebuilds"
20 ],
21 "addon": true,
22 "scripts": {
23 "test": "prettier . --check && bare test.js"
24 },
25 "repository": {
26 "type": "git",
27 "url": "git+https://github.com/holepunchto/bare-dns.git"
28 },
29 "author": "Holepunch",
30 "license": "Apache-2.0",
31 "bugs": {
32 "url": "https://github.com/holepunchto/bare-dns/issues"
33 },
34 "homepage": "https://github.com/holepunchto/bare-dns",
35 "engines": {
36 "bare": ">=1.7.0"
37 },
38 "devDependencies": {
39 "brittle": "^3.3.2",
40 "cmake-bare": "^1.1.6",
41 "cmake-fetch": "^1.3.0",
42 "prettier": "^3.4.1",
43 "prettier-config-standard": "^7.0.0"
44 }
45}
node_modules/bare-dns/prebuilds/android-arm/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/android-arm64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/android-ia32/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/android-x64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/darwin-arm64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/darwin-x64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/ios-arm64-simulator/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/ios-arm64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/ios-x64-simulator/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/linux-arm64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/linux-x64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/win32-arm64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-dns/prebuilds/win32-x64/bare-dns.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-encoding/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-encoding/README.md +17 -0
……@@ -0,0 +1,17 @@
1# bare-encoding
2
3WHATWG text encoding interfaces for JavaScript.
4
5```
6npm i bare-encoding
7```
8
9## Usage
10
11```js
12const { TextEncoder, TextDecoder } = require('bare-encoding')
13```
14
15## License
16
17Apache-2.0
node_modules/bare-encoding/global.d.ts +12 -0
……@@ -0,0 +1,12 @@
1import * as encoding from '.'
2
3type TextEncoderConstructor = typeof encoding.TextEncoder
4type TextDecoderConstructor = typeof encoding.TextDecoder
5
6declare global {
7 type TextEncoder = encoding.TextEncoder
8 type TextDecoder = encoding.TextDecoder
9
10 const TextEncoder: TextEncoderConstructor
11 const TextDecoder: TextDecoderConstructor
12}
node_modules/bare-encoding/global.js +4 -0
……@@ -0,0 +1,4 @@
1const encoding = require('.')
2
3global.TextDecoder = encoding.TextDecoder
4global.TextEncoder = encoding.TextEncoder
node_modules/bare-encoding/index.d.ts +26 -0
……@@ -0,0 +1,26 @@
1import Buffer from 'bare-buffer'
2
3export interface TextEncoder {
4 readonly encoding: 'utf-8'
5
6 encode(input: string): Buffer
7 encodeInto(
8 input: string,
9 destination: ArrayBufferView | ArrayBuffer | SharedArrayBuffer
10 ): { read: number; written: number }
11}
12
13export class TextEncoder {}
14
15export interface TextDecoder {
16 readonly encoding: 'utf-8'
17
18 decode(
19 input: ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
20 options?: { stream: boolean }
21 ): string
22}
23
24export class TextDecoder {
25 constructor(label?: string)
26}
node_modules/bare-encoding/index.js +74 -0
……@@ -0,0 +1,74 @@
1const UTF8Decoder = require('./lib/utf8-decoder')
2const PassThroughDecoder = require('./lib/pass-through-decoder')
3const errors = require('./lib/errors')
4
5exports.TextEncoder = class TextEncoder {
6 // https://encoding.spec.whatwg.org/#dom-textencoder-encoding
7 get encoding() {
8 return 'utf-8'
9 }
10
11 // https://encoding.spec.whatwg.org/#dom-textencoder-encode
12 encode(input) {
13 return Buffer.from(input)
14 }
15
16 // https://encoding.spec.whatwg.org/#dom-textencoder-encodeinto
17 encodeInto(input, destination) {
18 if (ArrayBuffer.isView(destination)) {
19 destination = Buffer.from(
20 destination.buffer,
21 destination.byteOffset,
22 destination.byteLength
23 )
24 } else {
25 destination = Buffer.from(destination)
26 }
27
28 return {
29 read: input.length,
30 written: destination.write(input)
31 }
32 }
33}
34
35exports.TextDecoder = class TextDecoder {
36 // https://encoding.spec.whatwg.org/#dom-textdecoder
37 constructor(label = 'utf-8') {
38 this.encoding = getEncoding(label)
39
40 switch (this.encoding) {
41 case 'utf-8':
42 this.decoder = new UTF8Decoder()
43 break
44 default:
45 this.decoder = new PassThroughDecoder(this.encoding)
46 break
47 }
48 }
49
50 // https://encoding.spec.whatwg.org/#dom-textdecoder-decode
51 decode(input, options = {}) {
52 const result = this.decoder.decode(input)
53
54 if (options.stream) return result
55
56 return result + this.decoder.flush()
57 }
58}
59
60// https://encoding.spec.whatwg.org/#concept-encoding-get
61function getEncoding(label) {
62 switch (label.trim().toLowerCase()) {
63 case 'unicode-1-1-utf-8':
64 case 'unicode11utf8':
65 case 'unicode11utf8':
66 case 'unicode20utf8':
67 case 'utf-8':
68 case 'utf8':
69 case 'x-unicode20utf8':
70 return 'utf-8'
71 default:
72 throw errors.INVALID_LABEL(`The label '${label}' is not a valid encoding`)
73 }
74}
node_modules/bare-encoding/lib/errors.d.ts +7 -0
……@@ -0,0 +1,7 @@
1declare class EncodingError extends Error {
2 readonly code: string
3
4 static INVALID_LABEL(msg: string): EncodingError
5}
6
7export = EncodingError
node_modules/bare-encoding/lib/errors.js +18 -0
……@@ -0,0 +1,18 @@
1module.exports = class EncodingError extends Error {
2 constructor(msg, code, fn = EncodingError) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'EncodingError'
13 }
14
15 static INVALID_LABEL(msg) {
16 return new EncodingError(msg, 'INVALID_LABEL', EncodingError.INVALID_LABEL)
17 }
18}
node_modules/bare-encoding/lib/pass-through-decoder.js +23 -0
……@@ -0,0 +1,23 @@
1module.exports = class PassThroughDecoder {
2 constructor(encoding) {
3 this.encoding = encoding
4 }
5
6 get remaining() {
7 return 0
8 }
9
10 decode(data) {
11 if (ArrayBuffer.isView(data)) {
12 data = Buffer.from(data.buffer, data.byteOffset, data.byteLength)
13 } else {
14 data = Buffer.from(data)
15 }
16
17 return data.toString(this.encoding)
18 }
19
20 flush() {
21 return ''
22 }
23}
node_modules/bare-encoding/lib/utf8-decoder.js +112 -0
……@@ -0,0 +1,112 @@
1// https://encoding.spec.whatwg.org/#utf-8-decoder
2module.exports = class UTF8Decoder {
3 constructor() {
4 this.codePoint = 0
5 this.bytesSeen = 0
6 this.bytesNeeded = 0
7 this.lowerBoundary = 0x80
8 this.upperBoundary = 0xbf
9 }
10
11 get remaining() {
12 return this.bytesSeen
13 }
14
15 decode(data) {
16 if (ArrayBuffer.isView(data)) {
17 data = Buffer.from(data.buffer, data.byteOffset, data.byteLength)
18 } else {
19 data = Buffer.from(data)
20 }
21
22 if (this.bytesNeeded === 0) {
23 let isBoundary = true
24
25 for (
26 let i = Math.max(0, data.byteLength - 4), n = data.byteLength;
27 i < n && isBoundary;
28 i++
29 ) {
30 isBoundary = data[i] <= 0x7f
31 }
32
33 if (isBoundary) return data.toString('utf8')
34 }
35
36 let result = ''
37
38 for (let i = 0, n = data.byteLength; i < n; i++) {
39 const byte = data[i]
40
41 if (this.bytesNeeded === 0) {
42 if (byte <= 0x7f) {
43 this.bytesSeen = 0
44
45 result += String.fromCharCode(byte)
46 } else {
47 this.bytesSeen = 1
48
49 if (byte >= 0xc2 && byte <= 0xdf) {
50 this.bytesNeeded = 2
51 this.codePoint = byte & 0x1f
52 } else if (byte >= 0xe0 && byte <= 0xef) {
53 if (byte === 0xe0) this.lowerBoundary = 0xa0
54 else if (byte === 0xed) this.upperBoundary = 0x9f
55 this.bytesNeeded = 3
56 this.codePoint = byte & 0xf
57 } else if (byte >= 0xf0 && byte <= 0xf4) {
58 if (byte === 0xf0) this.lowerBoundary = 0x90
59 if (byte === 0xf4) this.upperBoundary = 0x8f
60 this.bytesNeeded = 4
61 this.codePoint = byte & 0x7
62 } else {
63 result += '\ufffd'
64 }
65 }
66
67 continue
68 }
69
70 if (byte < this.lowerBoundary || byte > this.upperBoundary) {
71 this.codePoint = 0
72 this.bytesNeeded = 0
73 this.bytesSeen = 0
74 this.lowerBoundary = 0x80
75 this.upperBoundary = 0xbf
76
77 result += '\ufffd'
78 i--
79
80 continue
81 }
82
83 this.lowerBoundary = 0x80
84 this.upperBoundary = 0xbf
85
86 this.codePoint = (this.codePoint << 6) | (byte & 0x3f)
87 this.bytesSeen++
88
89 if (this.bytesSeen !== this.bytesNeeded) continue
90
91 result += String.fromCodePoint(this.codePoint)
92
93 this.codePoint = 0
94 this.bytesNeeded = 0
95 this.bytesSeen = 0
96 }
97
98 return result
99 }
100
101 flush() {
102 const result = this.bytesNeeded > 0 ? '\ufffd' : ''
103
104 this.codePoint = 0
105 this.bytesNeeded = 0
106 this.bytesSeen = 0
107 this.lowerBoundary = 0x80
108 this.upperBoundary = 0xbf
109
110 return result
111 }
112}
node_modules/bare-encoding/package.json +53 -0
……@@ -0,0 +1,53 @@
1{
2 "name": "bare-encoding",
3 "version": "1.0.3",
4 "description": "WHATWG text encoding interfaces for JavaScript",
5 "exports": {
6 "./package": "./package.json",
7 ".": {
8 "types": "./index.d.ts",
9 "default": "./index.js"
10 },
11 "./global": {
12 "types": "./global.d.ts",
13 "default": "./global.js"
14 },
15 "./errors": {
16 "types": "./lib/errors.d.ts",
17 "default": "./lib/errors.js"
18 }
19 },
20 "files": [
21 "index.js",
22 "index.d.ts",
23 "global.js",
24 "global.d.ts",
25 "lib"
26 ],
27 "scripts": {
28 "test": "prettier . --check && bare test.js"
29 },
30 "repository": {
31 "type": "git",
32 "url": "git+https://github.com/holepunchto/bare-encoding.git"
33 },
34 "author": "Holepunch",
35 "license": "Apache-2.0",
36 "bugs": {
37 "url": "https://github.com/holepunchto/bare-encoding/issues"
38 },
39 "homepage": "https://github.com/holepunchto/bare-encoding#readme",
40 "devDependencies": {
41 "brittle": "^3.1.1",
42 "prettier": "^3.3.3",
43 "prettier-config-standard": "^7.0.0"
44 },
45 "peerDependencies": {
46 "bare-buffer": "*"
47 },
48 "peerDependenciesMeta": {
49 "bare-buffer": {
50 "optional": true
51 }
52 }
53}
node_modules/bare-format/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-format/README.md +20 -0
……@@ -0,0 +1,20 @@
1# bare-format
2
3String formatting for JavaScript.
4
5```
6npm i bare-format
7```
8
9## Usage
10
11```js
12const format = require('bare-format')
13
14format('Hello %s', 'world!')
15// Hello world!
16```
17
18## License
19
20Apache-2.0
node_modules/bare-format/index.d.ts +9 -0
……@@ -0,0 +1,9 @@
1declare function format(...args: unknown[]): string
2
3declare namespace format {
4 export function format(...args: unknown[]): string
5
6 export function formatWithOptions(opts: {}, ...args: unknown[]): string
7}
8
9export = format
node_modules/bare-format/index.js +154 -0
……@@ -0,0 +1,154 @@
1const inspect = require('bare-inspect')
2
3module.exports = exports = function format(...args) {
4 return exports.formatWithOptions({}, ...args)
5}
6
7exports.format = exports
8
9exports.formatWithOptions = function formatWithOptions(opts, ...args) {
10 const format = args[0]
11
12 let result = ''
13 let join = ''
14 let i = 0
15
16 if (typeof format === 'string') {
17 if (args.length === 1) return format
18
19 let tmp
20 let j = 0
21 let c
22
23 for (let k = 0, n = format.length; k < n; k++) {
24 c = format.charCodeAt(k)
25
26 if (c === 0x25 /* % */) {
27 c = format.charCodeAt(++k)
28
29 if (i < args.length) {
30 switch (c) {
31 case 0x73 /* s */: {
32 const value = args[++i]
33
34 switch (typeof value) {
35 case 'string':
36 tmp = value
37 break
38 case 'bigint':
39 tmp = inspect(value, { ...opts, colors: false })
40 break
41 default:
42 tmp = String(value)
43 break
44 }
45
46 break
47 }
48
49 case 0x64 /* d */: {
50 const value = args[++i]
51
52 switch (typeof value) {
53 case 'symbol':
54 tmp = NaN
55 break
56 case 'bigint':
57 tmp = inspect(value, { ...opts, colors: false })
58 break
59 default:
60 tmp = inspect(Number(value), { ...opts, colors: false })
61 break
62 }
63
64 break
65 }
66
67 case 0x69 /* i */: {
68 const value = args[++i]
69
70 switch (typeof value) {
71 case 'symbol':
72 tmp = NaN
73 break
74 case 'bigint':
75 tmp = inspect(value, { ...opts, colors: false })
76 break
77 default:
78 tmp = inspect(parseInt(value, 10), { ...opts, colors: false })
79 break
80 }
81
82 break
83 }
84
85 case 0x66 /* f */: {
86 const value = args[++i]
87
88 switch (typeof value) {
89 case 'symbol':
90 tmp = NaN
91 break
92 default:
93 tmp = inspect(parseFloat(value), { ...opts, colors: false })
94 break
95 }
96
97 break
98 }
99
100 case 0x4f /* O */:
101 case 0x6f /* o */:
102 tmp = inspect(args[++i], opts)
103 break
104
105 case 0x6a /* j */:
106 tmp = JSON.stringify(args[++i])
107 break
108
109 case 0x63 /* c */:
110 i++
111 tmp = ''
112 break
113
114 case 0x25 /* % */:
115 result += format.substring(j, k)
116 j = k + 1
117 continue
118
119 default:
120 continue
121 }
122
123 if (j !== k - 1) result += format.substring(j, k - 1)
124
125 result += tmp
126 j = k + 1
127 } else if (c === 0x25 /* % */) {
128 result += format.substring(j, k)
129 j = k + 1
130 }
131 }
132 }
133
134 if (j !== 0) {
135 i++
136 join = ' '
137
138 if (j < format.length) {
139 result += format.substring(j)
140 }
141 }
142 }
143
144 while (i < args.length) {
145 const value = args[i++]
146
147 result += join
148 result += typeof value === 'string' ? value : inspect(value, opts)
149
150 join = ' '
151 }
152
153 return result
154}
node_modules/bare-format/package.json +37 -0
……@@ -0,0 +1,37 @@
1{
2 "name": "bare-format",
3 "version": "1.0.2",
4 "description": "String formatting for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json"
11 },
12 "files": [
13 "index.js",
14 "index.d.ts"
15 ],
16 "scripts": {
17 "test": "prettier . --check && bare test.js"
18 },
19 "repository": {
20 "type": "git",
21 "url": "git+https://github.com/holepunchto/bare-format.git"
22 },
23 "author": "Holepunch",
24 "license": "Apache-2.0",
25 "bugs": {
26 "url": "https://github.com/holepunchto/bare-format/issues"
27 },
28 "homepage": "https://github.com/holepunchto/bare-format#readme",
29 "dependencies": {
30 "bare-inspect": "^3.0.0"
31 },
32 "devDependencies": {
33 "brittle": "^3.5.0",
34 "prettier": "^3.4.2",
35 "prettier-config-holepunch": "^2.0.0"
36 }
37}
node_modules/bare-http-parser/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-http-parser/README.md +11 -0
……@@ -0,0 +1,11 @@
1# bare-http-parser
2
3Streaming HTTP request and response parser for Bare.
4
5```
6npm i bare-http-parser
7```
8
9## License
10
11Apache-2.0
node_modules/bare-http-parser/index.js +694 -0
……@@ -0,0 +1,694 @@
1const errors = require('./lib/errors')
2
3const constants = {
4 REQUEST: 1,
5 RESPONSE: 2,
6 DATA: 3,
7 END: 4
8}
9
10const TAB = 0x09
11const LF = 0x0a
12const CR = 0x0d
13const SP = 0x20
14const ZERO = 0x30
15const NINE = 0x39
16const UPPER_A = 0x41
17const UPPER_F = 0x46
18const UPPER_Z = 0x5a
19const LOWER_A = 0x61
20const LOWER_F = 0x66
21const COLON = 0x3a
22
23const MAX_CHUNK_SIZE_LENGTH = 16
24
25// Header states
26const FIRST_TOKEN = 0
27const REQUEST_URL = 1
28const REQUEST_VERSION = 2
29const STATUS_CODE = 3
30const STATUS_REASON = 4
31const FIRST_LINE_LF = 5
32const HEADER_START = 6
33const HEADER_NAME = 7
34const HEADER_VALUE_WS = 8
35const HEADER_VALUE = 9
36const HEADER_LINE_LF = 10
37const HEADER_END_LF = 11
38
39// Body states
40const BODY = 12
41const CHUNK_SIZE = 13
42const CHUNK_SIZE_LF = 14
43const CHUNK_DATA = 15
44const CHUNK_EXTENSION = 16
45
46// Trailing states
47const LAST_CHUNK_LF = 17
48const TRAILER_CR = 18
49const TRAILER_LF = 19
50
51module.exports = exports = class HTTPParser {
52 constructor(opts = {}) {
53 const { maxHeaderSize = 16384, maxHeadersCount = 2000 } = opts
54
55 this._maxHeaderSize = maxHeaderSize
56 this._maxHeadersCount = maxHeadersCount
57 this._state = FIRST_TOKEN
58 this._buffer = []
59 this._bufferIndex = 0
60 this._byteIndex = 0
61 this._buffered = 0
62 this._accumulator = []
63
64 this._isResponse = false
65 this._method = ''
66 this._url = ''
67 this._version = ''
68 this._code = 0
69 this._reason = ''
70
71 this._headerName = ''
72 this._headers = {}
73 this._headerCount = 0
74 this._headerSize = 0
75
76 this._remaining = 0
77 }
78
79 *push(data, encoding) {
80 if (typeof data === 'string') data = Buffer.from(data, encoding)
81
82 this._buffer.push(data)
83 this._buffered += data.byteLength
84
85 yield* this._parse()
86
87 this._compact()
88 }
89
90 end() {
91 const buffers = this._buffer
92 const bufferIndex = this._bufferIndex
93 const byteIndex = this._byteIndex
94
95 this._buffer = []
96 this._bufferIndex = 0
97 this._byteIndex = 0
98 this._buffered = 0
99
100 if (bufferIndex >= buffers.length) return Buffer.alloc(0)
101
102 buffers[bufferIndex] = buffers[bufferIndex].subarray(byteIndex)
103
104 const remaining = buffers.slice(bufferIndex)
105
106 if (remaining.length === 0) return Buffer.alloc(0)
107 if (remaining.length === 1) return remaining[0]
108
109 return Buffer.concat(remaining)
110 }
111
112 _compact() {
113 if (this._bufferIndex > 0) {
114 this._buffer = this._buffer.slice(this._bufferIndex)
115 this._bufferIndex = 0
116 }
117
118 if (this._byteIndex > 0 && this._buffer.length > 0) {
119 this._buffer[0] = this._buffer[0].subarray(this._byteIndex)
120 this._byteIndex = 0
121 }
122 }
123
124 _consume(n) {
125 this._buffered -= n
126
127 const current = this._buffer[this._bufferIndex]
128
129 if (this._byteIndex + n <= current.byteLength) {
130 const slice = current.subarray(this._byteIndex, this._byteIndex + n)
131
132 this._byteIndex += n
133
134 if (this._byteIndex >= current.byteLength) {
135 this._bufferIndex++
136 this._byteIndex = 0
137 }
138
139 return slice
140 }
141
142 const result = Buffer.allocUnsafe(n)
143
144 let written = 0
145
146 while (written < n) {
147 const buffer = this._buffer[this._bufferIndex]
148 const available = buffer.byteLength - this._byteIndex
149 const take = Math.min(available, n - written)
150
151 buffer.copy(result, written, this._byteIndex, this._byteIndex + take)
152
153 written += take
154
155 this._byteIndex += take
156
157 if (this._byteIndex >= buffer.byteLength) {
158 this._bufferIndex++
159 this._byteIndex = 0
160 }
161 }
162
163 return result
164 }
165
166 _buildString() {
167 const string = String.fromCharCode.apply(null, this._accumulator)
168
169 this._accumulator = []
170
171 return string
172 }
173
174 _checkHeaderSize() {
175 if (++this._headerSize > this._maxHeaderSize) {
176 throw errors.INVALID_MESSAGE('Header exceeds limit of ' + this._maxHeaderSize + ' bytes')
177 }
178 }
179
180 _storeHeader(name, value) {
181 let end = value.length
182
183 while (end > 0 && (value.charCodeAt(end - 1) === SP || value.charCodeAt(end - 1) === TAB)) {
184 end--
185 }
186
187 if (end < value.length) value = value.substring(0, end)
188
189 this._headerCount++
190
191 if (this._headerCount > this._maxHeadersCount) {
192 throw errors.INVALID_MESSAGE('Header count exceeds limit of ' + this._maxHeadersCount)
193 }
194
195 switch (name) {
196 case '__proto__':
197 case 'constructor':
198 case 'prototype':
199 throw errors.INVALID_HEADER("Unsafe header name '" + name + "'")
200
201 case 'host':
202 case 'content-length':
203 case 'transfer-encoding':
204 if (name in this._headers) {
205 throw errors.INVALID_HEADER("Duplicate header '" + name + "'")
206 }
207
208 this._headers[name] = value
209 break
210
211 default:
212 const delimiter = name === 'cookie' ? '; ' : ', '
213
214 if (name in this._headers) {
215 this._headers[name] += delimiter + value
216 } else {
217 this._headers[name] = value
218 }
219 }
220 }
221
222 *_parse() {
223 while (true) {
224 if (this._state === BODY) {
225 if (this._buffered === 0) return
226
227 const available = Math.min(this._buffered, this._remaining)
228 const data = this._consume(available)
229
230 this._remaining -= available
231
232 const ended = this._remaining === 0
233
234 if (ended) this._state = FIRST_TOKEN
235
236 yield { type: constants.DATA, data }
237
238 if (ended) yield { type: constants.END }
239
240 continue
241 }
242
243 if (this._state === CHUNK_DATA) {
244 if (this._buffered < this._remaining) return
245
246 const consumed = this._consume(this._remaining)
247
248 if (consumed[this._remaining - 2] !== CR || consumed[this._remaining - 1] !== LF) {
249 throw errors.INVALID_MESSAGE('Expected CRLF after chunk data')
250 }
251
252 const data = consumed.subarray(0, this._remaining - 2)
253
254 this._remaining = 0
255 this._state = CHUNK_SIZE
256
257 yield { type: constants.DATA, data }
258
259 continue
260 }
261
262 if (this._buffered === 0) return
263
264 const byte = this._buffer[this._bufferIndex][this._byteIndex++]
265
266 this._buffered--
267
268 if (this._byteIndex >= this._buffer[this._bufferIndex].byteLength) {
269 this._bufferIndex++
270 this._byteIndex = 0
271 }
272
273 switch (this._state) {
274 case FIRST_TOKEN: {
275 this._checkHeaderSize()
276
277 if (byte === SP) {
278 const token = this._buildString()
279
280 if (token.length === 0) throw errors.INVALID_MESSAGE()
281
282 this._isResponse = token.startsWith('HTTP/')
283
284 if (this._isResponse) {
285 if (token !== 'HTTP/1.0' && token !== 'HTTP/1.1') {
286 throw errors.INVALID_MESSAGE()
287 }
288
289 this._version = token
290 this._state = STATUS_CODE
291 } else {
292 this._method = token
293 this._state = REQUEST_URL
294 }
295 } else if (byte === CR) {
296 throw errors.INVALID_MESSAGE()
297 } else if (isTokenByte(byte)) {
298 this._accumulator.push(byte)
299 } else if (
300 byte === 0x2f &&
301 this._accumulator.length === 4 &&
302 this._accumulator[0] === 0x48 &&
303 this._accumulator[1] === 0x54 &&
304 this._accumulator[2] === 0x54 &&
305 this._accumulator[3] === 0x50
306 ) {
307 this._accumulator.push(byte)
308 } else {
309 throw errors.INVALID_MESSAGE()
310 }
311
312 break
313 }
314
315 case REQUEST_URL: {
316 this._checkHeaderSize()
317
318 if (byte === SP) {
319 this._url = this._buildString()
320
321 if (this._url.length === 0) throw errors.INVALID_MESSAGE()
322
323 this._state = REQUEST_VERSION
324 } else if (byte === CR) {
325 throw errors.INVALID_MESSAGE()
326 } else if (byte >= 0x21 && byte !== 0x7f) {
327 this._accumulator.push(byte)
328 } else {
329 throw errors.INVALID_MESSAGE()
330 }
331
332 break
333 }
334
335 case REQUEST_VERSION: {
336 this._checkHeaderSize()
337
338 if (byte === CR) {
339 this._version = this._buildString()
340
341 if (this._version !== 'HTTP/1.0' && this._version !== 'HTTP/1.1') {
342 throw errors.INVALID_MESSAGE()
343 }
344
345 this._state = FIRST_LINE_LF
346 } else if (byte >= 0x21 && byte !== 0x7f) {
347 this._accumulator.push(byte)
348 } else {
349 throw errors.INVALID_MESSAGE()
350 }
351
352 break
353 }
354
355 case STATUS_CODE: {
356 this._checkHeaderSize()
357
358 if (byte === SP) {
359 if (this._accumulator.length === 0) throw errors.INVALID_MESSAGE()
360
361 let code = 0
362
363 for (let i = 0, n = this._accumulator.length; i < n; i++) {
364 code = code * 10 + this._accumulator[i]
365 }
366
367 this._accumulator = []
368
369 if (code < 100 || code > 999) throw errors.INVALID_MESSAGE()
370
371 this._code = code
372 this._state = STATUS_REASON
373 } else if (byte >= ZERO && byte <= NINE) {
374 this._accumulator.push(byte - ZERO)
375 } else {
376 throw errors.INVALID_MESSAGE()
377 }
378
379 break
380 }
381
382 case STATUS_REASON: {
383 this._checkHeaderSize()
384
385 if (byte === CR) {
386 this._reason = this._buildString()
387 this._state = FIRST_LINE_LF
388 } else if (isFieldByte(byte)) {
389 this._accumulator.push(byte)
390 } else {
391 throw errors.INVALID_MESSAGE()
392 }
393
394 break
395 }
396
397 case FIRST_LINE_LF: {
398 if (byte !== LF) throw errors.INVALID_MESSAGE()
399
400 this._headers = {}
401 this._headerCount = 0
402 this._state = HEADER_START
403
404 break
405 }
406
407 case HEADER_START: {
408 this._checkHeaderSize()
409
410 if (byte === CR) {
411 this._state = HEADER_END_LF
412 } else if (byte !== COLON && isTokenByte(byte)) {
413 this._accumulator.push(byte >= UPPER_A && byte <= UPPER_Z ? byte + 0x20 : byte)
414 this._state = HEADER_NAME
415 } else {
416 throw errors.INVALID_HEADER()
417 }
418
419 break
420 }
421
422 case HEADER_NAME: {
423 this._checkHeaderSize()
424
425 if (byte === COLON) {
426 this._headerName = this._buildString()
427 this._state = HEADER_VALUE_WS
428 } else if (byte !== COLON && isTokenByte(byte)) {
429 this._accumulator.push(byte >= UPPER_A && byte <= UPPER_Z ? byte + 0x20 : byte)
430 } else {
431 throw errors.INVALID_HEADER()
432 }
433
434 break
435 }
436
437 case HEADER_VALUE_WS: {
438 this._checkHeaderSize()
439
440 if (byte === SP || byte === TAB) break
441
442 if (byte === CR) {
443 this._storeHeader(this._headerName, '')
444 this._headerName = ''
445 this._state = HEADER_LINE_LF
446
447 break
448 }
449
450 if (!isFieldByte(byte)) throw errors.INVALID_HEADER()
451
452 this._accumulator.push(byte)
453 this._state = HEADER_VALUE
454
455 break
456 }
457
458 case HEADER_VALUE: {
459 this._checkHeaderSize()
460
461 if (byte === CR) {
462 this._storeHeader(this._headerName, this._buildString())
463 this._headerName = ''
464 this._state = HEADER_LINE_LF
465 } else if (isFieldByte(byte)) {
466 this._accumulator.push(byte)
467 } else {
468 throw errors.INVALID_HEADER()
469 }
470
471 break
472 }
473
474 case HEADER_LINE_LF: {
475 if (byte !== LF) throw errors.INVALID_HEADER()
476
477 this._state = HEADER_START
478
479 break
480 }
481
482 case HEADER_END_LF: {
483 if (byte !== LF) throw errors.INVALID_MESSAGE()
484
485 const headers = this._headers
486
487 if (this._isResponse) {
488 yield {
489 type: constants.RESPONSE,
490 version: this._version,
491 code: this._code,
492 reason: this._reason,
493 headers
494 }
495 } else {
496 if (this._version === 'HTTP/1.1' && !('host' in headers)) {
497 throw errors.INVALID_HEADER("Header 'Host' is missing")
498 }
499
500 yield {
501 type: constants.REQUEST,
502 version: this._version,
503 method: this._method,
504 url: this._url,
505 headers
506 }
507 }
508
509 const transferEncoding = headers['transfer-encoding']
510 const contentLength = headers['content-length']
511
512 const encodings = transferEncoding ? transferEncoding.split(',') : null
513
514 const lastEncoding = encodings
515 ? encodings[encodings.length - 1].trim().toLowerCase()
516 : null
517
518 if (lastEncoding === 'chunked') {
519 if (contentLength) {
520 throw errors.INVALID_MESSAGE(
521 "Conflicting 'Content-Length' and 'Transfer-Encoding' headers"
522 )
523 }
524
525 this._state = CHUNK_SIZE
526 this._headerSize = 0
527
528 continue
529 }
530
531 if (contentLength) {
532 if (contentLength.length === 0) throw errors.INVALID_CONTENT_LENGTH()
533
534 let length = 0
535
536 for (let i = 0, n = contentLength.length; i < n; i++) {
537 const c = contentLength.charCodeAt(i)
538
539 if (c < ZERO || c > NINE) throw errors.INVALID_CONTENT_LENGTH()
540
541 length = length * 10 + (c - ZERO)
542 }
543
544 if (!Number.isSafeInteger(length) || length < 0) {
545 throw errors.INVALID_CONTENT_LENGTH()
546 }
547
548 if (length === 0) {
549 this._state = FIRST_TOKEN
550 this._headerSize = 0
551
552 yield { type: constants.END }
553 } else {
554 this._state = BODY
555 this._remaining = length
556 this._headerSize = 0
557 }
558 } else {
559 this._state = FIRST_TOKEN
560 this._headerSize = 0
561
562 yield { type: constants.END }
563 }
564
565 break
566 }
567
568 case CHUNK_SIZE: {
569 if (byte === CR || byte === 0x3b) {
570 if (this._accumulator.length === 0) throw errors.INVALID_CHUNK_LENGTH()
571
572 let length = 0
573
574 for (let i = 0, n = this._accumulator.length; i < n; i++) {
575 length = length * 16 + this._accumulator[i]
576 }
577
578 this._accumulator = []
579
580 if (!Number.isSafeInteger(length)) throw errors.INVALID_CHUNK_LENGTH()
581
582 if (byte === 0x3b) {
583 this._remaining = length
584 this._state = CHUNK_EXTENSION
585 } else if (length === 0) {
586 this._state = LAST_CHUNK_LF
587 } else {
588 this._remaining = length + 2
589 this._state = CHUNK_SIZE_LF
590 }
591 } else if (isHex(byte)) {
592 if (this._accumulator.length >= MAX_CHUNK_SIZE_LENGTH) {
593 throw errors.INVALID_CHUNK_LENGTH()
594 }
595
596 this._accumulator.push(hexValue(byte))
597 } else {
598 throw errors.INVALID_CHUNK_LENGTH()
599 }
600
601 break
602 }
603
604 case CHUNK_EXTENSION: {
605 this._checkHeaderSize()
606
607 if (byte === CR) {
608 if (this._remaining === 0) {
609 this._state = LAST_CHUNK_LF
610 } else {
611 this._remaining += 2
612 this._state = CHUNK_SIZE_LF
613 }
614 } else if (!isFieldByte(byte)) {
615 throw errors.INVALID_CHUNK_LENGTH()
616 }
617
618 break
619 }
620
621 case CHUNK_SIZE_LF: {
622 if (byte !== LF) throw errors.INVALID_CHUNK_LENGTH()
623
624 this._state = CHUNK_DATA
625
626 break
627 }
628
629 case LAST_CHUNK_LF: {
630 if (byte !== LF) throw errors.INVALID_CHUNK_LENGTH()
631
632 this._state = TRAILER_CR
633
634 break
635 }
636
637 case TRAILER_CR: {
638 if (byte !== CR) throw errors.INVALID_MESSAGE()
639
640 this._state = TRAILER_LF
641
642 break
643 }
644
645 case TRAILER_LF: {
646 if (byte !== LF) throw errors.INVALID_MESSAGE()
647
648 this._state = FIRST_TOKEN
649 this._headerSize = 0
650
651 yield { type: constants.END }
652
653 break
654 }
655
656 default:
657 throw errors.INVALID_MESSAGE()
658 }
659 }
660 }
661}
662
663exports.constants = constants
664
665const TOKEN_BYTES = Buffer.from([
666 // 0x00-0x1f (control characters) + 0x20 (space)
667 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
668 // 0x21-0x41: ! " # $ % & ' ( ) * + , - . / 0-9 : ; < = > ? @ A
669 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
670 // 0x42-0x62: B-Z [ \ ] ^ _ ` a b
671 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
672 // 0x63-0x7f: c-z { | } ~ DEL
673 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0
674])
675
676function isTokenByte(b) {
677 return TOKEN_BYTES[b] === 1
678}
679
680function isFieldByte(b) {
681 return b === TAB || (b >= 0x20 && b <= 0x7e)
682}
683
684function isHex(b) {
685 return (
686 (b >= ZERO && b <= NINE) || (b >= UPPER_A && b <= UPPER_F) || (b >= LOWER_A && b <= LOWER_F)
687 )
688}
689
690function hexValue(b) {
691 if (b >= ZERO && b <= NINE) return b - ZERO
692 if (b >= UPPER_A && b <= UPPER_F) return b - UPPER_A + 10
693 return b - LOWER_A + 10
694}
node_modules/bare-http-parser/lib/errors.js +29 -0
……@@ -0,0 +1,29 @@
1module.exports = class HTTPParserError extends Error {
2 constructor(msg, fn = HTTPParserError, code = fn.name) {
3 super(`${code}: ${msg}`)
4
5 this.code = code
6
7 if (Error.captureStackTrace) Error.captureStackTrace(this, fn)
8 }
9
10 get name() {
11 return 'HTTPParserError'
12 }
13
14 static INVALID_MESSAGE(msg = 'Invalid HTTP message') {
15 return new HTTPParserError(msg, HTTPParserError.INVALID_MESSAGE)
16 }
17
18 static INVALID_HEADER(msg = 'Invalid HTTP header') {
19 return new HTTPParserError(msg, HTTPParserError.INVALID_HEADER)
20 }
21
22 static INVALID_CONTENT_LENGTH(msg = 'Invalid HTTP Content-Length') {
23 return new HTTPParserError(msg, HTTPParserError.INVALID_CONTENT_LENGTH)
24 }
25
26 static INVALID_CHUNK_LENGTH(msg = 'Invalid HTTP chunk length') {
27 return new HTTPParserError(msg, HTTPParserError.INVALID_CHUNK_LENGTH)
28 }
29}
node_modules/bare-http-parser/package.json +32 -0
……@@ -0,0 +1,32 @@
1{
2 "name": "bare-http-parser",
3 "version": "1.1.3",
4 "description": "Streaming HTTP request and response parser for Bare",
5 "exports": {
6 "./package": "./package.json",
7 ".": "./index.js",
8 "./errors": "./lib/errors.js"
9 },
10 "files": [
11 "index.js",
12 "lib"
13 ],
14 "scripts": {
15 "test": "prettier . --check && bare test.js"
16 },
17 "repository": {
18 "type": "git",
19 "url": "git+https://github.com/holepunchto/bare-http-parser.git"
20 },
21 "author": "Holepunch",
22 "license": "Apache-2.0",
23 "bugs": {
24 "url": "https://github.com/holepunchto/bare-http-parser/issues"
25 },
26 "homepage": "https://github.com/holepunchto/bare-http-parser#readme",
27 "devDependencies": {
28 "brittle": "^3.3.0",
29 "prettier": "^3.4.1",
30 "prettier-config-holepunch": "^2.0.0"
31 }
32}
node_modules/bare-http1/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-http1/README.md +34 -0
……@@ -0,0 +1,34 @@
1# bare-http1
2
3HTTP/1 library for JavaScript.
4
5```
6npm i bare-http1
7```
8
9## Usage
10
11```js
12const http = require('bare-http1')
13
14const server = http.createServer((req, res) => {
15 res.statusCode = 200
16 res.setHeader('Content-Length', 10)
17 res.write('hello world!')
18 res.end()
19})
20
21server.listen(0, () => {
22 const { port } = server.address()
23 console.log('server is bound on', port)
24
25 const client = http.request({ port }, (res) => {
26 res.on('data', (data) => console.log(data.toString()))
27 })
28 client.end()
29})
30```
31
32## License
33
34Apache-2.0
node_modules/bare-http1/index.d.ts +272 -0
……@@ -0,0 +1,272 @@
1import { Readable, ReadableEvents, Writable, WritableEvents } from 'bare-stream'
2import {
3 TCPSocket,
4 TCPSocketOptions,
5 TCPSocketConnectOptions,
6 TCPServer,
7 TCPServerEvents
8} from 'bare-tcp'
9import Buffer from 'bare-buffer'
10import URL from 'bare-url'
11import constants, { HTTPMethod, HTTPStatusCode, HTTPStatusMessage } from './lib/constants'
12import HTTPError from './lib/errors'
13
14export {
15 constants,
16 type HTTPMethod,
17 type HTTPStatusCode,
18 type HTTPStatusMessage,
19 type HTTPError,
20 HTTPError as errors
21}
22
23export const METHODS: HTTPMethod[]
24export const STATUS_CODES: typeof constants.status
25
26export interface HTTPIncomingMessageEvents extends ReadableEvents {
27 timeout: []
28}
29
30export interface HTTPIncomingMessageOptions {
31 headers?: Record<string, string | number>
32 method?: HTTPMethod
33 url?: string
34 statusCode?: HTTPStatusCode
35 statusMessage?: HTTPStatusMessage
36}
37
38interface HTTPIncomingMessage<
39 M extends HTTPIncomingMessageEvents = HTTPIncomingMessageEvents
40> extends Readable<M> {
41 readonly socket: TCPSocket
42 readonly upgrade: boolean
43 headers: Record<string, string | number>
44 method: HTTPMethod
45 url: string
46 statusCode: HTTPStatusCode
47 statusMessage: HTTPStatusMessage
48 readonly httpVersion: '1.1'
49
50 getHeader(name: string): string | number | undefined
51 getHeaders(): Record<string, string | number>
52 hasHeader(name: string): boolean
53
54 setTimeout(ms: number, ontimeout?: () => void): this
55}
56
57declare class HTTPIncomingMessage<
58 M extends HTTPIncomingMessageEvents = HTTPIncomingMessageEvents
59> extends Readable<M> {
60 constructor(socket?: TCPSocket, opts?: HTTPIncomingMessageOptions)
61}
62
63export { type HTTPIncomingMessage, HTTPIncomingMessage as IncomingMessage }
64
65export interface HTTPOutgoingMessageEvents extends WritableEvents {
66 timeout: []
67}
68
69interface HTTPOutgoingMessage<
70 M extends HTTPOutgoingMessageEvents = HTTPOutgoingMessageEvents
71> extends Writable<M> {
72 readonly socket: TCPSocket
73 readonly upgrade: boolean
74 readonly headersSent: boolean
75 headers: Record<string, string | number>
76
77 getHeader(name: string): string | number | undefined
78 getHeaders(): Record<string, string | number>
79 hasHeader(name: string): boolean
80 setHeader(name: string, value: string | number): void
81 flushHeaders(): void
82
83 setTimeout(ms: number, ontimeout?: () => void): this
84}
85
86declare class HTTPOutgoingMessage<
87 M extends HTTPOutgoingMessageEvents = HTTPOutgoingMessageEvents
88> extends Writable<M> {
89 constructor(socket?: TCPSocket)
90}
91
92export { type HTTPOutgoingMessage, HTTPOutgoingMessage as OutgoingMessage }
93
94export interface HTTPAgentOptions {
95 keepAlive?: boolean
96 keepAliveMsecs?: number
97}
98
99interface HTTPAgent {
100 readonly suspended: boolean
101 readonly resumed: Promise<void> | null
102 readonly sockets: IterableIterator<TCPSocket>
103 readonly freeSockets: IterableIterator<TCPSocket>
104
105 createConnection(opts?: TCPSocketOptions & TCPSocketConnectOptions): TCPSocket
106 reuseSocket(socket: TCPSocket, req?: HTTPClientRequest): void
107 keepSocketAlive(socket: TCPSocket): boolean
108 getName(opts: { host: string; port: number }): string
109 addRequest(req: HTTPClientRequest, opts: TCPSocketOptions & TCPSocketConnectOptions): void
110
111 suspend(): void
112 resume(): void
113 destroy(): void
114}
115
116declare class HTTPAgent {
117 constructor(opts?: HTTPAgentOptions & TCPSocketOptions & TCPSocketConnectOptions)
118}
119
120declare namespace HTTPAgent {
121 export const global: HTTPAgent
122}
123
124export const globalAgent: HTTPAgent
125
126export { type HTTPAgent, HTTPAgent as Agent }
127
128export interface HTTPServerEvents extends TCPServerEvents {
129 request: [req: HTTPIncomingMessage, res: HTTPServerResponse]
130 upgrade: [req: HTTPIncomingMessage, socket: TCPSocket, head: Buffer]
131 timeout: [socket: TCPSocket]
132}
133
134interface HTTPServer<M extends HTTPServerEvents = HTTPServerEvents> extends TCPServer<M> {
135 readonly timeout: number | undefined
136
137 setTimeout(ms: number, ontimeout?: () => void): this
138}
139
140declare class HTTPServer<M extends HTTPServerEvents = HTTPServerEvents> extends TCPServer<M> {
141 constructor(
142 opts?: HTTPServerConnectionOptions,
143 onrequest?: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
144 )
145
146 constructor(onrequest: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void)
147}
148
149export { type HTTPServer, HTTPServer as Server }
150
151interface HTTPServerResponse extends HTTPOutgoingMessage {
152 readonly req: HTTPIncomingMessage
153 statusCode: HTTPStatusCode
154 statusMessage: HTTPStatusMessage | null
155
156 writeHead(
157 statusCode: HTTPStatusCode,
158 statusMessage?: HTTPStatusMessage,
159 headers?: Record<string, string | number>
160 ): void
161
162 writeHead(statusCode: HTTPStatusCode, headers?: Record<string, string | number>): void
163}
164
165declare class HTTPServerResponse extends HTTPOutgoingMessage {
166 constructor(socket: TCPSocket, req: HTTPIncomingMessage)
167}
168
169export { type HTTPServerResponse, HTTPServerResponse as ServerResponse }
170
171export interface HTTPServerConnectionOptions {
172 IncomingMessage?: typeof HTTPIncomingMessage
173 ServerResponse?: typeof HTTPServerResponse
174}
175
176interface HTTPServerConnection {
177 readonly server: HTTPServer
178 readonly socket: TCPSocket | null
179 readonly req: HTTPIncomingMessage | null
180 readonly res: HTTPServerResponse | null
181 readonly idle: boolean
182}
183
184declare class HTTPServerConnection {
185 constructor(server: HTTPServer, socket: TCPSocket, opts?: HTTPServerConnectionOptions)
186
187 static for(socket: TCPSocket): HTTPServerConnection
188}
189
190export { type HTTPServerConnection, HTTPServerConnection as ServerConnection }
191
192export interface HTTPClientRequestEvents extends HTTPOutgoingMessageEvents {
193 response: [res: HTTPIncomingMessage]
194 upgrade: [res: HTTPIncomingMessage, socket: TCPSocket, head: Buffer]
195}
196
197export interface HTTPClientRequestOptions extends TCPSocketConnectOptions {
198 agent?: HTTPAgent | false
199 headers?: Record<string, string | number>
200 method?: HTTPMethod
201 path?: string
202}
203
204interface HTTPClientRequest<
205 M extends HTTPClientRequestEvents = HTTPClientRequestEvents
206> extends HTTPOutgoingMessage<M> {
207 readonly method: HTTPMethod
208 readonly path: string
209 readonly headers: Record<string, string | number>
210}
211
212declare class HTTPClientRequest<
213 M extends HTTPClientRequestEvents = HTTPClientRequestEvents
214> extends HTTPOutgoingMessage<M> {
215 constructor(opts?: HTTPClientRequestOptions, onresponse?: () => void)
216
217 constructor(onresponse: () => void)
218}
219
220export { type HTTPClientRequest, HTTPClientRequest as ClientRequest }
221
222export interface HTTPClientConnectionOptions {
223 IncomingMessage?: typeof HTTPIncomingMessage
224}
225
226interface HTTPClientConnection {
227 readonly socket: TCPSocket | null
228 readonly req: HTTPClientRequest | null
229 readonly res: HTTPIncomingMessage | null
230 readonly idle: boolean
231}
232
233declare class HTTPClientConnection {
234 constructor(socket: TCPSocket, opts?: HTTPClientConnectionOptions)
235
236 static for(socket: TCPSocket): HTTPClientConnection | null
237
238 static from(socket: TCPSocket, opts?: HTTPClientConnectionOptions): HTTPClientConnection
239}
240
241export { type HTTPClientConnection, HTTPClientConnection as ClientConnection }
242
243export function createServer(
244 opts?: HTTPServerConnectionOptions,
245 onrequest?: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
246): HTTPServer
247
248export function createServer(
249 onrequest: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
250): HTTPServer
251
252export function request(
253 url: URL | string,
254 opts?: HTTPClientRequestOptions,
255 onresponse?: (res: HTTPIncomingMessage) => void
256): HTTPClientRequest
257
258export function get(
259 url: URL | string,
260 opts?: HTTPClientRequestOptions,
261 onresponse?: (res: HTTPIncomingMessage) => void
262): HTTPClientRequest
263
264export function request(
265 url: URL | string,
266 onresponse: (res: HTTPIncomingMessage) => void
267): HTTPClientRequest
268
269export function request(
270 opts: HTTPClientRequestOptions,
271 onresponse?: (res: HTTPIncomingMessage) => void
272): HTTPClientRequest
node_modules/bare-http1/index.js +81 -0
……@@ -0,0 +1,81 @@
1exports.IncomingMessage = require('./lib/incoming-message')
2exports.OutgoingMessage = require('./lib/outgoing-message')
3
4exports.Agent = require('./lib/agent')
5exports.globalAgent = exports.Agent.global
6
7exports.Server = require('./lib/server')
8exports.ServerResponse = require('./lib/server-response')
9exports.ServerConnection = require('./lib/server-connection')
10
11exports.ClientRequest = require('./lib/client-request')
12exports.ClientConnection = require('./lib/client-connection')
13
14exports.constants = require('./lib/constants')
15exports.errors = require('./lib/errors')
16
17exports.METHODS = Object.values(exports.constants.method) // For Node.js compatibility
18exports.STATUS_CODES = exports.constants.status // For Node.js compatibility
19
20exports.createServer = function createServer(opts, onrequest) {
21 return new exports.Server(opts, onrequest)
22}
23
24exports.request = function request(url, opts, onresponse) {
25 if (typeof opts === 'function') {
26 onresponse = opts
27 opts = {}
28 }
29
30 if (typeof url === 'string') url = new URL(url)
31
32 if (isURL(url)) {
33 opts = opts ? { ...url, ...opts } : { ...url }
34
35 opts.host = url.hostname
36 opts.path = url.pathname + url.search
37 opts.port = url.port ? parseInt(url.port, 10) : defaultPort(url)
38 } else {
39 opts = url ? { ...url } : {}
40
41 // For Node.js compatibility
42 opts.host = opts.hostname || opts.host
43 opts.port = typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
44 }
45
46 return new exports.ClientRequest(opts, onresponse)
47}
48
49exports.get = function get(url, opts, onresponse) {
50 const req = exports.request(url, opts, onresponse)
51 req.end()
52 return req
53}
54
55// https://url.spec.whatwg.org/#default-port
56function defaultPort(url) {
57 switch (url.protocol) {
58 case 'ftp:':
59 return 21
60 case 'http:':
61 case 'ws:':
62 return 80
63 case 'https:':
64 case 'wss:':
65 return 443
66 }
67
68 return null
69}
70
71// https://url.spec.whatwg.org/#api
72function isURL(url) {
73 return (
74 url !== null &&
75 typeof url === 'object' &&
76 typeof url.protocol === 'string' &&
77 typeof url.hostname === 'string' &&
78 typeof url.pathname === 'string' &&
79 typeof url.search === 'string'
80 )
81}
node_modules/bare-http1/lib/agent.js +220 -0
……@@ -0,0 +1,220 @@
1const EventEmitter = require('bare-events')
2const tcp = require('bare-tcp')
3const HTTPClientConnection = require('./client-connection')
4const errors = require('./errors')
5
6class HTTPSocketSet {
7 constructor() {
8 this._sockets = new Map()
9 this._size = 0
10 }
11
12 get size() {
13 return this._size
14 }
15
16 add(name, socket) {
17 const sockets = this._sockets.get(name)
18
19 this._size++
20
21 if (sockets === undefined) this._sockets.set(name, [socket])
22 else sockets.push(socket)
23 }
24
25 pop(name) {
26 const sockets = this._sockets.get(name)
27 if (sockets === undefined || sockets.length === 0) return null
28
29 this._size--
30
31 const last = sockets.pop()
32
33 if (sockets.length === 0) this._sockets.delete(name)
34
35 return last
36 }
37
38 delete(name, socket) {
39 const sockets = this._sockets.get(name)
40 if (sockets === undefined) return
41
42 const i = sockets.indexOf(socket)
43 if (i === -1) return
44
45 this._size--
46
47 const last = sockets.pop()
48 if (last !== socket) sockets[i] = last
49
50 if (sockets.length === 0) this._sockets.delete(name)
51 }
52
53 *sockets() {
54 for (const sockets of this._sockets.values()) {
55 yield* sockets
56 }
57 }
58
59 *[Symbol.iterator]() {
60 for (const [name, sockets] of this._sockets) {
61 for (const socket of sockets) yield [name, socket]
62 }
63 }
64}
65
66class HTTPAgent extends EventEmitter {
67 constructor(opts = {}) {
68 super()
69
70 const { keepAlive = false, keepAliveMsecs = 1000, defaultPort = 80 } = opts
71
72 this._suspended = false
73 this._resuming = null
74
75 this._sockets = new HTTPSocketSet()
76 this._freeSockets = new HTTPSocketSet()
77
78 this._keepAlive = typeof keepAlive === 'number' ? keepAlive : keepAlive ? keepAliveMsecs : -1
79 this._defaultPort = defaultPort
80
81 this._opts = { ...opts }
82 }
83
84 get suspended() {
85 return this._suspended
86 }
87
88 get resumed() {
89 return this._resuming ? this._resuming.promise : null
90 }
91
92 get sockets() {
93 return this._sockets.sockets()
94 }
95
96 get freeSockets() {
97 return this._freeSockets.sockets()
98 }
99
100 get defaultPort() {
101 return this._defaultPort
102 }
103
104 createConnection(opts) {
105 if (this._suspended) throw errors.AGENT_SUSPENDED()
106
107 return tcp.createConnection(opts)
108 }
109
110 reuseSocket(socket, req) {
111 socket.ref()
112 }
113
114 keepSocketAlive(socket) {
115 if (this._keepAlive === -1) return false
116
117 socket.setKeepAlive(true, this._keepAlive)
118 socket.unref()
119
120 return true
121 }
122
123 getName(opts) {
124 return `${opts.host}:${opts.port}`
125 }
126
127 addRequest(req, opts) {
128 opts = { ...opts, ...this._opts }
129
130 const name = this.getName(opts)
131
132 let socket = this._freeSockets.pop(name)
133
134 if (socket) this.reuseSocket(socket, req)
135 else {
136 const agent = this
137
138 socket = this.createConnection(opts)
139
140 socket
141 .on('free', onfree)
142 .on('end', onremove)
143 .on('finish', onremove)
144 .on('close', onremove)
145 .on('timeout', ontimeout)
146
147 function onfree() {
148 if (socket.destroyed) return
149
150 if (agent.keepSocketAlive(socket)) {
151 agent._freeSockets.add(name, socket)
152 } else {
153 socket.end()
154 }
155
156 agent.emit('free', socket)
157 }
158
159 function onremove() {
160 socket.off('free', onfree)
161
162 agent._sockets.delete(name, socket)
163 agent._freeSockets.delete(name, socket)
164
165 if (agent._sockets.size === 0) HTTPAgent._agents.delete(agent)
166 }
167
168 function ontimeout() {
169 socket.destroy()
170
171 agent._freeSockets.delete(name, socket)
172 }
173 }
174
175 if (this._sockets.size === 0) HTTPAgent._agents.add(this)
176
177 this._sockets.add(name, socket)
178
179 req._socket = socket
180
181 const connection = HTTPClientConnection.from(socket, opts)
182
183 connection._req = req
184 }
185
186 suspend() {
187 if (this._suspended) return
188
189 this._resuming = Promise.withResolvers()
190 this._suspended = true
191
192 this.destroy()
193 }
194
195 resume() {
196 if (this._resuming === null) return
197
198 this._resuming.resolve()
199 this._resuming = null
200 this._suspended = false
201 }
202
203 destroy() {
204 for (const socket of this._sockets.sockets()) socket.destroy()
205 }
206
207 static _agents = new Set()
208
209 static _onidle() {
210 for (const agent of this._agents) {
211 agent.destroy()
212 }
213 }
214}
215
216HTTPAgent.global = new HTTPAgent({ keepAlive: 1000, timeout: 5000 })
217
218module.exports = HTTPAgent
219
220Bare.on('idle', HTTPAgent._onidle.bind(HTTPAgent))
node_modules/bare-http1/lib/client-connection.js +169 -0
……@@ -0,0 +1,169 @@
1const HTTPParser = require('bare-http-parser')
2const HTTPIncomingMessage = require('./incoming-message')
3const errors = require('./errors')
4
5const {
6 constants: { RESPONSE, DATA, END }
7} = HTTPParser
8
9const EMPTY = Buffer.alloc(0)
10
11module.exports = class HTTPClientConnection {
12 static _connections = new WeakMap()
13
14 static for(socket) {
15 return this._connections.get(socket) || null
16 }
17
18 static from(socket, opts) {
19 return this.for(socket) || new this(socket, opts)
20 }
21
22 constructor(socket, opts = {}) {
23 const { IncomingMessage = HTTPIncomingMessage } = opts
24
25 this._socket = socket
26
27 this._req = null
28 this._res = null
29
30 this._IncomingMessage = IncomingMessage
31
32 this._parser = new HTTPParser()
33 this._idle = true
34
35 this._onerror = this._onerror.bind(this)
36 this._onclose = this._onclose.bind(this)
37 this._onend = this._onend.bind(this)
38 this._ondata = this._ondata.bind(this)
39 this._ondrain = this._ondrain.bind(this)
40 this._ontimeout = this._ontimeout.bind(this)
41
42 socket
43 .on('error', this._onerror)
44 .on('close', this._onclose)
45 .on('end', this._onend)
46 .on('data', this._ondata)
47 .on('drain', this._ondrain)
48 .on('timeout', this._ontimeout)
49
50 HTTPClientConnection._connections.set(socket, this)
51 }
52
53 get socket() {
54 return this._socket
55 }
56
57 get req() {
58 return this._req
59 }
60
61 get res() {
62 return this._res
63 }
64
65 get idle() {
66 return this._idle
67 }
68
69 _onerror(err) {
70 if (this._req) this._req.destroy(err)
71 }
72
73 _onclose() {
74 if (this._req) this._req.destroy()
75 }
76
77 _onend() {
78 if (this._req) this._req.destroy(errors.CONNECTION_LOST())
79 }
80
81 _ondata(data) {
82 this._idle = false
83
84 try {
85 for (const op of this._parser.push(data)) {
86 switch (op.type) {
87 case RESPONSE:
88 this._req.on('close', () => {
89 this._req = null
90 })
91
92 this._res = new this._IncomingMessage(this._socket, {
93 headers: op.headers,
94 statusCode: op.code,
95 statusMessage: op.reason
96 })
97
98 this._res.on('close', () => {
99 this._res = null
100 this._idle = true
101
102 this._socket.emit('free')
103 })
104
105 if (op.headers.connection && op.headers.connection.toLowerCase() === 'upgrade') {
106 return this._onupgrade(this._parser.end())
107 }
108
109 this._req.emit('response', this._res)
110 break
111
112 case DATA:
113 this._res.push(op.data)
114 break
115
116 case END:
117 if (this._res) {
118 this._res._socket = null
119 this._res.push(null)
120 }
121
122 if (this._req) {
123 this._req._socket = null
124 this._req.destroy()
125 }
126 break
127 }
128 }
129 } catch (err) {
130 this._socket.destroy(err)
131 }
132 }
133
134 _onupgrade(data) {
135 this._detach()
136
137 const res = this._res
138 const req = this._req
139
140 res._upgrade = req._upgrade = true
141
142 const upgraded = req.emit('upgrade', res, this._socket, data || EMPTY)
143
144 res.push(null)
145 req.destroy()
146
147 if (!upgraded) this._socket.destroy()
148 }
149
150 _ontimeout() {
151 if (this._req) this._req.emit('timeout')
152 }
153
154 _ondrain() {
155 if (this._req) this._req._continueWrite()
156 }
157
158 _detach() {
159 this._socket
160 .off('error', this._onerror)
161 .off('close', this._onclose)
162 .off('end', this._onend)
163 .off('data', this._ondata)
164 .off('drain', this._ondrain)
165 .off('timeout', this._ontimeout)
166
167 HTTPClientConnection._connections.delete(this._socket)
168 }
169}
node_modules/bare-http1/lib/client-request.js +143 -0
……@@ -0,0 +1,143 @@
1const HTTPAgent = require('./agent')
2const HTTPOutgoingMessage = require('./outgoing-message')
3
4const CHUNK_DELIMITER = Buffer.from('\r\n')
5const CHUNK_TERMINATOR = Buffer.from('0\r\n\r\n')
6
7module.exports = class HTTPClientRequest extends HTTPOutgoingMessage {
8 constructor(opts = {}, onresponse = null) {
9 if (typeof opts === 'function') {
10 onresponse = opts
11 opts = {}
12 }
13
14 opts = opts ? { ...opts } : {}
15
16 const agent = opts.agent === false ? new HTTPAgent() : opts.agent || HTTPAgent.global
17 const method = opts.method || 'GET'
18 const path = opts.path || '/'
19 const defaultPort = opts.defaultPort || (agent && agent.defaultPort) || 80
20 const host = (opts.host = opts.host || 'localhost')
21 const port = (opts.port = opts.port || defaultPort)
22 const headers = { host: hostHeader(host, port, defaultPort), ...opts.headers }
23
24 super()
25
26 agent.addRequest(this, opts)
27
28 this._headers = headers
29 this._method = method
30 this._path = path
31
32 this._chunked = method !== 'GET' && method !== 'HEAD'
33
34 this._pendingWrite = null
35 this._pendingFinal = null
36
37 if (onresponse) this.once('response', onresponse)
38 }
39
40 get method() {
41 return this._method
42 }
43
44 get path() {
45 return this._path
46 }
47
48 // For Node.js compatibility
49 abort() {
50 return this.destroy()
51 }
52
53 _header() {
54 let h = `${this._method} ${this._path} HTTP/1.1\r\n`
55
56 let upgrade = false
57
58 for (const name of Object.keys(this._headers)) {
59 const n = name.toLowerCase()
60 const v = this._headers[name]
61
62 if (n === 'content-length') this._chunked = false
63 if (n === 'connection' && v && v.toLowerCase() === 'upgrade') upgrade = true
64
65 h += `${httpCase(n)}: ${v}\r\n`
66 }
67
68 if (upgrade) this._chunked = false
69
70 if (this._chunked) h += 'Transfer-Encoding: chunked\r\n'
71
72 h += '\r\n'
73
74 return h
75 }
76
77 _write(data, encoding, cb) {
78 if (this._headersSent === false) this.flushHeaders()
79
80 if (this._chunked) {
81 this._socket.write(Buffer.from(data.byteLength.toString(16)))
82 this._socket.write(CHUNK_DELIMITER)
83 }
84
85 let flushed = this._socket.write(data)
86
87 if (this._chunked) flushed = this._socket.write(CHUNK_DELIMITER)
88
89 if (flushed) cb(null)
90 else this._pendingWrite = cb
91 }
92
93 _final(cb) {
94 if (this._headersSent === false) this.flushHeaders()
95
96 if (this._chunked) this._socket.write(CHUNK_TERMINATOR)
97
98 this._pendingFinal = cb
99 }
100
101 _predestroy() {
102 super._predestroy()
103
104 this._continueWrite()
105 this._continueFinal()
106 }
107
108 _continueWrite() {
109 if (this._pendingWrite === null) return
110 const cb = this._pendingWrite
111 this._pendingWrite = null
112 cb(null)
113 }
114
115 _continueFinal() {
116 if (this._pendingFinal === null) return
117 const cb = this._pendingFinal
118 this._pendingFinal = null
119 cb(null)
120 }
121}
122
123function httpCase(n) {
124 let s = ''
125 for (const part of n.split('-')) {
126 s += (s ? '-' : '') + part.slice(0, 1).toUpperCase() + part.slice(1)
127 }
128 return s
129}
130
131function hostHeader(host, port, defaultPort) {
132 const i = host.indexOf(':')
133
134 if (i !== -1 && host.includes(':', i + 1) && host.charCodeAt(0) !== 91 /* [ */) {
135 host = `[${host}]`
136 }
137
138 if (port && +port !== defaultPort) {
139 host += ':' + port
140 }
141
142 return host
143}
node_modules/bare-http1/lib/constants.d.ts +86 -0
……@@ -0,0 +1,86 @@
1declare const constants: {
2 method: {
3 GET: 'GET'
4 HEAD: 'HEAD'
5 POST: 'POST'
6 PUT: 'PUT'
7 DELETE: 'DELETE'
8 CONNECT: 'CONNECT'
9 OPTIONS: 'OPTIONS'
10 TRACE: 'TRACE'
11 PATCH: 'PATCH'
12 }
13 status: {
14 100: 'Continue'
15 101: 'Switching Protocols'
16 102: 'Processing'
17 103: 'Early Hints'
18 200: 'OK'
19 201: 'Created'
20 202: 'Accepted'
21 203: 'Non-Authoritative Information'
22 204: 'No Content'
23 205: 'Reset Content'
24 206: 'Partial Content'
25 207: 'Multi-Status'
26 208: 'Already Reported'
27 226: 'IM Used'
28 300: 'Multiple Choices'
29 301: 'Moved Permanently'
30 302: 'Found'
31 303: 'See Other'
32 304: 'Not Modified'
33 305: 'Use Proxy'
34 307: 'Temporary Redirect'
35 308: 'Permanent Redirect'
36 400: 'Bad Request'
37 401: 'Unauthorized'
38 402: 'Payment Required'
39 403: 'Forbidden'
40 404: 'Not Found'
41 405: 'Method Not Allowed'
42 406: 'Not Acceptable'
43 407: 'Proxy Authentication Required'
44 408: 'Request Timeout'
45 409: 'Conflict'
46 410: 'Gone'
47 411: 'Length Required'
48 412: 'Precondition Failed'
49 413: 'Payload Too Large'
50 414: 'URI Too Long'
51 415: 'Unsupported Media Type'
52 416: 'Range Not Satisfiable'
53 417: 'Expectation Failed'
54 418: "I'm a Teapot"
55 421: 'Misdirected Request'
56 422: 'Unprocessable Entity'
57 423: 'Locked'
58 424: 'Failed Dependency'
59 425: 'Too Early'
60 426: 'Upgrade Required'
61 428: 'Precondition Required'
62 429: 'Too Many Requests'
63 431: 'Request Header Fields Too Large'
64 451: 'Unavailable For Legal Reasons'
65 500: 'Internal Server Error'
66 501: 'Not Implemented'
67 502: 'Bad Gateway'
68 503: 'Service Unavailable'
69 504: 'Gateway Timeout'
70 505: 'HTTP Version Not Supported'
71 506: 'Variant Also Negotiates'
72 507: 'Insufficient Storage'
73 508: 'Loop Detected'
74 509: 'Bandwidth Limit Exceeded'
75 510: 'Not Extended'
76 511: 'Network Authentication Required'
77 }
78}
79
80declare namespace constants {
81 export type HTTPMethod = keyof typeof constants.method
82 export type HTTPStatusCode = keyof typeof constants.status
83 export type HTTPStatusMessage = (typeof constants.status)[HTTPStatusCode]
84}
85
86export = constants
node_modules/bare-http1/lib/constants.js +78 -0
……@@ -0,0 +1,78 @@
1module.exports = {
2 method: {
3 GET: 'GET',
4 HEAD: 'HEAD',
5 POST: 'POST',
6 PUT: 'PUT',
7 DELETE: 'DELETE',
8 CONNECT: 'CONNECT',
9 OPTIONS: 'OPTIONS',
10 TRACE: 'TRACE',
11 PATCH: 'PATCH'
12 },
13 status: {
14 100: 'Continue',
15 101: 'Switching Protocols',
16 102: 'Processing',
17 103: 'Early Hints',
18 200: 'OK',
19 201: 'Created',
20 202: 'Accepted',
21 203: 'Non-Authoritative Information',
22 204: 'No Content',
23 205: 'Reset Content',
24 206: 'Partial Content',
25 207: 'Multi-Status',
26 208: 'Already Reported',
27 226: 'IM Used',
28 300: 'Multiple Choices',
29 301: 'Moved Permanently',
30 302: 'Found',
31 303: 'See Other',
32 304: 'Not Modified',
33 305: 'Use Proxy',
34 307: 'Temporary Redirect',
35 308: 'Permanent Redirect',
36 400: 'Bad Request',
37 401: 'Unauthorized',
38 402: 'Payment Required',
39 403: 'Forbidden',
40 404: 'Not Found',
41 405: 'Method Not Allowed',
42 406: 'Not Acceptable',
43 407: 'Proxy Authentication Required',
44 408: 'Request Timeout',
45 409: 'Conflict',
46 410: 'Gone',
47 411: 'Length Required',
48 412: 'Precondition Failed',
49 413: 'Payload Too Large',
50 414: 'URI Too Long',
51 415: 'Unsupported Media Type',
52 416: 'Range Not Satisfiable',
53 417: 'Expectation Failed',
54 418: "I'm a Teapot",
55 421: 'Misdirected Request',
56 422: 'Unprocessable Entity',
57 423: 'Locked',
58 424: 'Failed Dependency',
59 425: 'Too Early',
60 426: 'Upgrade Required',
61 428: 'Precondition Required',
62 429: 'Too Many Requests',
63 431: 'Request Header Fields Too Large',
64 451: 'Unavailable For Legal Reasons',
65 500: 'Internal Server Error',
66 501: 'Not Implemented',
67 502: 'Bad Gateway',
68 503: 'Service Unavailable',
69 504: 'Gateway Timeout',
70 505: 'HTTP Version Not Supported',
71 506: 'Variant Also Negotiates',
72 507: 'Insufficient Storage',
73 508: 'Loop Detected',
74 509: 'Bandwidth Limit Exceeded',
75 510: 'Not Extended',
76 511: 'Network Authentication Required'
77 }
78}
node_modules/bare-http1/lib/errors.d.ts +5 -0
……@@ -0,0 +1,5 @@
1declare class HTTPError extends Error {
2 readonly code: string
3}
4
5export = HTTPError
node_modules/bare-http1/lib/errors.js +26 -0
……@@ -0,0 +1,26 @@
1module.exports = class HTTPError extends Error {
2 constructor(msg, fn = HTTPError, code = fn.name) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'HTTPError'
13 }
14
15 static NOT_IMPLEMENTED(msg = 'Method not implemented') {
16 return new HTTPError(msg, HTTPError.NOT_IMPLEMENTED)
17 }
18
19 static CONNECTION_LOST(msg = 'Socket hung up') {
20 return new HTTPError(msg, HTTPError.CONNECTION_LOST)
21 }
22
23 static AGENT_SUSPENDED(msg = 'Agent is suspended') {
24 return new HTTPError(msg, HTTPError.AGENT_SUSPENDED)
25 }
26}
node_modules/bare-http1/lib/incoming-message.js +95 -0
……@@ -0,0 +1,95 @@
1const { Readable } = require('bare-stream')
2
3module.exports = class HTTPIncomingMessage extends Readable {
4 constructor(socket = null, opts = {}) {
5 super()
6
7 this._socket = socket
8 this._upgrade = false
9 this._headers = opts.headers || {}
10
11 // Server options
12 this._method = opts.method || ''
13 this._url = opts.url || ''
14
15 // Client options
16 this._statusCode = opts.statusCode || 0
17 this._statusMessage = opts.statusMessage || ''
18 }
19
20 get socket() {
21 return this._socket
22 }
23
24 get upgrade() {
25 return this._upgrade
26 }
27
28 get headers() {
29 return this._headers
30 }
31
32 set headers(value) {
33 this._headers = value
34 }
35
36 get method() {
37 return this._method
38 }
39
40 set method(value) {
41 this._method = value
42 }
43
44 get url() {
45 return this._url
46 }
47
48 set url(value) {
49 this._url = value
50 }
51
52 get statusCode() {
53 return this._statusCode
54 }
55
56 set statusCode(value) {
57 this._statusCode = value
58 }
59
60 get statusMessage() {
61 return this._statusMessage
62 }
63
64 set statusMessage(value) {
65 this._statusMessage = value
66 }
67
68 get httpVersion() {
69 return '1.1'
70 }
71
72 getHeader(name) {
73 return this._headers[name.toLowerCase()]
74 }
75
76 getHeaders() {
77 return { ...this._headers }
78 }
79
80 hasHeader(name) {
81 return name.toLowerCase() in this._headers
82 }
83
84 setTimeout(ms, ontimeout) {
85 if (ontimeout) this.once('timeout', ontimeout)
86
87 this._socket.setTimeout(ms)
88
89 return this
90 }
91
92 _predestroy() {
93 if (this._upgrade === false && this._socket !== null) this._socket.destroy()
94 }
95}
node_modules/bare-http1/lib/outgoing-message.js +72 -0
……@@ -0,0 +1,72 @@
1const { Writable } = require('bare-stream')
2const errors = require('./errors')
3
4module.exports = class HTTPOutgoingMessage extends Writable {
5 constructor(socket = null) {
6 super()
7
8 this._socket = socket
9 this._upgrade = false
10 this._headersSent = false
11 this._headers = {}
12 }
13
14 get socket() {
15 return this._socket
16 }
17
18 get upgrade() {
19 return this._upgrade
20 }
21
22 get headersSent() {
23 return this._headersSent
24 }
25
26 get headers() {
27 return this._headers
28 }
29
30 set headers(value) {
31 this._headers = value
32 }
33
34 getHeader(name) {
35 return this._headers[name.toLowerCase()]
36 }
37
38 getHeaders() {
39 return { ...this._headers }
40 }
41
42 hasHeader(name) {
43 return name.toLowerCase() in this._headers
44 }
45
46 setHeader(name, value) {
47 this._headers[name.toLowerCase()] = value
48 }
49
50 flushHeaders() {
51 if (this._headersSent === true || this._socket === null) return
52
53 this._socket.write(Buffer.from(this._header()))
54 this._headersSent = true
55 }
56
57 setTimeout(ms, ontimeout) {
58 if (ontimeout) this.once('timeout', ontimeout)
59
60 this._socket.setTimeout(ms)
61
62 return this
63 }
64
65 _header() {
66 throw errors.NOT_IMPLEMENTED()
67 }
68
69 _predestroy() {
70 if (this._upgrade === false && this._socket !== null) this._socket.destroy()
71 }
72}
node_modules/bare-http1/lib/server-connection.js +172 -0
……@@ -0,0 +1,172 @@
1const { isEnded, isFinished, getStreamError } = require('bare-stream')
2const HTTPParser = require('bare-http-parser')
3const HTTPIncomingMessage = require('./incoming-message')
4const HTTPServerResponse = require('./server-response')
5
6const {
7 constants: { REQUEST, DATA, END }
8} = HTTPParser
9
10const EMPTY = Buffer.alloc(0)
11
12module.exports = class HTTPServerConnection {
13 static _connections = new WeakMap()
14
15 static for(socket) {
16 return this._connections.get(socket) || null
17 }
18
19 constructor(server, socket, opts = {}) {
20 const { IncomingMessage = HTTPIncomingMessage, ServerResponse = HTTPServerResponse } = opts
21
22 this._server = server
23 this._socket = socket
24
25 this._req = null
26 this._res = null
27
28 this._IncomingMessage = IncomingMessage
29 this._ServerResponse = ServerResponse
30
31 this._parser = new HTTPParser()
32 this._idle = true
33
34 this._onclose = this._onclose.bind(this)
35 this._ondata = this._ondata.bind(this)
36 this._ondrain = this._ondrain.bind(this)
37 this._ontimeout = this._ontimeout.bind(this)
38
39 socket
40 .on('error', noop)
41 .on('close', this._onclose)
42 .on('data', this._ondata)
43 .on('drain', this._ondrain)
44 .on('timeout', this._ontimeout)
45
46 HTTPServerConnection._connections.set(socket, this)
47
48 if (this._server.timeout) socket.setTimeout(this._server.timeout)
49 }
50
51 get server() {
52 return this._server
53 }
54
55 get socket() {
56 return this._socket
57 }
58
59 get req() {
60 return this._req
61 }
62
63 get res() {
64 return this._res
65 }
66
67 get idle() {
68 return this._idle
69 }
70
71 _onclose() {
72 if (this._req && !isEnded(this._req)) this._req.destroy()
73 if (this._res && !isFinished(this._res)) this._res.destroy()
74
75 const err = getStreamError(this._socket)
76 if (err) this._socket.destroy(err)
77 }
78
79 _ondata(data) {
80 this._idle = false
81
82 try {
83 for (const op of this._parser.push(data)) {
84 switch (op.type) {
85 case REQUEST:
86 this._req = new this._IncomingMessage(this._socket, {
87 headers: op.headers,
88 method: op.method,
89 url: op.url
90 })
91
92 this._req.on('close', () => {
93 this._req = null
94
95 this._idle = true
96
97 if (this._server.closing) this._socket.destroy()
98 })
99
100 // Eagerly open the request stream
101 this._req.resume()
102 this._req.pause()
103
104 if (op.headers.connection && op.headers.connection.toLowerCase() === 'upgrade') {
105 return this._onupgrade(this._parser.end())
106 }
107
108 this._res = new this._ServerResponse(this._socket, this._req)
109
110 this._res.on('close', () => {
111 this._res = null
112 })
113
114 this._server.emit('request', this._req, this._res)
115 break
116
117 case DATA:
118 this._req.push(op.data)
119 break
120
121 case END:
122 if (this._req) {
123 this._req._socket = null
124 this._req.push(null)
125 }
126 break
127 }
128 }
129 } catch (err) {
130 this._socket.destroy(err)
131 }
132 }
133
134 _onupgrade(data) {
135 this._detach()
136
137 const req = this._req
138
139 req._upgrade = true
140
141 const upgraded = this._server.emit('upgrade', req, this._socket, data || EMPTY)
142
143 req.push(null)
144
145 if (!upgraded) this._socket.destroy()
146 }
147
148 _ontimeout() {
149 const reqTimeout = this._req && this._req.emit('timeout')
150 const resTimeout = this._res && this._res.emit('timeout')
151 const serverTimeout = this._server.emit('timeout', this._socket)
152
153 if (!reqTimeout && !resTimeout && !serverTimeout) this._socket.destroy()
154 }
155
156 _ondrain() {
157 if (this._res) this._res._continueWrite()
158 }
159
160 _detach() {
161 this._socket
162 .off('error', noop)
163 .off('close', this._onclose)
164 .off('data', this._ondata)
165 .off('drain', this._ondrain)
166 .off('timeout', this._ontimeout)
167
168 HTTPServerConnection._connections.delete(this._socket)
169 }
170}
171
172function noop() {}
node_modules/bare-http1/lib/server-response.js +143 -0
……@@ -0,0 +1,143 @@
1const { isFinishing } = require('bare-stream')
2const HTTPOutgoingMessage = require('./outgoing-message')
3const constants = require('./constants')
4
5const CHUNK_DELIMITER = Buffer.from('\r\n')
6const CHUNK_TERMINATOR = Buffer.from('0\r\n\r\n')
7
8module.exports = class HTTPServerResponse extends HTTPOutgoingMessage {
9 constructor(socket, req) {
10 super(socket)
11
12 this._req = req
13
14 this._statusCode = 200
15 this._statusMessage = null
16
17 this._chunked = true
18 this._close = req.headers.connection === 'close'
19 this._onlyHeaders = req.method === 'HEAD'
20
21 this._pendingWrite = null
22 }
23
24 get req() {
25 return this._req
26 }
27
28 get statusCode() {
29 return this._statusCode
30 }
31
32 set statusCode(value) {
33 this._statusCode = value
34 }
35
36 get statusMessage() {
37 return this._statusMessage
38 }
39
40 set statusMessage(value) {
41 this._statusMessage = value
42 }
43
44 writeHead(statusCode, statusMessage = null, headers = {}) {
45 if (typeof statusMessage === 'object' && statusMessage !== null) {
46 headers = statusMessage
47 statusMessage = null
48 }
49
50 this._statusCode = statusCode
51 this._statusMessage = statusMessage || null
52
53 if (headers) this._headers = { ...this._headers, ...headers }
54 }
55
56 _header() {
57 let h =
58 'HTTP/1.1 ' +
59 this._statusCode +
60 ' ' +
61 (this._statusMessage === null ? constants.status[this._statusCode] : this._statusMessage) +
62 '\r\n'
63
64 for (const name of Object.keys(this._headers)) {
65 const n = name.toLowerCase()
66 const v = this._headers[name]
67
68 if (n === 'content-length') this._chunked = false
69 if (n === 'connection' && v && v.toLowerCase() === 'close') this._close = true
70
71 h += httpCase(n) + ': ' + v + '\r\n'
72 }
73
74 if (this._chunked) h += 'Transfer-Encoding: chunked\r\n'
75
76 h += '\r\n'
77
78 return h
79 }
80
81 _write(data, encoding, cb) {
82 if (this._headersSent === false) {
83 if (isFinishing(this)) {
84 this.setHeader(
85 'Content-Length',
86 (data.byteLength + this._writableState.buffered).toString()
87 )
88 }
89
90 this.flushHeaders()
91 }
92
93 if (this._onlyHeaders === true) return cb(null)
94
95 if (this._chunked) {
96 this._socket.write(Buffer.from(data.byteLength.toString(16)))
97 this._socket.write(CHUNK_DELIMITER)
98 }
99
100 let flushed = this._socket.write(data)
101
102 if (this._chunked) flushed = this._socket.write(CHUNK_DELIMITER)
103
104 if (flushed) cb(null)
105 else this._pendingWrite = cb
106 }
107
108 _final(cb) {
109 if (this._headersSent === false) {
110 this.setHeader('Content-Length', '0')
111 this.flushHeaders()
112 }
113
114 if (this._chunked && this._onlyHeaders === false) this._socket.write(CHUNK_TERMINATOR)
115
116 if (this._close) this._socket.end()
117
118 cb(null)
119 }
120
121 _predestroy() {
122 super._predestroy()
123
124 this._req.destroy()
125
126 this._continueWrite()
127 }
128
129 _continueWrite() {
130 if (this._pendingWrite === null) return
131 const cb = this._pendingWrite
132 this._pendingWrite = null
133 cb(null)
134 }
135}
136
137function httpCase(n) {
138 let s = ''
139 for (const part of n.split('-')) {
140 s += (s ? '-' : '') + part.slice(0, 1).toUpperCase() + part.slice(1)
141 }
142 return s
143}
node_modules/bare-http1/lib/server.js +47 -0
……@@ -0,0 +1,47 @@
1const TCPServer = require('bare-tcp').Server
2const HTTPServerConnection = require('./server-connection')
3
4module.exports = class HTTPServer extends TCPServer {
5 constructor(opts = {}, onrequest) {
6 if (typeof opts === 'function') {
7 onrequest = opts
8 opts = {}
9 }
10
11 super({ allowHalfOpen: false })
12
13 this._timeout = 0
14
15 this.on('connection', (socket) => {
16 new HTTPServerConnection(this, socket, opts)
17 })
18
19 if (onrequest) this.on('request', onrequest)
20 }
21
22 get timeout() {
23 return this._timeout || undefined // For Node.js compatibility
24 }
25
26 setTimeout(ms = 0, ontimeout) {
27 if (ontimeout) this.on('timeout', ontimeout)
28
29 this._timeout = ms
30
31 return this
32 }
33
34 close(onclose) {
35 super.close(onclose)
36
37 for (const socket of this.connections) {
38 const connection = HTTPServerConnection.for(socket)
39
40 if (connection === null || connection.idle) {
41 socket.destroy()
42 }
43 }
44
45 return this
46 }
47}
node_modules/bare-http1/package.json +63 -0
……@@ -0,0 +1,63 @@
1{
2 "name": "bare-http1",
3 "version": "4.5.5",
4 "description": "Native HTTP/1 library for JavaScript",
5 "exports": {
6 "./package": "./package.json",
7 ".": {
8 "types": "./index.d.ts",
9 "default": "./index.js"
10 },
11 "./constants": {
12 "types": "./lib/constants.d.ts",
13 "default": "./lib/constants.js"
14 },
15 "./errors": {
16 "types": "./lib/errors.d.ts",
17 "default": "./lib/errors.js"
18 }
19 },
20 "files": [
21 "index.js",
22 "index.d.ts",
23 "lib"
24 ],
25 "scripts": {
26 "test": "prettier . --check && bare test.js"
27 },
28 "repository": {
29 "type": "git",
30 "url": "git+https://github.com/holepunchto/bare-http1.git"
31 },
32 "author": "Holepunch",
33 "license": "Apache-2.0",
34 "bugs": {
35 "url": "https://github.com/holepunchto/bare-http1/issues"
36 },
37 "homepage": "https://github.com/holepunchto/bare-http1#readme",
38 "dependencies": {
39 "bare-events": "^2.6.0",
40 "bare-http-parser": "^1.1.1",
41 "bare-stream": "^2.10.0",
42 "bare-tcp": "^2.2.0"
43 },
44 "devDependencies": {
45 "bare-buffer": "^3.0.2",
46 "bare-url": "^2.1.3",
47 "brittle": "^3.3.0",
48 "prettier": "^3.4.1",
49 "prettier-config-holepunch": "^2.0.0"
50 },
51 "peerDependencies": {
52 "bare-buffer": "*",
53 "bare-url": "*"
54 },
55 "peerDependenciesMeta": {
56 "bare-buffer": {
57 "optional": true
58 },
59 "bare-url": {
60 "optional": true
61 }
62 }
63}
node_modules/bare-https/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-https/README.md +39 -0
……@@ -0,0 +1,39 @@
1# bare-https
2
3HTTPS library for JavaScript.
4
5```
6npm i bare-https
7```
8
9## Usage
10
11```js
12const https = require('bare-https')
13
14const options = {
15 cert: fs.readFileSync('test/fixtures/cert.crt'),
16 key: fs.readFileSync('test/fixtures/cert.key')
17}
18
19const server = https.createServer(options, (req, res) => {
20 res.statusCode = 200
21 res.setHeader('Content-Length', 10)
22 res.write('hello world!')
23 res.end()
24})
25
26server.listen(0, () => {
27 const { port } = server.address()
28 console.log('server is bound on', port)
29
30 const client = https.request({ port }, (res) => {
31 res.on('data', (data) => console.log(data.toString()))
32 })
33 client.end()
34})
35```
36
37## License
38
39Apache-2.0
node_modules/bare-https/index.d.ts +82 -0
……@@ -0,0 +1,82 @@
1import { TLSSocket, TLSSocketOptions } from 'bare-tls'
2import {
3 HTTPAgent,
4 HTTPClientRequest,
5 HTTPClientRequestOptions,
6 HTTPIncomingMessage,
7 HTTPServer,
8 HTTPServerConnectionOptions,
9 HTTPServerResponse
10} from 'bare-http1'
11import { TCPSocket, TCPSocketOptions, TCPSocketConnectOptions } from 'bare-tcp'
12
13export interface HTTPSSocketOptions
14 extends TLSSocketOptions, TCPSocketOptions, TCPSocketConnectOptions {}
15
16export interface HTTPSSocket extends TLSSocket, TCPSocket {}
17
18class HTTPSSocket extends TLSSocket {}
19
20export interface HTTPSAgent extends HTTPAgent {
21 createConnection(opts?: HTTPSSocketOptions): HTTPSSocket
22}
23
24class HTTPSAgent extends HTTPAgent {
25 static global: HTTPSAgent
26}
27
28export const globalAgent: HTTPSAgent
29
30export { HTTPSAgent as Agent }
31
32export interface HTTPSServerOptions extends HTTPSSocketOptions, HTTPServerConnectionOptions {}
33
34class HTTPSServer extends HTTPServer {
35 constructor(
36 opts?: HTTPSServerOptions,
37 onrequest?: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
38 )
39
40 constructor(onrequest: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void)
41}
42
43export { HTTPSServer as Server }
44
45export interface HTTPSClientRequestOptions extends HTTPClientRequestOptions {
46 agent?: HTTPSAgent | false
47}
48
49export interface HTTPSClientRequest extends HTTPClientRequest {}
50
51class HTTPSClientRequest extends HTTPClientRequest {
52 constructor(opts?: HTTPSClientRequestOptions, onresponse?: () => void)
53
54 constructor(onresponse: () => void)
55}
56
57export { HTTPClientRequest as ClientRequest }
58
59export function createServer(
60 opts?: HTTPSServerOptions,
61 onrequest?: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
62): HTTPSServer
63
64export function createServer(
65 onrequest: (req: HTTPIncomingMessage, res: HTTPServerResponse) => void
66): HTTPSServer
67
68export function request(
69 url: URL | string,
70 opts?: HTTPSClientRequestOptions,
71 onresponse?: (res: HTTPIncomingMessage) => void
72): HTTPSClientRequest
73
74export function request(
75 url: URL | string,
76 onresponse: (res: HTTPIncomingMessage) => void
77): HTTPSClientRequest
78
79export function request(
80 opts: HTTPSClientRequestOptions,
81 onresponse?: (res: HTTPIncomingMessage) => void
82): HTTPSClientRequest
node_modules/bare-https/index.js +63 -0
……@@ -0,0 +1,63 @@
1exports.Agent = require('./lib/agent')
2exports.globalAgent = exports.Agent.global
3
4exports.Server = require('./lib/server')
5
6exports.ClientRequest = require('./lib/client-request')
7
8exports.createServer = function createServer(opts, onrequest) {
9 return new exports.Server(opts, onrequest)
10}
11
12exports.request = function request(url, opts, onresponse) {
13 if (typeof opts === 'function') {
14 onresponse = opts
15 opts = {}
16 }
17
18 if (typeof url === 'string') url = new URL(url)
19
20 if (isURL(url)) {
21 opts = opts ? { ...url, ...opts } : { ...url }
22
23 opts.host = url.hostname
24 opts.path = url.pathname + url.search
25 opts.port = url.port ? parseInt(url.port, 10) : defaultPort(url)
26 } else {
27 opts = url ? { ...url } : {}
28
29 // For Node.js compatibility
30 opts.host = opts.hostname || opts.host
31 opts.port = typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
32 }
33
34 return new exports.ClientRequest(opts, onresponse)
35}
36
37// https://url.spec.whatwg.org/#default-port
38function defaultPort(url) {
39 switch (url.protocol) {
40 case 'ftp:':
41 return 21
42 case 'http:':
43 case 'ws:':
44 return 80
45 case 'https:':
46 case 'wss:':
47 return 443
48 }
49
50 return null
51}
52
53// https://url.spec.whatwg.org/#api
54function isURL(url) {
55 return (
56 url !== null &&
57 typeof url === 'object' &&
58 typeof url.protocol === 'string' &&
59 typeof url.hostname === 'string' &&
60 typeof url.pathname === 'string' &&
61 typeof url.search === 'string'
62 )
63}
node_modules/bare-https/lib/agent.js +16 -0
……@@ -0,0 +1,16 @@
1const HTTPAgent = require('bare-http1').Agent
2const HTTPSSocket = require('./socket')
3
4class HTTPSAgent extends HTTPAgent {
5 constructor(opts = {}) {
6 super({ defaultPort: 443, ...opts })
7 }
8
9 createConnection(opts) {
10 return new HTTPSSocket(super.createConnection(opts), opts)
11 }
12}
13
14HTTPSAgent.global = new HTTPSAgent({ keepAlive: 1000, timeout: 5000 })
15
16module.exports = HTTPSAgent
node_modules/bare-https/lib/client-request.js +17 -0
……@@ -0,0 +1,17 @@
1const HTTPClientRequest = require('bare-http1').ClientRequest
2const HTTPSAgent = require('./agent')
3
4module.exports = class HTTPSClientRequest extends HTTPClientRequest {
5 constructor(opts = {}, onresponse = null) {
6 if (typeof opts === 'function') {
7 onresponse = opts
8 opts = {}
9 }
10
11 opts = opts ? { ...opts } : {}
12
13 opts.agent = opts.agent === false ? new HTTPSAgent() : opts.agent || HTTPSAgent.global
14
15 super(opts, onresponse)
16 }
17}
node_modules/bare-https/lib/server.js +48 -0
……@@ -0,0 +1,48 @@
1const TCPServer = require('bare-tcp').Server
2const HTTPServerConnection = require('bare-http1').ServerConnection
3const HTTPSSocket = require('./socket')
4
5module.exports = class HTTPSServer extends TCPServer {
6 constructor(opts = {}, onrequest) {
7 if (typeof opts === 'function') {
8 onrequest = opts
9 opts = {}
10 }
11
12 super({ allowHalfOpen: false })
13
14 this._timeout = 0
15
16 this.on('connection', (socket) => {
17 new HTTPServerConnection(this, new HTTPSSocket(socket, { ...opts, isServer: true }), opts)
18 })
19
20 if (onrequest) this.on('request', onrequest)
21 }
22
23 get timeout() {
24 return this._timeout || undefined // For Node.js compatibility
25 }
26
27 setTimeout(ms = 0, ontimeout) {
28 if (ontimeout) this.on('timeout', ontimeout)
29
30 this._timeout = ms
31
32 return this
33 }
34
35 close(onclose) {
36 super.close(onclose)
37
38 for (const socket of this.connections) {
39 const connection = HTTPServerConnection.for(socket)
40
41 if (connection === null || connection.idle) {
42 socket.destroy()
43 }
44 }
45
46 return this
47 }
48}
node_modules/bare-https/lib/socket.js +33 -0
……@@ -0,0 +1,33 @@
1const TLSSocket = require('bare-tls').Socket
2
3module.exports = class HTTPSSocket extends TLSSocket {
4 setKeepAlive(...args) {
5 this.socket.setKeepAlive(...args)
6
7 return this
8 }
9
10 setNoDelay(...args) {
11 this.socket.setNoDelay(...args)
12
13 return this
14 }
15
16 setTimeout(...args) {
17 this.socket.setTimeout(...args)
18
19 return this
20 }
21
22 ref() {
23 this.socket.ref()
24
25 return this
26 }
27
28 unref() {
29 this.socket.unref()
30
31 return this
32 }
33}
node_modules/bare-https/package.json +41 -0
……@@ -0,0 +1,41 @@
1{
2 "name": "bare-https",
3 "version": "2.1.3",
4 "description": "HTTPS library for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json"
11 },
12 "files": [
13 "index.js",
14 "index.d.ts",
15 "lib"
16 ],
17 "scripts": {
18 "test": "prettier . --check && bare test.js"
19 },
20 "repository": {
21 "type": "git",
22 "url": "git+https://github.com/holepunchto/bare-https.git"
23 },
24 "author": "Holepunch",
25 "license": "Apache-2.0",
26 "bugs": {
27 "url": "https://github.com/holepunchto/bare-https/issues"
28 },
29 "homepage": "https://github.com/holepunchto/bare-https#readme",
30 "dependencies": {
31 "bare-http1": "^4.4.0",
32 "bare-tcp": "^2.2.0",
33 "bare-tls": "^2.0.0"
34 },
35 "devDependencies": {
36 "bare-fs": "^4.0.0",
37 "brittle": "^3.3.0",
38 "prettier": "^3.4.1",
39 "prettier-config-holepunch": "^2.0.0"
40 }
41}
node_modules/bare-inspector/CMakeLists.txt +13 -0
……@@ -0,0 +1,13 @@
1cmake_minimum_required(VERSION 3.25)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4
5project(bare_inspector C)
6
7add_bare_module(bare_inspector)
8
9target_sources(
10 ${bare_inspector}
11 PRIVATE
12 binding.c
13)
node_modules/bare-inspector/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-inspector/README.md +62 -0
……@@ -0,0 +1,62 @@
1# bare-inspector
2
3V8 inspector support for Bare.
4
5```
6npm i bare-inspector
7```
8
9## Usage
10
11```js
12const { Session } = require('bare-inspector')
13
14const session = new Session()
15session.connect()
16
17try {
18 const { result } = await session.post('Runtime.evaluate', {
19 expression: '1 + 2'
20 })
21
22 console.log(result)
23} catch (err) {
24 console.error(err)
25}
26```
27
28### Heap snapshots
29
30```js
31const { Session, HeapSnapshot } = require('bare-inspector')
32const fs = require('bare-fs')
33
34const session = new Session()
35session.connect()
36
37const snapshot = new HeapSnapshot(session)
38
39snapshot.pipe(fs.createWriteStream('profile.heapsnapshot'))
40```
41
42## API
43
44#### `const session = new Session()`
45
46#### `session.connect()`
47
48#### `session.post()`
49
50#### `session.destroy()`
51
52#### `session.on('<inspector-protocol-method>', message)`
53
54#### `session.on('inspectorNotification', message)`
55
56#### `const snapshot = new HeapSnapshot(session)`
57
58#### `for await (const chunk of snapshot)`
59
60## License
61
62Apache-2.0
node_modules/bare-inspector/binding.c +222 -0
……@@ -0,0 +1,222 @@
1#include <assert.h>
2#include <bare.h>
3#include <js.h>
4
5typedef struct {
6 js_inspector_t *handle;
7
8 js_env_t *env;
9 js_ref_t *ctx;
10 js_ref_t *on_response;
11 js_ref_t *on_paused;
12} bare_inspector_t;
13
14static void
15bare_inspector__on_response(js_env_t *env, js_inspector_t *handle, js_value_t *message, void *data) {
16 int err;
17
18 bare_inspector_t *inspector = (bare_inspector_t *) data;
19
20 js_handle_scope_t *scope;
21 err = js_open_handle_scope(env, &scope);
22 assert(err == 0);
23
24 js_value_t *ctx;
25 err = js_get_reference_value(env, inspector->ctx, &ctx);
26 assert(err == 0);
27
28 js_value_t *callback;
29 err = js_get_reference_value(env, inspector->on_response, &callback);
30 assert(err == 0);
31
32 js_call_function(env, ctx, callback, 1, &message, NULL);
33
34 err = js_close_handle_scope(env, scope);
35 assert(err == 0);
36}
37
38static bool
39bare_inspector__on_paused(js_env_t *env, js_inspector_t *handle, void *data) {
40 int err;
41
42 bare_inspector_t *inspector = (bare_inspector_t *) data;
43
44 js_handle_scope_t *scope;
45 err = js_open_handle_scope(env, &scope);
46 assert(err == 0);
47
48 js_value_t *ctx;
49 err = js_get_reference_value(env, inspector->ctx, &ctx);
50 assert(err == 0);
51
52 js_value_t *callback;
53 err = js_get_reference_value(env, inspector->on_paused, &callback);
54 assert(err == 0);
55
56 js_value_t *result;
57 err = js_call_function(env, ctx, callback, 0, NULL, &result);
58
59 bool value;
60
61 if (err < 0) value = false;
62 else {
63 err = js_get_value_bool(env, result, &value);
64 assert(err == 0);
65 }
66
67 err = js_close_handle_scope(env, scope);
68 assert(err == 0);
69
70 return value;
71}
72
73static js_value_t *
74bare_inspector_create(js_env_t *env, js_callback_info_t *info) {
75 int err;
76
77 size_t argc = 3;
78 js_value_t *argv[3];
79
80 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
81 assert(err == 0);
82
83 assert(argc == 3);
84
85 js_value_t *handle;
86
87 bare_inspector_t *inspector;
88 err = js_create_arraybuffer(env, sizeof(bare_inspector_t), (void **) &inspector, &handle);
89 assert(err == 0);
90
91 err = js_create_inspector(env, &inspector->handle);
92 assert(err == 0);
93
94 err = js_on_inspector_response(env, inspector->handle, bare_inspector__on_response, (void *) inspector);
95 assert(err == 0);
96
97 err = js_on_inspector_paused(env, inspector->handle, bare_inspector__on_paused, (void *) inspector);
98 assert(err == 0);
99
100 inspector->env = env;
101
102 err = js_create_reference(env, argv[0], 1, &inspector->ctx);
103 assert(err == 0);
104
105 err = js_create_reference(env, argv[1], 1, &inspector->on_response);
106 assert(err == 0);
107
108 err = js_create_reference(env, argv[2], 1, &inspector->on_paused);
109 assert(err == 0);
110
111 return handle;
112}
113
114static js_value_t *
115bare_inspector_destroy(js_env_t *env, js_callback_info_t *info) {
116 int err;
117
118 size_t argc = 1;
119 js_value_t *argv[1];
120
121 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
122 assert(err == 0);
123
124 assert(argc == 1);
125
126 bare_inspector_t *inspector;
127 err = js_get_arraybuffer_info(env, argv[0], (void **) &inspector, NULL);
128 assert(err == 0);
129
130 err = js_destroy_inspector(env, inspector->handle);
131 assert(err == 0);
132
133 err = js_delete_reference(env, inspector->on_response);
134 assert(err == 0);
135
136 err = js_delete_reference(env, inspector->on_paused);
137 assert(err == 0);
138
139 err = js_delete_reference(env, inspector->ctx);
140 assert(err == 0);
141
142 return NULL;
143}
144
145static js_value_t *
146bare_inspector_connect(js_env_t *env, js_callback_info_t *info) {
147 int err;
148
149 size_t argc = 1;
150 js_value_t *argv[1];
151
152 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
153 assert(err == 0);
154
155 assert(argc == 1);
156
157 bare_inspector_t *inspector;
158 err = js_get_arraybuffer_info(env, argv[0], (void **) &inspector, NULL);
159 assert(err == 0);
160
161 err = js_connect_inspector(env, inspector->handle);
162 assert(err == 0);
163
164 return NULL;
165}
166
167static js_value_t *
168bare_inspector_post(js_env_t *env, js_callback_info_t *info) {
169 int err;
170
171 size_t argc = 2;
172 js_value_t *argv[2];
173
174 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
175 assert(err == 0);
176
177 assert(argc == 2);
178
179 bare_inspector_t *inspector;
180 err = js_get_arraybuffer_info(env, argv[0], (void **) &inspector, NULL);
181 assert(err == 0);
182
183 err = js_send_inspector_request(env, inspector->handle, argv[1]);
184 assert(err == 0);
185
186 return NULL;
187}
188
189static js_value_t *
190bare_inspector_exports(js_env_t *env, js_value_t *exports) {
191 int err;
192
193#define V(name, fn) \
194 { \
195 js_value_t *val; \
196 err = js_create_function(env, name, -1, fn, NULL, &val); \
197 assert(err == 0); \
198 err = js_set_named_property(env, exports, name, val); \
199 assert(err == 0); \
200 }
201
202 V("create", bare_inspector_create)
203 V("destroy", bare_inspector_destroy)
204 V("connect", bare_inspector_connect)
205 V("post", bare_inspector_post)
206#undef V
207
208 js_value_t *bindings;
209 err = js_get_bindings(env, &bindings);
210 assert(err == 0);
211
212 js_value_t *console;
213 err = js_get_named_property(env, bindings, "console", &console);
214 assert(err == 0);
215
216 err = js_set_named_property(env, exports, "console", console);
217 assert(err == 0);
218
219 return exports;
220}
221
222BARE_MODULE(bare_inspector, bare_inspector_exports)
node_modules/bare-inspector/binding.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon()
node_modules/bare-inspector/index.d.ts +6 -0
……@@ -0,0 +1,6 @@
1import Console from './lib/console'
2import Session from './lib/session'
3import Server from './lib/server'
4import HeapSnapshot from './lib/heap-snapshot'
5
6export { Console, Session, Server, HeapSnapshot }
node_modules/bare-inspector/index.js +4 -0
……@@ -0,0 +1,4 @@
1exports.Console = require('./lib/console')
2exports.Session = require('./lib/session')
3exports.Server = require('./lib/server')
4exports.HeapSnapshot = require('./lib/heap-snapshot')
node_modules/bare-inspector/lib/console.d.ts +38 -0
……@@ -0,0 +1,38 @@
1interface DirOptions {
2 colors?: number
3 depth?: number
4 showHidden?: boolean
5}
6
7declare class InspectorConsole {
8 debug(...data: unknown[]): void
9 error(...data: unknown[]): void
10 info(...data: unknown[]): void
11 log(...data: unknown[]): void
12 warn(...data: unknown[]): void
13
14 assert(condition: unknown, ...data: unknown[]): void
15 clear(): void
16 count(label?: string): void
17 countReset(label?: string): void
18 dir(object: unknown, opts?: DirOptions): void
19 dirxml(...data: unknown[]): void
20 group(...data: unknown[]): void
21 groupCollapsed(...data: unknown[]): void
22 groupEnd(): void
23 table(data: unknown, props?: string[]): void
24 time(label?: string): void
25 timeEnd(label?: string): void
26 timeLog(label?: string, ...data: unknown[]): void
27 trace(...data: unknown[]): void
28
29 profile(label?: string): void
30 profileEnd(label?: string): void
31 timeStamp(label?: string): void
32}
33
34declare namespace InspectorConsole {
35 export { type DirOptions }
36}
37
38export = InspectorConsole
node_modules/bare-inspector/lib/console.js +9 -0
……@@ -0,0 +1,9 @@
1const binding = require('../binding')
2
3module.exports = class InspectorConsole {
4 constructor() {
5 for (const method of Object.keys(binding.console)) {
6 this[method] = binding.console[method]
7 }
8 }
9}
node_modules/bare-inspector/lib/constants.js +6 -0
……@@ -0,0 +1,6 @@
1module.exports = {
2 state: {
3 CONNECTED: 0x1,
4 DESTROYED: 0x2
5 }
6}
node_modules/bare-inspector/lib/heap-snapshot.d.ts +10 -0
……@@ -0,0 +1,10 @@
1import { Readable } from 'bare-stream'
2import Session from './session'
3
4interface InspectorHeapSnapshot extends Readable {}
5
6declare class InspectorHeapSnapshot {
7 constructor(session: Session)
8}
9
10export = InspectorHeapSnapshot
node_modules/bare-inspector/lib/heap-snapshot.js +30 -0
……@@ -0,0 +1,30 @@
1const { Readable } = require('bare-stream')
2
3module.exports = class InspectorHeapSnapshot extends Readable {
4 constructor(session) {
5 super()
6
7 this._session = session
8 this._request = null
9 }
10
11 _open(cb) {
12 const onchunk = ({ params }) => {
13 this.push(params.chunk)
14 }
15
16 const onclose = ({ error } = {}) => {
17 this._session.off('HeapProfiler.addHeapSnapshotChunk', onchunk)
18
19 if (error) this.destroy(error)
20 else this.push(null)
21 }
22
23 this._session.on('HeapProfiler.addHeapSnapshotChunk', onchunk)
24
25 this._request = this._session.post('HeapProfiler.takeHeapSnapshot')
26 this._request.then(onclose, onclose)
27
28 cb()
29 }
30}
node_modules/bare-inspector/lib/server.d.ts +35 -0
……@@ -0,0 +1,35 @@
1import EventEmitter, { EventMap } from 'bare-events'
2import { type TCPSocketAddress } from 'bare-tcp'
3import URL from 'bare-url'
4
5interface InspectorServerEvents extends EventMap {
6 listening: []
7}
8
9interface InspectorServerOptions {
10 path: URL | string
11}
12
13interface InspectorServer<
14 M extends InspectorServerEvents = InspectorServerEvents
15> extends EventEmitter<M> {
16 readonly listening: boolean
17
18 address(): TCPSocketAddress
19 close(onclose?: (err: Error) => void): void
20
21 ref(): void
22 unref(): void
23}
24
25declare class InspectorServer {
26 constructor(opts: InspectorServerOptions)
27 constructor(port: number, opts: InspectorServerOptions)
28 constructor(port: number, host: string, opts?: InspectorServerOptions)
29}
30
31declare namespace InspectorServer {
32 export { type InspectorServerEvents, type InspectorServerOptions }
33}
34
35export = InspectorServer
node_modules/bare-inspector/lib/server.js +120 -0
……@@ -0,0 +1,120 @@
1/* global Bare */
2const EventEmitter = require('bare-events')
3const url = require('bare-url')
4const ws = require('bare-ws')
5const http = require('bare-http1')
6const Session = require('./session')
7
8module.exports = class InspectorServer extends EventEmitter {
9 constructor(port, host, opts = {}) {
10 if (typeof port === 'object' && port !== null) {
11 opts = port
12 port = 0
13 host = 'localhost'
14 } else if (typeof host === 'object' && host !== null) {
15 opts = host
16 host = 'localhost'
17 }
18
19 const { path = require.main.path } = opts
20
21 super()
22
23 this._path = typeof path === 'string' ? url.pathToFileURL(path) : path
24 this._sessions = new Map()
25
26 this._server = new ws.Server(
27 {
28 server: new http.Server(this._onrequest.bind(this)).listen(
29 { port, host },
30 this._onlistening.bind(this)
31 )
32 },
33 this._onconnection.bind(this)
34 )
35 }
36
37 get listening() {
38 return this._server.listening
39 }
40
41 address() {
42 return this._server.address()
43 }
44
45 close(cb) {
46 for (const socket of this._sessions.keys()) socket.destroy()
47
48 return this._server.close(cb)
49 }
50
51 ref() {
52 this._server.ref()
53 }
54
55 unref() {
56 this._server.unref()
57 }
58
59 _onlistening() {
60 this.emit('listening')
61 }
62
63 _onrequest(req, res) {
64 if (req.url === '/json/list') return this._onlist(req, res)
65
66 res.writeHead(404)
67 res.end()
68 }
69
70 _onconnection(socket) {
71 const sessions = this._sessions
72
73 const session = new Session()
74
75 sessions.set(socket, session)
76
77 session.on('inspectorNotification', onnotification).connect()
78
79 socket.on('close', onclose).on('data', ondata)
80
81 function onnotification(message) {
82 socket.write(JSON.stringify(message))
83 }
84
85 function onclose() {
86 session.destroy()
87 sessions.delete(socket)
88 }
89
90 function ondata(data) {
91 const { id, method, params } = JSON.parse(data)
92
93 session.post(method, params, (err, result) => {
94 const response = err ? { id, error: err } : { id, result }
95
96 socket.write(JSON.stringify(response))
97 })
98 }
99 }
100
101 _onlist(req, res) {
102 res.writeHead(200, { 'Content-Type': 'application/json' })
103
104 const { address, port } = this.address()
105
106 res.end(
107 JSON.stringify([
108 {
109 title: `bare[${Bare.pid}]`,
110 id: `${Bare.pid}`,
111 type: 'node',
112 url: this._path,
113 devtoolsFrontendUrl: `devtools://devtools/bundled/js_app.html?ws=${address}:${port}`,
114 webSocketDebuggerUrl: `ws://${address}:${port}`,
115 faviconUrl: 'https://holepunch.to/favicon.ico'
116 }
117 ])
118 )
119 }
120}
node_modules/bare-inspector/lib/session.d.ts +43 -0
……@@ -0,0 +1,43 @@
1import EventEmitter, { EventMap } from 'bare-events'
2
3interface SessionMessage {
4 method: string
5 params: Record<string, unknown>
6}
7
8interface InspectorSessionEvents extends EventMap {
9 inspectorNotification: [message: SessionMessage]
10 [method: string]: [message: SessionMessage]
11}
12
13interface InspectorSession<
14 M extends InspectorSessionEvents = InspectorSessionEvents
15> extends EventEmitter<M> {
16 readonly connected: boolean
17 readonly destroyed: boolean
18
19 connect(): void
20
21 post<T extends unknown = unknown>(
22 method: string,
23 cb: (err: Error, result: T) => void
24 ): Promise<T>
25
26 post<T extends unknown = unknown>(
27 method: string,
28 params?: Record<string, unknown>,
29 cb?: (err: Error, result: T) => void
30 ): Promise<T>
31
32 destroy(): void
33}
34
35declare class InspectorSession {
36 constructor(onpaused?: () => boolean)
37}
38
39declare namespace InspectorSession {
40 export { type SessionMessage, type InspectorSessionEvents }
41}
42
43export = InspectorSession
node_modules/bare-inspector/lib/session.js +112 -0
……@@ -0,0 +1,112 @@
1const EventEmitter = require('bare-events')
2const binding = require('../binding')
3const constants = require('./constants')
4
5module.exports = class InspectorSession extends EventEmitter {
6 constructor(onpaused) {
7 super()
8
9 this._state = 0
10
11 this._nextId = 1
12 this._requests = new Map()
13
14 this._onpaused = onpaused || defaultPaused
15
16 this._handle = binding.create(this, this._onresponse, this._onpaused)
17 }
18
19 get connected() {
20 return (
21 (this._state & constants.state.CONNECTED) !== 0 &&
22 (this._state & constants.state.DESTROYED) === 0
23 )
24 }
25
26 get destroyed() {
27 return (this._state & constants.state.DESTROYED) !== 0
28 }
29
30 connect() {
31 if (this._state & (constants.state.CONNECTED | constants.state.DESTROYED))
32 return
33
34 this._state |= constants.state.CONNECTED
35
36 binding.connect(this._handle)
37 }
38
39 post(method, params, cb) {
40 if (typeof params === 'function') {
41 cb = params
42 params = null
43 }
44
45 let result
46
47 if (typeof cb !== 'function') {
48 result = new Promise((resolve, reject) => {
49 cb = (err, result) => {
50 if (err) reject(err)
51 else resolve(result)
52 }
53 })
54 }
55
56 const id = this._nextId++
57
58 const req = {
59 id,
60 callback: cb
61 }
62
63 this._requests.set(id, req)
64
65 binding.post(
66 this._handle,
67 JSON.stringify({
68 id,
69 method,
70 params
71 })
72 )
73
74 return result
75 }
76
77 destroy() {
78 if (this._state & constants.state.DESTROYED) return
79
80 this._state |= constants.state.DESTROYED
81
82 binding.destroy(this._handle)
83 }
84
85 _onresponse(string) {
86 const message = JSON.parse(string)
87
88 if (message.method) {
89 this.emit(message.method, message)
90 this.emit('inspectorNotification', message)
91 } else {
92 const req = this._requests.get(message.id)
93
94 if (req) {
95 this._requests.delete(message.id)
96
97 let err = null
98
99 if (message.error) {
100 err = new Error(message.error.message)
101 err.code = message.error.code
102 }
103
104 req.callback(err, message.result)
105 }
106 }
107 }
108}
109
110function defaultPaused() {
111 return false
112}
node_modules/bare-inspector/package.json +76 -0
……@@ -0,0 +1,76 @@
1{
2 "name": "bare-inspector",
3 "version": "4.0.3",
4 "description": "V8 inspector support for Bare",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./console": {
11 "types": "./lib/console.d.ts",
12 "default": "./lib/console.js"
13 },
14 "./session": {
15 "types": "./lib/session.d.ts",
16 "default": "./lib/session.js"
17 },
18 "./server": {
19 "types": "./lib/server.d.ts",
20 "default": "./lib/server.js"
21 },
22 "./heap-snapshot": {
23 "types": "./lib/heap-snapshot.d.ts",
24 "default": "./lib/heap-snapshot.js"
25 },
26 "./package": "./package.json"
27 },
28 "files": [
29 "index.js",
30 "index.d.ts",
31 "binding.c",
32 "binding.js",
33 "lib",
34 "CMakeLists.txt",
35 "prebuilds"
36 ],
37 "addon": true,
38 "scripts": {
39 "test": "prettier . --check && bare test.js"
40 },
41 "repository": {
42 "type": "git",
43 "url": "git+https://github.com/holepunchto/bare-inspector.git"
44 },
45 "author": "Holepunch",
46 "license": "Apache-2.0",
47 "bugs": {
48 "url": "https://github.com/holepunchto/bare-inspector/issues"
49 },
50 "homepage": "https://github.com/holepunchto/bare-inspector#readme",
51 "engines": {
52 "bare": ">=1.2.0"
53 },
54 "dependencies": {
55 "bare-events": "^2.1.0",
56 "bare-http1": "^4.0.0",
57 "bare-stream": "^2.0.0",
58 "bare-url": "^2.0.0",
59 "bare-ws": "^2.0.0"
60 },
61 "devDependencies": {
62 "bare-tcp": "^2.0.3",
63 "brittle": "^3.3.2",
64 "cmake-bare": "^1.1.6",
65 "prettier": "^3.4.1",
66 "prettier-config-standard": "^7.0.0"
67 },
68 "peerDependencies": {
69 "bare-tcp": "*"
70 },
71 "peerDependenciesMeta": {
72 "bare-tcp": {
73 "optional": true
74 }
75 }
76}
node_modules/bare-inspector/prebuilds/android-arm/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/android-arm64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/android-ia32/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/android-x64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/darwin-arm64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/darwin-x64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/ios-arm64-simulator/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/ios-arm64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/ios-x64-simulator/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/linux-arm64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/linux-x64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/win32-arm64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-inspector/prebuilds/win32-x64/bare-inspector.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/CMakeLists.txt +37 -0
……@@ -0,0 +1,37 @@
1cmake_minimum_required(VERSION 3.25)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4find_package(cmake-napi REQUIRED PATHS node_modules/cmake-napi)
5find_package(cmake-npm REQUIRED PATHS node_modules/cmake-npm)
6
7project(bare_module_lexer C)
8
9add_bare_module(bare_module_lexer)
10
11target_sources(
12 ${bare_module_lexer}
13 PRIVATE
14 binding.c
15)
16
17add_napi_module(bare_module_lexer_napi)
18
19target_sources(
20 ${bare_module_lexer_napi}
21 PRIVATE
22 binding.c
23)
24
25target_compile_definitions(
26 ${bare_module_lexer_napi}
27 PRIVATE
28 NAPI_VERSION=9
29)
30
31resolve_node_module(bare-compat-napi compat)
32
33target_include_directories(
34 ${bare_module_lexer_napi}
35 PRIVATE
36 "${compat}/include"
37)
node_modules/bare-module-lexer/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-module-lexer/README.md +73 -0
……@@ -0,0 +1,73 @@
1# bare-module-lexer
2
3Heuristic lexer for detecting imports and exports in JavaScript modules. It trades off correctness for performance, aiming to reliably support the most common import and export patterns with as little overhead as possible.
4
5## Usage
6
7```js
8const lex = require('bare-module-lexer')
9
10lex(`
11 const foo = require('./foo.js')
12 exports.bar = 42
13`)
14
15// {
16// imports: [
17// { specifier: './foo.js', type: REQUIRE, names: [], position: [ 15, 24, 32 ] }
18// ],
19// exports: [
20// { name: 'bar', position: [ 37, 45, 48 ] }
21// ]
22// }
23```
24
25## API
26
27#### `const { imports, exports } = lex(source[, encoding][, options])`
28
29`imports` is an array of objects with the following shape:
30
31```js
32imports = {
33 specifier: 'string',
34 type: number,
35 names: ['string'],
36 position: [
37 number, // Import start
38 number, // Specifier start
39 number // Specifier end
40 ]
41}
42```
43
44`exports` is an array of objects with the following shape:
45
46```js
47exports = {
48 name: 'string',
49 position: [
50 number, // Export start
51 number, // Name start
52 number // Name end
53 ]
54}
55```
56
57Options are reserved.
58
59#### `lex.constants`
60
61| Constant | Description |
62| :--------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
63| `REQUIRE` | CommonJS `require()`. |
64| `IMPORT` | ES module `import`. |
65| `DYNAMIC` | ES module `import()` if `IMPORT` is set. |
66| `ADDON` | CommonJS `require.addon()` if `REQUIRE` is set, or ES module `import.meta.addon()` if `IMPORT` is set. |
67| `ASSET` | CommonJS `require.asset()` if `REQUIRE` is set, or ES module `import.meta.asset()` if `IMPORT` is set. |
68| `RESOLVE` | CommonJS `require.resolve()` or `require.addon.resolve()` if `REQUIRE` and optionally `ADDON` are set, or ES module `import.meta.resolve()` or `import.meta.addon.resolve()` if `IMPORT` and optionally `ADDON` are set. |
69| `REEXPORT` | Re-export of a CommonJS `require()` if `REQUIRE` is set, or ES module `export from` if `IMPORT` is set. |
70
71## License
72
73Apache-2.0
node_modules/bare-module-lexer/binding.c +86 -0
……@@ -0,0 +1,86 @@
1#include <assert.h>
2#include <bare.h>
3#include <js.h>
4#include <uv.h>
5
6#include "lib/lex.h"
7
8static js_value_t *
9bare_module_lexer_lex(js_env_t *env, js_callback_info_t *info) {
10 int err;
11
12 size_t argc = 1;
13 js_value_t *argv[1];
14
15 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
16 assert(err == 0);
17
18 assert(argc == 1);
19
20 utf8_t *input;
21 size_t len;
22 err = js_get_typedarray_info(env, argv[0], NULL, (void **) &input, (size_t *) &len, NULL, NULL);
23 assert(err == 0);
24
25 js_value_t *imports;
26 err = js_create_array(env, &imports);
27 assert(err == 0);
28
29 js_value_t *exports;
30 err = js_create_array(env, &exports);
31 assert(err == 0);
32
33 err = bare_module_lexer__lex(env, imports, exports, input, len);
34 if (err < 0) return NULL;
35
36 js_value_t *result;
37 err = js_create_object(env, &result);
38 assert(err == 0);
39
40 err = js_set_named_property(env, result, "imports", imports);
41 assert(err == 0);
42
43 err = js_set_named_property(env, result, "exports", exports);
44 assert(err == 0);
45
46 return result;
47}
48
49static js_value_t *
50bare_module_lexer_exports(js_env_t *env, js_value_t *exports) {
51 int err;
52
53#define V(name, fn) \
54 { \
55 js_value_t *val; \
56 err = js_create_function(env, name, -1, fn, NULL, &val); \
57 assert(err == 0); \
58 err = js_set_named_property(env, exports, name, val); \
59 assert(err == 0); \
60 }
61
62 V("lex", bare_module_lexer_lex)
63#undef V
64
65#define V(name, n) \
66 { \
67 js_value_t *val; \
68 err = js_create_uint32(env, n, &val); \
69 assert(err == 0); \
70 err = js_set_named_property(env, exports, name, val); \
71 assert(err == 0); \
72 }
73
74 V("REQUIRE", bare_module_lexer_require)
75 V("IMPORT", bare_module_lexer_import)
76 V("DYNAMIC", bare_module_lexer_dynamic)
77 V("ADDON", bare_module_lexer_addon)
78 V("ASSET", bare_module_lexer_asset)
79 V("RESOLVE", bare_module_lexer_resolve)
80 V("REEXPORT", bare_module_lexer_reexport)
81#undef V
82
83 return exports;
84}
85
86BARE_MODULE(bare_module_lexer, bare_module_lexer_exports)
node_modules/bare-module-lexer/index.d.ts +38 -0
……@@ -0,0 +1,38 @@
1import Buffer, { BufferEncoding } from 'bare-buffer'
2
3interface Import {
4 specifier: string
5 type: number
6 names: string[]
7 attributes: { [attribute: string]: string }
8 position: [importStart: number, specifierStart: number, specifierEnd: number]
9}
10
11interface Export {
12 name: string
13 position: [exportStart: number, nameStart: number, nameEnd: number]
14}
15
16declare function lex(
17 input: string | Buffer,
18 encoding?: BufferEncoding
19): {
20 imports: Import[]
21 exports: Export[]
22}
23
24declare namespace lex {
25 export { type Import, type Export }
26
27 export const constants: {
28 REQUIRE: number
29 IMPORT: number
30 DYNAMIC: number
31 ADDON: number
32 ASSET: number
33 RESOLVE: number
34 REEXPORT: number
35 }
36}
37
38export = lex
node_modules/bare-module-lexer/index.js +56 -0
……@@ -0,0 +1,56 @@
1const binding = require('#binding')
2
3module.exports = exports = function lex(input, encoding, opts = {}) {
4 if (typeof encoding === 'object' && encoding !== null) {
5 opts = encoding
6 encoding = null
7 }
8
9 if (typeof input !== 'string' && !ArrayBuffer.isView(input)) {
10 throw new TypeError(
11 `Input must be a string or buffer. Received type ${typeof input}`
12 )
13 }
14
15 return binding.lex(
16 typeof input === 'string' ? Buffer.from(input, encoding) : input
17 )
18}
19
20exports.constants = {
21 /**
22 * CommonJS `require()`.
23 */
24 REQUIRE: binding.REQUIRE,
25
26 /**
27 * ES module `import`.
28 */
29 IMPORT: binding.IMPORT,
30
31 /**
32 * ES module `import()` if `IMPORT` is set.
33 */
34 DYNAMIC: binding.DYNAMIC,
35
36 /**
37 * CommonJS `require.addon()` if `REQUIRE` is set, or ES module `import.meta.addon()` if `IMPORT` is set.
38 */
39 ADDON: binding.ADDON,
40
41 /**
42 * CommonJS `require.asset()` if `REQUIRE` is set, or ES module `import.meta.asset()` if `IMPORT` is set.
43 */
44 ASSET: binding.ASSET,
45
46 /**
47 * CommonJS `require.resolve()` or `require.addon.resolve()` if `REQUIRE` and optionally `ADDON` are set, or ES module
48 * `import.meta.resolve()` or `import.meta.addon.resolve()` if `IMPORT` and optionally `ADDON` are set.
49 */
50 RESOLVE: binding.RESOLVE,
51
52 /**
53 * Re-export of a CommonJS `require()` if `REQUIRE` is set.
54 */
55 REEXPORT: binding.REEXPORT
56}
node_modules/bare-module-lexer/lib/binding/bare.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon('../..')
node_modules/bare-module-lexer/lib/binding/node.js +3 -0
……@@ -0,0 +1,3 @@
1require.addon = require('require-addon')
2
3module.exports = require.addon('../..', __filename)
node_modules/bare-module-lexer/lib/lex.h +1124 -0
……@@ -0,0 +1,1124 @@
1#ifndef BARE_MODULE_LEXER_H
2#define BARE_MODULE_LEXER_H
3
4#include <assert.h>
5#include <js.h>
6#include <stdbool.h>
7#include <stddef.h>
8#include <string.h>
9#include <utf.h>
10
11enum {
12 bare_module_lexer_require = 0x1,
13 bare_module_lexer_import = 0x2,
14 bare_module_lexer_dynamic = 0x4,
15 bare_module_lexer_addon = 0x8,
16 bare_module_lexer_asset = 0x10,
17 bare_module_lexer_resolve = 0x20,
18 bare_module_lexer_reexport = 0x40,
19};
20
21static inline bool
22bare_module_lexer__is_line_terminator(uint8_t c) {
23 return c == 0xa || c == 0xd;
24}
25
26static inline bool
27bare_module_lexer__is_whitespace(uint8_t c) {
28 return c == ' ' || c == '\t' || c == 0xb || c == 0xc || c == 0xa0 || bare_module_lexer__is_line_terminator(c);
29}
30
31static inline bool
32bare_module_lexer__is_id_start(uint8_t c) {
33 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$';
34}
35
36static inline bool
37bare_module_lexer__is_id(uint8_t c) {
38 return bare_module_lexer__is_id_start(c) || (c >= '0' && c <= '9');
39}
40
41static inline int
42bare_module_lexer__add_position(js_env_t *env, js_value_t *entry, size_t statement_start, size_t input_start, size_t input_end) {
43 int err;
44
45 js_value_t *position;
46 err = js_create_array_with_length(env, 3, &position);
47 assert(err == 0);
48
49#define V(i, n) \
50 { \
51 js_value_t *val; \
52 err = js_create_int64(env, n, &val); \
53 assert(err == 0); \
54 err = js_set_element(env, position, i, val); \
55 assert(err == 0); \
56 }
57
58 V(0, statement_start);
59 V(1, input_start);
60 V(2, input_end);
61#undef V
62
63 err = js_set_named_property(env, entry, "position", position);
64 assert(err == 0);
65
66 return 0;
67}
68
69static inline int
70bare_module_lexer__add_import(js_env_t *env, js_value_t *imports, uint32_t *i, const utf8_t *source, size_t import_start, size_t specifier_start, size_t specifier_end, int type, js_value_t *names, js_value_t *attributes) {
71 assert(specifier_end >= specifier_start);
72
73 int err;
74
75 js_value_t *entry;
76 err = js_create_object(env, &entry);
77 assert(err == 0);
78
79 err = js_set_element(env, imports, *i, entry);
80 assert(err == 0);
81
82#define V(key, fn, ...) \
83 { \
84 js_value_t *val; \
85 err = fn(env, __VA_ARGS__, &val); \
86 assert(err == 0); \
87 err = js_set_named_property(env, entry, key, val); \
88 assert(err == 0); \
89 }
90
91 V("specifier", js_create_string_utf8, &source[specifier_start], specifier_end - specifier_start);
92 V("type", js_create_uint32, type);
93#undef V
94
95 if (names == NULL) {
96 err = js_create_array(env, &names);
97 assert(err == 0);
98 }
99
100 err = js_set_named_property(env, entry, "names", names);
101 assert(err == 0);
102
103 if (attributes == NULL) {
104 err = js_create_object(env, &attributes);
105 assert(err == 0);
106 }
107
108 err = js_set_named_property(env, entry, "attributes", attributes);
109 assert(err == 0);
110
111 err = bare_module_lexer__add_position(env, entry, import_start, specifier_start, specifier_end);
112 assert(err == 0);
113
114 *i += 1;
115
116 return 0;
117}
118
119static inline int
120bare_module_lexer__add_export(js_env_t *env, js_value_t *exports, uint32_t *i, const utf8_t *source, size_t export_start, size_t name_start, size_t name_end) {
121 assert(name_end >= name_start);
122
123 int err;
124
125 js_value_t *entry;
126 err = js_create_object(env, &entry);
127 assert(err == 0);
128
129 err = js_set_element(env, exports, *i, entry);
130 assert(err == 0);
131
132#define V(key, fn, ...) \
133 { \
134 js_value_t *val; \
135 err = fn(env, __VA_ARGS__, &val); \
136 assert(err == 0); \
137 err = js_set_named_property(env, entry, key, val); \
138 assert(err == 0); \
139 }
140
141 V("name", js_create_string_utf8, &source[name_start], name_end - name_start);
142#undef V
143
144 err = bare_module_lexer__add_position(env, entry, export_start, name_start, name_end);
145 assert(err == 0);
146
147 *i += 1;
148
149 return 0;
150}
151
152static inline int
153bare_module_lexer__add_name(js_env_t *env, js_value_t **names, uint32_t *i, const utf8_t *name, size_t name_len) {
154 int err;
155
156 if (*names == NULL) {
157 err = js_create_array(env, names);
158 assert(err == 0);
159
160 *i = 0;
161 }
162
163 js_value_t *string;
164 err = js_create_string_utf8(env, name, name_len, &string);
165 assert(err == 0);
166
167 err = js_set_element(env, *names, *i, string);
168 assert(err == 0);
169
170 *i += 1;
171
172 return 0;
173}
174
175static inline int
176bare_module_lexer__add_attribute(js_env_t *env, js_value_t **attributes, const utf8_t *key, size_t key_len, const utf8_t *value, size_t value_len) {
177 int err;
178
179 if (*attributes == NULL) {
180 err = js_create_object(env, attributes);
181 assert(err == 0);
182 }
183
184 js_value_t *property;
185 err = js_create_property_key_utf8(env, key, key_len, &property);
186 assert(err == 0);
187
188 js_value_t *string;
189 err = js_create_string_utf8(env, value, value_len, &string);
190 assert(err == 0);
191
192 err = js_set_property(env, *attributes, property, string);
193 assert(err == 0);
194
195 return 0;
196}
197
198// Current character, unchecked
199#define u(offset) ((uint8_t) s[i + offset])
200
201// Current character, checked
202#define c(offset) (i + offset < n ? u(offset) : -1)
203
204// Begins with string, unchecked
205#define bu(t, l) (strncmp((const char *) &s[i], t, l) == 0)
206
207// Begins with string, checked
208#define bc(t, l) (i + l < n && bu(t, l))
209
210#define lt bare_module_lexer__is_line_terminator
211#define ws bare_module_lexer__is_whitespace
212#define ids bare_module_lexer__is_id_start
213#define id bare_module_lexer__is_id
214
215static inline int
216bare_module_lexer__lex_regex(js_env_t *env, const utf8_t *s, size_t n, size_t i, size_t *result) {
217 i++;
218
219 bool in_character_class = false;
220
221 while (i < n) {
222 if (in_character_class) {
223 if (u(0) == ']') {
224 in_character_class = false;
225 } else if (c(0) == '\\') {
226 i++;
227 }
228 } else if (u(0) == '/') {
229 i++;
230
231 while (i < n && u(0) >= 'a' && u(0) <= 'z') i++;
232
233 *result = i;
234
235 return 0;
236 } else if (u(0) == '[') {
237 in_character_class = true;
238 } else if (u(0) == '\\') {
239 i++;
240 } else if (u(0) == ';' || lt(u(0))) {
241 return -1;
242 }
243
244 i++;
245 }
246
247 return -1;
248}
249
250static inline int
251bare_module_lexer__lex_import_attributes(js_env_t *env, js_value_t **attributes, const utf8_t *s, size_t n, size_t i, size_t *result) {
252 int err;
253
254 size_t ks; // Key start
255 size_t ke; // Key end
256
257 size_t vs; // Value start
258 size_t ve; // Value end
259
260 while (i < n && ws(u(0))) i++;
261
262 if (c(0) == '{') {
263 i++;
264
265 while (c(0) != '}') {
266 while (i < n && ws(u(0))) i++;
267
268 if (ids(c(0))) {
269 ks = i++;
270
271 while (id(c(0))) i++;
272
273 ke = i;
274 } else if (c(0) == '\'' || c(0) == '"') {
275 utf8_t e = u(0);
276
277 ks = ++i;
278
279 while (i < n && u(0) != e) i++;
280
281 if (c(0) != e) break;
282
283 ke = i++;
284 } else break;
285
286 while (i < n && ws(u(0))) i++;
287
288 if (c(0) != ':') break;
289
290 i++;
291
292 while (i < n && ws(u(0))) i++;
293
294 if (c(0) != '\'' && c(0) != '"') break;
295
296 utf8_t e = u(0);
297
298 vs = ++i;
299
300 while (i < n && u(0) != e) i++;
301
302 if (c(0) != e) break;
303
304 ve = i++;
305
306 err = bare_module_lexer__add_attribute(env, attributes, &s[ks], ke - ks, &s[vs], ve - vs);
307 if (err < 0) return err;
308
309 if (c(0) != ',') break;
310
311 i++;
312 }
313 }
314
315 *result = i;
316
317 return 0;
318}
319
320static inline int
321bare_module_lexer__lex(js_env_t *env, js_value_t *imports, js_value_t *exports, const utf8_t *s, size_t n) {
322 int err;
323
324 size_t i = 0;
325
326 size_t is; // Import start
327 uint32_t il = 0; // Import count
328
329 size_t es; // Export start
330 uint32_t el = 0; // Export count
331
332 size_t ss; // Source start
333 size_t se; // Source end
334
335 int type;
336
337 js_value_t *names;
338 uint32_t nl; // Names count
339
340 js_value_t *attributes;
341
342 while (i < n) {
343 while (i < n && ws(u(0))) i++;
344
345 if (i + 8 >= n) break;
346
347 if (bu("//", 2)) {
348 i += 2;
349
350 while (i < n && !lt(u(0))) i++;
351
352 if (lt(c(0))) i++;
353
354 continue;
355 }
356
357 if (bu("/*", 2)) {
358 i += 2;
359
360 while (i + 1 < n && !bu("*/", 2)) i++;
361
362 if (bc("*/", 2)) i += 2;
363
364 continue;
365 }
366
367 if (u(0) == '\'' || u(0) == '"' || u(0) == '`') {
368 utf8_t e = u(0);
369
370 i++;
371
372 while (i < n) {
373 if (u(0) == '\\') i += 2;
374 else if (u(0) != e) i++;
375 else break;
376 }
377
378 if (c(0) == e) i++;
379
380 continue;
381 }
382
383 if (u(0) == '/') {
384 err = bare_module_lexer__lex_regex(env, s, n, i, &i);
385 if (err < 0) i++;
386
387 continue;
388 }
389
390 type = 0;
391 names = NULL;
392 attributes = NULL;
393
394 if (bu("require", 7)) {
395 is = i;
396
397 i += 7;
398
399 goto require;
400 }
401
402 else if (bu("import", 6)) {
403 type |= bare_module_lexer_import;
404 is = i;
405
406 i += 6;
407
408 while (i < n && ws(u(0))) i++;
409
410 // import \*
411 if (c(0) == '*') {
412 i++;
413
414 while (i < n && ws(u(0))) i++;
415
416 // import \* as
417 if (i + 3 < n && bu("as", 2) && ws(u(2))) {
418 i += 3;
419
420 while (i < n && ws(u(0))) i++;
421
422 // import \* as [^\s]+
423 while (i < n && !ws(u(0))) i++;
424
425 while (i < n && ws(u(0))) i++;
426
427 // import \* as [^\s]+ from
428 if (bc("from", 4)) {
429 i += 4;
430
431 err = bare_module_lexer__add_name(env, &names, &nl, (const utf8_t *) "*", -1);
432 assert(err == 0);
433
434 goto from;
435 }
436 }
437 }
438
439 // import {
440 else if (c(0) == '{') {
441 i++;
442
443 // import {[^}]*
444 while (i < n && u(0) != '}') i++;
445
446 // import {[^}]*}
447 if (c(0) == '}') {
448 i++;
449
450 while (i < n && ws(u(0))) i++;
451
452 // import {[^}]*} from
453 if (bc("from", 4)) {
454 i += 4;
455
456 goto from;
457 }
458 }
459 }
460
461 // import ['"]
462 else if (c(0) == '\'' || c(0) == '"') {
463 utf8_t e = u(0);
464
465 ss = ++i;
466
467 while (i < n && u(0) != e) i++;
468
469 // import ['"].*['"]
470 if (c(0) == e) {
471 se = i;
472
473 i++;
474
475 err = bare_module_lexer__add_import(env, imports, &il, s, is, ss, se, type, names, attributes);
476 if (err < 0) goto err;
477 }
478 }
479
480 // import\(
481 else if (c(0) == '(') {
482 type |= bare_module_lexer_dynamic;
483
484 i++;
485
486 while (i < n && ws(u(0))) i++;
487
488 // import\(['"]
489 if (c(0) == '\'' || c(0) == '"') {
490 utf8_t e = u(0);
491
492 ss = ++i;
493
494 while (i < n && u(0) != e) i++;
495
496 // import\(['"].*['"]
497 if (c(0) == e) {
498 se = i;
499
500 i++;
501
502 while (i < n && ws(u(0))) i++;
503
504 while (i < n && u(0) != ')') i++;
505
506 // import\(['"].*['"][^)]*\)
507 if (c(0) == ')') {
508 i++;
509
510 err = bare_module_lexer__add_import(env, imports, &il, s, is, ss, se, type, names, attributes);
511 if (err < 0) goto err;
512 }
513 }
514 }
515 }
516
517 // import\.
518 else if (c(0) == '.') {
519 i++;
520
521 while (i < n && ws(u(0))) i++;
522
523 // import\.meta
524 if (bc("meta", 4)) {
525 i += 4;
526
527 while (i < n && ws(u(0))) i++;
528
529 // import\.meta\.
530 if (c(0) == '.') {
531 i++;
532
533 // import\.meta\.a
534 if (i + 5 < n && u(0) == 'a') {
535 i++;
536
537 // import\.meta\.addon
538 if (bu("ddon", 4)) {
539 i += 4;
540
541 while (i < n && ws(u(0))) i++;
542
543 type |= bare_module_lexer_addon;
544
545 // import\.meta\.addon\.
546 if (c(0) == '.') {
547 i++;
548
549 while (i < n && ws(u(0))) i++;
550
551 // import\.meta\.addon\.resolve
552 if (i + 7 < n && bu("resolve", 7)) {
553 i += 7;
554
555 while (i < n && ws(u(0))) i++;
556
557 type |= bare_module_lexer_resolve;
558 }
559
560 else continue;
561 }
562 }
563
564 // import\.meta\.asset
565 else if (bu("sset", 4)) {
566 i += 4;
567
568 while (i < n && ws(u(0))) i++;
569
570 type |= bare_module_lexer_asset;
571 }
572 }
573
574 // import\.meta\.resolve
575 else if (i + 7 < n && bu("resolve", 7)) {
576 i += 7;
577
578 while (i < n && ws(u(0))) i++;
579
580 type |= bare_module_lexer_resolve;
581 }
582
583 else continue;
584
585 // import\.meta\.(resolve|addon(\.resolve)?|asset)\(
586 if (c(0) == '(') {
587 i++;
588
589 while (i < n && ws(u(0))) i++;
590
591 // import\.meta\.(resolve|addon(\.resolve)?|asset)\(['"]
592 if (c(0) == '\'' || c(0) == '"') {
593 utf8_t e = u(0);
594
595 ss = ++i;
596
597 while (i < n && u(0) != e) i++;
598
599 // import\.meta\.(resolve|addon(\.resolve)?|asset)\(['"].*['"]
600 if (c(0) == e) {
601 se = i;
602
603 i++;
604
605 while (i < n && u(0) != ')') i++;
606
607 // import\.meta\.(resolve|addon(\.resolve)?|asset)\(['"].*['"][^)]*\)
608 if (c(0) == ')') {
609 i++;
610
611 err = bare_module_lexer__add_import(env, imports, &il, s, is, ss, se, type, names, attributes);
612 if (err < 0) goto err;
613 }
614 }
615 }
616
617 // import\.meta\.addon(\.resolve)?\(\)
618 else if (c(0) == ')' && (type & bare_module_lexer_addon)) {
619 ss = se = i++;
620
621 err = bare_module_lexer__add_import(env, imports, &il, s, is, ss, se, type, names, attributes);
622 if (err < 0) goto err;
623 }
624 }
625 }
626 }
627 }
628
629 // import\s
630 else if (ws(c(-1))) {
631 size_t j = i;
632
633 // import [^\s,]+
634 while (i < n && !ws(u(0)) && u(0) != ',') i++;
635
636 if (j < i) {
637 while (i < n && ws(u(0))) i++;
638
639 // import [^\s,]+ from
640 if (bc("from", 4)) {
641 i += 4;
642
643 err = bare_module_lexer__add_name(env, &names, &nl, (const utf8_t *) "default", -1);
644 assert(err == 0);
645
646 goto from;
647 }
648
649 // import [^\s,]+,
650 else if (c(0) == ',') {
651 i++;
652
653 while (i < n && ws(u(0))) i++;
654
655 // import [^\s,]+, {
656 if (c(0) == '{') {
657 i++;
658
659 // import [^\s,]+, {[^}]*
660 while (i < n && u(0) != '}') i++;
661
662 // import [^\s,]+, {[^}]*}
663 if (c(0) == '}') {
664 i++;
665
666 while (i < n && ws(u(0))) i++;
667
668 // import [^\s,]+, {[^}]*} from
669 if (bc("from", 4)) {
670 i += 4;
671
672 err = bare_module_lexer__add_name(env, &names, &nl, (const utf8_t *) "default", -1);
673 assert(err == 0);
674
675 goto from;
676 }
677 }
678 }
679 }
680 }
681 }
682 }
683
684 else if (bu("module", 6)) {
685 es = i;
686
687 i += 6;
688
689 while (i < n && ws(u(0))) i++;
690
691 // module\.
692 if (c(0) == '.') {
693 i++;
694
695 while (i < n && ws(u(0))) i++;
696
697 // module\.exports
698 if (bc("exports", 7)) {
699 i += 7;
700
701 goto exports;
702 }
703 }
704 }
705
706 else if (bu("export", 6)) {
707 es = i;
708
709 i += 6;
710
711 // exports
712 if (c(0) == 's') {
713 i++;
714
715 goto exports;
716 }
717
718 while (i < n && ws(u(0))) i++;
719
720 // export \*
721 if (c(0) == '*') {
722 i++;
723
724 while (i < n && ws(u(0))) i++;
725
726 // export \* as
727 if (i + 3 < n && bu("as", 2) && ws(u(2))) {
728 i += 3;
729
730 while (i < n && ws(u(0))) i++;
731
732 // export \* as [^\s]+
733 while (i < n && !ws(u(0))) i++;
734
735 while (i < n && ws(u(0))) i++;
736
737 // export \* as [^\s]+ from
738 if (bc("from", 4)) {
739 type |= bare_module_lexer_import | bare_module_lexer_reexport;
740 is = es;
741
742 i += 4;
743
744 err = bare_module_lexer__add_name(env, &names, &nl, (const utf8_t *) "*", -1);
745 assert(err == 0);
746
747 goto from;
748 }
749 }
750
751 // export \* from
752 else if (bc("from", 4)) {
753 type |= bare_module_lexer_import | bare_module_lexer_reexport;
754 is = es;
755
756 i += 4;
757
758 err = bare_module_lexer__add_name(env, &names, &nl, (const utf8_t *) "*", -1);
759 assert(err == 0);
760
761 goto from;
762 }
763 }
764
765 // export {
766 else if (c(0) == '{') {
767 i++;
768
769 // export {[^}]*
770 while (i < n && u(0) != '}') i++;
771
772 // export {[^}]*}
773 if (c(0) == '}') {
774 i++;
775
776 while (i < n && ws(u(0))) i++;
777
778 // export {[^}]*} from
779 if (bc("from", 4)) {
780 type |= bare_module_lexer_import | bare_module_lexer_reexport;
781 is = es;
782
783 i += 4;
784
785 goto from;
786 }
787 }
788 }
789 }
790
791 else if (bu("__export", 8)) {
792 es = i;
793
794 i += 8;
795
796 // __exportStar
797 if (bc("Star", 4)) i += 4;
798
799 while (i < n && ws(u(0))) i++;
800
801 // __export(Star)?\(
802 if (c(0) == '(') {
803 i++;
804
805 while (i < n && ws(u(0))) i++;
806
807 // __export(Star)?\(require
808 if (bc("require", 7)) {
809 type |= bare_module_lexer_reexport;
810 is = i;
811
812 i += 7;
813
814 goto require;
815 }
816 }
817 }
818
819 else i++;
820
821 continue;
822
823 require:
824 type |= bare_module_lexer_require;
825
826 while (i < n && ws(u(0))) i++;
827
828 // require\.
829 if (c(0) == '.') {
830 i++;
831
832 while (i < n && ws(u(0))) i++;
833
834 // require\.a
835 if (i + 5 < n && u(0) == 'a') {
836 i++;
837
838 // require\.addon
839 if (bu("ddon", 4)) {
840 i += 4;
841
842 while (i < n && ws(u(0))) i++;
843
844 type |= bare_module_lexer_addon;
845
846 // require\.addon\.
847 if (c(0) == '.') {
848 i++;
849
850 while (i < n && ws(u(0))) i++;
851
852 // require\.addon\.resolve
853 if (i + 7 < n && bu("resolve", 7)) {
854 i += 7;
855
856 while (i < n && ws(u(0))) i++;
857
858 type |= bare_module_lexer_resolve;
859 }
860
861 else continue;
862 }
863 }
864
865 // require\.asset
866 else if (bu("sset", 4)) {
867 i += 4;
868
869 while (i < n && ws(u(0))) i++;
870
871 type |= bare_module_lexer_asset;
872 }
873 }
874
875 // require\.resolve
876 else if (i + 7 < n && bu("resolve", 7)) {
877 i += 7;
878
879 while (i < n && ws(u(0))) i++;
880
881 type |= bare_module_lexer_resolve;
882 }
883
884 else continue;
885 }
886
887 // require(\.(resolve|addon(\.resolve)?|asset))?\(
888 if (c(0) == '(') {
889 i++;
890
891 while (i < n && ws(u(0))) i++;
892
893 // require(\.(resolve|addon(\.resolve)?|asset))?\(['"]
894 if (c(0) == '\'' || c(0) == '"') {
895 utf8_t e = u(0);
896
897 ss = ++i;
898
899 while (i < n && u(0) != e) i++;
900
901 // require(\.(resolve|addon(\.resolve)?|asset))?\(['"].*['"]
902 if (c(0) == e) {
903 se = i;
904
905 i++;
906
907 while (i < n && ws(u(0))) i++;
908
909 if (c(0) == ',') {
910 i++;
911
912 while (i < n && ws(u(0))) i++;
913
914 if (c(0) == '{') {
915 i++;
916
917 while (i < n && ws(u(0))) i++;
918
919 if (bc("with", 4)) {
920 i += 4;
921
922 while (i < n && ws(u(0))) i++;
923
924 if (c(0) == ':') {
925 i++;
926
927 err = bare_module_lexer__lex_import_attributes(env, &attributes, s, n, i, &i);
928 if (err < 0) goto err;
929 }
930 }
931 }
932 }
933
934 while (i < n && u(0) != ')') i++;
935
936 // require(\.(resolve|addon(\.resolve)?|asset))?\(['"].*['"][^)]*\)
937 if (c(0) == ')') {
938 i++;
939
940 err = bare_module_lexer__add_import(env, imports, &il, s, is, ss, se, type, names, attributes);
941 if (err < 0) goto err;
942 }
943 }
944 }
945
946 // require\.addon(\.resolve)?\(\)
947 else if (c(0) == ')' && (type & bare_module_lexer_addon)) {
948 ss = se = i++;
949
950 err = bare_module_lexer__add_import(env, imports, &il, s, is, ss, se, type, names, attributes);
951 if (err < 0) goto err;
952 }
953 }
954
955 continue;
956
957 exports:
958 while (i < n && ws(u(0))) i++;
959
960 // exports =
961 if (c(0) == '=') {
962 i++;
963
964 while (i < n && ws(u(0))) i++;
965
966 // exports = \{
967 if (c(0) == '{') {
968 i++;
969
970 while (c(0) != '}') {
971 while (i < n && ws(u(0))) i++;
972
973 if (ids(c(0))) {
974 ss = i++;
975
976 while (id(c(0))) i++;
977
978 se = i;
979
980 err = bare_module_lexer__add_export(env, exports, &el, s, es, ss, se);
981 if (err < 0) goto err;
982 }
983
984 while (i < n && ws(u(0))) i++;
985
986 if (c(0) != ',') break;
987
988 i++;
989 }
990
991 // exports = \{[^}]*\}
992 if (c(0) == '}') i++;
993 }
994
995 // exports = require
996 else if (bc("require", 7)) {
997 type |= bare_module_lexer_reexport;
998 is = i;
999
1000 i += 7;
1001
1002 goto require;
1003 }
1004 }
1005
1006 // exports\.
1007 else if (c(0) == '.') {
1008 i++;
1009
1010 while (i < n && ws(u(0))) i++;
1011
1012 ss = i;
1013
1014 while (i < n && !ws(u(0)) && u(0) != '=') i++;
1015
1016 se = i;
1017
1018 while (i < n && ws(u(0))) i++;
1019
1020 // exports\.[^\s=] =
1021 if (c(0) == '=') {
1022 i++;
1023
1024 err = bare_module_lexer__add_export(env, exports, &el, s, es, ss, se);
1025 if (err < 0) goto err;
1026 }
1027 }
1028
1029 // exports\[
1030 else if (c(0) == '[') {
1031 i++;
1032
1033 while (i < n && ws(u(0))) i++;
1034
1035 // exports\[['"]
1036 if (c(0) == '\'' || c(0) == '"') {
1037 utf8_t e = u(0);
1038
1039 ss = ++i;
1040
1041 while (i < n && u(0) != e) i++;
1042
1043 // exports\[['"].*['"]
1044 if (c(0) == e) {
1045 se = i;
1046
1047 i++;
1048
1049 while (i < n && ws(u(0))) i++;
1050
1051 while (i < n && u(0) != ']') i++;
1052
1053 // exports\[['"].*['"][^\]]*\]
1054 if (c(0) == ']') {
1055 i++;
1056
1057 while (i < n && ws(u(0))) i++;
1058
1059 // exports\[['"].*['"][^\]]*\] =
1060 if (c(0) == '=') {
1061 i++;
1062
1063 err = bare_module_lexer__add_export(env, exports, &el, s, es, ss, se);
1064 if (err < 0) goto err;
1065 }
1066 }
1067 }
1068 }
1069 }
1070
1071 continue;
1072
1073 from:
1074 while (i < n && ws(u(0))) i++;
1075
1076 // from ['"]
1077 if (c(0) == '\'' || c(0) == '"') {
1078 utf8_t e = u(0);
1079
1080 ss = ++i;
1081
1082 while (i < n && u(0) != e) i++;
1083
1084 // from ['"].*['"]
1085 if (c(0) == e) {
1086 se = i;
1087
1088 i++;
1089
1090 while (i < n && ws(u(0))) i++;
1091
1092 if (bc("with", 4)) {
1093 i += 4;
1094
1095 while (i < n && ws(u(0))) i++;
1096
1097 err = bare_module_lexer__lex_import_attributes(env, &attributes, s, n, i, &i);
1098 if (err < 0) goto err;
1099 }
1100
1101 err = bare_module_lexer__add_import(env, imports, &il, s, is, ss, se, type, names, attributes);
1102 if (err < 0) goto err;
1103 }
1104 }
1105
1106 continue;
1107 }
1108
1109#undef u
1110#undef c
1111#undef bu
1112#undef bc
1113#undef lt
1114#undef ws
1115#undef ids
1116#undef id
1117
1118 return 0;
1119
1120err:
1121 return -1;
1122}
1123
1124#endif // BARE_MODULE_LEXER_H
node_modules/bare-module-lexer/package.json +64 -0
……@@ -0,0 +1,64 @@
1{
2 "name": "bare-module-lexer",
3 "version": "1.4.7",
4 "description": "Heuristic lexer for detecting imports and exports in JavaScript modules",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json"
11 },
12 "imports": {
13 "#binding": {
14 "bare": "./lib/binding/bare.js",
15 "node": "./lib/binding/node.js"
16 }
17 },
18 "files": [
19 "index.js",
20 "index.d.ts",
21 "binding.c",
22 "CMakeLists.txt",
23 "lib",
24 "prebuilds"
25 ],
26 "addon": true,
27 "scripts": {
28 "test": "npm run lint && npm run test:bare && npm run test:node",
29 "test:bare": "bare test.js",
30 "test:node": "node test.js",
31 "lint": "prettier . --check"
32 },
33 "repository": {
34 "type": "git",
35 "url": "git+https://github.com/holepunchto/bare-module-lexer.git"
36 },
37 "author": "Holepunch",
38 "license": "Apache-2.0",
39 "bugs": {
40 "url": "https://github.com/holepunchto/bare-module-lexer/issues"
41 },
42 "homepage": "https://github.com/holepunchto/bare-module-lexer#readme",
43 "dependencies": {
44 "require-addon": "^1.0.2"
45 },
46 "devDependencies": {
47 "bare-buffer": "^3.0.0",
48 "bare-compat-napi": "^1.0.0",
49 "brittle": "^3.1.1",
50 "cmake-bare": "^1.1.7",
51 "cmake-napi": "^1.0.5",
52 "cmake-npm": "^1.0.2",
53 "prettier": "^3.4.1",
54 "prettier-config-standard": "^7.0.0"
55 },
56 "peerDependencies": {
57 "bare-buffer": "*"
58 },
59 "peerDependenciesMeta": {
60 "bare-buffer": {
61 "optional": true
62 }
63 }
64}
node_modules/bare-module-lexer/prebuilds/android-arm/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/android-arm/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/android-arm64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/android-arm64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/android-ia32/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/android-ia32/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/android-x64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/android-x64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/darwin-arm64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/darwin-arm64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/darwin-x64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/darwin-x64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/ios-arm64-simulator/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/ios-arm64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/ios-x64-simulator/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/linux-arm64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/linux-arm64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/linux-x64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/linux-x64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/win32-arm64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/win32-arm64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/win32-x64/bare-module-lexer.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module-lexer/prebuilds/win32-x64/bare-module-lexer.node +0 -0
(no content changes — binary or rename)
node_modules/bare-module/CMakeLists.txt +13 -0
……@@ -0,0 +1,13 @@
1cmake_minimum_required(VERSION 4.0)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4
5project(bare_module C)
6
7add_bare_module(bare_module)
8
9target_sources(
10 ${bare_module}
11 PRIVATE
12 binding.c
13)
node_modules/bare-module/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-module/README.md +647 -0
……@@ -0,0 +1,647 @@
1# bare-module
2
3Module support for JavaScript.
4
5```
6npm i bare-module
7```
8
9## Usage
10
11```js
12const Module = require('bare-module')
13```
14
15## Packages
16
17A package is a directory with a `package.json` file.
18
19### Fields
20
21#### `"name"`
22
23```json
24{
25 "name": "my-package"
26}
27```
28
29The name of the package. This is used for [addon resolution](https://github.com/holepunchto/bare-addon-resolve#algorithm), [self-referencing](#self-referencing), and importing packages by name.
30
31#### `"version"`
32
33```json
34{
35 "version": "1.2.3"
36}
37```
38
39The current version of the package. This is used for [addon resolution](https://github.com/holepunchto/bare-addon-resolve#algorithm).
40
41#### `"type"`
42
43```json
44{
45 "type": "module"
46}
47```
48
49The module format used for `.js` files. If not defined, `.js` files are interpreted as CommonJS. If set to `"module"`, `.js` files are instead interpreted as ES modules.
50
51#### `"exports"`
52
53```json
54{
55 "exports": {
56 ".": "./index.js"
57 }
58}
59```
60
61The entry points of the package. If defined, only the modules explicitly exported by the package may be imported when importing the package by name.
62
63##### Subpath exports
64
65A package may define more than one entry point by declaring several subpaths with the main export being `"."`:
66
67```json
68{
69 "exports": {
70 ".": "./index.js",
71 "./submodule": "./lib/submodule.js"
72 }
73}
74```
75
76When importing the package by name, `require('my-package')` will resolve to `<modules>/my-package/index.js` whereas `require('my-package/submodule')` will resolve to `<modules>/my-package/lib/submodule.js`.
77
78##### Conditional exports
79
80Conditional exports allow packages to provide different exports for different conditions, such as the loading method the importing module uses (e.g. `require()` vs `import`):
81
82```json
83{
84 "exports": {
85 ".": {
86 "import": "./index.mjs",
87 "require": "./index.cjs"
88 }
89 }
90}
91```
92
93When importing the package by name, `require('my-package')` will resolve to `<modules>/my-package/index.cjs` whereas `import 'my-package'` will resolve to `<modules>/my-package/index.mjs`.
94
95Similarly, conditional exports can be used to provide different entry points for different runtimes:
96
97```json
98{
99 "exports": {
100 ".": {
101 "bare": "./bare.js",
102 "node": "./node.js"
103 }
104 }
105}
106```
107
108To provide a fallback for when no other conditions match, the `"default"` condition can be declared:
109
110```json
111{
112 "exports": {
113 ".": {
114 "bare": "./bare.js",
115 "node": "./node.js",
116 "default": "./fallback.js"
117 }
118 }
119}
120```
121
122The following conditions are supported, listed in order from most specific to least specific as conditions should be defined:
123
124| Condition | Description |
125| :------------- | :---------------------------------------------------------------------------------------------------------------------------------- |
126| `"import"` | Matches when the package is loaded via `import` or `import()`. |
127| `"require"` | Matches when the package is loaded via `require()`. |
128| `"asset"` | Matches when the package is loaded via `require.asset()`. |
129| `"addon"` | Matches when the package is loaded via `require.addon()`. |
130| `"bare"` | Matches for any [Bare](https://github.com/holepunchto/bare) environment. |
131| `"node"` | Matches for any Node.js environment. |
132| `"<platform>"` | Matches when equal to `Bare.platform`. See [`Bare.platform`](https://github.com/holepunchto/bare#bareplatform) for possible values. |
133| `"<arch>"` | Matches when equal to `Bare.arch`. See [`Bare.arch`](https://github.com/holepunchto/bare#barearch) for possible values. |
134| `"simulator"` | Matches when Bare was compiled for a simulator. |
135| `"default"` | The fallback that always matches. This condition should always be last. |
136
137Export conditions are evaluated in the order they are defined in the `"exports"` field. This means that less specific conditionals defined first will override more specific conditions define later. For example, the following will always call `./fallback.js` because `"default"` always matches and is defined first.
138
139```json
140{
141 "exports": {
142 ".": {
143 "default": "./fallback.js",
144 "bare": "./bare.js"
145 }
146 }
147}
148```
149
150This is why the general rule is that conditions should be from most specific to least specific when defined.
151
152##### Self-referencing
153
154Within a package, exports defined in the `"exports"` field can be referenced by importing the package by name. For example, given the following `package.json`...
155
156```json
157{
158 "name": "my-package",
159 "exports": {
160 ".": "./index.js",
161 "./submodule": "./lib/submodule.js"
162 }
163}
164```
165
166...any module within `my-package` may reference these entry points using either `require('my-package')` or `require('my-package/submodule')`.
167
168##### Exports sugar
169
170If a package defines only a single export, `"."`, it may leave out the subpath entirely:
171
172```json
173{
174 "exports": "./index.js"
175}
176```
177
178#### `"imports"`
179
180A private mapping for import specifiers within the package itself. Similar to `"exports"`, the `"imports"` field can be used to conditional import other packages within the package. But unlike `"exports"`, `"imports"` permits mapping to external packages.
181
182The rules are otherwise analogous to the [`"exports"`](#conditional-exports) field.
183
184##### Subpath imports
185
186Just like exports, subpaths can be used when importing a module internally.
187
188```json
189{
190 "imports": {
191 ".": "./index.js",
192 "./submodule": "./lib/submodule.js"
193 }
194}
195```
196
197##### Conditional imports
198
199Adding conditional imports allows importing different packages based on the configured conditions. As an example:
200
201```json
202{
203 "imports": {
204 "bar": {
205 "require": "./baz.cjs",
206 "import": "./baz.mjs"
207 }
208 }
209}
210```
211
212When importing the package `bar` as `require('bar')` will resolve to `./baz.cjs`, but when importing with `import('bar')` will resolve to `./baz.mjs`.
213
214To provide a fallback for when no other conditions are met, the `"default"` condition can be configured like so:
215
216```json
217{
218 "imports": {
219 "bar": {
220 "require": "./baz.cjs",
221 "asset": "./baz.txt",
222 "default": "./baz.mjs"
223 }
224 }
225}
226```
227
228The following conditions are supported, listed in order from most specific to least specific as conditions should be defined:
229
230| Condition | Description |
231| :------------- | :---------------------------------------------------------------------------------------------------------------------------------- |
232| `"import"` | Matches when the package is loaded via `import` or `import()`. |
233| `"require"` | Matches when the package is loaded via `require()`. |
234| `"asset"` | Matches when the package is loaded via `require.asset()`. |
235| `"addon"` | Matches when the package is loaded via `require.addon()`. |
236| `"bare"` | Matches for any [Bare](https://github.com/holepunchto/bare) environment. |
237| `"node"` | Matches for any Node.js environment. |
238| `"<platform>"` | Matches when equal to `Bare.platform`. See [`Bare.platform`](https://github.com/holepunchto/bare#bareplatform) for possible values. |
239| `"<arch>"` | Matches when equal to `Bare.arch`. See [`Bare.arch`](https://github.com/holepunchto/bare#barearch) for possible values. |
240| `"simulator"` | Matches when Bare was compiled for a simulator. |
241| `"default"` | The fallback that always matches. This condition should always be last. |
242
243The general rule is that conditions should be from most specific to least specific when defined.
244
245##### `#` Prefix
246
247All import maps are private to the package and allow mapping to external packages. Entries in `"imports"` may start with `#` to disambiguate from external packages, but it is not required unlike in Node.js.
248
249#### `"engines"`
250
251```json
252{
253 "engines": {
254 "bare": ">=1.0.5"
255 }
256}
257```
258
259The `"engines"` field defines the engine requirements of the package. During module resolution, the versions declared by `Bare.versions` will be tested against the requirements declared by the package and resolution fail if they're not satisfied.
260
261## API
262
263#### `Module.constants.states`
264
265The flags for the current state of a module.
266
267| Constant | Description |
268| :------------ | :------------------------------------------- |
269| `EVALUATED` | The module has been evaluated. |
270| `SYNTHESIZED` | The module named exports have been detected. |
271
272#### `Module.constants.types`
273
274| Constant | Description |
275| :------- | :--------------------------------------------------------------------------- |
276| `SCRIPT` | The module is a CommonJS module. |
277| `MODULE` | The module is a ECMAScript module. |
278| `JSON` | The module is a JSON file. |
279| `BUNDLE` | The module is a [`bare-bundle`](https://github.com/holepunchto/bare-bundle). |
280| `ADDON` | The module is a native addon. |
281| `BINARY` | The module is a binary file. |
282| `TEXT` | The module is a text file. |
283
284#### `Module.protocol`
285
286The default `ModuleProtocol` class for resolving, reading and loading modules. See [Protocols](#protocols) for usage.
287
288#### `Module.cache`
289
290The global cache of loaded modules.
291
292> [!WARNING]
293> The cache may contain `Module` instances from several independent versions of `bare-module` as the cache is inherited through the module graph.
294
295#### `const url = Module.resolve(specifier, parentURL[, options])`
296
297Resolve the module `specifier` relative to the `parentURL`. `specifier` is a string and `parentURL` is a WHATWG `URL`.
298
299Options include:
300
301```js
302options = {
303 // Whether the module is called via `import` or `import()`.
304 isImport: false,
305 // The referring module.
306 referrer: null,
307 // The type of the module. See Module.constants.types for possible values. The
308 // default is the equivalent constant of the `attributes`'s `type` property.
309 type,
310 // A list of file extensions to look for. The default is based on the `type`
311 // option.
312 extensions: [],
313 // The ModuleProtocol to resolve the specifier. Defaults to referrer's
314 // protocol if defined, otherwise defaults to Module.protocol
315 protocol,
316 // A default "imports" map to apply to all specifiers. Follows the same
317 // syntax and rules as the "imports" property defined in `package.json`.
318 imports,
319 // A map of preresolved imports with keys being serialized parent URLs and
320 // values being "imports" maps.
321 resolutions,
322 // A map of builtin module specifiers to loaded modules. If matched by the
323 // default resolver, the protocol of the resolved URL will be `builtin:`.
324 builtins,
325 // The supported import conditions. "default" is always recognized.
326 conditions: [],
327 // The import attributes, e.g. the `{ type: "json" }` in:
328 // `import foo from 'foo' with { type: "json" }`
329 // or in:
330 // `require('foo', { with: { type: "json" } })`
331 attributes
332}
333```
334
335#### `const url = Module.asset(specifier, parentURL[, options])`
336
337Get the asset URL by resolving `specifier` relative to `parentURL`. `specifier` is a string and `parentURL` is a WHATWG `URL`.
338
339Options include:
340
341```js
342options = {
343 // The referring module.
344 referrer: null,
345 // The ModuleProtocol to use resolve the specifier. Defaults to referrer's
346 // protocol if defined, otherwise defaults to Module.protocol
347 protocol,
348 // A default "imports" map to apply to all specifiers. Follows the same
349 // syntax and rules as the "imports" property defined in `package.json`.
350 imports,
351 // A map of preresolved imports with keys being serialized parent URLs and
352 // values being "imports" maps.
353 resolutions,
354 // The supported import conditions. "default" is always recognized.
355 conditions
356}
357```
358
359#### `const module = Module.load(url[, source][, options])`
360
361Load a module with the provided `url`. `url` is a WHATWG `URL`. If provided, the `source` will be passed to the matching `extension` for the `url`.
362
363Options include:
364
365```js
366options = {
367 // Whether the module is called via `import` or `import()`.
368 isImport: false,
369 // Whether the module is called via `import()`.
370 isDynamicImport: false,
371 // The referring module.
372 referrer: null,
373 // The type of the module. See Module.constants.types for possible values. The
374 // default is the equivalent constant of the `attributes`'s `type` property.
375 type,
376 // The assumed type of a module without a type using an ambiguous extension
377 // such as `.js`. See Module.constants.types. Inherited from `referrer` if it
378 // is defined.
379 defaultType: Module.constants.types.SCRIPT,
380 // Cache to use to load the Module. Defaults to `Module.cache`.
381 cache,
382 // The module representing the entry script where the program was launched.
383 main,
384 // The ModuleProtocol to use resolve the specifier. Defaults to referrer's
385 // `protocol` if defined, otherwise defaults to `Module.protocol`.
386 protocol,
387 // A default "imports" map to apply to all specifiers. Follows the same
388 // syntax and rules as the "imports" property defined in `package.json`.
389 imports,
390 // A map of preresolved imports with keys being serialized parent URLs and
391 // values being "imports" maps.
392 resolutions,
393 // A map of builtin module specifiers to loaded modules. If the `url`'s
394 // protocol is `builtin:`, the module's exports will be set to the matching
395 // value in the map for `url.pathname`.
396 builtins,
397 // The supported import conditions. "default" is always recognized.
398 conditions,
399 // The import attributes, e.g. the `{ type: "json" }` in:
400 // `import foo from 'foo' with { type: "json" }`
401 // or in:
402 // `require('foo', { with: { type: "json" } })`
403 attributes
404}
405```
406
407#### `module.url`
408
409The WHATWG `URL` identifier of the module.
410
411#### `module.filename`
412
413The file portion of `module.url`.
414
415#### `module.dirname`
416
417The directory portion of `module.url`.
418
419#### `module.type`
420
421The type of the module. See [`Module.constants.types`](#module.constants.types) for possible values.
422
423#### `module.defaultType`
424
425The assumed type of a module without a `type` using an ambiguous extension, such as `.js`. See [`Module.constants.types`](#module.constants.types) for possible values.
426
427#### `module.cache`
428
429A cache of loaded modules for this module. Defaults to `Module.cache`.
430
431#### `module.main`
432
433The module representing the entry script where the program was launched.
434
435#### `module.exports`
436
437The exports from the module.
438
439#### `module.imports`
440
441The import map when the module was loaded.
442
443#### `module.resolutions`
444
445A map of preresolved imports with keys being serialized parent URLs and values being `"imports"` maps.
446
447#### `module.builtins`
448
449A map of builtin module specifiers mapped to the loaded module.
450
451#### `module.conditions`
452
453An array of conditions used to resolve dependencies while loading the module. See [Conditional Exports](#conditional-exports) for possible values.
454
455#### `module.protocol`
456
457The `ModuleProtocol` class used for resolving, reading, and loading modules. See [Protocols](#protocols).
458
459### CommonJS modules
460
461#### `require(specifier[, options])`
462
463Used to import JavaScript or JSON modules and local files. Relative paths such as `./`, `./foo`, `./bar/baz`, and `../foo` will be resolved against the directory named by `__dirname`. POSIX style paths are resolved in an OS independent fashion, meaning that the examples above will work on Windows in the same way they would on POSIX systems.
464
465Returns the exported module contents.
466
467Options include:
468
469```js
470options = {
471 // The import attributes which instruct how the file or module should be loaded.
472 // Possible values for `type` are `script`, `module`, `json`, `bundle`,
473 // `addon`, `binary` and `text`.
474 with: { type: 'json' }
475}
476```
477
478#### `require.main`
479
480The module representing the entry script where the program was launched. The same value as [`module.main`](#modulemain) for the current module.
481
482#### `require.cache`
483
484A cache of loaded modules for this module. The same value as `module.cache` for the current module.
485
486#### `const path = require.resolve(specifier[, parentURL])`
487
488Use the internal machinery of `require()` to resolve the `specifier` string relative to the URL `parentURL` and return the path string.
489
490#### `require.addon([specifier][, parentURL])`
491
492Also used to import modules but specifically loads only addon modules. `specifier` is resolved relative to `parentURL` using the [addon resolution](https://github.com/holepunchto/bare-addon-resolve#algorithm) algorithm.
493
494Returns the exported module contents.
495
496A common pattern for writing an addon module is to use `require.addon()` as the JavaScript module exports:
497
498```js
499module.exports = require.addon()
500```
501
502See [`bare-addon`](https://github.com/holepunchto/bare-addon) for a template of building native addon modules.
503
504#### `require.addon.host`
505
506Returns the string representation of the platform and architecture used when resolving addons with the pattern `<platform>-<arch>[-<environment>]`. Returns the same value as `Bare.Addon.host`.
507
508#### `const path = require.addon.resolve([specifier][, parentURL])`
509
510Resolve the `specifier` string relative to the URL `parentURL` as an addon and returns the path string. The `specifier` is resolved using the [addon resolution algorithm](https://github.com/holepunchto/bare-addon-resolve#algorithm).
511
512#### `const path = require.asset(specifier[, parentURL])`
513
514Resolve the `specifier` relative to the `parentURL` and return the path of the asset as a string.
515
516Can be used to load assets, for example the following loads `./foo.txt` from the local files:
517
518```js
519const fs = require('bare-fs')
520const contents = fs.readFileSync(require.asset('./foo.txt'))
521```
522
523### ECMAScript modules
524
525#### `import defaultExport, * as name, { export1, export2 as alias2, ... } from 'specifier' with { type: 'json' }`
526
527The static `import` declaration is used to import read-only live bindings that are exported by another module. The imported bindings are called _live_ bindings because they are updated by the module that exported the binding, but cannot be re-assigned by the importing module. In brief, you can import what is exported from another module.
528
529For more information on `import` syntax, see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import).
530
531#### `import.meta.url`
532
533The string representation of the URL for the current module.
534
535#### `import.meta.main`
536
537A boolean representing whether the current module is the entry script where the program was launched.
538
539#### `import.meta.cache`
540
541A cache of loaded modules for this module. The same value as `module.cache` for the current module.
542
543#### `const href = import.meta.resolve(specifier[, parentURL])`
544
545A module-relative resolution function which returns the URL string for the module. The `specifier` is a string which is resolved relative to the `parentURL` which is a WHATWG URL.
546
547#### `import.meta.addon([specifier][, parentURL])`
548
549Also used to import modules but specifically loads only addon modules. `specifier` is resolved relative to `parentURL` using the [addon resolution](https://github.com/holepunchto/bare-addon-resolve#algorithm) algorithm.
550
551Returns the exported module contents.
552
553#### `import.meta.addon.host`
554
555Returns the string representation of the platform and architecture used when resolving addons with the pattern `<platform>-<arch>[-<environment>]`. Returns the same value as `Bare.Addon.host`.
556
557#### `const href = import.meta.addon.resolve([specifier][, parentURL])`
558
559Resolve the `specifier` string relative to the URL `parentURL` as an addon and returns the URL string. The `specifier` is resolved using the [addon resolution algorithm](https://github.com/holepunchto/bare-addon-resolve#algorithm).
560
561#### `const href = import.meta.asset(specifier[, parentURL])`
562
563Resolve the `specifier` relative to the `parentURL` and return the URL of the asset as a string.
564
565### Custom `require()`
566
567Creating a custom require allows one to create a preconfigured `require()`. This can be useful in scenarios such as a Read-Evaluate-Print-Loop (REPL) where the parent URL is set to a directory so requiring relative paths to work correctly.
568
569#### `const require = Module.createRequire(parentURL[, options])`
570
571Options include:
572
573```js
574options = {
575 // The module to become the `referrer` for the returned `require()`. Defaults
576 // to creating a new module instance from the `parentURL` with the same
577 // options.
578 module: null,
579 // The referring module.
580 referrer: null,
581 // The type of the module. See Module.constants.types for possible values.
582 type: Module.constants.types.SCRIPT,
583 // The assumed type of a module without a type using an ambiguous extension
584 // such as `.js`. See Module.constants.types. Inherited from `referrer` if it
585 // is defined, otherwise defaults to SCRIPT.
586 defaultType: Module.constants.types.SCRIPT,
587 // A cache of loaded modules. Inherited from `referrer` if it is defined,
588 // otherwise defaults to `Module.cache`
589 cache,
590 // The module representing the entry script where the program was launched.
591 main,
592 // The ModuleProtocol to use resolve the specifier and/or the module. Defaults to
593 // referrer's protocol if defined, otherwise defaults to Module.protocol
594 protocol,
595 // A default "imports" map to apply to all specifiers. Follows the same
596 // syntax and rules as the "imports" property defined in `package.json`.
597 imports,
598 // A map of preresolved imports with keys being serialized parent URLs and
599 // values being "imports" maps.
600 resolutions,
601 // A map of builtin module specifiers to loaded modules.
602 builtins,
603 // The supported import conditions. "default" is always recognized.
604 conditions
605}
606```
607
608### Protocols
609
610Protocols define how to resolve, access and load modules. Custom protocols can be defined to extend or replace how module are resolved and loaded to support things like loading modules via a [`Hyperdrive`](https://github.com/holepunchto/hyperdrive).
611
612#### `const protocol = new Module.Protocol(methods, context = null)`
613
614Methods include:
615
616```js
617methods = {
618 // function (specifier, parentURL): string
619 // A function to preprocess the `specifier` and `parentURL` before the resolve
620 // algorithm is called.
621 preresolve,
622 // function (url): string
623 // A function to process the resolved URL. Can be used to convert file paths,
624 // etc.
625 postresolve,
626 // function* (specifier, parentURL, imports): [URL]
627 // A generator to resolve the `specifier` to a URL.
628 resolve,
629 // function (url): boolean
630 // A function that returns whether the URL exists as a boolean.
631 exists,
632 // function (url): string | Buffer
633 // A function that returns the source code of a URL represented as a string or
634 // buffer.
635 read,
636 // function (url): URL
637 // A function used to post process URLs for addons before `postresolve()`.
638 addon,
639 // function (url): URL
640 // A function used to post process URLs for assets before `postresolve()`.
641 asset
642}
643```
644
645## License
646
647Apache-2.0
node_modules/bare-module/binding.c +712 -0
……@@ -0,0 +1,712 @@
1#include <assert.h>
2#include <bare.h>
3#include <js.h>
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <utf.h>
9#include <uv.h>
10
11typedef struct {
12 js_env_t *env;
13 js_ref_t *ctx;
14 js_ref_t *on_import;
15 js_ref_t *on_evaluate;
16 js_ref_t *on_meta;
17} bare_module_context_t;
18
19static js_module_t *
20bare_module__on_static_import(js_env_t *env, js_value_t *specifier, js_value_t *assertions, js_module_t *referrer, void *data) {
21 bare_module_context_t *context = (bare_module_context_t *) data;
22
23 int err;
24
25 js_handle_scope_t *scope;
26 err = js_open_handle_scope(env, &scope);
27 assert(err == 0);
28
29 js_value_t *ctx;
30 err = js_get_reference_value(env, context->ctx, &ctx);
31 assert(err == 0);
32
33 js_value_t *on_import;
34 err = js_get_reference_value(env, context->on_import, &on_import);
35 assert(err == 0);
36
37 const char *name;
38 err = js_get_module_name(env, referrer, &name);
39 assert(err == 0);
40
41 js_value_t *args[4] = {specifier, assertions};
42
43 err = js_create_string_utf8(env, (utf8_t *) name, -1, &args[2]);
44 if (err < 0) goto err;
45
46 err = js_get_boolean(env, false, &args[3]);
47 assert(err == 0);
48
49 js_value_t *result;
50 err = js_call_function(env, ctx, on_import, 4, args, &result);
51 if (err < 0) goto err;
52
53 js_module_t *module;
54 err = js_get_value_external(env, result, (void **) &module);
55 if (err < 0) goto err;
56
57 err = js_close_handle_scope(env, scope);
58 assert(err == 0);
59
60 return module;
61
62err:
63 err = js_close_handle_scope(env, scope);
64 assert(err == 0);
65
66 return NULL;
67}
68
69static js_value_t *
70bare_module__on_dynamic_import(js_env_t *env, js_value_t *specifier, js_value_t *assertions, js_value_t *referrer, void *data) {
71 bare_module_context_t *context = (bare_module_context_t *) data;
72
73 int err;
74
75 js_escapable_handle_scope_t *scope;
76 err = js_open_escapable_handle_scope(env, &scope);
77 assert(err == 0);
78
79 js_value_t *ctx;
80 err = js_get_reference_value(env, context->ctx, &ctx);
81 assert(err == 0);
82
83 js_value_t *on_import;
84 err = js_get_reference_value(env, context->on_import, &on_import);
85 assert(err == 0);
86
87 js_value_t *args[4] = {specifier, assertions, referrer};
88
89 err = js_get_boolean(env, true, &args[3]);
90 assert(err == 0);
91
92 js_value_t *result;
93 err = js_call_function(env, ctx, on_import, 4, args, &result);
94 if (err < 0) goto err;
95
96 err = js_escape_handle(env, scope, result, &result);
97 assert(err == 0);
98
99 err = js_close_escapable_handle_scope(env, scope);
100 assert(err == 0);
101
102 return result;
103
104err:
105 err = js_close_escapable_handle_scope(env, scope);
106 assert(err == 0);
107
108 return NULL;
109}
110
111static void
112bare_module__on_evaluate(js_env_t *env, js_module_t *module, void *data) {
113 bare_module_context_t *context = (bare_module_context_t *) data;
114
115 int err;
116
117 js_handle_scope_t *scope;
118 err = js_open_handle_scope(env, &scope);
119 assert(err == 0);
120
121 js_value_t *ctx;
122 err = js_get_reference_value(env, context->ctx, &ctx);
123 assert(err == 0);
124
125 js_value_t *on_evaluate;
126 err = js_get_reference_value(env, context->on_evaluate, &on_evaluate);
127 assert(err == 0);
128
129 const char *name;
130 err = js_get_module_name(env, module, &name);
131 assert(err == 0);
132
133 js_value_t *args[1];
134
135 err = js_create_string_utf8(env, (utf8_t *) name, -1, &args[0]);
136 if (err < 0) goto err;
137
138 js_value_t *result;
139 err = js_call_function(env, ctx, on_evaluate, 1, args, &result);
140 if (err < 0) goto err;
141
142 err = js_close_handle_scope(env, scope);
143 assert(err == 0);
144
145 return;
146
147err:
148 err = js_close_handle_scope(env, scope);
149 assert(err == 0);
150}
151
152static void
153bare_module__on_meta(js_env_t *env, js_module_t *module, js_value_t *meta, void *data) {
154 bare_module_context_t *context = (bare_module_context_t *) data;
155
156 int err;
157
158 js_handle_scope_t *scope;
159 err = js_open_handle_scope(env, &scope);
160 assert(err == 0);
161
162 js_value_t *ctx;
163 err = js_get_reference_value(env, context->ctx, &ctx);
164 assert(err == 0);
165
166 js_value_t *on_meta;
167 err = js_get_reference_value(env, context->on_meta, &on_meta);
168 assert(err == 0);
169
170 const char *name;
171 err = js_get_module_name(env, module, &name);
172 assert(err == 0);
173
174 js_value_t *args[2];
175
176 err = js_create_string_utf8(env, (utf8_t *) name, -1, &args[0]);
177 if (err < 0) goto err;
178
179 args[1] = meta;
180
181 js_value_t *result;
182 err = js_call_function(env, ctx, on_meta, 2, args, &result);
183 if (err < 0) goto err;
184
185 err = js_close_handle_scope(env, scope);
186 assert(err == 0);
187
188 return;
189
190err:
191 err = js_close_handle_scope(env, scope);
192 assert(err == 0);
193}
194
195static void
196bare_module__on_teardown(void *data) {
197 int err;
198
199 bare_module_context_t *context = data;
200
201 js_env_t *env = context->env;
202
203 err = js_delete_reference(env, context->on_import);
204 assert(err == 0);
205
206 err = js_delete_reference(env, context->on_evaluate);
207 assert(err == 0);
208
209 err = js_delete_reference(env, context->on_meta);
210 assert(err == 0);
211
212 err = js_delete_reference(env, context->ctx);
213 assert(err == 0);
214}
215
216static js_value_t *
217bare_module_init(js_env_t *env, js_callback_info_t *info) {
218 int err;
219
220 size_t argc = 4;
221 js_value_t *argv[4];
222
223 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
224 assert(err == 0);
225
226 assert(argc == 4);
227
228 bare_module_context_t *context;
229
230 js_value_t *result;
231 err = js_create_unsafe_arraybuffer(env, sizeof(bare_module_context_t), (void **) &context, &result);
232 assert(err == 0);
233
234 context->env = env;
235
236 err = js_create_reference(env, argv[0], 1, &context->ctx);
237 assert(err == 0);
238
239 err = js_create_reference(env, argv[1], 1, &context->on_import);
240 assert(err == 0);
241
242 err = js_create_reference(env, argv[2], 1, &context->on_evaluate);
243 assert(err == 0);
244
245 err = js_create_reference(env, argv[3], 1, &context->on_meta);
246 assert(err == 0);
247
248 err = js_add_teardown_callback(env, bare_module__on_teardown, context);
249 assert(err == 0);
250
251 err = js_on_dynamic_import(env, NULL, NULL);
252 assert(err == 0);
253
254 err = js_on_dynamic_import_transitional(env, bare_module__on_dynamic_import, (void *) context);
255 assert(err == 0);
256
257 return result;
258}
259
260static js_value_t *
261bare_module_create_function(js_env_t *env, js_callback_info_t *info) {
262 int err;
263
264 size_t argc = 4;
265 js_value_t *argv[4];
266
267 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
268 assert(err == 0);
269
270 assert(argc == 4);
271
272 size_t file_len;
273 utf8_t file[1024];
274 err = js_get_value_string_utf8(env, argv[0], file, 1024, &file_len);
275 if (err < 0) return NULL;
276
277 uint32_t args_len;
278 err = js_get_array_length(env, argv[1], &args_len);
279 if (err < 0) return NULL;
280
281 js_value_t **args = malloc(sizeof(js_value_t *) * args_len);
282
283 err = js_get_array_elements(env, argv[1], args, args_len, 0, NULL);
284 if (err < 0) goto err;
285
286 js_value_t *source = argv[2];
287
288 int32_t offset;
289 err = js_get_value_int32(env, argv[3], &offset);
290 if (err < 0) goto err;
291
292 js_value_t *result;
293 err = js_create_function_with_source(env, NULL, 0, (char *) file, file_len, args, args_len, 0, source, &result);
294 if (err < 0) goto err;
295
296 free(args);
297
298 return result;
299
300err:
301 free(args);
302
303 return NULL;
304}
305
306static void
307bare_module__on_finalize(js_env_t *env, void *data, void *finalize_hint) {
308 int err;
309
310 js_module_t *module = data;
311
312 err = js_delete_module(env, module);
313 assert(err == 0);
314}
315
316static js_value_t *
317bare_module_create_module(js_env_t *env, js_callback_info_t *info) {
318 int err;
319
320 size_t argc = 4;
321 js_value_t *argv[4];
322
323 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
324 assert(err == 0);
325
326 assert(argc == 4);
327
328 size_t file_len;
329 utf8_t file[1024];
330 err = js_get_value_string_utf8(env, argv[0], file, 1024, &file_len);
331 if (err < 0) return NULL;
332
333 js_value_t *source = argv[1];
334
335 int32_t offset;
336 err = js_get_value_int32(env, argv[2], &offset);
337 if (err < 0) return NULL;
338
339 bare_module_context_t *context;
340 err = js_get_arraybuffer_info(env, argv[3], (void **) &context, NULL);
341 if (err < 0) return NULL;
342
343 js_module_t *module;
344 err = js_create_module(env, (char *) file, file_len, offset, source, bare_module__on_meta, (void *) context, &module);
345 if (err < 0) return NULL;
346
347 js_value_t *result;
348 err = js_create_external(env, (void *) module, bare_module__on_finalize, NULL, &result);
349 if (err < 0) return NULL;
350
351 return result;
352}
353
354static js_value_t *
355bare_module_create_synthetic_module(js_env_t *env, js_callback_info_t *info) {
356 int err;
357
358 size_t argc = 3;
359 js_value_t *argv[3];
360
361 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
362 assert(err == 0);
363
364 assert(argc == 3);
365
366 size_t file_len;
367 utf8_t file[1024];
368 err = js_get_value_string_utf8(env, argv[0], file, 1024, &file_len);
369 if (err < 0) return NULL;
370
371 uint32_t names_len;
372 err = js_get_array_length(env, argv[1], &names_len);
373 if (err < 0) return NULL;
374
375 js_value_t **export_names = malloc(sizeof(js_value_t *) * names_len);
376
377 err = js_get_array_elements(env, argv[1], export_names, names_len, 0, NULL);
378 if (err < 0) goto err;
379
380 bare_module_context_t *context;
381 err = js_get_arraybuffer_info(env, argv[2], (void **) &context, NULL);
382 if (err < 0) goto err;
383
384 js_module_t *module;
385 err = js_create_synthetic_module(env, (char *) file, file_len, export_names, names_len, bare_module__on_evaluate, (void *) context, &module);
386 if (err < 0) goto err;
387
388 js_value_t *result;
389 err = js_create_external(env, (void *) module, bare_module__on_finalize, NULL, &result);
390 if (err < 0) goto err;
391
392 free(export_names);
393
394 return result;
395
396err:
397 free(export_names);
398
399 return NULL;
400}
401
402static js_value_t *
403bare_module_set_export(js_env_t *env, js_callback_info_t *info) {
404 int err;
405
406 size_t argc = 3;
407 js_value_t *argv[3];
408
409 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
410 assert(err == 0);
411
412 assert(argc == 3);
413
414 js_module_t *module;
415 err = js_get_value_external(env, argv[0], (void **) &module);
416 if (err < 0) return NULL;
417
418 js_set_module_export(env, module, argv[1], argv[2]);
419
420 return NULL;
421}
422
423static js_value_t *
424bare_module_run_module(js_env_t *env, js_callback_info_t *info) {
425 int err;
426
427 size_t argc = 3;
428 js_value_t *argv[3];
429
430 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
431 assert(err == 0);
432
433 assert(argc == 3);
434
435 js_module_t *module;
436 err = js_get_value_external(env, argv[0], (void **) &module);
437 if (err < 0) return NULL;
438
439 bare_module_context_t *context;
440 err = js_get_arraybuffer_info(env, argv[1], (void **) &context, NULL);
441 if (err < 0) return NULL;
442
443 err = js_instantiate_module(env, module, bare_module__on_static_import, (void *) context);
444 if (err < 0) return NULL;
445
446 js_value_t *promise;
447 err = js_run_module(env, module, &promise);
448 if (err < 0) return NULL;
449
450 bool is_promise;
451 err = js_is_promise(env, promise, &is_promise);
452 assert(err == 0);
453
454 if (is_promise) {
455 js_promise_state_t state;
456 err = js_get_promise_state(env, promise, &state);
457 assert(err == 0);
458
459 js_value_t *reason;
460
461 if (state == js_promise_rejected) {
462 err = js_get_promise_result(env, promise, &reason);
463 if (err < 0) return NULL;
464 } else {
465 err = js_get_null(env, &reason);
466 assert(err == 0);
467 }
468
469 js_value_t *exception;
470 err = js_get_and_clear_last_exception(env, &exception);
471 assert(err == 0);
472
473 js_value_t *ctx;
474 err = js_get_reference_value(env, context->ctx, &ctx);
475 assert(err == 0);
476
477 js_value_t *args[3] = {reason, promise, exception};
478
479 js_call_function(env, ctx, argv[2], 3, args, NULL);
480 }
481
482 return promise;
483}
484
485static js_value_t *
486bare_module_get_namespace(js_env_t *env, js_callback_info_t *info) {
487 int err;
488
489 size_t argc = 1;
490 js_value_t *argv[1];
491
492 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
493 assert(err == 0);
494
495 js_module_t *module;
496 err = js_get_value_external(env, argv[0], (void **) &module);
497 if (err < 0) return NULL;
498
499 js_value_t *result;
500 err = js_get_module_namespace(env, module, &result);
501 if (err < 0) return NULL;
502
503 return result;
504}
505
506static js_value_t *
507bare_module_exists(js_env_t *env, js_callback_info_t *info) {
508 int err;
509
510 uv_loop_t *loop;
511 err = js_get_env_loop(env, &loop);
512 assert(err == 0);
513
514 js_value_t *argv[2];
515 size_t argc = 2;
516
517 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
518 assert(err == 0);
519
520 assert(argc == 2);
521
522 utf8_t path[4096];
523 err = js_get_value_string_utf8(env, argv[0], path, 4096, NULL);
524 assert(err == 0);
525
526 uint32_t mode;
527 err = js_get_value_uint32(env, argv[1], &mode);
528 assert(err == 0);
529
530 uv_fs_t req;
531 uv_fs_stat(loop, &req, (char *) path, NULL);
532
533 uv_stat_t *st = req.result < 0 ? NULL : req.ptr;
534
535 js_value_t *result;
536 err = js_get_boolean(env, st && st->st_mode & mode, &result);
537 assert(err == 0);
538
539 uv_fs_req_cleanup(&req);
540
541 return result;
542}
543
544static js_value_t *
545bare_module_realpath(js_env_t *env, js_callback_info_t *info) {
546 int err;
547
548 uv_loop_t *loop;
549 err = js_get_env_loop(env, &loop);
550 assert(err == 0);
551
552 js_value_t *argv[1];
553 size_t argc = 1;
554
555 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
556 assert(err == 0);
557
558 assert(argc == 1);
559
560 utf8_t path[4096];
561 err = js_get_value_string_utf8(env, argv[0], path, 4096, NULL);
562 assert(err == 0);
563
564 uv_fs_t req;
565 uv_fs_realpath(loop, &req, (char *) path, NULL);
566
567 int res = req.result;
568
569 if (res < 0) {
570 uv_fs_req_cleanup(&req);
571 err = res;
572 goto err;
573 }
574
575 js_value_t *result;
576 err = js_create_string_utf8(env, (utf8_t *) req.ptr, -1, &result);
577 assert(err == 0);
578
579 uv_fs_req_cleanup(&req);
580
581 return result;
582
583err:
584 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
585 assert(err == 0);
586
587 return NULL;
588}
589
590static js_value_t *
591bare_module_read(js_env_t *env, js_callback_info_t *info) {
592 int err;
593
594 uv_loop_t *loop;
595 err = js_get_env_loop(env, &loop);
596 assert(err == 0);
597
598 js_value_t *argv[1];
599 size_t argc = 1;
600
601 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
602 assert(err == 0);
603
604 assert(argc == 1);
605
606 utf8_t path[4096];
607 err = js_get_value_string_utf8(env, argv[0], path, 4096, NULL);
608 assert(err == 0);
609
610 uv_fs_t req;
611 uv_fs_open(loop, &req, (char *) path, UV_FS_O_RDONLY, 0, NULL);
612
613 int fd = req.result;
614 uv_fs_req_cleanup(&req);
615
616 if (fd < 0) {
617 err = fd;
618 goto err;
619 }
620
621 uv_fs_fstat(loop, &req, fd, NULL);
622 uv_stat_t *st = req.ptr;
623
624 size_t len = st->st_size;
625 char *base;
626
627 js_value_t *result;
628 err = js_create_arraybuffer(env, len, (void **) &base, &result);
629 assert(err == 0);
630
631 uv_buf_t buffer = uv_buf_init(base, len);
632
633 uv_fs_req_cleanup(&req);
634
635 int64_t read = 0;
636
637 while (true) {
638 uv_fs_read(loop, &req, fd, &buffer, 1, read, NULL);
639
640 int res = req.result;
641 uv_fs_req_cleanup(&req);
642
643 if (res < 0) {
644 uv_fs_close(loop, &req, fd, NULL);
645 uv_fs_req_cleanup(&req);
646 err = res;
647 goto err;
648 }
649
650 buffer.base += res;
651 buffer.len -= res;
652
653 read += res;
654 if (res == 0 || read == len) break;
655 }
656
657 uv_fs_close(loop, &req, fd, NULL);
658 uv_fs_req_cleanup(&req);
659
660 return result;
661
662err:
663 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
664 assert(err == 0);
665
666 return NULL;
667}
668
669static js_value_t *
670bare_module_exports(js_env_t *env, js_value_t *exports) {
671 int err;
672
673#define V(name, fn) \
674 { \
675 js_value_t *val; \
676 err = js_create_function(env, name, -1, fn, NULL, &val); \
677 assert(err == 0); \
678 err = js_set_named_property(env, exports, name, val); \
679 assert(err == 0); \
680 }
681
682 V("init", bare_module_init)
683
684 V("createFunction", bare_module_create_function)
685 V("createModule", bare_module_create_module)
686 V("createSyntheticModule", bare_module_create_synthetic_module)
687 V("setExport", bare_module_set_export)
688 V("runModule", bare_module_run_module)
689 V("getNamespace", bare_module_get_namespace)
690
691 V("exists", bare_module_exists)
692 V("realpath", bare_module_realpath)
693 V("read", bare_module_read)
694#undef V
695
696#define V(name, n) \
697 { \
698 js_value_t *val; \
699 err = js_create_uint32(env, n, &val); \
700 assert(err == 0); \
701 err = js_set_named_property(env, exports, name, val); \
702 assert(err == 0); \
703 }
704
705 V("FILE", S_IFREG)
706 V("DIR", S_IFDIR)
707#undef V
708
709 return exports;
710}
711
712BARE_MODULE(bare_module, bare_module_exports)
node_modules/bare-module/binding.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon()
node_modules/bare-module/index.d.ts +117 -0
……@@ -0,0 +1,117 @@
1import Buffer from 'bare-buffer'
2import URL from 'bare-url'
3import Bundle from 'bare-bundle'
4import {
5 type Builtins,
6 type Conditions,
7 type ImportsMap,
8 type ResolutionsMap
9} from 'bare-module-resolve'
10import Protocol from './lib/protocol'
11import constants from './lib/constants'
12
13interface Cache {
14 [href: string]: Module
15}
16
17interface Attributes {
18 type: Lowercase<keyof typeof constants.types>
19}
20
21interface Options {
22 attributes?: Attributes
23 builtins?: Builtins
24 cache?: Cache
25 conditions?: Conditions
26 defaultType?: number
27 imports?: ImportsMap
28 main?: Module
29 protocol?: Protocol
30 referrer?: Module
31 resolutions?: ResolutionsMap
32 type?: number
33}
34
35interface LoadOptions extends Options {
36 isDynamicImport?: boolean
37 isImport?: boolean
38}
39
40interface ResolveOptions extends Options {
41 isImport?: boolean
42}
43
44interface Module {
45 readonly builtins: Builtins
46 readonly cache: Cache
47 readonly conditions: Conditions
48 readonly defaultType: number
49 readonly dirname: string
50 exports: unknown
51 readonly filename: string
52 readonly id: string
53 readonly imports: ImportsMap
54 readonly main: Module
55 readonly path: string
56 readonly protocol: Protocol
57 readonly resolutions: ResolutionsMap
58 readonly type: number
59 readonly url: URL
60}
61
62declare class Module {
63 static readonly protocol: Protocol
64 static readonly cache: Cache
65
66 static load(url: URL, opts: LoadOptions): Module
67 static load(url: URL, source?: Buffer | string | Bundle | null, opts?: LoadOptions): Module
68
69 static resolve(specifier: string, parentURL: URL, opts?: ResolveOptions): URL
70
71 static asset(specifier: string, parentURL: URL, opts?: Options): URL
72
73 constructor(url: URL)
74}
75
76declare namespace Module {
77 export {
78 type Attributes,
79 type Cache,
80 type Options,
81 type LoadOptions,
82 type ResolveOptions,
83 Protocol,
84 constants
85 }
86
87 export const builtinModules: Module[]
88
89 export function isBuiltin(): boolean
90
91 export interface CreateRequireOptions extends Options {
92 module?: Module
93 }
94
95 export interface RequireOptions {
96 with?: Attributes
97 }
98
99 export interface RequireAddon {
100 (specifier?: string, parentURL?: URL): string
101 host: string
102 resolve: (specifier: string, parentURL?: URL) => unknown
103 }
104
105 export interface Require {
106 (parentURL: string | URL, opts?: RequireOptions): unknown
107 main: Module
108 cache: Cache
109 resolve: (specifier: string, parentURL?: URL) => string
110 addon: RequireAddon
111 asset: (specifier: string, parentURL?: URL) => string
112 }
113
114 export function createRequire(parentURL: string | URL, opts?: CreateRequireOptions): Require
115}
116
117export = Module
node_modules/bare-module/index.js +1034 -0
……@@ -0,0 +1,1034 @@
1const path = require('bare-path')
2const resolve = require('bare-module-resolve')
3const lex = require('bare-module-lexer')
4const { isURL, fileURLToPath, pathToFileURL } = require('bare-url')
5const Bundle = require('bare-bundle')
6const Protocol = require('./lib/protocol')
7const constants = require('./lib/constants')
8const errors = require('./lib/errors')
9const binding = require('./binding')
10
11const kind = Symbol.for('bare.module.kind')
12
13const isWindows = Bare.platform === 'win32'
14
15const { startsWithWindowsDriveLetter } = resolve
16
17module.exports = exports = class Module {
18 static get [kind]() {
19 return 1 // Compatibility version
20 }
21
22 constructor(url) {
23 this._url = url
24 this._state = 0
25 this._type = 0
26 this._defaultType = 0
27 this._main = null
28 this._exports = null
29 this._imports = null
30 this._resolutions = null
31 this._builtins = null
32 this._conditions = null
33 this._protocol = null
34 this._cache = null
35 this._source = null
36 this._function = null
37 this._names = null
38 this._promise = null
39 this._handle = null
40
41 Object.preventExtensions(this)
42 }
43
44 get [kind]() {
45 return Module[kind]
46 }
47
48 get url() {
49 return this._url
50 }
51
52 get type() {
53 return this._type
54 }
55
56 get defaultType() {
57 return this._defaultType
58 }
59
60 get main() {
61 return this._main
62 }
63
64 get exports() {
65 return this._exports
66 }
67
68 set exports(value) {
69 this._exports = value
70 }
71
72 get imports() {
73 return this._imports
74 }
75
76 get resolutions() {
77 return this._resolutions
78 }
79
80 get builtins() {
81 return this._builtins
82 }
83
84 get conditions() {
85 return Array.from(this._conditions)
86 }
87
88 get protocol() {
89 return this._protocol
90 }
91
92 get cache() {
93 return this._cache
94 }
95
96 // For Node.js compatibility
97 get filename() {
98 return urlToPath(this._url)
99 }
100
101 // For Node.js compatibility
102 get dirname() {
103 return urlToDirname(this._url)
104 }
105
106 // For Node.js compatibility
107 get id() {
108 return this.filename
109 }
110
111 // For Node.js compatibility
112 get path() {
113 return this.dirname
114 }
115
116 _transform(isImport, isDynamicImport) {
117 if (isDynamicImport) {
118 this._run()
119 } else if (isImport) {
120 this._synthesize()
121 } else {
122 this._evaluate()
123 }
124
125 return this
126 }
127
128 _synthesize() {
129 if ((this._state & constants.states.SYNTHESIZED) !== 0) return
130
131 this._state |= constants.states.SYNTHESIZED
132
133 if (this._type === constants.types.MODULE) return
134
135 const names = new Set(['default'])
136 const queue = [this]
137 const seen = new Set()
138
139 while (queue.length) {
140 const module = queue.pop()
141
142 if (seen.has(module)) continue
143
144 seen.add(module)
145
146 switch (module._type) {
147 case constants.types.SCRIPT: {
148 const result = lex(module._source)
149
150 for (const { name } of result.exports) names.add(name)
151
152 const referrer = module
153
154 for (const { specifier, type } of result.imports) {
155 if (
156 (type & lex.constants.REEXPORT) !== 0 &&
157 (type & lex.constants.ADDON) === 0 &&
158 (type & lex.constants.ASSET) === 0
159 ) {
160 const resolved = Module.resolve(specifier, referrer._url, {
161 isImport: true,
162 referrer
163 })
164
165 const module = Module.load(resolved, {
166 isImport: true,
167 referrer
168 })
169
170 if (module._names) {
171 for (const name of module._names) names.add(name)
172 } else {
173 queue.push(module)
174 }
175 }
176 }
177
178 break
179 }
180
181 case constants.types.MODULE:
182 module._evaluate()
183
184 for (const name of Object.keys(module._exports)) names.add(name)
185
186 break
187
188 case constants.types.JSON:
189 for (const name of Object.keys(module._exports)) names.add(name)
190 }
191 }
192
193 this._names = Array.from(names)
194
195 this._handle = binding.createSyntheticModule(this._url.href, this._names, Module._handle)
196 }
197
198 _evaluate() {
199 if ((this._state & constants.states.EVALUATED) !== 0) return
200
201 this._state |= constants.states.EVALUATED
202
203 if (this._type === constants.types.SCRIPT) {
204 const require = exports.createRequire(this._url, { module: this })
205
206 this._exports = {}
207
208 const fn = this._function // Bind to variable to ensure proper stack trace
209
210 fn(require, this, this._exports, urlToPath(this._url), urlToDirname(this._url))
211 } else if (this._type === constants.types.MODULE) {
212 this._run()
213
214 this._exports = binding.getNamespace(this._handle)
215 }
216 }
217
218 _run() {
219 if ((this._state & constants.states.RUN) !== 0) return
220
221 this._state |= constants.states.RUN
222
223 this._synthesize()
224
225 this._promise = binding.runModule(this._handle, Module._handle, Module._onrun)
226 }
227
228 [Symbol.for('bare.inspect')]() {
229 return {
230 __proto__: { constructor: Module },
231
232 url: this.url,
233 type: this.type,
234 defaultType: this.defaultType,
235 main: this.main,
236 exports: this.exports,
237 imports: this.imports,
238 resolutions: this.resolutions,
239 builtins: this.builtins,
240 conditions: this.conditions
241 }
242 }
243
244 static _extensions = Object.create(null)
245
246 static _protocol = null
247
248 static _cache =
249 module[kind] === Module[kind] ? module.cache || Object.create(null) : Object.create(null)
250
251 static _conditions = ['bare', 'node', ...Bare.Addon.host.split('-')]
252
253 static _handle = binding.init(this, this._onimport, this._onevaluate, this._onmeta)
254
255 static _onimport(specifier, attributes, referrerHref, isDynamicImport) {
256 const referrer = this._cache[referrerHref] || null
257
258 if (referrer === null) {
259 throw errors.MODULE_NOT_FOUND(
260 `Cannot find referrer for module '${specifier}' imported from '${referrerHref}'`,
261 specifier,
262 referrer
263 )
264 }
265
266 const resolved = this.resolve(specifier, referrer._url, {
267 isImport: true,
268 referrer,
269 attributes
270 })
271
272 const module = this.load(resolved, {
273 isImport: true,
274 isDynamicImport,
275 referrer,
276 attributes
277 })
278
279 return isDynamicImport
280 ? module._promise.then(() => binding.getNamespace(module._handle))
281 : module._handle
282 }
283
284 static _onevaluate(href) {
285 const module = this._cache[href] || null
286
287 if (module === null) {
288 throw errors.MODULE_NOT_FOUND(`Cannot find module '${href}'`, href)
289 }
290
291 module._evaluate()
292
293 for (const name of module._names) {
294 let value
295
296 if (
297 name === 'default' &&
298 (typeof module._exports !== 'object' ||
299 module._exports === null ||
300 name in module._exports === false)
301 ) {
302 value = module._exports
303 } else {
304 value = module._exports[name]
305 }
306
307 binding.setExport(module._handle, name, value)
308 }
309 }
310
311 static _onmeta(href, meta) {
312 const self = Module
313
314 const module = this._cache[href] || null
315
316 if (module === null) {
317 throw errors.MODULE_NOT_FOUND(`Cannot find module '${href}'`, href)
318 }
319
320 const referrer = module
321
322 meta.url = module._url.href
323 meta.main = module._main === module
324 meta.cache = module._cache
325
326 meta.resolve = function resolve(specifier, parentURL = referrer._url) {
327 return self.resolve(specifier, toURL(parentURL, referrer._url), {
328 referrer
329 }).href
330 }
331
332 meta.addon = function addon(specifier = '.', parentURL = referrer._url) {
333 const resolved = Bare.Addon.resolve(specifier, toURL(parentURL, referrer._url), { referrer })
334
335 const addon = Bare.Addon.load(resolved, { referrer })
336
337 return addon._exports
338 }
339
340 meta.addon.resolve = function resolve(specifier = '.', parentURL = referrer._url) {
341 return Bare.Addon.resolve(specifier, toURL(parentURL, referrer._url), {
342 referrer
343 }).href
344 }
345
346 meta.addon.host = Bare.Addon.host
347
348 meta.asset = function asset(specifier, parentURL = referrer._url) {
349 return self.asset(specifier, toURL(parentURL, referrer._url), {
350 referrer
351 }).href
352 }
353 }
354
355 static _onrun(reason, promise, err = reason) {
356 if (err) {
357 promise.catch(() => {}) // Don't leak the rejection
358
359 throw err
360 } else {
361 promise.catch((err) =>
362 queueMicrotask(() => {
363 throw err
364 })
365 )
366 }
367 }
368
369 static get protocol() {
370 return this._protocol
371 }
372
373 static get cache() {
374 return this._cache
375 }
376
377 static load(url, source = null, opts = {}) {
378 const self = Module
379
380 if (
381 !ArrayBuffer.isView(source) &&
382 !Bundle.isBundle(source) &&
383 typeof source !== 'string' &&
384 source !== null
385 ) {
386 opts = source
387 source = null
388 }
389
390 const {
391 isImport = false,
392 isDynamicImport = false,
393 referrer = null,
394 attributes,
395 type = typeForAttributes(attributes),
396 defaultType = referrer ? referrer._defaultType : 0,
397 cache = referrer ? referrer._cache : self._cache,
398 main = referrer ? referrer._main : null,
399 protocol = referrer ? referrer._protocol : self._protocol,
400 imports = referrer ? referrer._imports : null,
401 resolutions = referrer ? referrer._resolutions : null,
402 builtins = referrer ? referrer._builtins : null,
403 conditions = referrer ? referrer._conditions : self._conditions
404 } = opts
405
406 let module = cache[url.href] || null
407
408 if (module !== null) {
409 if (type !== 0 && type !== module._type) {
410 throw errors.TYPE_INCOMPATIBLE(
411 `Module '${module.url.href}' is not of type '${nameOfType(type)}'`
412 )
413 }
414
415 return module._transform(isImport, isDynamicImport)
416 }
417
418 module = cache[url.href] = new Module(url)
419
420 try {
421 switch (url.protocol) {
422 case 'builtin:':
423 module._exports = builtins[url.pathname]
424 break
425
426 default: {
427 module._defaultType = defaultType
428 module._cache = cache
429 module._main = main || module
430 module._protocol = protocol
431 module._imports = imports
432 module._resolutions = resolutions
433 module._builtins = builtins
434 module._conditions = conditions
435
436 if (
437 typeof attributes === 'object' &&
438 attributes !== null &&
439 typeof attributes.imports === 'string'
440 ) {
441 const resolved = self.resolve(attributes.imports, referrer._url, {
442 referrer: module
443 })
444
445 const imports = self.load(resolved, {
446 referrer: module,
447 type: constants.types.JSON
448 })
449
450 module._imports = mixinImports(module._imports, imports._exports, resolved)
451 }
452
453 let extension = canonicalExtensionForType(type) || path.extname(url.pathname)
454
455 if (extension in self._extensions === false) {
456 if (defaultType) {
457 extension = canonicalExtensionForType(defaultType) || '.js'
458 } else {
459 extension = '.js'
460 }
461 }
462
463 self._extensions[extension](module, source, referrer)
464 }
465 }
466
467 return module._transform(isImport, isDynamicImport)
468 } catch (err) {
469 delete cache[url.href]
470
471 throw err
472 }
473 }
474
475 static resolve(specifier, parentURL, opts = {}) {
476 const self = Module
477
478 if (typeof specifier !== 'string') {
479 throw new TypeError(
480 `Specifier must be a string. Received type ${typeof specifier} (${specifier})`
481 )
482 }
483
484 const {
485 isImport = false,
486 referrer = null,
487 attributes,
488 type = typeForAttributes(attributes),
489 extensions = extensionsForType(type),
490 protocol = referrer ? referrer._protocol : self._protocol,
491 imports = referrer ? referrer._imports : null,
492 resolutions = referrer ? referrer._resolutions : null,
493 builtins = referrer ? referrer._builtins : null,
494 conditions = referrer ? referrer._conditions : self._conditions
495 } = opts
496
497 const resolved = protocol.preresolve(specifier, parentURL)
498
499 const [resolution] = protocol.resolve(resolved, parentURL, imports)
500
501 if (resolution) return protocol.postresolve(resolution)
502
503 const candidates = []
504
505 for (const resolution of resolve(
506 resolved,
507 parentURL,
508 {
509 conditions: isImport ? ['import', ...conditions] : ['require', ...conditions],
510 imports,
511 resolutions,
512 extensions,
513 builtins: builtins ? Object.keys(builtins) : [],
514 engines: Bare.versions
515 },
516 readPackage
517 )) {
518 candidates.push(resolution)
519
520 switch (resolution.protocol) {
521 case 'builtin:':
522 return resolution
523 default:
524 if (protocol.exists(resolution, type)) {
525 return protocol.postresolve(resolution)
526 }
527 }
528 }
529
530 let message = `Cannot find module '${specifier}' imported from '${parentURL.href}'`
531
532 if (candidates.length > 0) {
533 message += '\nCandidates:'
534 message += '\n' + candidates.map((url) => '- ' + url.href).join('\n')
535 }
536
537 throw errors.MODULE_NOT_FOUND(message, specifier, parentURL, candidates)
538
539 function readPackage(packageURL) {
540 if (protocol.exists(packageURL, constants.types.JSON)) {
541 return Module.load(packageURL, { protocol })._exports
542 }
543
544 return null
545 }
546 }
547
548 static asset(specifier, parentURL, opts = {}) {
549 const self = Module
550
551 if (typeof specifier !== 'string') {
552 throw new TypeError(
553 `Specifier must be a string. Received type ${typeof specifier} (${specifier})`
554 )
555 }
556
557 const {
558 referrer = null,
559 protocol = referrer ? referrer._protocol : self._protocol,
560 imports = referrer ? referrer._imports : null,
561 resolutions = referrer ? referrer._resolutions : null,
562 conditions = referrer ? referrer._conditions : self._conditions
563 } = opts
564
565 const resolved = protocol.preresolve(specifier, parentURL)
566
567 const [resolution] = protocol.resolve(resolved, parentURL, imports)
568
569 if (resolution) return protocol.postresolve(resolution)
570
571 const candidates = []
572
573 for (const resolution of resolve(
574 resolved,
575 parentURL,
576 {
577 conditions: ['asset', ...conditions],
578 imports,
579 resolutions,
580 engines: Bare.versions
581 },
582 readPackage
583 )) {
584 candidates.push(resolution)
585
586 if (protocol.exists(resolution, constants.types.ASSET)) {
587 return protocol.postresolve(protocol.asset ? protocol.asset(resolution) : resolution)
588 }
589 }
590
591 let message = `Cannot find asset '${specifier}' imported from '${parentURL.href}'`
592
593 if (candidates.length > 0) {
594 message += '\nCandidates:'
595 message += '\n' + candidates.map((url) => '- ' + url.href).join('\n')
596 }
597
598 throw errors.ASSET_NOT_FOUND(message, specifier, parentURL, candidates)
599
600 function readPackage(packageURL) {
601 if (protocol.exists(packageURL, constants.types.JSON)) {
602 return Module.load(packageURL, { protocol })._exports
603 }
604
605 return null
606 }
607 }
608}
609
610const Module = exports
611
612function extensionsForType(type) {
613 switch (type) {
614 case constants.types.SCRIPT:
615 return ['.js', '.cjs']
616 case constants.types.MODULE:
617 return ['.js', '.mjs']
618 case constants.types.JSON:
619 return ['.json']
620 case constants.types.BUNDLE:
621 return ['.bundle']
622 case constants.types.ADDON:
623 return ['.bare', '.node']
624 case constants.types.BINARY:
625 return ['.bin']
626 case constants.types.TEXT:
627 return ['.txt']
628 default:
629 return ['.js', '.cjs', '.mjs', '.json', '.bare', '.node']
630 }
631}
632
633function canonicalExtensionForType(type) {
634 switch (type) {
635 case constants.types.SCRIPT:
636 return '.cjs'
637 case constants.types.MODULE:
638 return '.esm'
639 case constants.types.JSON:
640 return '.json'
641 case constants.types.BUNDLE:
642 return '.bundle'
643 case constants.types.ADDON:
644 return '.bare'
645 case constants.types.BINARY:
646 return '.bin'
647 case constants.types.TEXT:
648 return '.txt'
649 default:
650 return null
651 }
652}
653
654function nameOfType(type) {
655 switch (type) {
656 case constants.types.SCRIPT:
657 return 'script'
658 case constants.types.MODULE:
659 return 'module'
660 case constants.types.JSON:
661 return 'json'
662 case constants.types.BUNDLE:
663 return 'bundle'
664 case constants.types.ADDON:
665 return 'bare'
666 case constants.types.BINARY:
667 return 'binary'
668 case constants.types.TEXT:
669 return 'text'
670 default:
671 return null
672 }
673}
674
675function typeForAttributes(attributes) {
676 if (typeof attributes !== 'object' || attributes === null) return 0
677
678 switch (attributes.type) {
679 case 'script':
680 return constants.types.SCRIPT
681 case 'module':
682 return constants.types.MODULE
683 case 'json':
684 return constants.types.JSON
685 case 'bundle':
686 return constants.types.BUNDLE
687 case 'addon':
688 return constants.types.ADDON
689 case 'binary':
690 return constants.types.BINARY
691 case 'text':
692 return constants.types.TEXT
693 default:
694 return 0
695 }
696}
697
698function mixinImports(target, imports, url) {
699 if (typeof imports === 'object' && imports !== null && 'imports' in imports) {
700 imports = imports.imports
701 }
702
703 if (typeof imports !== 'object' || imports === null) {
704 throw errors.INVALID_IMPORTS_MAP(`Imports map at '${url.href}' is not valid`)
705 }
706
707 return { ...target, ...imports }
708}
709
710exports.Protocol = Protocol
711
712exports.constants = constants
713
714// For Node.js compatibility
715exports.builtinModules = []
716
717// For Node.js compatibility
718exports.isBuiltin = function isBuiltin() {
719 return false
720}
721
722exports.createRequire = function createRequire(parentURL, opts = {}) {
723 const self = Module
724
725 let {
726 module = null,
727 referrer = null,
728 type = constants.types.SCRIPT,
729 defaultType = referrer ? referrer._defaultType : constants.types.SCRIPT,
730 cache = referrer ? referrer._cache : self._cache,
731 main = referrer ? referrer._main : null,
732 protocol = referrer ? referrer._protocol : self._protocol,
733 imports = referrer ? referrer._imports : null,
734 resolutions = referrer ? referrer._resolutions : null,
735 builtins = referrer ? referrer._builtins : null,
736 conditions = referrer ? referrer._conditions : self._conditions
737 } = opts
738
739 if (module === null) {
740 module = new Module(toURL(parentURL))
741
742 module._type = type
743 module._defaultType = defaultType
744 module._cache = cache
745 module._main = main || module
746 module._protocol = protocol
747 module._imports = imports
748 module._resolutions = resolutions
749 module._builtins = builtins
750 module._conditions = conditions
751 }
752
753 referrer = module
754
755 function require(specifier, opts = {}) {
756 const attributes = opts && opts.with
757
758 const resolved = self.resolve(specifier, referrer._url, {
759 referrer,
760 attributes
761 })
762
763 const module = self.load(resolved, { referrer, attributes })
764
765 return module._exports
766 }
767
768 require.main = module._main
769 require.cache = module._cache
770
771 require.resolve = function resolve(specifier, parentURL = referrer._url) {
772 return urlToPath(self.resolve(specifier, toURL(parentURL, referrer._url), { referrer }))
773 }
774
775 require.addon = function addon(specifier = '.', parentURL = referrer._url) {
776 const resolved = Bare.Addon.resolve(specifier, toURL(parentURL, referrer._url), { referrer })
777
778 const addon = Bare.Addon.load(resolved, { referrer })
779
780 return addon._exports
781 }
782
783 require.addon.host = Bare.Addon.host
784
785 require.addon.resolve = function resolve(specifier = '.', parentURL = referrer._url) {
786 return urlToPath(
787 Bare.Addon.resolve(specifier, toURL(parentURL, referrer._url), {
788 referrer
789 })
790 )
791 }
792
793 require.asset = function asset(specifier, parentURL = referrer._url) {
794 return urlToPath(self.asset(specifier, toURL(parentURL, referrer._url), { referrer }))
795 }
796
797 return require
798}
799
800Module._extensions['.js'] = function (module, source, referrer) {
801 const self = Module
802
803 const protocol = module._protocol
804 const resolutions = module._resolutions
805
806 let pkg
807
808 for (const packageURL of resolve.lookupPackageScope(module._url, {
809 resolutions
810 })) {
811 if (self._cache[packageURL.href]) {
812 pkg = self._cache[packageURL.href]
813 break
814 }
815
816 if (protocol.exists(packageURL, constants.types.JSON)) {
817 pkg = self.load(packageURL, { protocol })
818 break
819 }
820 }
821
822 const info = (pkg && pkg._exports) || {}
823
824 const isESM =
825 // The default type is ES modules.
826 constants.types.MODULE === module._defaultType ||
827 // The package is explicitly declared as an ES module.
828 (info && info.type === 'module')
829
830 return self._extensions[isESM ? '.mjs' : '.cjs'](module, source, referrer)
831}
832
833Module._extensions['.cjs'] = function (module, source, referrer) {
834 const protocol = module._protocol
835
836 module._type = constants.types.SCRIPT
837
838 if (source === null) source = protocol.read(module._url)
839
840 if (typeof source === 'string') source = Buffer.from(source)
841
842 module._source = source
843
844 module._function = binding.createFunction(
845 module._url.href,
846 ['require', 'module', 'exports', '__filename', '__dirname'],
847 source.toString(),
848 0
849 )
850}
851
852Module._extensions['.mjs'] = function (module, source, referrer) {
853 const self = Module
854
855 const protocol = module._protocol
856
857 module._type = constants.types.MODULE
858
859 if (source === null) source = protocol.read(module._url)
860
861 if (typeof source === 'string') source = Buffer.from(source)
862
863 module._source = source
864
865 module._handle = binding.createModule(module._url.href, source.toString(), 0, self._handle)
866}
867
868Module._extensions['.json'] = function (module, source, referrer) {
869 const protocol = module._protocol
870
871 module._type = constants.types.JSON
872
873 if (source === null) source = protocol.read(module._url)
874
875 if (typeof source === 'string') source = Buffer.from(source)
876
877 module._source = source
878 module._exports = JSON.parse(source.toString())
879}
880
881Module._extensions['.bare'] = function (module, source, referrer) {
882 module._type = constants.types.ADDON
883
884 referrer = module
885
886 module._exports = Bare.Addon.load(module._url, { referrer }).exports
887}
888
889Module._extensions['.node'] = function (module, source, referrer) {
890 module._type = constants.types.ADDON
891
892 referrer = module
893
894 module._exports = Bare.Addon.load(module._url, { referrer }).exports
895}
896
897Module._extensions['.bundle'] = function (module, source, referrer) {
898 const self = Module
899
900 const protocol = module._protocol
901
902 module._type = constants.types.BUNDLE
903
904 if (source === null) source = protocol.read(module._url)
905
906 if (typeof source === 'string') source = Buffer.from(source)
907
908 referrer = module
909
910 const bundle = Bundle.from(source).mount(module._url.href + '/')
911
912 module._source = source
913 module._imports = bundle.imports
914 module._resolutions = bundle.resolutions
915
916 module._protocol = protocol.extend({
917 postresolve(context, url) {
918 return bundle.exists(url.href) ? url : context.postresolve(url)
919 },
920
921 exists(context, url, type) {
922 return bundle.exists(url.href) || context.exists(url, type)
923 },
924
925 read(context, url) {
926 return bundle.read(url.href) || context.read(url)
927 }
928 })
929
930 if (bundle.main) {
931 module._exports = self.load(new URL(bundle.main), bundle.read(bundle.main), {
932 referrer
933 })._exports
934 }
935}
936
937Module._extensions['.bin'] = function (module, source, referrer) {
938 const protocol = module._protocol
939
940 module._type = constants.types.BINARY
941
942 if (source === null) source = protocol.read(module._url)
943
944 if (typeof source === 'string') source = Buffer.from(source)
945
946 module._source = module._exports = source
947}
948
949Module._extensions['.txt'] = function (module, source, referrer) {
950 const protocol = module._protocol
951
952 module._type = constants.types.TEXT
953
954 if (source === null) source = protocol.read(module._url)
955
956 if (typeof source === 'string') source = Buffer.from(source)
957
958 module._source = source
959 module._exports = source.toString()
960}
961
962Module._protocol = new Protocol({
963 postresolve(url) {
964 switch (url.protocol) {
965 case 'file:':
966 return pathToFileURL(binding.realpath(path.toNamespacedPath(fileURLToPath(url))))
967 default:
968 return url
969 }
970 },
971
972 exists(url, type = 0) {
973 switch (url.protocol) {
974 case 'file:':
975 return binding.exists(
976 path.toNamespacedPath(fileURLToPath(url)),
977 type === constants.types.ASSET ? binding.FILE | binding.DIR : binding.FILE
978 )
979 default:
980 return false
981 }
982 },
983
984 read(url) {
985 switch (url.protocol) {
986 case 'file:':
987 return Buffer.from(binding.read(path.toNamespacedPath(fileURLToPath(url))))
988 default:
989 throw errors.UNKNOWN_PROTOCOL(`Cannot load module '${url.href}'`)
990 }
991 }
992})
993
994function toURL(value, base) {
995 if (isURL(value)) return value
996
997 if (startsWithWindowsDriveLetter(value)) {
998 return pathToFileURL(value)
999 }
1000
1001 return URL.parse(value, base) || pathToFileURL(value)
1002}
1003
1004function urlToPath(url) {
1005 if (url.protocol === 'file:') return fileURLToPath(url)
1006
1007 if (isWindows) {
1008 if (/%2f|%5c/i.test(url.pathname)) {
1009 throw errors.INVALID_URL_PATH('The URL path must not include encoded \\ or / characters')
1010 }
1011 } else {
1012 if (/%2f/i.test(url.pathname)) {
1013 throw errors.INVALID_URL_PATH('The URL path must not include encoded / characters')
1014 }
1015 }
1016
1017 return decodeURIComponent(url.pathname)
1018}
1019
1020function urlToDirname(url) {
1021 if (url.protocol === 'file:') return path.dirname(fileURLToPath(url))
1022
1023 if (isWindows) {
1024 if (/%2f|%5c/i.test(url.pathname)) {
1025 throw errors.INVALID_URL_PATH('The URL path must not include encoded \\ or / characters')
1026 }
1027 } else {
1028 if (/%2f/i.test(url.pathname)) {
1029 throw errors.INVALID_URL_PATH('The URL path must not include encoded / characters')
1030 }
1031 }
1032
1033 return decodeURIComponent(new URL('.', url).pathname).replace(/\/$/, '')
1034}
node_modules/bare-module/lib/constants.d.ts +19 -0
……@@ -0,0 +1,19 @@
1declare const constants: {
2 states: {
3 EVALUATED: number
4 SYNTHESIZED: number
5 RUN: number
6 }
7 types: {
8 SCRIPT: number
9 MODULE: number
10 JSON: number
11 BUNDLE: number
12 ADDON: number
13 BINARY: number
14 TEXT: number
15 ASSET: number
16 }
17}
18
19export = constants
node_modules/bare-module/lib/constants.js +17 -0
……@@ -0,0 +1,17 @@
1module.exports = {
2 states: {
3 EVALUATED: 1,
4 SYNTHESIZED: 2,
5 RUN: 4
6 },
7 types: {
8 SCRIPT: 1,
9 MODULE: 2,
10 JSON: 3,
11 BUNDLE: 4,
12 ADDON: 5,
13 BINARY: 6,
14 TEXT: 7,
15 ASSET: 8
16 }
17}
node_modules/bare-module/lib/errors.js +54 -0
……@@ -0,0 +1,54 @@
1module.exports = class ModuleError extends Error {
2 constructor(msg, fn = ModuleError, code = fn.name) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'ModuleError'
13 }
14
15 static MODULE_NOT_FOUND(msg, specifier, referrer = null, candidates = []) {
16 const err = new ModuleError(msg, ModuleError.MODULE_NOT_FOUND)
17
18 err.specifier = specifier
19 err.referrer = referrer
20 err.candidates = candidates
21
22 return err
23 }
24
25 static ASSET_NOT_FOUND(msg, specifier, referrer = null, candidates = []) {
26 const err = new ModuleError(msg, ModuleError.ASSET_NOT_FOUND)
27
28 err.specifier = specifier
29 err.referrer = referrer
30 err.candidates = candidates
31
32 return err
33 }
34
35 static UNKNOWN_PROTOCOL(msg) {
36 return new ModuleError(msg, ModuleError.UNKNOWN_PROTOCOL)
37 }
38
39 static INVALID_BUNDLE_EXTENSION(msg) {
40 return new ModuleError(msg, ModuleError.INVALID_BUNDLE_EXTENSION)
41 }
42
43 static INVALID_URL_PATH(msg) {
44 return new ModuleError(msg, ModuleError.INVALID_URL_PATH)
45 }
46
47 static INVALID_IMPORTS_MAP(msg) {
48 return new ModuleError(msg, ModuleError.INVALID_IMPORTS_MAP)
49 }
50
51 static TYPE_INCOMPATIBLE(msg) {
52 return new ModuleError(msg, ModuleError.TYPE_INCOMPATIBLE)
53 }
54}
node_modules/bare-module/lib/protocol.d.ts +27 -0
……@@ -0,0 +1,27 @@
1import URL from 'bare-url'
2import Buffer from 'bare-buffer'
3import { type ImportsMap } from 'bare-module-resolve'
4
5interface ModuleProtocol {
6 preresolve(specifier: string, parentURL: URL): string
7
8 postresolve(url: URL): URL
9
10 resolve(specifier: string, parentURL: URL, imports: ImportsMap): URL
11
12 exists(url: URL, type: number): boolean
13
14 read(url: URL): Buffer | string | null
15
16 addon(url: URL): URL
17
18 asset(url: URL): URL
19
20 extend(methods: Partial<ModuleProtocol>): ModuleProtocol
21}
22
23declare class ModuleProtocol {
24 constructor(methods?: Partial<ModuleProtocol>, context?: ModuleProtocol)
25}
26
27export = ModuleProtocol
node_modules/bare-module/lib/protocol.js +55 -0
……@@ -0,0 +1,55 @@
1module.exports = class ModuleProtocol {
2 constructor(methods = {}, context = null) {
3 for (const name of [
4 'preresolve',
5 'postresolve',
6 'resolve',
7 'exists',
8 'read',
9 'addon',
10 'asset'
11 ]) {
12 const method = methods[name]
13
14 if (typeof method === 'function') {
15 this[name] = context ? method.bind(this, context) : method.bind(this)
16 } else if (context) {
17 const method = context[name]
18
19 if (typeof method === 'function') {
20 this[name] = method
21 }
22 }
23 }
24 }
25
26 preresolve(specifier, parentURL) {
27 return specifier
28 }
29
30 postresolve(url) {
31 return url
32 }
33
34 *resolve(specifier, parentURL, imports) {}
35
36 exists(url, type) {
37 return false
38 }
39
40 read(url) {
41 return null
42 }
43
44 addon(url) {
45 return url
46 }
47
48 asset(url) {
49 return url
50 }
51
52 extend(methods) {
53 return new ModuleProtocol(methods, this)
54 }
55}
node_modules/bare-module/package.json +60 -0
……@@ -0,0 +1,60 @@
1{
2 "name": "bare-module",
3 "version": "6.1.3",
4 "description": "Module support for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json"
11 },
12 "files": [
13 "index.js",
14 "index.d.ts",
15 "binding.c",
16 "binding.js",
17 "CMakeLists.txt",
18 "lib",
19 "prebuilds"
20 ],
21 "addon": true,
22 "scripts": {
23 "test": "prettier . --check && bare test.js"
24 },
25 "repository": {
26 "type": "git",
27 "url": "git+https://github.com/holepunchto/bare-module.git"
28 },
29 "author": "Holepunch",
30 "license": "Apache-2.0",
31 "bugs": {
32 "url": "https://github.com/holepunchto/bare-module/issues"
33 },
34 "homepage": "https://github.com/holepunchto/bare-module#readme",
35 "engines": {
36 "bare": ">=1.23.0"
37 },
38 "dependencies": {
39 "bare-bundle": "^1.3.0",
40 "bare-module-lexer": "^1.0.0",
41 "bare-module-resolve": "^1.8.0",
42 "bare-path": "^3.0.0",
43 "bare-url": "^2.0.1"
44 },
45 "devDependencies": {
46 "bare-buffer": "^3.0.2",
47 "brittle": "^3.1.1",
48 "cmake-bare": "^1.1.6",
49 "prettier": "^3.3.3",
50 "prettier-config-holepunch": "^2.0.0"
51 },
52 "peerDependencies": {
53 "bare-buffer": "*"
54 },
55 "peerDependenciesMeta": {
56 "bare-buffer": {
57 "optional": true
58 }
59 }
60}
node_modules/bare-module/prebuilds/android-arm/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/android-arm64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/android-ia32/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/android-x64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/darwin-arm64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/darwin-x64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/ios-arm64-simulator/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/ios-arm64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/ios-x64-simulator/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/linux-arm64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/linux-x64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/win32-arm64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-module/prebuilds/win32-x64/bare-module.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-net/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-net/README.md +25 -0
……@@ -0,0 +1,25 @@
1# bare-net
2
3TCP and IPC servers and clients for JavaScript.
4
5```
6npm i bare-net
7```
8
9## Usage
10
11```js
12const net = require('bare-net')
13
14const server = net.createServer()
15server.on('connection', (socket) => socket.on('data', console.log))
16server.listen(() => console.log('server is up'))
17
18const { port } = server.address()
19const socket = net.createConnection(port)
20socket.write('hello world')
21```
22
23## License
24
25Apache-2.0
node_modules/bare-net/index.d.ts +98 -0
……@@ -0,0 +1,98 @@
1import EventEmitter, { EventMap } from 'bare-events'
2import { Duplex, DuplexEvents } from 'bare-stream'
3import {
4 Pipe,
5 PipeServer,
6 createConnection as createPipeConnection,
7 createServer as createPipeServer
8} from 'bare-pipe'
9import {
10 TCPSocket,
11 TCPServer,
12 createConnection as createTCPConnection,
13 createServer as createTCPServer,
14 isIP,
15 isIPv4,
16 isIPv6
17} from 'bare-tcp'
18import constants from './lib/constants'
19
20export { constants, isIP, isIPv4, isIPv6 }
21
22export interface NetOptions {
23 allowHalfOpen?: boolean
24 eagerOpen?: boolean
25 readBufferSize?: number
26}
27
28export interface NetSocketEvents extends DuplexEvents {
29 connect: []
30}
31
32interface NetSocket<M extends NetSocketEvents = NetSocketEvents> extends Duplex<M> {
33 readonly connecting: boolean
34 readonly pending: boolean
35 readonly timeout?: number
36 readonly readyState: 'open' | 'readOnly' | 'writeOnly' | 'opening'
37 readonly localAddress?: string
38 readonly localPort?: number
39 readonly localFamily?: string
40 readonly remoteAddress?: string
41 readonly remotePort?: number
42 readonly remoteFamily?: string
43
44 connect: Pipe['connect'] & TCPSocket['connect']
45
46 setKeepAlive(enable?: boolean, delay?: number): this
47 setKeepAlive(delay: number): this
48
49 setNoDelay(enable?: boolean): this
50
51 setTimeout(ms: number, ontimeout?: () => void): this
52
53 ref(): this
54 unref(): this
55}
56
57declare class NetSocket {
58 constructor(opts?: NetOptions)
59}
60
61export { type NetSocket, NetSocket as Socket }
62
63export interface NetServerEvents extends EventMap {
64 close: []
65 connection: [socket: NetSocket]
66 error: [err: Error]
67 listening: []
68}
69
70interface NetServer<M extends NetServerEvents = NetServerEvents> extends EventEmitter<M> {
71 readonly listening: boolean
72
73 address(): (PipeServer['address'] & TCPServer['address']) | null
74
75 listen: PipeServer['listen'] & TCPServer['listen']
76
77 close(onclose: (err?: Error) => void): this
78
79 ref(): this
80 unref(): this
81}
82
83declare class NetServer {
84 constructor(opts?: NetOptions, onconnection?: (socket: NetSocket) => void)
85 constructor(onconnection: (socket: NetSocket) => void)
86}
87
88export { type NetServer, NetServer as Server }
89
90export function createConnection(
91 ...args: Parameters<typeof createPipeConnection & typeof createTCPConnection>
92): NetSocket
93
94export { createConnection as connect }
95
96export function createServer(
97 ...args: Parameters<typeof createPipeServer & typeof createTCPServer>
98): NetServer
node_modules/bare-net/index.js +414 -0
……@@ -0,0 +1,414 @@
1const EventEmitter = require('bare-events')
2const { Duplex } = require('bare-stream')
3const tcp = require('bare-tcp')
4const pipe = require('bare-pipe')
5const constants = require('./lib/constants')
6
7const defaultReadBufferSize = 65536
8
9exports.Socket = class NetSocket extends Duplex {
10 constructor(opts = {}) {
11 const {
12 readBufferSize = defaultReadBufferSize,
13 allowHalfOpen = false,
14 eagerOpen = false
15 } = opts
16
17 super({ eagerOpen, allowHalfOpen })
18
19 this._type = 0
20 this._state = 0
21 this._socket = null
22
23 this._opts = { readBufferSize, allowHalfOpen, eagerOpen }
24
25 this._pendingOpen = null
26 this._pendingWrite = null
27 this._pendingFinal = null
28 this._pendingDestroy = null
29 }
30
31 get connecting() {
32 return this._socket !== null && this._socket.connecting
33 }
34
35 get pending() {
36 return this._socket === null || this._socket.pending
37 }
38
39 get timeout() {
40 return this._socket === null ? undefined : this._socket.timeout
41 }
42
43 get readyState() {
44 return this._socket === null ? 'opening' : this._socket.readyState
45 }
46
47 get localAddress() {
48 return this._socket === null ? undefined : this._socket.localAddress
49 }
50
51 get localPort() {
52 return this._socket === null ? undefined : this._socket.localPort
53 }
54
55 get localFamily() {
56 return this._socket === null ? undefined : this._socket.localFamily
57 }
58
59 get remoteAddress() {
60 return this._socket === null ? undefined : this._socket.remoteAddress
61 }
62
63 get remotePort() {
64 return this._socket === null ? undefined : this._socket.remotePort
65 }
66
67 get remoteFamily() {
68 return this._socket === null ? undefined : this._socket.remoteFamily
69 }
70
71 connect(...args) {
72 let opts = {}
73 let onconnect
74
75 if (typeof args[0] === 'string') {
76 // connect(path[, onconnect])
77 opts.path = args[0]
78 onconnect = args[1]
79 } else if (typeof args[0] === 'number') {
80 // connect(port[, host][, onconnect])
81 opts.port = args[0]
82
83 if (typeof args[1] === 'function') {
84 onconnect = args[1]
85 } else {
86 opts.host = args[1]
87 onconnect = args[2]
88 }
89 } else {
90 // connect(opts[, onconnect])
91 opts = args[0] || {}
92 onconnect = args[1]
93 }
94
95 opts = { ...opts, ...this._opts }
96
97 if (opts.path) {
98 this._attach(constants.type.IPC, pipe.createConnection(opts))
99 } else {
100 this._attach(constants.type.TCP, tcp.createConnection(opts))
101 }
102
103 if (onconnect) this.once('connect', onconnect)
104
105 return this
106 }
107
108 setKeepAlive(...args) {
109 if (this._socket !== null) this._socket.setKeepAlive(...args)
110 return this
111 }
112
113 setNoDelay(...args) {
114 if (this._socket !== null) this._socket.setNoDelay(...args)
115 return this
116 }
117
118 setTimeout(...args) {
119 if (this._socket !== null) this._socket.setTimeout(...args)
120 return this
121 }
122
123 ref() {
124 this._state &= ~constants.state.UNREFED
125 if (this._socket !== null) this._socket.ref()
126 return this
127 }
128
129 unref() {
130 this._state |= constants.state.UNREFED
131 if (this._socket !== null) this._socket.unref()
132 return this
133 }
134
135 _attach(type, socket) {
136 this._type = type
137 this._socket = socket
138
139 this._socket
140 .on('connect', this._onconnect.bind(this))
141 .on('timeout', this._ontimeout.bind(this))
142 .on('error', this._onerror.bind(this))
143 .on('data', this._ondata.bind(this))
144 .on('end', this._onend.bind(this))
145 .on('finish', this._onfinish.bind(this))
146 .on('drain', this._ondrain.bind(this))
147 .on('close', this._onclose.bind(this))
148
149 if (this._state & constants.state.UNREFED) this._socket.unref()
150
151 this._continueOpen()
152
153 return this
154 }
155
156 _open(cb) {
157 if (this._socket !== null) return cb(null)
158 this._pendingOpen = cb
159 }
160
161 _write(data, encoding, cb) {
162 if (this._socket.write(data)) return cb(null)
163 this._pendingWrite = cb
164 }
165
166 _final(cb) {
167 this._socket.end()
168 this._pendingFinal = cb
169 }
170
171 _destroy(err, cb) {
172 if (this._socket === null || this._socket.destroyed) return cb(null)
173
174 this._socket.destroy(err)
175 this._pendingDestroy = cb
176 }
177
178 _onconnect() {
179 this.emit('connect')
180 }
181
182 _ontimeout() {
183 this.emit('timeout')
184 }
185
186 _onerror(err) {
187 this.destroy(err)
188 }
189
190 _ondata(data) {
191 this.push(data)
192 }
193
194 _onend() {
195 this.push(null)
196 }
197
198 _onfinish() {
199 this._continueFinal()
200 }
201
202 _ondrain() {
203 this._continueWrite()
204 }
205
206 _onclose() {
207 this._continueWrite()
208 this._continueFinal()
209
210 if (this._pendingDestroy) this._continueDestroy()
211 else this.destroy()
212 }
213
214 _continueOpen() {
215 if (this._pendingOpen === null) return
216 const cb = this._pendingOpen
217 this._pendingOpen = null
218 cb(null)
219 }
220
221 _continueWrite() {
222 if (this._pendingWrite === null) return
223 const cb = this._pendingWrite
224 this._pendingWrite = null
225 cb(null)
226 }
227
228 _continueFinal() {
229 if (this._pendingFinal === null) return
230 const cb = this._pendingFinal
231 this._pendingFinal = null
232 cb(null)
233 }
234
235 _continueDestroy() {
236 if (this._pendingDestroy === null) return
237 const cb = this._pendingDestroy
238 this._pendingDestroy = null
239 cb(null)
240 }
241}
242
243exports.Server = class NetServer extends EventEmitter {
244 constructor(opts = {}, onconnection) {
245 if (typeof opts === 'function') {
246 onconnection = opts
247 opts = {}
248 }
249
250 super()
251
252 const {
253 readBufferSize = defaultReadBufferSize,
254 allowHalfOpen = false,
255 pauseOnConnect = false
256 } = opts
257
258 this._type = 0
259 this._state = 0
260 this._server = null
261
262 this._opts = { readBufferSize, allowHalfOpen, pauseOnConnect }
263
264 if (onconnection) this.on('connection', onconnection)
265 }
266
267 get listening() {
268 return this._server !== null && this._server.listening
269 }
270
271 address() {
272 return this._server === null ? null : this._server.address()
273 }
274
275 listen(...args) {
276 let opts = {}
277 let onlistening
278
279 if (typeof args[0] === 'string') {
280 // listen(path[, backlog][, onlistening])
281 opts.path = args[0]
282
283 if (typeof args[1] === 'function') {
284 onlistening = args[1]
285 } else {
286 opts.backlog = args[1]
287 onlistening = args[2]
288 }
289 } else {
290 // listen([port[, host[, backlog]]][, onlistening])
291 if (typeof args[0] === 'function') {
292 onlistening = args[0]
293 } else {
294 opts.port = args[0]
295
296 if (typeof args[1] === 'function') {
297 onlistening = args[1]
298 } else {
299 opts.host = args[1]
300
301 if (typeof args[2] === 'function') {
302 onlistening = args[2]
303 } else {
304 opts.backlog = args[2]
305 onlistening = args[3]
306 }
307 }
308 }
309 }
310
311 opts = { ...opts, ...this._opts }
312
313 if (opts.path) {
314 this._attach(constants.type.IPC, pipe.createServer(opts))
315 } else {
316 this._attach(constants.type.TCP, tcp.createServer(opts))
317 }
318
319 this._server.listen(opts)
320
321 if (onlistening) this.once('listening', onlistening)
322
323 return this
324 }
325
326 close(onclose) {
327 if (onclose) this.once('close', onclose)
328 this._server.close()
329 return this
330 }
331
332 ref() {
333 this._state &= ~constants.state.UNREFED
334 if (this._server !== null) this._server.ref()
335 return this
336 }
337
338 unref() {
339 this._state |= constants.state.UNREFED
340 if (this._server !== null) this._server.unref()
341 return this
342 }
343
344 _attach(type, server) {
345 this._type = type
346 this._server = server
347
348 this._server
349 .on('listening', this._onlistening.bind(this))
350 .on('connection', this._onconnection.bind(this))
351 .on('error', this._onerror.bind(this))
352 .on('close', this._onclose.bind(this))
353
354 if (this._state & constants.state.UNREFED) this._server.unref()
355
356 return this
357 }
358
359 _onlistening() {
360 this.emit('listening')
361 }
362
363 _onconnection(socket) {
364 this.emit('connection', new exports.Socket(this._opts)._attach(this._type, socket))
365 }
366
367 _onerror(err) {
368 this.emit('error', err)
369 }
370
371 _onclose() {
372 this.emit('close')
373 }
374}
375
376exports.constants = constants
377
378exports.isIP = tcp.isIP
379exports.isIPv4 = tcp.isIPv4
380exports.isIPv6 = tcp.isIPv6
381
382exports.createConnection = function createConnection(...args) {
383 let opts = {}
384 let onconnect
385
386 if (typeof args[0] === 'string') {
387 // createConnection(path[, onconnect])
388 opts.path = args[0]
389 onconnect = args[1]
390 } else if (typeof args[0] === 'number') {
391 // createConnection(port[, host][, onconnect])
392 opts.port = args[0]
393
394 if (typeof args[1] === 'function') {
395 onconnect = args[1]
396 } else {
397 opts.host = args[1]
398 onconnect = args[2]
399 }
400 } else {
401 // createConnection(opts[, onconnect])
402 opts = args[0] || {}
403 onconnect = args[1]
404 }
405
406 return new exports.Socket(opts).connect(opts, onconnect)
407}
408
409// For Node.js compatibility
410exports.connect = exports.createConnection
411
412exports.createServer = function createServer(opts, onconnection) {
413 return new exports.Server(opts, onconnection)
414}
node_modules/bare-net/lib/constants.d.ts +6 -0
……@@ -0,0 +1,6 @@
1declare const constants: {
2 type: { TCP: 1; IPC: 2 }
3 state: { UNREFED: number }
4}
5
6export = constants
node_modules/bare-net/lib/constants.js +9 -0
……@@ -0,0 +1,9 @@
1module.exports = {
2 type: {
3 TCP: 1,
4 IPC: 2
5 },
6 state: {
7 UNREFED: 0x1
8 }
9}
node_modules/bare-net/package.json +45 -0
……@@ -0,0 +1,45 @@
1{
2 "name": "bare-net",
3 "version": "2.3.1",
4 "description": "TCP and IPC servers and clients for JavaScript",
5 "exports": {
6 "./package": "./package.json",
7 ".": {
8 "types": "./index.d.ts",
9 "default": "./index.js"
10 },
11 "./constants": {
12 "types": "./lib/constants.d.ts",
13 "default": "./lib/constants.js"
14 }
15 },
16 "files": [
17 "index.js",
18 "index.d.ts",
19 "lib"
20 ],
21 "scripts": {
22 "test": "prettier . --check && bare test.js"
23 },
24 "repository": {
25 "type": "git",
26 "url": "git+https://github.com/holepunchto/bare-net.git"
27 },
28 "author": "Holepunch",
29 "license": "Apache-2.0",
30 "bugs": {
31 "url": "https://github.com/holepunchto/bare-net/issues"
32 },
33 "homepage": "https://github.com/holepunchto/bare-net#readme",
34 "dependencies": {
35 "bare-events": "^2.2.2",
36 "bare-pipe": "^4.0.0",
37 "bare-stream": "^2.0.0",
38 "bare-tcp": "^2.0.0"
39 },
40 "devDependencies": {
41 "brittle": "^3.3.0",
42 "prettier": "^3.4.1",
43 "prettier-config-holepunch": "^2.0.0"
44 }
45}
node_modules/bare-stylize/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-stylize/README.md +20 -0
……@@ -0,0 +1,20 @@
1# bare-stylize
2
3Terminal string styling for JavaScript.
4
5```
6npm i bare-stylize
7```
8
9## Usage
10
11```js
12const stylize = require('bare-stylize')
13
14console.log(stylize('green', 'ok'))
15console.log(stylize(['bold', 'red'], 'error'))
16```
17
18## License
19
20Apache-2.0
node_modules/bare-stylize/index.js +36 -0
……@@ -0,0 +1,36 @@
1const escapes = require('bare-ansi-escapes')
2const process = require('bare-process')
3
4function getStylesMap() {
5 const stylesMap = {}
6
7 let style
8 for (const escape of Object.getOwnPropertyNames(escapes)) {
9 if (escape.startsWith('color')) {
10 style = escape[5].toLowerCase() + escape.slice(6)
11 } else if (escape.startsWith('modifier')) {
12 style = escape[8].toLowerCase() + escape.slice(9)
13 } else {
14 continue
15 }
16
17 stylesMap[style] = escapes[escape]
18 }
19
20 return stylesMap
21}
22
23const stylesMap = getStylesMap()
24
25module.exports = function stylize(styles, text, opts = {}) {
26 const validateStream = opts.validateStream ?? true
27 const stream = opts.stream ?? process.stdout
28
29 if (!validateStream || !stream.isTTY) return text
30
31 if (typeof styles === 'string') styles = [styles]
32
33 const code = styles.map((style) => stylesMap[style]).join('')
34
35 return code + text + escapes.modifierReset
36}
node_modules/bare-stylize/package.json +36 -0
……@@ -0,0 +1,36 @@
1{
2 "name": "bare-stylize",
3 "version": "0.0.1",
4 "description": "Terminal string styling for JavaScript",
5 "exports": {
6 "./package": "./package.json",
7 ".": {
8 "default": "./index.js"
9 }
10 },
11 "files": [
12 "index.js"
13 ],
14 "scripts": {
15 "test": "prettier . --check && bare test.js"
16 },
17 "repository": {
18 "type": "git",
19 "url": "git+https://github.com/holepunchto/bare-stylize.git"
20 },
21 "author": "Holepunch",
22 "license": "Apache-2.0",
23 "bugs": {
24 "url": "https://github.com/holepunchto/bare-stylize/issues"
25 },
26 "homepage": "https://github.com/holepunchto/bare-stylize#readme",
27 "dependencies": {
28 "bare-ansi-escapes": "^2.2.3",
29 "bare-process": "^4.2.1"
30 },
31 "devDependencies": {
32 "brittle": "^3.3.2",
33 "prettier": "^3.4.2",
34 "prettier-config-holepunch": "^2.0.0"
35 }
36}
node_modules/bare-subprocess/CMakeLists.txt +13 -0
……@@ -0,0 +1,13 @@
1cmake_minimum_required(VERSION 3.25)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4
5project(bare_subprocess C)
6
7add_bare_module(bare_subprocess)
8
9target_sources(
10 ${bare_subprocess}
11 PRIVATE
12 binding.c
13)
node_modules/bare-subprocess/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-subprocess/README.md +23 -0
……@@ -0,0 +1,23 @@
1# bare-subprocess
2
3Native process spawning for JavaScript.
4
5```
6npm i bare-subprocess
7```
8
9## Usage
10
11```js
12const { spawn } = require('bare-subprocess')
13
14const subprocess = spawn('echo', ['hello', 'world'], {
15 stdio: 'inherit'
16})
17
18subprocess.on('exit', () => console.log('done'))
19```
20
21## License
22
23Apache-2.0
node_modules/bare-subprocess/binding.c +725 -0
……@@ -0,0 +1,725 @@
1#include <assert.h>
2#include <bare.h>
3#include <js.h>
4#include <stdlib.h>
5#include <utf.h>
6#include <uv.h>
7
8typedef struct {
9 uv_process_t handle;
10
11 js_env_t *env;
12 js_ref_t *ctx;
13 js_ref_t *on_exit;
14
15 bool killed;
16 bool exiting;
17
18 js_deferred_teardown_t *teardown;
19} bare_subprocess_t;
20
21typedef struct {
22 uv_pipe_t pipe;
23 uv_buf_t read;
24 size_t written;
25} bare_subprocess_buffered_pipe_t;
26
27typedef utf8_t bare_subprocess_path_t[4096 + 1 /* NULL */];
28
29static void
30bare_subprocess__on_close(uv_handle_t *handle) {
31 int err;
32
33 bare_subprocess_t *subprocess = (bare_subprocess_t *) handle;
34
35 js_env_t *env = subprocess->env;
36
37 js_deferred_teardown_t *teardown = subprocess->teardown;
38
39 err = js_delete_reference(env, subprocess->on_exit);
40 assert(err == 0);
41
42 err = js_delete_reference(env, subprocess->ctx);
43 assert(err == 0);
44
45 err = js_finish_deferred_teardown_callback(teardown);
46 assert(err == 0);
47}
48
49static void
50bare_subprocess__on_exit(uv_process_t *handle, int64_t exit_status, int term_signal) {
51 int err;
52
53 bare_subprocess_t *subprocess = (bare_subprocess_t *) handle;
54
55 subprocess->killed = true;
56
57 if (subprocess->exiting) goto close;
58
59 js_env_t *env = subprocess->env;
60
61 js_handle_scope_t *scope;
62 err = js_open_handle_scope(env, &scope);
63 assert(err == 0);
64
65 js_value_t *ctx;
66 err = js_get_reference_value(env, subprocess->ctx, &ctx);
67 assert(err == 0);
68
69 js_value_t *on_exit;
70 err = js_get_reference_value(env, subprocess->on_exit, &on_exit);
71 assert(err == 0);
72
73 js_value_t *argv[2];
74
75 err = js_create_int64(env, exit_status, &argv[0]);
76 assert(err == 0);
77
78 err = js_create_int32(env, term_signal, &argv[1]);
79 assert(err == 0);
80
81 js_call_function(env, ctx, on_exit, 2, argv, NULL);
82
83 err = js_close_handle_scope(env, scope);
84 assert(err == 0);
85
86close:
87 uv_close((uv_handle_t *) &subprocess->handle, bare_subprocess__on_close);
88}
89
90static void
91bare_subprocess__on_teardown(js_deferred_teardown_t *handle, void *data) {
92 int err;
93
94 bare_subprocess_t *subprocess = (bare_subprocess_t *) data;
95
96 subprocess->exiting = true;
97
98 if (subprocess->killed) return;
99
100 err = uv_process_kill(&subprocess->handle, SIGTERM);
101 assert(err == 0);
102}
103
104static void
105bare_subprocess__on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
106 bare_subprocess_buffered_pipe_t *pipe = (bare_subprocess_buffered_pipe_t *) handle;
107
108 *buf = pipe->read;
109}
110
111static void
112bare_subprocess__on_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
113 if (nread == 0) return;
114
115 if (nread == UV_EOF) {
116 uv_close((uv_handle_t *) stream, NULL);
117 } else {
118 int err;
119
120 bare_subprocess_buffered_pipe_t *pipe = (bare_subprocess_buffered_pipe_t *) stream;
121
122 pipe->read.base += nread;
123 pipe->read.len -= nread;
124
125 pipe->written += nread;
126 }
127}
128
129static js_value_t *
130bare_subprocess_init(js_env_t *env, js_callback_info_t *info) {
131 int err;
132
133 size_t argc = 2;
134 js_value_t *argv[2];
135
136 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
137 assert(err == 0);
138
139 assert(argc == 2);
140
141 js_value_t *handle;
142
143 bare_subprocess_t *subprocess;
144 err = js_create_arraybuffer(env, sizeof(bare_subprocess_t), (void **) &subprocess, &handle);
145 assert(err == 0);
146
147 subprocess->env = env;
148 subprocess->killed = false;
149 subprocess->exiting = false;
150
151 err = js_create_reference(env, argv[0], 1, &subprocess->ctx);
152 assert(err == 0);
153
154 err = js_create_reference(env, argv[1], 1, &subprocess->on_exit);
155 assert(err == 0);
156
157 err = js_add_deferred_teardown_callback(env, bare_subprocess__on_teardown, (void *) subprocess, &subprocess->teardown);
158 assert(err == 0);
159
160 return handle;
161}
162
163static js_value_t *
164bare_subprocess_spawn(js_env_t *env, js_callback_info_t *info) {
165 int err;
166
167 size_t argc = 11;
168 js_value_t *argv[11];
169
170 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
171 assert(err == 0);
172
173 assert(argc == 11);
174
175 uv_loop_t *loop;
176 err = js_get_env_loop(env, &loop);
177 assert(err == 0);
178
179 bare_subprocess_t *subprocess;
180 err = js_get_arraybuffer_info(env, argv[0], (void **) &subprocess, NULL);
181 assert(err == 0);
182
183 bare_subprocess_path_t file;
184 err = js_get_value_string_utf8(env, argv[1], file, sizeof(bare_subprocess_path_t), NULL);
185 assert(err == 0);
186
187 uint32_t args_len;
188 err = js_get_array_length(env, argv[2], &args_len);
189 assert(err == 0);
190
191 utf8_t **args = calloc(1 /* file */ + args_len + 1 /* NULL */, sizeof(utf8_t *));
192
193 args[0] = file;
194
195 for (uint32_t i = 0; i < args_len; i++) {
196 js_value_t *value;
197 err = js_get_element(env, argv[2], i, &value);
198 assert(err == 0);
199
200 size_t arg_len;
201 err = js_get_value_string_utf8(env, value, NULL, 0, &arg_len);
202 assert(err == 0);
203
204 arg_len += 1 /* NULL */;
205
206 utf8_t *arg = malloc(arg_len);
207 err = js_get_value_string_utf8(env, value, arg, arg_len, NULL);
208 assert(err == 0);
209
210 args[i + 1] = arg;
211 }
212
213 bare_subprocess_path_t cwd;
214 err = js_get_value_string_utf8(env, argv[3], cwd, sizeof(bare_subprocess_path_t), NULL);
215 assert(err == 0);
216
217 uint32_t pairs_len;
218 err = js_get_array_length(env, argv[4], &pairs_len);
219 assert(err == 0);
220
221 utf8_t **pairs = calloc(pairs_len + 1 /* NULL */, sizeof(utf8_t *));
222
223 for (uint32_t i = 0; i < pairs_len; i++) {
224 js_value_t *value;
225 err = js_get_element(env, argv[4], i, &value);
226 assert(err == 0);
227
228 size_t pair_len;
229 err = js_get_value_string_utf8(env, value, NULL, 0, &pair_len);
230 assert(err == 0);
231
232 pair_len += 1 /* NULL */;
233
234 utf8_t *pair = malloc(pair_len);
235 err = js_get_value_string_utf8(env, value, pair, pair_len, NULL);
236 assert(err == 0);
237
238 pairs[i] = pair;
239 }
240
241 uint32_t stdio_len;
242 err = js_get_array_length(env, argv[5], &stdio_len);
243 assert(err == 0);
244
245 uv_stdio_container_t *stdio = malloc(stdio_len * sizeof(uv_stdio_container_t));
246
247 for (uint32_t i = 0; i < stdio_len; i++) {
248 js_value_t *value;
249 err = js_get_element(env, argv[5], i, &value);
250 assert(err == 0);
251
252 js_value_t *property;
253
254 err = js_get_named_property(env, value, "flags", &property);
255 assert(err == 0);
256
257 uint32_t flags;
258 err = js_get_value_uint32(env, property, &flags);
259 assert(err == 0);
260
261 stdio[i] = (uv_stdio_container_t) {
262 .flags = flags,
263 };
264
265 if (flags & UV_INHERIT_FD) {
266 err = js_get_named_property(env, value, "fd", &property);
267 assert(err == 0);
268
269 uint32_t fd;
270 err = js_get_value_uint32(env, property, &fd);
271 assert(err == 0);
272
273 stdio[i].data.fd = fd;
274 }
275
276 if (flags & UV_CREATE_PIPE) {
277 err = js_get_named_property(env, value, "pipe", &property);
278 assert(err == 0);
279
280 uv_stream_t *pipe;
281 err = js_get_arraybuffer_info(env, property, (void **) &pipe, NULL);
282 assert(err == 0);
283
284 stdio[i].data.stream = pipe;
285 }
286 }
287
288 bool detached;
289 err = js_get_value_bool(env, argv[6], &detached);
290 assert(err == 0);
291
292 int32_t uid;
293 err = js_get_value_int32(env, argv[7], &uid);
294 assert(err == 0);
295
296 int32_t gid;
297 err = js_get_value_int32(env, argv[8], &gid);
298 assert(err == 0);
299
300 bool windows_hide;
301 err = js_get_value_bool(env, argv[9], &windows_hide);
302 assert(err == 0);
303
304 bool windows_verbatim_arguments;
305 err = js_get_value_bool(env, argv[10], &windows_verbatim_arguments);
306 assert(err == 0);
307
308 int flags = UV_PROCESS_WINDOWS_HIDE_CONSOLE;
309
310 if (detached) flags |= UV_PROCESS_DETACHED;
311 if (uid != -1) flags |= UV_PROCESS_SETUID;
312 if (gid != -1) flags |= UV_PROCESS_SETGID;
313 if (windows_hide) flags |= UV_PROCESS_WINDOWS_HIDE;
314 if (windows_verbatim_arguments) flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
315
316 uv_process_options_t opts = {
317 .exit_cb = bare_subprocess__on_exit,
318 .file = (char *) file,
319 .args = (char **) args,
320 .env = (char **) pairs,
321 .cwd = (char *) cwd,
322 .flags = flags,
323 .stdio_count = stdio_len,
324 .stdio = stdio,
325 .uid = uid,
326 .gid = gid,
327 };
328
329 err = uv_spawn(loop, &subprocess->handle, &opts);
330
331 js_value_t *pid = NULL;
332
333 if (err < 0) {
334 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
335 assert(err == 0);
336 } else {
337 err = js_create_uint32(env, subprocess->handle.pid, &pid);
338 assert(err == 0);
339 }
340
341 for (uint32_t i = 0; i < args_len; i++) {
342 free(args[i + 1]);
343 }
344
345 for (uint32_t i = 0; i < pairs_len; i++) {
346 free(pairs[i]);
347 }
348
349 free(args);
350 free(pairs);
351 free(stdio);
352
353 return pid;
354}
355
356static js_value_t *
357bare_subprocess_spawn_sync(js_env_t *env, js_callback_info_t *info) {
358 int err;
359
360 size_t argc = 11;
361 js_value_t *argv[11];
362
363 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
364 assert(err == 0);
365
366 assert(argc == 11);
367
368 uv_loop_t loop;
369 err = uv_loop_init(&loop);
370 assert(err == 0);
371
372 bare_subprocess_t *subprocess;
373 err = js_get_arraybuffer_info(env, argv[0], (void **) &subprocess, NULL);
374 assert(err == 0);
375
376 bare_subprocess_path_t file;
377 err = js_get_value_string_utf8(env, argv[1], file, sizeof(bare_subprocess_path_t), NULL);
378 assert(err == 0);
379
380 uint32_t args_len;
381 err = js_get_array_length(env, argv[2], &args_len);
382 assert(err == 0);
383
384 utf8_t **args = calloc(1 /* file */ + args_len + 1 /* NULL */, sizeof(utf8_t *));
385
386 args[0] = file;
387
388 for (uint32_t i = 0; i < args_len; i++) {
389 js_value_t *value;
390 err = js_get_element(env, argv[2], i, &value);
391 assert(err == 0);
392
393 size_t arg_len;
394 err = js_get_value_string_utf8(env, value, NULL, 0, &arg_len);
395 assert(err == 0);
396
397 arg_len += 1 /* NULL */;
398
399 utf8_t *arg = malloc(arg_len);
400 err = js_get_value_string_utf8(env, value, arg, arg_len, NULL);
401 assert(err == 0);
402
403 args[i + 1] = arg;
404 }
405
406 bare_subprocess_path_t cwd;
407 err = js_get_value_string_utf8(env, argv[3], cwd, sizeof(bare_subprocess_path_t), NULL);
408 assert(err == 0);
409
410 uint32_t pairs_len;
411 err = js_get_array_length(env, argv[4], &pairs_len);
412 assert(err == 0);
413
414 utf8_t **pairs = calloc(pairs_len + 1 /* NULL */, sizeof(utf8_t *));
415
416 for (uint32_t i = 0; i < pairs_len; i++) {
417 js_value_t *value;
418 err = js_get_element(env, argv[4], i, &value);
419 assert(err == 0);
420
421 size_t pair_len;
422 err = js_get_value_string_utf8(env, value, NULL, 0, &pair_len);
423 assert(err == 0);
424
425 pair_len += 1 /* NULL */;
426
427 utf8_t *pair = malloc(pair_len);
428 err = js_get_value_string_utf8(env, value, pair, pair_len, NULL);
429 assert(err == 0);
430
431 pairs[i] = pair;
432 }
433
434 uint32_t stdio_len;
435 err = js_get_array_length(env, argv[5], &stdio_len);
436 assert(err == 0);
437
438 uv_stdio_container_t *stdio = malloc(stdio_len * sizeof(uv_stdio_container_t));
439
440 for (uint32_t i = 0; i < stdio_len; i++) {
441 js_value_t *value;
442 err = js_get_element(env, argv[5], i, &value);
443 assert(err == 0);
444
445 js_value_t *property;
446
447 err = js_get_named_property(env, value, "flags", &property);
448 assert(err == 0);
449
450 uint32_t flags;
451 err = js_get_value_uint32(env, property, &flags);
452 assert(err == 0);
453
454 stdio[i] = (uv_stdio_container_t) {
455 .flags = flags,
456 };
457
458 if (flags & UV_INHERIT_FD) {
459 err = js_get_named_property(env, value, "fd", &property);
460 assert(err == 0);
461
462 uint32_t fd;
463 err = js_get_value_uint32(env, property, &fd);
464 assert(err == 0);
465
466 stdio[i].data.fd = fd;
467 }
468
469 if (flags & UV_CREATE_PIPE) {
470 err = js_get_named_property(env, value, "buffer", &property);
471 assert(err == 0);
472
473 bare_subprocess_buffered_pipe_t *pipe = malloc(sizeof(bare_subprocess_buffered_pipe_t));
474
475 pipe->written = 0;
476
477 err = uv_pipe_init(&loop, (uv_pipe_t *) pipe, false);
478 assert(err == 0);
479
480 err = js_get_typedarray_info(env, property, NULL, (void **) &pipe->read.base, (size_t *) &pipe->read.len, NULL, NULL);
481 assert(err == 0);
482
483 stdio[i].data.stream = (uv_stream_t *) pipe;
484 }
485 }
486
487 bool detached;
488 err = js_get_value_bool(env, argv[6], &detached);
489 assert(err == 0);
490
491 int32_t uid;
492 err = js_get_value_int32(env, argv[7], &uid);
493 assert(err == 0);
494
495 int32_t gid;
496 err = js_get_value_int32(env, argv[8], &gid);
497 assert(err == 0);
498
499 bool windows_hide;
500 err = js_get_value_bool(env, argv[9], &windows_hide);
501 assert(err == 0);
502
503 bool windows_verbatim_arguments;
504 err = js_get_value_bool(env, argv[10], &windows_verbatim_arguments);
505 assert(err == 0);
506
507 int flags = UV_PROCESS_WINDOWS_HIDE_CONSOLE;
508
509 if (detached) flags |= UV_PROCESS_DETACHED;
510 if (uid != -1) flags |= UV_PROCESS_SETUID;
511 if (gid != -1) flags |= UV_PROCESS_SETGID;
512 if (windows_hide) flags |= UV_PROCESS_WINDOWS_HIDE;
513 if (windows_verbatim_arguments) flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
514
515 uv_process_options_t opts = {
516 .exit_cb = bare_subprocess__on_exit,
517 .file = (char *) file,
518 .args = (char **) args,
519 .env = (char **) pairs,
520 .cwd = (char *) cwd,
521 .flags = flags,
522 .stdio_count = stdio_len,
523 .stdio = stdio,
524 .uid = uid,
525 .gid = gid,
526 };
527
528 err = uv_spawn(&loop, &subprocess->handle, &opts);
529
530 js_value_t *pid = NULL;
531
532 int throw = err;
533
534 if (throw < 0) {
535 uv_close((uv_handle_t *) &subprocess->handle, bare_subprocess__on_close);
536
537 for (uint32_t i = 0; i < stdio_len; i++) {
538 if (stdio[i].flags & UV_CREATE_PIPE) {
539 bare_subprocess_buffered_pipe_t *pipe = (bare_subprocess_buffered_pipe_t *) stdio[i].data.stream;
540
541 uv_close((uv_handle_t *) pipe, NULL);
542 }
543 }
544 } else {
545 for (uint32_t i = 0; i < stdio_len; i++) {
546 if (stdio[i].flags & UV_CREATE_PIPE) {
547 bare_subprocess_buffered_pipe_t *pipe = (bare_subprocess_buffered_pipe_t *) stdio[i].data.stream;
548
549 err = uv_read_start((uv_stream_t *) pipe, bare_subprocess__on_alloc, bare_subprocess__on_read);
550 assert(err == 0);
551 }
552 }
553
554 err = js_create_uint32(env, subprocess->handle.pid, &pid);
555 assert(err == 0);
556 }
557
558 err = uv_run(&loop, UV_RUN_DEFAULT);
559 assert(err == 0);
560
561 for (uint32_t i = 0; i < stdio_len; i++) {
562 js_value_t *value;
563 err = js_get_element(env, argv[5], i, &value);
564 assert(err == 0);
565
566 js_value_t *property;
567
568 if (stdio[i].flags & UV_CREATE_PIPE) {
569 bare_subprocess_buffered_pipe_t *pipe = (bare_subprocess_buffered_pipe_t *) stdio[i].data.stream;
570
571 js_value_t *written;
572 err = js_create_int64(env, pipe->written, &written);
573 assert(err == 0);
574
575 err = js_set_named_property(env, value, "written", written);
576 assert(err == 0);
577
578 free(pipe);
579 }
580 }
581
582 err = uv_loop_close(&loop);
583 assert(err == 0);
584
585 for (uint32_t i = 0; i < args_len; i++) {
586 free(args[i + 1]);
587 }
588
589 for (uint32_t i = 0; i < pairs_len; i++) {
590 free(pairs[i]);
591 }
592
593 free(args);
594 free(pairs);
595 free(stdio);
596
597 if (throw < 0) {
598 err = js_throw_error(env, uv_err_name(throw), uv_strerror(throw));
599 assert(err == 0);
600
601 return NULL;
602 }
603
604 return pid;
605}
606
607static js_value_t *
608bare_subprocess_kill(js_env_t *env, js_callback_info_t *info) {
609 int err;
610
611 size_t argc = 2;
612 js_value_t *argv[2];
613
614 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
615 assert(err == 0);
616
617 assert(argc == 2);
618
619 bare_subprocess_t *subprocess;
620 err = js_get_arraybuffer_info(env, argv[0], (void **) &subprocess, NULL);
621 assert(err == 0);
622
623 if (subprocess->killed) return NULL;
624
625 uint32_t signum;
626 err = js_get_value_uint32(env, argv[1], &signum);
627 assert(err == 0);
628
629 subprocess->killed = true;
630
631 err = uv_process_kill(&subprocess->handle, signum);
632
633 if (err < 0) {
634 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
635 assert(err == 0);
636 }
637
638 return NULL;
639}
640
641static js_value_t *
642bare_subprocess_ref(js_env_t *env, js_callback_info_t *info) {
643 int err;
644
645 size_t argc = 1;
646 js_value_t *argv[1];
647
648 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
649 assert(err == 0);
650
651 assert(argc == 1);
652
653 bare_subprocess_t *subprocess;
654 err = js_get_arraybuffer_info(env, argv[0], (void **) &subprocess, NULL);
655 assert(err == 0);
656
657 uv_ref((uv_handle_t *) &subprocess->handle);
658
659 return NULL;
660}
661
662static js_value_t *
663bare_subprocess_unref(js_env_t *env, js_callback_info_t *info) {
664 int err;
665
666 size_t argc = 1;
667 js_value_t *argv[1];
668
669 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
670 assert(err == 0);
671
672 assert(argc == 1);
673
674 bare_subprocess_t *subprocess;
675 err = js_get_arraybuffer_info(env, argv[0], (void **) &subprocess, NULL);
676 assert(err == 0);
677
678 uv_unref((uv_handle_t *) &subprocess->handle);
679
680 return NULL;
681}
682
683static js_value_t *
684bare_subprocess_exports(js_env_t *env, js_value_t *exports) {
685 int err;
686
687#define V(name, fn) \
688 { \
689 js_value_t *val; \
690 err = js_create_function(env, name, -1, fn, NULL, &val); \
691 assert(err == 0); \
692 err = js_set_named_property(env, exports, name, val); \
693 assert(err == 0); \
694 }
695
696 V("init", bare_subprocess_init)
697 V("spawn", bare_subprocess_spawn)
698 V("spawnSync", bare_subprocess_spawn_sync)
699 V("kill", bare_subprocess_kill)
700 V("ref", bare_subprocess_ref)
701 V("unref", bare_subprocess_unref)
702#undef V
703
704#define V(name) \
705 { \
706 js_value_t *val; \
707 err = js_create_uint32(env, name, &val); \
708 assert(err == 0); \
709 err = js_set_named_property(env, exports, #name, val); \
710 assert(err == 0); \
711 }
712
713 V(UV_IGNORE)
714 V(UV_CREATE_PIPE)
715 V(UV_INHERIT_FD)
716 V(UV_INHERIT_STREAM)
717 V(UV_READABLE_PIPE)
718 V(UV_WRITABLE_PIPE)
719 V(UV_NONBLOCK_PIPE)
720#undef V
721
722 return exports;
723}
724
725BARE_MODULE(bare_subprocess, bare_subprocess_exports)
node_modules/bare-subprocess/binding.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon()
node_modules/bare-subprocess/index.d.ts +79 -0
……@@ -0,0 +1,79 @@
1import EventEmitter, { EventMap } from 'bare-events'
2import Buffer from 'bare-buffer'
3import Pipe from 'bare-pipe'
4import constants from './lib/constants'
5import errors from './lib/errors'
6
7export { constants, errors }
8
9export interface SubprocessEvents extends EventMap {
10 exit: [code: number, signalCode: string]
11}
12
13export type IO = 'inherit' | 'pipe' | 'overlapped' | 'ignore'
14
15export interface Subprocess<M extends SubprocessEvents = SubprocessEvents> extends EventEmitter<M> {
16 readonly exitCode: number | null
17 readonly killed: boolean
18 readonly pid: number
19 readonly signalCode: string | null
20 readonly spawnargs: string[]
21 readonly spawnfile: string
22 readonly stdio: (Pipe | null)[]
23 readonly stdin: Pipe | null
24 readonly stdout: Pipe | null
25 readonly stderr: Pipe | null
26
27 ref(): void
28 unref(): void
29
30 kill(signum?: number): void
31}
32
33export class Subprocess {}
34
35export interface SpawnOptions {
36 cwd?: string
37 stdio?: [stdin?: IO, stdout?: IO, stderr?: IO, ...fds: IO[]] | IO | null
38 shell?: boolean | string
39 detached?: boolean
40 uid?: number
41 gid?: number
42 env?: Record<string, string>
43 windowsHide?: boolean
44 windowsVerbatimArguments?: boolean
45}
46
47export function spawn(file: string, args?: string[] | null, opts?: SpawnOptions): Subprocess
48
49export function spawn(file: string, opts?: SpawnOptions): Subprocess
50
51export interface SpawnSyncOptions extends SpawnOptions {
52 input?: string | Buffer
53 maxBuffer?: number
54}
55
56export function spawnSync(
57 file: string,
58 args?: string[] | null,
59 opts?: SpawnSyncOptions
60): {
61 output: (Buffer | null)[]
62 pid: number
63 signal: number
64 status: number
65 stderr: Buffer | null
66 stdout: Buffer | null
67}
68
69export function spawnSync(
70 file: string,
71 opts?: SpawnSyncOptions
72): {
73 output: (Buffer | null)[]
74 pid: number
75 signal: number
76 status: number
77 stderr: Buffer | null
78 stdout: Buffer | null
79}
node_modules/bare-subprocess/index.js +369 -0
……@@ -0,0 +1,369 @@
1const EventEmitter = require('bare-events')
2const Pipe = require('bare-pipe')
3const os = require('bare-os')
4const env = require('bare-env')
5const { isURL, fileURLToPath } = require('bare-url')
6const binding = require('./binding')
7const constants = require('./lib/constants')
8const errors = require('./lib/errors')
9
10exports.Subprocess = class Subprocess extends EventEmitter {
11 constructor() {
12 super()
13
14 this.spawnfile = null
15 this.spawnargs = []
16 this.pid = null
17 this.stdio = []
18 this.exitCode = null
19 this.signalCode = null
20 this.killed = false
21
22 this._closing = []
23 this._handle = binding.init(this, this._onexit)
24 }
25
26 _flush() {
27 for (const pipe of this.stdio) {
28 if (pipe && typeof pipe.resume === 'function') pipe.resume()
29 }
30 }
31
32 async _onexit(code, signal) {
33 this.exitCode = code
34 this.signalCode = signal
35
36 this.emit('exit', code, signal)
37
38 queueMicrotask(this._flush.bind(this)) // Defer to provide a last chance to consume
39
40 await Promise.all(this._closing)
41
42 this.emit('close', code, signal)
43 }
44
45 get stdin() {
46 return this.stdio[0] || null
47 }
48
49 get stdout() {
50 return this.stdio[1] || null
51 }
52
53 get stderr() {
54 return this.stdio[2] || null
55 }
56
57 ref() {
58 for (const pipe of this.stdio) {
59 if (pipe && typeof pipe.ref === 'function') pipe.ref()
60 }
61
62 binding.ref(this._handle)
63 }
64
65 unref() {
66 for (const pipe of this.stdio) {
67 if (pipe && typeof pipe.unref === 'function') pipe.unref()
68 }
69
70 binding.unref(this._handle)
71 }
72
73 kill(signum = constants.SIGTERM) {
74 if (typeof signum === 'string') {
75 if (signum in constants === false) {
76 throw errors.UNKNOWN_SIGNAL('Unknown signal: ' + signum)
77 }
78
79 signum = constants[signum]
80 }
81
82 binding.kill(this._handle, signum)
83
84 this.killed = true
85 }
86}
87
88exports.ChildProcess = exports.Subprocess // For Node.js compatibility
89
90exports.constants = constants
91exports.errors = errors
92
93exports.spawn = function spawn(file, args, opts) {
94 if (Array.isArray(args)) {
95 args = [...args]
96 } else if (args === null) {
97 args = []
98 } else {
99 opts = args
100 args = []
101 }
102
103 if (!opts) opts = {}
104
105 args = args.map(String)
106
107 let {
108 cwd = defaultCwd(),
109 env = defaultEnv(),
110 stdio = [],
111 detached = false,
112 shell = false,
113 uid = -1,
114 gid = -1,
115 windowsHide = false,
116 windowsVerbatimArguments = false
117 } = opts
118
119 file = toPath(file)
120 cwd = toPath(cwd)
121
122 if (shell) {
123 const command = [file, ...args].join(' ')
124
125 if (Bare.platform === 'win32') {
126 if (typeof shell === 'string') {
127 file = shell
128 } else {
129 file = env.comspec || 'cmd.exe'
130 }
131
132 if (/^(.*\\)?cmd(\.exe)?$/i.test(file)) {
133 args = ['/d', '/s', '/c', `"${command}"`]
134 windowsVerbatimArguments = true
135 } else {
136 args = ['-c', command]
137 }
138 } else {
139 if (typeof shell === 'string') {
140 file = shell
141 } else if (Bare.platform === 'android') {
142 file = '/system/bin/sh'
143 } else {
144 file = '/bin/sh'
145 }
146
147 args = ['-c', command]
148 }
149 }
150
151 const pairs = []
152
153 for (const [key, value] of Object.entries(env)) {
154 pairs.push(`${key}=${value}`)
155 }
156
157 if (Array.isArray(stdio)) {
158 stdio = [...stdio]
159 } else if (typeof stdio === 'string') {
160 stdio = [stdio, stdio, stdio]
161 } else {
162 stdio = []
163 }
164
165 const subprocess = new exports.Subprocess()
166
167 subprocess.spawnfile = file
168 subprocess.spawnargs = args
169
170 for (let i = 0, n = Math.max(3, stdio.length); i < n; i++) {
171 subprocess.stdio[i] = null
172
173 let fd = stdio[i] || 'pipe'
174
175 if (fd === 'inherit') fd = i < 3 ? i : 'ignore'
176
177 if (fd === 'ignore') {
178 stdio[i] = { flags: binding.UV_IGNORE }
179 } else if (fd === 'pipe' || fd === 'overlapped') {
180 const pipe = new Pipe()
181
182 pipe._onspawn(i !== 0 /* Readable */, i === 0 || i > 2 /* Writable */)
183
184 if (i > 0) {
185 subprocess._closing.push(new Promise((resolve) => pipe.once('close', resolve)))
186 }
187
188 let flags = binding.UV_CREATE_PIPE | binding.UV_READABLE_PIPE | binding.UV_WRITABLE_PIPE
189
190 if (fd === 'overlapped') flags |= binding.UV_NONBLOCK_PIPE
191
192 stdio[i] = { flags, pipe: pipe._handle }
193
194 subprocess.stdio[i] = pipe
195 } else {
196 stdio[i] = { flags: binding.UV_INHERIT_FD, fd }
197 }
198 }
199
200 subprocess.pid = binding.spawn(
201 subprocess._handle,
202 file,
203 args,
204 cwd,
205 pairs,
206 stdio,
207 detached,
208 uid,
209 gid,
210 windowsHide,
211 windowsVerbatimArguments
212 )
213
214 return subprocess
215}
216
217exports.spawnSync = function spawn(file, args, opts) {
218 if (Array.isArray(args)) {
219 args = [...args]
220 } else if (args === null) {
221 args = []
222 } else {
223 opts = args
224 args = []
225 }
226
227 if (!opts) opts = {}
228
229 let {
230 cwd = defaultCwd(),
231 env = defaultEnv(),
232 input = null,
233 stdio = [],
234 detached = false,
235 shell = false,
236 uid = -1,
237 gid = -1,
238 windowsHide = false,
239 windowsVerbatimArguments = false,
240 maxBuffer = 1024 * 1024
241 } = opts
242
243 file = toPath(file)
244 cwd = toPath(cwd)
245
246 if (shell) {
247 const command = [file, ...args].join(' ')
248
249 if (Bare.platform === 'win32') {
250 if (typeof shell === 'string') {
251 file = shell
252 } else {
253 file = env.comspec || 'cmd.exe'
254 }
255
256 if (/^(.*\\)?cmd(\.exe)?$/i.test(file)) {
257 args = ['/d', '/s', '/c', `"${command}"`]
258 windowsVerbatimArguments = true
259 } else {
260 args = ['-c', command]
261 }
262 } else {
263 if (typeof shell === 'string') {
264 file = shell
265 } else if (Bare.platform === 'android') {
266 file = '/system/bin/sh'
267 } else {
268 file = '/bin/sh'
269 }
270
271 args = ['-c', command]
272 }
273 }
274
275 const pairs = []
276
277 for (const [key, value] of Object.entries(env)) {
278 pairs.push(`${key}=${value}`)
279 }
280
281 if (Array.isArray(stdio)) {
282 stdio = [...stdio]
283 } else if (typeof stdio === 'string') {
284 stdio = [stdio, stdio, stdio]
285 } else {
286 stdio = []
287 }
288
289 const subprocess = new exports.Subprocess()
290
291 if (input) {
292 stdio[0] = {
293 flags: binding.UV_CREATE_PIPE | binding.UV_READABLE_PIPE,
294 buffer: input
295 }
296
297 subprocess.stdio[0] = null
298 }
299
300 for (let i = input ? 1 : 0, n = Math.max(3, stdio.length); i < n; i++) {
301 subprocess.stdio[i] = null
302
303 let fd = stdio[i] || 'pipe'
304
305 if (fd === 'inherit') fd = i < 3 ? i : 'ignore'
306
307 if (fd === 'ignore') {
308 stdio[i] = { flags: binding.UV_IGNORE }
309 } else if (fd === 'pipe') {
310 const buffer = Buffer.alloc(maxBuffer)
311
312 stdio[i] = {
313 flags: binding.UV_CREATE_PIPE | binding.UV_WRITABLE_PIPE,
314 buffer,
315 written: 0
316 }
317
318 if (i > 0) subprocess.stdio[i] = buffer
319 } else if (typeof fd === 'number') {
320 stdio[i] = { flags: binding.UV_INHERIT_FD, fd }
321 }
322 }
323
324 subprocess.pid = binding.spawnSync(
325 subprocess._handle,
326 file,
327 args,
328 cwd,
329 pairs,
330 stdio,
331 detached,
332 uid,
333 gid,
334 windowsHide,
335 windowsVerbatimArguments
336 )
337
338 for (let i = 1, n = stdio.length; i < n; i++) {
339 if (stdio[i].flags & binding.UV_WRITABLE_PIPE) {
340 subprocess.stdio[i] = subprocess.stdio[i].subarray(0, stdio[i].written)
341 }
342 }
343
344 return {
345 status: subprocess.exitCode,
346 signal: subprocess.signalCode,
347 output: subprocess.stdio,
348 pid: subprocess.pid,
349 stdout: subprocess.stdout,
350 stderr: subprocess.stderr
351 }
352}
353
354function defaultCwd() {
355 return os.cwd()
356}
357
358function defaultEnv() {
359 return env
360}
361
362function toPath(filepath) {
363 if (typeof filepath !== 'string') {
364 if (isURL(filepath)) filepath = fileURLToPath(filepath)
365 else filepath = filepath.toString()
366 }
367
368 return filepath
369}
node_modules/bare-subprocess/lib/constants.d.ts +3 -0
……@@ -0,0 +1,3 @@
1import os from 'bare-os'
2
3export = os.constants.signals
node_modules/bare-subprocess/lib/constants.js +3 -0
……@@ -0,0 +1,3 @@
1const os = require('bare-os')
2
3module.exports = os.constants.signals
node_modules/bare-subprocess/lib/errors.d.ts +7 -0
……@@ -0,0 +1,7 @@
1declare class SubprocessError extends Error {
2 readonly code: string
3
4 static UNKNOWN_SIGNAL(msg: string): SubprocessError
5}
6
7export = SubprocessError
node_modules/bare-subprocess/lib/errors.js +18 -0
……@@ -0,0 +1,18 @@
1module.exports = class SubprocessError extends Error {
2 constructor(msg, code, fn = SubprocessError) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'SubprocessError'
13 }
14
15 static UNKNOWN_SIGNAL(msg) {
16 return new SubprocessError(msg, 'UNKNOWN_SIGNAL', SubprocessError.UNKNOWN_SIGNAL)
17 }
18}
node_modules/bare-subprocess/package.json +72 -0
……@@ -0,0 +1,72 @@
1{
2 "name": "bare-subprocess",
3 "version": "5.2.3",
4 "description": "Native process spawning for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json",
11 "./constants": {
12 "types": "./lib/constants.d.ts",
13 "default": "./lib/constants.js"
14 },
15 "./errors": {
16 "types": "./lib/errors.d.ts",
17 "default": "./lib/errors.js"
18 }
19 },
20 "files": [
21 "index.js",
22 "index.d.ts",
23 "binding.c",
24 "binding.js",
25 "CMakeLists.txt",
26 "lib",
27 "prebuilds"
28 ],
29 "addon": true,
30 "scripts": {
31 "test": "prettier . --check && bare test.js"
32 },
33 "repository": {
34 "type": "git",
35 "url": "git+https://github.com/holepunchto/bare-subprocess.git"
36 },
37 "author": "Holepunch",
38 "license": "Apache-2.0",
39 "bugs": {
40 "url": "https://github.com/holepunchto/bare-subprocess/issues"
41 },
42 "homepage": "https://github.com/holepunchto/bare-subprocess#readme",
43 "engines": {
44 "bare": ">=1.7.0"
45 },
46 "dependencies": {
47 "bare-env": "^3.0.0",
48 "bare-events": "^2.5.4",
49 "bare-os": "^3.0.1",
50 "bare-pipe": "^4.0.0",
51 "bare-url": "^2.2.2"
52 },
53 "devDependencies": {
54 "bare-abort": "^2.0.13",
55 "bare-assert": "^1.0.2",
56 "bare-buffer": "^3.0.2",
57 "bare-fs": "^4.1.2",
58 "bare-path": "^3.0.0",
59 "brittle": "^3.2.1",
60 "cmake-bare": "^1.1.7",
61 "prettier": "^3.4.1",
62 "prettier-config-holepunch": "^2.0.0"
63 },
64 "peerDependencies": {
65 "bare-buffer": "*"
66 },
67 "peerDependenciesMeta": {
68 "bare-buffer": {
69 "optional": true
70 }
71 }
72}
node_modules/bare-subprocess/prebuilds/android-arm/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/android-arm64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/android-ia32/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/android-x64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/darwin-arm64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/darwin-x64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/ios-arm64-simulator/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/ios-arm64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/ios-x64-simulator/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/linux-arm64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/linux-x64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/win32-arm64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-subprocess/prebuilds/win32-x64/bare-subprocess.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/CMakeLists.txt +23 -0
……@@ -0,0 +1,23 @@
1cmake_minimum_required(VERSION 4.0)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4
5project(bare_tcp C)
6
7bare_target(target)
8
9add_bare_module(bare_tcp)
10
11target_sources(
12 ${bare_tcp}
13 PRIVATE
14 binding.c
15)
16
17if(target MATCHES "win32")
18 target_link_libraries(
19 ${bare_tcp}
20 PUBLIC
21 ws2_32
22 )
23endif()
node_modules/bare-tcp/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-tcp/README.md +25 -0
……@@ -0,0 +1,25 @@
1# bare-tcp
2
3Native TCP sockets for JavaScript.
4
5```
6npm i bare-tcp
7```
8
9## Usage
10
11```js
12const tcp = require('bare-tcp')
13
14const server = tcp.createServer()
15server.on('connection', (socket) => socket.on('data', console.log))
16server.listen(() => console.log('server is up'))
17
18const { port } = server.address()
19const socket = tcp.createConnection(port)
20socket.write('hello world')
21```
22
23## License
24
25Apache-2.0
node_modules/bare-tcp/binding.c +1022 -0
……@@ -0,0 +1,1022 @@
1#include <assert.h>
2#include <bare.h>
3#include <js.h>
4#include <stdlib.h>
5#include <uv.h>
6
7typedef struct {
8 uv_tcp_t handle;
9
10 struct {
11 uv_connect_t connect;
12 uv_write_t write;
13 uv_shutdown_t shutdown;
14 } requests;
15
16 uv_buf_t read;
17
18 js_env_t *env;
19 js_ref_t *ctx;
20 js_ref_t *on_connection;
21 js_ref_t *on_connect;
22 js_ref_t *on_reset;
23 js_ref_t *on_read;
24 js_ref_t *on_write;
25 js_ref_t *on_end;
26 js_ref_t *on_close;
27
28 bool resetting;
29 bool closing;
30 bool exiting;
31
32 js_deferred_teardown_t *teardown;
33} bare_tcp_t;
34
35static void
36bare_tcp__on_connection(uv_stream_t *server, int status) {
37 int err;
38
39 bare_tcp_t *tcp = (bare_tcp_t *) server;
40
41 if (tcp->closing || tcp->exiting) return;
42
43 js_env_t *env = tcp->env;
44
45 js_handle_scope_t *scope;
46 err = js_open_handle_scope(env, &scope);
47 assert(err == 0);
48
49 js_value_t *ctx;
50 err = js_get_reference_value(env, tcp->ctx, &ctx);
51 assert(err == 0);
52
53 js_value_t *on_connection;
54 err = js_get_reference_value(env, tcp->on_connection, &on_connection);
55 assert(err == 0);
56
57 js_value_t *argv[1];
58
59 if (status < 0) {
60 js_value_t *code;
61 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(status), -1, &code);
62 assert(err == 0);
63
64 js_value_t *message;
65 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(status), -1, &message);
66 assert(err == 0);
67
68 err = js_create_error(env, code, message, &argv[0]);
69 assert(err == 0);
70 } else {
71 err = js_get_null(env, &argv[0]);
72 assert(err == 0);
73 }
74
75 js_call_function(env, ctx, on_connection, 1, argv, NULL);
76
77 err = js_close_handle_scope(env, scope);
78 assert(err == 0);
79}
80
81static void
82bare_tcp__on_connect(uv_connect_t *req, int status) {
83 int err;
84
85 bare_tcp_t *tcp = (bare_tcp_t *) req->data;
86
87 if (tcp->exiting) return;
88
89 js_env_t *env = tcp->env;
90
91 js_handle_scope_t *scope;
92 err = js_open_handle_scope(env, &scope);
93 assert(err == 0);
94
95 js_value_t *ctx;
96 err = js_get_reference_value(env, tcp->ctx, &ctx);
97 assert(err == 0);
98
99 js_value_t *on_connect;
100 err = js_get_reference_value(env, tcp->on_connect, &on_connect);
101 assert(err == 0);
102
103 js_value_t *argv[1];
104
105 if (status < 0) {
106 js_value_t *code;
107 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(status), -1, &code);
108 assert(err == 0);
109
110 js_value_t *message;
111 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(status), -1, &message);
112 assert(err == 0);
113
114 err = js_create_error(env, code, message, &argv[0]);
115 assert(err == 0);
116 } else {
117 err = js_get_null(env, &argv[0]);
118 assert(err == 0);
119 }
120
121 js_call_function(env, ctx, on_connect, 1, argv, NULL);
122
123 err = js_close_handle_scope(env, scope);
124 assert(err == 0);
125}
126
127static void
128bare_tcp__on_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
129 if (nread == UV_EOF) nread = 0;
130 else if (nread == 0) return;
131
132 int err;
133
134 bare_tcp_t *tcp = (bare_tcp_t *) stream;
135
136 if (tcp->exiting) return;
137
138 js_env_t *env = tcp->env;
139
140 js_handle_scope_t *scope;
141 err = js_open_handle_scope(env, &scope);
142 assert(err == 0);
143
144 js_value_t *ctx;
145 err = js_get_reference_value(env, tcp->ctx, &ctx);
146 assert(err == 0);
147
148 js_value_t *on_read;
149 err = js_get_reference_value(env, tcp->on_read, &on_read);
150 assert(err == 0);
151
152 js_value_t *argv[2];
153
154 if (nread < 0) {
155 js_value_t *code;
156 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(nread), -1, &code);
157 assert(err == 0);
158
159 js_value_t *message;
160 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(nread), -1, &message);
161 assert(err == 0);
162
163 err = js_create_error(env, code, message, &argv[0]);
164 assert(err == 0);
165
166 err = js_create_int32(env, 0, &argv[1]);
167 assert(err == 0);
168 } else {
169 err = js_get_null(env, &argv[0]);
170 assert(err == 0);
171
172 err = js_create_int32(env, nread, &argv[1]);
173 assert(err == 0);
174 }
175
176 js_call_function(env, ctx, on_read, 2, argv, NULL);
177
178 err = js_close_handle_scope(env, scope);
179 assert(err == 0);
180}
181
182static void
183bare_tcp__on_write(uv_write_t *req, int status) {
184 int err;
185
186 bare_tcp_t *tcp = (bare_tcp_t *) req->data;
187
188 if (tcp->exiting) return;
189
190 js_env_t *env = tcp->env;
191
192 js_handle_scope_t *scope;
193 err = js_open_handle_scope(env, &scope);
194 assert(err == 0);
195
196 js_value_t *ctx;
197 err = js_get_reference_value(env, tcp->ctx, &ctx);
198 assert(err == 0);
199
200 js_value_t *on_write;
201 err = js_get_reference_value(env, tcp->on_write, &on_write);
202 assert(err == 0);
203
204 js_value_t *argv[1];
205
206 if (status < 0) {
207 js_value_t *code;
208 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(status), -1, &code);
209 assert(err == 0);
210
211 js_value_t *message;
212 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(status), -1, &message);
213 assert(err == 0);
214
215 err = js_create_error(env, code, message, &argv[0]);
216 assert(err == 0);
217 } else {
218 err = js_get_null(env, &argv[0]);
219 assert(err == 0);
220 }
221
222 js_call_function(env, ctx, on_write, 1, argv, NULL);
223
224 err = js_close_handle_scope(env, scope);
225 assert(err == 0);
226}
227
228static void
229bare_tcp__on_shutdown(uv_shutdown_t *req, int status) {
230 int err;
231
232 bare_tcp_t *tcp = (bare_tcp_t *) req->data;
233
234 if (tcp->exiting) return;
235
236 js_env_t *env = tcp->env;
237
238 js_handle_scope_t *scope;
239 err = js_open_handle_scope(env, &scope);
240 assert(err == 0);
241
242 js_value_t *ctx;
243 err = js_get_reference_value(env, tcp->ctx, &ctx);
244 assert(err == 0);
245
246 js_value_t *on_end;
247 err = js_get_reference_value(env, tcp->on_end, &on_end);
248 assert(err == 0);
249
250 js_value_t *argv[1];
251
252 if (status < 0) {
253 js_value_t *code;
254 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(status), -1, &code);
255 assert(err == 0);
256
257 js_value_t *message;
258 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(status), -1, &message);
259 assert(err == 0);
260
261 err = js_create_error(env, code, message, &argv[0]);
262 assert(err == 0);
263 } else {
264 err = js_get_null(env, &argv[0]);
265 assert(err == 0);
266 }
267
268 js_call_function(env, ctx, on_end, 1, argv, NULL);
269
270 err = js_close_handle_scope(env, scope);
271 assert(err == 0);
272}
273
274static void
275bare_tcp__on_close(uv_handle_t *handle) {
276 int err;
277
278 bare_tcp_t *tcp = (bare_tcp_t *) handle;
279
280 js_env_t *env = tcp->env;
281
282 js_handle_scope_t *scope;
283 err = js_open_handle_scope(env, &scope);
284 assert(err == 0);
285
286 js_value_t *ctx;
287 err = js_get_reference_value(env, tcp->ctx, &ctx);
288 assert(err == 0);
289
290 if (tcp->resetting && !tcp->exiting) {
291 uv_loop_t *loop;
292 err = js_get_env_loop(env, &loop);
293 assert(err == 0);
294
295 js_value_t *on_reset;
296 err = js_get_reference_value(env, tcp->on_reset, &on_reset);
297 assert(err == 0);
298
299 err = uv_tcp_init(loop, &tcp->handle);
300
301 js_value_t *argv[1];
302
303 if (err < 0) {
304 js_value_t *code;
305 err = js_create_string_utf8(env, (utf8_t *) uv_err_name(err), -1, &code);
306 assert(err == 0);
307
308 js_value_t *message;
309 err = js_create_string_utf8(env, (utf8_t *) uv_strerror(err), -1, &message);
310 assert(err == 0);
311
312 err = js_create_error(env, code, message, &argv[0]);
313 assert(err == 0);
314 } else {
315 err = js_get_null(env, &argv[0]);
316 assert(err == 0);
317 }
318
319 tcp->resetting = false;
320
321 js_call_function(env, ctx, on_reset, 1, argv, NULL);
322
323 err = js_close_handle_scope(env, scope);
324 assert(err == 0);
325 } else {
326 js_deferred_teardown_t *teardown = tcp->teardown;
327
328 js_value_t *on_close;
329 err = js_get_reference_value(env, tcp->on_close, &on_close);
330 assert(err == 0);
331
332 err = js_delete_reference(env, tcp->on_connection);
333 assert(err == 0);
334
335 err = js_delete_reference(env, tcp->on_connect);
336 assert(err == 0);
337
338 err = js_delete_reference(env, tcp->on_reset);
339 assert(err == 0);
340
341 err = js_delete_reference(env, tcp->on_read);
342 assert(err == 0);
343
344 err = js_delete_reference(env, tcp->on_write);
345 assert(err == 0);
346
347 err = js_delete_reference(env, tcp->on_end);
348 assert(err == 0);
349
350 err = js_delete_reference(env, tcp->on_close);
351 assert(err == 0);
352
353 err = js_delete_reference(env, tcp->ctx);
354 assert(err == 0);
355
356 if (!tcp->exiting) js_call_function(env, ctx, on_close, 0, NULL, NULL);
357
358 err = js_close_handle_scope(env, scope);
359 assert(err == 0);
360
361 err = js_finish_deferred_teardown_callback(teardown);
362 assert(err == 0);
363 }
364}
365
366static void
367bare_tcp__on_teardown(js_deferred_teardown_t *handle, void *data) {
368 bare_tcp_t *tcp = (bare_tcp_t *) data;
369
370 tcp->exiting = true;
371
372 if (tcp->closing) return;
373
374 uv_close((uv_handle_t *) &tcp->handle, bare_tcp__on_close);
375}
376
377static void
378bare_tcp__on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
379 bare_tcp_t *tcp = (bare_tcp_t *) handle;
380
381 *buf = tcp->read;
382}
383
384static js_value_t *
385bare_tcp_init(js_env_t *env, js_callback_info_t *info) {
386 int err;
387
388 size_t argc = 9;
389 js_value_t *argv[9];
390
391 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
392 assert(err == 0);
393
394 assert(argc == 9);
395
396 uv_loop_t *loop;
397 err = js_get_env_loop(env, &loop);
398 assert(err == 0);
399
400 js_value_t *handle;
401
402 bare_tcp_t *tcp;
403 err = js_create_arraybuffer(env, sizeof(bare_tcp_t), (void **) &tcp, &handle);
404 assert(err == 0);
405
406 err = uv_tcp_init(loop, &tcp->handle);
407
408 if (err < 0) {
409 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
410 assert(err == 0);
411
412 return NULL;
413 }
414
415 tcp->env = env;
416 tcp->resetting = false;
417 tcp->closing = false;
418 tcp->exiting = false;
419
420 err = js_get_typedarray_info(env, argv[0], NULL, (void **) &tcp->read.base, (size_t *) &tcp->read.len, NULL, NULL);
421 assert(err == 0);
422
423 err = js_create_reference(env, argv[1], 1, &tcp->ctx);
424 assert(err == 0);
425
426 err = js_create_reference(env, argv[2], 1, &tcp->on_connection);
427 assert(err == 0);
428
429 err = js_create_reference(env, argv[3], 1, &tcp->on_connect);
430 assert(err == 0);
431
432 err = js_create_reference(env, argv[4], 1, &tcp->on_reset);
433 assert(err == 0);
434
435 err = js_create_reference(env, argv[5], 1, &tcp->on_read);
436 assert(err == 0);
437
438 err = js_create_reference(env, argv[6], 1, &tcp->on_write);
439 assert(err == 0);
440
441 err = js_create_reference(env, argv[7], 1, &tcp->on_end);
442 assert(err == 0);
443
444 err = js_create_reference(env, argv[8], 1, &tcp->on_close);
445 assert(err == 0);
446
447 err = js_add_deferred_teardown_callback(env, bare_tcp__on_teardown, (void *) tcp, &tcp->teardown);
448 assert(err == 0);
449
450 return handle;
451}
452
453static js_value_t *
454bare_tcp_connect(js_env_t *env, js_callback_info_t *info) {
455 int err;
456
457 size_t argc = 4;
458 js_value_t *argv[4];
459
460 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
461 assert(err == 0);
462
463 assert(argc == 4);
464
465 bare_tcp_t *tcp;
466 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
467 assert(err == 0);
468
469 uint32_t port;
470 err = js_get_value_uint32(env, argv[1], &port);
471 assert(err == 0);
472
473 utf8_t ip[INET6_ADDRSTRLEN];
474 err = js_get_value_string_utf8(env, argv[2], ip, INET6_ADDRSTRLEN, NULL);
475 assert(err == 0);
476
477 uint32_t family;
478 err = js_get_value_uint32(env, argv[3], &family);
479 assert(err == 0);
480
481 struct sockaddr_storage addr;
482
483 if (family == 4) {
484 err = uv_ip4_addr((char *) ip, port, (struct sockaddr_in *) &addr);
485 } else {
486 err = uv_ip6_addr((char *) ip, port, (struct sockaddr_in6 *) &addr);
487 }
488
489 if (err < 0) {
490 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
491 assert(err == 0);
492
493 return NULL;
494 }
495
496 uv_connect_t *req = &tcp->requests.connect;
497
498 req->data = tcp;
499
500 err = uv_tcp_connect(req, &tcp->handle, (struct sockaddr *) &addr, bare_tcp__on_connect);
501
502 if (err < 0) {
503 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
504 assert(err == 0);
505 }
506
507 return NULL;
508}
509
510static js_value_t *
511bare_tcp_reset(js_env_t *env, js_callback_info_t *info) {
512 int err;
513
514 size_t argc = 1;
515 js_value_t *argv[1];
516
517 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
518 assert(err == 0);
519
520 assert(argc == 1);
521
522 bare_tcp_t *tcp;
523 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
524 assert(err == 0);
525
526 tcp->resetting = true;
527
528 uv_close((uv_handle_t *) &tcp->handle, bare_tcp__on_close);
529
530 return NULL;
531}
532
533static js_value_t *
534bare_tcp_bind(js_env_t *env, js_callback_info_t *info) {
535 int err;
536
537 size_t argc = 5;
538 js_value_t *argv[5];
539
540 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
541 assert(err == 0);
542
543 assert(argc == 5);
544
545 bare_tcp_t *tcp;
546 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
547 assert(err == 0);
548
549 uint32_t port;
550 err = js_get_value_uint32(env, argv[1], &port);
551 assert(err == 0);
552
553 utf8_t ip[INET6_ADDRSTRLEN];
554 err = js_get_value_string_utf8(env, argv[2], ip, INET6_ADDRSTRLEN, NULL);
555 assert(err == 0);
556
557 uint32_t backlog;
558 err = js_get_value_uint32(env, argv[3], &backlog);
559 assert(err == 0);
560
561 uint32_t family;
562 err = js_get_value_uint32(env, argv[4], &family);
563 assert(err == 0);
564
565 struct sockaddr_storage addr;
566 int addr_len;
567
568 if (family == 4) {
569 addr_len = sizeof(struct sockaddr_in);
570 err = uv_ip4_addr((char *) ip, port, (struct sockaddr_in *) &addr);
571 } else {
572 addr_len = sizeof(struct sockaddr_in6);
573 err = uv_ip6_addr((char *) ip, port, (struct sockaddr_in6 *) &addr);
574 }
575
576 if (err < 0) {
577 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
578 assert(err == 0);
579
580 return NULL;
581 }
582
583 err = uv_tcp_bind(&tcp->handle, (struct sockaddr *) &addr, 0);
584
585 if (err < 0) {
586 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
587 assert(err == 0);
588
589 return NULL;
590 }
591
592 err = uv_listen((uv_stream_t *) &tcp->handle, backlog, bare_tcp__on_connection);
593
594 if (err < 0) {
595 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
596 assert(err == 0);
597
598 return NULL;
599 }
600
601 return NULL;
602}
603
604static js_value_t *
605bare_tcp_accept(js_env_t *env, js_callback_info_t *info) {
606 int err;
607
608 size_t argc = 2;
609 js_value_t *argv[2];
610
611 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
612 assert(err == 0);
613
614 assert(argc == 2);
615
616 bare_tcp_t *server;
617 err = js_get_arraybuffer_info(env, argv[0], (void **) &server, NULL);
618 assert(err == 0);
619
620 bare_tcp_t *client;
621 err = js_get_arraybuffer_info(env, argv[1], (void **) &client, NULL);
622 assert(err == 0);
623
624 err = uv_accept((uv_stream_t *) &server->handle, (uv_stream_t *) &client->handle);
625
626 if (err < 0) {
627 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
628 assert(err == 0);
629 }
630
631 return NULL;
632}
633
634static js_value_t *
635bare_tcp_resume(js_env_t *env, js_callback_info_t *info) {
636 int err;
637
638 size_t argc = 1;
639 js_value_t *argv[1];
640
641 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
642 assert(err == 0);
643
644 assert(argc == 1);
645
646 bare_tcp_t *tcp;
647 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
648 assert(err == 0);
649
650 if (!uv_is_readable((uv_stream_t *) &tcp->handle)) return NULL;
651
652 err = uv_read_start((uv_stream_t *) &tcp->handle, bare_tcp__on_alloc, bare_tcp__on_read);
653
654 if (err < 0) {
655 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
656 assert(err == 0);
657 }
658
659 return NULL;
660}
661
662static js_value_t *
663bare_tcp_pause(js_env_t *env, js_callback_info_t *info) {
664 int err;
665
666 size_t argc = 1;
667 js_value_t *argv[1];
668
669 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
670 assert(err == 0);
671
672 assert(argc == 1);
673
674 bare_tcp_t *tcp;
675 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
676 assert(err == 0);
677
678 if (!uv_is_readable((uv_stream_t *) &tcp->handle)) return NULL;
679
680 err = uv_read_stop((uv_stream_t *) &tcp->handle);
681
682 if (err < 0) {
683 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
684 assert(err == 0);
685 }
686
687 return NULL;
688}
689
690static js_value_t *
691bare_tcp_writev(js_env_t *env, js_callback_info_t *info) {
692 int err;
693
694 size_t argc = 2;
695 js_value_t *argv[2];
696
697 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
698 assert(err == 0);
699
700 assert(argc == 2);
701
702 bare_tcp_t *tcp;
703 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
704 assert(err == 0);
705
706 js_value_t *arr = argv[1];
707
708 uint32_t bufs_len;
709 err = js_get_array_length(env, arr, &bufs_len);
710 assert(err == 0);
711
712 uv_buf_t *bufs = malloc(sizeof(uv_buf_t) * bufs_len);
713
714 js_value_t **elements = malloc(sizeof(js_value_t *) * bufs_len);
715 err = js_get_array_elements(env, arr, elements, bufs_len, 0, NULL);
716 assert(err == 0);
717
718 for (uint32_t i = 0; i < bufs_len; i++) {
719 js_value_t *item = elements[i];
720
721 uv_buf_t *buf = &bufs[i];
722 err = js_get_typedarray_info(env, item, NULL, (void **) &buf->base, (size_t *) &buf->len, NULL, NULL);
723 assert(err == 0);
724 }
725
726 uv_write_t *req = &tcp->requests.write;
727
728 req->data = tcp;
729
730 err = uv_write(req, (uv_stream_t *) &tcp->handle, bufs, bufs_len, bare_tcp__on_write);
731
732 free(bufs);
733 free(elements);
734
735 if (err < 0) {
736 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
737 assert(err == 0);
738 }
739
740 return NULL;
741}
742
743static js_value_t *
744bare_tcp_end(js_env_t *env, js_callback_info_t *info) {
745 int err;
746
747 size_t argc = 1;
748 js_value_t *argv[1];
749
750 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
751 assert(err == 0);
752
753 assert(argc == 1);
754
755 bare_tcp_t *tcp;
756 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
757 assert(err == 0);
758
759 uv_shutdown_t *req = &tcp->requests.shutdown;
760
761 req->data = tcp;
762
763 err = uv_shutdown(req, (uv_stream_t *) &tcp->handle, bare_tcp__on_shutdown);
764
765 if (err < 0) {
766 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
767 assert(err == 0);
768 }
769
770 return NULL;
771}
772
773static js_value_t *
774bare_tcp_close(js_env_t *env, js_callback_info_t *info) {
775 int err;
776
777 size_t argc = 1;
778 js_value_t *argv[1];
779
780 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
781 assert(err == 0);
782
783 assert(argc == 1);
784
785 bare_tcp_t *tcp;
786 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
787 assert(err == 0);
788
789 tcp->closing = true;
790
791 uv_close((uv_handle_t *) &tcp->handle, bare_tcp__on_close);
792
793 return NULL;
794}
795
796static js_value_t *
797bare_tcp_keepalive(js_env_t *env, js_callback_info_t *info) {
798 int err;
799
800 size_t argc = 3;
801 js_value_t *argv[3];
802
803 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
804 assert(err == 0);
805
806 assert(argc == 3);
807
808 bare_tcp_t *tcp;
809 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
810 assert(err == 0);
811
812 bool enable;
813 err = js_get_value_bool(env, argv[1], &enable);
814 assert(err == 0);
815
816 uint32_t delay;
817 err = js_get_value_uint32(env, argv[2], &delay);
818 assert(err == 0);
819
820 err = uv_tcp_keepalive(&tcp->handle, enable, delay);
821 assert(err == 0);
822
823 return NULL;
824}
825
826static js_value_t *
827bare_tcp_nodelay(js_env_t *env, js_callback_info_t *info) {
828 int err;
829
830 size_t argc = 2;
831 js_value_t *argv[2];
832
833 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
834 assert(err == 0);
835
836 assert(argc == 2);
837
838 bare_tcp_t *tcp;
839 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
840 assert(err == 0);
841
842 bool enable;
843 err = js_get_value_bool(env, argv[1], &enable);
844 assert(err == 0);
845
846 err = uv_tcp_nodelay(&tcp->handle, enable);
847 assert(err == 0);
848
849 return NULL;
850}
851
852static js_value_t *
853bare_tcp_address(js_env_t *env, js_callback_info_t *info) {
854 int err;
855
856 size_t argc = 2;
857 js_value_t *argv[2];
858
859 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
860 assert(err == 0);
861
862 assert(argc == 2);
863
864 bare_tcp_t *tcp;
865 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
866 assert(err == 0);
867
868 bool local;
869 err = js_get_value_bool(env, argv[1], &local);
870 assert(err == 0);
871
872 struct sockaddr_storage addr;
873 int len = sizeof(addr);
874
875 if (local) {
876 err = uv_tcp_getsockname(&tcp->handle, (struct sockaddr *) &addr, &len);
877 } else {
878 err = uv_tcp_getpeername(&tcp->handle, (struct sockaddr *) &addr, &len);
879 }
880
881 if (err < 0) {
882 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
883 assert(err == 0);
884
885 return NULL;
886 }
887
888 js_value_t *result;
889 err = js_create_object(env, &result);
890 assert(err == 0);
891
892 js_value_t *result_address;
893 js_value_t *result_family;
894 js_value_t *result_port;
895
896 if (addr.ss_family == AF_INET) {
897 struct sockaddr_in *addr_in = (struct sockaddr_in *) &addr;
898
899 char address[INET_ADDRSTRLEN];
900 err = uv_inet_ntop(AF_INET, &(addr_in->sin_addr), address, sizeof(address));
901 assert(err == 0);
902
903 err = js_create_string_utf8(env, (utf8_t *) address, -1, &result_address);
904 assert(err == 0);
905
906 err = js_create_int32(env, 4, &result_family);
907 assert(err == 0);
908
909 err = js_create_int32(env, ntohs(addr_in->sin_port), &result_port);
910 assert(err == 0);
911 } else if (addr.ss_family == AF_INET6) {
912 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) &addr;
913
914 char address[INET6_ADDRSTRLEN];
915 err = uv_inet_ntop(AF_INET6, &(addr_in6->sin6_addr), address, sizeof(address));
916 assert(err == 0);
917
918 err = js_create_string_utf8(env, (utf8_t *) address, -1, &result_address);
919 assert(err == 0);
920
921 err = js_create_int32(env, 6, &result_family);
922 assert(err == 0);
923
924 err = js_create_int32(env, ntohs(addr_in6->sin6_port), &result_port);
925 assert(err == 0);
926 } else {
927 err = UV_EAI_ADDRFAMILY;
928
929 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
930 assert(err == 0);
931
932 return NULL;
933 }
934
935 err = js_set_named_property(env, result, "address", result_address);
936 assert(err == 0);
937
938 err = js_set_named_property(env, result, "family", result_family);
939 assert(err == 0);
940
941 err = js_set_named_property(env, result, "port", result_port);
942 assert(err == 0);
943
944 return result;
945}
946
947static js_value_t *
948bare_tcp_ref(js_env_t *env, js_callback_info_t *info) {
949 int err;
950
951 size_t argc = 1;
952 js_value_t *argv[1];
953
954 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
955 assert(err == 0);
956
957 assert(argc == 1);
958
959 bare_tcp_t *tcp;
960 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
961 assert(err == 0);
962
963 uv_ref((uv_handle_t *) &tcp->handle);
964
965 return NULL;
966}
967
968static js_value_t *
969bare_tcp_unref(js_env_t *env, js_callback_info_t *info) {
970 int err;
971
972 size_t argc = 1;
973 js_value_t *argv[1];
974
975 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
976 assert(err == 0);
977
978 assert(argc == 1);
979
980 bare_tcp_t *tcp;
981 err = js_get_arraybuffer_info(env, argv[0], (void **) &tcp, NULL);
982 assert(err == 0);
983
984 uv_unref((uv_handle_t *) &tcp->handle);
985
986 return NULL;
987}
988
989static js_value_t *
990bare_tcp_exports(js_env_t *env, js_value_t *exports) {
991 int err;
992
993#define V(name, fn) \
994 { \
995 js_value_t *val; \
996 err = js_create_function(env, name, -1, fn, NULL, &val); \
997 assert(err == 0); \
998 err = js_set_named_property(env, exports, name, val); \
999 assert(err == 0); \
1000 }
1001
1002 V("init", bare_tcp_init)
1003 V("connect", bare_tcp_connect)
1004 V("reset", bare_tcp_reset)
1005 V("bind", bare_tcp_bind)
1006 V("accept", bare_tcp_accept)
1007 V("resume", bare_tcp_resume)
1008 V("pause", bare_tcp_pause)
1009 V("writev", bare_tcp_writev)
1010 V("end", bare_tcp_end)
1011 V("close", bare_tcp_close)
1012 V("keepalive", bare_tcp_keepalive)
1013 V("nodelay", bare_tcp_nodelay)
1014 V("address", bare_tcp_address)
1015 V("ref", bare_tcp_ref)
1016 V("unref", bare_tcp_unref)
1017#undef V
1018
1019 return exports;
1020}
1021
1022BARE_MODULE(bare_tcp, bare_tcp_exports)
node_modules/bare-tcp/binding.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon()
node_modules/bare-tcp/index.d.ts +179 -0
……@@ -0,0 +1,179 @@
1import EventEmitter, { EventMap } from 'bare-events'
2import { Duplex, DuplexEvents } from 'bare-stream'
3import { IPFamily, LookupOptions } from 'bare-dns'
4import TCPError from './lib/errors'
5import constants from './lib/constants'
6
7interface DNSLookup {
8 (
9 hostname: string,
10 opts: LookupOptions,
11 cb: (err: Error | null, address: string | null, family: IPFamily | 0) => void
12 ): void
13}
14
15interface TCPSocketAddress {
16 address: string
17 family: `IPv${IPFamily}`
18 port: number
19}
20
21interface TCPSocketEvents extends DuplexEvents {
22 connect: []
23 lookup: [err: Error | null, address: string | null, family: IPFamily | 0, host: string]
24 timeout: [ms: number]
25}
26
27interface TCPSocketOptions {
28 allowHalfOpen?: boolean
29 eagerOpen?: boolean
30 readBufferSize?: number
31}
32
33interface TCPSocketConnectOptions extends LookupOptions {
34 lookup?: DNSLookup
35 host?: string
36 keepAlive?: boolean
37 keepAliveInitialDelay?: boolean
38 noDelay?: boolean
39 port?: number
40 timeout?: number
41}
42
43interface TCPSocket<M extends TCPSocketEvents = TCPSocketEvents> extends Duplex<M> {
44 readonly connecting: boolean
45 readonly pending: boolean
46 readonly timeout?: number
47 readonly readyState: 'open' | 'opening'
48 readonly localAddress?: string
49 readonly localFamily?: string
50 readonly localPort?: number
51 readonly remoteAddress?: string
52 readonly remoteFamily?: string
53 readonly remotePort?: number
54
55 connect(port: number, host?: string, opts?: TCPSocketConnectOptions, onconnect?: () => void): this
56 connect(port: number, host: string, onconnect: () => void): this
57 connect(port: number, onconnect: () => void): this
58 connect(opts: TCPSocketConnectOptions): this
59
60 setKeepAlive(enable?: boolean, delay?: number): this
61 setKeepAlive(delay: number): this
62
63 setNoDelay(enable?: boolean): this
64
65 setTimeout(ms: number, ontimeout?: () => void): this
66
67 ref(): this
68 unref(): this
69}
70
71declare class TCPSocket<M extends TCPSocketEvents = TCPSocketEvents> extends Duplex<M> {
72 constructor(opts?: TCPSocketOptions)
73}
74
75interface TCPServerEvents extends EventMap {
76 close: []
77 connection: [socket: TCPSocket]
78 error: [err: Error]
79 listening: []
80 lookup: [err: Error | null, address: string | null, family: IPFamily | 0, host: string]
81}
82
83interface TCPServerOptions {
84 allowHalfOpen?: number
85 keepAlive?: boolean
86 keepAliveInitialDelay?: boolean
87 noDelay?: boolean
88 pauseOnConnect?: boolean
89 readBufferSize?: number
90}
91
92interface TCPServerListenOptions extends LookupOptions {
93 lookup?: DNSLookup
94 backlog?: number
95 host?: string
96 port?: number
97}
98
99interface TCPServer<M extends TCPServerEvents = TCPServerEvents> extends EventEmitter<M> {
100 readonly listening: boolean
101 readonly closing: boolean
102 readonly connections: Set<TCPSocket>
103
104 address(): TCPSocketAddress
105
106 listen(
107 port?: number,
108 host?: string,
109 backlog?: number,
110 opts?: TCPServerListenOptions,
111 onlistening?: () => void
112 ): this
113 listen(port: number, host: string, backlog: number, onlistening: () => void): this
114 listen(port: number, host: string, onlistening: () => void): this
115 listen(port: number, onlistening: () => void): this
116 listen(onlistening: () => void): this
117
118 close(onclose?: (err?: Error) => void): this
119
120 ref(): this
121 unref(): this
122}
123
124declare class TCPServer<M extends TCPServerEvents = TCPServerEvents> extends EventEmitter<M> {
125 constructor(opts?: TCPServerOptions, onconnection?: () => void)
126 constructor(onconnection: () => void)
127}
128
129declare function createConnection(
130 port: number,
131 host?: string,
132 opts?: TCPSocketOptions & TCPSocketConnectOptions,
133 onconnect?: () => void
134): TCPSocket
135
136declare function createConnection(port: number, host: string, onconnect: () => void): TCPSocket
137
138declare function createConnection(port: number, onconnect: () => void): TCPSocket
139
140declare function createConnection(
141 opts: TCPSocketOptions & TCPSocketConnectOptions,
142 onconnect: () => void
143): TCPSocket
144
145declare function createConnection(opts: TCPSocketOptions & TCPSocketConnectOptions): TCPSocket
146
147declare function createServer(opts?: TCPServerOptions, onconnection?: () => void): TCPServer
148
149declare function createServer(onconnection: () => void): TCPServer
150
151declare function isIP(host: string): IPFamily | 0
152
153declare function isIPv4(host: string): boolean
154
155declare function isIPv6(host: string): boolean
156
157export {
158 type TCPSocket,
159 TCPSocket as Socket,
160 type TCPServer,
161 TCPServer as Server,
162 createConnection,
163 createConnection as connect,
164 createServer,
165 constants,
166 type TCPError,
167 TCPError as errors,
168 type IPFamily,
169 isIP,
170 isIPv4,
171 isIPv6,
172 type TCPSocketAddress,
173 type TCPSocketEvents,
174 type TCPSocketOptions,
175 type TCPSocketConnectOptions,
176 type TCPServerEvents,
177 type TCPServerOptions,
178 type TCPServerListenOptions
179}
node_modules/bare-tcp/index.js +681 -0
……@@ -0,0 +1,681 @@
1const EventEmitter = require('bare-events')
2const { Duplex } = require('bare-stream')
3const dns = require('bare-dns')
4const binding = require('./binding')
5const constants = require('./lib/constants')
6const errors = require('./lib/errors')
7const ip = require('./lib/ip')
8
9const defaultReadBufferSize = 65536
10const empty = Buffer.alloc(0)
11
12exports.Socket = class TCPSocket extends Duplex {
13 constructor(opts = {}) {
14 const { readBufferSize = defaultReadBufferSize, allowHalfOpen = true, eagerOpen = true } = opts
15
16 super({ eagerOpen })
17
18 this._state = 0
19
20 this._allowHalfOpen = allowHalfOpen
21
22 this._keepAlive = 0
23 this._keepAliveInitialDelay = 0
24 this._noDelay = 0
25
26 this._localAddress = null
27 this._remoteAddress = null
28
29 this._pendingOpen = null
30 this._pendingWrite = null
31 this._pendingFinal = null
32 this._pendingDestroy = null
33
34 this._timer = null
35 this._timeout = 0
36
37 this._buffer = Buffer.alloc(readBufferSize)
38
39 this._addresses = null
40 this._errors = null
41
42 this._handle = binding.init(
43 this._buffer,
44 this,
45 noop,
46 this._onconnect,
47 this._onreset,
48 this._onread,
49 this._onwrite,
50 this._onfinal,
51 this._onclose
52 )
53 }
54
55 get connecting() {
56 return (this._state & constants.state.CONNECTING) !== 0
57 }
58
59 get pending() {
60 return (this._state & constants.state.CONNECTED) === 0
61 }
62
63 get timeout() {
64 return this._timeout || undefined // For Node.js compatibility
65 }
66
67 get readyState() {
68 if (this._state & constants.state.CONNECTED) {
69 return 'open'
70 }
71
72 return 'opening'
73 }
74
75 get localAddress() {
76 if (this._localAddress) return this._localAddress.address
77 }
78
79 get localFamily() {
80 if (this._localAddress) return `IPv${this._localAddress.family}`
81 }
82
83 get localPort() {
84 if (this._localAddress) return this._localAddress.port
85 }
86
87 get remoteAddress() {
88 if (this._remoteAddress) return this._remoteAddress.address
89 }
90
91 get remoteFamily() {
92 if (this._remoteAddress) return `IPv${this._remoteAddress.family}`
93 }
94
95 get remotePort() {
96 if (this._remoteAddress) return this._remoteAddress.port
97 }
98
99 connect(port, host = 'localhost', opts = {}, onconnect) {
100 if (this._state & constants.state.CONNECTING || this._state & constants.state.CONNECTED) {
101 throw errors.SOCKET_ALREADY_CONNECTED('Socket is already connected')
102 }
103
104 this._state |= constants.state.CONNECTING
105
106 if (typeof host === 'function') {
107 onconnect = host
108 host = 'localhost'
109 } else if (typeof opts === 'function') {
110 onconnect = opts
111 opts = {}
112 }
113
114 let family = 0
115
116 if (typeof port === 'object' && port !== null) {
117 opts = port || {}
118 port = opts.port || 0
119 host = opts.host || 'localhost'
120 family = opts.family || 0
121 }
122
123 if (!host) host = 'localhost'
124
125 const {
126 lookup = dns.lookup,
127 hints,
128 keepAlive = false,
129 keepAliveInitialDelay = 0,
130 noDelay = false,
131 timeout
132 } = opts
133
134 const type = ip.isIP(host)
135
136 if (type === 0) {
137 lookup(host, { all: true, family, hints }, (err, addresses) => {
138 if (this._state & constants.state.CLOSING) return
139
140 this._state &= ~constants.state.CONNECTING
141
142 if (err || addresses.length === 0) {
143 if (!err) {
144 err = new Error(`No address found for host "${host}"`)
145 err.code = 'ENOTFOUND'
146 }
147
148 this.emit('lookup', err, null, 0, host)
149
150 if (this._pendingOpen) this._continueOpen(err)
151 else this.destroy(err)
152 return
153 }
154
155 for (const { address, family } of addresses) {
156 this.emit('lookup', null, address, family, host)
157 }
158
159 const [{ address, family }, ...rest] = addresses
160
161 if (rest.length > 0) {
162 this._addresses = rest.map(({ address, family }) => [
163 port,
164 address,
165 { ...opts, family },
166 onconnect
167 ])
168
169 this._errors = []
170 }
171
172 this.connect(port, address, { ...opts, family }, onconnect)
173 })
174
175 return this
176 }
177
178 family = type
179
180 try {
181 binding.connect(this._handle, port, host, family)
182
183 if (keepAlive) {
184 this._keepAlive = keepAlive
185 this._keepAliveInitialDelay = keepAliveInitialDelay
186 }
187 if (noDelay) this._noDelay = noDelay
188 if (timeout) this.setTimeout(timeout)
189
190 if (onconnect) this.once('connect', onconnect)
191 } catch (err) {
192 queueMicrotask(() => {
193 if (this._pendingOpen) this._pendingOpen(err)
194 else this.destroy(err)
195 })
196 }
197
198 return this
199 }
200
201 setKeepAlive(enable = false, delay = 0) {
202 if (typeof enable === 'number') {
203 delay = enable
204 enable = false
205 }
206
207 delay = Math.floor(delay / 1000)
208
209 if (delay === 0) enable = false
210
211 binding.keepalive(this._handle, enable, delay)
212
213 return this
214 }
215
216 setNoDelay(enable = true) {
217 binding.nodelay(this._handle, enable)
218
219 return this
220 }
221
222 setTimeout(ms, ontimeout) {
223 if (ms === 0) {
224 clearTimeout(this._timer)
225
226 this._timer = null
227 } else {
228 if (ontimeout) this.once('timeout', ontimeout)
229
230 this._timer = setTimeout(() => this.emit('timeout'), ms)
231 this._timer.unref()
232 }
233
234 this._timeout = ms
235
236 return this
237 }
238
239 ref() {
240 binding.ref(this._handle)
241
242 return this
243 }
244
245 unref() {
246 binding.unref(this._handle)
247
248 return this
249 }
250
251 _open(cb) {
252 if (this._state & constants.state.CONNECTED) return cb(null)
253
254 this._pendingOpen = cb
255 }
256
257 _read() {
258 if ((this._state & constants.state.READING) === 0) {
259 this._state |= constants.state.READING
260
261 binding.resume(this._handle)
262 }
263 }
264
265 _writev(batch, cb) {
266 this._pendingWrite = [cb, batch]
267
268 binding.writev(
269 this._handle,
270 batch.map(({ chunk }) => chunk)
271 )
272 }
273
274 _final(cb) {
275 this._pendingFinal = cb
276
277 binding.end(this._handle)
278 }
279
280 _predestroy() {
281 if (this._state & constants.state.CLOSING) return
282 this._state |= constants.state.CLOSING
283
284 binding.close(this._handle)
285 }
286
287 _destroy(err, cb) {
288 if (this._state & constants.state.CLOSING) return cb(err)
289 this._state |= constants.state.CLOSING
290
291 this._pendingDestroy = cb
292
293 binding.close(this._handle)
294 }
295
296 _continueOpen(err) {
297 if (this._pendingOpen === null) return
298 const cb = this._pendingOpen
299 this._pendingOpen = null
300 cb(err)
301 }
302
303 _continueWrite(err) {
304 if (this._pendingWrite === null) return
305 const cb = this._pendingWrite[0]
306 this._pendingWrite = null
307 cb(err)
308 }
309
310 _continueFinal(err) {
311 if (this._pendingFinal === null) return
312 const cb = this._pendingFinal
313 this._pendingFinal = null
314 cb(err)
315 }
316
317 _continueDestroy() {
318 if (this._pendingDestroy === null) return
319 const cb = this._pendingDestroy
320 this._pendingDestroy = null
321 cb(null)
322 }
323
324 _reset() {
325 this._state = 0
326
327 this._localAddress = null
328 this._remoteAddress = null
329
330 binding.reset(this._handle)
331 }
332
333 _onconnect(err) {
334 if (err) {
335 if (this._addresses !== null) {
336 this._errors.push(err)
337
338 if (this._addresses.length > 0) return this._reset()
339
340 err = this._errors.length === 1 ? this._errors[0] : new AggregateError(this._errors)
341 }
342
343 if (this._pendingOpen) this._continueOpen(err)
344 else this.destroy(err)
345 return
346 }
347
348 if (this._keepAlive) this.setKeepAlive(this._keepAlive, this._keepAliveInitialDelay)
349 if (this._noDelay) this.setNoDelay()
350
351 this._localAddress = binding.address(this._handle, true)
352 this._remoteAddress = binding.address(this._handle, false)
353
354 this._state |= constants.state.CONNECTED
355 this._state &= ~constants.state.CONNECTING
356 this._continueOpen()
357
358 this.emit('connect')
359 }
360
361 _onreset(err) {
362 if (err) {
363 this._errors.push(err)
364 this.destroy(this._errors.length === 1 ? this._errors[0] : new AggregateError(this._errors))
365 return
366 }
367
368 this.connect(...this._addresses.shift())
369 }
370
371 _onread(err, read) {
372 if (this._timer) this._timer.refresh()
373
374 if (err) {
375 this.destroy(err)
376 return
377 }
378
379 if (read === 0) {
380 this.push(null)
381 if (this._allowHalfOpen === false) this.end()
382 return
383 }
384
385 const copy = Buffer.allocUnsafe(read)
386 copy.set(this._buffer.subarray(0, read))
387
388 if (this.push(copy) === false && this.destroying === false) {
389 this._state &= ~constants.state.READING
390
391 binding.pause(this._handle)
392 }
393 }
394
395 _onwrite(err) {
396 if (this._timer) this._timer.refresh()
397
398 this._continueWrite(err)
399 }
400
401 _onfinal(err) {
402 this._continueFinal(err)
403 }
404
405 _onclose() {
406 clearTimeout(this._timer)
407
408 this._continueDestroy()
409 }
410}
411
412exports.Server = class TCPServer extends EventEmitter {
413 constructor(opts = {}, onconnection) {
414 if (typeof opts === 'function') {
415 onconnection = opts
416 opts = {}
417 }
418
419 super()
420
421 const {
422 readBufferSize = defaultReadBufferSize,
423 allowHalfOpen = true,
424 keepAlive = false,
425 keepAliveInitialDelay = 0,
426 noDelay = false,
427 pauseOnConnect = false
428 } = opts
429
430 this._state = 0
431
432 this._readBufferSize = readBufferSize
433 this._allowHalfOpen = allowHalfOpen
434 this._keepAlive = keepAlive
435 this._keepAliveInitialDelay = keepAliveInitialDelay
436 this._noDelay = noDelay
437 this._pauseOnConnect = pauseOnConnect
438
439 this._address = null
440 this._connections = new Set()
441
442 this._error = null
443 this._handle = null
444
445 if (onconnection) this.on('connection', onconnection)
446 }
447
448 get listening() {
449 return (this._state & constants.state.BOUND) !== 0
450 }
451
452 get closing() {
453 return (this._state & constants.state.CLOSING) !== 0
454 }
455
456 get connections() {
457 return this._connections
458 }
459
460 address() {
461 if ((this._state & constants.state.BOUND) === 0) return null
462
463 const { address, family, port } = this._address
464
465 return { address, family: `IPv${family}`, port }
466 }
467
468 listen(port = 0, host = 'localhost', backlog = 511, opts = {}, onlistening) {
469 if (this._state & constants.state.BINDING || this._state & constants.state.BOUND) {
470 throw errors.SERVER_ALREADY_LISTENING('Server is already listening')
471 }
472
473 if (this._state & constants.state.CLOSING) {
474 throw errors.SERVER_IS_CLOSED('Server is closed')
475 }
476
477 this._state |= constants.state.BINDING
478
479 if (typeof port === 'function') {
480 onlistening = port
481 port = 0
482 } else if (typeof host === 'function') {
483 onlistening = host
484 host = 'localhost'
485 } else if (typeof backlog === 'function') {
486 onlistening = backlog
487 backlog = 511
488 } else if (typeof opts === 'function') {
489 onlistening = opts
490 opts = {}
491 }
492
493 let family = 0
494
495 if (typeof port === 'object' && port !== null) {
496 opts = port || {}
497 port = opts.port || 0
498 host = opts.host || 'localhost'
499 family = opts.family || 0
500 backlog = opts.backlog || 511
501 }
502
503 if (!host) host = 'localhost'
504 if (!backlog) backlog = 511
505
506 const { lookup = dns.lookup, hints } = opts
507
508 const type = ip.isIP(host)
509
510 if (type === 0) {
511 lookup(host, { family, hints }, (err, address, family) => {
512 if (this._state & constants.state.CLOSING) return
513
514 this.emit('lookup', err, address, family, host)
515
516 this._state &= ~constants.state.BINDING
517
518 if (err) return this.emit('error', err)
519
520 this.listen(port, address, backlog, { ...opts, family }, onlistening)
521 })
522
523 return this
524 }
525
526 family = type
527
528 this._handle = binding.init(
529 empty,
530 this,
531 this._onconnection,
532 noop,
533 noop,
534 noop,
535 noop,
536 noop,
537 this._onclose
538 )
539
540 if (this._state & constants.state.UNREFED) binding.unref(this._handle)
541
542 try {
543 binding.bind(this._handle, port, host, backlog, family)
544
545 this._address = binding.address(this._handle, true)
546
547 this._state |= constants.state.BOUND
548 this._state &= ~constants.state.BINDING
549
550 if (onlistening) this.once('listening', onlistening)
551
552 queueMicrotask(() => this.emit('listening'))
553 } catch (err) {
554 this._error = err
555
556 binding.close(this._handle)
557 }
558
559 return this
560 }
561
562 close(onclose) {
563 if (onclose) this.once('close', onclose)
564
565 if (this._state & constants.state.CLOSING) return this
566 this._state |= constants.state.CLOSING
567
568 this._closeMaybe()
569
570 return this
571 }
572
573 ref() {
574 this._state &= ~constants.state.UNREFED
575
576 if (this._handle !== null) binding.ref(this._handle)
577
578 return this
579 }
580
581 unref() {
582 this._state |= constants.state.UNREFED
583
584 if (this._handle !== null) binding.unref(this._handle)
585
586 return this
587 }
588
589 _closeMaybe() {
590 if (this._state & constants.state.CLOSING && this._connections.size === 0) {
591 if (this._handle !== null) binding.close(this._handle)
592 else queueMicrotask(() => this.emit('close'))
593 }
594 }
595
596 _onconnection(err) {
597 if (err) {
598 this.emit('error', err)
599 return
600 }
601
602 if (this._state & constants.state.CLOSING) return
603
604 const socket = new exports.Socket({
605 readBufferSize: this._readBufferSize,
606 allowHalfOpen: this._allowHalfOpen,
607 eagerOpen: !this._pauseOnConnect
608 })
609
610 try {
611 binding.accept(this._handle, socket._handle)
612
613 socket._localAddress = binding.address(socket._handle, true)
614 socket._remoteAddress = binding.address(socket._handle, false)
615
616 socket._state |= constants.state.CONNECTED
617
618 this._connections.add(socket)
619
620 if (this._keepAlive) socket.setKeepAlive(this._keepAlive, this._keepAliveInitialDelay)
621 if (this._noDelay) socket.setNoDelay()
622
623 socket.on('close', () => {
624 this._connections.delete(socket)
625 this._closeMaybe()
626 })
627
628 this.emit('connection', socket)
629 } catch (err) {
630 socket.destroy()
631
632 this.emit('error', err)
633 }
634 }
635
636 _onclose() {
637 const err = this._error
638
639 this._state &= ~constants.state.BINDING
640 this._error = null
641 this._handle = null
642 this._address = null
643
644 if (err) this.emit('error', err)
645 else this.emit('close')
646 }
647}
648
649exports.constants = constants
650exports.errors = errors
651
652exports.isIP = ip.isIP
653exports.isIPv4 = ip.isIPv4
654exports.isIPv6 = ip.isIPv6
655
656exports.createConnection = function createConnection(port, host, opts, onconnect) {
657 if (typeof host === 'function') {
658 onconnect = host
659 host = 'localhost'
660 } else if (typeof opts === 'function') {
661 onconnect = opts
662 opts = {}
663 }
664
665 if (typeof port === 'object' && port !== null) {
666 opts = port || {}
667 port = opts.port || 0
668 host = opts.host || 'localhost'
669 }
670
671 return new exports.Socket(opts).connect(port, host, opts, onconnect)
672}
673
674// For Node.js compatibility
675exports.connect = exports.createConnection
676
677exports.createServer = function createServer(opts, onconnection) {
678 return new exports.Server(opts, onconnection)
679}
680
681function noop() {}
node_modules/bare-tcp/lib/constants.d.ts +13 -0
……@@ -0,0 +1,13 @@
1declare const constants: {
2 state: {
3 CONNECTING: number
4 CONNECTED: number
5 BINDING: number
6 BOUND: number
7 READING: number
8 CLOSING: number
9 UNREFED: number
10 }
11}
12
13exports = constants
node_modules/bare-tcp/lib/constants.js +11 -0
……@@ -0,0 +1,11 @@
1module.exports = {
2 state: {
3 CONNECTING: 0x1,
4 CONNECTED: 0x2,
5 BINDING: 0x4,
6 BOUND: 0x8,
7 READING: 0x10,
8 CLOSING: 0x20,
9 UNREFED: 0x40
10 }
11}
node_modules/bare-tcp/lib/errors.d.ts +5 -0
……@@ -0,0 +1,5 @@
1declare class TCPError extends Error {
2 readonly code: string
3}
4
5export = TCPError
node_modules/bare-tcp/lib/errors.js +30 -0
……@@ -0,0 +1,30 @@
1module.exports = class TCPError extends Error {
2 constructor(msg, fn = TCPError, code = fn.name) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'TCPError'
13 }
14
15 static SOCKET_ALREADY_CONNECTED(msg) {
16 return new TCPError(msg, TCPError.SOCKET_ALREADY_CONNECTED)
17 }
18
19 static SERVER_ALREADY_LISTENING(msg) {
20 return new TCPError(msg, TCPError.SERVER_ALREADY_LISTENING)
21 }
22
23 static SERVER_IS_CLOSED(msg) {
24 return new TCPError(msg, TCPError.SERVER_IS_CLOSED)
25 }
26
27 static INVALID_HOST(msg = 'Unrecognizable host format') {
28 return new TCPError(msg, TCPError.INVALID_HOST)
29 }
30}
node_modules/bare-tcp/lib/ip.js +52 -0
……@@ -0,0 +1,52 @@
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22const v4Seg = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
23const v4Str = `(${v4Seg}[.]){3}${v4Seg}`
24const IPv4Pattern = new RegExp(`^${v4Str}$`)
25
26const v6Seg = '(?:[0-9a-fA-F]{1,4})'
27const IPv6Pattern = new RegExp(
28 '^(' +
29 `(?:${v6Seg}:){7}(?:${v6Seg}|:)|` +
30 `(?:${v6Seg}:){6}(?:${v4Str}|:${v6Seg}|:)|` +
31 `(?:${v6Seg}:){5}(?::${v4Str}|(:${v6Seg}){1,2}|:)|` +
32 `(?:${v6Seg}:){4}(?:(:${v6Seg}){0,1}:${v4Str}|(:${v6Seg}){1,3}|:)|` +
33 `(?:${v6Seg}:){3}(?:(:${v6Seg}){0,2}:${v4Str}|(:${v6Seg}){1,4}|:)|` +
34 `(?:${v6Seg}:){2}(?:(:${v6Seg}){0,3}:${v4Str}|(:${v6Seg}){1,5}|:)|` +
35 `(?:${v6Seg}:){1}(?:(:${v6Seg}){0,4}:${v4Str}|(:${v6Seg}){1,6}|:)|` +
36 `(?::((?::${v6Seg}){0,5}:${v4Str}|(?::${v6Seg}){1,7}|:))` +
37 ')(%[0-9a-zA-Z-.:]{1,})?$'
38)
39
40const isIPv4 = (exports.isIPv4 = function isIPv4(host) {
41 return IPv4Pattern.test(host)
42})
43
44const isIPv6 = (exports.isIPv6 = function isIPv6(host) {
45 return IPv6Pattern.test(host)
46})
47
48exports.isIP = function isIP(host) {
49 if (isIPv4(host)) return 4
50 if (isIPv6(host)) return 6
51 return 0
52}
node_modules/bare-tcp/package.json +51 -0
……@@ -0,0 +1,51 @@
1{
2 "name": "bare-tcp",
3 "version": "2.2.7",
4 "description": "Native TCP sockets for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json",
11 "./constants": "./lib/constants.js",
12 "./errors": "./lib/errors.js"
13 },
14 "files": [
15 "index.js",
16 "index.d.ts",
17 "binding.c",
18 "binding.js",
19 "CMakeLists.txt",
20 "lib",
21 "prebuilds"
22 ],
23 "addon": true,
24 "scripts": {
25 "test": "prettier . --check && bare test.js"
26 },
27 "repository": {
28 "type": "git",
29 "url": "git+https://github.com/holepunchto/bare-tcp.git"
30 },
31 "author": "Holepunch",
32 "license": "Apache-2.0",
33 "bugs": {
34 "url": "https://github.com/holepunchto/bare-tcp/issues"
35 },
36 "homepage": "https://github.com/holepunchto/bare-tcp#readme",
37 "engines": {
38 "bare": ">=1.16.0"
39 },
40 "dependencies": {
41 "bare-dns": "^2.0.4",
42 "bare-events": "^2.5.4",
43 "bare-stream": "^2.6.4"
44 },
45 "devDependencies": {
46 "brittle": "^3.5.0",
47 "cmake-bare": "^1.1.6",
48 "prettier": "^3.4.1",
49 "prettier-config-holepunch": "^2.0.0"
50 }
51}
node_modules/bare-tcp/prebuilds/android-arm/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/android-arm64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/android-ia32/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/android-x64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/darwin-arm64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/darwin-x64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/ios-arm64-simulator/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/ios-arm64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/ios-x64-simulator/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/linux-arm64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/linux-x64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/win32-arm64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tcp/prebuilds/win32-x64/bare-tcp.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/CMakeLists.txt +34 -0
……@@ -0,0 +1,34 @@
1cmake_minimum_required(VERSION 4.0)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4find_package(cmake-fetch REQUIRED PATHS node_modules/cmake-fetch)
5
6project(bare_tls C CXX)
7
8bare_target(target)
9
10if(target MATCHES "win32")
11 add_definitions(-DWIN32_LEAN_AND_MEAN)
12endif()
13
14if(target MATCHES "win32-x64")
15 enable_language(ASM_NASM)
16else()
17 enable_language(ASM)
18endif()
19
20fetch_package("github:google/boringssl#0.20260211.0")
21
22add_bare_module(bare_tls)
23
24target_sources(
25 ${bare_tls}
26 PRIVATE
27 binding.c
28)
29
30target_link_libraries(
31 ${bare_tls}
32 PUBLIC
33 ssl
34)
node_modules/bare-tls/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-tls/README.md +44 -0
……@@ -0,0 +1,44 @@
1# bare-tls
2
3Transport Layer Security (TLS) streams for JavaScript.
4
5```
6npm i bare-tls
7```
8
9## Usage
10
11On the server side:
12
13```js
14const tls = require('bare-tls')
15const fs = require('bare-fs')
16
17const socket = new tls.Socket(stream, {
18 isServer: true,
19 cert: fs.readFileSync('server-cert.pem'),
20 key: fs.readFileSync('server-key.pem')
21})
22
23socket
24 .on('connect', () => console.log('server connected'))
25 .on('data', (data) => console.log(data))
26 .write('Hello from server')
27```
28
29On the client side:
30
31```js
32const tls = require('bare-tls')
33
34const socket = new tls.Socket(stream)
35
36socket
37 .on('connect', () => console.log('client connected'))
38 .on('data', (data) => console.log(data))
39 .write('Hello from client')
40```
41
42## License
43
44Apache-2.0
node_modules/bare-tls/binding.c +661 -0
……@@ -0,0 +1,661 @@
1#include <assert.h>
2#include <bare.h>
3#include <js.h>
4#include <openssl/base.h>
5#include <openssl/bio.h>
6#include <openssl/err.h>
7#include <openssl/evp.h>
8#include <openssl/ssl.h>
9#include <stddef.h>
10
11typedef struct {
12 SSL_CTX *ssl;
13 BIO_METHOD *io;
14
15 js_env_t *env;
16 js_ref_t *ctx;
17} bare_tls_context_t;
18
19typedef struct {
20 SSL *ssl;
21 BIO *io;
22 X509 *certificate;
23 EVP_PKEY *key;
24
25 uint8_t *alpn;
26 size_t alpn_len;
27
28 js_env_t *env;
29 js_ref_t *ctx;
30 js_ref_t *on_read;
31 js_ref_t *on_write;
32} bare_tls_t;
33
34static int
35bare_tls__on_read(BIO *io, char *buffer, int len) {
36 if (len == 0) return 0;
37
38 int err;
39
40 BIO_clear_retry_flags(io);
41
42 bare_tls_t *socket = BIO_get_ex_data(io, 0);
43
44 js_env_t *env = socket->env;
45
46 js_value_t *arraybuffer;
47 err = js_create_external_arraybuffer(env, (void *) buffer, len, NULL, NULL, &arraybuffer);
48 assert(err == 0);
49
50 js_value_t *typedarray;
51 err = js_create_typedarray(env, js_uint8array, len, arraybuffer, 0, &typedarray);
52 assert(err == 0);
53
54 js_value_t *ctx;
55 err = js_get_reference_value(env, socket->ctx, &ctx);
56 assert(err == 0);
57
58 js_value_t *on_read;
59 err = js_get_reference_value(env, socket->on_read, &on_read);
60 assert(err == 0);
61
62 js_value_t *result;
63 err = js_call_function(env, ctx, on_read, 1, &typedarray, &result);
64 if (err < 0) return -1;
65
66 err = js_get_value_int32(env, result, &len);
67 assert(err == 0);
68
69 err = js_detach_arraybuffer(env, arraybuffer);
70 assert(err == 0);
71
72 if (len == 0) {
73 BIO_set_retry_read(io);
74
75 return -1;
76 }
77
78 return len;
79}
80
81static int
82bare_tls__on_write(BIO *io, const char *buffer, int len) {
83 if (len == 0) return 0;
84
85 int err;
86
87 BIO_clear_retry_flags(io);
88
89 bare_tls_t *socket = BIO_get_ex_data(io, 0);
90
91 js_env_t *env = socket->env;
92
93 js_value_t *arraybuffer;
94 err = js_create_external_arraybuffer(env, (void *) buffer, len, NULL, NULL, &arraybuffer);
95 assert(err == 0);
96
97 js_value_t *typedarray;
98 err = js_create_typedarray(env, js_uint8array, len, arraybuffer, 0, &typedarray);
99 assert(err == 0);
100
101 js_value_t *ctx;
102 err = js_get_reference_value(env, socket->ctx, &ctx);
103 assert(err == 0);
104
105 js_value_t *on_write;
106 err = js_get_reference_value(env, socket->on_write, &on_write);
107 assert(err == 0);
108
109 js_value_t *result;
110 err = js_call_function(env, ctx, on_write, 1, &typedarray, &result);
111 if (err < 0) return -1;
112
113 err = js_get_value_int32(env, result, &len);
114 assert(err == 0);
115
116 err = js_detach_arraybuffer(env, arraybuffer);
117 assert(err == 0);
118
119 if (len == 0) {
120 BIO_set_retry_write(io);
121
122 return -1;
123 }
124
125 return len;
126}
127
128static long
129bare_tls__on_ctrl(BIO *io, int cmd, long argc, void *argv) {
130 switch (cmd) {
131 case BIO_CTRL_FLUSH:
132 return 1;
133
134 default:
135 return 0;
136 }
137}
138
139static int
140bare_tls__on_alpn_select(SSL *ssl, const uint8_t **out, uint8_t *outlen, const uint8_t *in, unsigned int inlen, void *arg) {
141 bare_tls_t *socket = (bare_tls_t *) SSL_get_ex_data(ssl, 0);
142
143 if (socket == NULL || socket->alpn == NULL || socket->alpn_len == 0) {
144 return SSL_TLSEXT_ERR_NOACK;
145 }
146
147 if (SSL_select_next_proto((uint8_t **) out, outlen, socket->alpn, (unsigned int) socket->alpn_len, in, inlen) != OPENSSL_NPN_NEGOTIATED) {
148 return SSL_TLSEXT_ERR_NOACK;
149 }
150
151 return SSL_TLSEXT_ERR_OK;
152}
153
154static void
155bare_tls__on_teardown(void *data) {
156 int err;
157
158 bare_tls_context_t *context = (bare_tls_context_t *) data;
159
160 js_env_t *env = context->env;
161
162 SSL_CTX_free(context->ssl);
163
164 BIO_meth_free(context->io);
165
166 err = js_delete_reference(env, context->ctx);
167 assert(err == 0);
168}
169
170static js_value_t *
171bare_tls_context(js_env_t *env, js_callback_info_t *info) {
172 int err;
173
174 js_value_t *handle;
175
176 bare_tls_context_t *context;
177 err = js_create_arraybuffer(env, sizeof(bare_tls_context_t), (void **) &context, &handle);
178 assert(err == 0);
179
180 BIO_METHOD *io = context->io = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "callback");
181
182 if (io == NULL) goto err;
183
184 SSL_CTX *ssl = context->ssl = SSL_CTX_new(TLS_method());
185
186 if (ssl == NULL) {
187 BIO_meth_free(io);
188
189 goto err;
190 }
191
192 BIO_meth_set_read(io, bare_tls__on_read);
193 BIO_meth_set_write(io, bare_tls__on_write);
194 BIO_meth_set_ctrl(io, bare_tls__on_ctrl);
195
196 err = SSL_CTX_set_ex_data(ssl, 0, (void *) context);
197 assert(err == 1);
198
199 err = SSL_CTX_set_min_proto_version(ssl, TLS1_2_VERSION);
200 assert(err == 1);
201
202 SSL_CTX_set_alpn_select_cb(ssl, bare_tls__on_alpn_select, NULL);
203
204 context->env = env;
205
206 err = js_add_teardown_callback(env, bare_tls__on_teardown, (void *) context);
207 assert(err == 0);
208
209 err = js_create_reference(env, handle, 1, &context->ctx);
210 assert(err == 0);
211
212 return handle;
213
214err:
215 js_throw_error(env, ERR_reason_symbol_name(ERR_peek_last_error()), "Context initialisation failed");
216 return NULL;
217}
218
219static js_value_t *
220bare_tls_init(js_env_t *env, js_callback_info_t *info) {
221 int err;
222
223 size_t argc = 9;
224 js_value_t *argv[9];
225
226 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
227 assert(err == 0);
228
229 assert(argc == 9);
230
231 bare_tls_context_t *context;
232 err = js_get_arraybuffer_info(env, argv[0], (void **) &context, NULL);
233 assert(err == 0);
234
235 js_value_t *handle;
236
237 bare_tls_t *socket;
238 err = js_create_arraybuffer(env, sizeof(bare_tls_t), (void **) &socket, &handle);
239 assert(err == 0);
240
241 socket->certificate = NULL;
242 socket->key = NULL;
243 socket->alpn = NULL;
244 socket->alpn_len = 0;
245
246 BIO *io = socket->io = BIO_new(context->io);
247
248 if (io == NULL) goto err;
249
250 SSL *ssl = socket->ssl = SSL_new(context->ssl);
251
252 if (ssl == NULL) {
253 BIO_free(io);
254
255 goto err;
256 }
257
258 err = BIO_set_ex_data(io, 0, (void *) socket);
259 assert(err == 1);
260
261 BIO_set_init(io, true);
262
263 err = SSL_set_ex_data(ssl, 0, (void *) socket);
264 assert(err == 1);
265
266 SSL_set_bio(ssl, io, io);
267
268 bool is_server;
269 err = js_get_value_bool(env, argv[1], &is_server);
270 assert(err == 0);
271
272 if (is_server) SSL_set_accept_state(ssl);
273 else SSL_set_connect_state(ssl);
274
275 bool has_cert;
276 err = js_is_typedarray(env, argv[2], &has_cert);
277 assert(err == 0);
278
279 if (has_cert) {
280 char *pem;
281 size_t len;
282 err = js_get_typedarray_info(env, argv[2], NULL, (void **) &pem, &len, NULL, NULL);
283 assert(err == 0);
284
285 BIO *io = BIO_new(BIO_s_mem());
286 BIO_write(io, pem, (int) len);
287
288 X509 *certificate = socket->certificate = PEM_read_bio_X509(io, NULL, NULL, NULL);
289
290 BIO_free(io);
291
292 if (certificate == NULL) {
293 SSL_free(ssl);
294
295 goto err;
296 }
297
298 err = SSL_use_certificate(ssl, certificate);
299
300 if (err == 0) {
301 SSL_free(ssl);
302
303 X509_free(certificate);
304
305 goto err;
306 }
307 }
308
309 bool has_key;
310 err = js_is_typedarray(env, argv[3], &has_key);
311 assert(err == 0);
312
313 if (has_key) {
314 char *pem;
315 size_t len;
316 err = js_get_typedarray_info(env, argv[3], NULL, (void **) &pem, &len, NULL, NULL);
317 assert(err == 0);
318
319 BIO *io = BIO_new(BIO_s_mem());
320 BIO_write(io, pem, (int) len);
321
322 EVP_PKEY *key = socket->key = PEM_read_bio_PrivateKey(io, NULL, NULL, NULL);
323
324 BIO_free(io);
325
326 if (key == NULL) {
327 SSL_free(ssl);
328
329 goto err;
330 }
331
332 int res = SSL_use_PrivateKey(ssl, key);
333
334 if (res == 0) {
335 SSL_free(ssl);
336
337 EVP_PKEY_free(key);
338
339 goto err;
340 }
341 }
342
343 bool has_host;
344 err = js_is_string(env, argv[4], &has_host);
345 assert(err == 0);
346
347 if (has_host) {
348 size_t len;
349 err = js_get_value_string_utf8(env, argv[4], NULL, 0, &len);
350 assert(err == 0);
351
352 len += 1 /* NULL */;
353
354 utf8_t *host = malloc(len);
355 err = js_get_value_string_utf8(env, argv[4], host, len, NULL);
356 assert(err == 0);
357
358 err = SSL_set_tlsext_host_name(ssl, (char *) host);
359 assert(err == 1);
360
361 free(host);
362 }
363
364 bool has_alpn;
365 err = js_is_typedarray(env, argv[5], &has_alpn);
366 assert(err == 0);
367
368 if (has_alpn) {
369 uint8_t *alpn;
370 size_t len;
371 err = js_get_typedarray_info(env, argv[5], NULL, (void **) &alpn, &len, NULL, NULL);
372 assert(err == 0);
373
374 if (is_server) {
375 socket->alpn = malloc(len);
376 socket->alpn_len = len;
377
378 memcpy(socket->alpn, alpn, len);
379 } else {
380 err = SSL_set_alpn_protos(ssl, alpn, len);
381 assert(err == 0);
382 }
383 }
384
385 socket->env = env;
386
387 err = js_create_reference(env, argv[6], 1, &socket->ctx);
388 assert(err == 0);
389
390 err = js_create_reference(env, argv[7], 1, &socket->on_read);
391 assert(err == 0);
392
393 err = js_create_reference(env, argv[8], 1, &socket->on_write);
394 assert(err == 0);
395
396 return handle;
397
398err:
399 js_throw_error(env, ERR_reason_symbol_name(ERR_peek_last_error()), "Socket initialisation failed");
400 return NULL;
401}
402
403static js_value_t *
404bare_tls_destroy(js_env_t *env, js_callback_info_t *info) {
405 int err;
406
407 size_t argc = 1;
408 js_value_t *argv[1];
409
410 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
411 assert(err == 0);
412
413 assert(argc == 1);
414
415 bare_tls_t *socket;
416 err = js_get_arraybuffer_info(env, argv[0], (void **) &socket, NULL);
417 assert(err == 0);
418
419 SSL_free(socket->ssl);
420
421 if (socket->certificate) X509_free(socket->certificate);
422
423 if (socket->key) EVP_PKEY_free(socket->key);
424
425 if (socket->alpn) free(socket->alpn);
426
427 err = js_delete_reference(env, socket->on_read);
428 assert(err == 0);
429
430 err = js_delete_reference(env, socket->on_write);
431 assert(err == 0);
432
433 err = js_delete_reference(env, socket->ctx);
434 assert(err == 0);
435
436 return NULL;
437}
438
439static js_value_t *
440bare_tls_handshake(js_env_t *env, js_callback_info_t *info) {
441 int err;
442
443 size_t argc = 1;
444 js_value_t *argv[1];
445
446 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
447 assert(err == 0);
448
449 assert(argc == 1);
450
451 bare_tls_t *socket;
452 err = js_get_arraybuffer_info(env, argv[0], (void **) &socket, NULL);
453 assert(err == 0);
454
455 bool done = true;
456
457 err = SSL_do_handshake(socket->ssl);
458
459 if (err <= 0) {
460 err = SSL_get_error(socket->ssl, err);
461
462 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
463 done = false;
464 } else {
465 js_throw_error(env, ERR_reason_symbol_name(ERR_peek_last_error()), "Handshake failed");
466 return NULL;
467 }
468 }
469
470 js_value_t *result;
471 err = js_get_boolean(env, done, &result);
472 assert(err == 0);
473
474 return result;
475}
476
477static js_value_t *
478bare_tls_read(js_env_t *env, js_callback_info_t *info) {
479 int err;
480
481 size_t argc = 2;
482 js_value_t *argv[2];
483
484 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
485 assert(err == 0);
486
487 assert(argc == 2);
488
489 bare_tls_t *socket;
490 err = js_get_arraybuffer_info(env, argv[0], (void **) &socket, NULL);
491 assert(err == 0);
492
493 char *buffer;
494 size_t len;
495 err = js_get_typedarray_info(env, argv[1], NULL, (void **) &buffer, &len, NULL, NULL);
496 assert(err == 0);
497
498 bool retry = false;
499 bool eof = false;
500
501 err = SSL_read(socket->ssl, buffer, len);
502
503 if (err <= 0) {
504 err = SSL_get_error(socket->ssl, err);
505
506 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
507 retry = true;
508 } else if (SSL_get_shutdown(socket->ssl)) {
509 eof = true;
510 } else {
511 js_throw_error(env, ERR_reason_symbol_name(ERR_peek_last_error()), "Read failed");
512 return NULL;
513 }
514 }
515
516 int res = eof ? 0 : retry ? -1
517 : err;
518
519 js_value_t *result;
520 err = js_create_int64(env, res, &result);
521 assert(err == 0);
522
523 return result;
524}
525
526static js_value_t *
527bare_tls_write(js_env_t *env, js_callback_info_t *info) {
528 int err;
529
530 size_t argc = 2;
531 js_value_t *argv[2];
532
533 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
534 assert(err == 0);
535
536 assert(argc == 2);
537
538 bare_tls_t *socket;
539 err = js_get_arraybuffer_info(env, argv[0], (void **) &socket, NULL);
540 assert(err == 0);
541
542 char *buffer;
543 size_t len;
544 err = js_get_typedarray_info(env, argv[1], NULL, (void **) &buffer, &len, NULL, NULL);
545 assert(err == 0);
546
547 bool retry = false;
548
549 err = SSL_write(socket->ssl, buffer, len);
550
551 if (err <= 0) {
552 err = SSL_get_error(socket->ssl, err);
553
554 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
555 retry = true;
556 } else {
557 js_throw_error(env, ERR_reason_symbol_name(ERR_peek_last_error()), "Write failed");
558 return NULL;
559 }
560 }
561
562 int res = retry ? 0 : err;
563
564 js_value_t *result;
565 err = js_create_int64(env, res, &result);
566 assert(err == 0);
567
568 return result;
569}
570
571static js_value_t *
572bare_tls_shutdown(js_env_t *env, js_callback_info_t *info) {
573 int err;
574
575 size_t argc = 1;
576 js_value_t *argv[1];
577
578 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
579 assert(err == 0);
580
581 assert(argc == 1);
582
583 bare_tls_t *socket;
584 err = js_get_arraybuffer_info(env, argv[0], (void **) &socket, NULL);
585 assert(err == 0);
586
587 err = SSL_shutdown(socket->ssl);
588
589 if (err < 0) {
590 js_throw_error(env, ERR_reason_symbol_name(ERR_peek_last_error()), "Shutdown failed");
591 return NULL;
592 }
593
594 js_value_t *result;
595 err = js_get_boolean(env, err == 1, &result);
596 assert(err == 0);
597
598 return result;
599}
600
601static js_value_t *
602bare_tls_alpn_protocol(js_env_t *env, js_callback_info_t *info) {
603 int err;
604
605 size_t argc = 1;
606 js_value_t *argv[1];
607
608 err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
609 assert(err == 0);
610
611 assert(argc == 1);
612
613 bare_tls_t *socket;
614 err = js_get_arraybuffer_info(env, argv[0], (void **) &socket, NULL);
615 assert(err == 0);
616
617 const uint8_t *data = NULL;
618 unsigned int len = 0;
619
620 SSL_get0_alpn_selected(socket->ssl, &data, &len);
621
622 js_value_t *result;
623
624 if (data && len) {
625 err = js_create_string_utf8(env, data, len, &result);
626 assert(err == 0);
627 } else {
628 err = js_get_null(env, &result);
629 assert(err == 0);
630 }
631
632 return result;
633}
634
635static js_value_t *
636bare_tls_exports(js_env_t *env, js_value_t *exports) {
637 int err;
638
639#define V(name, fn) \
640 { \
641 js_value_t *val; \
642 err = js_create_function(env, name, -1, fn, NULL, &val); \
643 assert(err == 0); \
644 err = js_set_named_property(env, exports, name, val); \
645 assert(err == 0); \
646 }
647
648 V("context", bare_tls_context);
649 V("init", bare_tls_init);
650 V("destroy", bare_tls_destroy);
651 V("handshake", bare_tls_handshake);
652 V("read", bare_tls_read);
653 V("write", bare_tls_write);
654 V("shutdown", bare_tls_shutdown);
655 V("alpnProtocol", bare_tls_alpn_protocol);
656#undef V
657
658 return exports;
659}
660
661BARE_MODULE(bare_tls, bare_tls_exports)
node_modules/bare-tls/binding.js +1 -0
……@@ -0,0 +1 @@
1module.exports = require.addon()
node_modules/bare-tls/index.d.ts +31 -0
……@@ -0,0 +1,31 @@
1import { Duplex, DuplexEvents } from 'bare-stream'
2import constants from './lib/constants'
3import TLSError from './lib/errors'
4
5export { constants, TLSError as errors }
6
7export interface TLSSocketEvents extends DuplexEvents {
8 connect: []
9}
10
11export interface TLSSocketOptions {
12 allowHalfOpen?: boolean
13 cert?: ArrayBufferView
14 eagerOpen?: boolean
15 host?: string
16 isServer?: boolean
17 key?: ArrayBufferView
18}
19
20export interface TLSSocket<
21 M extends TLSSocketEvents = TLSSocketEvents
22> extends Duplex<M> {
23 readonly socket: Duplex
24 readonly encrypted: true
25}
26
27export class TLSSocket {
28 constructor(socket: Duplex, opts?: TLSSocketOptions)
29}
30
31export { TLSSocket as Socket }
node_modules/bare-tls/index.js +298 -0
……@@ -0,0 +1,298 @@
1const { Duplex, Writable } = require('bare-stream')
2const binding = require('./binding')
3const constants = require('./lib/constants')
4const errors = require('./lib/errors')
5
6const defaultReadBufferSize = 65536
7
8const context = binding.context()
9
10exports.Socket = class TLSSocket extends Duplex {
11 constructor(socket, opts = {}) {
12 const {
13 isServer = false,
14 cert = null,
15 key = null,
16 host = null,
17 alpnProtocols = null,
18 eagerOpen = true,
19 allowHalfOpen = true,
20 readBufferSize = defaultReadBufferSize
21 } = opts
22
23 super({ eagerOpen })
24
25 this._state = 0
26
27 this._socket = socket
28 this._key = key
29 this._cert = cert
30 this._allowHalfOpen = allowHalfOpen
31
32 this._pendingOpen = null
33 this._pendingWrite = null
34
35 this._reading = Buffer.alloc(readBufferSize)
36 this._buffer = []
37 this._buffered = 0
38
39 let alpn = null
40
41 if (alpnProtocols && alpnProtocols.length > 0) {
42 const parts = []
43
44 for (const protocol of alpnProtocols) {
45 const encoded = Buffer.from(protocol)
46
47 if (encoded.byteLength === 0 || encoded.byteLength > 255) {
48 throw new RangeError('ALPN protocol name must be 1-255 bytes')
49 }
50
51 parts.push(Buffer.of(encoded.byteLength), encoded)
52 }
53
54 alpn = Buffer.concat(parts)
55 }
56
57 try {
58 this._handle = binding.init(
59 context,
60 isServer,
61 cert,
62 key,
63 host,
64 alpn,
65 this,
66 this._onread,
67 this._onwrite
68 )
69 } catch (err) {
70 this._handle = null
71
72 this.destroy(err)
73 }
74 }
75
76 get socket() {
77 return this._socket
78 }
79
80 get encrypted() {
81 return true
82 }
83
84 get alpnProtocol() {
85 return binding.alpnProtocol(this._handle)
86 }
87
88 _onconnect() {
89 this._state |= constants.state.CONNECTED
90
91 this.emit('connect')
92
93 const cb = this._pendingOpen
94 this._pendingOpen = null
95 cb(null)
96 }
97
98 _ondata(data) {
99 this._buffer.push(data)
100 this._buffered += data.byteLength
101
102 while (this._buffered > 0) {
103 if (this._state & constants.state.CONNECTED) {
104 let read
105 try {
106 read = binding.read(this._handle, this._reading)
107 } catch (err) {
108 return this.destroy(errors.from(err))
109 }
110
111 if (read < 0) break
112
113 if (read === 0) {
114 this.push(null)
115 if (this._allowHalfOpen === false) this.end()
116 return
117 }
118
119 const copy = Buffer.allocUnsafe(read)
120 copy.set(this._reading.subarray(0, read))
121
122 this.push(copy)
123 } else {
124 try {
125 if (binding.handshake(this._handle)) this._onconnect()
126 else break
127 } catch (err) {
128 if (this._pendingOpen) {
129 const cb = this._pendingOpen
130 this._pendingOpen = null
131 cb(errors.from(err))
132 } else {
133 this.destroy(errors.from(err))
134 }
135 return
136 }
137 }
138 }
139 }
140
141 _ondrain() {
142 if (this._pendingWrite === null) return
143 const cb = this._pendingWrite
144 this._pendingWrite = null
145 cb(null)
146 }
147
148 _onend() {
149 this.push(null)
150 }
151
152 _onerror(err) {
153 if (this._pendingOpen) {
154 const cb = this._pendingOpen
155 this._pendingOpen = null
156 cb(err)
157 } else {
158 this.destroy(err)
159 }
160 }
161
162 _onread(data) {
163 if (this._buffered < data.byteLength) return 0
164
165 let offset = 0
166 let remaining = data.byteLength
167
168 while (remaining > 0) {
169 const chunk = this._buffer[0]
170
171 if (chunk.byteLength <= remaining) {
172 data.set(chunk, offset)
173
174 offset += chunk.byteLength
175 remaining -= chunk.byteLength
176
177 this._buffer.shift()
178 } else {
179 data.set(chunk.subarray(0, remaining), offset)
180
181 this._buffer[0] = chunk.subarray(remaining)
182
183 remaining = 0
184 }
185 }
186
187 this._buffered -= data.byteLength
188
189 return data.byteLength
190 }
191
192 _onwrite(data) {
193 this._socket.write(Buffer.from(data.slice()))
194
195 return data.byteLength
196 }
197
198 _attach() {
199 if (this._state & constants.state.ATTACHED) return
200 this._state |= constants.state.ATTACHED
201
202 this._ondata = this._ondata.bind(this)
203 this._ondrain = this._ondrain.bind(this)
204 this._onend = this._onend.bind(this)
205 this._onerror = this._onerror.bind(this)
206
207 this._socket
208 .on('data', this._ondata)
209 .on('drain', this._ondrain)
210 .on('end', this._onend)
211 .on('error', this._onerror)
212 }
213
214 _detach() {
215 if (!(this._state & constants.state.ATTACHED)) return
216 this._state &= ~constants.state.ATTACHED
217
218 this._socket
219 .off('data', this._ondata)
220 .off('drain', this._ondrain)
221 .off('end', this._onend)
222 .off('error', this._onerror)
223 }
224
225 _open(cb) {
226 this._pendingOpen = cb
227 this._attach()
228
229 try {
230 if (binding.handshake(this._handle)) this._onconnect()
231 } catch (err) {
232 this._pendingOpen = null
233
234 cb(errors.from(err))
235 }
236 }
237
238 _write(data, encoding, cb) {
239 try {
240 binding.write(this._handle, data)
241
242 if (Writable.isBackpressured(this._socket)) {
243 this._pendingWrite = cb
244 } else {
245 cb(null)
246 }
247 } catch (err) {
248 this._pendingWrite = null
249
250 cb(errors.from(err))
251 }
252 }
253
254 _final(cb) {
255 try {
256 binding.shutdown(this._handle)
257
258 cb(null)
259 } catch (err) {
260 cb(err)
261 }
262
263 this._socket.end()
264 }
265
266 _predestroy() {
267 if (!this._handle) return
268
269 this._detach()
270
271 binding.destroy(this._handle)
272 this._handle = null
273 }
274
275 _destroy(err, cb) {
276 if (!this._handle) return cb(err)
277
278 this._detach()
279
280 binding.destroy(this._handle)
281 this._handle = null
282
283 cb(err)
284 }
285}
286
287exports.TLSSocket = exports.Socket // For Node.js compatibility
288
289exports.constants = constants
290exports.errors = errors
291
292const net = require('./net')
293
294exports.createConnection = net.createConnection
295exports.createServer = net.createServer
296
297// For Node.js compatibility
298exports.connect = exports.createConnection
node_modules/bare-tls/lib/constants.d.ts +8 -0
……@@ -0,0 +1,8 @@
1declare const constants: {
2 state: {
3 CONNECTED: number
4 ATTACHED: number
5 }
6}
7
8export = constants
node_modules/bare-tls/lib/constants.js +6 -0
……@@ -0,0 +1,6 @@
1module.exports = {
2 state: {
3 CONNECTED: 0x1,
4 ATTACHED: 0x2
5 }
6}
node_modules/bare-tls/lib/errors.d.ts +5 -0
……@@ -0,0 +1,5 @@
1declare class TLSError extends Error {
2 static from(err: Error): TLSError
3}
4
5export = TLSError
node_modules/bare-tls/lib/errors.js +18 -0
……@@ -0,0 +1,18 @@
1module.exports = class TLSError extends Error {
2 constructor(msg, code, fn = TLSError) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'TLSError'
13 }
14
15 static from(err) {
16 return new TLSError(err.message, err.code, TLSError.from)
17 }
18}
node_modules/bare-tls/net.js +127 -0
……@@ -0,0 +1,127 @@
1const EventEmitter = require('bare-events')
2const net = require('bare-net')
3const tls = require('bare-tls')
4
5class TLSNetSocket extends tls.Socket {
6 ref() {
7 this.socket.ref()
8 }
9
10 unref() {
11 this.socket.unref()
12 }
13}
14
15class TLSNetServer extends EventEmitter {
16 constructor(opts = {}, onconnection) {
17 if (typeof opts === 'function') {
18 onconnection = opts
19 opts = {}
20 }
21
22 const {
23 cert = null,
24 key = null,
25 host = null,
26 alpnProtocols = null,
27 eagerOpen = true,
28 allowHalfOpen = true
29 } = opts
30
31 super()
32
33 this._opts = {
34 cert,
35 key,
36 host,
37 alpnProtocols,
38 eagerOpen,
39 allowHalfOpen
40 }
41
42 this._server = net.createServer(opts)
43 this._server
44 .on('listening', this._onlistening.bind(this))
45 .on('connection', this._onconnection.bind(this))
46 .on('error', this._onerror.bind(this))
47 .on('close', this._onclose.bind(this))
48
49 if (onconnection) this.on('connection', onconnection)
50 }
51
52 get listening() {
53 return this._server.listening
54 }
55
56 address() {
57 return this._server.address()
58 }
59
60 listen(...args) {
61 this._server.listen(...args)
62 return this
63 }
64
65 close(onclose) {
66 if (onclose) this.once('close', onclose)
67 this._server.close()
68 }
69
70 ref() {
71 this._server.ref()
72 }
73
74 unref() {
75 this._server.unref()
76 }
77
78 _onlistening() {
79 this.emit('listening')
80 }
81
82 _onconnection(socket) {
83 this.emit(
84 'connection',
85 new TLSNetSocket(socket, { ...this._opts, isServer: true })
86 )
87 }
88
89 _onerror(err) {
90 this.emit('error', err)
91 }
92
93 _onclose() {
94 this.emit('close')
95 }
96}
97
98exports.createConnection = function createConnection(...args) {
99 let opts = {}
100 let onconnect
101
102 if (typeof args[0] === 'string') {
103 // createConnection(path[, onconnect])
104 opts.path = args[0]
105 onconnect = args[1]
106 } else if (typeof args[0] === 'number') {
107 // createConnection(port[, host][, onconnect])
108 opts.port = args[0]
109
110 if (typeof args[1] === 'function') {
111 onconnect = args[1]
112 } else {
113 opts.host = args[1]
114 onconnect = args[2]
115 }
116 } else {
117 // createConnection(opts[, onconnect])
118 opts = args[0] || {}
119 onconnect = args[1]
120 }
121
122 return new TLSNetSocket(net.createConnection(opts, onconnect), opts)
123}
124
125exports.createServer = function createServer(opts, onconnection) {
126 return new TLSNetServer(opts, onconnection)
127}
node_modules/bare-tls/package.json +60 -0
……@@ -0,0 +1,60 @@
1{
2 "name": "bare-tls",
3 "version": "2.2.1",
4 "description": "Transport Layer Security (TLS) streams for JavaScript",
5 "exports": {
6 ".": {
7 "types": "./index.d.ts",
8 "default": "./index.js"
9 },
10 "./package": "./package.json",
11 "./constants": {
12 "types": "./lib/constants.d.ts",
13 "default": "./lib/constants.js"
14 },
15 "./errors": {
16 "types": "./lib/errors.d.ts",
17 "default": "./lib/errors.js"
18 }
19 },
20 "files": [
21 "index.js",
22 "index.d.ts",
23 "net.js",
24 "binding.c",
25 "binding.js",
26 "CMakeLists.txt",
27 "lib",
28 "prebuilds"
29 ],
30 "addon": true,
31 "scripts": {
32 "test": "prettier . --check && bare test.js"
33 },
34 "repository": {
35 "type": "git",
36 "url": "git+https://github.com/holepunchto/bare-tls.git"
37 },
38 "author": "Holepunch",
39 "license": "Apache-2.0",
40 "bugs": {
41 "url": "https://github.com/holepunchto/bare-tls/issues"
42 },
43 "homepage": "https://github.com/holepunchto/bare-tls#readme",
44 "engines": {
45 "bare": ">=1.7.0"
46 },
47 "dependencies": {
48 "bare-net": "^2.0.1",
49 "bare-stream": "^2.6.4"
50 },
51 "devDependencies": {
52 "bare-events": "^2.6.0",
53 "bare-fs": "^4.0.2",
54 "brittle": "^3.1.1",
55 "cmake-bare": "^1.1.6",
56 "cmake-fetch": "^1.0.0",
57 "prettier": "^3.4.1",
58 "prettier-config-standard": "^7.0.0"
59 }
60}
node_modules/bare-tls/prebuilds/android-arm/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/android-arm64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/android-ia32/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/android-x64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/darwin-arm64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/darwin-x64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/ios-arm64-simulator/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/ios-arm64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/ios-x64-simulator/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/linux-arm64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/linux-x64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/win32-arm64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-tls/prebuilds/win32-x64/bare-tls.bare +0 -0
(no content changes — binary or rename)
node_modules/bare-utils/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-utils/README.md +20 -0
……@@ -0,0 +1,20 @@
1# bare-utils
2
3Node.js-compatibile utility functions for Bare.
4
5```
6npm i bare-utils
7```
8
9## Usage
10
11```js
12const util = require('bare-utils')
13
14util.format('Hello %s', 'world!')
15// Hello world!
16```
17
18## License
19
20Apache-2.0
node_modules/bare-utils/index.js +15 -0
……@@ -0,0 +1,15 @@
1const { TextEncoder, TextDecoder } = require('bare-encoding')
2
3exports.TextEncoder = TextEncoder
4exports.TextDecoder = TextDecoder
5
6exports.debuglog = require('bare-debug-log')
7exports.format = require('bare-format')
8exports.formatWithOptions = exports.format.formatWithOptions
9exports.inspect = require('bare-inspect')
10exports.styleText = require('bare-stylize')
11
12exports.deprecate = require('./lib/deprecate')
13exports.inherits = require('./lib/inherits')
14exports.promisify = require('./lib/promisify')
15exports.types = require('./lib/types')
node_modules/bare-utils/lib/deprecate.js +19 -0
……@@ -0,0 +1,19 @@
1module.exports = function deprecate(fn, msg, code) {
2 let warned = false
3
4 return function (...args) {
5 if (!warned) {
6 warned = true
7
8 if (code) {
9 console.warn(`[${code}]`, 'DeprecationWarning:', msg)
10 } else {
11 console.warn('DeprecationWarning:', msg)
12 }
13 }
14
15 if (new.target) return Reflect.construct(fn, args, new.target)
16
17 return Reflect.apply(fn, this, args)
18 }
19}
node_modules/bare-utils/lib/inherits.js +3 -0
……@@ -0,0 +1,3 @@
1module.exports = function inherits(ctor, superCtor) {
2 if (superCtor) Object.setPrototypeOf(ctor.prototype, superCtor.prototype)
3}
node_modules/bare-utils/lib/promisify.js +12 -0
……@@ -0,0 +1,12 @@
1module.exports = function promisify(fn) {
2 return function (...args) {
3 return new Promise((resolve, reject) => {
4 args.push((err, ...result) => {
5 if (err) reject(err)
6 else resolve(...result)
7 })
8
9 Reflect.apply(fn, this, args)
10 })
11 }
12}
node_modules/bare-utils/lib/types.js +103 -0
……@@ -0,0 +1,103 @@
1const type = require('bare-type')
2
3exports.isAnyArrayBuffer = (value) => {
4 const t = type(value)
5 return t.isArrayBuffer() || t.isSharedArrayBuffer()
6}
7
8exports.isArrayBufferView = (value) => ArrayBuffer.isView(value)
9
10exports.isArgumentsObject = (value) => type(value).isArguments()
11
12exports.isArrayBuffer = (value) => type(value).isArrayBuffer()
13
14exports.isAsyncFunction = (value) => type(value).isAsyncFunction()
15
16exports.isBigInt64Array = (value) => type(value).isBigInt64Array()
17
18exports.isBigIntObject = (value) => value instanceof BigInt
19
20exports.isBigUint64Array = (value) => type(value).isBigUint64Array()
21
22exports.isBooleanObject = (value) => value instanceof Boolean
23
24exports.isBoxedPrimitive = (value) =>
25 exports.isBigIntObject(value) ||
26 exports.isBooleanObject(value) ||
27 exports.isNumberObject(value) ||
28 exports.isStringObject(value) ||
29 exports.isSymbolObject(value)
30
31exports.isCryptoKey = () => {
32 throw new Error('Not implemented')
33}
34
35exports.isDataView = (value) => type(value).isDataView()
36
37exports.isDate = (value) => type(value).isDate()
38
39exports.isExternal = (value) => type(value).isExternal()
40
41exports.isFloat16Array = () => {
42 throw new Error('Not implemented')
43}
44
45exports.isFloat32Array = (value) => type(value).isFloat32Array()
46
47exports.isFloat64Array = (value) => type(value).isFloat64Array()
48
49exports.isGeneratorFunction = (value) => type(value).isGeneratorFunction()
50
51exports.isGeneratorObject = (value) => type(value).isGenerator()
52
53exports.isInt8Array = (value) => type(value).isInt8Array()
54
55exports.isInt16Array = (value) => type(value).isInt16Array()
56
57exports.isInt32Array = (value) => type(value).isInt32Array()
58
59exports.isKeyObject = () => {
60 throw new Error('Not implemented')
61}
62
63exports.isMap = (value) => type(value).isMap()
64
65exports.isMapIterator = () => {
66 throw new Error('Not implemented')
67}
68
69exports.isModuleNamespaceObject = (value) => type(value).isModuleNamespace()
70
71exports.isNativeError = () => {
72 throw new Error('Not implemented')
73}
74
75exports.isNumberObject = (value) => value instanceof Number
76
77exports.isPromise = (value) => type(value).isPromise()
78
79exports.isProxy = (value) => type(value).isProxy()
80
81exports.isRegExp = (value) => type(value).isRegExp()
82
83exports.isSet = (value) => type(value).isSet()
84
85exports.isSetIterator = () => {
86 throw new Error('Not implemented')
87}
88
89exports.isSharedArrayBuffer = (value) => type(value).isSharedArrayBuffer()
90
91exports.isStringObject = (value) => value instanceof String
92
93exports.isSymbolObject = (value) => value instanceof Symbol
94
95exports.isTypedArray = (value) => type(value).isTypedArray()
96
97exports.isUint8Array = (value) => type(value).isUint8Array()
98
99exports.isUint8ClampedArray = (value) => type(value).isUint8ClampedArray()
100
101exports.isUint16Array = (value) => type(value).isUint16Array()
102
103exports.isUint32Array = (value) => type(value).isUint32Array()
node_modules/bare-utils/package.json +41 -0
……@@ -0,0 +1,41 @@
1{
2 "name": "bare-utils",
3 "version": "1.6.0",
4 "description": "Node.js-compatible utility functions for Bare",
5 "exports": {
6 "./package": "./package.json",
7 ".": "./index.js",
8 "./types": "./lib/types.js"
9 },
10 "files": [
11 "index.js",
12 "types.js",
13 "lib"
14 ],
15 "scripts": {
16 "test": "prettier . --check && bare test.js"
17 },
18 "repository": {
19 "type": "git",
20 "url": "git+https://github.com/holepunchto/bare-utils.git"
21 },
22 "author": "Holepunch",
23 "license": "Apache-2.0",
24 "bugs": {
25 "url": "https://github.com/holepunchto/bare-utils/issues"
26 },
27 "homepage": "https://github.com/holepunchto/bare-utils#readme",
28 "dependencies": {
29 "bare-debug-log": "^2.0.0",
30 "bare-encoding": "^1.0.0",
31 "bare-format": "^1.0.0",
32 "bare-inspect": "^3.0.0",
33 "bare-stylize": "^0.0.1",
34 "bare-type": "^1.0.6"
35 },
36 "devDependencies": {
37 "brittle": "^3.5.0",
38 "prettier": "^3.5.3",
39 "prettier-config-holepunch": "^2.0.0"
40 }
41}
node_modules/bare-v8-to-istanbul/.github/workflows/lint.yml +22 -0
……@@ -0,0 +1,22 @@
1name: Run linter
2
3on:
4 push:
5 branches: [ main ]
6 pull_request:
7 branches: [ main ]
8
9jobs:
10 lint:
11 runs-on: ubuntu-latest
12 steps:
13 - uses: actions/checkout@v4
14
15 - name: Setup Node.js
16 uses: actions/setup-node@v4
17
18 - name: Install dependencies
19 run: npm i
20
21 - name: Lint
22 run: npm run lint
node_modules/bare-v8-to-istanbul/LICENSE +202 -0
……@@ -0,0 +1,202 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
202
node_modules/bare-v8-to-istanbul/README.md +9 -0
……@@ -0,0 +1,9 @@
1# bare-v8-to-istanbul
2Wrapper for v8-to-istanbul to make it work with Bare
3
4```bash
5npm i bare-v8-to-istanbul
6```
7
8## License
9Apache-2.0
node_modules/bare-v8-to-istanbul/index.js +10 -0
……@@ -0,0 +1,10 @@
1const { isBare } = require('which-runtime')
2
3if (isBare) {
4 const originalProcess = global.process
5 global.process = require('bare-process')
6
7 try { module.exports = require('v8-to-istanbul', { with: { imports: './package.json' } }) } finally { global.process = originalProcess }
8} else {
9 module.exports = require('v8-to-istanbul')
10}
node_modules/bare-v8-to-istanbul/package.json +56 -0
……@@ -0,0 +1,56 @@
1{
2 "name": "bare-v8-to-istanbul",
3 "version": "1.0.2",
4 "description": "Wrapper for v8-to-istanbul that works with Bare",
5 "license": "Apache-2.0",
6 "author": "Holepunch",
7 "main": "index.js",
8 "scripts": {
9 "test": "echo \"Error: no test specified\" && exit 1",
10 "lint": "standard"
11 },
12 "dependencies": {
13 "bare-assert": "^1.0.2",
14 "bare-fs": "^4.1.2",
15 "bare-module": "^6.1.2",
16 "bare-path": "^3.0.0",
17 "bare-process": "^4.2.0",
18 "bare-url": "^2.1.5",
19 "bare-utils": "^1.2.0",
20 "v8-to-istanbul": "^9.3.0",
21 "which-runtime": "^1.2.1"
22 },
23 "imports": {
24 "assert": {
25 "bare": "bare-assert",
26 "default": "assert"
27 },
28 "fs": {
29 "bare": "bare-fs",
30 "default": "fs"
31 },
32 "module": {
33 "bare": "bare-module",
34 "default": "module"
35 },
36 "path": {
37 "bare": "bare-path",
38 "default": "path"
39 },
40 "process": {
41 "bare": "bare-process",
42 "default": "process"
43 },
44 "url": {
45 "bare": "bare-url",
46 "default": "url"
47 },
48 "util": {
49 "bare": "bare-utils",
50 "default": "util"
51 }
52 },
53 "devDependencies": {
54 "standard": "^17.1.2"
55 }
56}
node_modules/bare-ws/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/bare-ws/README.md +29 -0
……@@ -0,0 +1,29 @@
1# bare-ws
2
3WebSocket library for JavaScript.
4
5```
6npm i bare-ws
7```
8
9## Usage
10
11```js
12const ws = require('bare-ws')
13
14const server = new ws.Server({ port: 8080 }, (socket) => {
15 socket.on('data', (data) => {
16 console.log(data.toString())
17 })
18})
19
20server.on('listening', () => {
21 const socket = new ws.Socket({ port: 8080 })
22
23 socket.write('Hello WebSocket')
24})
25```
26
27## License
28
29Apache-2.0
node_modules/bare-ws/global.d.ts +9 -0
……@@ -0,0 +1,9 @@
1import * as ws from '.'
2
3type WebSocketConstructor = typeof ws.Socket
4
5declare global {
6 type WebSocket = ws.Socket
7
8 const WebSocket: WebSocketConstructor
9}
node_modules/bare-ws/global.js +3 -0
……@@ -0,0 +1,3 @@
1const ws = require('.')
2
3global.WebSocket = ws.Socket
node_modules/bare-ws/index.d.ts +4 -0
……@@ -0,0 +1,4 @@
1import WebSocket from './lib/socket'
2import WebSocketServer from './lib/server'
3
4export { WebSocket as Socket, WebSocketServer as Server }
node_modules/bare-ws/index.js +2 -0
……@@ -0,0 +1,2 @@
1exports.Server = require('./lib/server')
2exports.Socket = require('./lib/socket')
node_modules/bare-ws/lib/constants.d.ts +17 -0
……@@ -0,0 +1,17 @@
1import Buffer from 'bare-buffer'
2
3export const EOL: string
4export const EOF: string
5
6export const GUID: Buffer
7
8export const opcode: {
9 CONTINUATION: number
10 TEXT: number
11 BINARY: number
12 CLOSE: number
13 PING: number
14 PONG: number
15}
16
17export const status: { PROTOCOL_ERROR: number; MESSAGE_TOO_LARGE: number }
node_modules/bare-ws/lib/constants.js +20 -0
……@@ -0,0 +1,20 @@
1exports.EOL = '\r\n'
2exports.EOF = exports.EOL.repeat(2)
3
4exports.GUID = Buffer.from('258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
5
6// https://datatracker.ietf.org/doc/html/rfc6455#section-11.8
7exports.opcode = {
8 CONTINUATION: 0x0,
9 TEXT: 0x1,
10 BINARY: 0x2,
11 CLOSE: 0x8,
12 PING: 0x9,
13 PONG: 0xa
14}
15
16// https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1
17exports.status = {
18 PROTOCOL_ERROR: 1002,
19 MESSAGE_TOO_LARGE: 1009
20}
node_modules/bare-ws/lib/errors.d.ts +23 -0
……@@ -0,0 +1,23 @@
1declare class WebSocketError extends Error {
2 constructor(msg: string, code: string, status: number, fn?: WebSocketError, cause?: unknown)
3
4 static NETWORK_ERROR(msg: string, cause?: unknown): WebSocketError
5 static NOT_CONNECTED(msg?: string): WebSocketError
6 static UNEXPECTED_RSV1(msg?: string): WebSocketError
7 static UNEXPECTED_RSV2(msg?: string): WebSocketError
8 static UNEXPECTED_RSV3(msg?: string): WebSocketError
9 static EXPECTED_MASK(msg?: string): WebSocketError
10 static EXPECTED_CONTINUATION(msg?: string): WebSocketError
11 static UNEXPECTED_CONTINUATION(msg?: string): WebSocketError
12 static UNEXPECTED_CONTROL(msg?: string): WebSocketError
13 static INVALID_ENCODING(msg?: string): WebSocketError
14 static INVALID_UPGRADE_HEADER(msg?: string): WebSocketError
15 static INVALID_VERSION_HEADER(msg?: string): WebSocketError
16 static INVALID_KEY_HEADER(msg?: string): WebSocketError
17 static INVALID_ACCEPT_HEADER(msg?: string): WebSocketError
18 static INVALID_OPCODE(msg?: string): WebSocketError
19 static INVALID_PAYLOAD_LENGTH(msg?: string): WebSocketError
20 static INCOMPLETE_FRAME(msg?: string, length?: number): WebSocketError
21}
22
23export = WebSocketError
node_modules/bare-ws/lib/errors.js +164 -0
……@@ -0,0 +1,164 @@
1const { status } = require('./constants')
2
3module.exports = class WebSocketError extends Error {
4 constructor(msg, code, status, fn = WebSocketError, cause) {
5 super(`${code}: ${msg}`, { cause })
6 this.code = code
7 this.status = status
8
9 if (Error.captureStackTrace) {
10 Error.captureStackTrace(this, fn)
11 }
12 }
13
14 get name() {
15 return 'WebSocketError'
16 }
17
18 static NETWORK_ERROR(msg, cause) {
19 return new WebSocketError(msg, 'NETWORK_ERROR', 0, WebSocketError.NETWORK_ERROR, cause)
20 }
21
22 static NOT_CONNECTED(msg = 'Socket is not connected') {
23 return new WebSocketError(msg, 'NOT_CONNECTED', 0, WebSocketError.NOT_CONNECTED)
24 }
25
26 static UNEXPECTED_RSV1(msg = 'RSV1 must be unset') {
27 return new WebSocketError(
28 msg,
29 'UNEXPECTED_RSV1',
30 status.PROTOCOL_ERROR,
31 WebSocketError.UNEXPECTED_RSV1
32 )
33 }
34
35 static UNEXPECTED_RSV2(msg = 'RSV2 must be unset') {
36 return new WebSocketError(
37 msg,
38 'UNEXPECTED_RSV2',
39 status.PROTOCOL_ERROR,
40 WebSocketError.UNEXPECTED_RSV2
41 )
42 }
43
44 static UNEXPECTED_RSV3(msg = 'RSV3 must be unset') {
45 return new WebSocketError(
46 msg,
47 'UNEXPECTED_RSV3',
48 status.PROTOCOL_ERROR,
49 WebSocketError.UNEXPECTED_RSV3
50 )
51 }
52
53 static EXPECTED_MASK(msg = 'MASK must be set') {
54 return new WebSocketError(
55 msg,
56 'EXPECTED_MASK',
57 status.PROTOCOL_ERROR,
58 WebSocketError.EXPECTED_MASK
59 )
60 }
61
62 static UNEXPECTED_MASK(msg = 'MASK must be unset') {
63 return new WebSocketError(
64 msg,
65 'UNEXPECTED_MASK',
66 status.PROTOCOL_ERROR,
67 WebSocketError.UNEXPECTED_MASK
68 )
69 }
70
71 static EXPECTED_CONTINUATION(msg = 'Expected a continuation frame') {
72 return new WebSocketError(
73 msg,
74 'EXPECTED_CONTINUATION',
75 status.PROTOCOL_ERROR,
76 WebSocketError.EXPECTED_CONTINUATION
77 )
78 }
79
80 static UNEXPECTED_CONTINUATION(msg = 'Unexpected continuation frame') {
81 return new WebSocketError(
82 msg,
83 'UNEXPECTED_CONTINUATION',
84 status.PROTOCOL_ERROR,
85 WebSocketError.UNEXPECTED_CONTINUATION
86 )
87 }
88
89 static UNEXPECTED_CONTROL(msg = 'Unexpected control frame') {
90 return new WebSocketError(
91 msg,
92 'UNEXPECTED_CONTROL',
93 status.PROTOCOL_ERROR,
94 WebSocketError.UNEXPECTED_CONTROL
95 )
96 }
97
98 static INVALID_ENCODING(msg = 'Invalid encoding') {
99 return new WebSocketError(
100 msg,
101 'INVALID_ENCODING',
102 status.PROTOCOL_ERROR,
103 WebSocketError.INVALID_ENCODING
104 )
105 }
106
107 static INVALID_UPGRADE_HEADER(msg = 'Invalid Upgrade header') {
108 return new WebSocketError(
109 msg,
110 'INVALID_UPGRADE_HEADER',
111 status.PROTOCOL_ERROR,
112 WebSocketError.INVALID_UPGRADE_HEADER
113 )
114 }
115
116 static INVALID_VERSION_HEADER(msg = 'Invalid Sec-WebSocket-Version header') {
117 return new WebSocketError(
118 msg,
119 'INVALID_VERSION_HEADER',
120 status.PROTOCOL_ERROR,
121 WebSocketError.INVALID_VERSION_HEADER
122 )
123 }
124
125 static INVALID_KEY_HEADER(msg = 'Invalid Sec-WebSocket-Key header') {
126 return new WebSocketError(
127 msg,
128 'INVALID_KEY_HEADER',
129 status.PROTOCOL_ERROR,
130 WebSocketError.INVALID_KEY_HEADER
131 )
132 }
133
134 static INVALID_ACCEPT_HEADER(msg = 'Invalid Sec-WebSocket-Accept header') {
135 return new WebSocketError(
136 msg,
137 'INVALID_ACCEPT_HEADER',
138 status.PROTOCOL_ERROR,
139 WebSocketError.INVALID_ACCEPT_HEADER
140 )
141 }
142
143 static INVALID_OPCODE(msg = 'Invalid opcode') {
144 return new WebSocketError(
145 msg,
146 'INVALID_OPCODE',
147 status.PROTOCOL_ERROR,
148 WebSocketError.INVALID_OPCODE
149 )
150 }
151
152 static INVALID_PAYLOAD_LENGTH(msg = 'Invalid payload length') {
153 return new WebSocketError(
154 msg,
155 'INVALID_PAYLOAD_LENGTH',
156 status.MESSAGE_TOO_LARGE,
157 WebSocketError.INVALID_PAYLOAD_LENGTH
158 )
159 }
160
161 static INCOMPLETE_FRAME(msg = 'Incomplete frame', length = -1) {
162 return new WebSocketError(msg, 'INCOMPLETE_FRAME', length, WebSocketError.INCOMPLETE_FRAME)
163 }
164}
node_modules/bare-ws/lib/frame.js +215 -0
……@@ -0,0 +1,215 @@
1const crypto = require('bare-crypto')
2const errors = require('./errors')
3
4const EMPTY = Buffer.alloc(0)
5
6const FIN = 0b10000000
7const RSV1 = 0b01000000
8const RSV2 = 0b00100000
9const RSV3 = 0b00010000
10const OPCODE = 0b00001111
11const MASK = 0b10000000
12const LENGTH = 0b01111111
13
14// https://datatracker.ietf.org/doc/html/rfc6455#section-5
15module.exports = exports = class Frame {
16 constructor(opcode, payload = EMPTY, opts = {}) {
17 if (payload && !Buffer.isBuffer(payload)) {
18 opts = payload
19 payload = EMPTY
20 }
21
22 const { fin = true, rsv1 = false, rsv2 = false, rsv3 = false, mask = null } = opts
23
24 this.fin = fin
25 this.rsv1 = rsv1
26 this.rsv2 = rsv2
27 this.rsv3 = rsv3
28 this.opcode = opcode
29 this.mask = mask
30 this.payload = payload
31 }
32
33 toBuffer() {
34 const state = { start: 0, end: 0, buffer: null }
35
36 Frame.preencode(state, this)
37
38 state.buffer = Buffer.allocUnsafe(state.end)
39
40 Frame.encode(state, this)
41
42 return state.buffer
43 }
44}
45
46const Frame = exports
47
48exports.preencode = function preencode(state, f) {
49 let i = state.end
50
51 i++
52
53 const length = f.payload.length
54
55 if (length <= 0x7d) i++
56 else {
57 if (length <= 0xffff) i += 3
58 else i += 9
59 }
60
61 if (f.mask) i += 4
62
63 i += length
64
65 state.end = i
66}
67
68exports.encode = function encode(state, f) {
69 const b = state.buffer
70
71 let i = state.start
72
73 const v = new DataView(b.buffer, b.byteOffset, b.byteLength)
74
75 b[i] = f.opcode & OPCODE
76
77 if (f.fin) b[i] |= FIN
78 if (f.rsv1) b[i] |= RSV1
79 if (f.rsv1) b[i] |= RSV2
80 if (f.rsv1) b[i] |= RSV3
81
82 i++
83
84 b[i] = f.mask ? MASK : 0
85
86 const length = f.payload.length
87
88 if (length <= 0x7d) b[i++] |= length
89 else {
90 if (length <= 0xffff) {
91 b[i++] |= 0x7e
92
93 v.setUint16(i, length, false)
94
95 i += 2
96 } else {
97 b[i++] |= 0x7f
98
99 const high = Math.floor(length / 0x100000000)
100
101 v.setUint32(i, high, false)
102
103 i += 4
104
105 const low = length & 0xffffffff
106
107 v.setUint32(i, low, false)
108
109 i += 4
110 }
111 }
112
113 if (f.mask) {
114 crypto.randomFill(f.mask, 0, 4)
115
116 b.set(f.mask, i)
117
118 i += 4
119
120 for (let j = 0; j < length; j++) {
121 b[i + j] = f.payload[j] ^ f.mask[j & 3]
122 }
123 } else {
124 b.set(f.payload, i)
125 }
126
127 i += length
128
129 state.start = i
130}
131
132exports.decode = function decode(state) {
133 const s = state.start
134 const b = state.buffer
135
136 let i = s
137 let n = b.byteLength
138
139 if (n < 2) throw errors.INCOMPLETE_FRAME()
140
141 const view = new DataView(b.buffer, b.byteOffset, b.byteLength)
142
143 const fin = !!(b[i] & FIN)
144
145 const rsv1 = !!(b[i] & RSV1)
146 const rsv2 = !!(b[i] & RSV2)
147 const rsv3 = !!(b[i] & RSV3)
148
149 const opcode = b[i] & OPCODE
150
151 i++
152 n--
153
154 const masked = !!(b[i] & MASK)
155
156 let length = b[i] & LENGTH
157
158 i++
159 n--
160
161 if (length === 0x7e) {
162 if (n < 2) throw errors.INCOMPLETE_FRAME()
163
164 length = view.getUint16(i, false)
165
166 i += 2
167 n -= 2
168 } else if (length === 0x7f) {
169 if (n < 8) throw errors.INCOMPLETE_FRAME()
170
171 const high = view.getUint32(i, false)
172
173 if (high >= 0x200000) throw errors.INVALID_PAYLOAD_LENGTH()
174
175 i += 4
176 n -= 4
177
178 const low = view.getUint32(i, false)
179
180 i += 4
181 n -= 4
182
183 length = high * 0x100000000 + low
184 }
185
186 let mask = null
187
188 if (masked) {
189 if (n < 4) throw errors.INCOMPLETE_FRAME()
190
191 mask = b.subarray(i, i + 4)
192
193 i += 4
194 n -= 4
195 }
196
197 if (n < length) {
198 throw errors.INCOMPLETE_FRAME('Incomplete frame', i - s + length)
199 }
200
201 const payload = b.subarray(i, i + length)
202
203 i += length
204 n -= length
205
206 if (mask) {
207 for (let i = 0; i < length; i++) {
208 payload[i] ^= mask[i & 3]
209 }
210 }
211
212 state.start = i
213
214 return new Frame(opcode, payload, { fin, rsv1, rsv2, rsv3, mask })
215}
node_modules/bare-ws/lib/server.d.ts +57 -0
……@@ -0,0 +1,57 @@
1import { type HTTPSServerConnectionOptions } from 'bare-https'
2import { HTTPClientRequest, type HTTPServerConnectionOptions } from 'bare-http1'
3import { Socket as TCPSocket, type TCPSocketAddress } from 'bare-tcp'
4import { type DuplexEvents } from 'bare-stream'
5import EventEmitter from 'bare-events'
6import Buffer from 'bare-buffer'
7import WebSocket from './socket'
8import WebSocketError from './errors'
9
10interface WebSocketServerOptions extends HTTPServerConnectionOptions, HTTPSServerConnectionOptions {
11 secure?: boolean
12}
13
14interface WebSocketServerEvents extends DuplexEvents {
15 connection: [socket: WebSocket, req: HTTPClientRequest]
16 listening: []
17}
18
19interface WebSocketServer<M extends WebSocketServerEvents = WebSocketServerEvents>
20 extends EventEmitter<M> {
21 readonly listening: boolean
22
23 address(): TCPSocketAddress
24 close(cb?: (err?: Error | null) => void): this
25 ref(): this
26 unref(): this
27}
28
29declare class WebSocketServer {
30 constructor(onconnection: (socket: WebSocket, req: HTTPClientRequest) => void)
31
32 constructor(
33 opts?: WebSocketServerOptions,
34 onconnection?: (socket: WebSocket, req: HTTPClientRequest) => void
35 )
36}
37
38declare namespace WebSocketServer {
39 export { type WebSocketServerOptions, type WebSocketServerEvents }
40
41 export function handshake(req: HTTPClientRequest, cb: (err: WebSocketError | null) => void): void
42
43 export function handshake(
44 req: HTTPClientRequest,
45 socket: TCPSocket,
46 cb?: (err: WebSocketError | null) => void
47 ): void
48
49 export function handshake(
50 req: HTTPClientRequest,
51 socket?: TCPSocket,
52 head?: Buffer,
53 cb?: (err: WebSocketError | null) => void
54 ): void
55}
56
57export = WebSocketServer
node_modules/bare-ws/lib/server.js +131 -0
……@@ -0,0 +1,131 @@
1const EventEmitter = require('bare-events')
2const http = require('bare-http1')
3const https = require('bare-https')
4const crypto = require('bare-crypto')
5const { GUID, EOL, EOF } = require('./constants')
6const errors = require('./errors')
7const WebSocket = require('./socket')
8
9const EMPTY = Buffer.alloc(0)
10
11const KEY = /^[+/0-9A-Za-z]{22}==$/
12
13module.exports = exports = class WebSocketServer extends EventEmitter {
14 constructor(opts = {}, onconnection) {
15 if (typeof opts === 'function') {
16 onconnection = opts
17 opts = {}
18 }
19
20 super()
21
22 const createServer = opts.secure ? https.createServer : http.createServer
23
24 const {
25 server = createServer(opts, this._onrequest.bind(this)).listen(
26 opts,
27 this._onlistening.bind(this)
28 )
29 } = opts
30
31 this._server = server
32
33 this._server.on('upgrade', this._onupgrade.bind(this))
34
35 if (onconnection) this.on('connection', onconnection)
36 }
37
38 get listening() {
39 return this._server.listening
40 }
41
42 address() {
43 return this._server.address()
44 }
45
46 close(cb) {
47 this._server.close(cb)
48
49 return this
50 }
51
52 ref() {
53 this._server.ref()
54
55 return this
56 }
57
58 unref() {
59 this._server.unref()
60
61 return this
62 }
63
64 _onlistening() {
65 this.emit('listening')
66 }
67
68 _onrequest(req, res) {
69 const body = http.constants.status[426]
70
71 res.writeHead(426, {
72 'Content-Type': 'text/plain',
73 'Content-Length': body.length
74 })
75
76 res.end(body)
77 }
78
79 _onupgrade(req, socket, head) {
80 exports.handshake(req, socket, head, (err) => {
81 if (err) return socket.destroy(err)
82
83 this.emit('connection', new WebSocket({ socket, isServer: true }), req)
84 })
85 }
86}
87
88// https://datatracker.ietf.org/doc/html/rfc6455#section-4.2
89exports.handshake = function handshake(req, socket = req.socket, head = EMPTY, cb) {
90 if (typeof socket === 'function') {
91 cb = socket
92 socket = req.socket
93 head = EMPTY
94 } else if (typeof head === 'function') {
95 cb = head
96 head = EMPTY
97 }
98
99 if (req.headers.upgrade.toLowerCase() !== 'websocket') {
100 return cb(errors.INVALID_UPGRADE_HEADER())
101 }
102
103 const version = +req.headers['sec-websocket-version']
104
105 if (version !== 8 && version !== 13) {
106 return cb(errors.INVALID_VERSION_HEADER())
107 }
108
109 const key = req.headers['sec-websocket-key']
110
111 if (!key || !KEY.test(key)) {
112 return cb(errors.INVALID_KEY_HEADER())
113 }
114
115 const digest = crypto.createHash('sha1').update(key).update(GUID).digest('base64')
116
117 socket.write(
118 'HTTP/1.1 101 Web Socket Protocol Handshake' +
119 EOL +
120 'Upgrade: WebSocket' +
121 EOL +
122 'Connection: Upgrade' +
123 EOL +
124 `Sec-WebSocket-Accept: ${digest}` +
125 EOF
126 )
127
128 if (head.byteLength) socket.unshift(head)
129
130 cb(null)
131}
node_modules/bare-ws/lib/socket.d.ts +40 -0
……@@ -0,0 +1,40 @@
1import { HTTPClientRequest } from 'bare-http1'
2import { Socket as TCPSocket } from 'bare-tcp'
3import { Duplex, type DuplexEvents } from 'bare-stream'
4import URL from 'bare-url'
5import WebSocketError from './errors'
6
7interface WebSocketOptions {
8 host?: string
9 hostname?: string
10 path?: string
11 port?: string | number
12 secure?: boolean
13 socket?: TCPSocket
14}
15
16interface WebSocketEvents extends DuplexEvents {
17 ping: [payload: unknown]
18 pong: [payload: unknown]
19}
20
21interface WebSocket<M extends WebSocketEvents = WebSocketEvents> extends Duplex<M> {
22 ping(data: unknown): void
23 pong(data: unknown): void
24}
25
26declare class WebSocket {
27 constructor(opts: WebSocketOptions)
28 constructor(url: URL | string, opts?: WebSocketOptions)
29}
30
31declare namespace WebSocket {
32 export { type WebSocketOptions, type WebSocketEvents }
33
34 export function handshake(
35 req: HTTPClientRequest,
36 cb: (error: WebSocketError | null) => void
37 ): void
38}
39
40export = WebSocket
node_modules/bare-ws/lib/socket.js +300 -0
……@@ -0,0 +1,300 @@
1const { Duplex } = require('bare-stream')
2const http = require('bare-http1')
3const https = require('bare-https')
4const crypto = require('bare-crypto')
5const { GUID, opcode } = require('./constants')
6const errors = require('./errors')
7const Frame = require('./frame')
8
9const CLOSE = new Frame(opcode.CLOSE).toBuffer()
10
11module.exports = exports = class WebSocket extends Duplex {
12 constructor(url, opts = {}) {
13 if (typeof url === 'string') url = new URL(url)
14
15 if (isURL(url)) {
16 opts = opts ? { ...opts } : {}
17
18 opts.host = url.hostname
19 opts.path = url.pathname + url.search
20 opts.port = url.port ? parseInt(url.port, 10) : defaultPort(url)
21 opts.secure = url.protocol === 'https:' || url.protocol === 'wss:'
22 } else {
23 opts = url ? { ...url } : {}
24
25 // For Node.js compatibility
26 opts.host = opts.hostname || opts.host
27 opts.port = typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
28 }
29
30 const { isServer = false, socket = null } = opts
31
32 super({ eagerOpen: true })
33
34 this._socket = null
35 this._isServer = isServer
36 this._mask = isServer ? null : Buffer.allocUnsafe(4)
37 this._fragments = []
38
39 this._pendingOpen = null
40 this._pendingWrite = null
41
42 this._buffer = []
43 this._buffered = 0
44 this._frame = -1
45
46 if (socket !== null) this._attach(socket)
47 else this._connect(opts)
48 }
49
50 ping(data) {
51 if (this._socket === null) throw errors.NOT_CONNECTED()
52
53 if (typeof data === 'string') data = Buffer.from(data)
54
55 this._socket.write(new Frame(opcode.PING, data, { mask: this._mask }).toBuffer())
56 }
57
58 pong(data) {
59 if (this._socket === null) throw errors.NOT_CONNECTED()
60
61 if (typeof data === 'string') data = Buffer.from(data)
62
63 this._socket.write(new Frame(opcode.PONG, data, { mask: this._mask }).toBuffer())
64 }
65
66 _attach(socket) {
67 this._socket = socket
68
69 this._socket
70 .on('error', this._onerror.bind(this))
71 .on('close', this._onclose.bind(this))
72 .on('data', this._ondata.bind(this))
73 .on('drain', this._ondrain.bind(this))
74 }
75
76 _connect(opts) {
77 const request = opts.secure ? https.request : http.request
78
79 const req = request(opts)
80
81 exports.handshake(req, (err) => {
82 const cb = this._pendingOpen
83 this._pendingOpen = null
84
85 if (err) req.socket.destroy()
86 else this._attach(req.socket)
87
88 cb(err)
89 })
90 }
91
92 _onerror(err) {
93 this.destroy(err)
94 }
95
96 _onclose() {
97 this.destroy()
98 }
99
100 _ondata(data) {
101 this._buffer.push(data)
102 this._buffered += data.byteLength
103
104 while (this._frame === -1 || this._frame <= this._buffered) {
105 const buffer = this._buffer.length === 1 ? this._buffer[0] : Buffer.concat(this._buffer)
106
107 this._buffer = [buffer]
108
109 const state = { start: 0, end: buffer.length, buffer }
110
111 try {
112 this._onframe(Frame.decode(state))
113 } catch (err) {
114 if (err.code === 'INCOMPLETE_FRAME') this._frame = err.status
115 else this.destroy(err)
116 return
117 }
118
119 this._buffered -= state.start
120 this._buffer = this._buffered > 0 ? [buffer.subarray(state.start)] : []
121 this._frame = -1
122 }
123 }
124
125 _onframe(frame) {
126 if (frame.rsv1) throw errors.UNEXPECTED_RSV1()
127
128 if (frame.rsv2) throw errors.UNEXPECTED_RSV2()
129
130 if (frame.rsv3) throw errors.UNEXPECTED_RSV3()
131
132 if (frame.payload.length > 0 && !frame.mask === this._isServer) {
133 throw this._isServer ? errors.EXPECTED_MASK() : errors.UNEXPECTED_MASK()
134 }
135
136 if (frame.fin === false) {
137 if (this._fragments.push(frame) === 1) {
138 // First frame
139 if (frame.opcode === opcode.CONTINUATION) {
140 throw errors.UNEXPECTED_CONTINUATION()
141 }
142
143 if (frame.opcode >= opcode.CLOSE) {
144 throw errors.UNEXPECTED_CONTROL()
145 }
146
147 return
148 }
149
150 if (frame.opcode !== opcode.CONTINUATION) {
151 throw errors.EXPECTED_CONTINUATION()
152 }
153
154 return
155 }
156
157 switch (frame.opcode) {
158 case opcode.CLOSE:
159 this.push(null)
160 this.end()
161 return
162
163 case opcode.PING:
164 this.pong(frame.payload)
165 this.emit('ping', frame.payload)
166 return
167
168 case opcode.PONG:
169 this.emit('pong', frame.payload)
170 return
171
172 case opcode.CONTINUATION: {
173 if (this._fragments.length === 0) throw errors.UNEXPECTED_CONTINUATION()
174
175 frame.opcode = this._fragments[0].opcode
176
177 const payloads = this._fragments.map((frame) => frame.payload)
178
179 payloads.push(frame.payload)
180
181 frame.payload = Buffer.concat(payloads)
182
183 this._fragments = []
184
185 break
186 }
187
188 default:
189 if (this._fragments.length > 0) throw errors.EXPECTED_CONTINUATION()
190 }
191
192 switch (frame.opcode) {
193 case opcode.TEXT:
194 case opcode.BINARY:
195 this.push(frame.payload)
196 break
197
198 default:
199 throw errors.INVALID_OPCODE()
200 }
201 }
202
203 _ondrain() {
204 if (this._pendingWrite === null) return
205 const cb = this._pendingWrite
206 this._pendingWrite = null
207 cb(null)
208 }
209
210 _open(cb) {
211 if (this._socket === null) this._pendingOpen = cb
212 else cb(null)
213 }
214
215 _write(data, encoding, cb) {
216 if (encoding !== 'buffer' && encoding !== 'utf8') {
217 return cb(errors.INVALID_ENCODING())
218 }
219
220 const frame = new Frame(encoding === 'buffer' ? opcode.BINARY : opcode.TEXT, data, {
221 mask: this._mask
222 })
223
224 if (this._socket.write(frame.toBuffer())) cb(null)
225 else this._pendingWrite = cb
226 }
227
228 _final(cb) {
229 this._socket.end(CLOSE)
230 cb(null)
231 }
232
233 _predestroy() {
234 if (!this._socket) return
235 this._socket.destroy()
236 }
237}
238
239// https://datatracker.ietf.org/doc/html/rfc6455#section-4.1
240exports.handshake = function handshake(req, cb) {
241 const key = crypto.randomBytes(16).toString('base64')
242
243 req.headers = {
244 ...req.headers,
245 Connection: 'Upgrade',
246 Upgrade: 'websocket',
247 'Sec-WebSocket-Version': 13,
248 'Sec-WebSocket-Key': key
249 }
250
251 req.on('upgrade', (res, socket, head) => {
252 if (res.headers.upgrade.toLowerCase() !== 'websocket') {
253 return cb(errors.INVALID_UPGRADE_HEADER())
254 }
255
256 const digest = crypto.createHash('sha1').update(key).update(GUID).digest('base64')
257
258 if (res.headers['sec-websocket-accept'] !== digest) {
259 return cb(errors.INVALID_ACCEPT_HEADER())
260 }
261
262 if (head.byteLength) socket.unshift(head)
263
264 cb(null)
265 })
266
267 req.on('error', (err) => {
268 cb(errors.NETWORK_ERROR('Network error', err))
269 })
270
271 req.end()
272}
273
274// https://url.spec.whatwg.org/#default-port
275function defaultPort(url) {
276 switch (url.protocol) {
277 case 'ftp:':
278 return 21
279 case 'http:':
280 case 'ws:':
281 return 80
282 case 'https:':
283 case 'wss:':
284 return 443
285 }
286
287 return null
288}
289
290// https://url.spec.whatwg.org/#api
291function isURL(url) {
292 return (
293 url !== null &&
294 typeof url === 'object' &&
295 typeof url.protocol === 'string' &&
296 typeof url.hostname === 'string' &&
297 typeof url.pathname === 'string' &&
298 typeof url.search === 'string'
299 )
300}
node_modules/bare-ws/package.json +71 -0
……@@ -0,0 +1,71 @@
1{
2 "name": "bare-ws",
3 "version": "2.1.0",
4 "description": "WebSocket library for JavaScript",
5 "exports": {
6 "./package": "./package.json",
7 ".": {
8 "types": "./index.d.ts",
9 "default": "./index.js"
10 },
11 "./global": {
12 "types": "./global.d.ts",
13 "default": "./global.js"
14 },
15 "./constants": {
16 "types": "./lib/constants.d.ts",
17 "default": "./lib/constants.js"
18 },
19 "./errors": {
20 "types": "./lib/errors.d.ts",
21 "default": "./lib/errors.js"
22 }
23 },
24 "files": [
25 "index.js",
26 "index.d.ts",
27 "global.js",
28 "global.d.ts",
29 "lib"
30 ],
31 "scripts": {
32 "test": "prettier . --check && bare test.js"
33 },
34 "repository": {
35 "type": "git",
36 "url": "git+https://github.com/holepunchto/bare-ws.git"
37 },
38 "author": "Holepunch",
39 "license": "Apache-2.0",
40 "bugs": {
41 "url": "https://github.com/holepunchto/bare-ws/issues"
42 },
43 "homepage": "https://github.com/holepunchto/bare-ws#readme",
44 "dependencies": {
45 "bare-crypto": "^1.2.0",
46 "bare-events": "^2.3.1",
47 "bare-http1": "^4.0.0",
48 "bare-https": "^2.0.0",
49 "bare-stream": "^2.1.2"
50 },
51 "devDependencies": {
52 "bare-buffer": "^3.0.2",
53 "bare-fs": "^4.0.0",
54 "bare-url": "^2.1.3",
55 "brittle": "^3.3.0",
56 "prettier": "^3.4.1",
57 "prettier-config-holepunch": "^2.0.0"
58 },
59 "peerDependencies": {
60 "bare-buffer": "*",
61 "bare-url": "*"
62 },
63 "peerDependenciesMeta": {
64 "bare-buffer": {
65 "optional": true
66 },
67 "bare-url": {
68 "optional": true
69 }
70 }
71}
node_modules/bits-to-bytes/LICENSE +15 -0
……@@ -0,0 +1,15 @@
1ISC License
2
3Copyright (c) 2022 Contributors
4
5Permission to use, copy, modify, and/or distribute this software for any
6purpose with or without fee is hereby granted, provided that the above
7copyright notice and this permission notice appear in all copies.
8
9THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15PERFORMANCE OF THIS SOFTWARE.
node_modules/bits-to-bytes/README.md +80 -0
……@@ -0,0 +1,80 @@
1# Bits to Bytes
2
3Functions for doing bit manipulation of typed arrays.
4
5```npm
6npm i bits-to-bytes
7```
8
9## Usage
10
11```js
12const bits = require('bits-to-bytes')
13
14const buffer = Uint8Array.from([0b11001000])
15
16bits.get(buffer, 3)
17// true
18```
19
20`buffer` may be any typed array with a `number` element type, including `Uint8Array`, `Uint16Array`, and `Uint32Array`.
21
22## API
23
24#### `const n = bits.byteLength(size)`
25
26Get the number of bytes required to contain `size` bits.
27
28#### `const b = bits.get(buffer, bit)`
29
30Get the given bit, which will either be `true` (set) or `false` (unset).
31
32#### `const changed = bits.set(buffer, bit[, value])`
33
34Set the given bit to `value`, which defaults to `true`. Returns `true` if the bit changed, otherwise `false`.
35
36#### `const changed = bits.setRange(buffer, start, end[, value])`
37
38Set the given bit range to `value`, which defaults to `true`. Returns `true` if any of the bits changed, otherwise `false`.
39
40If you don't need the additional information about whether any of the bits changed, consider `bits.fill()` as a more performant alternative.
41
42#### `buffer = bits.fill(buffer, value[, start[, end]])`
43
44Fill the given bit range with `value`. `start` defaults to `0` and `end` defaults to the bit length of the array. Returns the modified array.
45
46#### `const b = bits.toggle(buffer, bit)`
47
48Toggle the given bit, returning its new value.
49
50#### `const changed = bits.remove(buffer, bit)`
51
52Unset the given bit. Returns `true` if the bit was set, otherwise `false`.
53
54#### `const changed = bits.removeRange(buffer, start, end)`
55
56Unset the given bit range. Returns `true` if any of the bits were set, otherwise `false`.
57
58#### `const index = bits.indexOf(buffer, value[, position])`
59
60Return the index of the first occurrence of `value`, or `-1` if not found. If `position` is given, return the first index that is greater than or equal to `position`.
61
62#### `const index = bits.lastIndexOf(buffer, value[, position])`
63
64Return the index of the last occurrence of `value`, or `-1` if not found. If `position` is given, return the last index that is less than or equal to `position`.
65
66#### `const buffer = bits.of(...values)`
67
68Create a buffer containing the given bits.
69
70#### `const buffer = bits.from(values)`
71
72Create a buffer containing the given bits.
73
74#### `const iterator = bits.iterator(buffer)`
75
76Create an iterator over bits.
77
78## License
79
80ISC
node_modules/bits-to-bytes/index.js +161 -0
……@@ -0,0 +1,161 @@
1const b4a = require('b4a')
2
3function byteLength (size) {
4 return Math.ceil(size / 8)
5}
6
7function get (buffer, bit) {
8 const n = buffer.BYTES_PER_ELEMENT * 8
9
10 const offset = bit & (n - 1)
11 const i = (bit - offset) / n
12
13 return (buffer[i] & (1 << offset)) !== 0
14}
15
16function set (buffer, bit, value = true) {
17 const n = buffer.BYTES_PER_ELEMENT * 8
18
19 const offset = bit & (n - 1)
20 const i = (bit - offset) / n
21 const mask = 1 << offset
22
23 if (value) {
24 if ((buffer[i] & mask) !== 0) return false
25 } else {
26 if ((buffer[i] & mask) === 0) return false
27 }
28
29 buffer[i] ^= mask
30 return true
31}
32
33function setRange (buffer, start, end, value = true) {
34 const n = buffer.BYTES_PER_ELEMENT * 8
35
36 let remaining = end - start
37 let offset = start & (n - 1)
38 let i = (start - offset) / n
39
40 let changed = false
41
42 while (remaining > 0) {
43 const mask = (2 ** Math.min(remaining, n - offset) - 1) << offset
44
45 if (value) {
46 if ((buffer[i] & mask) !== mask) {
47 buffer[i] |= mask
48 changed = true
49 }
50 } else {
51 if ((buffer[i] & mask) !== 0) {
52 buffer[i] &= ~mask
53 changed = true
54 }
55 }
56
57 remaining -= n - offset
58 offset = 0
59 i++
60 }
61
62 return changed
63}
64
65function fill (buffer, value, start = 0, end = buffer.byteLength * 8) {
66 const n = buffer.BYTES_PER_ELEMENT * 8
67 let i, j
68
69 {
70 const offset = start & (n - 1)
71 i = (start - offset) / n
72
73 if (offset !== 0) {
74 const mask = (2 ** Math.min(n - offset, end - start) - 1) << offset
75
76 if (value) buffer[i] |= mask
77 else buffer[i] &= ~mask
78
79 i++
80 }
81 }
82
83 {
84 const offset = end & (n - 1)
85 j = (end - offset) / n
86
87 if (offset !== 0 && j >= i) {
88 const mask = (2 ** offset) - 1
89
90 if (value) buffer[j] |= mask
91 else buffer[j] &= ~mask
92 }
93 }
94
95 return buffer.fill(value ? (2 ** n) - 1 : 0, i, j)
96}
97
98function toggle (buffer, bit) {
99 const n = buffer.BYTES_PER_ELEMENT * 8
100
101 const offset = bit & (n - 1)
102 const i = (bit - offset) / n
103 const mask = 1 << offset
104
105 buffer[i] ^= mask
106 return (buffer[i] & mask) !== 0
107}
108
109function remove (buffer, bit) {
110 return set(buffer, bit, false)
111}
112
113function removeRange (buffer, start, end) {
114 return setRange(buffer, start, end, false)
115}
116
117function indexOf (buffer, value, position = 0) {
118 for (let i = position, n = buffer.byteLength * 8; i < n; i++) {
119 if (get(buffer, i) === value) return i
120 }
121
122 return -1
123}
124
125function lastIndexOf (buffer, value, position = buffer.byteLength * 8 - 1) {
126 for (let i = position; i >= 0; i--) {
127 if (get(buffer, i) === value) return i
128 }
129
130 return -1
131}
132
133function of (...bits) {
134 return from(bits)
135}
136
137function from (bits) {
138 const buffer = b4a.alloc(byteLength(bits.length))
139 for (let i = 0; i < bits.length; i++) set(buffer, i, bits[i])
140 return buffer
141}
142
143function * iterator (buffer) {
144 for (let i = 0, n = buffer.byteLength * 8; i < n; i++) yield get(buffer, i)
145}
146
147module.exports = {
148 byteLength,
149 get,
150 set,
151 setRange,
152 fill,
153 toggle,
154 remove,
155 removeRange,
156 indexOf,
157 lastIndexOf,
158 of,
159 from,
160 iterator
161}
node_modules/bits-to-bytes/package.json +29 -0
……@@ -0,0 +1,29 @@
1{
2 "name": "bits-to-bytes",
3 "version": "1.3.0",
4 "description": "Functions for doing bit manipulation of typed arrays",
5 "main": "index.js",
6 "files": [
7 "index.js"
8 ],
9 "scripts": {
10 "test": "standard && brittle test.mjs"
11 },
12 "repository": {
13 "type": "git",
14 "url": "git+https://github.com/holepunchto/bits-to-bytes.git"
15 },
16 "author": "Kasper Isager Dalsgarð <kasper@funktionel.co>",
17 "license": "ISC",
18 "bugs": {
19 "url": "https://github.com/holepunchto/bits-to-bytes/issues"
20 },
21 "homepage": "https://github.com/holepunchto/bits-to-bytes#readme",
22 "dependencies": {
23 "b4a": "^1.5.0"
24 },
25 "devDependencies": {
26 "brittle": "^2.3.1",
27 "standard": "^17.0.0"
28 }
29}
node_modules/blind-relay/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/blind-relay/README.md +61 -0
……@@ -0,0 +1,61 @@
1# blind-relay
2
3Blind relay for [UDX](https://github.com/holepunchto/udx-native) over [Protomux](https://github.com/mafintosh/protomux) channels. By acting as a blind relay, a host may accept pairing requests from other hosts and relay UDX stream messages between them, similar to Traversal Using Relays around NAT (TURN).
4
5```sh
6npm i blind-relay
7```
8
9## Protocol
10
11```mermaid
12sequenceDiagram
13 actor a as peer a
14 actor r as relay
15 actor b as peer b
16
17 par
18 a ->> r: pair { isInitiator: true, token, id, seq }
19 and
20 b ->> r: pair { isInitiator: false, token, id, seq }
21 end
22
23 note over r: The relay pairs peers a and b based on the token, allocates a new stream for both peers, and sends back the stream info
24
25 par
26 r -->> a: pair { isInitiator: true, token, id, seq }
27 and
28 r -->> b: pair { isInitiator: false, token, id, seq }
29 end
30
31 par
32 a ->> r: unpair { token }
33
34 note left of r: The relay deallocates the stream previously allocated to peer a
35 and
36 b ->> r: unpair { token }
37
38 note right of r: The relay deallocates the stream previously allocated to peer b
39 end
40```
41
42### Messages
43
44All types are specified as their corresponding [compact-encoding](https://github.com/compact-encoding) codec.
45
46#### `pair` (`0`)
47
481. `bitfield(1)` Flags.
49 1. `isInitiator`
502. `fixed32` Preexchanged token.
513. `uint` Stream ID of the sender.
524. `uint` Initial stream sequence no. of the sender.
53
54#### `unpair` (`1`)
55
561. `bitfield(0)` Flags, reserved.
572. `fixed32` Preexchanged token.
58
59## License
60
61Apache-2.0
node_modules/blind-relay/index.js +523 -0
……@@ -0,0 +1,523 @@
1const EventEmitter = require('events')
2const Protomux = require('protomux')
3const { Readable } = require('streamx')
4const sodium = require('sodium-universal')
5const b4a = require('b4a')
6const c = require('compact-encoding')
7const bitfield = require('compact-encoding-bitfield')
8const bits = require('bits-to-bytes')
9const errors = require('./lib/errors')
10
11exports.Server = class BlindRelayServer extends EventEmitter {
12 constructor (opts = {}) {
13 super()
14
15 const {
16 createStream
17 } = opts
18
19 this._createStream = createStream
20 this._pairing = new Map()
21 this._sessions = new Set()
22 }
23
24 get sessions () {
25 return this._sessions[Symbol.iterator]()
26 }
27
28 accept (stream, opts) {
29 const session = new BlindRelaySession(this, stream, opts)
30
31 this._sessions.add(session)
32
33 return session
34 }
35
36 async close () {
37 const ending = []
38
39 for (const session of this._sessions) {
40 ending.push(session.end())
41 }
42
43 await Promise.all(ending)
44
45 this._pairing.clear()
46 }
47}
48
49class BlindRelaySession extends EventEmitter {
50 constructor (server, stream, opts = {}) {
51 super()
52
53 const {
54 id,
55 handshake,
56 handshakeEncoding
57 } = opts
58
59 this._server = server
60 this._mux = Protomux.from(stream)
61
62 this._channel = this._mux.createChannel({
63 protocol: 'blind-relay',
64 id,
65 handshake: handshake ? handshakeEncoding || c.raw : null,
66 onopen: this._onopen.bind(this),
67 onclose: this._onclose.bind(this),
68 ondestroy: this._ondestroy.bind(this)
69 })
70
71 this._pair = this._channel.addMessage({
72 encoding: m.pair,
73 onmessage: this._onpair.bind(this)
74 })
75
76 this._unpair = this._channel.addMessage({
77 encoding: m.unpair,
78 onmessage: this._onunpair.bind(this)
79 })
80
81 this._ending = null
82 this._destroyed = false
83 this._error = null
84 this._pairing = new Set()
85 this._streams = new Map()
86
87 this._onerror = (err) => this.emit('error', err)
88
89 this._channel.open(handshake)
90 }
91
92 get closed () {
93 return this._channel.closed
94 }
95
96 get mux () {
97 return this._mux
98 }
99
100 get stream () {
101 return this._mux.stream
102 }
103
104 _onopen () {
105 this.emit('open')
106 }
107
108 _onclose () {
109 this._ending = Promise.resolve()
110
111 const err = this._error || errors.CHANNEL_CLOSED()
112
113 for (const token of this._pairing) {
114 this._server._pairing.delete(token.toString('hex'))
115 }
116
117 for (const stream of this._streams.values()) {
118 stream
119 .off('error', this._onerror)
120 .on('error', noop)
121 .destroy(err)
122 }
123
124 this._pairing.clear()
125 this._streams.clear()
126
127 this._server._sessions.delete(this)
128
129 this.emit('close')
130 }
131
132 _ondestroy () {
133 this._destroyed = true
134 this.emit('destroy')
135 }
136
137 _onpair ({ isInitiator, token, id: remoteId }) {
138 const keyString = token.toString('hex')
139
140 let pair = this._server._pairing.get(keyString)
141
142 if (pair === undefined) {
143 pair = new BlindRelayPair(token)
144 this._server._pairing.set(keyString, pair)
145 } else if (pair.links[+isInitiator]) return
146
147 this._pairing.add(keyString)
148
149 pair.links[+isInitiator] = new BlindRelayLink(this, isInitiator, remoteId)
150
151 if (!pair.paired) return
152
153 this._server._pairing.delete(keyString)
154
155 // 1st pass: Create the raw streams needed for each end of the link.
156 for (const link of pair.links) {
157 link.createStream()
158 }
159
160 // 2nd pass: Connect the raw streams and set up handlers.
161 for (const { isInitiator, session, stream } of pair.links) {
162 const remote = pair.remote(isInitiator)
163
164 stream
165 .on('error', session._onerror)
166 .on('close', () => session._streams.delete(keyString))
167 .relayTo(remote.stream)
168
169 session._pairing.delete(keyString)
170 session._streams.set(keyString, stream)
171 }
172
173 // 3rd pass: Let either end of the link know the streams were set up.
174 for (const { isInitiator, session, remoteId, stream } of pair.links) {
175 session._pair.send({
176 isInitiator,
177 token,
178 id: stream.id,
179 seq: 0
180 })
181
182 session._endMaybe()
183
184 session.emit('pair', isInitiator, token, stream, remoteId)
185 }
186 }
187
188 _onunpair ({ token }) {
189 const keyString = token.toString('hex')
190
191 const pair = this._server._pairing.get(keyString)
192
193 if (pair) {
194 for (const link of pair.links) {
195 if (link) link.session._pairing.delete(keyString)
196 }
197
198 return this._server._pairing.delete(keyString)
199 }
200
201 const stream = this._streams.get(keyString)
202
203 if (stream) {
204 stream
205 .off('error', this._onerror)
206 .on('error', noop)
207 .destroy(errors.PAIRING_CANCELLED())
208
209 this._streams.delete(keyString)
210 }
211 }
212
213 cork () {
214 this._channel.cork()
215 }
216
217 uncork () {
218 this._channel.uncork()
219 }
220
221 async end () {
222 if (this._ending) return this._ending
223
224 this._ending = EventEmitter.once(this, 'close')
225 this._endMaybe()
226
227 return this._ending
228 }
229
230 _endMaybe () {
231 if (this._ending && this._pairing.size === 0) {
232 this._channel.close()
233 }
234 }
235
236 destroy (err) {
237 if (this._destroyed) return
238 this._destroyed = true
239
240 this._error = err || errors.CHANNEL_DESTROYED()
241 this._channel.close()
242 }
243}
244
245class BlindRelayPair {
246 constructor (token) {
247 this.token = token
248 this.links = [null, null]
249 }
250
251 get paired () {
252 return this.links[0] !== null && this.links[1] !== null
253 }
254
255 remote (isInitiator) {
256 return this.links[isInitiator ? 0 : 1]
257 }
258}
259
260class BlindRelayLink {
261 constructor (session, isInitiator, remoteId) {
262 this.session = session
263 this.isInitiator = isInitiator
264 this.remoteId = remoteId
265 this.stream = null
266 }
267
268 createStream () {
269 if (this.stream) return
270
271 this.stream = this.session._server._createStream({
272 firewall: this._onfirewall.bind(this)
273 })
274 }
275
276 _onfirewall (socket, port, host) {
277 this.stream.connect(socket, this.remoteId, port, host)
278
279 return false
280 }
281}
282
283exports.Client = class BlindRelayClient extends EventEmitter {
284 static _clients = new WeakMap()
285
286 static from (stream, opts) {
287 let client = this._clients.get(stream)
288 if (client) return client
289 client = new this(stream, opts)
290 this._clients.set(stream, client)
291 return client
292 }
293
294 constructor (stream, opts = {}) {
295 super()
296
297 const {
298 id,
299 handshake,
300 handshakeEncoding
301 } = opts
302
303 this._mux = Protomux.from(stream)
304
305 this._channel = this._mux.createChannel({
306 protocol: 'blind-relay',
307 id,
308 handshake: handshake ? handshakeEncoding || c.raw : null,
309 onopen: this._onopen.bind(this),
310 onclose: this._onclose.bind(this),
311 ondestroy: this._ondestroy.bind(this)
312 })
313
314 this._pair = this._channel.addMessage({
315 encoding: m.pair,
316 onmessage: this._onpair.bind(this)
317 })
318
319 this._unpair = this._channel.addMessage({
320 encoding: m.unpair
321 })
322
323 this._ending = false
324 this._destroyed = false
325 this._error = null
326 this._requests = new Map()
327
328 this._channel.open(handshake)
329 }
330
331 get closed () {
332 return this._channel.closed
333 }
334
335 get mux () {
336 return this._mux
337 }
338
339 get stream () {
340 return this._mux.stream
341 }
342
343 get requests () {
344 return this._requests.values()
345 }
346
347 _onopen () {
348 this.emit('open')
349 }
350
351 _onclose () {
352 this._ending = Promise.resolve()
353
354 const err = this._error || errors.CHANNEL_CLOSED()
355
356 for (const request of this._requests.values()) {
357 request.destroy(err)
358 }
359
360 this._requests.clear()
361
362 this.constructor._clients.delete(this.stream)
363
364 this.emit('close')
365 }
366
367 _ondestroy () {
368 this._destroyed = true
369 this.emit('destroy')
370 }
371
372 _onpair ({ isInitiator, token, id: remoteId }) {
373 const request = this._requests.get(token.toString('hex'))
374
375 if (request === undefined || request.isInitiator !== isInitiator) return
376
377 request.push(remoteId)
378 request.push(null)
379
380 this.emit('pair', request.isInitiator, request.token, request.stream, remoteId)
381 }
382
383 pair (isInitiator, token, stream) {
384 if (this._destroyed) throw errors.CHANNEL_DESTROYED()
385
386 const keyString = token.toString('hex')
387
388 if (this._requests.has(keyString)) throw errors.ALREADY_PAIRING()
389
390 const request = new BlindRelayRequest(this, isInitiator, token, stream)
391
392 this._requests.set(keyString, request)
393
394 return request
395 }
396
397 unpair (token) {
398 if (this._destroyed) throw errors.CHANNEL_DESTROYED()
399
400 const request = this._requests.get(token.toString('hex'))
401
402 if (request) request.destroy(errors.PAIRING_CANCELLED())
403
404 this._unpair.send({ token })
405 }
406
407 cork () {
408 this._channel.cork()
409 }
410
411 uncork () {
412 this._channel.uncork()
413 }
414
415 async end () {
416 if (this._ending) return this._ending
417
418 this._ending = EventEmitter.once(this, 'close')
419 this._endMaybe()
420
421 return this._ending
422 }
423
424 _endMaybe () {
425 if (this._ending && this._requests.size === 0) {
426 this._channel.close()
427 }
428 }
429
430 destroy (err) {
431 if (this._destroyed) return
432 this._destroyed = true
433
434 this._error = err || errors.CHANNEL_DESTROYED()
435 this._channel.close()
436 }
437}
438
439class BlindRelayRequest extends Readable {
440 constructor (client, isInitiator, token, stream) {
441 super()
442
443 this.client = client
444 this.isInitiator = isInitiator
445 this.token = token
446 this.stream = stream
447 }
448
449 _open (cb) {
450 if (this.client._destroyed) return cb(errors.CHANNEL_DESTROYED())
451
452 this.client._pair.send({
453 isInitiator: this.isInitiator,
454 token: this.token,
455 id: this.stream.id,
456 seq: 0
457 })
458
459 cb(null)
460 }
461
462 _destroy (cb) {
463 this.client._requests.delete(this.token.toString('hex'))
464
465 cb(null)
466
467 this.client._endMaybe()
468 }
469}
470
471exports.token = function token (buf = b4a.allocUnsafe(32)) {
472 sodium.randombytes_buf(buf)
473 return buf
474}
475
476function noop () {}
477
478const m = exports.messages = {}
479
480const flags = bitfield(7)
481
482m.pair = {
483 preencode (state, m) {
484 flags.preencode(state)
485 c.fixed32.preencode(state, m.token)
486 c.uint.preencode(state, m.id)
487 c.uint.preencode(state, m.seq)
488 },
489 encode (state, m) {
490 flags.encode(state, bits.of(m.isInitiator))
491 c.fixed32.encode(state, m.token)
492 c.uint.encode(state, m.id)
493 c.uint.encode(state, m.seq)
494 },
495 decode (state) {
496 const [isInitiator] = bits.iterator(flags.decode(state))
497
498 return {
499 isInitiator,
500 token: c.fixed32.decode(state),
501 id: c.uint.decode(state),
502 seq: c.uint.decode(state)
503 }
504 }
505}
506
507m.unpair = {
508 preencode (state, m) {
509 flags.preencode(state)
510 c.fixed32.preencode(state, m.token)
511 },
512 encode (state, m) {
513 flags.encode(state, bits.of())
514 c.fixed32.encode(state, m.token)
515 },
516 decode (state) {
517 flags.decode(state)
518
519 return {
520 token: c.fixed32.decode(state)
521 }
522 }
523}
node_modules/blind-relay/lib/errors.js +34 -0
……@@ -0,0 +1,34 @@
1module.exports = class BlindRelayError extends Error {
2 constructor (msg, code, fn = BlindRelayError) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name () {
12 return 'BlindRelayError'
13 }
14
15 static DUPLICATE_CHANNEL (msg = 'Duplicate channel') {
16 return new BlindRelayError(msg, 'DUPLICATE_CHANNEL', BlindRelayError.DUPLICATE_CHANNEL)
17 }
18
19 static CHANNEL_CLOSED (msg = 'Channel closed') {
20 return new BlindRelayError(msg, 'CHANNEL_CLOSED', BlindRelayError.CHANNEL_CLOSED)
21 }
22
23 static CHANNEL_DESTROYED (msg = 'Channel destroyed') {
24 return new BlindRelayError(msg, 'CHANNEL_DESTROYED', BlindRelayError.CHANNEL_DESTROYED)
25 }
26
27 static ALREADY_PAIRING (msg = 'Already pairing') {
28 return new BlindRelayError(msg, 'ALREADY_PAIRING', BlindRelayError.ALREADY_PAIRING)
29 }
30
31 static PAIRING_CANCELLED (msg = 'Pairing cancelled') {
32 return new BlindRelayError(msg, 'PAIRING_CANCELLED', BlindRelayError.PAIRING_CANCELLED)
33 }
34}
node_modules/blind-relay/package.json +45 -0
……@@ -0,0 +1,45 @@
1{
2 "name": "blind-relay",
3 "version": "1.4.0",
4 "description": "Blind relay for UDX over Protomux channels",
5 "main": "index.js",
6 "files": [
7 "index.js",
8 "lib"
9 ],
10 "scripts": {
11 "test": "standard && brittle test.mjs"
12 },
13 "repository": {
14 "type": "git",
15 "url": "git+https://github.com/holepunchto/blind-relay.git"
16 },
17 "author": "Holepunch",
18 "license": "Apache-2.0",
19 "bugs": {
20 "url": "https://github.com/holepunchto/blind-relay/issues"
21 },
22 "homepage": "https://github.com/holepunchto/blind-relay#readme",
23 "imports": {
24 "events": {
25 "bare": "bare-events",
26 "default": "events"
27 }
28 },
29 "dependencies": {
30 "b4a": "^1.6.4",
31 "bare-events": "^2.2.0",
32 "bits-to-bytes": "^1.3.0",
33 "compact-encoding": "^2.12.0",
34 "compact-encoding-bitfield": "^1.0.0",
35 "protomux": "^3.5.1",
36 "sodium-universal": "^5.0.0",
37 "streamx": "^2.15.1"
38 },
39 "devDependencies": {
40 "brittle": "^3.2.1",
41 "hyperdht": "^6.6.1",
42 "standard": "^17.0.0",
43 "udx-native": "^1.6.1"
44 }
45}
node_modules/bogon/.github/workflows/test-node.yml +23 -0
……@@ -0,0 +1,23 @@
1name: Build Status
2on:
3 push:
4 branches:
5 - master
6 pull_request:
7 branches:
8 - master
9jobs:
10 build:
11 strategy:
12 matrix:
13 node-version: [lts/*]
14 os: [ubuntu-latest, macos-latest, windows-latest]
15 runs-on: ${{ matrix.os }}
16 steps:
17 - uses: actions/checkout@v2
18 - name: Use Node.js ${{ matrix.node-version }}
19 uses: actions/setup-node@v2
20 with:
21 node-version: ${{ matrix.node-version }}
22 - run: npm install
23 - run: npm test
node_modules/bogon/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2021 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/bogon/README.md +32 -0
……@@ -0,0 +1,32 @@
1# bogon
2
3Check if an IP is a bogon
4
5```
6npm install bogon
7```
8
9https://ipinfo.io/bogon
10
11
12## Usage
13
14``` js
15const bogon = require('bogon')
16
17console.log(bogon('192.168.0.1')) // true
18console.log(bogon('8.8.8.8')) // false
19```
20
21As a utility it also exposes an `isPrivate` helper
22to detect if a bogon IP is a private IP address on a local network.
23
24``` js
25console.log(bogon.isPrivate('192.168.0.1')) // true
26console.log(bogon('224.0.1.1')) // true
27console.log(bogon.isPrivate('224.0.1.1')) // false
28```
29
30## License
31
32MIT
node_modules/bogon/bench.mjs +34 -0
……@@ -0,0 +1,34 @@
1import bench from 'nanobench'
2import b4a from 'b4a'
3
4import isBogon from './index.js'
5
6bench('string', (b) => {
7 const ip = '255.255.255.255'
8
9 b.start()
10
11 let result
12
13 for (let i = 0; i < 10000000; i++) {
14 result = isBogon(ip)
15 }
16
17 b.log(result)
18 b.end()
19})
20
21bench('buffer', (b) => {
22 const ip = b4a.from([255, 255, 255, 255])
23
24 b.start()
25
26 let result
27
28 for (let i = 0; i < 10000000; i++) {
29 result = isBogon(ip)
30 }
31
32 b.log(result)
33 b.end()
34})
node_modules/bogon/index.js +122 -0
……@@ -0,0 +1,122 @@
1// https://ipinfo.io/bogon
2
3const b4a = require('b4a')
4const c = require('compact-encoding')
5const net = require('compact-encoding-net')
6
7module.exports = exports = function isBogon (ip) {
8 return isBogonIP(ensureBuffer(ip))
9}
10
11exports.isBogon = exports
12
13exports.isPrivate = function isPrivate (ip) {
14 return isPrivateIP(ensureBuffer(ip))
15}
16
17exports.isReserved = function isReserved (ip) {
18 return isReservedIP(ensureBuffer(ip))
19}
20
21function isBogonIP (ip) {
22 return isPrivateIP(ip) || isReservedIP(ip)
23}
24
25function isPrivateIP (ip) {
26 return ip.byteLength === 4 ? isPrivateIPv4(ip) : false // IPv6 has no private IPs
27}
28
29function isPrivateIPv4 (ip) {
30 return (
31 // 10.0.0.0/8 Private-use networks
32 (ip[0] === 10) ||
33 // 100.64.0.0/10 Carrier-grade NAT
34 (ip[0] === 100 && ip[1] >= 64 && ip[1] <= 127) ||
35 // 127.0.0.0/8 Loopback + Name collision occurrence (127.0.53.53)
36 (ip[0] === 127) ||
37 // 169.254.0.0/16 Link local
38 (ip[0] === 169 && ip[1] === 254) ||
39 // 172.16.0.0/12 Private-use networks
40 (ip[0] === 172 && ip[1] >= 16 && ip[1] <= 31) ||
41 // 192.168.0.0/16 Private-use networks
42 (ip[0] === 192 && ip[1] === 168)
43 )
44}
45
46function isReservedIP (ip) {
47 return ip.byteLength === 4 ? isReservedIPv4(ip) : isReservedIPv6(ip)
48}
49
50function isReservedIPv4 (ip) {
51 return (
52 // 0.0.0.0/8 "This" network
53 (ip[0] === 0) ||
54 // 192.0.0.0/24 IETF protocol assignments
55 (ip[0] === 192 && ip[1] === 0 && ip[2] === 0) ||
56 // 192.0.2.0/24 TEST-NET-1
57 (ip[0] === 192 && ip[1] === 0 && ip[2] === 2) ||
58 // 198.18.0.0/15 Network interconnect device benchmark testing
59 (ip[0] === 198 && ip[1] >= 18 && ip[1] <= 19) ||
60 // 198.51.100.0/24 TEST-NET-2
61 (ip[0] === 198 && ip[1] === 51 && ip[2] === 100) ||
62 // 203.0.113.0/24 TEST-NET-3
63 (ip[0] === 203 && ip[1] === 0 && ip[2] === 113) ||
64 // 224.0.0.0/4 Multicast
65 (ip[0] >= 224 && ip[0] <= 239) ||
66 // 240.0.0.0/4 Reserved for future use
67 (ip[0] >= 240) ||
68 // 255.255.255.255/32
69 (ip[0] === 255 && ip[1] === 255 && ip[2] === 255 && ip[3] === 255)
70 )
71}
72
73function isReservedIPv6 (ip) {
74 return (
75 // ::/128 Node-scope unicast unspecified address
76 // ::1/128 Node-scope unicast loopback address
77 (
78 ip[0] === 0 && ip[1] === 0 && ip[2] === 0 && ip[3] === 0 && ip[4] === 0 &&
79 ip[5] === 0 && ip[6] === 0 && ip[7] === 0 && ip[8] === 0 && ip[9] === 0 &&
80 ip[10] === 0 && ip[11] === 0 && ip[12] === 0 && ip[13] === 0 && ip[14] === 0 &&
81 ip[15] <= 1
82 ) ||
83 // ::ffff:0:0/96 IPv4-mapped addresses
84 // ::/96 IPv4-compatible addresses
85 (
86 ip[0] === 0 && ip[1] === 0 && ip[2] === 0 && ip[3] === 0 && ip[4] === 0 &&
87 ip[5] === 0 && ip[6] === 0 && ip[7] === 0 && ip[8] === 0 && ip[9] === 0 &&
88 (ip[10] === 0 || ip[10] === 0xff) &&
89 (ip[11] === 0 || ip[11] === 0xff)
90 ) ||
91 // 100::/64 Remotely triggered black hole addresses
92 (ip[0] === 0x01 && ip[1] === 0 && ip[2] === 0 && ip[3] === 0 && ip[4] === 0 && ip[5] === 0 && ip[6] === 0 && ip[7] === 0) ||
93 // 2001:10::/28 Overlay routable cryptographic hash identifiers (ORCHID)
94 (ip[0] === 0x20 && ip[1] === 0x01 && ip[2] === 0 && ip[3] >= 0x10 && ip[3] <= 0x1f) ||
95 // 2001:20::/28 Overlay routable cryptographic hash identifiers version 2 (ORCHIDv2)
96 (ip[0] === 0x20 && ip[1] === 0x01 && ip[2] === 0 && ip[3] >= 0x20 && ip[3] <= 0x2f) ||
97 // 2001:db8::/32 Documentation prefix
98 (ip[0] === 0x20 && ip[1] === 0x01 && ip[2] === 0x0d && ip[3] === 0xb8) ||
99 // fc00::/7 Unique local addresses (ULA)
100 (ip[0] >= 0xfc && ip[0] <= 0xfd) ||
101 // fe80::/10 Link-local unicast
102 (ip[0] === 0xfe && ip[1] >= 0x80 && ip[1] <= 0xbf) ||
103 // ff00::/8 Multicast
104 (ip[0] === 0xff)
105 )
106}
107
108const state = c.state(0, 0, b4a.allocUnsafe(1 /* family */ + 16))
109
110function ensureBuffer (ip) {
111 if (b4a.isBuffer(ip)) return ip
112
113 net.ip.preencode(state, ip)
114 net.ip.encode(state, ip)
115
116 const buffer = state.buffer.subarray(1 /* family */, state.end)
117
118 state.start = 0
119 state.end = 0
120
121 return buffer
122}
node_modules/bogon/package.json +28 -0
……@@ -0,0 +1,28 @@
1{
2 "name": "bogon",
3 "version": "1.2.0",
4 "description": "Check if an IP is a bogon",
5 "main": "index.js",
6 "scripts": {
7 "test": "standard && brittle test.mjs"
8 },
9 "dependencies": {
10 "compact-encoding": "^2.11.0",
11 "compact-encoding-net": "^1.2.0"
12 },
13 "devDependencies": {
14 "brittle": "^3.0.4",
15 "nanobench": "^2.1.1",
16 "standard": "^17.0.0"
17 },
18 "repository": {
19 "type": "git",
20 "url": "https://github.com/mafintosh/bogon.git"
21 },
22 "author": "Mathias Buus (@mafintosh)",
23 "license": "MIT",
24 "bugs": {
25 "url": "https://github.com/mafintosh/bogon/issues"
26 },
27 "homepage": "https://github.com/mafintosh/bogon"
28}
node_modules/bogon/test.mjs +23 -0
……@@ -0,0 +1,23 @@
1import test from 'brittle'
2import b4a from 'b4a'
3
4import { isBogon } from './index.js'
5
6test('ipv4', (t) => {
7 t.ok(isBogon('127.0.0.1'), 'loopback, string')
8 t.ok(isBogon(b4a.from([127, 0, 0, 1])), 'loopback, buffer')
9
10 t.absent(isBogon('84.123.96.194'), 'not bogon, string')
11 t.absent(isBogon(b4a.from([84, 123, 96, 194])), 'not bogon, buffer')
12})
13
14test('ipv6', (t) => {
15 t.ok(isBogon('::1'), 'loopback, string')
16 t.ok(isBogon(b4a.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])), 'loopback, buffer')
17
18 t.absent(isBogon('89c7:2c35:937e:3171:10c:831a:a32e:bff4'), 'not bogon, string')
19 t.absent(isBogon(b4a.from([0x89, 0xc7, 0x2c, 0x35, 0x93, 0x7e, 0x31, 0x71, 0x10, 0xc, 0x83, 0x1a, 0xa3, 0x2e, 0xbf, 0xf4])), 'not bogon, buffer')
20
21 t.ok(isBogon('::ffff:127.0.0.1'), 'ipv4-mapped')
22 t.ok(isBogon('fe80::c001:1dff:fee0:0'), 'link-local')
23})
node_modules/brittle/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/brittle/README.md +673 -0
……@@ -0,0 +1,673 @@
1# brittle
2
3> tap à la mode
4
5A TAP test runner built for modern times.
6
7<img width=300 height=200 src=brittle.png>
8
9## Usage
10
11First install brittle from npm
12
13```
14npm i brittle
15```
16
17Then start writing tests
18
19```javascript
20import test from 'brittle'
21
22test('basic', function (t) {
23 t.is(typeof Date.now(), 'number')
24 t.not(typeof Date.now(), 'string')
25
26 t.ok(Date.now() > 0)
27 t.absent(null)
28
29 t.comment('text')
30
31 t.alike({ a: 1 }, { a: 1 })
32 t.unlike({ a: 2 }, { a: 3 })
33
34 t.pass()
35 t.fail()
36})
37
38test('asynchronous', async function (t) {
39 await new Promise(r => setTimeout(r, 250))
40 t.pass()
41})
42
43test('plans', function (t) {
44 t.plan(2)
45 t.pass()
46 setTimeout(() => t.pass(), 250)
47})
48
49test('classic subtest', function (t) {
50 t.test('subtest', function (sub) {
51 sub.plan(1)
52 sub.pass()
53 })
54})
55
56test('inverted subtest', function (t) {
57 const sub = t.test('subtest')
58 sub.plan(1)
59 sub.pass()
60})
61
62test('executions', async function (t) {
63 t.execution(() => 'should not throw')
64 await t.execution(async () => 'should not reject')
65})
66
67test('exceptions', async function (t) {
68 t.exception(() => { throw Error('expected to throw') })
69 await t.exception(async () => { throw Error('expected to reject') })
70})
71
72const a = test('inverted test without plan needs end()')
73a.pass()
74a.end()
75
76const b = test('inverted test with plan')
77b.plan(1)
78b.pass()
79
80const c = test('inverted tests can be awaited')
81c.plan(1)
82setTimeout(() => c.pass(), 250)
83await c
84```
85
86Every assertion can have a message, i.e. `t.pass('msg')`, `t.ok(false, 'should be true')`, etc.\
87There are also utilities like `t.timeout(ms)`, `t.teardown(fn)`, etc.\
88Check the API but also all the [assertions here](#assertions) and [utilities here](#utilities).
89
90## Test Runtimes
91When installed as a dependency or globally, the following commands for using different runtimes are available:
92* `brittle-node`/`brittle` - Runs tests using [Node.js](https://nodejs.org/).
93* `brittle-bare` - Runs tests using [Bare](https://docs.pears.com/bare-reference/overview).
94* `brittle-pear` - Runs tests using [Pear](https://docs.pears.com/).
95
96## API
97
98```js
99import { test, solo, skip, hook, todo, configure } from 'brittle'
100```
101
102#### `test([name], [options], callback)`
103
104Create a classic test with an optional `name`.
105
106#### Available `options` for any test creation:
107 * `timeout` (`30000`) - milliseconds to wait before ending a stalling test.
108 * `solo` (`false`) - Skip all other tests except the `solo()` ones.
109 * `hook` (`false`) - setup and teardown resources.
110 * `skip` (`false`) - skip this test, alternatively use the `skip()` function.
111 * `todo` (`false`) - mark this test as todo and skip it, alternatively use the `todo()` function.
112 * `stealth` (`false`) - only print test summary.
113
114The `callback` function (can be async) receives an object called `assert`.\
115`assert` (or `t`) provides the assertions and utilities interface.
116
117```js
118import test from 'brittle'
119
120test('basic', function (t) {
121 t.pass()
122})
123```
124
125Test files can be executed directly with `node`, as they're normal Node.js programs.
126
127The `test` method is conveniently both the default export and named exported method:
128
129```js
130import { test } from 'brittle'
131```
132
133Classic tests will run sequentially, buffering pending tests until any prior test catches up.
134
135Any test function returns a promise so you can optionally await for its result:
136
137```js
138const isOk = await test('basic', function (t) {
139 t.pass()
140})
141```
142
143#### `test([name], [options]) => assert`
144
145Create an inverted test with an optional `name`.
146
147All `options` for inverted tests are [listed here](#available-options-for-any-test-creation).
148
149An object called `assert` (or `t`) is returned, the same as the classic test.
150
151This time it's also a promise, it can be awaited and it resolves at test completion.
152
153```js
154import test from 'brittle'
155
156const t = test('basic')
157
158t.plan(1)
159
160setTimeout(() => {
161 t.pass()
162}, 1000)
163
164await t // Won't proceed past here until plan is fulfilled
165```
166
167For inverted tests without a plan, the `end` method must be called:
168
169```js
170const t = test('basic')
171
172setTimeout(() => {
173 t.pass()
174 t.end()
175}, 1000)
176
177await t
178```
179
180The `end()` method can be called inline, for inverted tests without a plan:
181
182```js
183const t = test('basic')
184t.pass()
185t.end()
186```
187
188Control flow of inverted is entirely dependent on where its `assert` is awaited.\
189The following executes one test after another:
190
191```js
192const a = test('first test')
193const b = test('second test')
194a.plan(1)
195b.plan(1)
196a.pass()
197await a
198b.pass()
199await b
200```
201
202Awaiting the promise gives you its result:
203
204```js
205const t = test('first test')
206t.plan(1)
207t.pass()
208const isOk = await t
209```
210
211#### `stealth([name], [options], callback)`
212#### `stealth([name], [options]) => assert`
213
214Create a stealth test.\
215This will provide a new sub-assert object that only prints the test summary without assertions and ends the current test upon a failed assertion.
216
217All `options` are the same as `test` which are [listed here](#available-options-for-any-test-creation).
218
219#### `t.test([name], [options], callback)`
220#### `t.test([name], [options]) => assert`
221
222A subtest can be created by calling `test` on an `assert` (or `t`) object.\
223This will provide a new sub-assert object.
224
225All `options` for subtests are [listed here](#available-options-for-any-test-creation).
226
227Using this in inverted style can be very useful for flow control within a test:
228
229```js
230test('basic', async function (t) {
231 const a = t.test('sub test')
232 const b = t.test('other sub test')
233
234 a.plan(1)
235 b.plan(1)
236
237 setTimeout(() => a.ok(true), Math.random() * 1000)
238 setTimeout(() => b.ok(true), Math.random() * 1000)
239
240 // Won't proceed past here until both a and b plans are fulfilled
241 await a
242 await b
243
244 t.pass()
245})
246```
247
248Subtest test options can be set by passing an object to the `test` function:
249
250```js
251test('parent', { timeout: 1000 }, function (t) {
252 t.test('basic using parent config', async function (t) {
253 await new Promise(r => setTimeout(r, 500))
254 t.pass()
255 })
256
257 t.test('another basic using parent config', function (t) {
258 t.pass()
259 })
260})
261```
262
263You can also await for its result as well:
264
265```js
266test('basic', async function (t) {
267 t.plan(1)
268 t.pass()
269 const isOk = await t
270 console.log(isOk)
271})
272```
273
274#### `t.stealth([name], [options], callback)`
275#### `t.stealth([name], [options]) => assert`
276
277Create a stealth sub-test.\
278This will provide a new sub-assert object that only prints the test summary without assertions and ends the current test upon a failed assertion.
279
280All `options` are the same as `test` which are [listed here](#available-options-for-any-test-creation).
281
282#### `solo([name], [options], callback)`
283#### `solo([name], [options]) => assert`
284
285Filter out other tests by using the `solo` method:
286
287```js
288import { test, solo } from 'brittle'
289
290test('this test is skipped', function (t) {
291 t.pass()
292})
293
294solo('some test', function (t) {
295 t.pass()
296})
297```
298
299If a `solo` function is used, `test` functions will not execute.\
300
301If `solo` is used in a future tick (for example, in a `setTimeout` callback),\
302after `test` has already been used those tests won't be filtered.
303
304A few ways to enable `solo` functions:
305- Use `configure({ solo: true })` before any tests.
306- You can call `solo()` without callback underneath the imports.
307- Using the `--solo` flag with the `brittle` test runner.
308
309It can also be used as an inverted test:
310
311```js
312const t = test.solo('inverted some test')
313t.pass()
314t.end()
315```
316
317#### `skip([name], [options], callback)`
318
319Skip a test:
320
321```js
322import { test, skip } from 'brittle'
323
324skip('this test is skipped', function (t) {
325 t.pass()
326})
327
328test('middle test', function (t) {
329 t.pass()
330})
331
332test.skip('another skipped test', function (t) {
333 t.pass()
334})
335```
336
337Only the `middle test` will be executed.
338
339#### `hook([name], [options], callback)`
340
341Use before tests for setting up and after tests for tearing down. Runs the same way as `test` except always executes regardless of `solo` usage.
342
343```js
344import { test, solo, hook } from 'brittle'
345
346hook('setup hook', function (t) {
347 // setup resources
348})
349
350solo('solo test', function (t) {
351 t.pass()
352})
353
354test('middle test', function (t) {
355 t.pass()
356})
357
358hook('teardown hook', function (t) {
359 // teardown resources
360})
361```
362
363The `setup hook`, `solo test` and `teardown hook` will be executed.
364
365#### `configure([options])`
366
367The `configure` function can be used to set options for all tests (including child tests).\
368It must be executed before any tests.
369
370#### Options
371
372 * `timeout` (`30000`) - milliseconds to wait before ending a stalling test
373 * `bail` (`false`) - exit the process on first test failure
374 * `solo` (`false`) - skip all other tests except the `solo()` ones
375 * `source` (`true`) - shows error `source` information
376 * `unstealth` (`false`) - show assertions even if `stealth` is used
377 * `coverage` (`false`) - enable coverage reporting (string path of the output directory or `true` for default)
378
379```js
380import { configure } from 'brittle'
381
382configure({ timeout: 15000 }) // All tests will have a 15 seconds timeout
383```
384
385### Assertions
386
387#### `t.is(actual, expected, [message])`
388
389Compare `actual` to `expected` with `===`
390
391#### `t.not(actual, expected, [message])`
392
393Compare `actual` to `expected` with `!==`
394
395#### `t.alike(actual, expected, [message])`
396
397Object comparison, comparing all primitives on the
398`actual` object to those on the `expected` object
399using `===`.
400
401#### `t.unlike(actual, expected, [message])`
402
403Object comparison, comparing all primitives on the
404`actual` object to those on the `expected` object
405using `!==`.
406
407#### `t.ok(value, [message])`
408
409Checks that `value` is truthy: `!!value === true`
410
411#### `t.absent(value, [message])`
412
413Checks that `value` is falsy: `!!value === false`
414
415#### `t.pass([message])`
416
417Asserts success. Useful for explicitly confirming
418that a function was called, or that behavior is
419as expected.
420
421#### `t.fail([message])`
422
423Asserts failure. Useful for explicitly checking
424that a function should not be called.
425
426#### `t.exception(Promise|function|async function, [error], [message])`
427
428Verify that a function throws, or a promise rejects.
429
430```js
431t.exception(() => { throw Error('an err') }, /an err/)
432await t.exception(async () => { throw Error('an err') }, /an err/)
433await t.exception(Promise.reject(Error('an err')), /an err/)
434```
435
436If the error is an instance of any of the following native error constructors,
437then this will still result in failure since native errors often tend to be unintentational.
438
439* `SyntaxError`
440* `ReferenceError`
441* `TypeError`
442* `EvalError`
443* `RangeError`
444
445If a `t.exception` is async, then you're supposed to await it.
446
447#### `t.exception.all(Promise|function|async function, [error], [message])`
448
449Verify that a function throws, or a promise rejects, including native errors.
450
451```js
452t.exception.all(() => { throw Error('an err') }, /an err/)
453await t.exception.all(async () => { throw Error('an err') }, /an err/)
454await t.exception.all(Promise.reject(new SyntaxError('native error')), /native error/)
455```
456
457The `t.exception.all` method is an escape-hatch so it can be used with the
458normally filtered native errors.
459
460If a `t.exception.all` is async, then you're supposed to await it.
461
462#### `t.execution(Promise|function|async function, [message])`
463
464Assert that a function executes instead of throwing or that a promise resolves instead of rejecting. Resolves to the execution time, in milliseconds, of the function or promise.
465
466```js
467t.execution(() => {})
468await t.execution(async () => {})
469await t.execution(Promise.resolve('cool'))
470```
471
472If a `t.execution` is async, then you're supposed to await it
473
474#### `t.is.coercively(actual, expected, [message])`
475
476Compare `actual` to `expected` with `==`.
477
478#### `t.not.coercively(actual, expected, [message])`
479
480Compare `actual` to `expected` with `!=`.
481
482#### `t.alike.coercively(actual, expected, [message])`
483
484Object comparison, comparing all primitives on the
485`actual` object to those on the `expected` object
486using `==`.
487
488#### `t.unlike.coercively(actual, expected, [message])`
489
490Object comparison, comparing all primitives on the
491`actual` object to those on the `expected` object
492using `!=`.
493
494
495### Utilities
496
497#### `t.plan(n)`
498
499Constrain a test to an explicit amount of assertions.
500
501#### `t.tmp() -> <Promise<String>>`
502
503Creates a temporary folder and returns a promise that resolves its path. Once a test either succeeds or fails, the temporary folder is removed.
504
505#### `t.teardown(function|async function, [options])`
506
507**Options:**
508
509 * `order` (`0`) - set the ascending position priority for a teardown to be executed.
510 * `force` (`false`) - run the teardown on failure as well as success
511
512The function passed to `teardown` is called right after a test ends:
513
514```js
515test('basic', function (t) {
516 const timeoutId = setTimeout(() => {}, 1000)
517
518 t.teardown(async function () {
519 clearTimeout(timeoutId)
520 await doMoreCleanUp()
521 })
522
523 t.ok('cool')
524})
525```
526
527If `teardown` is called multiple times in a test, every function passed will be called after the test ends:
528
529```js
530test('basic', function (t) {
531 t.teardown(doSomeCleanUp)
532
533 const timeoutId = setTimeout(() => {}, 1000)
534 t.teardown(() => clearTimeout(timeoutId))
535
536 t.ok('again, cool')
537})
538```
539
540Set `order: -Infinity` to always be in first place, and vice versa with `order: Infinity`.\
541If two teardowns have the same `order` they are ordered per time of invocation within that order group.
542
543```js
544test('teardown order', function (t) {
545 t.teardown(async function () {
546 await new Promise(r => setTimeout(r, 200))
547 console.log('teardown B')
548 })
549
550 t.teardown(async function () {
551 await new Promise(r => setTimeout(r, 200))
552 console.log('teardown A')
553 }, { order: -1 })
554
555 t.teardown(async function () {
556 await new Promise(r => setTimeout(r, 200))
557 console.log('teardown C')
558 }, { order: 1 })
559
560 t.pass()
561})
562```
563
564The `A` teardown is executed first, then `B`, and finally `C` due to the `order` option.
565
566#### `t.timeout(ms)`
567
568Fail the test after a given timeout.
569
570#### `t.comment(message)`
571
572Inject a TAP comment into the output.
573
574#### `t.end()`
575
576Force end a test.\
577`end` is determined by `assert` resolution or when a containing async function completes.\
578In case of inverted tests, they're required to be explicitly called.
579
580
581### Readable Properties
582
583#### `t.name`
584The name of the test.
585
586#### `t.passes`
587The number of assertions that passed within the test.
588
589#### `t.fails`
590The number of assertions that failed within the test.
591
592#### `t.assertions`
593The number of assertions that were executed within the test.
594
595## Runner
596
597### Default timeout
598
599The default timeout is 30 seconds.
600
601### Example of `package.json` with `test` script
602
603The following would run all `.js` files in the test folder:
604
605```json
606{
607 "name": "my-app",
608 "version": "1.0.0",
609 "scripts": {
610 "test": "brittle test/*.js"
611 },
612 "devDependencies": {
613 "brittle": "^3.0.0-alpha.3"
614 }
615}
616```
617
618## CLI
619
620```sh
621npm install -g brittle
622```
623
624```shell
625brittle [flags] <files>
626
627Flags:
628 --version, -v Print the current version
629 --solo, -s Engage solo mode
630 --bail, -b Bail out on first assert failure
631 --coverage, -c Turn on coverage
632 --cov-dir <dir> Configure coverage output directory (default: ./coverage)
633 --trace Trace all active promises and print them if the test fails
634 --timeout, -t <timeout> Set the test timeout in milliseconds (default: 30000)
635 --runner, -r <runner> Generates an out file that contains all target tests
636 --mine, -m <miners> Keep running the tests in <miners> processes until they fail.
637 --unstealth, -u Show assertions even if stealth is used
638 --help|-h Show help
639```
640
641Note globbing is supported:
642```sh
643brittle --coverage path/to/test/*.js
644```
645
646Auto generate a single file containing "all tests":
647```shell
648brittle -r test/all.js test/*.js
649
650node test/all.js
651```
652
653You can use an environment variable to also set flags:
654```shell
655BRITTLE="--coverage --bail" brittle test.js
656```
657
658Force disable coverage with an environment variable:
659```shell
660BRITTLE_COVERAGE=false brittle test.js
661```
662### Coverage
663If the `--coverage` flag is set, brittle will output the coverage summary as a table at the end of execution and generate a json coverage report in the coverage output directory (configurable using `--cov-dir`).
664
665The coverage output directory will contain a `coverage-final.json` file which contains an istanbul json coverage report and a `v8-coverage.json` file which contains the raw v8 coverage data.
666
667Istanbul can be used to convert the istanbul json report into other formats. e.g.:
668```
669npx istanbul report html
670```
671
672## License
673Apache-2.0
node_modules/brittle/bin/bare.js +8 -0
……@@ -0,0 +1,8 @@
1#!/usr/bin/env bare
2
3if (!global.Bare && global.process) {
4 const { status } = require('child_process').spawnSync('bare', process.argv.slice(1), { stdio: 'inherit', shell: true })
5 process.exit(status)
6}
7
8require('../cmd.js')
node_modules/brittle/bin/node.js +3 -0
……@@ -0,0 +1,3 @@
1#!/usr/bin/env node
2
3require('../cmd.js')
node_modules/brittle/bin/pear.js +11 -0
……@@ -0,0 +1,11 @@
1#!/usr/bin/env pear
2
3/* global Pear */
4if (!global.Pear && global.process) {
5 const { status } = require('child_process').spawnSync('pear', process.argv.slice(1), { stdio: 'inherit', shell: true })
6 process.exit(status)
7}
8
9if (!Pear.run) throw new Error('Incompatible with current Pear version (must be v2+)')
10
11require('../brittle/cmd.js')
node_modules/brittle/cmd.js +251 -0
……@@ -0,0 +1,251 @@
1#!/usr/bin/env node
2
3const path = require('path')
4const os = require('os')
5const { command, flag, rest } = require('paparam')
6const Globbie = require('globbie')
7const { spawn } = require('child_process')
8const process = require('process')
9const TracingPromise = require('./lib/tracing-promise')
10const pkg = require('./package')
11
12const args = (process.env.BRITTLE || '').split(/\s|,/g).map(s => s.trim()).filter(s => s).concat(process.argv.slice(2))
13const cmd = command('brittle',
14 flag('--version|-v', 'Print the current version'),
15 flag('--solo, -s', 'Engage solo mode'),
16 flag('--bail, -b', 'Bail out on first assert failure'),
17 flag('--coverage, -c', 'Turn on coverage'),
18 flag('--cov-dir <dir>', 'Configure coverage output directory (default: ./coverage)'),
19 flag('--trace', 'Trace all active promises and print them if the test fails'),
20 flag('--timeout, -t <timeout>', 'Set the test timeout in milliseconds (default: 30000)'),
21 flag('--runner, -r <runner>', 'Generates an out file that contains all target tests'),
22 flag('--mine, -m <miners>', 'Keep running the tests in <miners> processes until they fail.'),
23 flag('--unstealth, -u', 'Print out assertions even if stealth is used'),
24 rest('<files>')
25).parse(args)
26if (!cmd) process.exit(0)
27
28const { version } = cmd.flags
29if (version) {
30 console.log(`v${pkg.version}`)
31 process.exit(0)
32}
33
34const argv = cmd.flags
35
36const files = []
37for (const g of cmd.rest || []) {
38 const glob = new Globbie(g, { sync: true })
39 const matches = glob.match()
40
41 if (matches.length === 0) {
42 if (g[0] === '-') continue
43 console.error(`Error: no files found when resolving ${g}`)
44 process.exit(1)
45 }
46
47 files.push(...matches)
48}
49
50if (files.length === 0) {
51 console.error('Error: No test files were specified')
52 process.exit(1)
53}
54
55const { solo, bail, timeout, coverage, covDir, mine, trace, unstealth } = argv
56
57process.title = 'brittle'
58
59if (trace && !mine) {
60 TracingPromise.enable()
61 process.on('exit', function (code, signal) {
62 if (!code && !signal) return
63 console.error()
64 console.error('Printing tracing info since the tests failed:')
65 console.error()
66 TracingPromise.print()
67 })
68}
69
70if (argv.runner) {
71 const fs = require('fs')
72
73 if (argv.runner === true) {
74 console.error('--runner must be a path to the generated test runner')
75 process.exit(2)
76 }
77
78 const out = path.resolve(argv.runner)
79 const dir = path.dirname(out)
80
81 let s = ''
82
83 s += 'runTests()\n\nasync function runTests () {\n const test = (await import(\'brittle\')).default\n\n'
84
85 if (bail || solo || unstealth || timeout) {
86 s += ` test.configure({ bail: ${!!bail}, solo: ${!!solo}, unstealth: ${!!unstealth}, timeout: ${timeout} })\n`
87 }
88
89 s += ' test.pause()\n\n'
90
91 for (const f of files) {
92 const t = path.resolve(f)
93 if (t === out) continue
94
95 let r = path.relative(dir, t).replace(/\\/g, '/')
96 if (r[0] !== '.') r = './' + r
97 s += ' await import(\'' + r + '\')\n'
98 }
99
100 s = s.trimRight()
101
102 s += '\n\n test.resume()\n}\n'
103 s = '// This runner is auto-generated by Brittle\n\n' + s
104
105 try {
106 fs.mkdirSync(dir)
107 } catch {}
108
109 fs.writeFileSync(out, s)
110 process.exit(0)
111}
112
113if (coverage && process.env.BRITTLE_COVERAGE !== 'false') require('bare-cov')({ dir: covDir })
114
115if (mine) startMining().catch()
116else start().catch(onerror)
117
118function onerror (err) {
119 console.error(err.stack)
120 process.exit(1)
121}
122
123async function start () {
124 const brittle = require('./')
125
126 if (bail || solo || unstealth || timeout) {
127 brittle.configure({ bail, solo, unstealth, timeout: timeout ? Number(timeout) : undefined })
128 }
129
130 brittle.pause()
131
132 for (const f of files) {
133 await import('file://' + path.resolve(f))
134 }
135
136 brittle.resume()
137}
138
139async function startMining () {
140 const args = [__filename]
141 .concat(solo ? ['--solo'] : [])
142 .concat(bail ? ['--bail'] : [])
143 .concat(unstealth ? ['--unstealth'] : [])
144 .concat(trace ? ['--trace'] : [])
145 .concat(timeout ? ['--timeout', timeout + ''] : [])
146 .concat(files)
147
148 const running = new Set()
149 const max = Number(argv.mine) || 1
150
151 let runs = 0
152 let bailed = false
153 let newline = false
154
155 const interval = setInterval(function () {
156 console.log('Still mining... Total runs: ' + runs)
157 newline = true
158 }, 1000)
159
160 bump()
161
162 process.once('SIGINT', bail)
163 process.once('SIGTERM', bail)
164
165 function bail () {
166 bailed = true
167 clearInterval(interval)
168 for (const r of running) r.kill()
169 }
170
171 async function bump () {
172 if (running.size >= max || bailed) return
173
174 const r = run()
175 running.add(r)
176
177 const { exitCode, signalCode, output } = await r.promise
178 running.delete(r)
179 runs++
180
181 if (bailed) return
182
183 if (!exitCode && !signalCode) {
184 bump()
185 bump()
186 return
187 }
188
189 bailed = true
190
191 clearInterval(interval)
192
193 if (newline) console.log()
194 if (exitCode) console.log('Runner failed with exit code ' + exitCode + '!')
195 else console.log('Runner failed with signal code ' + signalCode + ' (' + signalToName(signalCode) + ')!')
196
197 console.log('Shutting down the rest and printing output...')
198
199 for (const r of running) {
200 r.kill()
201 await r.promise
202 }
203
204 console.log('Done! The tests took ' + runs + ' runs to fail.')
205 console.log()
206
207 for (const { stdout, data } of output) {
208 if (stdout) process.stdout.write(data)
209 else process.stderr.write(data)
210 }
211
212 clearInterval(interval)
213 process.exitCode = exitCode || 1
214 }
215
216 function run () {
217 const p = spawn(process.execPath, args)
218
219 const output = []
220
221 p.stdout.on('data', (data) => output.push({ stdout: true, data }))
222 p.stderr.on('data', (data) => output.push({ stdout: false, data }))
223
224 const stdoutClosed = new Promise(resolve => p.stdout.on('close', resolve))
225 const stderrClosed = new Promise(resolve => p.stderr.on('close', resolve))
226
227 const promise = new Promise((resolve) => {
228 p.on('exit', async (exitCode, signalCode) => {
229 await stdoutClosed
230 await stderrClosed
231 resolve({
232 exitCode,
233 signalCode,
234 output
235 })
236 })
237 })
238
239 return {
240 promise,
241 kill: () => p.kill()
242 }
243 }
244}
245
246function signalToName (code) {
247 for (const [k, v] of Object.entries(os.constants.signals)) {
248 if (v === code) return k
249 }
250 return null
251}
node_modules/brittle/index.js +885 -0
……@@ -0,0 +1,885 @@
1const sameObject = require('same-object')
2const tmp = require('test-tmp')
3const b4a = require('b4a')
4const { getSnapshot, createTypedArray } = require('./lib/snapshot')
5const { INDENT, RUNNER, IS_NODE, IS_BARE, DEFAULT_TIMEOUT } = require('./lib/constants')
6const AssertionError = require('./lib/assertion-error')
7const TracingPromise = require('./lib/tracing-promise')
8const Promise = TracingPromise.Untraced // never trace internal onces
9
10const highDefTimer = IS_NODE ? highDefTimerNode : highDefTimerFallback
11const program = IS_NODE ? process : global.Bare
12
13// loaded on demand since it's error flow and we want ultra fast positive test runs
14const lazy = {
15 _errors: null,
16 _tmatch: null,
17 get errors () {
18 if (!lazy._errors) lazy._errors = require('./lib/errors.js')
19 return lazy._errors
20 },
21 get tmatch () {
22 if (!lazy._tmatch) lazy._tmatch = require('tmatch')
23 return lazy._tmatch
24 }
25}
26
27class Runner {
28 constructor () {
29 this.tests = { count: 0, pass: 0 }
30 this.assertions = { count: 0, pass: 0 }
31
32 this.next = null
33 this.solos = new Set()
34 this.padded = true
35 this.started = false
36 this.defaultTimeout = DEFAULT_TIMEOUT
37 this.bail = false
38 this.unstealth = false
39 this.skipAll = false
40 this.explicitSolo = false
41 this.source = true
42
43 this._timer = highDefTimer()
44 this._log = console.log.bind(console)
45 this._paused = null
46 this._resume = null
47
48 const ondeadlock = () => {
49 if (this.next && this.next._checkDeadlock === false) return
50 program.off('beforeExit', ondeadlock)
51 this.end()
52 }
53
54 program.on('beforeExit', ondeadlock)
55 }
56
57 resume () {
58 if (!this._paused) return
59 this._resume()
60 this._resume = this._paused = null
61 }
62
63 pause () {
64 if (this._paused) return
65 this._paused = new Promise((resolve) => { this._resume = resolve })
66 }
67
68 async _wait () {
69 await wait()
70 await this._paused
71 }
72
73 async queue (test) {
74 this.start()
75
76 if (test._isSolo) {
77 this.solos.add(test)
78 }
79
80 await this._wait()
81
82 if (this.explicitSolo && !test._isSolo) {
83 return false
84 }
85
86 if (this._shouldTest(test)) {
87 while (this.next !== null) {
88 const next = this.next
89 await next
90 if (next === this.next) this.next = null
91 }
92
93 if (test._isSkip) {
94 this._skip('SKIP', test)
95 return false
96 }
97
98 if (test._isTodo) {
99 this._skip('TODO', test)
100 return false
101 }
102
103 if (!this._shouldTest(test)) {
104 return false
105 }
106
107 this.next = test
108 test._header()
109
110 if (!IS_NODE && !IS_BARE) this._autoExit(test)
111
112 return true
113 }
114
115 return false
116 }
117
118 _skip (reason, test) {
119 if (this._shouldTest(test)) {
120 test._header()
121 this.tests.pass++
122 this.tests.count++
123 this.assert(false, true, this.tests.count, '- ' + test.name + ' # ' + reason, null)
124 }
125 }
126
127 _shouldTest (test) {
128 return test._isHook || (!this.skipAll && (this.solos.size === 0 || this.solos.has(test)))
129 }
130
131 async _autoExit (test) {
132 try {
133 await test
134 await wait(10) // wait 10 ticks...
135 if (this.next === test) {
136 this.end()
137 }
138 } catch {}
139 }
140
141 log (...message) {
142 this._log(...message)
143 this.padded = false
144 }
145
146 padding () {
147 if (this.padded) return
148 this.padded = true
149 this.log()
150 }
151
152 start () {
153 if (this.started) return
154 this.started = true
155 this.log('TAP version 13')
156 }
157
158 comment (...message) {
159 this.log('#', ...message)
160 }
161
162 end () {
163 if (this.next) {
164 if (!this.next._isEnded && !(this.next._hasPlan && this.next._planned === 0)) {
165 this.next._onend(prematureEnd(this.next, 'Test did not end (' + this.next.name + ')'))
166 return
167 }
168
169 if (!this.next._isResolved) {
170 if (this.next._isDone) {
171 this.next._onend(new Error('Teardown did not end (unresolved promise)'))
172 return
173 }
174 this.next._onend(new Error('Test appears deadlocked (unresolved promise)'))
175 return
176 }
177 }
178
179 if (this.bail && this.skipAll) {
180 this.log('Bail out!')
181 }
182
183 this.padding()
184 this.log('1..' + this.tests.count)
185 this.log('# tests = ' + this.tests.pass + '/' + this.tests.count + ' pass')
186 this.log('# asserts = ' + this.assertions.pass + '/' + this.assertions.count + ' pass')
187 this.log('# time = ' + this._timer() + 'ms')
188 this.log()
189
190 if (this.tests.count === this.tests.pass && this.assertions.count === this.assertions.pass) this.log('# ok')
191 else this.log('# not ok')
192 }
193
194 assert (indent, ok, number, message, explanation, stealth) {
195 const ind = indent ? INDENT : ''
196
197 if (ok) {
198 if (!stealth || this.unstealth) this.log(ind + 'ok ' + number, message)
199 } else {
200 if (IS_NODE) process.exitCode = 1
201 if (IS_BARE) global.Bare.exitCode = 1
202 this.log(ind + 'not ok ' + number, message)
203 if (explanation) this.log(lazy.errors.stringify(explanation))
204 if (this.bail && !this.skipAll) this.skipAll = true
205 if (!this.unstealth && stealth) throw new AssertionError({ message: 'Stealth assertion failed' })
206 }
207 }
208}
209
210class Test {
211 constructor (name, parent, opts = {}) {
212 this._resolve = null
213 this._reject = null
214
215 this._promise = new Promise((resolve, reject) => {
216 this._resolve = resolve
217 this._reject = reject
218 })
219
220 this._parents = []
221 this._main = parent ? parent._main : this
222 this._runner = getRunner()
223 this.name = name
224 this.passes = 0
225 this.fails = 0
226 this.assertions = 0
227
228 this._isEnded = false
229 this._isDone = false
230 this._isHook = opts?.hook || false
231 this._isSolo = opts?.solo || false
232 this._isSkip = opts?.skip || false
233 this._isTodo = opts?.todo || false
234 this._isResolved = false
235 this._isQueued = false
236 this._isMain = this._main === this
237 this._isStealth = opts?.stealth || parent?._isStealth || false
238 this._checkDeadlock = opts?.deadlock !== false
239
240 // allow destructuring by binding the functions
241 this.comment = this._comment.bind(this)
242 this.timeout = this._timeout.bind(this)
243 this.teardown = this._teardown.bind(this)
244 this.test = this._test.bind(this)
245 this.plan = this._plan.bind(this)
246
247 this.pass = this._pass.bind(this)
248 this.fail = this._fail.bind(this)
249
250 this.ok = this._ok.bind(this)
251 this.absent = this._absent.bind(this)
252
253 this.is = this._is.bind(this, true)
254 this.is.coercively = this._is.bind(this, false)
255
256 this.not = this._not.bind(this, true)
257 this.not.coercively = this._not.bind(this, false)
258
259 this.alike = this._alike.bind(this, true)
260 this.alike.coercively = this._alike.bind(this, false)
261
262 this.unlike = this._unlike.bind(this, true)
263 this.unlike.coercively = this._unlike.bind(this, false)
264
265 this.exception = this._exception.bind(this, false)
266 this.exception.all = this._exception.bind(this, true)
267
268 this.execution = this._execution.bind(this)
269
270 this.stealth = this._stealth.bind(this)
271
272 this.snapshot = this._snapshot.bind(this)
273
274 this.end = this._end.bind(this)
275
276 this._parent = parent
277 this._first = true
278 this._wait = false
279 this._planned = 0
280 this._hasPlan = false
281 this._active = 0
282 this._timer = null
283
284 this._headerLogged = false
285 this._to = null
286 this._teardowns = []
287 this._tickers = new Map()
288
289 while (parent) {
290 this._parents.push(parent)
291 parent = parent._parent
292 }
293 }
294
295 then (...args) {
296 return this._promise.then(...args)
297 }
298
299 catch (...args) {
300 return this._promise.catch(...args)
301 }
302
303 finally (...args) {
304 return this._promise.finally(...args)
305 }
306
307 _header () {
308 if (this._headerLogged) return
309 this._headerLogged = true
310 this._runner.start()
311 this._runner.padding()
312 this._runner.comment(this.name || 'test')
313 }
314
315 tmp () { return tmp(this) }
316
317 _planDoneOrEnd () {
318 return this._isEnded || (this._hasPlan && this._planned === 0)
319 }
320
321 _timeout (ms) {
322 if (!ms) {
323 if (this._to) clearTimeout(this._to)
324 this._to = null
325 return
326 }
327
328 const ontimeout = () => {
329 this._to = null
330 this._onend(new Error('Test timed out after ' + ms + ' ms'))
331 }
332
333 if (this._to) clearTimeout(this._to)
334 this._to = setTimeout(ontimeout, ms)
335 if (this._to.unref) this._to.unref()
336 }
337
338 _plan (n) {
339 if (typeof n !== 'number' || n < 0) {
340 throw new Error('Plan takes a positive whole number only')
341 }
342
343 this._hasPlan = true
344 this._planned = n
345 }
346
347 _comment (...m) {
348 if (this._isResolved) throw new Error('Can\'t comment after end')
349 this._runner.log(INDENT + '#', ...m)
350 }
351
352 _message (message) {
353 let m = '- '
354
355 if (!this._isMain) {
356 for (let i = this._parents.length - 2; i >= 0; i--) {
357 const p = this._parents[i]
358 if (!p.name) continue
359 m += '(' + p.name + ') - '
360 }
361 if (this.name) {
362 m += '(' + this.name + ') - '
363 }
364 }
365
366 if (message) {
367 m += message
368 }
369
370 return m
371 }
372
373 _tick (ok) {
374 if (ok) this.passes++
375 else this.fails++
376 this.assertions++
377 }
378
379 _track (topLevel, ok) {
380 if (topLevel) {
381 this._runner.tests.count++
382 if (ok) this._runner.tests.pass++
383 return this._runner.tests.count
384 }
385
386 if (this._hasPlan) this._planned--
387 this._tick(ok)
388
389 if (!this._isMain) this._main._tick(ok)
390
391 this._runner.assertions.count++
392 if (ok) this._runner.assertions.pass++
393
394 return this._main.assertions
395 }
396
397 _assertion (ok, message, explanation, caller, top, isStealth = this._isStealth) {
398 this._runner.assert(!this._main._isResolved, ok, this._track(false, ok), this._message(message), explanation, isStealth)
399
400 if (this._isEnded || this._isDone) {
401 throw new AssertionError({ message: 'Assertion after end' })
402 }
403
404 if (this._hasPlan && this._planned < 0) {
405 throw new AssertionError({ message: 'Too many assertions' })
406 }
407
408 if (this._hasPlan && this._planned === 0) {
409 this._checkEnd()
410 }
411 }
412
413 _fail (message = 'failed') {
414 const explanation = explain(false, message, 'fail', this._fail)
415 this._assertion(false, message, explanation, this._fail, undefined)
416 }
417
418 _pass (message = 'passed') {
419 this._assertion(true, message, null, this._pass, undefined)
420 }
421
422 _ok (assertion, message = 'expected truthy value') {
423 const ok = assertion
424 const explanation = explain(ok, message, 'ok', this._ok)
425 this._assertion(ok, message, explanation, this._ok, undefined)
426 }
427
428 _absent (assertion, message = 'expected falsy value') {
429 const ok = !assertion
430 const explanation = explain(ok, message, 'absent', this._absent)
431 this._assertion(ok, message, explanation, this._absent, undefined)
432 }
433
434 _is (strict, actual, expected, message = 'should be equal') {
435 const ok = strict ? actual === expected : actual == expected // eslint-disable-line
436 const explanation = explain(ok, message, 'is', this._is, actual, expected)
437 this._assertion(ok, message, explanation, this._is, undefined)
438 }
439
440 _not (strict, actual, expected, message = 'should not be equal') {
441 const ok = strict ? actual !== expected : actual != expected // eslint-disable-line
442 const explanation = explain(ok, message, 'not', this._not, actual, expected)
443 this._assertion(ok, message, explanation, this._not, undefined)
444 }
445
446 _alike (strict, actual, expected, message = 'should deep equal') {
447 const ok = sameObject(actual, expected, { strict })
448 const explanation = explain(ok, message, 'alike', this._alike, actual, expected)
449 this._assertion(ok, message, explanation, this._alike, undefined)
450 }
451
452 _unlike (strict, actual, expected, message = 'should not deep equal') {
453 const ok = sameObject(actual, expected, { strict }) === false
454 const explanation = explain(ok, message, 'unlike', this._unlike, actual, expected)
455 this._assertion(ok, message, explanation, this._unlike, undefined)
456 }
457
458 _teardown (fn, opts = {}) {
459 if (this._isDone) throw new Error('Can\'t add teardown after end')
460 this._teardowns.push([opts.order || 0, !!opts.force, fn])
461 }
462
463 async _exception (natives, functionOrPromise, expectedError, message) {
464 if (typeof expectedError === 'string') {
465 message = expectedError
466 expectedError = undefined
467 }
468
469 const top = originFrame(this._exception)
470 const pristineMessage = message === undefined
471
472 let ok = null
473 let actual = false
474
475 if (pristineMessage) message = 'should throw'
476
477 this._active++
478 try {
479 if (typeof functionOrPromise === 'function') functionOrPromise = functionOrPromise()
480 if (isPromise(functionOrPromise)) {
481 if (pristineMessage) message = 'should reject'
482 await functionOrPromise
483 }
484 ok = false
485 } catch (err) {
486 const native = natives === false && isUncaught(err)
487 if (native) throw err
488
489 if (!expectedError) {
490 ok = true
491 } else {
492 ok = lazy.tmatch(err, expectedError)
493 }
494
495 actual = err
496 } finally {
497 this._active--
498 }
499
500 const explanation = explain(ok, message, 'exception', this._exception, actual, expectedError, top)
501 this._assertion(ok, message, explanation, this._execution, top)
502 this._checkEnd()
503 }
504
505 async _execution (functionOrPromise, message) {
506 const top = originFrame(this._execution)
507 const pristineMessage = message === undefined
508
509 let ok = false
510 let error = null
511
512 if (pristineMessage) message = 'should return'
513
514 const time = highDefTimer()
515
516 this._active++
517 try {
518 if (typeof functionOrPromise === 'function') functionOrPromise = functionOrPromise()
519 if (isPromise(functionOrPromise)) {
520 if (pristineMessage) message = 'should resolve'
521 await functionOrPromise
522 }
523 ok = true
524 } catch (err) {
525 error = err
526 } finally {
527 this._active--
528 }
529
530 const elapsed = time()
531
532 const explanation = explain(ok, message, 'execution', this._execution, error, null, top)
533 this._assertion(ok, message, explanation, this._execution, top)
534 this._checkEnd()
535
536 return elapsed
537 }
538
539 _stealth (name, opts, fn) {
540 if (typeof name === 'function') return this.stealth(null, null, name)
541 if (typeof opts === 'function') return this.stealth(name, null, opts)
542
543 return this.test(name, { ...opts, stealth: true }, fn)
544 }
545
546 _snapshot (actual, message = 'should match snapshot') {
547 const top = originFrame(this._snapshot)
548
549 if (!top) {
550 this._assertion(true, message, null, this._snapshot, undefined)
551 return
552 }
553
554 if (b4a.isBuffer(actual)) {
555 actual = new Uint8Array(actual.buffer, actual.byteOffset, actual.byteLength)
556 }
557
558 const filename = top.getFileName()
559 const key = (this.name || '') + ' ' + this._message(message)
560 const expected = getSnapshot(filename, key + ' - ' + this._getTick(key), actual)
561
562 const ok = sameObject(actual, expected, { strict: true })
563 const explanation = explain(ok, message, 'snapshot', this._snapshot, actual, expected)
564
565 this._assertion(ok, message, explanation, this._snapshot, undefined)
566 }
567
568 _getTick (key) {
569 const tick = this._tickers.get(key) || 0
570 this._tickers.set(key, 1 + tick)
571 return tick
572 }
573
574 _test (name, opts, fn) {
575 if (typeof name === 'function') return this.test(null, null, name)
576 if (typeof opts === 'function') return this.test(name, null, opts)
577
578 const t = new Test(name, this, opts)
579
580 if (this._hasPlan) this._planned--
581 this._active++
582
583 return fn ? t._run(fn, opts || {}) : t
584 }
585
586 async _run (fn, opts) {
587 this._isQueued = true
588
589 if (!this._parent) {
590 if (!(await this._runner.queue(this))) return
591 }
592
593 this._onstart(opts)
594 this._wait = true
595
596 try {
597 await fn(this)
598 } catch (err) {
599 if (!(err instanceof AssertionError && err.message === 'ERR_ASSERTION: Stealth assertion failed')) {
600 this._wait = false
601 await this._runTeardown(err)
602 throw err
603 }
604 }
605
606 if (!this._hasPlan) this.end()
607
608 this._wait = false
609 this._checkEnd()
610
611 return await this
612 }
613
614 _end () {
615 this._isEnded = true
616
617 if (this._hasPlan && this._planned > 0) {
618 throw prematureEnd(this, 'Too few assertions')
619 }
620
621 this._checkEnd()
622 }
623
624 _checkEnd () {
625 if (this._active || this._wait) return
626 if (this._isEnded || (this._hasPlan && this._planned === 0)) this._done()
627 }
628
629 _done () {
630 if (this._isDone) return
631 this._isDone = true
632
633 if (this._teardowns.length) {
634 this._teardowns.sort(cmp)
635 this._runTeardown(null)
636 } else {
637 this._onend(null)
638 }
639
640 if (this._parent) {
641 const p = this._parent
642
643 this._parent._active--
644 this._parent = null
645
646 p._checkEnd()
647 }
648 }
649
650 async _runTeardown (error) {
651 const forced = !!error
652
653 let fired = false
654
655 const t = setTimeout(() => {
656 fired = true
657 this.comment('...teardown still running after 250ms')
658 }, 250)
659
660 if (t.unref) t.unref()
661
662 const time = highDefTimer()
663
664 for (const [, force, teardown] of this._teardowns) {
665 try {
666 if (force || !forced) await teardown()
667 } catch (err) {
668 if (!error) error = err
669 }
670 }
671
672 clearTimeout(t)
673 if (fired) this.comment('...teardown time ' + time() + 'ms')
674 this._onend(error)
675 }
676
677 _onstart (opts) {
678 const to = this._isMain
679 ? (opts && opts.timeout !== undefined) ? opts.timeout : this._runner.defaultTimeout // main tests need a default timeout, unless opt-out
680 : opts && opts.timeout // non main ones do not
681
682 if (this._isMain) {
683 if (!this._isQueued) {
684 if (this._runner.next) throw new Error('Only run test can be running at the same time')
685 this._runner.next = this
686 }
687 this._header()
688 this._timer = highDefTimer()
689 }
690
691 if (to) this._timeout(to)
692 }
693
694 _onend (err) {
695 if (this._isResolved) return
696
697 this._timeout(0) // just to be sure incase someone ran this during teardown...
698
699 const ok = (this.fails === 0)
700
701 if (this._isMain && !err) {
702 const time = this._timer ? ' # time = ' + this._timer() + 'ms' : ''
703 this._runner.assert(false, ok, this._track(true, ok), '- ' + (this.name || '') + time, null)
704 }
705
706 this._isResolved = true
707 this._isDone = true
708
709 if (this._isMain && this._runner.next === this) {
710 this._runner.next = null
711 }
712
713 if (err) this._reject(err)
714 else this._resolve(ok)
715
716 // if test is running without deadlock detection, trigger "io" to rerun it in case idle now
717 if (this._checkDeadlock === false) setImmediate(() => {})
718 }
719}
720
721exports = module.exports = test
722
723exports.Test = Test
724exports.test = test
725exports.hook = hook
726exports.solo = solo
727exports.skip = skip
728exports.todo = todo
729exports.configure = configure
730exports.pause = pause
731exports.resume = resume
732exports.stealth = stealth
733
734// Used by snapshots
735exports.createTypedArray = createTypedArray
736
737function configure ({ timeout = DEFAULT_TIMEOUT, bail = false, solo = false, unstealth = false, source = true, coverage = false } = {}) {
738 const runner = getRunner()
739
740 if (runner.tests.count > 0 || runner.assertions.count > 0) {
741 throw new Error('Configuration must happen prior to registering any tests')
742 }
743
744 if (coverage) require('bare-cov')({ dir: typeof coverage === 'string' ? coverage : undefined })
745
746 runner.defaultTimeout = timeout
747 runner.bail = bail
748 runner.explicitSolo = solo
749 runner.unstealth = unstealth
750 runner.source = source
751}
752
753function highDefTimerNode () {
754 const then = process.hrtime.bigint()
755 return function () {
756 const now = process.hrtime.bigint()
757 return Number(now - then) / 1e6
758 }
759}
760
761function highDefTimerFallback () {
762 const then = Date.now()
763 return function () {
764 const now = Date.now()
765 return now - then
766 }
767}
768
769function cmp (a, b) {
770 return a[0] - b[0]
771}
772
773function test (name, opts, fn, overrides) {
774 if (typeof name === 'function') return test(null, null, name, overrides)
775 if (typeof opts === 'function') return test(name, null, opts, overrides)
776
777 opts = { ...opts, ...overrides }
778
779 const t = new Test(name, null, opts)
780
781 if (fn) return t._run(fn, opts)
782 if (t._isTodo) return t._run(() => {}, opts)
783
784 if (t._isSkip) {
785 throw new Error('An inverted test cannot be skipped')
786 }
787 if (t._isSolo) {
788 t._runner.solo = t
789 }
790
791 t._onstart(opts)
792
793 return t
794}
795
796function hook (name, opts, fn) {
797 return test(name, opts, fn, { hook: true })
798}
799
800function solo (name, opts, fn) {
801 if (!name && !opts && !fn) return test.configure({ solo: true })
802 return test(name, opts, fn, { solo: true })
803}
804
805function skip (name, opts, fn) {
806 return test(name, opts, fn, { skip: true })
807}
808
809function todo (name, opts, fn) {
810 return test(name, opts, fn, { todo: true })
811}
812
813function pause () {
814 getRunner().pause()
815}
816
817function resume () {
818 getRunner().resume()
819}
820
821function wait (ticks = 1) {
822 return new Promise(resolve => {
823 tickish(function loop () {
824 if (--ticks <= 0) return resolve()
825 tickish(loop)
826 })
827 })
828}
829
830function tickish (fn) {
831 if (IS_NODE) { // do both types of tick in node to flush both queues
832 process.nextTick(queueMicrotask, fn)
833 } else {
834 queueMicrotask(fn)
835 }
836}
837
838function explain (ok, message, assert, stackStartFunction, actual, expected, top = !ok && originFrame(stackStartFunction), extra) {
839 const runner = getRunner()
840 return ok ? null : lazy.errors.explain(ok, message, assert, stackStartFunction, actual, expected, runner.source ? top : null, extra)
841}
842
843function originFrame (stackStartFunction) {
844 if (!Error.captureStackTrace) return undefined
845 const { prepareStackTrace } = Error
846 Error.prepareStackTrace = (_, stack) => {
847 if (stack[0].getFunctionName() === '[brittle.error]') return null
848 if (stack[0].getMethodName() === 'coercively') return stack[1]
849 return stack[0]
850 }
851 const err = {}
852 Error.captureStackTrace(err, stackStartFunction)
853 const { stack: top } = err
854 Error.prepareStackTrace = prepareStackTrace
855 return top
856}
857
858function isPromise (p) {
859 return !!(p && typeof p.then === 'function')
860}
861
862function isUncaught (err) {
863 return err instanceof SyntaxError ||
864 err instanceof ReferenceError ||
865 err instanceof TypeError ||
866 err instanceof EvalError ||
867 err instanceof RangeError
868}
869
870function getRunner () {
871 if (!global[RUNNER]) global[RUNNER] = new Runner()
872 return global[RUNNER]
873}
874
875function prematureEnd (t, message) {
876 const details = t._hasPlan
877 ? ' [assertion count (' + t.assertions + ') did not reach plan (' + (t.assertions + t._planned) + ')]'
878 : ''
879
880 return new Error(message + details)
881}
882
883function stealth (name, opts, fn) {
884 return test(name, opts, fn, { stealth: true })
885}
node_modules/brittle/lib/assertion-error.js +12 -0
……@@ -0,0 +1,12 @@
1const CODE = 'ERR_ASSERTION'
2
3module.exports = class AssertionError extends Error {
4 constructor ({ message }) {
5 super(`${CODE}: ${message}`)
6 this.code = CODE
7
8 if (Error.captureStackTrace) {
9 Error.captureStackTrace(this, AssertionError)
10 }
11 }
12}
node_modules/brittle/lib/constants.js +5 -0
……@@ -0,0 +1,5 @@
1exports.INDENT = ' '
2exports.RUNNER = Symbol.for('brittle-runner')
3exports.IS_NODE = !!(typeof process === 'object' && process && process.versions && (typeof (process.versions.node || process.versions.pear || process.versions.bare) === 'string') && !process.browser)
4exports.IS_BARE = typeof Bare !== 'undefined'
5exports.DEFAULT_TIMEOUT = 30000
node_modules/brittle/lib/errors.js +127 -0
……@@ -0,0 +1,127 @@
1const { AssertionError } = require('assert')
2const fs = require('fs')
3const url = require('url')
4const os = require('os')
5const StackParser = require('error-stack-parser')
6const { INDENT, IS_BARE } = require('./constants')
7
8const parseStack = StackParser.parse.bind(StackParser)
9
10const IGNORE = typeof __filename === 'string' ? [__filename, __filename.replace(/lib(\/|\\)errors\.js$/, 'index.js')] : []
11
12exports.stringify = stringify
13exports.explain = explain
14
15function explain (ok, message, assert, stackStartFunction, actual, expected, top, extra) {
16 if (ok) return null
17
18 const cwd = IS_BARE ? os.cwd() : process.cwd()
19
20 const err = new AssertionError({ stackStartFunction, message, operator: assert, actual, expected })
21 stackScrub(err)
22
23 if (top) {
24 const line = top.getLineNumber()
25 const column = top.getColumnNumber()
26 let file = top.getFileName()?.replace(/\?cacheBust=\d+/g, '')
27
28 try {
29 try {
30 if (url) file = url.fileURLToPath(new URL(file, 'file:'))
31 } catch {}
32
33 if (file.startsWith(cwd)) {
34 file = file.replace(cwd, '.')
35 }
36
37 if (fs) {
38 const code = fs.readFileSync(file, { encoding: 'utf-8' })
39 const split = code.split(/\r?\n/g)
40 const point = Array.from({ length: column - 1 }).map(() => '-').join('') + '^'
41 const source = [...split.slice(line - 2, line), point, ...split.slice(line, line + 2)]
42 err.source = source.join('\n')
43 } else {
44 err.source = ''
45 }
46 } /* c8 ignore next */ catch {}
47 }
48 const { code, generatedMessage, ...info } = err
49 err.code = code
50 err.generatedMessage = generatedMessage
51 Object.defineProperty(info, 'err', { value: err })
52
53 if (err.stack) {
54 info.stack = err.stack.slice(err.toString().length + 1).split('\n').map((line) => {
55 let match = false
56
57 line = line.slice(7).replace(cwd, () => {
58 match = true
59 return '.'
60 })
61
62 if (match) line = line.replace(/file:\/?\/?\/?/, '')
63 return line
64 }).join('\n').trim()
65 }
66
67 if (!info.stack || code === 'ERR_TIMEOUT' || code === 'ERR_PREMATURE_END' || actual?.code === 'ERR_TIMEOUT' || actual?.code === 'ERR_PREMATURE_END') delete info.stack
68
69 if (actual === undefined && expected === undefined) {
70 delete info.actual
71 delete info.expected
72 }
73
74 if (info.diff) delete info.diff
75
76 return info
77}
78
79function stackScrub (err) {
80 if (err && err.stack) {
81 const errString = err.toString()
82 const stack = '\n' + err.stack.slice(errString.length + 1)
83 const scrubbed = parseStack({ stack }).filter(({ fileName }) => !IGNORE.includes(fileName))
84 if (scrubbed.length > 0) {
85 err.stack = `${errString}\n at ${scrubbed.join('\n at ').replace(/\?cacheBust=\d+/g, '')}`
86 }
87 }
88 return err
89}
90
91function indent (src) {
92 return src.split('\n').map(s => INDENT + ' ' + s).join('\n')
93}
94
95function stringify (o) {
96 return indent('---\n' + toYAML(o)).trimRight() + '\n' + INDENT + ' ...'
97}
98
99// for the life of me can't find a module that does this, that also works in the browser...
100function toYAML (o, maxDepth = 5, indent = '', prev = null) {
101 if (maxDepth < 0) return indent + '...'
102
103 if (typeof o === 'string') {
104 if (o.indexOf('\n') === -1) return o + '\n'
105 return '|\n' + o.split('\n').map(s => indent + s).join('\n').trimRight() + '\n'
106 }
107
108 if (Array.isArray(o) || o instanceof Set) {
109 let s = prev ? '\n' : ''
110 for (const i of o) {
111 s += indent + '- ' + toYAML(i, maxDepth - 1, indent + ' ', 'array')
112 }
113 return s.trimRight() + '\n'
114 }
115
116 if (o && typeof o === 'object') {
117 const p = prev && prev !== 'array'
118 let s = p ? '\n' : ''
119 for (const k of Object.keys(o)) {
120 const v = o[k]
121 s += indent + k + ': ' + toYAML(v, maxDepth - 1, indent + ' ', 'object')
122 }
123 return (p ? s.trimRight() : s.trim()) + '\n'
124 }
125
126 return '' + o + '\n'
127}
node_modules/brittle/lib/snapshot.js +89 -0
……@@ -0,0 +1,89 @@
1const b4a = require('b4a')
2const { fileURLToPath } = require('url')
3
4exports.createTypedArray = function (TypedArray, src) {
5 const b = b4a.from(src, 'base64')
6 return new TypedArray(b.buffer, b.byteOffset, b.byteLength / TypedArray.BYTES_PER_ELEMENT)
7}
8
9exports.getSnapshot = function (filename, key, actual) {
10 let snap = {}
11
12 const p = split(filename)
13 if (!p) return actual
14
15 try {
16 snap = require(p.filename)
17 } catch {}
18
19 if (snap[key] !== undefined) return snap[key]
20
21 snap[key] = actual
22
23 const fs = requireMaybe('fs')
24 if (!fs) return actual
25
26 try {
27 fs.mkdirSync(p.dirname)
28 } catch {}
29
30 let brittle = false
31 let s = ''
32
33 for (const k of Object.keys(snap)) {
34 s += 'exports[' + toString(k) + '] = '
35
36 const v = snap[k]
37
38 if (isTypedArray(v)) {
39 if (!brittle) {
40 brittle = true
41 s = 'const { createTypedArray } = require(\'brittle\')\n\n' + s
42 }
43 const b = b4a.from(v.buffer, v.byteOffset, v.byteLength)
44 s += 'createTypedArray(' + v.constructor.name + ', ' + toString(b4a.toString(b, 'base64')) + ')\n\n'
45 } else {
46 s += toString(v) + '\n\n'
47 }
48 }
49 s = '/* eslint-disable */\n\n' + s + '/* eslint-enable */\n'
50
51 fs.writeFileSync(p.filename, s)
52 return actual
53}
54
55function isTypedArray (v) {
56 return !!(v && v.BYTES_PER_ELEMENT)
57}
58
59function toString (s) {
60 if (typeof s === 'string' && s.indexOf('\n') > 0 && s.indexOf('`') === -1) return '`' + s + '`'
61 if (typeof s === 'string' && s.indexOf('"') === -1) return '\'' + s + '\''
62 return JSON.stringify(s, null, 2)
63}
64
65function split (filename) {
66 if (filename.startsWith('file://')) filename = fileURLToPath(filename)
67
68 const a = filename.lastIndexOf('/')
69 const b = filename.lastIndexOf('\\')
70 const sep = a > b ? '/' : '\\'
71 const i = a > b ? a : b
72
73 if (i === -1) return null
74
75 const dirname = filename.slice(0, i) + sep + 'fixtures'
76
77 return {
78 dirname,
79 filename: dirname + sep + filename.slice(i + 1).replace(/\.[^.]+$/, '') + '.snapshot.cjs'
80 }
81}
82
83function requireMaybe (name) {
84 try {
85 return require(name)
86 } catch {
87 return null
88 }
89}
node_modules/brittle/lib/tracing-promise.js +72 -0
……@@ -0,0 +1,72 @@
1const activePromises = new Map()
2
3class TracingPromise extends Promise {
4 constructor (fn) {
5 const stack = (new Error()).stack
6 let deleted = false
7
8 addStack(stack)
9
10 super((resolve, reject) => {
11 const innerResolve = (value) => {
12 if (!deleted) {
13 deleted = true
14 deleteStack(stack)
15 }
16 resolve(value)
17 }
18 const innerReject = (err) => {
19 if (!deleted) {
20 deleted = true
21 deleteStack(stack)
22 }
23 reject(err)
24 }
25
26 return fn(innerResolve, innerReject)
27 })
28 }
29
30 static Untraced = Promise
31
32 static enable () {
33 global.Promise = TracingPromise
34 }
35
36 static print () {
37 if (activePromises.size === 0) {
38 console.error('(All promises are resolved)')
39 return
40 }
41 for (const [stack, count] of activePromises) {
42 const lines = stack.split('\n')
43 lines.shift()
44 lines.shift()
45
46 const trace = lines.map((line) => {
47 line = line.slice(7)
48 if (/\(node:[^(]*\)$/.test(line)) return null
49 if (line.startsWith('TracingPromise.then ')) return null
50 return ' at ' + line
51 }).filter(x => x).join('\n')
52
53 if (!trace) continue
54
55 console.error(count + ' promise' + (count === 1 ? '' : 's') + ' unresolved')
56 console.error(trace)
57 console.error()
58 }
59 }
60}
61
62module.exports = TracingPromise
63
64function addStack (s) {
65 activePromises.set(s, (activePromises.get(s) || 0) + 1)
66}
67
68function deleteStack (s) {
69 const n = activePromises.get(s)
70 if (n === 1) activePromises.delete(s)
71 else activePromises.set(s, n - 1)
72}
node_modules/brittle/package.json +84 -0
……@@ -0,0 +1,84 @@
1{
2 "name": "brittle",
3 "version": "3.19.1",
4 "description": "A TAP test runner built for modern times",
5 "main": "index.js",
6 "bin": {
7 "brittle": "bin/node.js",
8 "brittle-node": "bin/node.js",
9 "brittle-bare": "bin/bare.js",
10 "brittle-pear": "bin/pear.js"
11 },
12 "author": "David Mark Clements (@davidmarkclem)",
13 "license": "Apache-2.0",
14 "scripts": {
15 "test": "standard && node test/all.mjs",
16 "test-bare": "bare test/bare-test.mjs"
17 },
18 "files": [
19 "index.js",
20 "cmd.js",
21 "lib/**.js",
22 "bin/**.js"
23 ],
24 "dependencies": {
25 "b4a": "^1.6.0",
26 "bare-assert": "^1.0.2",
27 "bare-cov": "^1.1.0",
28 "bare-fs": "^4.1.6",
29 "bare-os": "^3.6.1",
30 "bare-path": "^3.0.0",
31 "bare-process": "^4.2.1",
32 "bare-subprocess": "^5.0.0",
33 "bare-url": "^2.1.6",
34 "error-stack-parser": "^2.1.4",
35 "globbie": "^1.0.2",
36 "paparam": "^1.6.2",
37 "same-object": "^1.0.2",
38 "test-tmp": "^1.4.0",
39 "tmatch": "^5.0.0"
40 },
41 "devDependencies": {
42 "chalk": "^4.1.2",
43 "safety-catch": "^1.0.2",
44 "standard": "^17.0.0"
45 },
46 "imports": {
47 "assert": {
48 "bare": "bare-assert",
49 "default": "assert"
50 },
51 "child_process": {
52 "bare": "bare-subprocess",
53 "default": "child_process"
54 },
55 "fs": {
56 "bare": "bare-fs",
57 "default": "fs"
58 },
59 "os": {
60 "bare": "bare-os",
61 "default": "os"
62 },
63 "path": {
64 "bare": "bare-path",
65 "default": "path"
66 },
67 "process": {
68 "bare": "bare-process",
69 "default": "process"
70 },
71 "url": {
72 "bare": "bare-url",
73 "default": "url"
74 }
75 },
76 "repository": {
77 "type": "git",
78 "url": "git+https://github.com/holepunchto/brittle.git"
79 },
80 "bugs": {
81 "url": "https://github.com/holepunchto/brittle/issues"
82 },
83 "homepage": "https://github.com/holepunchto/brittle#readme"
84}
node_modules/compact-encoding-bitfield/LICENSE +15 -0
……@@ -0,0 +1,15 @@
1ISC License
2
3Copyright (c) 2022 Contributors
4
5Permission to use, copy, modify, and/or distribute this software for any
6purpose with or without fee is hereby granted, provided that the above
7copyright notice and this permission notice appear in all copies.
8
9THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15PERFORMANCE OF THIS SOFTWARE.
node_modules/compact-encoding-bitfield/README.md +39 -0
……@@ -0,0 +1,39 @@
1# compact-encoding-bitfield
2
3[compact-encoding](https://github.com/compact-encoding/compact-encoding) codec for bitfields. Uses a variable length encoding that is ABI compatible with `cenc.uint`.
4
5```sh
6npm install compact-encoding-bitfield
7```
8
9## Usage
10
11```js
12const cenc = require('compact-encoding')
13const bitfield = require('compact-encoding-bitfield')
14
15const buffer = cenc.encode(bitfield(8), 0b1110_1011)
16// <Buffer fd eb 00>
17
18cenc.decode(bitfield(8), buffer)
19// <Buffer eb>
20```
21
22Bitfields are represented as buffers. For each byte, the least significant bit denotes the first bit and the most significant bit denotes the last bit. For example, bit `0` will be the least significant bit of the first byte and bit `15` will be the most significant bit of the second byte.
23
24The encoding will convert numbers to buffers. Buffers may also be passed directly and will be returned on decode.
25
26## ABI
27
28Depending on `length`, the bitfield is stored using a variable number of bytes:
29
301. `length < 8`: 1 byte with no prefix.
312. `length <= 16`: 2 bytes with a `0xfd` prefix.
323. `length <= 32`: 4 bytes with a `0xfe` prefix.
334. `length <= 64`: 8 bytes with a `0xff` prefix.
34
35`length` must not exceed 64 bits.
36
37## License
38
39ISC
node_modules/compact-encoding-bitfield/index.js +67 -0
……@@ -0,0 +1,67 @@
1const c = require('compact-encoding')
2
3module.exports = function bitfield (length) {
4 if (length > 64) throw new RangeError('Bitfield cannot be larger than 64 bits')
5
6 let byteLength
7 if (length < 8) byteLength = 1
8 else if (length <= 16) byteLength = 2
9 else if (length <= 32) byteLength = 4
10 else byteLength = 8
11
12 return {
13 preencode (state) {
14 state.end++ // Length byte, used for data when byteLength === 1
15
16 if (byteLength === 1) ;
17 else if (byteLength === 2) c.uint16.preencode(state)
18 else if (byteLength === 4) c.uint32.preencode(state)
19 else c.uint64.preencode(state)
20 },
21
22 encode (state, b) {
23 if (byteLength === 1) ;
24 else if (byteLength === 2) c.uint8.encode(state, 0xfd)
25 else if (byteLength === 4) c.uint8.encode(state, 0xfe)
26 else c.uint8.encode(state, 0xff)
27
28 if (typeof b === 'number') {
29 if (byteLength === 1) c.uint8.encode(state, b)
30 else if (byteLength === 2) c.uint16.encode(state, b)
31 else if (byteLength === 4) c.uint32.encode(state, b)
32 else c.uint64.encode(state, b)
33 } else {
34 state.buffer.set(b, state.start)
35
36 if (b.byteLength < byteLength) {
37 // Zero-fill the rest of the byte length.
38 state.buffer.fill(
39 0,
40 state.start + b.byteLength,
41 state.start + byteLength
42 )
43 }
44
45 state.start += byteLength
46 }
47 },
48
49 decode (state) {
50 const byte = state.buffer[state.start]
51
52 let byteLength
53 if (byte <= 0xfc) byteLength = 1
54 else if (byte === 0xfd) byteLength = 2
55 else if (byte === 0xfe) byteLength = 4
56 else byteLength = 8
57
58 if (byteLength > 1) state.start++ // Skip the length byte
59
60 if (state.end - state.start < byteLength) throw new Error('Out of bounds')
61
62 const b = state.buffer.subarray(state.start, (state.start += byteLength))
63
64 return length <= 8 ? b.subarray(0, 1) : b
65 }
66 }
67}
node_modules/compact-encoding-bitfield/package.json +34 -0
……@@ -0,0 +1,34 @@
1{
2 "name": "compact-encoding-bitfield",
3 "version": "1.0.0",
4 "description": "Compact codec for bitfields",
5 "main": "index.js",
6 "files": [
7 "index.js"
8 ],
9 "scripts": {
10 "test": "standard && brittle test.mjs"
11 },
12 "repository": {
13 "type": "git",
14 "url": "git+https://github.com/compact-encoding/compact-encoding-bitfield.git"
15 },
16 "author": "Kasper Isager Dalsgarð <kasper@funktionel.co>",
17 "license": "ISC",
18 "bugs": {
19 "url": "https://github.com/compact-encoding/compact-encoding-bitfield/issues"
20 },
21 "homepage": "https://github.com/compact-encoding/compact-encoding-bitfield#readme",
22 "dependencies": {
23 "compact-encoding": "^2.4.1"
24 },
25 "devDependencies": {
26 "brittle": "^1.3.5",
27 "standard": "^16.0.3"
28 },
29 "standard": {
30 "ignore": [
31 "__snapshots__/**"
32 ]
33 }
34}
node_modules/compact-encoding-net/.github/workflows/test-node.yml +23 -0
……@@ -0,0 +1,23 @@
1name: Build Status
2on:
3 push:
4 branches:
5 - main
6 pull_request:
7 branches:
8 - main
9jobs:
10 build:
11 strategy:
12 matrix:
13 node-version: [lts/*]
14 os: [ubuntu-latest, macos-latest, windows-latest]
15 runs-on: ${{ matrix.os }}
16 steps:
17 - uses: actions/checkout@v2
18 - name: Use Node.js ${{ matrix.node-version }}
19 uses: actions/setup-node@v2
20 with:
21 node-version: ${{ matrix.node-version }}
22 - run: npm install
23 - run: npm test
node_modules/compact-encoding-net/LICENSE +15 -0
……@@ -0,0 +1,15 @@
1ISC License
2
3Copyright (c) 2021 Contributors
4
5Permission to use, copy, modify, and/or distribute this software for any
6purpose with or without fee is hereby granted, provided that the above
7copyright notice and this permission notice appear in all copies.
8
9THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15PERFORMANCE OF THIS SOFTWARE.
node_modules/compact-encoding-net/README.md +168 -0
……@@ -0,0 +1,168 @@
1# compact-encoding-net
2
3[compact-encoding](https://github.com/compact-encoding/compact-encoding) codecs for net types.
4
5## Installation
6
7```sh
8npm install compact-encoding-net
9```
10
11## Codecs
12
13### `port`
14
15Codec for 16 bit port numbers.
16
17```js
18const { port } = require('compact-encoding-net')
19```
20
21#### Encoding
22
23```js
24const buffer = cenc.encode(port, 8080)
25```
26
27#### Decoding
28
29```js
30cenc.decode(port, buffer)
31// 8080
32```
33
34### `ipv4`
35
36Codec for IPv4 addresses.
37
38> :warning: The codec is only defined for valid IPv4 addresses.
39
40```js
41const { ipv4 } = require('compact-encoding-net')
42```
43
44#### Encoding
45
46```js
47const buffer = cenc.encode(ipv4, '127.0.0.1')
48```
49
50#### Decoding
51
52```js
53cenc.decode(ipv4, buffer)
54// '127.0.0.1'
55```
56
57### `ipv4Address`
58
59Codec for IPv4 addresses plus a port.
60
61```js
62const { ipv4Address } = require('compact-encoding-net')
63```
64
65#### Encoding
66
67```js
68const buffer = cenc.encode(ipv4, { host: '127.0.0.1', port: 8080 })
69```
70
71#### Decoding
72
73```js
74cenc.decode(ipv4Address, buffer)
75// { host: '127.0.0.1', port: 8080 }
76```
77
78### `ipv6`
79
80Codec for IPv6 addresses.
81
82> :warning: The codec is only defined for valid IPv6 addresses.
83
84```js
85const { ipv6 } = require('compact-encoding-net')
86```
87
88#### Encoding
89
90```js
91const buffer = cenc.encode(ipv6, '::1')
92```
93
94#### Decoding
95
96```js
97cenc.decode(ipv6, buffer)
98// '0:0:0:0:0:0:0:1'
99```
100
101### `ipv6Address`
102
103Codec for IPv6 addresses plus a port.
104
105```js
106const { ipv6Address } = require('compact-encoding-net')
107```
108
109#### Encoding
110
111```js
112const buffer = cenc.encode(ipv6Address, { host: '::1', port: 8080 })
113```
114
115#### Decoding
116
117```js
118cenc.decode(ipv6Address, buffer)
119// { host: '0:0:0:0:0:0:0:1', port: 8080 }
120```
121
122### `ip`
123
124Codec for dual IPv4/6 addresses.
125
126> :warning: The codec is only defined for valid IPv4 and IPv6 addresses.
127
128```js
129const { ip } = require('compact-encoding-net')
130```
131
132#### Encoding
133
134```js
135const buffer = cenc.encode(ip, '::1')
136```
137
138#### Decoding
139
140```js
141cenc.decode(ip, buffer)
142// '0:0:0:0:0:0:0:1'
143```
144
145### `ipAddress`
146
147Codec for dual IPv4/6 addresses plus a port.
148
149```js
150const { ipAddress } = require('compact-encoding-net')
151```
152
153#### Encoding
154
155```js
156const buffer = cenc.encode(ipAddress, { host: '::1', port: 8080 })
157```
158
159#### Decoding
160
161```js
162cenc.decode(ipv6Address, buffer)
163// { host: '0:0:0:0:0:0:0:1', family: 6, port: 8080 }
164```
165
166## License
167
168ISC
node_modules/compact-encoding-net/bench/ipv4.js +33 -0
……@@ -0,0 +1,33 @@
1const bench = require('nanobench')
2const c = require('compact-encoding')
3const { ipv4 } = require('../')
4
5const ip = '1.2.3.4'
6
7bench('ipv4 encode', function (b) {
8 b.start()
9
10 let result
11
12 for (let i = 0; i < 10000000; i++) {
13 result = c.encode(ipv4, ip)
14 }
15
16 b.log(result.toString('hex'))
17 b.end()
18})
19
20bench('ipv4 encode', function (b) {
21 const buffer = c.encode(ipv4, ip)
22
23 b.start()
24
25 let result
26
27 for (let i = 0; i < 10000000; i++) {
28 result = c.decode(ipv4, buffer)
29 }
30
31 b.log(JSON.stringify(result))
32 b.end()
33})
node_modules/compact-encoding-net/bench/ipv6.js +33 -0
……@@ -0,0 +1,33 @@
1const bench = require('nanobench')
2const c = require('compact-encoding')
3const { ipv6 } = require('../')
4
5const ip = '1:2:3:4:5:6:7:8'
6
7bench('ipv6 encode', function (b) {
8 b.start()
9
10 let result
11
12 for (let i = 0; i < 10000000; i++) {
13 result = c.encode(ipv6, ip)
14 }
15
16 b.log(result.toString('hex'))
17 b.end()
18})
19
20bench('ipv6 encode', function (b) {
21 const buffer = c.encode(ipv6, ip)
22
23 b.start()
24
25 let result
26
27 for (let i = 0; i < 10000000; i++) {
28 result = c.decode(ipv6, buffer)
29 }
30
31 b.log(JSON.stringify(result))
32 b.end()
33})
node_modules/compact-encoding-net/index.js +164 -0
……@@ -0,0 +1,164 @@
1const c = require('compact-encoding')
2
3const port = c.uint16
4
5const address = (host, family) => {
6 return {
7 preencode (state, m) {
8 host.preencode(state, m.host)
9 port.preencode(state, m.port)
10 },
11 encode (state, m) {
12 host.encode(state, m.host)
13 port.encode(state, m.port)
14 },
15 decode (state) {
16 return {
17 host: host.decode(state),
18 family,
19 port: port.decode(state)
20 }
21 }
22 }
23}
24
25const ipv4 = {
26 preencode (state) {
27 state.end += 4
28 },
29 encode (state, string) {
30 const start = state.start
31 const end = start + 4
32
33 let i = 0
34
35 while (i < string.length) {
36 let n = 0
37 let c
38
39 while (i < string.length && (c = string.charCodeAt(i++)) !== /* . */ 0x2e) {
40 n = n * 10 + (c - /* 0 */ 0x30)
41 }
42
43 state.buffer[state.start++] = n
44 }
45
46 state.start = end
47 },
48 decode (state) {
49 if (state.end - state.start < 4) throw new Error('Out of bounds')
50 return (
51 state.buffer[state.start++] + '.' +
52 state.buffer[state.start++] + '.' +
53 state.buffer[state.start++] + '.' +
54 state.buffer[state.start++]
55 )
56 }
57}
58
59const ipv4Address = address(ipv4, 4)
60
61const ipv6 = {
62 preencode (state) {
63 state.end += 16
64 },
65 encode (state, string) {
66 const start = state.start
67 const end = start + 16
68
69 let i = 0
70 let split = null
71
72 while (i < string.length) {
73 let n = 0
74 let c
75
76 while (i < string.length && (c = string.charCodeAt(i++)) !== /* : */ 0x3a) {
77 if (c >= 0x30 && c <= 0x39) n = n * 0x10 + (c - /* 0 */ 0x30)
78 else if (c >= 0x41 && c <= 0x46) n = n * 0x10 + (c - /* A */ 0x41 + 10)
79 else if (c >= 0x61 && c <= 0x66) n = n * 0x10 + (c - /* a */ 0x61 + 10)
80 }
81
82 state.buffer[state.start++] = n >>> 8
83 state.buffer[state.start++] = n
84
85 if (i < string.length && string.charCodeAt(i) === /* : */ 0x3a) {
86 i++
87 split = state.start
88 }
89 }
90
91 if (split !== null) {
92 const offset = end - state.start
93 state.buffer
94 .copyWithin(split + offset, split)
95 .fill(0, split, split + offset)
96 }
97
98 state.start = end
99 },
100 decode (state) {
101 if (state.end - state.start < 16) throw new Error('Out of bounds')
102 return (
103 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16) + ':' +
104 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16) + ':' +
105 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16) + ':' +
106 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16) + ':' +
107 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16) + ':' +
108 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16) + ':' +
109 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16) + ':' +
110 (state.buffer[state.start++] * 256 + state.buffer[state.start++]).toString(16)
111 )
112 }
113}
114
115const ipv6Address = address(ipv6, 6)
116
117const ip = {
118 preencode (state, string) {
119 const family = string.includes(':') ? 6 : 4
120 c.uint8.preencode(state, family)
121 if (family === 4) ipv4.preencode(state)
122 else ipv6.preencode(state)
123 },
124 encode (state, string) {
125 const family = string.includes(':') ? 6 : 4
126 c.uint8.encode(state, family)
127 if (family === 4) ipv4.encode(state, string)
128 else ipv6.encode(state, string)
129 },
130 decode (state) {
131 const family = c.uint8.decode(state)
132 if (family === 4) return ipv4.decode(state)
133 else return ipv6.decode(state)
134 }
135}
136
137const ipAddress = {
138 preencode (state, m) {
139 ip.preencode(state, m.host)
140 port.preencode(state, m.port)
141 },
142 encode (state, m) {
143 ip.encode(state, m.host)
144 port.encode(state, m.port)
145 },
146 decode (state) {
147 const family = c.uint8.decode(state)
148 return {
149 host: family === 4 ? ipv4.decode(state) : ipv6.decode(state),
150 family,
151 port: port.decode(state)
152 }
153 }
154}
155
156module.exports = {
157 port,
158 ipv4,
159 ipv4Address,
160 ipv6,
161 ipv6Address,
162 ip,
163 ipAddress
164}
node_modules/compact-encoding-net/package.json +27 -0
……@@ -0,0 +1,27 @@
1{
2 "name": "compact-encoding-net",
3 "version": "1.2.0",
4 "description": "Compact codecs for net types",
5 "main": "index.js",
6 "scripts": {
7 "test": "standard && brittle test.mjs"
8 },
9 "repository": {
10 "type": "git",
11 "url": "git+https://github.com/compact-encoding/compact-encoding-net.git"
12 },
13 "author": "Kasper Isager Dalsgarð <kasper@funktionel.co>",
14 "license": "ISC",
15 "bugs": {
16 "url": "https://github.com/compact-encoding/compact-encoding-net/issues"
17 },
18 "homepage": "https://github.com/compact-encoding/compact-encoding-net#readme",
19 "dependencies": {
20 "compact-encoding": "^2.4.1"
21 },
22 "devDependencies": {
23 "brittle": "^1.3.5",
24 "nanobench": "^2.1.1",
25 "standard": "^16.0.3"
26 }
27}
node_modules/compact-encoding-net/test.mjs +128 -0
……@@ -0,0 +1,128 @@
1import test from 'brittle'
2import c from 'compact-encoding'
3
4import { port, ipv4, ipv6, ipv4Address, ipv6Address, ip, ipAddress } from './index.js'
5
6test('port', (t) => {
7 const p = 0x1234
8 const buf = Buffer.from([0x34, 0x12])
9
10 t.alike(c.encode(port, p), buf)
11 t.alike(c.decode(port, buf), p)
12})
13
14test('ipv4', (t) => {
15 const ip = '1.2.3.4'
16 const buf = Buffer.from([1, 2, 3, 4])
17
18 t.alike(c.encode(ipv4, ip), buf)
19 t.alike(c.decode(ipv4, buf), ip)
20})
21
22test('ipv4 + port', (t) => {
23 const host = '1.2.3.4'
24 const port = 1234
25
26 t.alike(c.decode(ipv4Address, c.encode(ipv4Address, { host, port })), {
27 host,
28 family: 4,
29 port
30 })
31})
32
33test('ipv6', (t) => {
34 const ip = '1:2:3:4:5:6:7:8'
35 const buf = Buffer.from([0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8])
36
37 t.alike(c.encode(ipv6, ip), buf)
38 t.alike(c.decode(ipv6, buf), ip)
39
40 t.test('abbreviated', (t) => {
41 const buf = Buffer.from([0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 8])
42
43 t.alike(c.encode(ipv6, '1:2::7:8'), buf)
44 t.alike(c.decode(ipv6, buf), '1:2:0:0:0:0:7:8')
45 })
46
47 t.test('prefix abbreviated', (t) => {
48 const buf = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 7, 0, 8])
49
50 t.alike(c.encode(ipv6, '::5:6:7:8'), buf)
51 t.alike(c.decode(ipv6, buf), '0:0:0:0:5:6:7:8')
52 })
53
54 t.test('suffix abbreviated', (t) => {
55 const buf = Buffer.from([0, 1, 0, 2, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0])
56
57 t.alike(c.encode(ipv6, '1:2:3:4::'), buf)
58 t.alike(c.decode(ipv6, buf), '1:2:3:4:0:0:0:0')
59 })
60
61 t.test('any', (t) => {
62 const buf = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
63
64 t.alike(c.encode(ipv6, '::'), buf)
65 t.alike(c.decode(ipv6, buf), '0:0:0:0:0:0:0:0')
66 })
67
68 t.test('lowercase hex', (t) => {
69 const buf = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xab, 0xcd])
70
71 t.alike(c.encode(ipv6, '::abcd'), buf)
72 t.alike(c.decode(ipv6, buf), '0:0:0:0:0:0:0:abcd')
73 })
74
75 t.test('uppercase hex', (t) => {
76 const buf = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xab, 0xcd])
77
78 t.alike(c.encode(ipv6, '::ABCD'), buf)
79 t.alike(c.decode(ipv6, buf), '0:0:0:0:0:0:0:abcd')
80 })
81})
82
83test('ipv6 + port', (t) => {
84 const host = '1:2:3:4:5:6:7:8'
85 const port = 1234
86
87 t.alike(c.decode(ipv6Address, c.encode(ipv6Address, { host, port })), {
88 host,
89 family: 6,
90 port
91 })
92})
93
94test('dual ip', (t) => {
95 {
96 const host = '1.2.3.4'
97
98 t.alike(c.decode(ip, c.encode(ip, host)), host, 'ipv4')
99 }
100 {
101 const host = '1:2:3:4:5:6:7:8'
102
103 t.alike(c.decode(ip, c.encode(ip, host)), host, 'ipv6')
104 }
105})
106
107test('dual ip + port', (t) => {
108 const port = 1234
109
110 {
111 const host = '1.2.3.4'
112
113 t.alike(c.decode(ipAddress, c.encode(ipAddress, { host, port })), {
114 host,
115 family: 4,
116 port
117 }, 'ipv4')
118 }
119 {
120 const host = '1:2:3:4:5:6:7:8'
121
122 t.alike(c.decode(ipAddress, c.encode(ipAddress, { host, port })), {
123 host,
124 family: 6,
125 port
126 }, 'ipv6')
127 }
128})
node_modules/convert-source-map/LICENSE +23 -0
……@@ -0,0 +1,23 @@
1Copyright 2013 Thorsten Lorenz.
2All rights reserved.
3
4Permission is hereby granted, free of charge, to any person
5obtaining a copy of this software and associated documentation
6files (the "Software"), to deal in the Software without
7restriction, including without limitation the rights to use,
8copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the
10Software is furnished to do so, subject to the following
11conditions:
12
13The above copyright notice and this permission notice shall be
14included in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23OTHER DEALINGS IN THE SOFTWARE.
node_modules/convert-source-map/README.md +206 -0
……@@ -0,0 +1,206 @@
1# convert-source-map [![Build Status][ci-image]][ci-url]
2
3Converts a source-map from/to different formats and allows adding/changing properties.
4
5```js
6var convert = require('convert-source-map');
7
8var json = convert
9 .fromComment('//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQvZm9vLm1pbi5qcyIsInNvdXJjZXMiOlsic3JjL2Zvby5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSIsInNvdXJjZVJvb3QiOiIvIn0=')
10 .toJSON();
11
12var modified = convert
13 .fromComment('//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQvZm9vLm1pbi5qcyIsInNvdXJjZXMiOlsic3JjL2Zvby5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSIsInNvdXJjZVJvb3QiOiIvIn0=')
14 .setProperty('sources', [ 'SRC/FOO.JS' ])
15 .toJSON();
16
17console.log(json);
18console.log(modified);
19```
20
21```json
22{"version":3,"file":"build/foo.min.js","sources":["src/foo.js"],"names":[],"mappings":"AAAA","sourceRoot":"/"}
23{"version":3,"file":"build/foo.min.js","sources":["SRC/FOO.JS"],"names":[],"mappings":"AAAA","sourceRoot":"/"}
24```
25
26## Upgrading
27
28Prior to v2.0.0, the `fromMapFileComment` and `fromMapFileSource` functions took a String directory path and used that to resolve & read the source map file from the filesystem. However, this made the library limited to nodejs environments and broke on sources with querystrings.
29
30In v2.0.0, you now need to pass a function that does the file reading. It will receive the source filename as a String that you can resolve to a filesystem path, URL, or anything else.
31
32If you are using `convert-source-map` in nodejs and want the previous behavior, you'll use a function like such:
33
34```diff
35+ var fs = require('fs'); // Import the fs module to read a file
36+ var path = require('path'); // Import the path module to resolve a path against your directory
37- var conv = convert.fromMapFileSource(css, '../my-dir');
38+ var conv = convert.fromMapFileSource(css, function (filename) {
39+ return fs.readFileSync(path.resolve('../my-dir', filename), 'utf-8');
40+ });
41```
42
43## API
44
45### fromObject(obj)
46
47Returns source map converter from given object.
48
49### fromJSON(json)
50
51Returns source map converter from given json string.
52
53### fromURI(uri)
54
55Returns source map converter from given uri encoded json string.
56
57### fromBase64(base64)
58
59Returns source map converter from given base64 encoded json string.
60
61### fromComment(comment)
62
63Returns source map converter from given base64 or uri encoded json string prefixed with `//# sourceMappingURL=...`.
64
65### fromMapFileComment(comment, readMap)
66
67Returns source map converter from given `filename` by parsing `//# sourceMappingURL=filename`.
68
69`readMap` must be a function which receives the source map filename and returns either a String or Buffer of the source map (if read synchronously), or a `Promise` containing a String or Buffer of the source map (if read asynchronously).
70
71If `readMap` doesn't return a `Promise`, `fromMapFileComment` will return a source map converter synchronously.
72
73If `readMap` returns a `Promise`, `fromMapFileComment` will also return `Promise`. The `Promise` will be either resolved with the source map converter or rejected with an error.
74
75#### Examples
76
77**Synchronous read in Node.js:**
78
79```js
80var convert = require('convert-source-map');
81var fs = require('fs');
82
83function readMap(filename) {
84 return fs.readFileSync(filename, 'utf8');
85}
86
87var json = convert
88 .fromMapFileComment('//# sourceMappingURL=map-file-comment.css.map', readMap)
89 .toJSON();
90console.log(json);
91```
92
93
94**Asynchronous read in Node.js:**
95
96```js
97var convert = require('convert-source-map');
98var { promises: fs } = require('fs'); // Notice the `promises` import
99
100function readMap(filename) {
101 return fs.readFile(filename, 'utf8');
102}
103
104var converter = await convert.fromMapFileComment('//# sourceMappingURL=map-file-comment.css.map', readMap)
105var json = converter.toJSON();
106console.log(json);
107```
108
109**Asynchronous read in the browser:**
110
111```js
112var convert = require('convert-source-map');
113
114async function readMap(url) {
115 const res = await fetch(url);
116 return res.text();
117}
118
119const converter = await convert.fromMapFileComment('//# sourceMappingURL=map-file-comment.css.map', readMap)
120var json = converter.toJSON();
121console.log(json);
122```
123
124### fromSource(source)
125
126Finds last sourcemap comment in file and returns source map converter or returns `null` if no source map comment was found.
127
128### fromMapFileSource(source, readMap)
129
130Finds last sourcemap comment in file and returns source map converter or returns `null` if no source map comment was found.
131
132`readMap` must be a function which receives the source map filename and returns either a String or Buffer of the source map (if read synchronously), or a `Promise` containing a String or Buffer of the source map (if read asynchronously).
133
134If `readMap` doesn't return a `Promise`, `fromMapFileSource` will return a source map converter synchronously.
135
136If `readMap` returns a `Promise`, `fromMapFileSource` will also return `Promise`. The `Promise` will be either resolved with the source map converter or rejected with an error.
137
138### toObject()
139
140Returns a copy of the underlying source map.
141
142### toJSON([space])
143
144Converts source map to json string. If `space` is given (optional), this will be passed to
145[JSON.stringify](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify) when the
146JSON string is generated.
147
148### toURI()
149
150Converts source map to uri encoded json string.
151
152### toBase64()
153
154Converts source map to base64 encoded json string.
155
156### toComment([options])
157
158Converts source map to an inline comment that can be appended to the source-file.
159
160By default, the comment is formatted like: `//# sourceMappingURL=...`, which you would
161normally see in a JS source file.
162
163When `options.encoding == 'uri'`, the data will be uri encoded, otherwise they will be base64 encoded.
164
165When `options.multiline == true`, the comment is formatted like: `/*# sourceMappingURL=... */`, which you would find in a CSS source file.
166
167### addProperty(key, value)
168
169Adds given property to the source map. Throws an error if property already exists.
170
171### setProperty(key, value)
172
173Sets given property to the source map. If property doesn't exist it is added, otherwise its value is updated.
174
175### getProperty(key)
176
177Gets given property of the source map.
178
179### removeComments(src)
180
181Returns `src` with all source map comments removed
182
183### removeMapFileComments(src)
184
185Returns `src` with all source map comments pointing to map files removed.
186
187### commentRegex
188
189Provides __a fresh__ RegExp each time it is accessed. Can be used to find source map comments.
190
191Breaks down a source map comment into groups: Groups: 1: media type, 2: MIME type, 3: charset, 4: encoding, 5: data.
192
193### mapFileCommentRegex
194
195Provides __a fresh__ RegExp each time it is accessed. Can be used to find source map comments pointing to map files.
196
197### generateMapFileComment(file, [options])
198
199Returns a comment that links to an external source map via `file`.
200
201By default, the comment is formatted like: `//# sourceMappingURL=...`, which you would normally see in a JS source file.
202
203When `options.multiline == true`, the comment is formatted like: `/*# sourceMappingURL=... */`, which you would find in a CSS source file.
204
205[ci-url]: https://github.com/thlorenz/convert-source-map/actions?query=workflow:ci
206[ci-image]: https://img.shields.io/github/workflow/status/thlorenz/convert-source-map/CI?style=flat-square
node_modules/convert-source-map/index.js +233 -0
……@@ -0,0 +1,233 @@
1'use strict';
2
3Object.defineProperty(exports, 'commentRegex', {
4 get: function getCommentRegex () {
5 // Groups: 1: media type, 2: MIME type, 3: charset, 4: encoding, 5: data.
6 return /^\s*?\/[\/\*][@#]\s+?sourceMappingURL=data:(((?:application|text)\/json)(?:;charset=([^;,]+?)?)?)?(?:;(base64))?,(.*?)$/mg;
7 }
8});
9
10
11Object.defineProperty(exports, 'mapFileCommentRegex', {
12 get: function getMapFileCommentRegex () {
13 // Matches sourceMappingURL in either // or /* comment styles.
14 return /(?:\/\/[@#][ \t]+?sourceMappingURL=([^\s'"`]+?)[ \t]*?$)|(?:\/\*[@#][ \t]+sourceMappingURL=([^*]+?)[ \t]*?(?:\*\/){1}[ \t]*?$)/mg;
15 }
16});
17
18var decodeBase64;
19if (typeof Buffer !== 'undefined') {
20 if (typeof Buffer.from === 'function') {
21 decodeBase64 = decodeBase64WithBufferFrom;
22 } else {
23 decodeBase64 = decodeBase64WithNewBuffer;
24 }
25} else {
26 decodeBase64 = decodeBase64WithAtob;
27}
28
29function decodeBase64WithBufferFrom(base64) {
30 return Buffer.from(base64, 'base64').toString();
31}
32
33function decodeBase64WithNewBuffer(base64) {
34 if (typeof value === 'number') {
35 throw new TypeError('The value to decode must not be of type number.');
36 }
37 return new Buffer(base64, 'base64').toString();
38}
39
40function decodeBase64WithAtob(base64) {
41 return decodeURIComponent(escape(atob(base64)));
42}
43
44function stripComment(sm) {
45 return sm.split(',').pop();
46}
47
48function readFromFileMap(sm, read) {
49 var r = exports.mapFileCommentRegex.exec(sm);
50 // for some odd reason //# .. captures in 1 and /* .. */ in 2
51 var filename = r[1] || r[2];
52
53 try {
54 var sm = read(filename);
55 if (sm != null && typeof sm.catch === 'function') {
56 return sm.catch(throwError);
57 } else {
58 return sm;
59 }
60 } catch (e) {
61 throwError(e);
62 }
63
64 function throwError(e) {
65 throw new Error('An error occurred while trying to read the map file at ' + filename + '\n' + e.stack);
66 }
67}
68
69function Converter (sm, opts) {
70 opts = opts || {};
71
72 if (opts.hasComment) {
73 sm = stripComment(sm);
74 }
75
76 if (opts.encoding === 'base64') {
77 sm = decodeBase64(sm);
78 } else if (opts.encoding === 'uri') {
79 sm = decodeURIComponent(sm);
80 }
81
82 if (opts.isJSON || opts.encoding) {
83 sm = JSON.parse(sm);
84 }
85
86 this.sourcemap = sm;
87}
88
89Converter.prototype.toJSON = function (space) {
90 return JSON.stringify(this.sourcemap, null, space);
91};
92
93if (typeof Buffer !== 'undefined') {
94 if (typeof Buffer.from === 'function') {
95 Converter.prototype.toBase64 = encodeBase64WithBufferFrom;
96 } else {
97 Converter.prototype.toBase64 = encodeBase64WithNewBuffer;
98 }
99} else {
100 Converter.prototype.toBase64 = encodeBase64WithBtoa;
101}
102
103function encodeBase64WithBufferFrom() {
104 var json = this.toJSON();
105 return Buffer.from(json, 'utf8').toString('base64');
106}
107
108function encodeBase64WithNewBuffer() {
109 var json = this.toJSON();
110 if (typeof json === 'number') {
111 throw new TypeError('The json to encode must not be of type number.');
112 }
113 return new Buffer(json, 'utf8').toString('base64');
114}
115
116function encodeBase64WithBtoa() {
117 var json = this.toJSON();
118 return btoa(unescape(encodeURIComponent(json)));
119}
120
121Converter.prototype.toURI = function () {
122 var json = this.toJSON();
123 return encodeURIComponent(json);
124};
125
126Converter.prototype.toComment = function (options) {
127 var encoding, content, data;
128 if (options != null && options.encoding === 'uri') {
129 encoding = '';
130 content = this.toURI();
131 } else {
132 encoding = ';base64';
133 content = this.toBase64();
134 }
135 data = 'sourceMappingURL=data:application/json;charset=utf-8' + encoding + ',' + content;
136 return options != null && options.multiline ? '/*# ' + data + ' */' : '//# ' + data;
137};
138
139// returns copy instead of original
140Converter.prototype.toObject = function () {
141 return JSON.parse(this.toJSON());
142};
143
144Converter.prototype.addProperty = function (key, value) {
145 if (this.sourcemap.hasOwnProperty(key)) throw new Error('property "' + key + '" already exists on the sourcemap, use set property instead');
146 return this.setProperty(key, value);
147};
148
149Converter.prototype.setProperty = function (key, value) {
150 this.sourcemap[key] = value;
151 return this;
152};
153
154Converter.prototype.getProperty = function (key) {
155 return this.sourcemap[key];
156};
157
158exports.fromObject = function (obj) {
159 return new Converter(obj);
160};
161
162exports.fromJSON = function (json) {
163 return new Converter(json, { isJSON: true });
164};
165
166exports.fromURI = function (uri) {
167 return new Converter(uri, { encoding: 'uri' });
168};
169
170exports.fromBase64 = function (base64) {
171 return new Converter(base64, { encoding: 'base64' });
172};
173
174exports.fromComment = function (comment) {
175 var m, encoding;
176 comment = comment
177 .replace(/^\/\*/g, '//')
178 .replace(/\*\/$/g, '');
179 m = exports.commentRegex.exec(comment);
180 encoding = m && m[4] || 'uri';
181 return new Converter(comment, { encoding: encoding, hasComment: true });
182};
183
184function makeConverter(sm) {
185 return new Converter(sm, { isJSON: true });
186}
187
188exports.fromMapFileComment = function (comment, read) {
189 if (typeof read === 'string') {
190 throw new Error(
191 'String directory paths are no longer supported with `fromMapFileComment`\n' +
192 'Please review the Upgrading documentation at https://github.com/thlorenz/convert-source-map#upgrading'
193 )
194 }
195
196 var sm = readFromFileMap(comment, read);
197 if (sm != null && typeof sm.then === 'function') {
198 return sm.then(makeConverter);
199 } else {
200 return makeConverter(sm);
201 }
202};
203
204// Finds last sourcemap comment in file or returns null if none was found
205exports.fromSource = function (content) {
206 var m = content.match(exports.commentRegex);
207 return m ? exports.fromComment(m.pop()) : null;
208};
209
210// Finds last sourcemap comment in file or returns null if none was found
211exports.fromMapFileSource = function (content, read) {
212 if (typeof read === 'string') {
213 throw new Error(
214 'String directory paths are no longer supported with `fromMapFileSource`\n' +
215 'Please review the Upgrading documentation at https://github.com/thlorenz/convert-source-map#upgrading'
216 )
217 }
218 var m = content.match(exports.mapFileCommentRegex);
219 return m ? exports.fromMapFileComment(m.pop(), read) : null;
220};
221
222exports.removeComments = function (src) {
223 return src.replace(exports.commentRegex, '');
224};
225
226exports.removeMapFileComments = function (src) {
227 return src.replace(exports.mapFileCommentRegex, '');
228};
229
230exports.generateMapFileComment = function (file, options) {
231 var data = 'sourceMappingURL=' + file;
232 return options && options.multiline ? '/*# ' + data + ' */' : '//# ' + data;
233};
node_modules/convert-source-map/package.json +38 -0
……@@ -0,0 +1,38 @@
1{
2 "name": "convert-source-map",
3 "version": "2.0.0",
4 "description": "Converts a source-map from/to different formats and allows adding/changing properties.",
5 "main": "index.js",
6 "scripts": {
7 "test": "tap test/*.js --color"
8 },
9 "repository": {
10 "type": "git",
11 "url": "git://github.com/thlorenz/convert-source-map.git"
12 },
13 "homepage": "https://github.com/thlorenz/convert-source-map",
14 "devDependencies": {
15 "inline-source-map": "~0.6.2",
16 "tap": "~9.0.0"
17 },
18 "keywords": [
19 "convert",
20 "sourcemap",
21 "source",
22 "map",
23 "browser",
24 "debug"
25 ],
26 "author": {
27 "name": "Thorsten Lorenz",
28 "email": "thlorenz@gmx.de",
29 "url": "http://thlorenz.com"
30 },
31 "license": "MIT",
32 "engine": {
33 "node": ">=4"
34 },
35 "files": [
36 "index.js"
37 ]
38}
node_modules/dht-rpc/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2021 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/dht-rpc/README.md +384 -0
……@@ -0,0 +1,384 @@
1# dht-rpc
2
3Make RPC calls over a [Kademlia](https://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf) based DHT.
4
5```
6npm install dht-rpc
7```
8
9## Key Features
10
11- Remote IP / firewall detection
12- Easily add any command to your DHT
13- Streaming queries and updates
14
15Note that internally V5 of dht-rpc differs significantly from V4, due to a series
16of improvements to NAT detection, secure routing IDs and more.
17
18## Usage
19
20Here is an example implementing a simple key value store
21
22First spin up a bootstrap node. You can make multiple if you want for redundancy.
23There is nothing special about a bootstrap node, except it needs to know it's own host and port,
24since it knows no other nodes to infer it from.
25
26```js
27import DHT from 'dht-rpc'
28
29const bootstrap = DHT.bootstrapper(10001, '127.0.0.1')
30```
31
32Now lets make some dht nodes that can store values in our key value store.
33
34```js
35import DHT from 'dht-rpc'
36import crypto from 'crypto'
37
38// Let's create 100 dht nodes for our example.
39for (var i = 0; i < 100; i++) createNode()
40
41function createNode() {
42 const node = new DHT({
43 bootstrap: ['localhost:10001']
44 })
45
46 const values = new Map()
47 const VALUES = 0 // define a command enum
48
49 node.on('request', function (req) {
50 if (req.command === VALUES) {
51 if (req.token) {
52 // if we are the closest node store the value (ie the node sent a valid roundtrip token)
53 const key = hash(req.value).toString('hex')
54 values.set(key, req.value)
55 console.log('Storing', key, '-->', req.value.toString())
56 return req.reply(null)
57 }
58
59 const value = values.get(req.target.toString('hex'))
60 req.reply(value)
61 }
62 })
63}
64
65function hash(value) {
66 return crypto.createHash('sha256').update(value).digest()
67}
68```
69
70To insert a value into this dht make another script that does this following
71
72```js
73const node = new DHT()
74
75const q = node.query(
76 {
77 target: hash(val),
78 command: VALUES,
79 value
80 },
81 {
82 // commit true will make the query re-request the 20 closest
83 // nodes with a valid round trip token to update the values
84 commit: true
85 }
86)
87
88await q.finished()
89```
90
91Then after inserting run this script to query for a value
92
93```js
94const target = Buffer.from(hexFromAbove, 'hex')
95for await (const data of node.query({ target, command: VALUES })) {
96 if (data.value && hash(data.value).toString('hex') === hexFromAbove) {
97 // We found the value! Destroy the query stream as there is no need to continue.
98 console.log(val, '-->', data.value.toString())
99 break
100 }
101}
102console.log('(query finished)')
103```
104
105## API
106
107#### `const node = new DHT([options])`
108
109Create a new DHT node.
110
111Options include:
112
113```js
114{
115 // A list of bootstrap nodes. Optionally prefix a suggested-IP, i.e. '192.168.1.10@bootstrap-node.com:24242'
116 bootstrap: [ 'bootstrap-node.com:24242', ... ],
117 // Optionally pass in array of { host, port } to add to the routing table if you know any peers
118 nodes: [{ host, port }, ...],
119 // Optionally pass a port you prefer to bind to instead of a random one, or a range of ports it will try to bind to in order: [startPort, endPort], endPort exclusive
120 port: 0,
121 // Optionally pass a host you prefer to bind to instead of all networks
122 host: '0.0.0.0',
123 // Optionally pass a UDX instance on which sockets will be created.
124 udx,
125 // dht-rpc will automatically detect if you are firewalled. If you know that you are not set this to false
126 firewalled: true,
127 // dht-rpc will hint when a node is down if a request times out. Setting to false disables sending hints
128 sendDownHints: true,
129 // How many down hints can be sent per tick. -1 is unlimited
130 downHintsRateLimit: 50
131}
132```
133
134Nodes per default use something called adaptive mode to decide whether or not they want to join other nodes' routing table.
135This includes things like node uptime, if the node is firewalled etc. Adaptive mode is conservative, so it might take ~20-30 mins for the node to turn persistent. If you are making a test case with your own bootstrap network you'd usually want to turn this off to make sure your test finishes in a timely manner. You can do this by passing `ephemeral: false` in the constructor.
136For the vast majority of use-cases you should always use adaptive mode to ensure good DHT health, ie the defaults.
137
138Your DHT routing id is `hash(publicIp + publicPort)` and will be autoconfigured internally.
139
140#### `const node = DHT.bootstrapper(port, host, [options])`
141
142Make a bootstrap node for your DHT. The port and host needs to be its globally accessible port and host.
143Note: `port` and `host` parameters are used to create the node id. Use `options.host` if you want to bind to i.e. 127.0.0.1.
144DHT nodes can use any other DHT node to bootstrap, but a bootstrap node can bootstrap itself, by itself.
145
146#### `await node.fullyBootstrapped()`
147
148Wait for the node to be fully bootstrapped etc.
149You don't have to wait for this method, but can be useful during testing.
150
151#### `node.id`
152
153Get your own routing ID. Only available when the node is not ephemeral.
154
155#### `node.ephemeral`
156
157A boolean indicating if you are currently ephemeral or not
158
159#### `node.on('bootstrap')`
160
161Emitted when the routing table is fully bootstrapped. Emitted as a conveinience.
162
163#### `node.on('listening')`
164
165Emitted when the underlying UDX socket is listening. Emitted as a conveinience.
166
167#### `node.on('ready')`
168
169Emitted when the node is fully bootstrapped etc.
170
171#### `node.on('persistent')`
172
173Emitted when the node is no longer in ephemeral mode.
174All nodes start in ephemeral mode, as they figure out their NAT settings.
175If you set `ephemeral: false` then this is emitted during the bootstrap phase, assuming
176you are on an open NAT.
177
178#### `node.on('wake-up')`
179
180Emitted when the node has detected that the computer has gone to sleep. If this happens,
181it will switch from persistent mode to ephemeral again.
182
183#### `node.on('network-change', interfaces)`
184
185Emitted when the network interfaces of the computer change.
186
187#### `node.on('nat-update', (host, port) => {})`
188
189Emitted when `node.host` or `node.port` were changed.
190
191#### `node.on('close')`
192
193Will be emitted after `node.destroy()` is completed.
194
195#### `node.refresh()`
196
197Refresh the routing table by looking up a random node in the background.
198This is called internally periodically, but exposed in-case you want to force a refresh.
199
200#### `node.host`
201
202Get your node's public ip, inferred from other nodes in the DHT.
203If the ip cannot be determined, this is set to `null`.
204
205#### `node.port`
206
207Get your node's public port, inferred from other nodes in the DHT.
208If your node does not have a consistent port, this is set to 0.
209
210#### `node.firewalled`
211
212Boolean indicated if your node is behind a firewall.
213
214This is auto detected by having other nodes trying to do a PING to you
215without you contacting them first.
216
217#### `node.randomized`
218
219Boolean indicating if your node is likely behind a randomizing NAT.
220
221#### `const addr = node.address()`
222
223Get the local address of the UDP socket bound.
224
225Note that if you are in ephemeral mode, this will return a different
226port than the one you provided in the constructor (under `port`), as ephemeral
227mode always uses a random port.
228
229#### `node.on('request', req)`
230
231Emitted when an incoming DHT request is received. This is where you can add your own RPC methods.
232
233- `req.target` - the dht target the peer is looking (routing is handled behind the scene)
234- `req.command` - the RPC command enum
235- `req.value` - the RPC value buffer
236- `req.token` - If the remote peer echoed back a valid roundtrip token, proving their "from address" this is set
237- `req.from` - who sent this request (host, port)
238
239To reply to a request use the `req.reply(value)` method and to reply with an error code use `req.error(errorCode)`.
240
241In general error codes are up to the user to define, with the general suggestion to start application specific errors
242from error code `16` and up, to avoid future clashes with `dht-rpc` internals.
243
244Currently dht-rpc defines the following errors
245
246```js
247DHT.OK = 0 // ie no error
248DHT.ERROR_UNKNOWN_COMMAND = 1 // the command requested does not exist
249DHT.ERROR_INVALID_TOKEN = 2 // the round trip token sent is invalid
250```
251
252#### `reply = await node.request({ token, target, command, value }, to, [options])`
253
254Send a request to a specific node specified by the `to` address (`{ host, port }`).
255See the query API for more info on the arguments.
256
257Options include:
258
259```js
260{
261 retry: true, // whether the request should retry on timeout
262 socket: udxSocket // request on this specific socket
263}
264```
265
266Normally you'd set the token when committing to the dht in the query's commit hook.
267
268#### `reply = await node.ping(to, [options])`
269
270Ping a remote node described by `to`. The return promise resolves if the remote node replies. `to` is an object with the shape `{ host, port }`.
271
272Additional options include:
273
274```js
275{
276 size: 0, // size of the value buffer, filled with zeroes
277 ttl: 0 // Set the ttl for the packet sent. `0` is the default ttl.
278}
279```
280
281#### `reply = await node.delayedPing(to, delayMs, [options])`
282
283Send a ping that intentionally waits before replying. Useful for testing latency/timeout behavior and scheduling a delayed response.
284
285- `to` - `{ host, port }` of the target peer
286- `delayMs` - integer milliseconds to delay the reply (0–10_000). Values above 10_000 ms are rejected and no reply is sent (the request will time out).
287- `options` - same options as `node.request()`:
288
289Example:
290
291```js
292const start = Date.now()
293await node.delayedPing({ host: peer.host, port: peer.port }, 1000)
294console.log('elapsed >=', Date.now() - start, 'ms') // ~1s + network overhead
295```
296
297#### `stream = node.query({ target, command, value }, [options])`
298
299Query the DHT. Will move as close as possible to the `target` provided, which should be a 32-byte uniformly distributed buffer (ie a hash).
300
301- `target` - find nodes close to this (should be a 32 byte buffer like a hash)
302- `command` - an enum (uint) indicating the method you want to invoke
303- `value` - optional binary payload to send with it
304
305If you want to modify state stored in the dht, you can use the commit flag to signal the closest
306nodes.
307
308```js
309{
310 // "commit" the query to the 20 closest nodes so they can modify/update their state
311 commit: true
312}
313```
314
315Commiting a query will just re-request your command to the closest nodes once those are verified.
316If you want to do some more specific logic with the closest nodes you can specify a function instead,
317that is called for each close reply.
318
319```js
320{
321 async commit (reply, dht, query) {
322 // normally you'd send back the roundtrip token here, to prove to the remote that you own
323 // your ip/port
324 await dht.request({ token: reply.token, target, command, value }, reply.from)
325 }
326}
327```
328
329Other options include:
330
331```js
332{
333 nodes: [
334 // start the query by querying these nodes
335 // useful if you are re-doing a query from a set of closest nodes.
336 ],
337 replies: [
338 // similar to nodes, but useful if you have an array of closest replies instead
339 // from a previous query.
340 ],
341 map (reply) {
342 // map the reply into what you want returned on the stream
343 return { onlyValue: reply.value }
344 }
345}
346```
347
348The query method returns a stream encapsulating the query, that is also an async iterator. Each `data` event contain a DHT reply.
349If you just want to wait for the query to finish, you can use the `await stream.finished()` helper. After completion the closest
350nodes are stored in `stream.closestNodes` array.
351
352If you want to access the closest replies to your provided target you can see those at `stream.closestReplies`.
353
354#### `stream = node.findNode(target, [options])`
355
356Find the node closest to the node with id `target`. Returns a stream encapsulating the query (see `node.query()`). `options` are the same as `node.query()`.
357
358#### `node.destroy()`
359
360Shutdown the DHT node.
361
362#### `node.destroyed`
363
364Boolean indicating if this has been destroyed.
365
366#### `node.toArray([options])`
367
368Get the routing table peers out as an array of `{ host, port }`. Use `options.limit` to get a subset.
369
370#### `node.addNode({ host, port })`
371
372Manually add a node to the routing table.
373
374#### `await node.suspend()`
375
376Tell the DHT you are going to background (ie suspend and allow it to make preperations for that)
377
378#### `await node.resume()`
379
380Tell the DHT you are resuming from suspension.
381
382## License
383
384MIT
node_modules/dht-rpc/index.js +1081 -0
……@@ -0,0 +1,1081 @@
1const { EventEmitter } = require('events')
2const Table = require('kademlia-routing-table')
3const TOS = require('time-ordered-set')
4const UDX = require('udx-native')
5const sodium = require('sodium-universal')
6const c = require('compact-encoding')
7const NatSampler = require('nat-sampler')
8const b4a = require('b4a')
9const NetworkHealth = require('./lib/health')
10const IO = require('./lib/io')
11const Query = require('./lib/query')
12const Session = require('./lib/session')
13const peer = require('./lib/peer')
14const { UNKNOWN_COMMAND, INVALID_TOKEN } = require('./lib/errors')
15const { PING, PING_NAT, FIND_NODE, DOWN_HINT, DELAYED_PING } = require('./lib/commands')
16
17const TMP = b4a.allocUnsafe(32)
18const TICK_INTERVAL = 5000
19const SLEEPING_INTERVAL = 3 * TICK_INTERVAL
20const STABLE_TICKS = 240 // if nothing major bad happens in ~20mins we can consider this node stable (if nat is friendly)
21const MORE_STABLE_TICKS = 3 * STABLE_TICKS
22const REFRESH_TICKS = 60 // refresh every ~5min when idle
23const RECENT_NODE = 12 // we've heard from a node less than 1min ago
24const OLD_NODE = 360 // if an node has been around more than 30 min we consider it old
25
26const DEFAULTS = {
27 concurrency: 10,
28 maxWindow: IO.DEFAULT_MAX_WINDOW,
29 maxPingDelay: 10_000
30}
31
32class DHT extends EventEmitter {
33 constructor(opts = {}) {
34 super()
35
36 this.bootstrapNodes = opts.bootstrap === false ? [] : (opts.bootstrap || []).map(parseNode)
37 this.table = new Table(randomBytes(32))
38 this.nodes = new TOS()
39 this.udx = opts.udx || new UDX()
40 this.io = new IO(this.table, this.udx, {
41 ...opts,
42 onrequest: this._onrequest.bind(this),
43 onresponse: this._onresponse.bind(this),
44 ontimeout: this._ontimeout.bind(this)
45 })
46 this.health = new NetworkHealth(this)
47
48 this.concurrency = opts.concurrency || DEFAULTS.concurrency
49 this.maxPingDelay = opts.maxPingDelay || DEFAULTS.maxPingDelay
50 this.bootstrapped = false
51 this.ephemeral = true
52 this.firewalled = this.io.firewalled
53 this.adaptive = typeof opts.ephemeral !== 'boolean' && opts.adaptive !== false
54 this.destroyed = false
55 this.suspended = false
56 this.online = true
57 this.degraded = false
58 this.stats = {
59 queries: { active: 0, total: 0 },
60 requests: this.io.stats.requests,
61 commands: {
62 ping: this.io.stats.commands[PING],
63 pingNat: this.io.stats.commands[PING_NAT],
64 findNode: this.io.stats.commands[FIND_NODE],
65 downHint: this.io.stats.commands[DOWN_HINT]
66 }
67 }
68
69 this._nat = new NatSampler()
70 this._quickFirewall = opts.quickFirewall !== false
71 this._forcePersistent = opts.ephemeral === false
72 this._repinging = 0
73 this._checks = 0
74 this._tick = randomOffset(100) // make sure to random offset all the network ticks
75 this._refreshTicks = randomOffset(REFRESH_TICKS)
76 this._stableTicks = this.adaptive ? STABLE_TICKS : 0
77 this._tickInterval = setInterval(this._ontick.bind(this), TICK_INTERVAL)
78 this._lastTick = Date.now()
79 this._lastHost = null
80 this._filterNode = opts.filterNode || opts.addNode || null // opts.addNode is deprecating, use opts.filterNode instead
81 this._onrow = (row) => row.on('full', (node) => this._onfullrow(node, row))
82 this._nonePersistentSamples = []
83 this._bootstrapping = this._bootstrap()
84 this._bootstrapping.catch(noop)
85 this._sendDownHints = opts.sendDownHints !== false
86 this._downHintsRateLimit =
87 opts.downHintsRateLimit !== undefined ? opts.downHintsRateLimit : 10 * 5
88 this._downHintsSentPerTick = 0
89 this._pendingTimers = new Set()
90
91 this.table.on('row', this._onrow)
92
93 this.io.networkInterfaces.on('change', (interfaces) => this._onnetworkchange(interfaces))
94
95 if (opts.nodes) {
96 for (let i = opts.nodes.length - 1; i >= 0; i--) {
97 this.addNode(opts.nodes[i])
98 }
99 }
100 }
101
102 static DEFAULTS = DEFAULTS
103
104 static bootstrapper(port, host, opts) {
105 if (!port) throw new Error('Port is required')
106 if (!host) throw new Error('Host is required')
107 if (host === '0.0.0.0' || host === '::') throw new Error('Invalid host')
108 if (!UDX.isIPv4(host)) throw new Error('Host must be a IPv4 address')
109
110 const dht = new this({
111 port,
112 ephemeral: false,
113 firewalled: false,
114 anyPort: false,
115 bootstrap: [],
116 ...opts
117 })
118 dht._nat.add(host, port)
119 return dht
120 }
121
122 get id() {
123 return this.ephemeral ? null : this.table.id
124 }
125
126 get host() {
127 return this._nat.host
128 }
129
130 get port() {
131 return this._nat.port
132 }
133
134 get randomized() {
135 return this._nat.host !== null && this._nat.port === 0
136 }
137
138 get socket() {
139 return this.firewalled ? this.io.clientSocket : this.io.serverSocket
140 }
141
142 get config() {
143 return {
144 concurrency: this.concurrency,
145 maxWindow: this.io.congestion._maxWindow,
146 randomPunchInterval: this._randomPunchInterval,
147 connectionKeepAlive: this.connectionKeepAlive,
148 sendDownHints: this._sendDownHints,
149 downHintsRateLimit: this._downHintsRateLimit
150 }
151 }
152
153 onmessage(socket, buf, rinfo) {
154 if (buf.byteLength > 1) this.io.onmessage(socket, buf, rinfo)
155 }
156
157 bind() {
158 return this.io.bind()
159 }
160
161 async suspend({ log = noop } = {}) {
162 log('Suspending waiting for io bind...')
163 await this.io.bind()
164 log('Done, continuing')
165 if (this.suspended || this.destroyed) return
166 this.suspended = true
167 clearInterval(this._tickInterval)
168 log('Done, suspending io')
169 await this.io.suspend({ log })
170 log('Done, dht suspended')
171 this.emit('suspend')
172 }
173
174 async resume({ log = noop } = {}) {
175 if (!this.suspended || this.destroyed) return
176 this.suspended = false
177 this._tickInterval = setInterval(this._ontick.bind(this), TICK_INTERVAL)
178 this._onwakeup()
179 log('Resuming io')
180 await this.io.resume()
181 log('Done, dht resumed')
182 this.io.networkInterfaces.on('change', (interfaces) => this._onnetworkchange(interfaces))
183 this.refresh()
184 this.emit('resume')
185 }
186
187 address() {
188 const socket = this.socket
189 return socket ? socket.address() : null
190 }
191
192 localAddress() {
193 if (!this.io.serverSocket) return null
194
195 return {
196 host: localIP(this.udx),
197 port: this.io.serverSocket.address().port
198 }
199 }
200
201 remoteAddress() {
202 if (!this.host) return null
203 if (!this.port) return null
204 if (this.firewalled) return null
205 if (!this.io.serverSocket) return null
206
207 const port = this.io.serverSocket.address().port
208 if (port !== this.port) return null
209
210 return {
211 host: this.host,
212 port
213 }
214 }
215
216 addNode({ host, port }) {
217 this._addNode({
218 id: peer.id(host, port),
219 port,
220 host,
221 token: null,
222 to: null,
223 sampled: 0,
224 added: this._tick,
225 pinged: 0,
226 seen: 0,
227 downHints: 0,
228 prev: null,
229 next: null
230 })
231 }
232
233 toArray(opts) {
234 const limit = opts && opts.limit
235 if (limit === 0) return []
236 return this.nodes.toArray({ limit, reverse: true }).map(({ host, port }) => ({ host, port }))
237 }
238
239 async fullyBootstrapped() {
240 return this._bootstrapping
241 }
242
243 ready() {
244 // Deprecating, use fullyBootstrapped instead (removed on next major)
245 return this.fullyBootstrapped()
246 }
247
248 findNode(target, opts) {
249 if (this.destroyed) throw new Error('Node destroyed')
250 this._refreshTicks = REFRESH_TICKS
251 return new Query(this, target, true, FIND_NODE, null, opts)
252 }
253
254 query({ target, command, value }, opts) {
255 if (this.destroyed) throw new Error('Node destroyed')
256 this._refreshTicks = REFRESH_TICKS
257 return new Query(this, target, false, command, value || null, opts)
258 }
259
260 ping({ host, port }, opts) {
261 let value = null
262
263 if (opts && opts.size && opts.size > 0) value = b4a.alloc(opts.size)
264
265 const req = this.io.createRequest(
266 { id: null, host, port },
267 null,
268 true,
269 PING,
270 null,
271 value,
272 (opts && opts.session) || null,
273 opts && opts.ttl
274 )
275 return this._requestToPromise(req, opts)
276 }
277
278 delayedPing({ host, port }, delayMs, opts) {
279 if (delayMs > this.maxPingDelay) {
280 throw new Error(`Delay exceeds max delay: ${this.maxPingDelay}ms`)
281 }
282
283 const value = b4a.allocUnsafe(4)
284 c.uint32.encode({ start: 0, end: 4, buffer: value }, delayMs)
285
286 const req = this.io.createRequest(
287 { id: null, host, port },
288 null,
289 true,
290 DELAYED_PING,
291 null,
292 value,
293 (opts && opts.session) || null,
294 opts && opts.ttl
295 )
296 // add 1 second to the timeout to account for network overhead
297 req.timeout = delayMs + 1_000
298 return this._requestToPromise(req, opts)
299 }
300
301 async rttStats() {
302 const stats = {
303 successes: 0,
304 errors: 0,
305 responses: {
306 avgRtt: 0,
307 errors: 0,
308 avgCloserNodes: 0
309 },
310 closestReplies: {
311 avgRtt: 0,
312 errors: 0,
313 avgCloserNodes: 0
314 }
315 }
316
317 if (this.nodes.latest) {
318 const q = this.findNode(this.nodes.latest.id)
319
320 let responseCount = 0
321 let closestCount = 0
322
323 for await (const msg of q) {
324 stats.responses.avgRtt += msg.rtt
325 stats.responses.errors += msg.error
326 stats.responses.avgCloserNodes += msg.closerNodes?.length || 0
327 responseCount++
328 }
329 stats.responses.avgRtt /= responseCount
330 stats.responses.avgCloserNodes /= responseCount
331
332 for await (const msg of q.closestReplies) {
333 stats.closestReplies.avgRtt += msg.rtt
334 stats.closestReplies.errors += msg.error
335 stats.closestReplies.avgCloserNodes += msg.closerNodes?.length || 0
336 closestCount++
337 }
338 stats.closestReplies.avgRtt /= closestCount
339 stats.closestReplies.avgCloserNodes /= closestCount
340
341 stats.successes = q.successes
342 stats.errors = q.errors
343 }
344
345 return stats
346 }
347
348 request({ token = null, command, target = null, value = null }, { host, port }, opts) {
349 const req = this.io.createRequest(
350 { id: null, host, port },
351 token,
352 false,
353 command,
354 target,
355 value,
356 (opts && opts.session) || null,
357 opts && opts.ttl
358 )
359 return this._requestToPromise(req, opts)
360 }
361
362 session() {
363 return new Session(this)
364 }
365
366 _requestToPromise(req, opts) {
367 if (req === null) return Promise.reject(new Error('Node destroyed'))
368
369 if (opts && opts.socket) req.socket = opts.socket
370 if (opts && opts.retry === false) req.retries = 0
371
372 return new Promise((resolve, reject) => {
373 req.onresponse = resolve
374 req.onerror = reject
375 req.send()
376 })
377 }
378
379 async _bootstrap() {
380 const self = this
381
382 await Promise.resolve() // wait a tick, so apis can be used from the outside
383 await this.io.bind()
384
385 this.emit('listening')
386
387 // TODO: some papers describe more advanced ways of bootstrapping - we should prob look into that
388
389 let first = this.firewalled && this._quickFirewall && !this._forcePersistent
390 let testNat = false
391
392 const onlyFirewall = !this._forcePersistent
393
394 for (let i = 0; i < 2; i++) {
395 await this._backgroundQuery(this.table.id).on('data', ondata).finished()
396
397 if (this.bootstrapped || (!testNat && !this._forcePersistent)) break
398 if (!(await this._updateNetworkState(onlyFirewall))) break
399 }
400
401 if (this.bootstrapped) return
402 this.bootstrapped = true
403
404 this.emit('ready')
405
406 function ondata(data) {
407 // Simple QUICK nat heuristic.
408 // If we get ONE positive nat ping before the bootstrap query finishes
409 // then we always to a nat test, no matter if we are adaptive...
410 // This should be expanded in the future to try more than one node etc, not always hit the first etc
411 // If this fails, then nbd, as the onstable hook will pick it up later.
412
413 if (!first) return
414 first = false
415
416 const value = b4a.allocUnsafe(2)
417 c.uint16.encode({ start: 0, end: 2, buffer: value }, self.io.serverSocket.address().port)
418
419 self._request(
420 data.from,
421 false,
422 true,
423 PING_NAT,
424 null,
425 value,
426 null,
427 () => {
428 testNat = true
429 },
430 noop
431 )
432 }
433 }
434
435 refresh() {
436 const node = this.table.random()
437 this._backgroundQuery(node ? node.id : this.table.id).on('error', noop)
438 }
439
440 async destroy() {
441 const emitClose = !this.destroyed
442 this.destroyed = true
443 clearInterval(this._tickInterval)
444 for (const timer of this._pendingTimers) {
445 clearTimeout(timer)
446 }
447 await this.io.destroy()
448 if (emitClose) this.emit('close')
449 }
450
451 _request(to, force, internal, command, target, value, session, onresponse, onerror) {
452 if (internal && !this._sendDownHints && command === DOWN_HINT) return null
453 const req = this.io.createRequest(to, null, internal, command, target, value, session)
454 if (req === null) return null
455
456 req.onresponse = onresponse
457 req.onerror = onerror
458 req.send(force)
459
460 return req
461 }
462
463 _natAdd(host, port) {
464 const prevHost = this._nat.host
465 const prevPort = this._nat.port
466
467 this._nat.add(host, port)
468
469 if (prevHost === this._nat.host && prevPort === this._nat.port) return
470
471 this.emit('nat-update', this._nat.host, this._nat.port)
472 }
473
474 // we don't check that this is a bootstrap node but we limit the sample size to very few nodes, so fine
475 _sampleBootstrapMaybe(from, to) {
476 if (this._nonePersistentSamples.length >= Math.max(1, this.bootstrapNodes.length)) return
477 const id = from.host + ':' + from.port
478 if (this._nonePersistentSamples.indexOf(id) > -1) return
479 this._nonePersistentSamples.push(id)
480 this._natAdd(to.host, to.port)
481 }
482
483 _addNodeFromNetwork(sample, from, to) {
484 if (this._filterNode !== null && !this._filterNode(from)) {
485 return
486 }
487
488 if (from.id === null) {
489 this._sampleBootstrapMaybe(from, to)
490 return
491 }
492
493 const oldNode = this.table.get(from.id)
494
495 // refresh it, if we've seen this before
496 if (oldNode) {
497 if (sample && (oldNode.sampled === 0 || this._tick - oldNode.sampled >= OLD_NODE)) {
498 oldNode.to = to
499 oldNode.sampled = this._tick
500 this._natAdd(to.host, to.port)
501 }
502
503 oldNode.pinged = oldNode.seen = this._tick
504 this.nodes.add(oldNode)
505 return
506 }
507
508 this._addNode({
509 id: from.id,
510 port: from.port,
511 host: from.host,
512 to,
513 sampled: 0,
514 added: this._tick,
515 pinged: this._tick, // last time we interacted with them
516 seen: this._tick, // last time we heard from them
517 downHints: 0,
518 prev: null,
519 next: null
520 })
521 }
522
523 _addNode(node) {
524 if (this.nodes.has(node) || b4a.equals(node.id, this.table.id)) return
525
526 node.added = node.pinged = node.seen = this._tick
527
528 if (!this.table.add(node)) return
529 this.nodes.add(node)
530
531 if (node.to && node.sampled === 0) {
532 node.sampled = this._tick
533 this._natAdd(node.to.host, node.to.port)
534 }
535
536 this.emit('add-node', node)
537 }
538
539 _removeStaleNode(node, lastSeen) {
540 if (node.seen <= lastSeen) this._removeNode(node)
541 }
542
543 _removeNode(node) {
544 if (!this.nodes.has(node)) return
545
546 this.table.remove(node.id)
547 this.nodes.remove(node)
548
549 this.emit('remove-node', node)
550 }
551
552 _onwakeup() {
553 this._tick += 2 * OLD_NODE // bump the tick enough that everything appears old.
554 this._tick += 8 - (this._tick & 7) - 2 // triggers a series of pings in two ticks
555 this._stableTicks = MORE_STABLE_TICKS
556 this._refreshTicks = 1 // triggers a refresh next tick (allow network time to wake up also)
557 this._lastHost = null // clear network cache check
558 this.health.reset()
559
560 if (this.adaptive) {
561 // TODO: re-enable this as soon as we find out why this is over triggering in some edge cases
562 // this.firewalled = true
563 // this.io.firewalled = true
564
565 if (!this.ephemeral) {
566 this.ephemeral = true
567 this.io.ephemeral = true
568 this.emit('ephemeral')
569 }
570 }
571
572 this.emit('wakeup')
573 }
574
575 _onfullrow(newNode, row) {
576 if (!this.bootstrapped || this._repinging >= 3) return
577
578 let oldest = null
579 for (const node of row.nodes) {
580 if (node.pinged === this._tick) continue
581 if (
582 oldest === null ||
583 oldest.pinged > node.pinged ||
584 (oldest.pinged === node.pinged && oldest.added > node.added)
585 ) {
586 oldest = node
587 }
588 }
589
590 if (oldest === null) return
591 if (this._tick - oldest.pinged < RECENT_NODE && this._tick - oldest.added > OLD_NODE) return
592
593 this._repingAndSwap(newNode, oldest)
594 }
595
596 _onnetworkchange(interfaces) {
597 this.emit('network-change', interfaces)
598 this.emit('network-update')
599 }
600
601 _repingAndSwap(newNode, oldNode) {
602 const self = this
603 const lastSeen = oldNode.seen
604
605 oldNode.pinged = this._tick
606
607 this._repinging++
608 this._request(
609 { id: null, host: oldNode.host, port: oldNode.port },
610 false,
611 true,
612 PING,
613 null,
614 null,
615 null,
616 onsuccess,
617 onswap
618 )
619
620 function onsuccess(m) {
621 if (oldNode.seen <= lastSeen) return onswap()
622 self._repinging--
623 }
624
625 function onswap(e) {
626 self._repinging--
627 self._removeNode(oldNode)
628 self._addNode(newNode)
629 }
630 }
631
632 _onrequest(req, external) {
633 if (req.from.id !== null) {
634 this._addNodeFromNetwork(!external, req.from, req.to)
635 }
636
637 if (req.internal) {
638 switch (req.command) {
639 // standard keep alive call
640 case PING: {
641 req.sendReply(0, null, false, false)
642 return
643 }
644 case DELAYED_PING: {
645 this._ondelayedping(req)
646 return
647 }
648 // check if the other side can receive a message to their other socket
649 case PING_NAT: {
650 if (req.value === null || req.value.byteLength < 2) return
651 const port = c.uint16.decode({ start: 0, end: 2, buffer: req.value })
652 if (port === 0) return
653 req.from.port = port
654 req.sendReply(0, null, false, false)
655 return
656 }
657 // empty dht reply back
658 case FIND_NODE: {
659 if (!req.target) return
660 req.sendReply(0, null, false, true)
661 return
662 }
663 // "this is node you sent me is down" - let's try to ping it
664 case DOWN_HINT: {
665 if (req.value === null || req.value.byteLength < 6) return
666 if (this._checks < 10) {
667 sodium.crypto_generichash(TMP, req.value.subarray(0, 6))
668 const node = this.table.get(TMP)
669 if (node && (node.pinged < this._tick || node.downHints === 0)) {
670 node.downHints++
671 this._check(node)
672 }
673 }
674 req.sendReply(0, null, false, false)
675 return
676 }
677 }
678
679 req.sendReply(UNKNOWN_COMMAND, null, false, req.target !== null)
680 return
681 }
682
683 // ask the user to handle it or reply back with a bad command
684 if (this.onrequest(req) === false) {
685 req.sendReply(UNKNOWN_COMMAND, null, false, req.target !== null)
686 }
687 }
688
689 onrequest(req) {
690 return this.emit('request', req)
691 }
692
693 _ondelayedping(req) {
694 if (req.value === null || req.value.byteLength < 4) return
695 const delayMs = c.uint32.decode({ start: 0, end: 4, buffer: req.value })
696 if (delayMs > this.maxPingDelay) return
697 const timer = setTimeout(() => {
698 if (this.destroyed) return
699 this._pendingTimers.delete(timer)
700 req.sendReply(0, null, false, false)
701 }, delayMs)
702 this._pendingTimers.add(timer)
703 }
704
705 _onresponse(res, external) {
706 this._addNodeFromNetwork(!external, res.from, res.to)
707 }
708
709 _ontimeout(req) {
710 if (!req.to.id) return
711 const node = this.table.get(req.to.id)
712 if (node) this._removeNode(node)
713 }
714
715 _pingSome() {
716 let cnt = this.io.inflight.length > 2 ? 3 : 5
717 let oldest = this.nodes.oldest
718
719 // tiny dht, pinged the bootstrap again
720 if (!oldest) {
721 this.refresh()
722 return
723 }
724
725 // we've recently pinged the oldest one, so only trigger a couple of repings
726 if (this._tick - oldest.pinged < RECENT_NODE) {
727 cnt = 2
728 }
729
730 while (cnt--) {
731 if (!oldest || this._tick === oldest.pinged) continue
732 this._check(oldest)
733 oldest = oldest.next
734 }
735 }
736
737 _check(node) {
738 node.pinged = this._tick
739
740 const lastSeen = node.seen
741 const onresponse = () => {
742 this._checks--
743 this._removeStaleNode(node, lastSeen)
744 }
745 const onerror = () => {
746 this._checks--
747 this._removeNode(node)
748 }
749
750 this._checks++
751 this._request(
752 { id: null, host: node.host, port: node.port },
753 false,
754 true,
755 PING,
756 null,
757 null,
758 null,
759 onresponse,
760 onerror
761 )
762 }
763
764 _ontick() {
765 const time = Date.now()
766
767 if (time - this._lastTick > SLEEPING_INTERVAL && this.suspended === false) {
768 this._onwakeup()
769 } else {
770 this._tick++
771 }
772
773 this._lastTick = time
774
775 if (!this.bootstrapped || this.suspended) return
776
777 if (this.adaptive && this.ephemeral && --this._stableTicks <= 0) {
778 if (this._lastHost === this._nat.host) {
779 // do not recheck the same network...
780 this._stableTicks = MORE_STABLE_TICKS
781 } else {
782 this._updateNetworkState() // the promise returned here never fails so just ignore it
783 }
784 }
785
786 if ((this._tick & 7) === 0) {
787 this._pingSome()
788 }
789
790 if (
791 ((this._tick & 63) === 0 && this.nodes.length < this.table.k) ||
792 --this._refreshTicks <= 0
793 ) {
794 this.refresh()
795 }
796
797 this._downHintsSentPerTick = 0
798 this.health.update()
799 }
800
801 async _updateNetworkState(onlyFirewall = false) {
802 if (!this.ephemeral) return false
803 if (onlyFirewall && !this.firewalled) return false
804
805 const { host, port } = this._nat
806
807 if (!onlyFirewall) {
808 // remember what host we checked and reset the counter
809 this._stableTicks = MORE_STABLE_TICKS
810 this._lastHost = host
811 }
812
813 // check if we have a consistent host and port
814 if (host === null || port === 0) {
815 return false
816 }
817
818 const natSampler = this.firewalled ? new NatSampler() : this._nat
819
820 // ask remote nodes to ping us on our server socket to see if we have the port open
821 const firewalled = this.firewalled && (await this._checkIfFirewalled(natSampler))
822 if (firewalled) return false
823
824 this.firewalled = this.io.firewalled = false
825
826 // incase it's called in parallel for some reason, or if our nat status somehow changed
827 if (!this.ephemeral || host !== this._nat.host || port !== this._nat.port) return false
828 // if the firewall probe returned a different host / non consistent port, bail as well
829 if (natSampler.host !== host || natSampler.port === 0) return false
830
831 const id = peer.id(natSampler.host, natSampler.port)
832
833 if (!onlyFirewall) {
834 this.ephemeral = this.io.ephemeral = false
835 }
836
837 if (natSampler !== this._nat) {
838 const prevHost = this._nat.host
839 const prevPort = this._nat.port
840
841 this._nonePersistentSamples = []
842 this._nat = natSampler
843
844 if (prevHost !== this._nat.host || prevPort !== this._nat.port) {
845 this.emit('nat-update', this._nat.host, this._nat.port)
846 }
847 }
848
849 // TODO: we should make this a bit more defensive in terms of using more
850 // resources to make sure that the new routing table contains as many alive nodes
851 // as possible, vs blindly copying them over...
852
853 // all good! copy over the old routing table to the new one
854 if (!b4a.equals(this.table.id, id)) {
855 const nodes = this.table.toArray()
856
857 this.table = this.io.table = new Table(id)
858
859 for (const node of nodes) {
860 if (b4a.equals(node.id, id)) continue
861 if (!this.table.add(node)) this.nodes.remove(node)
862 }
863
864 this.table.on('row', this._onrow)
865
866 // we need to rebootstrap/refresh since we updated our id
867 if (this.bootstrapped) this.refresh()
868 }
869
870 if (!this.ephemeral) {
871 this.emit('persistent')
872 }
873
874 return true
875 }
876
877 async *_resolveBootstrapNodes() {
878 for (let { host, port } of this.bootstrapNodes) {
879 let doLookup = false
880
881 if (host.indexOf('@') === -1) {
882 doLookup = true
883 } else {
884 const [suggestedIP, fallbackHost] = host.split('@')
885 try {
886 await this.ping({ host: suggestedIP, port })
887 host = suggestedIP
888 } catch {
889 host = fallbackHost
890 doLookup = true
891 }
892 }
893
894 if (doLookup) {
895 try {
896 host = UDX.isIPv4(host) ? host : (await this.udx.lookup(host, { family: 4 })).host
897 } catch {
898 continue
899 }
900 }
901
902 yield {
903 id: peer.id(host, port),
904 host,
905 port
906 }
907 }
908 }
909
910 async _addBootstrapNodes(nodes) {
911 for await (const node of this._resolveBootstrapNodes()) {
912 nodes.push(node)
913 }
914 }
915
916 async _checkIfFirewalled(natSampler = new NatSampler()) {
917 const nodes = []
918 for (let node = this.nodes.latest; node && nodes.length < 5; node = node.prev) {
919 nodes.push(node)
920 }
921
922 if (nodes.length < 5) await this._addBootstrapNodes(nodes)
923 // if no nodes are available, including bootstrappers - bail
924 if (nodes.length === 0) return true
925
926 const hosts = new Set()
927 const value = b4a.allocUnsafe(2)
928
929 c.uint16.encode({ start: 0, end: 2, buffer: value }, this.io.serverSocket.address().port)
930
931 // double check they actually came on the server socket...
932 this.io.serverSocket.on('message', onmessage)
933
934 const pongs = await requestAll(this, true, PING_NAT, value, nodes)
935
936 let count = 0
937 for (const res of pongs) {
938 if (hosts.has(res.from.host)) {
939 count++
940 natSampler.add(res.to.host, res.to.port)
941 }
942 }
943
944 this.io.serverSocket.removeListener('message', onmessage)
945
946 // if we got no or very few replies, consider it a fluke
947 if (count < (nodes.length >= 5 ? 3 : 1)) return true
948
949 // check that the server socket has the same ip as the client socket
950 if (natSampler.host === null || this._nat.host !== natSampler.host) return true
951
952 // check that the local port of the server socket is the same as the remote port
953 // TODO: we might want a flag to opt out of this heuristic for specific remapped port servers
954 if (natSampler.port === 0 || natSampler.port !== this.io.serverSocket.address().port) {
955 return true
956 }
957
958 return false
959
960 function onmessage(_, { host }) {
961 hosts.add(host)
962 }
963 }
964
965 _backgroundQuery(target) {
966 this._refreshTicks = REFRESH_TICKS
967
968 const backgroundCon = Math.min(this.concurrency, Math.max(2, (this.concurrency / 8) | 0))
969 const q = new Query(this, target, true, FIND_NODE, null, {
970 concurrency: backgroundCon
971 })
972
973 q.on('data', () => {
974 // yield to other traffic
975 q.concurrency = this.io.inflight.length < 3 ? this.concurrency : backgroundCon
976 })
977
978 return q
979 }
980
981 // called by health
982 _online() {
983 if (this.online && !this.degraded) return
984 this.online = true
985 this.degraded = false
986 this.emit('network-update')
987 }
988
989 // called by health
990 _degraded() {
991 if (this.degraded) return
992 this.online = true
993 this.degraded = true
994 this.emit('network-update')
995 }
996
997 // called by health
998 _offline() {
999 if (!this.online) return
1000 this.online = false
1001 this.degraded = false
1002 this.emit('network-update')
1003 }
1004}
1005
1006DHT.OK = 0
1007DHT.ERROR_UNKNOWN_COMMAND = UNKNOWN_COMMAND
1008DHT.ERROR_INVALID_TOKEN = INVALID_TOKEN
1009
1010module.exports = DHT
1011
1012function localIP(udx, family = 4) {
1013 let host = null
1014
1015 for (const n of udx.networkInterfaces()) {
1016 if (n.family !== family || n.internal) continue
1017
1018 // mac really likes en0, mb a better way but this shouldnt be bad anywhere so return now
1019 if (n.name === 'en0') return n.host
1020
1021 // otherwise pick the first non internal host (let the loop continue in case we see en0)
1022 if (host === null) host = n.host
1023 }
1024
1025 return host || (family === 4 ? '127.0.0.1' : '::1')
1026}
1027
1028function parseNode(s) {
1029 if (typeof s === 'object') return s
1030 if (typeof s === 'number') return { host: '127.0.0.1', port: s }
1031 const [host, port] = s.split(':')
1032 if (!port) throw new Error('Bootstrap node format is host:port')
1033
1034 return {
1035 host,
1036 port: Number(port)
1037 }
1038}
1039
1040function randomBytes(n) {
1041 const b = b4a.alloc(n)
1042 sodium.randombytes_buf(b)
1043 return b
1044}
1045
1046function randomOffset(n) {
1047 return n - ((Math.random() * 0.5 * n) | 0)
1048}
1049
1050function requestAll(dht, internal, command, value, nodes) {
1051 let missing = nodes.length
1052 const replies = []
1053
1054 return new Promise((resolve) => {
1055 for (const node of nodes) {
1056 const req = dht._request(
1057 node,
1058 false,
1059 internal,
1060 command,
1061 null,
1062 value,
1063 null,
1064 onsuccess,
1065 onerror
1066 )
1067 if (!req) return resolve(replies)
1068 }
1069
1070 function onsuccess(res) {
1071 replies.push(res)
1072 if (--missing === 0) resolve(replies)
1073 }
1074
1075 function onerror() {
1076 if (--missing === 0) resolve(replies)
1077 }
1078 })
1079}
1080
1081function noop() {}
node_modules/dht-rpc/lib/commands.js +5 -0
……@@ -0,0 +1,5 @@
1exports.PING = 0
2exports.PING_NAT = 1
3exports.FIND_NODE = 2
4exports.DOWN_HINT = 3
5exports.DELAYED_PING = 4
node_modules/dht-rpc/lib/errors.js +29 -0
……@@ -0,0 +1,29 @@
1module.exports = class DHTError extends Error {
2 constructor(msg, code, fn = DHTError) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'DHTError'
13 }
14
15 static UNKNOWN_COMMAND = 1
16 static INVALID_TOKEN = 2
17
18 static REQUEST_TIMEOUT(msg = 'Request timed out') {
19 return new DHTError(msg, 'REQUEST_TIMEOUT', DHTError.REQUEST_TIMEOUT)
20 }
21
22 static REQUEST_DESTROYED(msg = 'Request destroyed') {
23 return new DHTError(msg, 'REQUEST_DESTROYED', DHTError.REQUEST_DESTROYED)
24 }
25
26 static IO_SUSPENDED(msg = 'I/O suspended') {
27 return new DHTError(msg, 'IO_SUSPENDED', DHTError.IO_SUSPENDED)
28 }
29}
node_modules/dht-rpc/lib/health.js +110 -0
……@@ -0,0 +1,110 @@
1const MAX_HEALTH_WINDOW = 4
2const IDLE_THRESHOLD = 4
3const DEGRADED_TIMEOUT_RATE_THRESHOLD = 0.5
4
5module.exports = class NetworkHealth {
6 constructor(dht) {
7 this._dht = dht
8 this._window = []
9 this._head = -1
10 this._degradedTicks = 0
11 this._healthyTicks = 0
12 this.online = true
13 this.degraded = false
14 }
15
16 get oldest() {
17 return this._window[this._tail]
18 }
19
20 get previous() {
21 return this._window[(this._head - 1 + MAX_HEALTH_WINDOW) % MAX_HEALTH_WINDOW]
22 }
23
24 get newest() {
25 return this._window[this._head]
26 }
27
28 get responses() {
29 if (!this.newest || !this.previous) return 0
30 return this.newest.responses - this.previous.responses
31 }
32
33 get timeouts() {
34 if (!this.newest || !this.previous) return 0
35 return this.newest.timeouts - this.previous.timeouts
36 }
37
38 get timeoutsRate() {
39 if (this.timeouts === 0) return 0
40 return this.timeouts / (this.responses + this.timeouts)
41 }
42
43 get cold() {
44 return this._window.length < MAX_HEALTH_WINDOW
45 }
46
47 get idle() {
48 return this.responses + this.timeouts < IDLE_THRESHOLD
49 }
50
51 get allDegraded() {
52 return this._degradedTicks === MAX_HEALTH_WINDOW
53 }
54
55 get allHealthy() {
56 return this._healthyTicks === MAX_HEALTH_WINDOW
57 }
58
59 get stats() {
60 return {
61 online: this.online,
62 degraded: this.degraded,
63 cold: this.cold,
64 idle: this.idle,
65 responses: this.responses,
66 timeouts: this.timeouts,
67 timeoutsRate: this.timeoutsRate
68 }
69 }
70
71 get _tail() {
72 return (this._head + 1) % MAX_HEALTH_WINDOW
73 }
74
75 reset() {
76 this._window = []
77 this._head = -1
78 this._degradedTicks = 0
79 this._healthyTicks = 0
80 this.online = true
81 this.degraded = false
82 this._dht._online()
83 }
84
85 update() {
86 if (this.oldest?.degraded) this._degradedTicks--
87 else if (this.oldest?.degraded === false) this._healthyTicks--
88
89 this._head = this._tail
90 this._window[this._head] = {
91 responses: this._dht.stats.requests.responses,
92 timeouts: this._dht.stats.requests.timeouts
93 }
94
95 if (this.cold || this.idle) return
96
97 this.newest.degraded = this.timeoutsRate > DEGRADED_TIMEOUT_RATE_THRESHOLD
98
99 if (this.newest.degraded) this._degradedTicks++
100 else this._healthyTicks++
101
102 this.online = this.responses > 0
103 if (this.online && this.allDegraded) this.degraded = true
104 if (!this.online || this.allHealthy) this.degraded = false
105
106 if (this.online && !this.degraded) this._dht._online()
107 else if (this.degraded) this._dht._degraded()
108 else this._dht._offline()
109 }
110}
node_modules/dht-rpc/lib/io.js +630 -0
……@@ -0,0 +1,630 @@
1const FIFO = require('fast-fifo')
2const sodium = require('sodium-universal')
3const c = require('compact-encoding')
4const b4a = require('b4a')
5const AdaptiveTimeout = require('adaptive-timeout')
6const peer = require('./peer')
7const { INVALID_TOKEN, REQUEST_TIMEOUT, REQUEST_DESTROYED, IO_SUSPENDED } = require('./errors')
8
9const VERSION = 0b11
10const RESPONSE_ID = (0b0001 << 4) | VERSION
11const REQUEST_ID = (0b0000 << 4) | VERSION
12const EMPTY_ARRAY = []
13const MAX_WINDOW = 80
14
15module.exports = class IO {
16 constructor(
17 table,
18 udx,
19 {
20 maxWindow = MAX_WINDOW,
21 port = 0,
22 host = '0.0.0.0',
23 anyPort = true,
24 firewalled = true,
25 onrequest,
26 onresponse = noop,
27 ontimeout = noop,
28 adaptiveTimeout
29 } = {}
30 ) {
31 this.table = table
32 this.udx = udx
33 this.inflight = []
34 this.clientSocket = null
35 this.serverSocket = null
36 this.firewalled = firewalled !== false
37 this.ephemeral = true
38 this.congestion = new CongestionWindow(maxWindow)
39 this.networkInterfaces = udx.watchNetworkInterfaces()
40 this.suspended = false
41
42 this.stats = {
43 requests: {
44 active: 0,
45 total: 0,
46 responses: 0,
47 timeouts: 0,
48 retries: 0
49 },
50 commands: [
51 { tx: 0, rx: 0 }, // tx = transmitted, rx = received
52 { tx: 0, rx: 0 },
53 { tx: 0, rx: 0 },
54 { tx: 0, rx: 0 }
55 ]
56 }
57
58 this.onrequest = onrequest
59 this.onresponse = onresponse
60 this.ontimeout = ontimeout
61
62 this._pending = new FIFO()
63 this._rotateSecrets = 10
64 this._tid = (Math.random() * 65536) | 0
65 this._secrets = null
66 this._drainInterval = null
67 this._destroying = null
68 this._binding = null
69
70 // port can be a number or a range [start, to]
71 this.portRange = port.length ? port : port === 0 ? [0, 0] : [port, port + 5]
72
73 this._host = host
74 this._anyPort = anyPort !== false
75 this._boundServerPort = 0
76 this._boundClientPort = 0
77
78 this._adt = adaptiveTimeout ? new AdaptiveTimeout(adaptiveTimeout) : null
79 }
80
81 static DEFAULT_MAX_WINDOW = MAX_WINDOW
82
83 onmessage(socket, buffer, { host, port }) {
84 if (buffer.byteLength < 2 || !(port > 0 && port < 65536) || this.suspended === true) return
85
86 const from = { id: null, host, port }
87 const state = { start: 1, end: buffer.byteLength, buffer }
88 const expectedSocket = this.firewalled ? this.clientSocket : this.serverSocket
89 const external = socket !== expectedSocket
90
91 if (buffer[0] === REQUEST_ID) {
92 const req = Request.decode(this, socket, from, state)
93 if (req === null) return
94 if (
95 req.token !== null &&
96 !b4a.equals(req.token, this.token(req.from, 1)) &&
97 !b4a.equals(req.token, this.token(req.from, 0))
98 ) {
99 req.error(INVALID_TOKEN, { token: true })
100 return
101 }
102 this.onrequest(req, external)
103 return
104 }
105
106 if (buffer[0] === RESPONSE_ID) {
107 const res = decodeReply(from, state)
108 if (res === null) return
109
110 for (let i = 0; i < this.inflight.length; i++) {
111 const req = this.inflight[i]
112 if (req.tid !== res.tid) continue
113
114 res.rtt = Date.now() - req._timestamp
115
116 if (this._adt && req.sent <= 2) {
117 this._adt.put(`${req.to.host}:${req.to.port}`, res.rtt)
118 }
119
120 if (i === this.inflight.length - 1) this.inflight.pop()
121 else this.inflight[i] = this.inflight.pop()
122
123 if (req.session) req.session._detach(req)
124
125 // TODO: Auto retry here if errors.INVALID_TOKEN is returned?
126
127 if (req._timeout) {
128 clearTimeout(req._timeout)
129 req._timeout = null
130 }
131
132 this.congestion.recv()
133
134 if (req.internal && req.command < this.stats.commands.length) {
135 this.stats.commands[req.command].rx++
136 }
137
138 this.stats.requests.active--
139 this.stats.requests.responses++
140
141 this.onresponse(res, external)
142 req.onresponse(res, req)
143 break
144 }
145 }
146 }
147
148 token(addr, i) {
149 if (this._secrets === null) {
150 const buf = b4a.alloc(64)
151 this._secrets = [buf.subarray(0, 32), buf.subarray(32, 64)]
152 sodium.randombytes_buf(this._secrets[0])
153 sodium.randombytes_buf(this._secrets[1])
154 }
155
156 const token = b4a.allocUnsafe(32)
157 sodium.crypto_generichash(token, b4a.from(addr.host), this._secrets[i])
158 return token
159 }
160
161 async destroy() {
162 if (this._destroying) return this._destroying
163 this._destroying = this._destroy()
164 return this._destroying
165 }
166
167 async _destroy() {
168 // simplifies timing to await the bind here also, although it might be unneeded
169 await this.bind()
170 await this._clear(false)
171 }
172
173 async _clear(suspended) {
174 if (this._drainInterval) {
175 clearInterval(this._drainInterval)
176 this._drainInterval = null
177 }
178
179 while (this.inflight.length) {
180 const req = this.inflight.pop()
181 if (req._timeout) clearTimeout(req._timeout)
182 req._timeout = null
183 req.destroyed = true
184
185 if (req.session) req.session._detach(req)
186
187 this.congestion.recv()
188 this.stats.requests.active--
189
190 req.onerror(suspended ? IO_SUSPENDED() : REQUEST_DESTROYED(), req)
191 }
192
193 await Promise.allSettled([this.serverSocket.close(), this.clientSocket.close()])
194
195 this.networkInterfaces.destroy()
196 }
197
198 async suspend() {
199 this.suspended = true
200 await this._clear(true)
201
202 this.congestion.clear()
203
204 if (this._drainInterval) {
205 clearInterval(this._drainInterval)
206 this._drainInterval = null
207 }
208 }
209
210 async _rebind(binding) {
211 if (binding) await binding
212 if (this._destroying) return this._destroying
213 await this._bindSockets()
214 this.networkInterfaces = this.udx.watchNetworkInterfaces()
215 }
216
217 resume() {
218 this.suspended = false
219 const binding = this._binding
220 this._binding = this._rebind(binding)
221 return this._binding
222 }
223
224 bind() {
225 if (this._binding) return this._binding
226 this._binding = this._bindSockets()
227 return this._binding
228 }
229
230 async _bindSockets() {
231 const serverSocket = this.udx.createSocket()
232
233 const candidatePorts = []
234
235 // Retrying previous port always has precedence
236 if (this._boundServerPort) candidatePorts.push(this._boundServerPort)
237
238 for (let i = this.portRange[0]; i < this.portRange[1]; i++) candidatePorts.push(i)
239
240 for (const port of candidatePorts) {
241 if (serverSocket.bound) break
242
243 try {
244 serverSocket.bind(port, this._host)
245 } catch (err) {
246 if (!this._anyPort) {
247 await serverSocket.close()
248 throw err
249 }
250 }
251 }
252
253 if (!serverSocket.bound) {
254 try {
255 serverSocket.bind(0, this._host)
256 } catch (err) {
257 await serverSocket.close()
258 throw err
259 }
260 }
261
262 const clientSocket = this.udx.createSocket()
263
264 try {
265 clientSocket.bind(this._boundClientPort || 0, this._host)
266 } catch {
267 try {
268 clientSocket.bind(0, this._host)
269 } catch (err) {
270 await serverSocket.close()
271 await clientSocket.close()
272 throw err
273 }
274 }
275
276 this._boundServerPort = serverSocket.address().port
277 this._boundClientPort = clientSocket.address().port
278
279 this.clientSocket = clientSocket
280 this.serverSocket = serverSocket
281
282 this.serverSocket.on('message', this.onmessage.bind(this, this.serverSocket))
283 this.clientSocket.on('message', this.onmessage.bind(this, this.clientSocket))
284
285 if (this._drainInterval === null) {
286 this._drainInterval = setInterval(this._drain.bind(this), 750)
287 if (this._drainInterval.unref) this._drainInterval.unref()
288 }
289
290 for (const req of this.inflight) {
291 if (!req.socket) req.socket = this.firewalled ? this.clientSocket : this.serverSocket
292 req.sent = 0
293 req.send(false)
294 }
295 }
296
297 _drain() {
298 if (this._secrets !== null && --this._rotateSecrets === 0) {
299 this._rotateSecrets = 10
300 const tmp = this._secrets[0]
301 this._secrets[0] = this._secrets[1]
302 this._secrets[1] = tmp
303 sodium.crypto_generichash(tmp, tmp)
304 }
305
306 this.congestion.drain()
307
308 while (!this.congestion.isFull()) {
309 const p = this._pending.shift()
310 if (p === undefined) return
311 p._sendNow()
312 }
313 }
314
315 createRequest(to, token, internal, command, target, value, session, ttl) {
316 if (this._destroying !== null) return null
317
318 if (this._tid === 65536) this._tid = 0
319
320 const tid = this._tid++
321 const socket = this.firewalled ? this.clientSocket : this.serverSocket
322
323 const req = new Request(
324 this,
325 socket,
326 tid,
327 null,
328 to,
329 token,
330 internal,
331 command,
332 target,
333 value,
334 session,
335 ttl || 0
336 )
337 this.inflight.push(req)
338 if (session) session._attach(req)
339
340 if (internal && command < this.stats.commands.length) {
341 this.stats.commands[command].tx++
342 }
343
344 this.stats.requests.active++
345 this.stats.requests.total++
346
347 return req
348 }
349}
350
351class Request {
352 constructor(io, socket, tid, from, to, token, internal, command, target, value, session, ttl) {
353 this.socket = socket
354 this.tid = tid
355 this.from = from
356 this.to = to
357 this.token = token
358 this.command = command
359 this.target = target
360 this.value = value
361 this.internal = internal
362 this.session = session
363 this.ttl = ttl
364 this.index = -1
365 this.sent = 0
366 this.retries = 3
367 this.destroyed = false
368 this.timeout = 0
369
370 this.oncycle = noop
371 this.onerror = noop
372 this.onresponse = noop
373
374 this._buffer = null
375 this._io = io
376 this._timeout = null
377 this._timestamp = Date.now()
378 }
379
380 static decode(io, socket, from, state) {
381 try {
382 const flags = c.uint.decode(state)
383 const tid = c.uint16.decode(state)
384 const to = peer.ipv4.decode(state)
385 const id = flags & 1 ? c.fixed32.decode(state) : null
386 const token = flags & 2 ? c.fixed32.decode(state) : null
387 const internal = (flags & 4) !== 0
388 const command = c.uint.decode(state)
389 const target = flags & 8 ? c.fixed32.decode(state) : null
390 const value = flags & 16 ? c.buffer.decode(state) : null
391
392 if (id !== null) from.id = validateId(id, from)
393
394 return new Request(
395 io,
396 socket,
397 tid,
398 from,
399 to,
400 token,
401 internal,
402 command,
403 target,
404 value,
405 null,
406 0
407 )
408 } catch {
409 return null
410 }
411 }
412
413 reply(value, opts = {}) {
414 const socket = opts.socket || this.socket
415 const to = opts.to || this.from
416 this._sendReply(0, value || null, opts.token !== false, opts.closerNodes !== false, to, socket)
417 }
418
419 error(code, opts = {}) {
420 const socket = opts.socket || this.socket
421 const to = opts.to || this.from
422 this._sendReply(code, null, opts.token === true, opts.closerNodes !== false, to, socket)
423 }
424
425 relay(value, to, opts) {
426 const socket = (opts && opts.socket) || this.socket
427 const buffer = this._encodeRequest(null, value, to, socket)
428 socket.trySend(buffer, to.port, to.host, this.ttl)
429 }
430
431 send(force = false) {
432 if (this.destroyed) return
433
434 if (this.socket === null) return
435 if (this._buffer === null) {
436 this._buffer = this._encodeRequest(this.token, this.value, this.to, this.socket)
437 }
438
439 if (!force && this._io.congestion.isFull()) {
440 this._io._pending.push(this)
441 return
442 }
443
444 this._sendNow()
445 }
446
447 sendReply(error, value, token, hasCloserNodes) {
448 this._sendReply(error, value, token, hasCloserNodes, this.from, this.socket, null)
449 }
450
451 _sendNow() {
452 if (this.destroyed) return
453 this.sent++
454 this._io.congestion.send()
455 this.socket.trySend(this._buffer, this.to.port, this.to.host, this.ttl)
456 if (this._timeout) clearTimeout(this._timeout)
457 const value =
458 this.timeout || this._io._adt?.get(`${this.to.host}:${this.to.port}`, this.sent) || 1000
459 this._timeout = setTimeout(oncycle, value, this)
460 }
461
462 destroy(err) {
463 if (this.destroyed) return
464 this.destroyed = true
465
466 if (this._timeout) {
467 clearTimeout(this._timeout)
468 this._timeout = null
469 }
470
471 const i = this._io.inflight.indexOf(this)
472 if (i === -1) return
473
474 if (i === this._io.inflight.length - 1) this._io.inflight.pop()
475 else this._io.inflight[i] = this._io.inflight.pop()
476
477 if (this.session) this.session._detach(this)
478
479 this._io.stats.requests.active--
480 this._io.congestion.recv()
481
482 this.onerror(err || REQUEST_DESTROYED(), this)
483 }
484
485 _sendReply(error, value, token, hasCloserNodes, from, socket) {
486 if (socket === null || this.destroyed) return
487
488 const id = this._io.ephemeral === false && socket === this._io.serverSocket
489 const closerNodes =
490 this.target !== null && hasCloserNodes ? this._io.table.closest(this.target) : EMPTY_ARRAY
491 const state = { start: 0, end: 1 + 1 + 6 + 2, buffer: null } // (type | version) + flags + to + tid
492
493 if (id) state.end += 32
494 if (token) state.end += 32
495 if (closerNodes.length > 0) peer.ipv4Array.preencode(state, closerNodes)
496 if (error > 0) c.uint.preencode(state, error)
497 if (value) c.buffer.preencode(state, value)
498
499 state.buffer = b4a.allocUnsafe(state.end)
500 state.buffer[state.start++] = RESPONSE_ID
501 state.buffer[state.start++] =
502 (id ? 1 : 0) |
503 (token ? 2 : 0) |
504 (closerNodes.length > 0 ? 4 : 0) |
505 (error > 0 ? 8 : 0) |
506 (value ? 16 : 0)
507
508 c.uint16.encode(state, this.tid)
509 peer.ipv4.encode(state, from)
510
511 if (id) c.fixed32.encode(state, this._io.table.id)
512 if (token) c.fixed32.encode(state, this._io.token(from, 1))
513 if (closerNodes.length > 0) peer.ipv4Array.encode(state, closerNodes)
514 if (error > 0) c.uint.encode(state, error)
515 if (value) c.buffer.encode(state, value)
516
517 socket.trySend(state.buffer, from.port, from.host, this.ttl)
518 }
519
520 _encodeRequest(token, value, to, socket) {
521 const id = this._io.ephemeral === false && socket === this._io.serverSocket
522 const state = { start: 0, end: 1 + 1 + 6 + 2, buffer: null } // (type | version) + flags + to + tid
523
524 if (id) state.end += 32
525 if (token) state.end += 32
526
527 c.uint.preencode(state, this.command)
528
529 if (this.target) state.end += 32
530 if (value) c.buffer.preencode(state, value)
531
532 state.buffer = b4a.allocUnsafe(state.end)
533 state.buffer[state.start++] = REQUEST_ID
534 state.buffer[state.start++] =
535 (id ? 1 : 0) |
536 (token ? 2 : 0) |
537 (this.internal ? 4 : 0) |
538 (this.target ? 8 : 0) |
539 (value ? 16 : 0)
540
541 c.uint16.encode(state, this.tid)
542 peer.ipv4.encode(state, to)
543
544 if (id) c.fixed32.encode(state, this._io.table.id)
545 if (token) c.fixed32.encode(state, token)
546
547 c.uint.encode(state, this.command)
548
549 if (this.target) c.fixed32.encode(state, this.target)
550 if (value) c.buffer.encode(state, value)
551
552 return state.buffer
553 }
554}
555
556class CongestionWindow {
557 constructor(maxWindow) {
558 this._i = 0
559 this._total = 0
560 this._window = [0, 0, 0, 0]
561 this._maxWindow = maxWindow
562 }
563
564 clear() {
565 this._i = 0
566 this._total = 0
567 this._window = [0, 0, 0, 0]
568 }
569
570 isFull() {
571 return this._total >= 2 * this._maxWindow || this._window[this._i] >= this._maxWindow
572 }
573
574 recv() {
575 if (this._window[this._i] > 0) {
576 this._window[this._i]--
577 this._total--
578 }
579 }
580
581 send() {
582 this._total++
583 this._window[this._i]++
584 }
585
586 drain() {
587 this._i = (this._i + 1) & 3
588 this._total -= this._window[this._i]
589 this._window[this._i] = 0 // clear oldest
590 }
591}
592
593function noop() {}
594
595function oncycle(req) {
596 req._timeout = null
597 req.oncycle(req)
598 if (req.sent > req.retries) {
599 req._io.stats.requests.timeouts++
600 req.destroy(REQUEST_TIMEOUT())
601 req._io.ontimeout(req)
602 } else {
603 req._io.stats.requests.retries++
604 req.send()
605 }
606}
607
608function decodeReply(from, state) {
609 try {
610 const flags = c.uint.decode(state)
611 const tid = c.uint16.decode(state)
612 const to = peer.ipv4.decode(state)
613 const id = flags & 1 ? c.fixed32.decode(state) : null
614 const token = flags & 2 ? c.fixed32.decode(state) : null
615 const closerNodes = flags & 4 ? peer.ipv4Array.decode(state) : null
616 const error = flags & 8 ? c.uint.decode(state) : 0
617 const value = flags & 16 ? c.buffer.decode(state) : null
618
619 if (id !== null) from.id = validateId(id, from)
620
621 return { tid, rtt: 0, from, to, token, closerNodes, error, value }
622 } catch {
623 return null
624 }
625}
626
627function validateId(id, from) {
628 const expected = peer.id(from.host, from.port)
629 return b4a.equals(expected, id) ? expected : null
630}
node_modules/dht-rpc/lib/peer.js +25 -0
……@@ -0,0 +1,25 @@
1const sodium = require('sodium-universal')
2const c = require('compact-encoding')
3const net = require('compact-encoding-net')
4const b4a = require('b4a')
5
6const ipv4 = {
7 ...net.ipv4Address,
8 decode(state) {
9 const ip = net.ipv4Address.decode(state)
10 return {
11 id: null, // populated by the callee
12 host: ip.host,
13 port: ip.port
14 }
15 }
16}
17
18module.exports = { id, ipv4, ipv4Array: c.array(ipv4) }
19
20function id(host, port, out = b4a.allocUnsafeSlow(32)) {
21 const addr = out.subarray(0, 6)
22 ipv4.encode({ start: 0, end: 6, buffer: addr }, { host, port })
23 sodium.crypto_generichash(out, addr)
24 return out
25}
node_modules/dht-rpc/lib/query.js +409 -0
……@@ -0,0 +1,409 @@
1const { Readable, getStreamError } = require('streamx')
2const b4a = require('b4a')
3const peer = require('./peer')
4const { DOWN_HINT } = require('./commands')
5
6const DONE = []
7const DOWN = []
8
9module.exports = class Query extends Readable {
10 constructor(dht, target, internal, command, value, opts = {}) {
11 super()
12
13 dht.stats.queries.total++
14 dht.stats.queries.active++
15
16 this.force = !!opts.force
17 this.dht = dht
18 this.k = this.dht.table.k
19 this.target = target
20 this.internal = internal
21 this.command = command
22 this.value = value
23 this.errors = 0
24 this.successes = 0
25 this.concurrency = opts.concurrency || this.dht.concurrency
26 this.inflight = 0
27 this.map = opts.map || defaultMap
28 this.retries =
29 opts.retries === 0 ? 0 : opts.retries || (this.internal && command === DOWN_HINT ? 3 : 5)
30 this.closestReplies = []
31
32 this._slow = 0
33 this._slowdown = false
34 this._seen = new Map()
35 this._pending = []
36 this._fromTable = false
37 this._commit = opts.commit === true ? autoCommit : opts.commit || null
38 this._commiting = false
39 this._session = opts.session || dht.session()
40 this._autoDestroySession = !opts.session
41 this._onlyClosestNodes = false
42
43 this._onvisitbound = this._onvisit.bind(this)
44 this._onerrorbound = this._onerror.bind(this)
45 this._oncyclebound = this._oncycle.bind(this)
46
47 const nodes = opts.nodes || opts.closestNodes
48 const replies = opts.replies || opts.closestReplies
49
50 // add them reverse as we pop below
51 if (nodes) {
52 for (let i = nodes.length - 1; i >= 0; i--) {
53 const node = nodes[i]
54 this._addPending(
55 {
56 id: node.id || peer.id(node.host, node.port),
57 host: node.host,
58 port: node.port
59 },
60 null
61 )
62 }
63 } else if (replies) {
64 for (let i = replies.length - 1; i >= 0; i--) {
65 this._addPending(replies[i].from, null)
66 }
67 }
68
69 if (opts.onlyClosestNodes) this._onlyClosestNodes = true
70 }
71
72 get closestNodes() {
73 const nodes = new Array(this.closestReplies.length)
74
75 for (let i = 0; i < nodes.length; i++) {
76 nodes[i] = this.closestReplies[i].from
77 }
78
79 return nodes
80 }
81
82 finished() {
83 return new Promise((resolve, reject) => {
84 if (this.destroyed) {
85 const error = getStreamError(this)
86 if (error) reject(error)
87 else resolve()
88 return
89 }
90
91 const self = this
92 let error = null
93
94 this.resume()
95 this.on('error', onerror)
96 this.on('close', onclose)
97
98 function onclose() {
99 self.removeListener('error', onerror)
100 self.removeListener('close', onclose)
101 if (error) reject(error)
102 else resolve()
103 }
104
105 function onerror(err) {
106 error = err
107 }
108 })
109 }
110
111 _addFromTable() {
112 if (this._pending.length >= this.k) return
113 this._fromTable = true
114
115 const closest = this.dht.table.closest(this.target, this.k - this._pending.length)
116
117 for (const node of closest) {
118 this._addPending({ id: node.id, host: node.host, port: node.port }, null)
119 }
120 }
121
122 async _open(cb) {
123 this._addFromTable()
124 if (this._pending.length >= this.k) return cb(null)
125
126 for await (const node of this.dht._resolveBootstrapNodes()) {
127 this._addPending(node, null)
128 }
129
130 cb(null)
131 }
132
133 _isCloser(id) {
134 return (
135 this.closestReplies.length < this.k ||
136 this._compare(id, this.closestReplies[this.closestReplies.length - 1].from.id) < 0
137 )
138 }
139
140 _addPending(node, ref) {
141 if (this._onlyClosestNodes) return false
142
143 const addr = node.host + ':' + node.port
144 const refs = this._seen.get(addr)
145 const isCloser = this._isCloser(node.id)
146
147 if (refs === DONE) {
148 return isCloser
149 }
150
151 if (refs === DOWN) {
152 if (ref) this._downHint(ref, node)
153 return isCloser
154 }
155
156 if (refs) {
157 if (ref !== null) refs.push(ref)
158 return isCloser
159 }
160
161 if (!isCloser) {
162 return false
163 }
164
165 this._seen.set(addr, ref === null ? [] : [ref])
166 this._pending.push(node)
167
168 return true
169 }
170
171 _read(cb) {
172 this._readMore()
173 cb(null)
174 }
175
176 _readMore() {
177 if (this.destroying || this._commiting) return
178
179 const concurrency = (this._slowdown ? 3 : this.concurrency) + this._slow
180
181 while (this.inflight < concurrency && this._pending.length > 0) {
182 const next = this._pending.pop()
183 if (next && next.id && !this._isCloser(next.id)) continue
184 this._visit(next)
185 }
186
187 // if reusing closest nodes, slow down after the first readMore tick to allow
188 // the closest node a chance to reply before going broad to question more
189 if (!this._fromTable && this.successes === 0 && this.errors === 0) {
190 this._slowdown = true
191 }
192
193 if (this._pending.length > 0) return
194
195 // if no inflight OR all the queries we are waiting on are marked as slow and we have a full result.
196 if (
197 this.inflight === 0 ||
198 (this._slow === this.inflight && this.closestReplies.length >= this.k)
199 ) {
200 // if more than 3/4 failed and we only used cached nodes, try again from the routing table
201 if (!this._fromTable && this.successes < this.k / 4) {
202 this._addFromTable()
203 this._readMore()
204 return
205 }
206
207 this._flush()
208 }
209 }
210
211 _flush() {
212 if (this._commiting) return
213 this._commiting = true
214
215 if (this._commit === null) {
216 this.push(null)
217 return
218 }
219
220 const p = []
221 for (const m of this.closestReplies) p.push(this._commit(m, this.dht, this))
222 this._endAfterCommit(p)
223 }
224
225 _endAfterCommit(ps) {
226 if (!ps.length) {
227 this.destroy(new Error('Too few nodes responded'))
228 return
229 }
230
231 const self = this
232
233 let pending = ps.length
234 let success = 0
235
236 for (const p of ps) p.then(ondone, onerror)
237
238 function ondone() {
239 success++
240 if (--pending === 0) self.push(null)
241 }
242
243 function onerror(err) {
244 if (--pending > 0) return
245 if (success) self.push(null)
246 else self.destroy(err)
247 }
248 }
249
250 _dec(req) {
251 if (req.oncycle === noop) {
252 this._slow--
253 } else {
254 req.oncycle = noop
255 }
256 this.inflight--
257 }
258
259 _onvisit(m, req) {
260 this._dec(req)
261
262 const addr = req.to.host + ':' + req.to.port
263 this._seen.set(addr, DONE)
264
265 if (this._commiting) return
266
267 if (m.error === 0) this.successes++
268 else this.errors++
269
270 if (m.error === 0 && m.from.id !== null && this._isCloser(m.from.id)) this._pushClosest(m)
271
272 if (m.closerNodes !== null) {
273 for (const node of m.closerNodes) {
274 node.id = peer.id(node.host, node.port)
275 if (this.dht._filterNode !== null && !this.dht._filterNode(node)) continue
276 if (b4a.equals(node.id, this.dht.table.id)) continue
277 // TODO: we could continue here instead of breaking to ensure that one of the nodes in the closer list
278 // is later marked as DOWN that we gossip that back
279 if (!this._addPending(node, m.from)) break
280 }
281 }
282
283 if (!this._fromTable && this.successes + this.errors >= this.concurrency) {
284 this._slowdown = false
285 }
286
287 if (m.error !== 0) {
288 this._readMore()
289 return
290 }
291
292 const data = this.map(m)
293 if (!data || this.push(data) !== false) {
294 this._readMore()
295 }
296 }
297
298 _onerror(err, req) {
299 const addr = req.to.host + ':' + req.to.port
300 const refs = this._seen.get(addr)
301
302 if (err.code === 'REQUEST_TIMEOUT') {
303 this._seen.set(addr, DOWN)
304 for (const node of refs) this._downHint(node, req.to)
305 }
306
307 this._dec(req)
308 this.errors++
309 this._readMore()
310 }
311
312 _oncycle(req) {
313 req.oncycle = noop
314 this._slow++
315 this._readMore()
316 }
317
318 _downHint(node, down) {
319 // Check rate limit
320 if (
321 this.dht._downHintsRateLimit !== -1 &&
322 this.dht._downHintsSentPerTick >= this.dht._downHintsRateLimit
323 ) {
324 return null
325 }
326
327 this.dht._downHintsSentPerTick++
328
329 const state = { start: 0, end: 6, buffer: b4a.allocUnsafe(6) }
330 peer.ipv4.encode(state, down)
331 this.dht._request(node, false, true, DOWN_HINT, null, state.buffer, this._session, noop, noop)
332 }
333
334 _pushClosest(m) {
335 this.closestReplies.push(m)
336 for (let i = this.closestReplies.length - 2; i >= 0; i--) {
337 const prev = this.closestReplies[i]
338 const cmp = this._compare(prev.from.id, m.from.id)
339 // if sorted, done!
340 if (cmp < 0) break
341 // if dup, splice it out (rare)
342 if (cmp === 0) {
343 this.closestReplies.splice(i + 1, 1)
344 break
345 }
346 // swap and continue down
347 this.closestReplies[i + 1] = prev
348 this.closestReplies[i] = m
349 }
350 if (this.closestReplies.length > this.k) this.closestReplies.pop()
351 }
352
353 _compare(a, b) {
354 for (let i = 0; i < a.length; i++) {
355 if (a[i] === b[i]) continue
356 const t = this.target[i]
357 return (t ^ a[i]) - (t ^ b[i])
358 }
359 return 0
360 }
361
362 _visit(to) {
363 this.inflight++
364
365 const req = this.dht._request(
366 to,
367 this.force,
368 this.internal,
369 this.command,
370 this.target,
371 this.value,
372 this._session,
373 this._onvisitbound,
374 this._onerrorbound
375 )
376 if (req === null) {
377 this.destroy(new Error('Node was destroyed'))
378 return
379 }
380 req.retries = this.retries
381 req.oncycle = this._oncyclebound
382 if (this.force) req.retries = 0
383 }
384
385 _destroy(cb) {
386 this.dht.stats.queries.active--
387 if (this._autoDestroySession) this._session.destroy()
388 cb(null)
389 }
390}
391
392function autoCommit(reply, dht, query) {
393 if (!reply.token) return Promise.reject(new Error('No token received for closest node'))
394 return dht.request(
395 {
396 token: reply.token,
397 target: query.target,
398 command: query.command,
399 value: query.value
400 },
401 reply.from
402 )
403}
404
405function defaultMap(m) {
406 return m
407}
408
409function noop() {}
node_modules/dht-rpc/lib/session.js +47 -0
……@@ -0,0 +1,47 @@
1module.exports = class Session {
2 constructor(dht) {
3 this.dht = dht
4 this.inflight = []
5 }
6
7 _attach(req) {
8 req.index = this.inflight.push(req) - 1
9 }
10
11 _detach(req) {
12 const i = req.index
13 if (i === -1) return
14 req.index = -1
15
16 if (i === this.inflight.length - 1) this.inflight.pop()
17 else {
18 const req = (this.inflight[i] = this.inflight.pop())
19 req.index = i
20 }
21 }
22
23 query({ target, command, value }, opts = {}) {
24 return this.dht.query({ target, command, value }, { ...opts, session: this })
25 }
26
27 request({ token, command, target, value }, { host, port }, opts = {}) {
28 return this.dht.request(
29 { token, command, target, value },
30 { host, port },
31 { ...opts, session: this }
32 )
33 }
34
35 ping({ host, port }, opts = {}) {
36 return this.dht.ping({ host, port }, { ...opts, session: this })
37 }
38
39 destroy(err) {
40 while (this.inflight.length) {
41 const req = this.inflight[0]
42 // prevent destroyed requests from contributing to congestion counts
43 this.dht.io.congestion.recv()
44 req.destroy(err)
45 }
46 }
47}
node_modules/dht-rpc/package.json +54 -0
……@@ -0,0 +1,54 @@
1{
2 "name": "dht-rpc",
3 "version": "6.26.3",
4 "description": "Make RPC calls over a Kademlia based DHT",
5 "main": "index.js",
6 "files": [
7 "index.js",
8 "lib/*.js"
9 ],
10 "imports": {
11 "events": {
12 "bare": "bare-events",
13 "default": "events"
14 }
15 },
16 "dependencies": {
17 "adaptive-timeout": "^1.0.1",
18 "b4a": "^1.6.1",
19 "bare-events": "^2.2.0",
20 "compact-encoding": "^2.11.0",
21 "compact-encoding-net": "^1.2.0",
22 "fast-fifo": "^1.1.0",
23 "kademlia-routing-table": "^1.0.1",
24 "nat-sampler": "^1.0.1",
25 "sodium-universal": "^5.0.0",
26 "streamx": "^2.13.2",
27 "time-ordered-set": "^2.0.0",
28 "udx-native": "^1.5.3"
29 },
30 "devDependencies": {
31 "brittle": "^3.0.0",
32 "lunte": "^1.3.0",
33 "prettier": "^3.6.2",
34 "prettier-config-holepunch": "^2.0.0",
35 "test-suspend": "^1.0.0"
36 },
37 "scripts": {
38 "format": "prettier --write .",
39 "test": "npm run test:node && npm run test:bare",
40 "test:bare": "brittle-bare --coverage test.js",
41 "lint": "prettier --check . && lunte",
42 "test:node": "brittle-node --coverage test.js"
43 },
44 "repository": {
45 "type": "git",
46 "url": "https://github.com/mafintosh/dht-rpc.git"
47 },
48 "author": "Mathias Buus (@mafintosh)",
49 "license": "MIT",
50 "bugs": {
51 "url": "https://github.com/mafintosh/dht-rpc/issues"
52 },
53 "homepage": "https://github.com/mafintosh/dht-rpc"
54}
node_modules/error-stack-parser/LICENSE +19 -0
……@@ -0,0 +1,19 @@
1Copyright (c) 2017 Eric Wendelin and other contributors
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7of the Software, and to permit persons to whom the Software is furnished to do
8so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
node_modules/error-stack-parser/README.md +44 -0
……@@ -0,0 +1,44 @@
1error-stack-parser.js - Extract meaning from JS Errors
2===============
3[![Build Status](https://img.shields.io/github/workflow/status/stacktracejs/error-stack-parser/Continuous%20Integration/master?logo=github&style=flat-square)](https://github.com/stacktracejs/error-stack-parser/actions?query=workflow%3AContinuous+Integration+branch%3Amaster)
4[![Coverage Status](https://img.shields.io/coveralls/stacktracejs/error-stack-parser.svg?style=flat-square)](https://coveralls.io/r/stacktracejs/error-stack-parser?branch=master)
5[![GitHub license](https://img.shields.io/github/license/stacktracejs/error-stack-parser.svg?style=flat-square)](https://opensource.org/licenses/MIT)
6[![size with dependencies](https://img.shields.io/badge/size-4.8k-green.svg?style=flat-square)](https://github.com/stacktracejs/error-stack-parser/releases)
7[![gzip size](https://img.shields.io/badge/gzipped-1.8k-green.svg?style=flat-square)](https://github.com/stacktracejs/error-stack-parser/releases)
8[![module format](https://img.shields.io/badge/module%20format-umd-lightgrey.svg?style=flat-square&colorB=ff69b4)](https://github.com/stacktracejs/error-stack-parser/releases)
9[![code of conduct](https://img.shields.io/badge/code%20of-conduct-lightgrey.svg?style=flat-square&colorB=ff69b4)](http://todogroup.org/opencodeofconduct/#stacktrace.js/me@eriwen.com)
10[![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/error-stack-parser/badge)](https://www.jsdelivr.com/package/npm/error-stack-parser)
11
12Simple, cross-browser [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) parser.
13This library parses and extracts function names, URLs, line numbers, and column numbers from the given Error's `stack` as
14an Array of [StackFrame](http://git.io/stackframe)s.
15
16Once you have parsed out StackFrames, you can do much more interesting things. See [stacktrace-gps](http://git.io/stacktrace-gps).
17
18Note that in IE9 and earlier, `Error` objects don't have enough information to extract much of anything. In IE 10, `Error`s
19are given a `stack` once they're `throw`n.
20
21## Browser Support
22[![Sauce Test Status](https://saucelabs.com/browser-matrix/stacktracejs.svg)](https://saucelabs.com/u/stacktracejs)
23
24## Usage
25```js
26ErrorStackParser.parse(new Error('BOOM'));
27
28=> [
29 StackFrame({functionName: 'foo', args: [], fileName: 'path/to/file.js', lineNumber: 35, columnNumber: 79, isNative: false, isEval: false}),
30 StackFrame({functionName: 'Bar', fileName: 'https://cdn.somewherefast.com/utils.min.js', lineNumber: 1, columnNumber: 832, isNative: false, isEval: false, isConstructor: true}),
31 StackFrame(... and so on ...)
32 ]
33```
34
35## Installation
36```bash
37npm install error-stack-parser
38bower install error-stack-parser
39https://raw.githubusercontent.com/stacktracejs/error-stack-parser/master/dist/error-stack-parser.min.js
40```
41
42## Contributing
43Want to be listed as a *Contributor*? Start with the [Contributing Guide](.github/CONTRIBUTING.md)!
44
node_modules/error-stack-parser/dist/error-stack-parser.js +202 -0
……@@ -0,0 +1,202 @@
1(function(root, factory) {
2 'use strict';
3 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
4
5 /* istanbul ignore next */
6 if (typeof define === 'function' && define.amd) {
7 define('error-stack-parser', ['stackframe'], factory);
8 } else if (typeof exports === 'object') {
9 module.exports = factory(require('stackframe'));
10 } else {
11 root.ErrorStackParser = factory(root.StackFrame);
12 }
13}(this, function ErrorStackParser(StackFrame) {
14 'use strict';
15
16 var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+:\d+/;
17 var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
18 var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
19
20 return {
21 /**
22 * Given an Error object, extract the most information from it.
23 *
24 * @param {Error} error object
25 * @return {Array} of StackFrames
26 */
27 parse: function ErrorStackParser$$parse(error) {
28 if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {
29 return this.parseOpera(error);
30 } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {
31 return this.parseV8OrIE(error);
32 } else if (error.stack) {
33 return this.parseFFOrSafari(error);
34 } else {
35 throw new Error('Cannot parse given Error object');
36 }
37 },
38
39 // Separate line and column numbers from a string of the form: (URI:Line:Column)
40 extractLocation: function ErrorStackParser$$extractLocation(urlLike) {
41 // Fail-fast but return locations like "(native)"
42 if (urlLike.indexOf(':') === -1) {
43 return [urlLike];
44 }
45
46 var regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
47 var parts = regExp.exec(urlLike.replace(/[()]/g, ''));
48 return [parts[1], parts[2] || undefined, parts[3] || undefined];
49 },
50
51 parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {
52 var filtered = error.stack.split('\n').filter(function(line) {
53 return !!line.match(CHROME_IE_STACK_REGEXP);
54 }, this);
55
56 return filtered.map(function(line) {
57 if (line.indexOf('(eval ') > -1) {
58 // Throw away eval information until we implement stacktrace.js/stackframe#8
59 line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(,.*$)/g, '');
60 }
61 var sanitizedLine = line.replace(/^\s+/, '').replace(/\(eval code/g, '(').replace(/^.*?\s+/, '');
62
63 // capture and preseve the parenthesized location "(/foo/my bar.js:12:87)" in
64 // case it has spaces in it, as the string is split on \s+ later on
65 var location = sanitizedLine.match(/ (\(.+\)$)/);
66
67 // remove the parenthesized location from the line, if it was matched
68 sanitizedLine = location ? sanitizedLine.replace(location[0], '') : sanitizedLine;
69
70 // if a location was matched, pass it to extractLocation() otherwise pass all sanitizedLine
71 // because this line doesn't have function name
72 var locationParts = this.extractLocation(location ? location[1] : sanitizedLine);
73 var functionName = location && sanitizedLine || undefined;
74 var fileName = ['eval', '<anonymous>'].indexOf(locationParts[0]) > -1 ? undefined : locationParts[0];
75
76 return new StackFrame({
77 functionName: functionName,
78 fileName: fileName,
79 lineNumber: locationParts[1],
80 columnNumber: locationParts[2],
81 source: line
82 });
83 }, this);
84 },
85
86 parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {
87 var filtered = error.stack.split('\n').filter(function(line) {
88 return !line.match(SAFARI_NATIVE_CODE_REGEXP);
89 }, this);
90
91 return filtered.map(function(line) {
92 // Throw away eval information until we implement stacktrace.js/stackframe#8
93 if (line.indexOf(' > eval') > -1) {
94 line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ':$1');
95 }
96
97 if (line.indexOf('@') === -1 && line.indexOf(':') === -1) {
98 // Safari eval frames only have function names and nothing else
99 return new StackFrame({
100 functionName: line
101 });
102 } else {
103 var functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
104 var matches = line.match(functionNameRegex);
105 var functionName = matches && matches[1] ? matches[1] : undefined;
106 var locationParts = this.extractLocation(line.replace(functionNameRegex, ''));
107
108 return new StackFrame({
109 functionName: functionName,
110 fileName: locationParts[0],
111 lineNumber: locationParts[1],
112 columnNumber: locationParts[2],
113 source: line
114 });
115 }
116 }, this);
117 },
118
119 parseOpera: function ErrorStackParser$$parseOpera(e) {
120 if (!e.stacktrace || (e.message.indexOf('\n') > -1 &&
121 e.message.split('\n').length > e.stacktrace.split('\n').length)) {
122 return this.parseOpera9(e);
123 } else if (!e.stack) {
124 return this.parseOpera10(e);
125 } else {
126 return this.parseOpera11(e);
127 }
128 },
129
130 parseOpera9: function ErrorStackParser$$parseOpera9(e) {
131 var lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
132 var lines = e.message.split('\n');
133 var result = [];
134
135 for (var i = 2, len = lines.length; i < len; i += 2) {
136 var match = lineRE.exec(lines[i]);
137 if (match) {
138 result.push(new StackFrame({
139 fileName: match[2],
140 lineNumber: match[1],
141 source: lines[i]
142 }));
143 }
144 }
145
146 return result;
147 },
148
149 parseOpera10: function ErrorStackParser$$parseOpera10(e) {
150 var lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
151 var lines = e.stacktrace.split('\n');
152 var result = [];
153
154 for (var i = 0, len = lines.length; i < len; i += 2) {
155 var match = lineRE.exec(lines[i]);
156 if (match) {
157 result.push(
158 new StackFrame({
159 functionName: match[3] || undefined,
160 fileName: match[2],
161 lineNumber: match[1],
162 source: lines[i]
163 })
164 );
165 }
166 }
167
168 return result;
169 },
170
171 // Opera 10.65+ Error.stack very similar to FF/Safari
172 parseOpera11: function ErrorStackParser$$parseOpera11(error) {
173 var filtered = error.stack.split('\n').filter(function(line) {
174 return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
175 }, this);
176
177 return filtered.map(function(line) {
178 var tokens = line.split('@');
179 var locationParts = this.extractLocation(tokens.pop());
180 var functionCall = (tokens.shift() || '');
181 var functionName = functionCall
182 .replace(/<anonymous function(: (\w+))?>/, '$2')
183 .replace(/\([^)]*\)/g, '') || undefined;
184 var argsRaw;
185 if (functionCall.match(/\(([^)]*)\)/)) {
186 argsRaw = functionCall.replace(/^[^(]+\(([^)]*)\)$/, '$1');
187 }
188 var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ?
189 undefined : argsRaw.split(',');
190
191 return new StackFrame({
192 functionName: functionName,
193 args: args,
194 fileName: locationParts[0],
195 lineNumber: locationParts[1],
196 columnNumber: locationParts[2],
197 source: line
198 });
199 }, this);
200 }
201 };
202}));
node_modules/error-stack-parser/dist/error-stack-parser.min.js +2 -0
……@@ -0,0 +1,2 @@
1!function(e,t){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],t):"object"==typeof exports?module.exports=t():e.StackFrame=t()}(this,function(){"use strict";function e(e){return e.charAt(0).toUpperCase()+e.substring(1)}function t(e){return function(){return this[e]}}var r=["isConstructor","isEval","isNative","isToplevel"],n=["columnNumber","lineNumber"],i=["fileName","functionName","source"],a=r.concat(n,i,["args"],["evalOrigin"]);function o(t){if(t)for(var r=0;r<a.length;r++)void 0!==t[a[r]]&&this["set"+e(a[r])](t[a[r]])}o.prototype={getArgs:function(){return this.args},setArgs:function(e){if("[object Array]"!==Object.prototype.toString.call(e))throw new TypeError("Args must be an Array");this.args=e},getEvalOrigin:function(){return this.evalOrigin},setEvalOrigin:function(e){if(e instanceof o)this.evalOrigin=e;else{if(!(e instanceof Object))throw new TypeError("Eval Origin must be an Object or StackFrame");this.evalOrigin=new o(e)}},toString:function(){var e=this.getFileName()||"",t=this.getLineNumber()||"",r=this.getColumnNumber()||"",n=this.getFunctionName()||"";return this.getIsEval()?e?"[eval] ("+e+":"+t+":"+r+")":"[eval]:"+t+":"+r:n?n+" ("+e+":"+t+":"+r+")":e+":"+t+":"+r}},o.fromString=function(e){var t=e.indexOf("("),r=e.lastIndexOf(")"),n=e.substring(0,t),i=e.substring(t+1,r).split(","),a=e.substring(r+1);if(0===a.indexOf("@"))var s=/@(.+?)(?::(\d+))?(?::(\d+))?$/.exec(a,""),c=s[1],u=s[2],f=s[3];return new o({functionName:n,args:i||void 0,fileName:c,lineNumber:u||void 0,columnNumber:f||void 0})};for(var s=0;s<r.length;s++)o.prototype["get"+e(r[s])]=t(r[s]),o.prototype["set"+e(r[s])]=function(e){return function(t){this[e]=Boolean(t)}}(r[s]);for(var c=0;c<n.length;c++)o.prototype["get"+e(n[c])]=t(n[c]),o.prototype["set"+e(n[c])]=function(e){return function(t){if(r=t,isNaN(parseFloat(r))||!isFinite(r))throw new TypeError(e+" must be a Number");var r;this[e]=Number(t)}}(n[c]);for(var u=0;u<i.length;u++)o.prototype["get"+e(i[u])]=t(i[u]),o.prototype["set"+e(i[u])]=function(e){return function(t){this[e]=String(t)}}(i[u]);return o}),function(e,t){"use strict";"function"==typeof define&&define.amd?define("error-stack-parser",["stackframe"],t):"object"==typeof exports?module.exports=t(require("stackframe")):e.ErrorStackParser=t(e.StackFrame)}(this,function(e){"use strict";var t=/(^|@)\S+:\d+/,r=/^\s*at .*(\S+:\d+|\(native\))/m,n=/^(eval@)?(\[native code])?$/;return{parse:function(e){if(void 0!==e.stacktrace||void 0!==e["opera#sourceloc"])return this.parseOpera(e);if(e.stack&&e.stack.match(r))return this.parseV8OrIE(e);if(e.stack)return this.parseFFOrSafari(e);throw new Error("Cannot parse given Error object")},extractLocation:function(e){if(-1===e.indexOf(":"))return[e];var t=/(.+?)(?::(\d+))?(?::(\d+))?$/.exec(e.replace(/[()]/g,""));return[t[1],t[2]||void 0,t[3]||void 0]},parseV8OrIE:function(t){return t.stack.split("\n").filter(function(e){return!!e.match(r)},this).map(function(t){t.indexOf("(eval ")>-1&&(t=t.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var r=t.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),n=r.match(/ (\(.+\)$)/);r=n?r.replace(n[0],""):r;var i=this.extractLocation(n?n[1]:r),a=n&&r||void 0,o=["eval","<anonymous>"].indexOf(i[0])>-1?void 0:i[0];return new e({functionName:a,fileName:o,lineNumber:i[1],columnNumber:i[2],source:t})},this)},parseFFOrSafari:function(t){return t.stack.split("\n").filter(function(e){return!e.match(n)},this).map(function(t){if(t.indexOf(" > eval")>-1&&(t=t.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),-1===t.indexOf("@")&&-1===t.indexOf(":"))return new e({functionName:t});var r=/((.*".+"[^@]*)?[^@]*)(?:@)/,n=t.match(r),i=n&&n[1]?n[1]:void 0,a=this.extractLocation(t.replace(r,""));return new e({functionName:i,fileName:a[0],lineNumber:a[1],columnNumber:a[2],source:t})},this)},parseOpera:function(e){return!e.stacktrace||e.message.indexOf("\n")>-1&&e.message.split("\n").length>e.stacktrace.split("\n").length?this.parseOpera9(e):e.stack?this.parseOpera11(e):this.parseOpera10(e)},parseOpera9:function(t){for(var r=/Line (\d+).*script (?:in )?(\S+)/i,n=t.message.split("\n"),i=[],a=2,o=n.length;a<o;a+=2){var s=r.exec(n[a]);s&&i.push(new e({fileName:s[2],lineNumber:s[1],source:n[a]}))}return i},parseOpera10:function(t){for(var r=/Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i,n=t.stacktrace.split("\n"),i=[],a=0,o=n.length;a<o;a+=2){var s=r.exec(n[a]);s&&i.push(new e({functionName:s[3]||void 0,fileName:s[2],lineNumber:s[1],source:n[a]}))}return i},parseOpera11:function(r){return r.stack.split("\n").filter(function(e){return!!e.match(t)&&!e.match(/^Error created at/)},this).map(function(t){var r,n=t.split("@"),i=this.extractLocation(n.pop()),a=n.shift()||"",o=a.replace(/<anonymous function(: (\w+))?>/,"$2").replace(/\([^)]*\)/g,"")||void 0;a.match(/\(([^)]*)\)/)&&(r=a.replace(/^[^(]+\(([^)]*)\)$/,"$1"));var s=void 0===r||"[arguments not available]"===r?void 0:r.split(",");return new e({functionName:o,args:s,fileName:i[0],lineNumber:i[1],columnNumber:i[2],source:t})},this)}}});
2//# sourceMappingURL=error-stack-parser.min.js.map
node_modules/error-stack-parser/dist/error-stack-parser.min.js.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"sources":["node_modules/stackframe/stackframe.js","error-stack-parser.js"],"names":["root","factory","define","amd","exports","module","StackFrame","this","_capitalize","str","charAt","toUpperCase","substring","_getter","p","booleanProps","numericProps","stringProps","props","concat","obj","i","length","undefined","prototype","getArgs","args","setArgs","v","Object","toString","call","TypeError","getEvalOrigin","evalOrigin","setEvalOrigin","fileName","getFileName","lineNumber","getLineNumber","columnNumber","getColumnNumber","functionName","getFunctionName","getIsEval","fromString","argsStartIndex","indexOf","argsEndIndex","lastIndexOf","split","locationString","parts","exec","Boolean","j","n","isNaN","parseFloat","isFinite","Number","k","String","require","ErrorStackParser","FIREFOX_SAFARI_STACK_REGEXP","CHROME_IE_STACK_REGEXP","SAFARI_NATIVE_CODE_REGEXP","parse","error","stacktrace","parseOpera","stack","match","parseV8OrIE","parseFFOrSafari","Error","extractLocation","urlLike","replace","filter","line","map","sanitizedLine","location","locationParts","source","functionNameRegex","matches","e","message","parseOpera9","parseOpera11","parseOpera10","lineRE","lines","result","len","push","argsRaw","tokens","pop","functionCall","shift"],"mappings":"CAAC,SAASA,EAAMC,GACZ,aAIsB,mBAAXC,QAAyBA,OAAOC,IACvCD,OAAO,gBAAkBD,GACC,iBAAZG,QACdC,OAAOD,QAAUH,IAEjBD,EAAKM,WAAaL,IAV1B,CAYEM,KAAM,WACJ,aAKA,SAASC,EAAYC,GACjB,OAAOA,EAAIC,OAAO,GAAGC,cAAgBF,EAAIG,UAAU,GAGvD,SAASC,EAAQC,GACb,OAAO,WACH,OAAOP,KAAKO,IAIpB,IAAIC,GAAgB,gBAAiB,SAAU,WAAY,cACvDC,GAAgB,eAAgB,cAChCC,GAAe,WAAY,eAAgB,UAI3CC,EAAQH,EAAaI,OAAOH,EAAcC,GAH5B,SACC,eAInB,SAASX,EAAWc,GAChB,GAAKA,EACL,IAAK,IAAIC,EAAI,EAAGA,EAAIH,EAAMI,OAAQD,SACRE,IAAlBH,EAAIF,EAAMG,KACVd,KAAK,MAAQC,EAAYU,EAAMG,KAAKD,EAAIF,EAAMG,KAK1Df,EAAWkB,WACPC,QAAS,WACL,OAAOlB,KAAKmB,MAEhBC,QAAS,SAASC,GACd,GAA0C,mBAAtCC,OAAOL,UAAUM,SAASC,KAAKH,GAC/B,MAAM,IAAII,UAAU,yBAExBzB,KAAKmB,KAAOE,GAGhBK,cAAe,WACX,OAAO1B,KAAK2B,YAEhBC,cAAe,SAASP,GACpB,GAAIA,aAAatB,EACbC,KAAK2B,WAAaN,MACf,CAAA,KAAIA,aAAaC,QAGpB,MAAM,IAAIG,UAAU,+CAFpBzB,KAAK2B,WAAa,IAAI5B,EAAWsB,KAMzCE,SAAU,WACN,IAAIM,EAAW7B,KAAK8B,eAAiB,GACjCC,EAAa/B,KAAKgC,iBAAmB,GACrCC,EAAejC,KAAKkC,mBAAqB,GACzCC,EAAenC,KAAKoC,mBAAqB,GAC7C,OAAIpC,KAAKqC,YACDR,EACO,WAAaA,EAAW,IAAME,EAAa,IAAME,EAAe,IAEpE,UAAYF,EAAa,IAAME,EAEtCE,EACOA,EAAe,KAAON,EAAW,IAAME,EAAa,IAAME,EAAe,IAE7EJ,EAAW,IAAME,EAAa,IAAME,IAInDlC,EAAWuC,WAAa,SAAgCpC,GACpD,IAAIqC,EAAiBrC,EAAIsC,QAAQ,KAC7BC,EAAevC,EAAIwC,YAAY,KAE/BP,EAAejC,EAAIG,UAAU,EAAGkC,GAChCpB,EAAOjB,EAAIG,UAAUkC,EAAiB,EAAGE,GAAcE,MAAM,KAC7DC,EAAiB1C,EAAIG,UAAUoC,EAAe,GAElD,GAAoC,IAAhCG,EAAeJ,QAAQ,KACvB,IAAIK,EAAQ,gCAAgCC,KAAKF,EAAgB,IAC7Df,EAAWgB,EAAM,GACjBd,EAAac,EAAM,GACnBZ,EAAeY,EAAM,GAG7B,OAAO,IAAI9C,GACPoC,aAAcA,EACdhB,KAAMA,QAAQH,EACda,SAAUA,EACVE,WAAYA,QAAcf,EAC1BiB,aAAcA,QAAgBjB,KAItC,IAAK,IAAIF,EAAI,EAAGA,EAAIN,EAAaO,OAAQD,IACrCf,EAAWkB,UAAU,MAAQhB,EAAYO,EAAaM,KAAOR,EAAQE,EAAaM,IAClFf,EAAWkB,UAAU,MAAQhB,EAAYO,EAAaM,KAAO,SAAUP,GACnE,OAAO,SAASc,GACZrB,KAAKO,GAAKwC,QAAQ1B,IAFmC,CAI1Db,EAAaM,IAGpB,IAAK,IAAIkC,EAAI,EAAGA,EAAIvC,EAAaM,OAAQiC,IACrCjD,EAAWkB,UAAU,MAAQhB,EAAYQ,EAAauC,KAAO1C,EAAQG,EAAauC,IAClFjD,EAAWkB,UAAU,MAAQhB,EAAYQ,EAAauC,KAAO,SAAUzC,GACnE,OAAO,SAASc,GACZ,GA9GO4B,EA8GQ5B,EA7Gf6B,MAAMC,WAAWF,MAAOG,SAASH,GA8G7B,MAAM,IAAIxB,UAAUlB,EAAI,qBA/GxC,IAAmB0C,EAiHPjD,KAAKO,GAAK8C,OAAOhC,IALoC,CAO1DZ,EAAauC,IAGpB,IAAK,IAAIM,EAAI,EAAGA,EAAI5C,EAAYK,OAAQuC,IACpCvD,EAAWkB,UAAU,MAAQhB,EAAYS,EAAY4C,KAAOhD,EAAQI,EAAY4C,IAChFvD,EAAWkB,UAAU,MAAQhB,EAAYS,EAAY4C,KAAO,SAAU/C,GAClE,OAAO,SAASc,GACZrB,KAAKO,GAAKgD,OAAOlC,IAFmC,CAIzDX,EAAY4C,IAGnB,OAAOvD,IC7IV,SAASN,EAAMC,GACZ,aAIsB,mBAAXC,QAAyBA,OAAOC,IACvCD,OAAO,sBAAuB,cAAeD,GACnB,iBAAZG,QACdC,OAAOD,QAAUH,EAAQ8D,QAAQ,eAEjC/D,EAAKgE,iBAAmB/D,EAAQD,EAAKM,YAV7C,CAYEC,KAAM,SAA0BD,GAC9B,aAEA,IAAI2D,EAA8B,eAC9BC,EAAyB,iCACzBC,EAA4B,8BAEhC,OAOIC,MAAO,SAAiCC,GACpC,QAAgC,IAArBA,EAAMC,iBAAkE,IAA7BD,EAAM,mBACxD,OAAO9D,KAAKgE,WAAWF,GACpB,GAAIA,EAAMG,OAASH,EAAMG,MAAMC,MAAMP,GACxC,OAAO3D,KAAKmE,YAAYL,GACrB,GAAIA,EAAMG,MACb,OAAOjE,KAAKoE,gBAAgBN,GAE5B,MAAM,IAAIO,MAAM,oCAKxBC,gBAAiB,SAA2CC,GAExD,IAA8B,IAA1BA,EAAQ/B,QAAQ,KAChB,OAAQ+B,GAGZ,IACI1B,EADS,+BACMC,KAAKyB,EAAQC,QAAQ,QAAS,KACjD,OAAQ3B,EAAM,GAAIA,EAAM,SAAM7B,EAAW6B,EAAM,SAAM7B,IAGzDmD,YAAa,SAAuCL,GAKhD,OAJeA,EAAMG,MAAMtB,MAAM,MAAM8B,OAAO,SAASC,GACnD,QAASA,EAAKR,MAAMP,IACrB3D,MAEa2E,IAAI,SAASD,GACrBA,EAAKlC,QAAQ,WAAa,IAE1BkC,EAAOA,EAAKF,QAAQ,aAAc,QAAQA,QAAQ,6BAA8B,KAEpF,IAAII,EAAgBF,EAAKF,QAAQ,OAAQ,IAAIA,QAAQ,eAAgB,KAAKA,QAAQ,UAAW,IAIzFK,EAAWD,EAAcV,MAAM,cAGnCU,EAAgBC,EAAWD,EAAcJ,QAAQK,EAAS,GAAI,IAAMD,EAIpE,IAAIE,EAAgB9E,KAAKsE,gBAAgBO,EAAWA,EAAS,GAAKD,GAC9DzC,EAAe0C,GAAYD,QAAiB5D,EAC5Ca,GAAY,OAAQ,eAAeW,QAAQsC,EAAc,KAAO,OAAI9D,EAAY8D,EAAc,GAElG,OAAO,IAAI/E,GACPoC,aAAcA,EACdN,SAAUA,EACVE,WAAY+C,EAAc,GAC1B7C,aAAc6C,EAAc,GAC5BC,OAAQL,KAEb1E,OAGPoE,gBAAiB,SAA2CN,GAKxD,OAJeA,EAAMG,MAAMtB,MAAM,MAAM8B,OAAO,SAASC,GACnD,OAAQA,EAAKR,MAAMN,IACpB5D,MAEa2E,IAAI,SAASD,GAMzB,GAJIA,EAAKlC,QAAQ,YAAc,IAC3BkC,EAAOA,EAAKF,QAAQ,mDAAoD,SAGjD,IAAvBE,EAAKlC,QAAQ,OAAsC,IAAvBkC,EAAKlC,QAAQ,KAEzC,OAAO,IAAIzC,GACPoC,aAAcuC,IAGlB,IAAIM,EAAoB,6BACpBC,EAAUP,EAAKR,MAAMc,GACrB7C,EAAe8C,GAAWA,EAAQ,GAAKA,EAAQ,QAAKjE,EACpD8D,EAAgB9E,KAAKsE,gBAAgBI,EAAKF,QAAQQ,EAAmB,KAEzE,OAAO,IAAIjF,GACPoC,aAAcA,EACdN,SAAUiD,EAAc,GACxB/C,WAAY+C,EAAc,GAC1B7C,aAAc6C,EAAc,GAC5BC,OAAQL,KAGjB1E,OAGPgE,WAAY,SAAsCkB,GAC9C,OAAKA,EAAEnB,YAAemB,EAAEC,QAAQ3C,QAAQ,OAAS,GAC7C0C,EAAEC,QAAQxC,MAAM,MAAM5B,OAASmE,EAAEnB,WAAWpB,MAAM,MAAM5B,OACjDf,KAAKoF,YAAYF,GAChBA,EAAEjB,MAGHjE,KAAKqF,aAAaH,GAFlBlF,KAAKsF,aAAaJ,IAMjCE,YAAa,SAAuCF,GAKhD,IAJA,IAAIK,EAAS,oCACTC,EAAQN,EAAEC,QAAQxC,MAAM,MACxB8C,KAEK3E,EAAI,EAAG4E,EAAMF,EAAMzE,OAAQD,EAAI4E,EAAK5E,GAAK,EAAG,CACjD,IAAIoD,EAAQqB,EAAOzC,KAAK0C,EAAM1E,IAC1BoD,GACAuB,EAAOE,KAAK,IAAI5F,GACZ8B,SAAUqC,EAAM,GAChBnC,WAAYmC,EAAM,GAClBa,OAAQS,EAAM1E,MAK1B,OAAO2E,GAGXH,aAAc,SAAwCJ,GAKlD,IAJA,IAAIK,EAAS,6DACTC,EAAQN,EAAEnB,WAAWpB,MAAM,MAC3B8C,KAEK3E,EAAI,EAAG4E,EAAMF,EAAMzE,OAAQD,EAAI4E,EAAK5E,GAAK,EAAG,CACjD,IAAIoD,EAAQqB,EAAOzC,KAAK0C,EAAM1E,IAC1BoD,GACAuB,EAAOE,KACH,IAAI5F,GACAoC,aAAc+B,EAAM,SAAMlD,EAC1Ba,SAAUqC,EAAM,GAChBnC,WAAYmC,EAAM,GAClBa,OAAQS,EAAM1E,MAM9B,OAAO2E,GAIXJ,aAAc,SAAwCvB,GAKlD,OAJeA,EAAMG,MAAMtB,MAAM,MAAM8B,OAAO,SAASC,GACnD,QAASA,EAAKR,MAAMR,KAAiCgB,EAAKR,MAAM,sBACjElE,MAEa2E,IAAI,SAASD,GACzB,IAMIkB,EANAC,EAASnB,EAAK/B,MAAM,KACpBmC,EAAgB9E,KAAKsE,gBAAgBuB,EAAOC,OAC5CC,EAAgBF,EAAOG,SAAW,GAClC7D,EAAe4D,EACdvB,QAAQ,iCAAkC,MAC1CA,QAAQ,aAAc,UAAOxD,EAE9B+E,EAAa7B,MAAM,iBACnB0B,EAAUG,EAAavB,QAAQ,qBAAsB,OAEzD,IAAIrD,OAAoBH,IAAZ4E,GAAqC,8BAAZA,OACjC5E,EAAY4E,EAAQjD,MAAM,KAE9B,OAAO,IAAI5C,GACPoC,aAAcA,EACdhB,KAAMA,EACNU,SAAUiD,EAAc,GACxB/C,WAAY+C,EAAc,GAC1B7C,aAAc6C,EAAc,GAC5BC,OAAQL,KAEb1E"}
node_modules/error-stack-parser/error-stack-parser.d.ts +19 -0
……@@ -0,0 +1,19 @@
1// Type definitions for ErrorStackParser v2.1.0
2// Project: https://github.com/stacktracejs/error-stack-parser
3// Definitions by: Eric Wendelin <https://www.eriwen.com>
4// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5
6import StackFrame = require("stackframe");
7
8declare namespace ErrorStackParser {
9 export type {StackFrame};
10 /**
11 * Given an Error object, extract the most information from it.
12 *
13 * @param {Error} error object
14 * @return {Array} of StackFrames
15 */
16 export function parse(error: Error): StackFrame[];
17}
18
19export = ErrorStackParser;
node_modules/error-stack-parser/error-stack-parser.js +202 -0
……@@ -0,0 +1,202 @@
1(function(root, factory) {
2 'use strict';
3 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
4
5 /* istanbul ignore next */
6 if (typeof define === 'function' && define.amd) {
7 define('error-stack-parser', ['stackframe'], factory);
8 } else if (typeof exports === 'object') {
9 module.exports = factory(require('stackframe'));
10 } else {
11 root.ErrorStackParser = factory(root.StackFrame);
12 }
13}(this, function ErrorStackParser(StackFrame) {
14 'use strict';
15
16 var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+:\d+/;
17 var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
18 var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
19
20 return {
21 /**
22 * Given an Error object, extract the most information from it.
23 *
24 * @param {Error} error object
25 * @return {Array} of StackFrames
26 */
27 parse: function ErrorStackParser$$parse(error) {
28 if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {
29 return this.parseOpera(error);
30 } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {
31 return this.parseV8OrIE(error);
32 } else if (error.stack) {
33 return this.parseFFOrSafari(error);
34 } else {
35 throw new Error('Cannot parse given Error object');
36 }
37 },
38
39 // Separate line and column numbers from a string of the form: (URI:Line:Column)
40 extractLocation: function ErrorStackParser$$extractLocation(urlLike) {
41 // Fail-fast but return locations like "(native)"
42 if (urlLike.indexOf(':') === -1) {
43 return [urlLike];
44 }
45
46 var regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
47 var parts = regExp.exec(urlLike.replace(/[()]/g, ''));
48 return [parts[1], parts[2] || undefined, parts[3] || undefined];
49 },
50
51 parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {
52 var filtered = error.stack.split('\n').filter(function(line) {
53 return !!line.match(CHROME_IE_STACK_REGEXP);
54 }, this);
55
56 return filtered.map(function(line) {
57 if (line.indexOf('(eval ') > -1) {
58 // Throw away eval information until we implement stacktrace.js/stackframe#8
59 line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(,.*$)/g, '');
60 }
61 var sanitizedLine = line.replace(/^\s+/, '').replace(/\(eval code/g, '(').replace(/^.*?\s+/, '');
62
63 // capture and preseve the parenthesized location "(/foo/my bar.js:12:87)" in
64 // case it has spaces in it, as the string is split on \s+ later on
65 var location = sanitizedLine.match(/ (\(.+\)$)/);
66
67 // remove the parenthesized location from the line, if it was matched
68 sanitizedLine = location ? sanitizedLine.replace(location[0], '') : sanitizedLine;
69
70 // if a location was matched, pass it to extractLocation() otherwise pass all sanitizedLine
71 // because this line doesn't have function name
72 var locationParts = this.extractLocation(location ? location[1] : sanitizedLine);
73 var functionName = location && sanitizedLine || undefined;
74 var fileName = ['eval', '<anonymous>'].indexOf(locationParts[0]) > -1 ? undefined : locationParts[0];
75
76 return new StackFrame({
77 functionName: functionName,
78 fileName: fileName,
79 lineNumber: locationParts[1],
80 columnNumber: locationParts[2],
81 source: line
82 });
83 }, this);
84 },
85
86 parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {
87 var filtered = error.stack.split('\n').filter(function(line) {
88 return !line.match(SAFARI_NATIVE_CODE_REGEXP);
89 }, this);
90
91 return filtered.map(function(line) {
92 // Throw away eval information until we implement stacktrace.js/stackframe#8
93 if (line.indexOf(' > eval') > -1) {
94 line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ':$1');
95 }
96
97 if (line.indexOf('@') === -1 && line.indexOf(':') === -1) {
98 // Safari eval frames only have function names and nothing else
99 return new StackFrame({
100 functionName: line
101 });
102 } else {
103 var functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
104 var matches = line.match(functionNameRegex);
105 var functionName = matches && matches[1] ? matches[1] : undefined;
106 var locationParts = this.extractLocation(line.replace(functionNameRegex, ''));
107
108 return new StackFrame({
109 functionName: functionName,
110 fileName: locationParts[0],
111 lineNumber: locationParts[1],
112 columnNumber: locationParts[2],
113 source: line
114 });
115 }
116 }, this);
117 },
118
119 parseOpera: function ErrorStackParser$$parseOpera(e) {
120 if (!e.stacktrace || (e.message.indexOf('\n') > -1 &&
121 e.message.split('\n').length > e.stacktrace.split('\n').length)) {
122 return this.parseOpera9(e);
123 } else if (!e.stack) {
124 return this.parseOpera10(e);
125 } else {
126 return this.parseOpera11(e);
127 }
128 },
129
130 parseOpera9: function ErrorStackParser$$parseOpera9(e) {
131 var lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
132 var lines = e.message.split('\n');
133 var result = [];
134
135 for (var i = 2, len = lines.length; i < len; i += 2) {
136 var match = lineRE.exec(lines[i]);
137 if (match) {
138 result.push(new StackFrame({
139 fileName: match[2],
140 lineNumber: match[1],
141 source: lines[i]
142 }));
143 }
144 }
145
146 return result;
147 },
148
149 parseOpera10: function ErrorStackParser$$parseOpera10(e) {
150 var lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
151 var lines = e.stacktrace.split('\n');
152 var result = [];
153
154 for (var i = 0, len = lines.length; i < len; i += 2) {
155 var match = lineRE.exec(lines[i]);
156 if (match) {
157 result.push(
158 new StackFrame({
159 functionName: match[3] || undefined,
160 fileName: match[2],
161 lineNumber: match[1],
162 source: lines[i]
163 })
164 );
165 }
166 }
167
168 return result;
169 },
170
171 // Opera 10.65+ Error.stack very similar to FF/Safari
172 parseOpera11: function ErrorStackParser$$parseOpera11(error) {
173 var filtered = error.stack.split('\n').filter(function(line) {
174 return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
175 }, this);
176
177 return filtered.map(function(line) {
178 var tokens = line.split('@');
179 var locationParts = this.extractLocation(tokens.pop());
180 var functionCall = (tokens.shift() || '');
181 var functionName = functionCall
182 .replace(/<anonymous function(: (\w+))?>/, '$2')
183 .replace(/\([^)]*\)/g, '') || undefined;
184 var argsRaw;
185 if (functionCall.match(/\(([^)]*)\)/)) {
186 argsRaw = functionCall.replace(/^[^(]+\(([^)]*)\)$/, '$1');
187 }
188 var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ?
189 undefined : argsRaw.split(',');
190
191 return new StackFrame({
192 functionName: functionName,
193 args: args,
194 fileName: locationParts[0],
195 lineNumber: locationParts[1],
196 columnNumber: locationParts[2],
197 source: line
198 });
199 }, this);
200 }
201 };
202}));
node_modules/error-stack-parser/package.json +63 -0
……@@ -0,0 +1,63 @@
1{
2 "name": "error-stack-parser",
3 "description": "Extract meaning from JS Errors",
4 "maintainers": [
5 "Eric Wendelin <me@eriwen.com> (https://www.eriwen.com)",
6 "Victor Homyakov <vkhomyackov@gmail.com> (https://github.com/victor-homyakov)",
7 "Oliver Salzburg (https://github.com/oliversalzburg)",
8 "Ben Gourley (https://github.com/bengourley)"
9 ],
10 "version": "2.1.4",
11 "license": "MIT",
12 "keywords": [
13 "stacktrace",
14 "error",
15 "stack",
16 "parser"
17 ],
18 "homepage": "https://www.stacktracejs.com",
19 "dependencies": {
20 "stackframe": "^1.3.4"
21 },
22 "repository": {
23 "type": "git",
24 "url": "git://github.com/stacktracejs/error-stack-parser.git"
25 },
26 "devDependencies": {
27 "eslint": "^8.17.0",
28 "jasmine": "^4.1.0",
29 "jasmine-core": "^4.1.1",
30 "karma": "^6.3.20",
31 "karma-chrome-launcher": "^3.1.1",
32 "karma-coverage": "^2.2.0",
33 "karma-coveralls": "^2.1.0",
34 "karma-firefox-launcher": "^2.1.2",
35 "karma-ie-launcher": "^1.0.0",
36 "karma-jasmine": "^4.0.2",
37 "karma-opera-launcher": "^1.0.0",
38 "karma-phantomjs-launcher": "^1.0.4",
39 "karma-safari-launcher": "^1.0.0",
40 "karma-sauce-launcher": "^4.3.6",
41 "karma-spec-reporter": "^0.0.34",
42 "uglify-es": "^3.3.9"
43 },
44 "bugs": {
45 "url": "https://github.com/stacktracejs/error-stack-parser/issues"
46 },
47 "main": "./error-stack-parser.js",
48 "typings": "./error-stack-parser.d.ts",
49 "files": [
50 "LICENSE",
51 "README.md",
52 "error-stack-parser.js",
53 "error-stack-parser.d.ts",
54 "dist/"
55 ],
56 "scripts": {
57 "lint": "eslint --fix .",
58 "test": "karma start karma.conf.js --single-run",
59 "test-pr": "karma start karma.conf.js --single-run --browsers Firefox,Chrome_No_Sandbox",
60 "test-ci": "karma start karma.conf.ci.js --single-run",
61 "prepare": "cp error-stack-parser.js dist/ && uglifyjs node_modules/stackframe/stackframe.js error-stack-parser.js -o dist/error-stack-parser.min.js --compress --mangle --source-map \"url=error-stack-parser.min.js.map\""
62 }
63}
node_modules/globbie/.github/workflows/test-bare.yml +44 -0
……@@ -0,0 +1,44 @@
1name: Test with Bare
2
3on:
4 push:
5 branches: [ main ]
6 pull_request:
7 branches: [ main ]
8
9jobs:
10 test:
11 strategy:
12 matrix:
13 include:
14 - os: ubuntu-latest
15 platform: linux
16 arch: x64
17
18 - os: macos-latest
19 platform: darwin
20 arch: x64
21
22 - os: windows-latest
23 platform: win32
24 arch: x64
25
26 runs-on: ${{ matrix.os }}
27 name: ${{ matrix.platform }}-${{ matrix.arch }}
28 steps:
29 - uses: actions/checkout@v4
30
31 - name: Setup Node.js
32 uses: actions/setup-node@v4
33
34 - name: Setup bare
35 run: npm i -g bare-runtime
36
37 - name: Install dependencies
38 run: npm i
39
40 - name: Lint
41 run: npm run lint
42
43 - name: Run tests
44 run: npm run test:bare
node_modules/globbie/.github/workflows/test-node.yml +41 -0
……@@ -0,0 +1,41 @@
1name: Test with Node
2
3on:
4 push:
5 branches: [ main ]
6 pull_request:
7 branches: [ main ]
8
9jobs:
10 test:
11 strategy:
12 matrix:
13 include:
14 - os: ubuntu-latest
15 platform: linux
16 arch: x64
17
18 - os: macos-latest
19 platform: darwin
20 arch: x64
21
22 - os: windows-latest
23 platform: win32
24 arch: x64
25
26 runs-on: ${{ matrix.os }}
27 name: ${{ matrix.platform }}-${{ matrix.arch }}
28 steps:
29 - uses: actions/checkout@v4
30
31 - name: Setup Node.js
32 uses: actions/setup-node@v4
33
34 - name: Install dependencies
35 run: npm i
36
37 - name: Lint
38 run: npm run lint
39
40 - name: Run tests
41 run: npm test
node_modules/globbie/LICENSE +202 -0
……@@ -0,0 +1,202 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
202
node_modules/globbie/NOTICE +13 -0
……@@ -0,0 +1,13 @@
1Copyright 2023-2024 Holepunch Inc
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
node_modules/globbie/README.md +22 -0
……@@ -0,0 +1,22 @@
1# globbie
2A simple directory glob matcher using picomatch
3
4## Usage
5```js
6const Globbie = require('globbie')
7
8const pattern = 'src/**/*.js'
9
10const globbie = new Globbie(pattern)
11await globbie.match() // => ['src/index.js', 'src/utils/index.js', ...]
12
13const globbieSync = new Globbie(pattern, { sync: true })
14globbie.match() // => ['src/index.js', 'src/utils/index.js', ...]
15```
16
17## Options
18The following options are available to be set in the `options` object:
19- `sync` (boolean, default: `false`): Whether to use async or sync methods when running match
20
21## License
22Apache-2.0
node_modules/globbie/index.js +48 -0
……@@ -0,0 +1,48 @@
1const fs = require('fs')
2const path = require('path')
3const picomatch = require('picomatch')
4const process = require('process')
5
6class Globbie {
7 constructor (pattern, { sync = false } = {}) {
8 this._isMatch = picomatch(pattern, { windows: process.platform === 'win32' })
9 this._sync = sync
10 }
11
12 match (dir = '.') {
13 return this._sync ? this.#matchSync(dir) : this.#matchAsync(dir)
14 }
15
16 #matchSync (dir = '.') {
17 const matches = []
18 for (const file of fs.readdirSync(dir)) {
19 const filePath = path.join(dir, file)
20 if (fs.lstatSync(filePath).isDirectory()) matches.push(...this.match(filePath))
21 else if (this._isMatch(filePath)) matches.push(filePath)
22 }
23
24 return matches
25 }
26
27 async #matchAsync (dir = '.') {
28 const files = await fs.promises.readdir(dir)
29
30 const matches = []
31 const promises = files.map(async (file) => {
32 const filePath = path.join(dir, file)
33
34 if ((await fs.promises.lstat(filePath)).isDirectory()) matches.push(...(await this.#matchAsync(filePath)))
35 else if (this._isMatch(filePath)) matches.push(filePath)
36 })
37
38 for (const promise of promises) promise.catch(() => {})
39
40 const results = await Promise.allSettled(promises)
41 const error = results.find(({ status }) => status === 'rejected')?.reason
42 if (error) throw error
43
44 return matches
45 }
46}
47
48module.exports = Globbie
node_modules/globbie/package.json +47 -0
……@@ -0,0 +1,47 @@
1{
2 "name": "globbie",
3 "version": "1.0.3",
4 "description": "Simple directory globbing using picomatch",
5 "main": "index.js",
6 "scripts": {
7 "test": "node test/globbie.test.js",
8 "test:bare": "bare test/globbie.test.js",
9 "lint": "standard"
10 },
11 "repository": {
12 "type": "git",
13 "url": "git+https://github.com/holepunchto/globbie.git"
14 },
15 "keywords": [
16 "globbie",
17 "glob",
18 "picomatch"
19 ],
20 "author": "Holepunch",
21 "license": "Apache-2.0",
22 "bugs": {
23 "url": "https://github.com/holepunchto/globbie/issues"
24 },
25 "homepage": "https://github.com/holepunchto/globbie#readme",
26 "imports": {
27 "fs": {
28 "bare": "bare-fs"
29 },
30 "path": {
31 "bare": "bare-path"
32 },
33 "process": {
34 "bare": "bare-process"
35 }
36 },
37 "dependencies": {
38 "bare-fs": "^4.1.2",
39 "bare-path": "^3.0.0",
40 "bare-process": "^4.2.1",
41 "picomatch": "^4.0.2"
42 },
43 "devDependencies": {
44 "brittle": "^3.16.2",
45 "standard": "^17.1.0"
46 }
47}
node_modules/globbie/test/fixtures/rootfile-1.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/rootfile-2.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/rootfile-3.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/rootfile-invalid.ts +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subpathfile-1.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subpathfile-2.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subpathfile-3.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subpathfile-invalid.ts +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subsubpath/subsubpathfile-1.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subsubpath/subsubpathfile-2.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subsubpath/subsubpathfile-3.js +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/fixtures/subpath/subsubpath/subsubpathfile-invalid.ts +0 -0
(no content changes — binary or rename)
node_modules/globbie/test/globbie.test.js +133 -0
……@@ -0,0 +1,133 @@
1const Globbie = require('../index')
2const path = require('path')
3const test = require('brittle')
4const process = require('process')
5
6process.chdir(path.join(__dirname, 'fixtures'))
7
8function toPlatformPaths (paths) {
9 return process.platform === 'win32' ? paths.map(p => p.replace(/\//g, path.sep)) : paths
10}
11
12test('match all js files', async (t) => {
13 const g = new Globbie('**.js', { sync: true })
14 const matches = g.match()
15
16 t.alike(matches.sort(), toPlatformPaths([
17 'rootfile-1.js',
18 'rootfile-2.js',
19 'rootfile-3.js',
20 'subpath/subpathfile-1.js',
21 'subpath/subpathfile-2.js',
22 'subpath/subpathfile-3.js',
23 'subpath/subsubpath/subsubpathfile-1.js',
24 'subpath/subsubpath/subsubpathfile-2.js',
25 'subpath/subsubpath/subsubpathfile-3.js'
26 ]))
27})
28
29test('match all js and ts files', async (t) => {
30 const g = new Globbie('**/*.{js,ts}', { sync: true })
31 const matches = g.match()
32
33 t.alike(matches.sort(), toPlatformPaths([
34 'rootfile-1.js',
35 'rootfile-2.js',
36 'rootfile-3.js',
37 'rootfile-invalid.ts',
38 'subpath/subpathfile-1.js',
39 'subpath/subpathfile-2.js',
40 'subpath/subpathfile-3.js',
41 'subpath/subpathfile-invalid.ts',
42 'subpath/subsubpath/subsubpathfile-1.js',
43 'subpath/subsubpath/subsubpathfile-2.js',
44 'subpath/subsubpath/subsubpathfile-3.js',
45 'subpath/subsubpath/subsubpathfile-invalid.ts'
46 ]))
47})
48
49test('match only subpath js files', async (t) => {
50 const g = new Globbie('subpath/**/*.js', { sync: true })
51 const matches = g.match()
52
53 t.alike(matches.sort(), toPlatformPaths([
54 'subpath/subpathfile-1.js',
55 'subpath/subpathfile-2.js',
56 'subpath/subpathfile-3.js',
57 'subpath/subsubpath/subsubpathfile-1.js',
58 'subpath/subsubpath/subsubpathfile-2.js',
59 'subpath/subsubpath/subsubpathfile-3.js'
60 ]))
61})
62
63test('match only subpath js files - dir set to subsubpath', async (t) => {
64 const g = new Globbie('subpath/**/*.js', { sync: true })
65 const matches = g.match('subpath/subsubpath')
66
67 t.alike(matches.sort(), toPlatformPaths([
68 'subpath/subsubpath/subsubpathfile-1.js',
69 'subpath/subsubpath/subsubpathfile-2.js',
70 'subpath/subsubpath/subsubpathfile-3.js'
71 ]))
72})
73
74test('async match all js files', async (t) => {
75 const g = new Globbie('**.js')
76 const matches = await g.match()
77 t.alike(matches.sort(), toPlatformPaths([
78 'rootfile-1.js',
79 'rootfile-2.js',
80 'rootfile-3.js',
81 'subpath/subpathfile-1.js',
82 'subpath/subpathfile-2.js',
83 'subpath/subpathfile-3.js',
84 'subpath/subsubpath/subsubpathfile-1.js',
85 'subpath/subsubpath/subsubpathfile-2.js',
86 'subpath/subsubpath/subsubpathfile-3.js'
87 ]))
88})
89
90test('async match all js and ts files', async (t) => {
91 const g = new Globbie('**/*.{js,ts}')
92 const matches = await g.match()
93
94 t.alike(matches.sort(), toPlatformPaths([
95 'rootfile-1.js',
96 'rootfile-2.js',
97 'rootfile-3.js',
98 'rootfile-invalid.ts',
99 'subpath/subpathfile-1.js',
100 'subpath/subpathfile-2.js',
101 'subpath/subpathfile-3.js',
102 'subpath/subpathfile-invalid.ts',
103 'subpath/subsubpath/subsubpathfile-1.js',
104 'subpath/subsubpath/subsubpathfile-2.js',
105 'subpath/subsubpath/subsubpathfile-3.js',
106 'subpath/subsubpath/subsubpathfile-invalid.ts'
107 ]))
108})
109
110test('async match only subpath', async (t) => {
111 const g = new Globbie('subpath/**/*.js')
112 const matches = await g.match()
113
114 t.alike(matches.sort(), toPlatformPaths([
115 'subpath/subpathfile-1.js',
116 'subpath/subpathfile-2.js',
117 'subpath/subpathfile-3.js',
118 'subpath/subsubpath/subsubpathfile-1.js',
119 'subpath/subsubpath/subsubpathfile-2.js',
120 'subpath/subsubpath/subsubpathfile-3.js'
121 ]))
122})
123
124test('async match only subpath js files - dir set to subsubpath', async (t) => {
125 const g = new Globbie('subpath/**/*.js')
126 const matches = await g.match('subpath/subsubpath')
127
128 t.alike(matches.sort(), toPlatformPaths([
129 'subpath/subsubpath/subsubpathfile-1.js',
130 'subpath/subsubpath/subsubpathfile-2.js',
131 'subpath/subsubpath/subsubpathfile-3.js'
132 ]))
133})
node_modules/hyperdht/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2018-2019 Mathias Buus, David Mark Clements & Contributors
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/hyperdht/README.md +334 -0
……@@ -0,0 +1,334 @@
1# hyperdht
2
3### [See the full API docs at docs.pears.com](https://docs.pears.com/building-blocks/hyperdht)
4
5The DHT powering Hyperswarm
6
7```
8npm install hyperdht
9```
10
11Built on top of [dht-rpc](https://github.com/mafintosh/dht-rpc).
12
13The Hyperswarm DHT uses a series of holepunching techniques to make sure connectivity works on most networks,
14and is mainly used to facilitate finding and connecting to peers using end to end encrypted Noise streams.
15
16## Usage
17
18To try it out, first instantiate a DHT instance
19
20```js
21import DHT from 'hyperdht'
22
23const node = new DHT()
24```
25
26Then on one computer listen for connections
27
28```js
29// create a server to listen for secure connections
30const server = node.createServer()
31
32server.on('connection', function (socket) {
33 // socket is E2E encrypted between you and the other peer
34 console.log('Remote public key', socket.remotePublicKey)
35
36 // pipe it somewhere like any duplex stream
37 process.stdin.pipe(socket).pipe(process.stdout)
38})
39
40// make a ed25519 keypair to listen on
41const keyPair = DHT.keyPair()
42
43// this makes the server accept connections on this keypair
44await server.listen(keyPair)
45```
46
47Then on another connect to the computer using the public key of the key-pair it is listening on
48
49```js
50// publicKey here is keyPair.publicKey from above
51const socket = anotherNode.connect(publicKey)
52
53socket.on('open', function () {
54 // socket fully open with the other peer
55})
56
57// pipe it somewhere like any duplex stream
58process.stdin.pipe(socket).pipe(process.stdout)
59```
60
61## API
62
63#### `const node = new DHT([options])`
64
65Create a new DHT node.
66
67Options include:
68
69```js
70{
71 // Optionally overwrite the default bootstrap servers, just need to be an array of any known dht node(s)
72 // Defaults to Pear.config.dht.bootstrap in a Pear app or ['88.99.3.86@node1.hyperdht.org:49737', '142.93.90.113@node2.hyperdht.org:49737', '138.68.147.8@node3.hyperdht.org:49737'] elsewhere
73 // Supports suggested-IP to avoid DNS calls: [suggested-IP@]<host>:<port>
74 bootstrap: ['host:port'],
75 keyPair, // set the default key pair to use for server.listen and connect
76 connectionKeepAlive, // set a default keep-alive (in ms) on all opened sockets. Defaults to 5000. Set false to turn off (advanced usage).
77 randomPunchInterval: 20000 // set a default time for interval between punches (in ms). Defaults to 20000.
78
79}
80```
81
82See [dht-rpc](https://github.com/mafintosh/dht-rpc) for more options as HyperDHT inherits from that.
83
84_Note:_ The default bootstrap servers are publicly served on behalf of the commons. To run a fully isolated DHT, start one or more dht nodes with an empty bootstrap array (`new DHT({bootstrap:[]})`) and then use the addresses of those nodes as the `bootstrap` option in all other dht nodes. You'll need at least one persistent node for the network to be completely operational.
85
86#### `keyPair = DHT.keyPair([seed])`
87
88Use this method to generate the required keypair for DHT operations.
89
90Returns an object with `{publicKey, secretKey}`. `publicKey` holds a public key buffer, `secretKey` holds a private key buffer.
91
92If you pass any options they are forwarded to dht-rpc.
93
94#### `await node.destroy([options])`
95
96Fully destroy this DHT node.
97
98This will also unannounce any running servers.
99If you want to force close the node without waiting for the servers to unannounce pass `{ force: true }`.
100
101#### `node = DHT.bootstrapper(port, host, [options])`
102
103If you want to run your own Hyperswarm network use this method to easily create a bootstrap node.
104
105## Creating P2P servers
106
107#### `const server = node.createServer([options], [onconnection])`
108
109Create a new server for accepting incoming encrypted P2P connections.
110
111Options include:
112
113```js
114{
115 firewall (remotePublicKey, remoteHandshakePayload) {
116 // validate if you want a connection from remotePublicKey
117 // if you do return false, else return true
118 // remoteHandshakePayload contains their ip and some more info
119 return true
120 }
121}
122```
123
124You can run servers on normal home computers, as the DHT will UDP holepunch connections for you.
125
126#### `await server.listen(keyPair)`
127
128Make the server listen on a keyPair.
129To connect to this server use keyPair.publicKey as the connect address.
130
131#### `server.refresh()`
132
133Refresh the server, causing it to reannounce its address. This is automatically called on network changes.
134
135#### `server.on('connection', socket)`
136
137Emitted when a new encrypted connection has passed the firewall check.
138
139`socket` is a [NoiseSecretStream](https://github.com/holepunchto/hyperswarm-secret-stream) instance.
140
141You can check who you are connected to using `socket.remotePublicKey` and `socket.handshakeHash` contains a unique hash representing this crypto session (same on both sides).
142
143#### `server.on('listening')`
144
145Emitted when the server is fully listening on a keyPair.
146
147#### `server.address()`
148
149Returns an object containing the address of the server:
150
151```js
152{
153 ;(host, // external IP of the server,
154 port, // external port of the server if predictable,
155 publicKey) // public key of the server
156}
157```
158
159You can also get this info from `node.remoteAddress()` minus the public key.
160
161#### `await server.close()`
162
163Stop listening.
164
165#### `server.on('close')`
166
167Emitted when the server is fully closed.
168
169## Connecting to P2P servers
170
171#### `const socket = node.connect(remotePublicKey, [options])`
172
173Connect to a remote server. Similar to `createServer` this performs UDP holepunching for P2P connectivity.
174
175The remote public key can be encoded as either a buffer, a hex string or a z-base32 string.
176
177Options include:
178
179```js
180{
181 nodes: [...], // optional array of close dht nodes to speed up connecting
182 keyPair // optional key pair to use when connection (defaults to node.defaultKeyPair)
183}
184```
185
186#### `socket.on('open')`
187
188Emitted when the encrypted connection has been fully established with the server.
189
190#### `socket.remotePublicKey`
191
192The public key of the remote peer.
193
194#### `socket.publicKey`
195
196The public key of the local socket.
197
198## Additional peer discovery
199
200#### `const stream = node.lookup(topic, [options])`
201
202Look for peers in the DHT on the given topic. Topic should be a 32 byte buffer (normally a hash of something).
203
204The returned stream looks like this
205
206```js
207{
208 // Who sent the response?
209 from: { id, host, port },
210 // What address they responded to (i.e. your address)
211 to: { host, port },
212 // List of peers announcing under this topic
213 peers: [ { publicKey, nodes: [{ host, port }, ...] } ]
214}
215```
216
217To connect to the peers you should afterwards call `connect` with those public keys.
218
219If you pass any options they are forwarded to dht-rpc.
220
221#### `const stream = node.announce(topic, keyPair, [relayAddresses], [options])`
222
223Announce that you are listening on a key-pair to the DHT under a specific topic.
224
225When announcing you'll send a signed proof to peers that you own the key-pair and wish to announce under the specific topic. Optionally you can provide up to 3 nodes, indicating which DHT nodes can relay messages to you - this speeds up connects later on for other users.
226
227An announce does a parallel lookup so the stream returned looks like the lookup stream.
228
229Creating a server using `dht.createServer` automatically announces itself periodically on the key-pair it is listening on. When announcing the server under a specific topic, you can access the nodes it is close to using `server.nodes`.
230
231If you pass any options they are forwarded to dht-rpc.
232
233#### `await node.unannounce(topic, keyPair, [options])`
234
235Unannounce a key-pair.
236
237If you pass any options they are forwarded to dht-rpc.
238
239## Mutable/immutable records
240
241#### `const { hash, closestNodes } = await node.immutablePut(value, [options])`
242
243Store an immutable value in the DHT. When successful, the hash of the value is returned.
244
245If you pass any options they are forwarded to dht-rpc.
246
247#### `const { value, from } = await node.immutableGet(hash, [options])`
248
249Fetch an immutable value from the DHT. When successful, it returns the value corresponding to the hash.
250
251If you pass any options they are forwarded to dht-rpc.
252
253#### `const { publicKey, closestNodes, seq, signature } = await node.mutablePut(keyPair, value, [options])`
254
255Store a mutable value in the DHT.
256
257If you pass any options they are forwarded to dht-rpc.
258
259#### `const { value, from, seq, signature } = await node.mutableGet(publicKey, [options])`
260
261Fetch a mutable value from the DHT.
262
263Options:
264
265- `seq` - OPTIONAL, default `0`, a number which will only return values with corresponding `seq` values that are greater than or equal to the supplied `seq` option.
266- `latest` - OPTIONAL - default `false`, a boolean indicating whether the query should try to find the highest seq before returning, or just the first verified value larger than `options.seq` it sees.
267
268Any additional options you pass are forwarded to dht-rpc.
269
270## Additional API
271
272See [dht-rpc](https://github.com/mafintosh/dht-rpc) for the additional APIs the DHT exposes.
273
274## CLI
275
276You can start a DHT node in the command line:
277
278```sh
279npm install -g hyperdht
280```
281
282Run a DHT node:
283
284```sh
285hyperdht # [--port 0] [--host 0.0.0.0] [--bootstrap <comma separated list of ip:port>]
286```
287
288Or run multiple nodes:
289
290```sh
291hyperdht --nodes 5 # [--host 0.0.0.0] [--bootstrap <list>]
292```
293
294Note: by default it uses the [mainnet bootstrap nodes](lib/constants.js).
295
296#### Isolated DHT network
297
298To create your own DHT network is as follows:
299
3001. Run your first bootstrap node:
301
302```sh
303hyperdht --bootstrap --host (server-ip) # [--port 49737]
304```
305
306Important: it requires the port to be open.
307
308Now your bootstrap node is ready to use at `(server-ip):49737`, for example:
309
310```js
311const dht = new DHT({ bootstrap: ['(server-ip):49737'] })
312```
313
314Note: You could configure some DNS for the bootstrap IP addresses.
315
316For the network to be fully operational it needs at least one persistent node.
317
3182. Provide the first node by using your own bootstrap values:
319
320```sh
321hyperdht --port 49738 --bootstrap (server-ip):49737
322```
323
324Important: it requires the port to be open too.
325
326You need to wait ~30 mins for the node to become persistent.
327
328Having persistent nodes in different places makes the network more decentralized and resilient!
329
330For more information: [`examples/isolated-dht.mjs`](examples/isolated-dht.mjs)
331
332## License
333
334MIT
node_modules/hyperdht/bin.js +83 -0
……@@ -0,0 +1,83 @@
1#!/usr/bin/env node
2
3const HyperDHT = require('./')
4
5const bootstrap = arg('bootstrap')
6const nodes = arg('node') ? '' : arg('nodes')
7
8const isBootstrap = bootstrap === '' || (bootstrap !== null && bootstrap.startsWith('--'))
9
10if (isBootstrap) {
11 const port = Number(arg('port') || '0') || 49737
12 const host = arg('host')
13 if (!host) throw new Error('You need to specify --host <node ip>')
14 startBootstrapNode(port, host)
15} else {
16 startNodes(Number(nodes) || 1, bootstrap ? bootstrap.split(',') : undefined)
17}
18
19function arg(name) {
20 const i = process.argv.indexOf('--' + name)
21 if (i === -1) return null
22 return i < process.argv.length - 1 ? process.argv[i + 1] : ''
23}
24
25async function startBootstrapNode(port, host) {
26 console.log('Starting DHT bootstrap node...')
27
28 const node = HyperDHT.bootstrapper(port, host)
29 await node.ready()
30
31 node.on('close', function () {
32 console.log('Bootstrap node closed')
33 })
34
35 console.log('Bootstrap node bound to', node.address())
36 console.log('Fully started Hyperswarm DHT bootstrap node')
37
38 process.once('SIGINT', function () {
39 node.destroy()
40 })
41}
42
43async function startNodes(cnt, bootstrap) {
44 console.log('Booting DHT nodes...')
45
46 const port = Number(arg('port') || '0') || 0
47 const host = arg('host') || undefined
48 const all = []
49
50 if (port && cnt !== 1) throw new Error('--port is only valid when running a single node')
51
52 while (all.length < cnt) {
53 const node = new HyperDHT({ host, port, anyPort: !port, bootstrap })
54 await node.ready()
55
56 all.push(node)
57
58 const id = all.push(node) - 1
59 console.log('Node #' + id + ' bound to', node.address())
60
61 node.on('ephemeral', function () {
62 console.log('Node #' + id + ' is ephemeral', node.address())
63 })
64
65 node.on('persistent', function () {
66 console.log('Node #' + id + ' is persistent, joining remote routing tables', node.address())
67 })
68
69 node.on('close', function () {
70 console.log('Node #' + id + ' closed')
71 })
72 }
73
74 console.log('Fully started ' + cnt + ' Hyperswarm DHT node' + (cnt === 1 ? '' : 's'))
75
76 process.once('SIGINT', function () {
77 console.log('Shutting down nodes...')
78
79 for (const node of all) {
80 node.destroy()
81 }
82 })
83}
node_modules/hyperdht/browser.js +15 -0
……@@ -0,0 +1,15 @@
1const { hash, createKeyPair } = require('./lib/crypto')
2
3module.exports = class Stub {
4 constructor() {
5 throw new Error('hyperdht is not supported in browsers')
6 }
7
8 static keyPair(seed) {
9 return createKeyPair(seed)
10 }
11
12 static hash(data) {
13 return hash(data)
14 }
15}
node_modules/hyperdht/index.js +620 -0
……@@ -0,0 +1,620 @@
1const DHT = require('dht-rpc')
2const sodium = require('sodium-universal')
3const c = require('compact-encoding')
4const b4a = require('b4a')
5const safetyCatch = require('safety-catch')
6const m = require('./lib/messages')
7const SocketPool = require('./lib/socket-pool')
8const Persistent = require('./lib/persistent')
9const Router = require('./lib/router')
10const Cache = require('xache')
11const Server = require('./lib/server')
12const connect = require('./lib/connect')
13const { FIREWALL, BOOTSTRAP_NODES, KNOWN_NODES, COMMANDS } = require('./lib/constants')
14const { hash, createKeyPair } = require('./lib/crypto')
15const { decode } = require('hypercore-id-encoding')
16const RawStreamSet = require('./lib/raw-stream-set')
17const ConnectionPool = require('./lib/connection-pool')
18const { STREAM_NOT_CONNECTED } = require('./lib/errors')
19
20const DEFAULTS = {
21 ...DHT.DEFAULTS,
22 connectionKeepAlive: 5000,
23 randomPunchInterval: 20000
24}
25
26class HyperDHT extends DHT {
27 constructor(opts = {}) {
28 const port = opts.port || 49737
29 const bootstrap = opts.bootstrap || BOOTSTRAP_NODES
30 const nodes = opts.nodes || KNOWN_NODES
31
32 super({ ...opts, port, bootstrap, nodes, filterNode })
33
34 const { router, relayAddresses, persistent } = defaultCacheOpts(opts)
35
36 this.defaultKeyPair = opts.keyPair || createKeyPair(opts.seed)
37 this.listening = new Set()
38 this.connectionKeepAlive =
39 opts.connectionKeepAlive === false
40 ? 0
41 : opts.connectionKeepAlive || DEFAULTS.connectionKeepAlive
42
43 // stats is inherited from dht-rpc so fwd the ones from there
44 this.stats = {
45 punches: { consistent: 0, random: 0, open: 0 },
46 relaying: { attempts: 0, successes: 0, aborts: 0 },
47 ...this.stats
48 }
49 this.rawStreams = new RawStreamSet(this)
50
51 this._router = new Router(this, router)
52 this._socketPool = new SocketPool(this, opts.host || '0.0.0.0')
53 this._persistent = null
54 this._validatedLocalAddresses = new Map()
55 this._relayAddressesCache = new Cache(relayAddresses)
56
57 this._deferRandomPunch = !!opts.deferRandomPunch
58 this._lastRandomPunch = this._deferRandomPunch ? Date.now() : 0
59 this._connectable = true
60 this._randomPunchInterval = opts.randomPunchInterval || DEFAULTS.randomPunchInterval // min 20s between random punches...
61 this._randomPunches = 0
62 this._randomPunchLimit = 1 // set to one for extra safety for now
63
64 this.once('persistent', () => {
65 this._persistent = new Persistent(this, persistent)
66 })
67
68 this.on('network-change', () => {
69 for (const server of this.listening) server.refresh()
70 })
71
72 this.on('network-update', () => {
73 if (!this.online) return
74 for (const server of this.listening) server.notifyOnline()
75 })
76 }
77
78 static DEFAULTS = DEFAULTS
79
80 connect(remotePublicKey, opts) {
81 return connect(this, decode(remotePublicKey), opts)
82 }
83
84 createServer(opts, onconnection) {
85 if (typeof opts === 'function') return this.createServer({}, opts)
86 if (opts && opts.onconnection) onconnection = opts.onconnection
87 const s = new Server(this, opts)
88 if (onconnection) s.on('connection', onconnection)
89 return s
90 }
91
92 pool() {
93 return new ConnectionPool(this)
94 }
95
96 async resume({ log = noop } = {}) {
97 if (this._deferRandomPunch) this._lastRandomPunch = Date.now()
98 await super.resume({ log })
99 const resuming = []
100 for (const server of this.listening) resuming.push(server.resume())
101 log('Resuming hyperdht servers')
102 await Promise.allSettled(resuming)
103 log('Done, hyperdht fully resumed')
104 }
105
106 async suspend({ log = noop } = {}) {
107 this._connectable = false // just so nothing gets connected during suspension
108 const suspending = []
109 for (const server of this.listening) suspending.push(server.suspend())
110 log('Suspending all hyperdht servers')
111 await Promise.allSettled(suspending)
112 log('Done, clearing all raw streams')
113 await this.rawStreams.clear()
114 log('Done, suspending dht-rpc')
115 await super.suspend({ log })
116 log('Done, clearing raw streams again')
117 await this.rawStreams.clear()
118 log('Done, hyperdht fully suspended')
119 this._connectable = true
120 }
121
122 async destroy({ force = false } = {}) {
123 if (!force) {
124 const closing = []
125 for (const server of this.listening) closing.push(server.close())
126 await Promise.allSettled(closing)
127 }
128 this._router.destroy()
129 if (this._persistent) this._persistent.destroy()
130 await this.rawStreams.clear()
131 await this._socketPool.destroy()
132 await super.destroy()
133 }
134
135 async validateLocalAddresses(addresses) {
136 const list = []
137 const socks = []
138 const waiting = []
139
140 for (const addr of addresses) {
141 const { host } = addr
142
143 if (this._validatedLocalAddresses.has(host)) {
144 if (await this._validatedLocalAddresses.get(host)) {
145 list.push(addr)
146 }
147 continue
148 }
149
150 const sock = this.udx.createSocket()
151 try {
152 sock.bind(0, host)
153 } catch {
154 this._validatedLocalAddresses.set(host, Promise.resolve(false))
155 continue
156 }
157
158 socks.push(sock)
159
160 // semi terrible heuristic until we proper fix local connections by racing them to the remote...
161 const promise = new Promise((resolve) => {
162 sock.on('message', () => resolve(true))
163 setTimeout(() => resolve(false), 500)
164 sock.trySend(b4a.alloc(1), sock.address().port, addr.host)
165 })
166
167 this._validatedLocalAddresses.set(host, promise)
168 waiting.push(addr)
169 }
170
171 for (const addr of waiting) {
172 const { host } = addr
173 if (this._validatedLocalAddresses.has(host)) {
174 if (await this._validatedLocalAddresses.get(host)) {
175 list.push(addr)
176 }
177 continue
178 }
179 }
180
181 for (const sock of socks) await sock.close()
182
183 return list
184 }
185
186 findPeer(publicKey, opts = {}) {
187 const target = opts.hash === false ? publicKey : hash(publicKey)
188 opts = { ...opts, map: mapFindPeer }
189 return this.query({ target, command: COMMANDS.FIND_PEER, value: null }, opts)
190 }
191
192 lookup(target, opts = {}) {
193 opts = { ...opts, map: mapLookup }
194 return this.query({ target, command: COMMANDS.LOOKUP, value: null }, opts)
195 }
196
197 lookupAndUnannounce(target, keyPair, opts = {}) {
198 const unannounces = []
199 const dht = this
200 const userCommit = opts.commit || noop
201 const signUnannounce = opts.signUnannounce || Persistent.signUnannounce
202
203 if (this._persistent !== null) {
204 // unlink self
205 this._persistent.unannounce(target, keyPair.publicKey)
206 }
207
208 opts = { ...opts, map, commit }
209 return this.query({ target, command: COMMANDS.LOOKUP, value: null }, opts)
210
211 async function commit(reply, dht, query) {
212 await Promise.all(unannounces) // can never fail, caught below
213 return userCommit(reply, dht, query)
214 }
215
216 function map(reply) {
217 const data = mapLookup(reply)
218
219 if (!data || !data.token) return data
220
221 let found = data.peers.length >= 20
222 for (let i = 0; !found && i < data.peers.length; i++) {
223 found = b4a.equals(data.peers[i].publicKey, keyPair.publicKey)
224 }
225
226 if (!found) return data
227
228 if (!data.from.id) return data
229
230 unannounces.push(
231 dht
232 ._requestUnannounce(keyPair, dht, target, data.token, data.from, signUnannounce)
233 .catch(safetyCatch)
234 )
235
236 return data
237 }
238 }
239
240 unannounce(target, keyPair, opts = {}) {
241 return this.lookupAndUnannounce(target, keyPair, opts).finished()
242 }
243
244 announce(target, keyPair, relayAddresses, opts = {}) {
245 const signAnnounce = opts.signAnnounce || Persistent.signAnnounce
246 const bump = opts.bump || 0
247
248 opts = { ...opts, commit }
249
250 return opts.clear ? this.lookupAndUnannounce(target, keyPair, opts) : this.lookup(target, opts)
251
252 function commit(reply, dht) {
253 return dht._requestAnnounce(
254 keyPair,
255 dht,
256 target,
257 reply.token,
258 reply.from,
259 relayAddresses,
260 signAnnounce,
261 bump
262 )
263 }
264 }
265
266 async immutableGet(target, opts = {}) {
267 opts = { ...opts, map: mapImmutable }
268
269 const query = this.query({ target, command: COMMANDS.IMMUTABLE_GET, value: null }, opts)
270 const check = b4a.allocUnsafe(32)
271
272 for await (const node of query) {
273 const { value } = node
274 sodium.crypto_generichash(check, value)
275 if (b4a.equals(check, target)) return node
276 }
277
278 return null
279 }
280
281 async immutablePut(value, opts = {}) {
282 const target = b4a.allocUnsafe(32)
283 sodium.crypto_generichash(target, value)
284
285 opts = {
286 ...opts,
287 map: mapImmutable,
288 commit(reply, dht) {
289 return dht.request(
290 { token: reply.token, target, command: COMMANDS.IMMUTABLE_PUT, value },
291 reply.from
292 )
293 }
294 }
295
296 const query = this.query({ target, command: COMMANDS.IMMUTABLE_GET, value: null }, opts)
297 await query.finished()
298
299 return { hash: target, closestNodes: query.closestNodes }
300 }
301
302 async mutableGet(publicKey, opts = {}) {
303 let refresh = opts.refresh || null
304 let signed = null
305 let result = null
306
307 opts = { ...opts, map: mapMutable, commit: refresh ? commit : null }
308
309 const target = b4a.allocUnsafe(32)
310 sodium.crypto_generichash(target, publicKey)
311
312 const userSeq = opts.seq || 0
313 const query = this.query(
314 { target, command: COMMANDS.MUTABLE_GET, value: c.encode(c.uint, userSeq) },
315 opts
316 )
317 const latest = opts.latest !== false
318
319 for await (const node of query) {
320 if (result && node.seq <= result.seq) continue
321 if (
322 node.seq < userSeq ||
323 !Persistent.verifyMutable(node.signature, node.seq, node.value, publicKey)
324 )
325 continue
326 if (!latest) return node
327 if (!result || node.seq > result.seq) result = node
328 }
329
330 return result
331
332 function commit(reply, dht) {
333 if (!signed && result && refresh) {
334 if (refresh(result)) {
335 signed = c.encode(m.mutablePutRequest, {
336 publicKey,
337 seq: result.seq,
338 value: result.value,
339 signature: result.signature
340 })
341 } else {
342 refresh = null
343 }
344 }
345
346 return signed
347 ? dht.request(
348 { token: reply.token, target, command: COMMANDS.MUTABLE_PUT, value: signed },
349 reply.from
350 )
351 : Promise.resolve(null)
352 }
353 }
354
355 async mutablePut(keyPair, value, opts = {}) {
356 const signMutable = opts.signMutable || Persistent.signMutable
357
358 const target = b4a.allocUnsafe(32)
359 sodium.crypto_generichash(target, keyPair.publicKey)
360
361 const seq = opts.seq || 0
362 const signature = await signMutable(seq, value, keyPair)
363
364 const signed = c.encode(m.mutablePutRequest, {
365 publicKey: keyPair.publicKey,
366 seq,
367 value,
368 signature
369 })
370
371 opts = {
372 ...opts,
373 map: mapMutable,
374 commit(reply, dht) {
375 return dht.request(
376 { token: reply.token, target, command: COMMANDS.MUTABLE_PUT, value: signed },
377 reply.from
378 )
379 }
380 }
381
382 // use seq = 0, for the query part here, as we don't care about the actual values
383 const query = this.query(
384 { target, command: COMMANDS.MUTABLE_GET, value: c.encode(c.uint, 0) },
385 opts
386 )
387 await query.finished()
388
389 return { publicKey: keyPair.publicKey, closestNodes: query.closestNodes, seq, signature }
390 }
391
392 onrequest(req) {
393 switch (req.command) {
394 case COMMANDS.PEER_HANDSHAKE: {
395 this._router.onpeerhandshake(req)
396 return true
397 }
398 case COMMANDS.PEER_HOLEPUNCH: {
399 this._router.onpeerholepunch(req)
400 return true
401 }
402 }
403
404 if (this._persistent === null || this.id === null) return false
405
406 switch (req.command) {
407 case COMMANDS.FIND_PEER: {
408 this._persistent.onfindpeer(req)
409 return true
410 }
411 case COMMANDS.LOOKUP: {
412 this._persistent.onlookup(req)
413 return true
414 }
415 case COMMANDS.ANNOUNCE: {
416 this._persistent.onannounce(req)
417 return true
418 }
419 case COMMANDS.UNANNOUNCE: {
420 this._persistent.onunannounce(req)
421 return true
422 }
423 case COMMANDS.MUTABLE_PUT: {
424 this._persistent.onmutableput(req)
425 return true
426 }
427 case COMMANDS.MUTABLE_GET: {
428 this._persistent.onmutableget(req)
429 return true
430 }
431 case COMMANDS.IMMUTABLE_PUT: {
432 this._persistent.onimmutableput(req)
433 return true
434 }
435 case COMMANDS.IMMUTABLE_GET: {
436 this._persistent.onimmutableget(req)
437 return true
438 }
439 }
440
441 return false
442 }
443
444 static keyPair(seed) {
445 return createKeyPair(seed)
446 }
447
448 static hash(data) {
449 return hash(data)
450 }
451
452 static connectRawStream(encryptedStream, rawStream, remoteId) {
453 const stream = encryptedStream.rawStream
454
455 if (!stream.connected) throw STREAM_NOT_CONNECTED()
456
457 rawStream.connect(stream.socket, remoteId, stream.remotePort, stream.remoteHost)
458 }
459
460 createRawStream(opts) {
461 return this.rawStreams.add(opts)
462 }
463
464 async _requestAnnounce(keyPair, dht, target, token, from, relayAddresses, sign, bump) {
465 const ann = {
466 peer: {
467 publicKey: keyPair.publicKey,
468 relayAddresses: relayAddresses || []
469 },
470 refresh: null,
471 signature: null,
472 bump
473 }
474
475 ann.signature = await sign(target, token, from.id, ann, keyPair)
476
477 const value = c.encode(m.announce, ann)
478
479 return dht.request(
480 {
481 token,
482 target,
483 command: COMMANDS.ANNOUNCE,
484 value
485 },
486 from
487 )
488 }
489
490 async _requestUnannounce(keyPair, dht, target, token, from, sign) {
491 const unann = {
492 peer: {
493 publicKey: keyPair.publicKey,
494 relayAddresses: []
495 },
496 signature: null
497 }
498
499 unann.signature = await sign(target, token, from.id, unann, keyPair)
500
501 const value = c.encode(m.announce, unann)
502
503 return dht.request(
504 {
505 token,
506 target,
507 command: COMMANDS.UNANNOUNCE,
508 value
509 },
510 from
511 )
512 }
513}
514
515HyperDHT.BOOTSTRAP = BOOTSTRAP_NODES
516HyperDHT.FIREWALL = FIREWALL
517
518module.exports = HyperDHT
519
520function mapLookup(node) {
521 if (!node.value) return null
522
523 try {
524 const l = c.decode(m.lookupRawReply, node.value)
525
526 return {
527 token: node.token,
528 from: node.from,
529 to: node.to,
530 peers: l.peers,
531 bump: l.bump
532 }
533 } catch {
534 return null
535 }
536}
537
538function mapFindPeer(node) {
539 if (!node.value) return null
540
541 try {
542 return {
543 token: node.token,
544 from: node.from,
545 to: node.to,
546 peer: c.decode(m.peer, node.value)
547 }
548 } catch {
549 return null
550 }
551}
552
553function mapImmutable(node) {
554 if (!node.value) return null
555
556 return {
557 token: node.token,
558 from: node.from,
559 to: node.to,
560 value: node.value
561 }
562}
563
564function mapMutable(node) {
565 if (!node.value) return null
566
567 try {
568 const { seq, value, signature } = c.decode(m.mutableGetResponse, node.value)
569
570 return {
571 token: node.token,
572 from: node.from,
573 to: node.to,
574 seq,
575 value,
576 signature
577 }
578 } catch {
579 return null
580 }
581}
582
583function noop() {}
584
585function filterNode(node) {
586 // always skip these testnet nodes that got mixed in by accident, until they get updated
587 return (
588 !(node.port === 49738 && (node.host === '134.209.28.98' || node.host === '167.99.142.185')) &&
589 !(node.port === 9400 && node.host === '35.233.47.252') &&
590 !(node.host === '150.136.142.116')
591 )
592}
593
594const defaultMaxSize = 65536
595const defaultMaxAge = 20 * 60 * 1000 // 20 minutes
596
597function defaultCacheOpts(opts) {
598 const maxSize = opts.maxSize || defaultMaxSize
599 const maxAge = opts.maxAge || defaultMaxAge
600
601 return {
602 router: {
603 forwards: { maxSize, maxAge }
604 },
605 relayAddresses: { maxSize: Math.min(maxSize, 512), maxAge: 0 },
606 persistent: {
607 records: { maxSize, maxAge },
608 refreshes: { maxSize, maxAge },
609 mutables: {
610 maxSize: (maxSize / 2) | 0,
611 maxAge: opts.maxAge || 48 * 60 * 60 * 1000 // 48 hours
612 },
613 immutables: {
614 maxSize: (maxSize / 2) | 0,
615 maxAge: opts.maxAge || 48 * 60 * 60 * 1000 // 48 hours
616 },
617 bumps: { maxSize, maxAge }
618 }
619 }
620}
node_modules/hyperdht/lib/announcer.js +303 -0
……@@ -0,0 +1,303 @@
1const safetyCatch = require('safety-catch')
2const c = require('compact-encoding')
3const Signal = require('signal-promise')
4const { encodeUnslab } = require('./encode')
5const Sleeper = require('./sleeper')
6const m = require('./messages')
7const Persistent = require('./persistent')
8const { COMMANDS } = require('./constants')
9
10const MIN_ACTIVE = 3
11
12module.exports = class Announcer {
13 constructor(dht, keyPair, target, opts = {}) {
14 this.dht = dht
15 this.keyPair = keyPair
16 this.target = target
17 this.relays = []
18 this.relayAddresses = []
19 this.stopped = false
20 this.suspended = false
21 this.record = encodeUnslab(m.peer, { publicKey: keyPair.publicKey, relayAddresses: [] })
22 this.online = new Signal()
23
24 this._refreshing = false
25 this._closestNodes = null
26 this._active = null
27 this._sleeper = new Sleeper()
28 this._resumed = new Signal()
29 this._signAnnounce = opts.signAnnounce || Persistent.signAnnounce
30 this._signUnannounce = opts.signUnannounce || Persistent.signUnannounce
31 this._updating = null
32 this._activeQuery = null
33 this._unannouncing = null
34
35 this._serverRelays = [new Map(), new Map(), new Map()]
36 }
37
38 isRelay(addr) {
39 const id = addr.host + ':' + addr.port
40 const [a, b, c] = this._serverRelays
41 return a.has(id) || b.has(id) || c.has(id)
42 }
43
44 async suspend({ log = noop } = {}) {
45 if (this.suspended) return
46 this.suspended = true
47
48 log('Suspending announcer')
49
50 // Suspend has its own sleep logic
51 // so we don't want to hang on this one
52 this.online.notify()
53
54 if (this._activeQuery) this._activeQuery.destroy()
55
56 this._sleeper.resume()
57 if (this._updating) await this._updating
58 log('Suspending announcer (post update)')
59
60 if (this.suspended === false || this.stopped) return
61
62 log('Suspending announcer (pre unannounce)')
63 await this._unannounceCurrent()
64 log('Suspending announcer (post unannounce)')
65 }
66
67 resume() {
68 if (!this.suspended) return
69 this.suspended = false
70
71 this.refresh()
72 this._sleeper.resume()
73 this._resumed.notify()
74 }
75
76 refresh() {
77 if (this.stopped) return
78 this._refreshing = true
79 }
80
81 async start() {
82 if (this.stopped) return
83 this._active = this._runUpdate()
84 await this._active
85 if (this.stopped) return
86 this._active = this._background()
87 }
88
89 async stop() {
90 this.stopped = true
91 this.online.notify() // Break out of the _background loop if we're offline
92 this._sleeper.resume()
93 this._resumed.notify()
94 await this._active
95 await this._unannounceCurrent()
96 }
97
98 async _unannounceCurrent() {
99 while (this._unannouncing !== null) await this._unannouncing
100 const un = (this._unannouncing = this._unannounceAll(this._serverRelays[2].values()))
101 await this._unannouncing
102 if (un === this._unannouncing) this._unannouncing = null
103 }
104
105 async _background() {
106 while (!this.dht.destroyed && !this.stopped) {
107 try {
108 this._refreshing = false
109
110 // ~5min +-
111 for (let i = 0; i < 100 && !this.stopped && !this._refreshing && !this.suspended; i++) {
112 const pings = []
113
114 for (const node of this._serverRelays[2].values()) {
115 pings.push(this.dht.ping(node))
116 }
117
118 const active = await resolved(pings)
119 if (active < Math.min(pings.length, MIN_ACTIVE)) {
120 this.refresh() // we lost too many relay nodes, retry all
121 }
122
123 if (this.stopped) return
124
125 if (!this.suspended && !this._refreshing) await this._sleeper.pause(3000)
126 }
127
128 while (!this.stopped && this.suspended) await this._resumed.wait()
129
130 if (!this.stopped) await this._runUpdate()
131
132 while (!this.dht.online && !this.stopped && !this.suspended) {
133 // Being offline can make _background repeat very quickly
134 // So wait until we're back online
135 await this.online.wait()
136 }
137 } catch (err) {
138 safetyCatch(err)
139 }
140 }
141 }
142
143 async _runUpdate() {
144 this._updating = this._update()
145 await this._updating
146 this._updating = null
147 }
148
149 async _update() {
150 while (this._unannouncing) await this._unannouncing
151
152 this._cycle()
153
154 const q = (this._activeQuery = this.dht.findPeer(this.target, {
155 hash: false,
156 nodes: this._closestNodes
157 }))
158
159 try {
160 await q.finished()
161 } catch {
162 // ignore failures...
163 }
164
165 this._activeQuery = null
166
167 if (this.stopped || this.suspended) return
168
169 const ann = []
170 const replies = pickBest(q.closestReplies)
171
172 const relays = []
173 const relayAddresses = []
174
175 if (!this.dht.firewalled) {
176 const addr = this.dht.remoteAddress()
177 if (addr) relayAddresses.push(addr)
178 }
179
180 for (const msg of replies) {
181 ann.push(this._commit(msg, relays, relayAddresses))
182 }
183
184 await Promise.allSettled(ann)
185 if (this.stopped || this.suspended) return
186
187 this._closestNodes = q.closestNodes
188 this.relays = relays
189 this.relayAddresses = relayAddresses
190
191 const removed = []
192 for (const [key, value] of this._serverRelays[1]) {
193 if (!this._serverRelays[2].has(key)) removed.push(value)
194 }
195
196 await this._unannounceAll(removed)
197 }
198
199 _unannounceAll(relays) {
200 const unann = []
201 for (const r of relays) unann.push(this._unannounce(r))
202 return Promise.allSettled(unann)
203 }
204
205 async _unannounce(to) {
206 const unann = {
207 peer: {
208 publicKey: this.keyPair.publicKey,
209 relayAddresses: []
210 },
211 refresh: null,
212 signature: null
213 }
214
215 const { from, token, value } = await this.dht.request(
216 {
217 token: null,
218 command: COMMANDS.FIND_PEER,
219 target: this.target,
220 value: null
221 },
222 to
223 )
224
225 if (!token || !from.id || !value) return
226
227 unann.signature = await this._signUnannounce(this.target, token, from.id, unann, this.keyPair)
228
229 await this.dht.request(
230 {
231 token,
232 command: COMMANDS.UNANNOUNCE,
233 target: this.target,
234 value: c.encode(m.announce, unann)
235 },
236 to
237 )
238 }
239
240 async _commit(msg, relays, relayAddresses) {
241 const ann = {
242 peer: {
243 publicKey: this.keyPair.publicKey,
244 relayAddresses: []
245 },
246 refresh: null,
247 signature: null
248 }
249
250 ann.signature = await this._signAnnounce(this.target, msg.token, msg.from.id, ann, this.keyPair)
251
252 const res = await this.dht.request(
253 {
254 token: msg.token,
255 command: COMMANDS.ANNOUNCE,
256 target: this.target,
257 value: c.encode(m.announce, ann)
258 },
259 msg.from
260 )
261
262 if (res.error !== 0) return
263
264 if (relayAddresses.length < 3) relayAddresses.push({ host: msg.from.host, port: msg.from.port })
265 relays.push({ relayAddress: msg.from, peerAddress: msg.to })
266
267 this._serverRelays[2].set(msg.from.host + ':' + msg.from.port, msg.from)
268 }
269
270 _cycle() {
271 const tmp = this._serverRelays[0]
272 this._serverRelays[0] = this._serverRelays[1]
273 this._serverRelays[1] = this._serverRelays[2]
274 this._serverRelays[2] = tmp
275 tmp.clear()
276 }
277}
278
279function resolved(ps) {
280 let replied = 0
281 let ticks = ps.length + 1
282
283 return new Promise((resolve) => {
284 for (const p of ps) p.then(push, tick)
285 tick()
286
287 function push(v) {
288 replied++
289 tick()
290 }
291
292 function tick() {
293 if (--ticks === 0) resolve(replied)
294 }
295 })
296}
297
298function pickBest(replies) {
299 // TODO: pick the ones closest to us RTT wise
300 return replies.slice(0, 3)
301}
302
303function noop() {}
node_modules/hyperdht/lib/connect.js +850 -0
……@@ -0,0 +1,850 @@
1const NoiseSecretStream = require('@hyperswarm/secret-stream')
2const b4a = require('b4a')
3const relay = require('blind-relay')
4const { isReserved, isBogon } = require('bogon')
5const safetyCatch = require('safety-catch')
6const unslab = require('unslab')
7const Semaphore = require('./semaphore')
8const NoiseWrap = require('./noise-wrap')
9const SecurePayload = require('./secure-payload')
10const Holepuncher = require('./holepuncher')
11const Sleeper = require('./sleeper')
12const { FIREWALL, ERROR } = require('./constants')
13const { unslabbedHash } = require('./crypto')
14const {
15 CANNOT_HOLEPUNCH,
16 HANDSHAKE_INVALID,
17 HOLEPUNCH_ABORTED,
18 HOLEPUNCH_INVALID,
19 HOLEPUNCH_PROBE_TIMEOUT,
20 HOLEPUNCH_DOUBLE_RANDOMIZED_NATS,
21 PEER_CONNECTION_FAILED,
22 PEER_NOT_FOUND,
23 REMOTE_ABORTED,
24 REMOTE_NOT_HOLEPUNCHABLE,
25 REMOTE_NOT_HOLEPUNCHING,
26 SERVER_ERROR,
27 SERVER_INCOMPATIBLE,
28 RELAY_ABORTED,
29 SUSPENDED
30} = require('./errors')
31
32module.exports = function connect(dht, publicKey, opts = {}) {
33 const pool = opts.pool || null
34
35 if (pool && pool.has(publicKey)) return pool.get(publicKey)
36
37 publicKey = unslab(publicKey)
38
39 const keyPair = opts.keyPair || dht.defaultKeyPair
40 const relayThrough = selectRelay(opts.relayThrough || null)
41 const encryptedSocket = (opts.createSecretStream || defaultCreateSecretStream)(true, null, {
42 publicKey: keyPair.publicKey,
43 remotePublicKey: publicKey,
44 autoStart: false,
45 keepAlive: dht.connectionKeepAlive
46 })
47
48 // in case a socket is made during suspended state, destroy it immediately
49 if (dht.suspended || !dht._connectable) {
50 encryptedSocket.destroy(SUSPENDED())
51 return encryptedSocket
52 }
53
54 if (pool) pool._attachStream(encryptedSocket, false)
55
56 const id = b4a.toString(publicKey, 'hex')
57 const c = {
58 id,
59 dht,
60 session: dht.session(),
61 relayAddresses: opts.relayAddresses || [],
62 remoteRelayAddresses: [],
63 pool,
64 round: 0,
65 target: unslabbedHash(publicKey),
66 remotePublicKey: publicKey,
67 reusableSocket: !!opts.reusableSocket,
68 handshake: (opts.createHandshake || defaultCreateHandshake)(keyPair, publicKey),
69 request: null,
70 requesting: false,
71 lan: opts.localConnection !== false,
72 firewall: FIREWALL.UNKNOWN,
73 rawStream: dht.createRawStream({ framed: true, firewall }),
74 connect: null,
75 query: null,
76 puncher: null,
77 payload: null,
78 passiveConnectTimeout: null,
79 serverSocket: null,
80 serverAddress: null,
81 onsocket: null,
82 sleeper: new Sleeper(),
83 encryptedSocket,
84
85 // Relay state
86 relayTimeout: null,
87 relayThrough,
88 relayToken: relayThrough ? relay.token() : null,
89 relaySocket: null,
90 relayClient: null,
91 relayPaired: false,
92 relayKeepAlive: opts.relayKeepAlive || 5000
93 }
94
95 // If the raw stream receives an error signal pre connect (ie from the firewall hook), make sure
96 // to forward that to the encrypted socket for proper teardown
97 c.rawStream.on('error', autoDestroy)
98 c.rawStream.once('connect', () => {
99 c.rawStream.removeListener('error', autoDestroy)
100 })
101
102 encryptedSocket.on('close', function () {
103 if (c.passiveConnectTimeout) clearPassiveConnectTimeout(c)
104 if (c.query) c.query.destroy()
105 if (c.puncher) c.puncher.destroy()
106 if (c.rawStream) c.rawStream.destroy()
107 c.session.destroy()
108 c.sleeper.resume()
109 })
110
111 // Safe to run in the background - never throws
112 if (dht.suspended) encryptedSocket.destroy(SUSPENDED())
113 else connectAndHolepunch(c, opts)
114
115 return encryptedSocket
116
117 function autoDestroy(err) {
118 maybeDestroyEncryptedSocket(c, err)
119 }
120
121 function firewall(socket, port, host) {
122 // Check if the traffic originated from the socket on which we're expecting relay traffic. If so,
123 // we haven't hole punched yet and the other side is just sending us traffic through the relay.
124 if (c.relaySocket && isRelay(c.relaySocket, socket, port, host)) {
125 return false
126 }
127
128 if (c.onsocket) {
129 c.onsocket(socket, port, host)
130 } else {
131 c.serverSocket = socket
132 c.serverAddress = { port, host }
133 }
134 return false
135 }
136}
137
138function isDone(c) {
139 // we are destroying or the puncher is connected - done
140 if (c.encryptedSocket.destroying || !!(c.puncher && c.puncher.connected)) {
141 return true
142 }
143 // not destroying, but no raw stream - def not done
144 if (c.encryptedSocket.rawStream === null) {
145 return false
146 }
147 // we are relayed, but the puncher is not done yet
148 if (c.relaySocket && !!(c.puncher && !c.puncher.connected && !c.puncher.destroyed)) {
149 return false
150 }
151 // we are done
152 return true
153}
154
155async function retryRoute(c, route) {
156 const ref = c.dht._socketPool.lookup(route.socket)
157
158 if (!ref) {
159 if (route.socket === c.dht.socket) {
160 await connectThroughNode(c, route.address, c.dht.socket)
161 }
162 return
163 }
164
165 ref.active()
166
167 try {
168 await connectThroughNode(c, route.address, route.socket)
169 } catch {
170 // if error, just ignore, and continue through the existing strat
171 }
172
173 ref.inactive()
174}
175
176async function connectAndHolepunch(c, opts) {
177 const route = c.reusableSocket ? c.dht._socketPool.routes.get(c.remotePublicKey) : null
178
179 if (route) {
180 await retryRoute(c, route)
181 if (isDone(c)) return
182 }
183
184 await findAndConnect(c, opts)
185 if (isDone(c)) return
186
187 if (!c.connect) {
188 // TODO: just a quick fix for now, should retry prob
189 maybeDestroyEncryptedSocket(c, HANDSHAKE_INVALID())
190 return
191 }
192
193 await holepunch(c, opts)
194}
195
196function getFirstRemoteAddress(addrs, serverAddress) {
197 for (const addr of addrs) {
198 if (isBogon(addr.host)) continue
199 return addr
200 }
201
202 return serverAddress
203}
204
205async function holepunch(c, opts) {
206 let { relayAddress, serverAddress, clientAddress, payload } = c.connect
207
208 const remoteHolepunchable = !!(payload.holepunch && payload.holepunch.relays.length)
209
210 const relayed = diffAddress(serverAddress, relayAddress)
211
212 if (payload.firewall === FIREWALL.OPEN || (relayed && !remoteHolepunchable)) {
213 const addr = getFirstRemoteAddress(payload.addresses4, serverAddress)
214 if (addr) {
215 const socket = c.dht.socket
216 c.dht.stats.punches.open++
217 c.onsocket(socket, addr.port, addr.host)
218 return
219 }
220 // TODO: check all addresses also obvs
221 }
222
223 const onabort = () => {
224 c.session.destroy()
225 maybeDestroyEncryptedSocket(c, HOLEPUNCH_ABORTED())
226 }
227
228 if (c.firewall === FIREWALL.OPEN) {
229 c.passiveConnectTimeout = setTimeout(onabort, 10000)
230 return
231 }
232
233 // TODO: would be better to just try local addrs in the background whilst continuing with other strategies...
234 if (c.lan && relayed && clientAddress.host === serverAddress.host) {
235 const serverAddresses = payload.addresses4.filter(onlyNonReserved)
236
237 if (serverAddresses.length > 0) {
238 const myAddresses = Holepuncher.localAddresses(c.dht.io.serverSocket)
239 const addr = Holepuncher.matchAddress(myAddresses, serverAddresses) || serverAddresses[0]
240
241 const socket = c.dht.io.serverSocket
242 try {
243 await c.dht.ping(addr)
244 } catch {
245 maybeDestroyEncryptedSocket(c, HOLEPUNCH_ABORTED())
246 return
247 }
248 c.onsocket(socket, addr.port, addr.host)
249 return
250 }
251 }
252
253 if (!remoteHolepunchable) {
254 maybeDestroyEncryptedSocket(c, CANNOT_HOLEPUNCH())
255 return
256 }
257
258 c.puncher = new Holepuncher(c.dht, c.session, true, payload.firewall)
259
260 c.puncher.onconnect = c.onsocket
261 c.puncher.onabort = onabort
262
263 const serverRelay = pickServerRelay(payload.holepunch.relays, relayAddress)
264
265 // Begin holepunching!
266
267 let probe
268 try {
269 probe = await probeRound(c, opts.fastOpen === false ? null : serverAddress, serverRelay, true)
270 } catch (err) {
271 destroyPuncher(c)
272 // TODO: we should retry here with some of the other relays, bail for now
273 maybeDestroyEncryptedSocket(c, err)
274 return
275 }
276
277 if (isDone(c) || !probe) return
278 const { token, peerAddress } = probe
279
280 // If the relay the server picked is the same as the relay the client picked,
281 // then we can use the peerAddress that round one indicates the server wants to use.
282 // This shaves off a roundtrip if the server chose to reroll its socket due to some NAT
283 // issue with the first one it picked (ie mobile nat inconsistencies...).
284 // If the relays were different, then the server would not have a UDP session open on this address
285 // to the client relay, which round2 uses.
286 if (
287 !diffAddress(serverRelay.relayAddress, relayAddress) &&
288 diffAddress(serverAddress, peerAddress)
289 ) {
290 serverAddress = peerAddress
291 await c.puncher.openSession(serverAddress)
292 if (isDone(c)) return
293 }
294
295 // TODO: still continue here if a local connection might work, but then do not holepunch...
296 if (
297 opts.holepunch &&
298 !opts.holepunch(
299 c.puncher.remoteFirewall,
300 c.puncher.nat.firewall,
301 c.puncher.remoteAddresses,
302 c.puncher.nat.addresses
303 )
304 ) {
305 await abort(c, serverRelay, HOLEPUNCH_ABORTED('Client aborted holepunch'))
306 return
307 }
308
309 try {
310 await roundPunch(c, serverAddress, token, relayAddress, serverRelay, false)
311 } catch (err) {
312 destroyPuncher(c)
313 // TODO: retry with another relay?
314 maybeDestroyEncryptedSocket(c, err)
315 }
316}
317
318async function findAndConnect(c, opts) {
319 let attempts = 0
320 let closestNodes = opts.relayAddresses && opts.relayAddresses.length ? opts.relayAddresses : null
321
322 if (!closestNodes) {
323 const cachedRelayAddresses = c.dht._relayAddressesCache.get(c.id)
324 if (cachedRelayAddresses) closestNodes = cachedRelayAddresses
325 }
326
327 if (c.dht._persistent) {
328 // check if we know the route ourself...
329 const route = c.dht._router.get(c.target)
330 if (route && route.relay !== null) {
331 closestNodes = [{ host: route.relay.host, port: route.relay.port }]
332 }
333 }
334
335 // 2 is how many parallel connect attempts we want to do, we can make this configurable
336 const sem = new Semaphore(2)
337 const signal = sem.signal.bind(sem)
338 const tries = closestNodes !== null ? 2 : 1
339
340 try {
341 for (let i = 0; i < tries && !isDone(c) && !c.connect; i++) {
342 c.query = c.dht.findPeer(c.target, {
343 hash: false,
344 session: c.session,
345 closestNodes,
346 onlyClosestNodes: closestNodes !== null,
347 retries: closestNodes ? 1 : 3
348 })
349
350 for await (const data of c.query) {
351 await sem.wait()
352 if (isDone(c)) return
353
354 if (c.connect) {
355 sem.signal()
356 break
357 }
358
359 c.remoteRelayAddresses.push(data.from)
360 attempts++
361 connectThroughNode(c, data.from, null).then(signal, signal)
362 }
363
364 closestNodes = null
365
366 if (attempts > 0) await sem.flush()
367 }
368
369 c.query = null
370 if (isDone(c)) return
371
372 // flush the semaphore
373 await sem.flush()
374 if (isDone(c)) return
375 } catch (err) {
376 c.query = null
377 maybeDestroyEncryptedSocket(c, err)
378 return
379 }
380
381 if (!c.connect) {
382 maybeDestroyEncryptedSocket(c, attempts ? PEER_CONNECTION_FAILED() : PEER_NOT_FOUND())
383 }
384}
385
386async function connectThroughNode(c, address, socket) {
387 if (!c.requesting) {
388 // If we have a stable server address, send it over now
389 const addr = c.dht.remoteAddress()
390 const localAddrs = c.lan ? Holepuncher.localAddresses(c.dht.io.serverSocket) : null
391 const addresses4 = []
392
393 if (addr) addresses4.push(addr)
394 if (localAddrs) addresses4.push(...localAddrs)
395
396 c.firewall = addr ? FIREWALL.OPEN : FIREWALL.UNKNOWN
397 c.requesting = true
398 c.request = await c.handshake.send({
399 error: ERROR.NONE,
400 firewall: c.firewall,
401 holepunch: null,
402 addresses4,
403 addresses6: [],
404 udx: {
405 reusableSocket: c.reusableSocket,
406 id: c.rawStream.id,
407 seq: 0
408 },
409 secretStream: {},
410 relayThrough: c.relayThrough ? { publicKey: c.relayThrough, token: c.relayToken } : null
411 })
412 if (isDone(c)) return
413 }
414
415 const { serverAddress, clientAddress, relayed, noise } = await c.dht._router.peerHandshake(
416 c.target,
417 { noise: c.request, socket, session: c.session },
418 address
419 )
420 if (isDone(c) || c.connect) return
421
422 const payload = await c.handshake.recv(noise)
423 if (isDone(c) || !payload) return
424
425 if (payload.version !== 1) {
426 maybeDestroyEncryptedSocket(c, SERVER_INCOMPATIBLE())
427 return
428 }
429 if (payload.error !== ERROR.NONE) {
430 maybeDestroyEncryptedSocket(c, SERVER_ERROR())
431 return
432 }
433 if (!payload.udx) {
434 maybeDestroyEncryptedSocket(c, SERVER_ERROR('Server did not send UDX data'))
435 return
436 }
437
438 const hs = c.handshake.final()
439
440 c.handshake = null
441 c.request = null
442 c.requesting = false
443 c.connect = {
444 relayed,
445 relayAddress: address,
446 clientAddress,
447 serverAddress,
448 payload
449 }
450
451 c.payload = new SecurePayload(hs.holepunchSecret)
452
453 c.onsocket = function (socket, port, host) {
454 if (c.rawStream === null) return // Already hole punched
455
456 if (c.rawStream.connected) {
457 const remoteChanging = c.rawStream.changeRemote(socket, c.connect.payload.udx.id, port, host)
458
459 if (remoteChanging) remoteChanging.catch(safetyCatch)
460 } else {
461 // cache the relay addrs for a future reconnect, we prefer the remote one so they
462 // can give us the correct ones from their pov
463 if (payload.relayAddresses && payload.relayAddresses.length) {
464 c.dht._relayAddressesCache.set(c.id, payload.relayAddresses)
465 } else if (c.remoteRelayAddresses.length) {
466 c.dht._relayAddressesCache.set(c.id, c.remoteRelayAddresses)
467 }
468
469 c.rawStream.connect(socket, c.connect.payload.udx.id, port, host)
470 c.encryptedSocket.start(c.rawStream, { handshake: hs })
471 }
472
473 if (c.reusableSocket && payload.udx.reusableSocket) {
474 c.dht._socketPool.routes.add(c.remotePublicKey, c.rawStream)
475 }
476
477 if (c.puncher) {
478 c.puncher.onabort = noop
479 c.puncher.destroy()
480 }
481
482 if (c.passiveConnectTimeout) {
483 clearPassiveConnectTimeout(c)
484 }
485
486 c.rawStream = null
487 }
488
489 if (payload.relayThrough || c.relayThrough) {
490 relayConnection(c, c.relayThrough, payload, hs)
491 }
492
493 if (c.serverSocket) {
494 c.onsocket(c.serverSocket, c.serverAddress.port, c.serverAddress.host)
495 return
496 }
497
498 if (!relayed) {
499 c.onsocket(socket || c.dht.socket, address.port, address.host)
500 }
501
502 c.session.destroy()
503}
504
505async function updateHolepunch(c, peerAddress, relayAddr, payload) {
506 const holepunch = await c.dht._router.peerHolepunch(
507 c.target,
508 {
509 id: c.connect.payload.holepunch.id,
510 payload: c.payload.encrypt(payload),
511 peerAddress,
512 socket: c.puncher.socket,
513 session: c.session
514 },
515 relayAddr
516 )
517
518 if (isDone(c)) return null
519
520 const remotePayload = c.payload.decrypt(holepunch.payload)
521 if (!remotePayload) {
522 throw HOLEPUNCH_INVALID()
523 }
524
525 const { error, firewall, punching, addresses, remoteToken } = remotePayload
526
527 if (error === ERROR.TRY_LATER && c.relayToken && payload.punching) {
528 return {
529 tryLater: true,
530 ...holepunch,
531 payload: remotePayload
532 }
533 }
534
535 if (error !== ERROR.NONE) {
536 throw REMOTE_ABORTED('Remote aborted with error code ' + error)
537 }
538
539 const echoed = !!(remoteToken && payload.token && b4a.equals(remoteToken, payload.token))
540
541 c.puncher.updateRemote({
542 punching,
543 firewall,
544 addresses,
545 verified: echoed ? peerAddress.host : null
546 })
547
548 return {
549 tryLater: false,
550 ...holepunch,
551 payload: remotePayload
552 }
553}
554
555async function probeRound(c, serverAddress, serverRelay, retry) {
556 // Open a quick low ttl session against what we think is the server
557 if (serverAddress) await c.puncher.openSession(serverAddress)
558
559 if (isDone(c)) return null
560
561 const reply = await updateHolepunch(c, serverRelay.peerAddress, serverRelay.relayAddress, {
562 error: ERROR.NONE,
563 firewall: c.puncher.nat.firewall,
564 round: c.round++,
565 connected: false,
566 punching: false,
567 addresses: c.puncher.nat.addresses,
568 remoteAddress: serverAddress,
569 token: null,
570 remoteToken: null
571 })
572
573 if (isDone(c) || !reply) return null
574
575 const { peerAddress } = reply
576 const { address, token } = reply.payload
577
578 c.puncher.nat.add(reply.to, reply.from)
579
580 // Open another quick low ttl session against what the server says their address is,
581 // if they haven't said they are random yet
582 if (
583 c.puncher.remoteFirewall < FIREWALL.RANDOM &&
584 address &&
585 address.host &&
586 address.port &&
587 diffAddress(address, serverAddress)
588 ) {
589 await c.puncher.openSession(address)
590 if (isDone(c)) return null
591 }
592
593 // If the remote told us they didn't know their nat firewall yet, give them a chance to figure it out
594 // They might say this to see if the "fast mode" punch comes through first.
595 if (c.puncher.remoteFirewall === FIREWALL.UNKNOWN) {
596 await c.sleeper.pause(1000)
597 if (isDone(c)) return null
598 }
599
600 let stable = await c.puncher.analyze(false)
601 if (isDone(c)) return null
602
603 // If the socket seems unstable, try to make it stable by setting the "allowReopen" flag
604 // Mostly relevant for mobile networks
605 if (!stable) {
606 stable = await c.puncher.analyze(true)
607 if (isDone(c)) return null
608 if (stable) return probeRound(c, serverAddress, serverRelay, false)
609 }
610
611 if ((c.puncher.remoteFirewall === FIREWALL.UNKNOWN || !token) && retry) {
612 return probeRound(c, serverAddress, serverRelay, false)
613 }
614
615 if (
616 c.puncher.remoteFirewall === FIREWALL.UNKNOWN ||
617 c.puncher.nat.firewall === FIREWALL.UNKNOWN
618 ) {
619 await abort(c, serverRelay, HOLEPUNCH_PROBE_TIMEOUT())
620 return null
621 }
622
623 if (c.puncher.remoteFirewall >= FIREWALL.RANDOM && c.puncher.nat.firewall >= FIREWALL.RANDOM) {
624 await abort(c, serverRelay, HOLEPUNCH_DOUBLE_RANDOMIZED_NATS())
625 return null
626 }
627
628 return { token, peerAddress }
629}
630
631async function roundPunch(c, serverAddress, remoteToken, clientRelay, serverRelay, delayed) {
632 // We are gossiping our final NAT status to the other peer now
633 // so make sure we don't update our local view for now as that can make things weird
634 c.puncher.nat.freeze()
635
636 const isRandom =
637 c.puncher.remoteFirewall >= FIREWALL.RANDOM || c.puncher.nat.firewall >= FIREWALL.RANDOM
638 if (isRandom) {
639 while (
640 c.dht._randomPunches >= c.dht._randomPunchLimit ||
641 Date.now() - c.dht._lastRandomPunch < c.dht._randomPunchInterval
642 ) {
643 // if no relay can help, bail
644 if (!c.relayToken) throw HOLEPUNCH_ABORTED()
645
646 if (!delayed) {
647 delayed = true
648 await updateHolepunch(c, serverAddress, clientRelay, {
649 error: ERROR.NONE,
650 firewall: c.puncher.nat.firewall,
651 round: c.round++,
652 connected: false,
653 punching: false,
654 addresses: c.puncher.nat.addresses,
655 remoteAddress: null,
656 token: c.payload.token(serverAddress),
657 remoteToken
658 })
659 if (isDone(c)) return
660 }
661
662 await tryLater(c)
663 if (isDone(c)) return
664 }
665 }
666
667 // increment now, so we can commit to punching
668 if (isRandom) c.dht._randomPunches++
669
670 let reply
671
672 try {
673 // if delayed switch to the servers chosen relay - we validated anyway
674 reply = await updateHolepunch(
675 c,
676 delayed ? serverRelay.peerAddress : serverAddress,
677 delayed ? serverRelay.relayAddress : clientRelay,
678 {
679 error: ERROR.NONE,
680 firewall: c.puncher.nat.firewall,
681 round: c.round++,
682 connected: false,
683 punching: true,
684 addresses: c.puncher.nat.addresses,
685 remoteAddress: null,
686 token: delayed ? null : c.payload.token(serverAddress),
687 remoteToken
688 }
689 )
690 } finally {
691 // decrement as punch increments for us
692 if (isRandom) c.dht._randomPunches--
693 }
694
695 if (isDone(c)) return
696 if (!reply) return
697
698 if (reply.tryLater) {
699 await tryLater(c)
700 if (isDone(c)) return
701 return roundPunch(c, serverAddress, remoteToken, clientRelay, serverRelay, true)
702 }
703
704 if (!c.puncher.remoteHolepunching) {
705 throw REMOTE_NOT_HOLEPUNCHING()
706 }
707
708 if (!(await c.puncher.punch())) {
709 throw REMOTE_NOT_HOLEPUNCHABLE()
710 }
711}
712
713async function tryLater(c) {
714 if (!c.relayToken) throw HOLEPUNCH_ABORTED()
715 await c.sleeper.pause(10000 + Math.round(Math.random() * 10000))
716}
717
718function maybeDestroyEncryptedSocket(c, err) {
719 if (isDone(c)) return
720 if (c.encryptedSocket.rawStream) return
721 if (c.relaySocket) return // waiting for the relay
722 if (c.puncher && !c.puncher.destroyed) return // waiting for the puncher
723 c.session.destroy()
724 c.encryptedSocket.destroy(err)
725}
726
727async function abort(c, { peerAddress, relayAddress }, err) {
728 try {
729 await updateHolepunch(peerAddress, relayAddress, {
730 error: ERROR.ABORTED,
731 firewall: FIREWALL.UNKNOWN,
732 round: c.round++,
733 connected: false,
734 punching: false,
735 addresses: null,
736 remoteAddress: null,
737 token: null,
738 remoteToken: null
739 })
740 } catch {}
741
742 destroyPuncher(c)
743 maybeDestroyEncryptedSocket(c, err)
744}
745
746function relayConnection(c, relayThrough, payload, hs) {
747 let isInitiator
748 let publicKey
749 let token
750
751 if (payload.relayThrough) {
752 isInitiator = false
753 publicKey = payload.relayThrough.publicKey
754 token = payload.relayThrough.token
755 } else {
756 isInitiator = true
757 publicKey = relayThrough
758 token = c.relayToken
759 }
760
761 c.relayToken = token
762 c.relaySocket = c.dht.connect(publicKey)
763 c.relaySocket.setKeepAlive(c.relayKeepAlive)
764 c.relayClient = relay.Client.from(c.relaySocket, { id: c.relaySocket.publicKey })
765 c.relayTimeout = setTimeout(onabort, 15000, null)
766
767 c.relayClient.pair(isInitiator, token, c.rawStream).on('error', onabort).on('data', ondata)
768
769 function ondata(remoteId) {
770 if (c.relayTimeout) clearRelayTimeout(c)
771 if (c.rawStream === null) {
772 onabort(null)
773 return
774 }
775
776 c.relayPaired = true
777
778 const { remotePort, remoteHost, socket } = c.relaySocket.rawStream
779
780 c.rawStream
781 .on('close', () => c.relaySocket.destroy())
782 .connect(socket, remoteId, remotePort, remoteHost)
783
784 c.encryptedSocket.start(c.rawStream, { handshake: hs })
785 }
786
787 function onabort(err) {
788 if (c.relayTimeout) clearRelayTimeout(c)
789 const socket = c.relaySocket
790 c.relayToken = null
791 c.relaySocket = null
792 if (socket) socket.destroy()
793 maybeDestroyEncryptedSocket(c, err || RELAY_ABORTED())
794 }
795}
796
797function clearPassiveConnectTimeout(c) {
798 clearTimeout(c.passiveConnectTimeout)
799 c.passiveConnectTimeout = null
800}
801
802function clearRelayTimeout(c) {
803 clearTimeout(c.relayTimeout)
804 c.relayTimeout = null
805}
806
807function destroyPuncher(c) {
808 if (c.puncher) c.puncher.destroy()
809 c.session.destroy()
810}
811
812function pickServerRelay(relays, clientRelay) {
813 for (const r of relays) {
814 if (!diffAddress(r.relayAddress, clientRelay)) return r
815 }
816 return relays[0]
817}
818
819function diffAddress(a, b) {
820 return a.host !== b.host || a.port !== b.port
821}
822
823function defaultCreateHandshake(keyPair, remotePublicKey) {
824 return new NoiseWrap(keyPair, remotePublicKey)
825}
826
827function defaultCreateSecretStream(isInitiator, rawStream, opts) {
828 return new NoiseSecretStream(isInitiator, rawStream, opts)
829}
830
831function onlyNonReserved(addr) {
832 return !isReserved(addr.host)
833}
834
835function isRelay(relaySocket, socket, port, host) {
836 const stream = relaySocket.rawStream
837 if (!stream) return false
838 if (stream.socket !== socket) return false
839 return port === stream.remotePort && host === stream.remoteHost
840}
841
842function selectRelay(relayThrough) {
843 if (typeof relayThrough === 'function') relayThrough = relayThrough()
844 if (relayThrough === null) return null
845 if (Array.isArray(relayThrough))
846 return relayThrough[Math.floor(Math.random() * relayThrough.length)]
847 return relayThrough
848}
849
850function noop() {}
node_modules/hyperdht/lib/connection-pool.js +142 -0
……@@ -0,0 +1,142 @@
1const EventEmitter = require('events')
2const b4a = require('b4a')
3const errors = require('./errors')
4
5module.exports = class ConnectionPool extends EventEmitter {
6 constructor(dht) {
7 super()
8
9 this._dht = dht
10 this._servers = new Map()
11 this._connecting = new Map()
12 this._connections = new Map()
13 }
14
15 _attachServer(server) {
16 const keyString = b4a.toString(server.publicKey, 'hex')
17
18 this._servers.set(keyString, server)
19
20 server
21 .on('close', () => {
22 this._servers.delete(keyString)
23 })
24 .on('connection', (socket) => {
25 this._attachStream(socket, true)
26 })
27 }
28
29 _attachStream(stream, opened) {
30 const existing = this.get(stream.remotePublicKey)
31
32 if (existing) {
33 const keepNew =
34 stream.isInitiator === existing.isInitiator ||
35 b4a.compare(stream.publicKey, stream.remotePublicKey) > 0
36
37 if (keepNew) {
38 let closed = false
39
40 const onclose = () => {
41 closed = true
42 }
43
44 existing
45 .on('error', noop)
46 .on('close', () => {
47 if (closed) return
48
49 stream.off('error', noop).off('close', onclose)
50
51 this._attachStream(stream, opened)
52 })
53 .destroy(errors.DUPLICATE_CONNECTION())
54
55 stream.on('error', noop).on('close', onclose)
56 } else {
57 stream.on('error', noop).destroy(errors.DUPLICATE_CONNECTION())
58 }
59
60 return
61 }
62
63 const session = new ConnectionRef(this, stream)
64
65 const keyString = b4a.toString(stream.remotePublicKey, 'hex')
66
67 if (opened) {
68 this._connections.set(keyString, session)
69
70 stream.on('close', () => {
71 this._connections.delete(keyString)
72 })
73
74 this.emit('connection', stream, session)
75 } else {
76 this._connecting.set(keyString, session)
77
78 stream
79 .on('error', noop)
80 .on('close', () => {
81 if (opened) this._connections.delete(keyString)
82 else this._connecting.delete(keyString)
83 })
84 .on('open', () => {
85 opened = true
86
87 this._connecting.delete(keyString)
88 this._connections.set(keyString, session)
89
90 stream.off('error', noop)
91
92 this.emit('connection', stream, session)
93 })
94 }
95
96 return session
97 }
98
99 get connecting() {
100 return this._connecting.size
101 }
102
103 get connections() {
104 return this._connections.values()
105 }
106
107 has(publicKey) {
108 const keyString = b4a.toString(publicKey, 'hex')
109
110 return this._connections.has(keyString) || this._connecting.has(keyString)
111 }
112
113 get(publicKey) {
114 const keyString = b4a.toString(publicKey, 'hex')
115
116 const existing = this._connections.get(keyString) || this._connecting.get(keyString)
117
118 return existing?._stream || null
119 }
120}
121
122class ConnectionRef {
123 constructor(pool, stream) {
124 this._pool = pool
125 this._stream = stream
126 this._refs = 0
127 }
128
129 active() {
130 this._refs++
131 }
132
133 inactive() {
134 this._refs--
135 }
136
137 release() {
138 this._stream.destroy()
139 }
140}
141
142function noop() {}
node_modules/hyperdht/lib/constants.js +57 -0
……@@ -0,0 +1,57 @@
1const crypto = require('hypercore-crypto')
2
3const COMMANDS = (exports.COMMANDS = {
4 PEER_HANDSHAKE: 0,
5 PEER_HOLEPUNCH: 1,
6 FIND_PEER: 2,
7 LOOKUP: 3,
8 ANNOUNCE: 4,
9 UNANNOUNCE: 5,
10 MUTABLE_PUT: 6,
11 MUTABLE_GET: 7,
12 IMMUTABLE_PUT: 8,
13 IMMUTABLE_GET: 9
14})
15
16exports.BOOTSTRAP_NODES = global.Pear?.config.dht?.bootstrap || [
17 '88.99.3.86@node1.hyperdht.org:49737',
18 '142.93.90.113@node2.hyperdht.org:49737',
19 '138.68.147.8@node3.hyperdht.org:49737'
20]
21
22exports.KNOWN_NODES = global.Pear?.config.dht?.nodes || []
23
24exports.FIREWALL = {
25 UNKNOWN: 0,
26 OPEN: 1,
27 CONSISTENT: 2,
28 RANDOM: 3
29}
30
31exports.ERROR = {
32 // noise / connection related
33 NONE: 0,
34 ABORTED: 1,
35 VERSION_MISMATCH: 2,
36 TRY_LATER: 3,
37 // dht related
38 SEQ_REUSED: 16,
39 SEQ_TOO_LOW: 17
40}
41
42const [NS_ANNOUNCE, NS_UNANNOUNCE, NS_MUTABLE_PUT, NS_PEER_HANDSHAKE, NS_PEER_HOLEPUNCH] =
43 crypto.namespace('hyperswarm/dht', [
44 COMMANDS.ANNOUNCE,
45 COMMANDS.UNANNOUNCE,
46 COMMANDS.MUTABLE_PUT,
47 COMMANDS.PEER_HANDSHAKE,
48 COMMANDS.PEER_HOLEPUNCH
49 ])
50
51exports.NS = {
52 ANNOUNCE: NS_ANNOUNCE,
53 UNANNOUNCE: NS_UNANNOUNCE,
54 MUTABLE_PUT: NS_MUTABLE_PUT,
55 PEER_HANDSHAKE: NS_PEER_HANDSHAKE,
56 PEER_HOLEPUNCH: NS_PEER_HOLEPUNCH
57}
node_modules/hyperdht/lib/crypto.js +28 -0
……@@ -0,0 +1,28 @@
1const sodium = require('sodium-universal')
2const b4a = require('b4a')
3
4function hash(data) {
5 const out = b4a.allocUnsafe(32)
6 sodium.crypto_generichash(out, data)
7 return out
8}
9
10function unslabbedHash(data) {
11 const out = b4a.allocUnsafeSlow(32)
12 sodium.crypto_generichash(out, data)
13 return out
14}
15
16function createKeyPair(seed) {
17 const publicKey = b4a.alloc(32)
18 const secretKey = b4a.alloc(64)
19 if (seed) sodium.crypto_sign_seed_keypair(publicKey, secretKey, seed)
20 else sodium.crypto_sign_keypair(publicKey, secretKey)
21 return { publicKey, secretKey }
22}
23
24module.exports = {
25 hash,
26 unslabbedHash,
27 createKeyPair
28}
node_modules/hyperdht/lib/encode.js +16 -0
……@@ -0,0 +1,16 @@
1const b4a = require('b4a')
2const cenc = require('compact-encoding')
3
4function encodeUnslab(enc, m) {
5 // Faster than unslab(c.encode(enc, data)) because it avoids the mem copy.
6 // Makes sense to put in compact-encoding when we need it in other modules too
7 const state = cenc.state()
8 enc.preencode(state, m)
9 state.buffer = b4a.allocUnsafeSlow(state.end)
10 enc.encode(state, m)
11 return state.buffer
12}
13
14module.exports = {
15 encodeUnslab
16}
node_modules/hyperdht/lib/errors.js +110 -0
……@@ -0,0 +1,110 @@
1module.exports = class DHTError extends Error {
2 constructor(msg, code, fn = DHTError) {
3 super(`${code}: ${msg}`)
4 this.code = code
5
6 if (Error.captureStackTrace) {
7 Error.captureStackTrace(this, fn)
8 }
9 }
10
11 get name() {
12 return 'DHTError'
13 }
14
15 static BAD_HANDSHAKE_REPLY(msg = 'Bad handshake reply') {
16 return new DHTError(msg, 'BAD_HANDSHAKE_REPLY', DHTError.BAD_HANDSHAKE_REPLY)
17 }
18
19 static BAD_HOLEPUNCH_REPLY(msg = 'Bad holepunch reply') {
20 return new DHTError(msg, 'BAD_HOLEPUNCH_REPLY', DHTError.BAD_HOLEPUNCH_REPLY)
21 }
22
23 static HOLEPUNCH_ABORTED(msg = 'Holepunch aborted') {
24 return new DHTError(msg, 'HOLEPUNCH_ABORTED', DHTError.HOLEPUNCH_ABORTED)
25 }
26
27 static HOLEPUNCH_INVALID(msg = 'Invalid holepunch payload') {
28 return new DHTError(msg, 'HOLEPUNCH_INVALID', DHTError.HOLEPUNCH_INVALID)
29 }
30
31 static HOLEPUNCH_PROBE_TIMEOUT(msg = 'Holepunching probe did not finish in time') {
32 return new DHTError(msg, 'HOLEPUNCH_PROBE_TIMEOUT', DHTError.HOLEPUNCH_PROBE_TIMEOUT)
33 }
34
35 static HOLEPUNCH_DOUBLE_RANDOMIZED_NATS(msg = 'Both remote and local NATs are randomized') {
36 return new DHTError(
37 msg,
38 'HOLEPUNCH_DOUBLE_RANDOMIZED_NATS',
39 DHTError.HOLEPUNCH_DOUBLE_RANDOMIZED_NATS
40 )
41 }
42
43 static CANNOT_HOLEPUNCH(msg = 'Cannot holepunch to remote') {
44 return new DHTError(msg, 'CANNOT_HOLEPUNCH', DHTError.CANNOT_HOLEPUNCH)
45 }
46
47 static REMOTE_NOT_HOLEPUNCHING(msg = 'Remote is not holepunching') {
48 return new DHTError(msg, 'REMOTE_NOT_HOLEPUNCHING', DHTError.REMOTE_NOT_HOLEPUNCHING)
49 }
50
51 static REMOTE_NOT_HOLEPUNCHABLE(msg = 'Remote is not holepunchable') {
52 return new DHTError(msg, 'REMOTE_NOT_HOLEPUNCHABLE', DHTError.REMOTE_NOT_HOLEPUNCHABLE)
53 }
54
55 static REMOTE_ABORTED(msg = 'Remote aborted') {
56 return new DHTError(msg, 'REMOTE_ABORTED', DHTError.REMOTE_ABORTED)
57 }
58
59 static HANDSHAKE_UNFINISHED(msg = 'Handshake did not finish') {
60 return new DHTError(msg, 'HANDSHAKE_UNFINISHED', DHTError.HANDSHAKE_UNFINISHED)
61 }
62
63 static HANDSHAKE_INVALID(msg = 'Received invalid handshake') {
64 return new DHTError(msg, 'HANDSHAKE_INVALID', DHTError.HANDSHAKE_INVALID)
65 }
66
67 static ALREADY_LISTENING(msg = 'Already listening') {
68 return new DHTError(msg, 'ALREADY_LISTENING', DHTError.ALREADY_LISTENING)
69 }
70
71 static KEYPAIR_ALREADY_USED(msg = 'Keypair already used') {
72 return new DHTError(msg, 'KEYPAIR_ALREADY_USED', DHTError.KEYPAIR_ALREADY_USED)
73 }
74
75 static NODE_DESTROYED(msg = 'Node destroyed') {
76 return new DHTError(msg, 'NODE_DESTROYED', DHTError.NODE_DESTROYED)
77 }
78
79 static PEER_CONNECTION_FAILED(msg = 'Could not connect to peer') {
80 return new DHTError(msg, 'PEER_CONNECTION_FAILED', DHTError.PEER_CONNECTION_FAILED)
81 }
82
83 static PEER_NOT_FOUND(msg = 'Peer not found') {
84 return new DHTError(msg, 'PEER_NOT_FOUND', DHTError.PEER_NOT_FOUND)
85 }
86
87 static STREAM_NOT_CONNECTED(msg = 'Stream is not connected') {
88 return new DHTError(msg, 'STREAM_NOT_CONNECTED', DHTError.STREAM_DISCONNECTED)
89 }
90
91 static SERVER_INCOMPATIBLE(msg = 'Server is using an incompatible version') {
92 return new DHTError(msg, 'SERVER_INCOMPATIBLE', DHTError.SERVER_INCOMPATIBLE)
93 }
94
95 static SERVER_ERROR(msg = 'Server returned an error') {
96 return new DHTError(msg, 'SERVER_ERROR', DHTError.SERVER_ERROR)
97 }
98
99 static DUPLICATE_CONNECTION(msg = 'Duplicate connection') {
100 return new DHTError(msg, 'DUPLICATE_CONNECTION', DHTError.DUPLICATE_CONNECTION)
101 }
102
103 static RELAY_ABORTED(msg = 'Relay aborted') {
104 return new DHTError(msg, 'RELAY_ABORTED', DHTError.RELAY_ABORTED)
105 }
106
107 static SUSPENDED(msg = 'Suspended') {
108 return new DHTError(msg, 'SUSPENDED', DHTError.SUSPENDED)
109 }
110}
node_modules/hyperdht/lib/holepuncher.js +388 -0
……@@ -0,0 +1,388 @@
1const b4a = require('b4a')
2const Nat = require('./nat')
3const Sleeper = require('./sleeper')
4const { FIREWALL } = require('./constants')
5
6const BIRTHDAY_SOCKETS = 256
7const HOLEPUNCH = b4a.from([0])
8const HOLEPUNCH_TTL = 5
9const DEFAULT_TTL = 64
10const MAX_REOPENS = 3
11
12module.exports = class Holepuncher {
13 constructor(dht, session, isInitiator, remoteFirewall = FIREWALL.UNKNOWN) {
14 const holder = dht._socketPool.acquire()
15
16 this.dht = dht
17 this.session = session
18
19 this.nat = new Nat(dht, session, holder.socket)
20 this.nat.autoSample()
21
22 this.isInitiator = isInitiator
23
24 // events
25 this.onconnect = noop
26 this.onabort = noop
27
28 this.punching = false
29 this.connected = false
30 this.destroyed = false
31 this.randomized = false
32
33 // track remote state
34 this.remoteFirewall = remoteFirewall
35 this.remoteAddresses = []
36 this.remoteHolepunching = false
37
38 this._sleeper = new Sleeper()
39 this._reopening = null
40 this._timeout = null
41 this._punching = null
42 this._allHolders = []
43 this._holder = this._addRef(holder)
44 }
45
46 get socket() {
47 return this._holder.socket
48 }
49
50 updateRemote({ punching, firewall, addresses, verified }) {
51 const remoteAddresses = []
52
53 if (addresses) {
54 for (const addr of addresses) {
55 remoteAddresses.push({
56 host: addr.host,
57 port: addr.port,
58 verified: verified === addr.host || this._isVerified(addr.host)
59 })
60 }
61 }
62
63 this.remoteFirewall = firewall
64 this.remoteAddresses = remoteAddresses
65 this.remoteHolepunching = punching
66 }
67
68 _isVerified(host) {
69 for (const addr of this.remoteAddresses) {
70 if (addr.verified && addr.host === host) {
71 return true
72 }
73 }
74 return false
75 }
76
77 ping(addr, socket = this._holder.socket) {
78 return holepunch(socket, addr, false)
79 }
80
81 openSession(addr, socket = this._holder.socket) {
82 return holepunch(socket, addr, true)
83 }
84
85 async analyze(allowReopen) {
86 await this.nat.analyzing
87 if (this._unstable()) {
88 if (!allowReopen) return false
89 if (!this._reopening) this._reopening = this._reopen()
90 return this._reopening
91 }
92 return true
93 }
94
95 _unstable() {
96 // TODO!!: We need an additional heuristic here... If we were NOT random in the past we should also do this.
97 const firewall = this.nat.firewall
98 return (
99 (this.remoteFirewall >= FIREWALL.RANDOM && firewall >= FIREWALL.RANDOM) ||
100 firewall === FIREWALL.UNKNOWN
101 )
102 }
103
104 _reset() {
105 const prev = this._holder
106
107 this._allHolders.pop()
108 this._holder = this._addRef(this.dht._socketPool.acquire())
109
110 prev.release()
111 this.nat.destroy()
112
113 this.nat = new Nat(this.dht, this.session, this._holder.socket)
114 // TODO: maybe make auto sampling configurable somehow?
115 this.nat.autoSample()
116 }
117
118 _addRef(ref) {
119 this._allHolders.push(ref)
120 ref.onholepunchmessage = (msg, rinfo) => this._onholepunchmessage(msg, rinfo, ref)
121 return ref
122 }
123
124 _onholepunchmessage(_, addr, ref) {
125 if (!this.isInitiator) {
126 // TODO: we don't need this if we had a way to connect a socket to many hosts
127 holepunch(ref.socket, addr, false) // never fails
128 return
129 }
130
131 if (this.connected) return
132
133 this.connected = true
134 this.punching = false
135
136 for (const r of this._allHolders) {
137 if (r === ref) continue
138 r.release()
139 }
140
141 this._allHolders[0] = ref
142 while (this._allHolders.length > 1) this._allHolders.pop()
143
144 this._decrementRandomized()
145 this.onconnect(ref.socket, addr.port, addr.host)
146 }
147
148 _done() {
149 return this.destroyed || this.connected
150 }
151
152 async _reopen() {
153 for (let i = 0; this._unstable() && i < MAX_REOPENS && !this._done() && !this.punching; i++) {
154 this._reset()
155 await this.nat.analyzing
156 }
157
158 return coerceFirewall(this.nat.firewall) === FIREWALL.CONSISTENT
159 }
160
161 punch() {
162 if (!this._punching) this._punching = this._punch()
163 return this._punching
164 }
165
166 async _punch() {
167 if (this._done() || !this.remoteAddresses.length) return false
168
169 this.punching = true
170
171 // Coerce into consistency for now. Obvs we could make this this more efficient if we use that info
172 // but that's seldomly used since those will just use tcp most of the time.
173
174 const local = coerceFirewall(this.nat.firewall)
175 const remote = coerceFirewall(this.remoteFirewall)
176
177 // Note that most of these async functions are meant to run in the background
178 // which is why we don't await them here and why they are not allowed to throw
179
180 let remoteVerifiedAddress = null
181 for (const addr of this.remoteAddresses) {
182 if (addr.verified) {
183 remoteVerifiedAddress = addr
184 break
185 }
186 }
187
188 if (local === FIREWALL.CONSISTENT && remote === FIREWALL.CONSISTENT) {
189 this.dht.stats.punches.consistent++
190 this._consistentProbe()
191 return true
192 }
193
194 if (!remoteVerifiedAddress) return false
195
196 if (local === FIREWALL.CONSISTENT && remote >= FIREWALL.RANDOM) {
197 this.dht.stats.punches.random++
198 this._incrementRandomized()
199 this._randomProbes(remoteVerifiedAddress)
200 return true
201 }
202
203 if (local >= FIREWALL.RANDOM && remote === FIREWALL.CONSISTENT) {
204 this.dht.stats.punches.random++
205 this._incrementRandomized()
206 await this._openBirthdaySockets(remoteVerifiedAddress)
207 if (this.punching) this._keepAliveRandomNat(remoteVerifiedAddress)
208 return true
209 }
210
211 return false
212 }
213
214 // Note that this never throws so it is safe to run in the background
215 async _consistentProbe() {
216 // Here we do the sleep first because the "fast open" mode in the server just fired a ping
217 if (!this.isInitiator) await this._sleeper.pause(1000)
218
219 let tries = 0
220
221 while (this.punching && tries++ < 10) {
222 for (const addr of this.remoteAddresses) {
223 // only try unverified addresses every 4 ticks
224 if (!addr.verified && (tries & 3) !== 0) continue
225 await holepunch(this._holder.socket, addr, false)
226 }
227 if (this.punching) await this._sleeper.pause(1000)
228 }
229
230 this._autoDestroy()
231 }
232
233 // Note that this never throws so it is safe to run in the background
234 async _randomProbes(remoteAddr) {
235 let tries = 1750 // ~35s
236
237 while (this.punching && tries-- > 0) {
238 const addr = { host: remoteAddr.host, port: randomPort() }
239 await holepunch(this._holder.socket, addr, false)
240 if (this.punching) await this._sleeper.pause(20)
241 }
242
243 this._autoDestroy()
244 }
245
246 // Note that this never throws so it is safe to run in the background
247 async _keepAliveRandomNat(remoteAddr) {
248 let i = 0
249 let lowTTLRounds = 1
250
251 // TODO: experiment with this here. We just bursted all the messages in
252 // openOtherSockets to ensure the sockets are open, so it's potentially
253 // a good idea to slow down for a bit.
254 await this._sleeper.pause(100)
255
256 let tries = 1750 // ~35s
257
258 while (this.punching && tries-- > 0) {
259 if (i === this._allHolders.length) {
260 i = 0
261 if (lowTTLRounds > 0) lowTTLRounds--
262 }
263
264 await holepunch(this._allHolders[i++].socket, remoteAddr, lowTTLRounds > 0)
265 if (this.punching) await this._sleeper.pause(20)
266 }
267
268 this._autoDestroy()
269 }
270
271 async _openBirthdaySockets(remoteAddr) {
272 while (this.punching && this._allHolders.length < BIRTHDAY_SOCKETS) {
273 const ref = this._addRef(this.dht._socketPool.acquire())
274 await holepunch(ref.socket, remoteAddr, HOLEPUNCH_TTL)
275 }
276 }
277
278 _autoDestroy() {
279 if (!this.connected) this.destroy()
280 }
281
282 _incrementRandomized() {
283 if (!this.randomized) {
284 this.randomized = true
285 this.dht._randomPunches++
286 }
287 }
288
289 _decrementRandomized() {
290 if (this.randomized) {
291 this.dht._lastRandomPunch = Date.now()
292 this.randomized = false
293 this.dht._randomPunches--
294 }
295 }
296
297 destroy() {
298 if (this.destroyed) return
299 this.destroyed = true
300 this.punching = false
301
302 for (const ref of this._allHolders) ref.release()
303 this._allHolders = []
304 this.nat.destroy()
305
306 if (!this.connected) {
307 this._decrementRandomized()
308 this.onabort()
309 }
310 }
311
312 static ping(socket, addr) {
313 return holepunch(socket, addr, false)
314 }
315
316 static localAddresses(socket) {
317 return localAddresses(socket)
318 }
319
320 static matchAddress(myAddresses, externalAddresses) {
321 return matchAddress(myAddresses, externalAddresses)
322 }
323}
324
325function holepunch(socket, addr, lowTTL) {
326 return socket.send(HOLEPUNCH, addr.port, addr.host, lowTTL ? HOLEPUNCH_TTL : DEFAULT_TTL)
327}
328
329function randomPort() {
330 return (1000 + Math.random() * 64536) | 0
331}
332
333function coerceFirewall(fw) {
334 return fw === FIREWALL.OPEN ? FIREWALL.CONSISTENT : fw
335}
336
337function localAddresses(socket) {
338 const addrs = []
339 const { host, port } = socket.address()
340
341 if (host === '127.0.0.1') return [{ host, port }]
342
343 for (const n of socket.udx.networkInterfaces()) {
344 if (n.family !== 4 || n.internal) continue
345
346 addrs.push({ host: n.host, port })
347 }
348
349 if (addrs.length === 0) {
350 addrs.push({ host: '127.0.0.1', port })
351 }
352
353 return addrs
354}
355
356function matchAddress(localAddresses, remoteLocalAddresses) {
357 if (remoteLocalAddresses.length === 0) return null
358
359 let best = { segment: 1, addr: null }
360
361 for (const localAddress of localAddresses) {
362 // => 192.168.122.238
363 const a = localAddress.host.split('.')
364
365 for (const remoteAddress of remoteLocalAddresses) {
366 // => 192.168.0.23
367 // => 192.168.122.1
368 const b = remoteAddress.host.split('.')
369
370 // Matches 192.*.*.*
371 if (a[0] === b[0]) {
372 if (best.segment === 1) best = { segment: 2, addr: remoteAddress }
373
374 // Matches 192.168.*.*
375 if (a[1] === b[1]) {
376 if (best.segment === 2) best = { segment: 3, addr: remoteAddress }
377
378 // Matches 192.168.122.*
379 if (a[2] === b[2]) return remoteAddress
380 }
381 }
382 }
383 }
384
385 return best.addr
386}
387
388function noop() {}
node_modules/hyperdht/lib/messages.js +421 -0
……@@ -0,0 +1,421 @@
1const c = require('compact-encoding')
2
3const ipv4 = {
4 ...c.ipv4Address,
5 decode(state) {
6 const ip = c.ipv4Address.decode(state)
7 return {
8 host: ip.host,
9 port: ip.port
10 }
11 }
12}
13
14const ipv4Array = c.array(ipv4)
15
16const ipv6 = {
17 ...c.ipv6Address,
18 decode(state) {
19 const ip = c.ipv6Address.decode(state)
20 return {
21 host: ip.host,
22 port: ip.port
23 }
24 }
25}
26
27const ipv6Array = c.array(ipv6)
28
29exports.handshake = {
30 preencode(state, m) {
31 state.end += 1 + 1 + (m.peerAddress ? 6 : 0) + (m.relayAddress ? 6 : 0)
32 c.buffer.preencode(state, m.noise)
33 },
34 encode(state, m) {
35 const flags = (m.peerAddress ? 1 : 0) | (m.relayAddress ? 2 : 0)
36
37 c.uint.encode(state, flags)
38 c.uint.encode(state, m.mode)
39 c.buffer.encode(state, m.noise)
40
41 if (m.peerAddress) ipv4.encode(state, m.peerAddress)
42 if (m.relayAddress) ipv4.encode(state, m.relayAddress)
43 },
44 decode(state) {
45 const flags = c.uint.decode(state)
46
47 return {
48 mode: c.uint.decode(state),
49 noise: c.buffer.decode(state),
50 peerAddress: flags & 1 ? ipv4.decode(state) : null,
51 relayAddress: flags & 2 ? ipv4.decode(state) : null
52 }
53 }
54}
55
56const relayInfo = {
57 preencode(state, m) {
58 state.end += 12
59 },
60 encode(state, m) {
61 ipv4.encode(state, m.relayAddress)
62 ipv4.encode(state, m.peerAddress)
63 },
64 decode(state) {
65 return {
66 relayAddress: ipv4.decode(state),
67 peerAddress: ipv4.decode(state)
68 }
69 }
70}
71
72const relayInfoArray = c.array(relayInfo)
73
74const holepunchInfo = {
75 preencode(state, m) {
76 c.uint.preencode(state, m.id)
77 relayInfoArray.preencode(state, m.relays)
78 },
79 encode(state, m) {
80 c.uint.encode(state, m.id)
81 relayInfoArray.encode(state, m.relays)
82 },
83 decode(state) {
84 return {
85 id: c.uint.decode(state),
86 relays: relayInfoArray.decode(state)
87 }
88 }
89}
90
91const udxInfo = {
92 preencode(state, m) {
93 state.end += 2 // version + features
94 c.uint.preencode(state, m.id)
95 c.uint.preencode(state, m.seq)
96 },
97 encode(state, m) {
98 c.uint.encode(state, 1)
99 c.uint.encode(state, m.reusableSocket ? 1 : 0)
100 c.uint.encode(state, m.id)
101 c.uint.encode(state, m.seq)
102 },
103 decode(state) {
104 const version = c.uint.decode(state)
105 const features = c.uint.decode(state)
106
107 return {
108 version,
109 reusableSocket: (features & 1) !== 0,
110 id: c.uint.decode(state),
111 seq: c.uint.decode(state)
112 }
113 }
114}
115
116const secretStreamInfo = {
117 preencode(state, m) {
118 c.uint.preencode(state, 1)
119 },
120 encode(state, m) {
121 c.uint.encode(state, 1)
122 },
123 decode(state) {
124 return {
125 version: c.uint.decode(state)
126 }
127 }
128}
129
130const relayThroughInfo = {
131 preencode(state, m) {
132 c.uint.preencode(state, 1) // version
133 c.uint.preencode(state, 0) // flags
134 c.fixed32.preencode(state, m.publicKey)
135 c.fixed32.preencode(state, m.token)
136 },
137 encode(state, m) {
138 c.uint.encode(state, 1)
139 c.uint.encode(state, 0)
140 c.fixed32.encode(state, m.publicKey)
141 c.fixed32.encode(state, m.token)
142 },
143 decode(state) {
144 const version = c.uint.decode(state)
145 c.uint.decode(state)
146
147 return {
148 version,
149 publicKey: c.fixed32.decode(state),
150 token: c.fixed32.decode(state)
151 }
152 }
153}
154
155exports.noisePayload = {
156 preencode(state, m) {
157 state.end += 4 // version + flags + error + firewall
158 if (m.holepunch) holepunchInfo.preencode(state, m.holepunch)
159 if (m.addresses4 && m.addresses4.length) ipv4Array.preencode(state, m.addresses4)
160 if (m.addresses6 && m.addresses6.length) ipv6Array.preencode(state, m.addresses6)
161 if (m.udx) udxInfo.preencode(state, m.udx)
162 if (m.secretStream) secretStreamInfo.preencode(state, m.secretStream)
163 if (m.relayThrough) relayThroughInfo.preencode(state, m.relayThrough)
164 if (m.relayAddresses) ipv4Array.preencode(state, m.relayAddresses)
165 },
166 encode(state, m) {
167 let flags = 0
168
169 if (m.holepunch) flags |= 1
170 if (m.addresses4 && m.addresses4.length) flags |= 2
171 if (m.addresses6 && m.addresses6.length) flags |= 4
172 if (m.udx) flags |= 8
173 if (m.secretStream) flags |= 16
174 if (m.relayThrough) flags |= 32
175 if (m.relayAddresses) flags |= 64
176
177 c.uint.encode(state, 1) // version
178 c.uint.encode(state, flags)
179 c.uint.encode(state, m.error)
180 c.uint.encode(state, m.firewall)
181
182 if (m.holepunch) holepunchInfo.encode(state, m.holepunch)
183 if (m.addresses4 && m.addresses4.length) ipv4Array.encode(state, m.addresses4)
184 if (m.addresses6 && m.addresses6.length) ipv6Array.encode(state, m.addresses6)
185 if (m.udx) udxInfo.encode(state, m.udx)
186 if (m.secretStream) secretStreamInfo.encode(state, m.secretStream)
187 if (m.relayThrough) relayThroughInfo.encode(state, m.relayThrough)
188 if (m.relayAddresses) ipv4Array.encode(state, m.relayAddresses)
189 },
190 decode(state) {
191 const version = c.uint.decode(state)
192
193 if (version !== 1) {
194 // Do not attempt to decode but return this back to the user so they can
195 // actually handle it
196 return {
197 version,
198 error: 0,
199 firewall: 0,
200 holepunch: null,
201 addresses4: [],
202 addresses6: [],
203 udx: null,
204 secretStream: null,
205 relayThrough: null,
206 relayAddresses: null
207 }
208 }
209
210 const flags = c.uint.decode(state)
211
212 return {
213 version,
214 error: c.uint.decode(state),
215 firewall: c.uint.decode(state),
216 holepunch: (flags & 1) !== 0 ? holepunchInfo.decode(state) : null,
217 addresses4: (flags & 2) !== 0 ? ipv4Array.decode(state) : [],
218 addresses6: (flags & 4) !== 0 ? ipv6Array.decode(state) : [],
219 udx: (flags & 8) !== 0 ? udxInfo.decode(state) : null,
220 secretStream: (flags & 16) !== 0 ? secretStreamInfo.decode(state) : null,
221 relayThrough: (flags & 32) !== 0 ? relayThroughInfo.decode(state) : null,
222 relayAddresses: (flags & 64) !== 0 ? ipv4Array.decode(state) : null
223 }
224 }
225}
226
227exports.holepunch = {
228 preencode(state, m) {
229 state.end += 2
230 c.uint.preencode(state, m.id)
231 c.buffer.preencode(state, m.payload)
232 if (m.peerAddress) ipv4.preencode(state, m.peerAddress)
233 },
234 encode(state, m) {
235 const flags = m.peerAddress ? 1 : 0
236 c.uint.encode(state, flags)
237 c.uint.encode(state, m.mode)
238 c.uint.encode(state, m.id)
239 c.buffer.encode(state, m.payload)
240 if (m.peerAddress) ipv4.encode(state, m.peerAddress)
241 },
242 decode(state) {
243 const flags = c.uint.decode(state)
244 return {
245 mode: c.uint.decode(state),
246 id: c.uint.decode(state),
247 payload: c.buffer.decode(state),
248 peerAddress: flags & 1 ? ipv4.decode(state) : null
249 }
250 }
251}
252
253exports.holepunchPayload = {
254 preencode(state, m) {
255 state.end += 4 // flags + error + firewall + round
256 if (m.addresses) ipv4Array.preencode(state, m.addresses)
257 if (m.remoteAddress) state.end += 6
258 if (m.token) state.end += 32
259 if (m.remoteToken) state.end += 32
260 },
261 encode(state, m) {
262 const flags =
263 (m.connected ? 1 : 0) |
264 (m.punching ? 2 : 0) |
265 (m.addresses ? 4 : 0) |
266 (m.remoteAddress ? 8 : 0) |
267 (m.token ? 16 : 0) |
268 (m.remoteToken ? 32 : 0)
269
270 c.uint.encode(state, flags)
271 c.uint.encode(state, m.error)
272 c.uint.encode(state, m.firewall)
273 c.uint.encode(state, m.round)
274
275 if (m.addresses) ipv4Array.encode(state, m.addresses)
276 if (m.remoteAddress) ipv4.encode(state, m.remoteAddress)
277 if (m.token) c.fixed32.encode(state, m.token)
278 if (m.remoteToken) c.fixed32.encode(state, m.remoteToken)
279 },
280 decode(state) {
281 const flags = c.uint.decode(state)
282
283 return {
284 error: c.uint.decode(state),
285 firewall: c.uint.decode(state),
286 round: c.uint.decode(state),
287 connected: (flags & 1) !== 0,
288 punching: (flags & 2) !== 0,
289 addresses: (flags & 4) !== 0 ? ipv4Array.decode(state) : null,
290 remoteAddress: (flags & 8) !== 0 ? ipv4.decode(state) : null,
291 token: (flags & 16) !== 0 ? c.fixed32.decode(state) : null,
292 remoteToken: (flags & 32) !== 0 ? c.fixed32.decode(state) : null
293 }
294 }
295}
296
297const peer = (exports.peer = {
298 preencode(state, m) {
299 state.end += 32
300 ipv4Array.preencode(state, m.relayAddresses)
301 },
302 encode(state, m) {
303 c.fixed32.encode(state, m.publicKey)
304 ipv4Array.encode(state, m.relayAddresses)
305 },
306 decode(state) {
307 return {
308 publicKey: c.fixed32.decode(state),
309 relayAddresses: ipv4Array.decode(state)
310 }
311 }
312})
313
314const peers = (exports.peers = c.array(peer))
315
316const rawPeers = c.array(c.raw)
317
318exports.lookupRawReply = {
319 preencode(state, m) {
320 rawPeers.preencode(state, m.peers)
321 c.uint.preencode(state, m.bump)
322 },
323 encode(state, m) {
324 rawPeers.encode(state, m.peers)
325 c.uint.encode(state, m.bump)
326 },
327 decode(state) {
328 return {
329 peers: peers.decode(state),
330 bump: state.start < state.end ? c.uint.decode(state) : 0
331 }
332 }
333}
334
335exports.announce = {
336 preencode(state, m) {
337 state.end++ // flags
338 if (m.peer) peer.preencode(state, m.peer)
339 if (m.refresh) state.end += 32
340 if (m.signature) state.end += 64
341 if (m.bump) c.uint.preencode(state, m.bump)
342 },
343 encode(state, m) {
344 const flags = (m.peer ? 1 : 0) | (m.refresh ? 2 : 0) | (m.signature ? 4 : 0) | (m.bump ? 8 : 0)
345 c.uint.encode(state, flags)
346 if (m.peer) peer.encode(state, m.peer)
347 if (m.refresh) c.fixed32.encode(state, m.refresh)
348 if (m.signature) c.fixed64.encode(state, m.signature)
349 if (m.bump) c.uint.encode(state, m.bump)
350 },
351 decode(state) {
352 const flags = c.uint.decode(state)
353
354 return {
355 peer: (flags & 1) !== 0 ? peer.decode(state) : null,
356 refresh: (flags & 2) !== 0 ? c.fixed32.decode(state) : null,
357 signature: (flags & 4) !== 0 ? c.fixed64.decode(state) : null,
358 bump: (flags & 8) !== 0 ? c.uint.decode(state) : 0
359 }
360 }
361}
362
363exports.mutableSignable = {
364 preencode(state, m) {
365 c.uint.preencode(state, m.seq)
366 c.buffer.preencode(state, m.value)
367 },
368 encode(state, m) {
369 c.uint.encode(state, m.seq)
370 c.buffer.encode(state, m.value)
371 },
372 decode(state) {
373 return {
374 seq: c.uint.decode(state),
375 value: c.buffer.decode(state)
376 }
377 }
378}
379
380exports.mutablePutRequest = {
381 preencode(state, m) {
382 c.fixed32.preencode(state, m.publicKey)
383 c.uint.preencode(state, m.seq)
384 c.buffer.preencode(state, m.value)
385 c.fixed64.preencode(state, m.signature)
386 },
387 encode(state, m) {
388 c.fixed32.encode(state, m.publicKey)
389 c.uint.encode(state, m.seq)
390 c.buffer.encode(state, m.value)
391 c.fixed64.encode(state, m.signature)
392 },
393 decode(state) {
394 return {
395 publicKey: c.fixed32.decode(state),
396 seq: c.uint.decode(state),
397 value: c.buffer.decode(state),
398 signature: c.fixed64.decode(state)
399 }
400 }
401}
402
403exports.mutableGetResponse = {
404 preencode(state, m) {
405 c.uint.preencode(state, m.seq)
406 c.buffer.preencode(state, m.value)
407 c.fixed64.preencode(state, m.signature)
408 },
409 encode(state, m) {
410 c.uint.encode(state, m.seq)
411 c.buffer.encode(state, m.value)
412 c.fixed64.encode(state, m.signature)
413 },
414 decode(state) {
415 return {
416 seq: c.uint.decode(state),
417 value: c.buffer.decode(state),
418 signature: c.fixed64.decode(state)
419 }
420 }
421}
node_modules/hyperdht/lib/nat.js +207 -0
……@@ -0,0 +1,207 @@
1const { FIREWALL } = require('../lib/constants')
2
3module.exports = class Nat {
4 constructor(dht, session, socket) {
5 this._samplesHost = []
6 this._samplesFull = []
7 this._visited = new Map()
8 this._resolve = null
9 this._minSamples = 4
10 this._autoSampling = false
11
12 this.dht = dht
13 this.session = session
14 this.socket = socket
15
16 this.sampled = 0
17 this.firewall = dht.firewalled ? FIREWALL.UNKNOWN : FIREWALL.OPEN
18 this.addresses = null
19
20 this.analyzing = new Promise((resolve) => {
21 this._resolve = resolve
22 })
23 }
24
25 autoSample(retry = true) {
26 if (this._autoSampling) return
27 this._autoSampling = true
28
29 const self = this
30 const socket = this.socket
31 const maxPings = this._minSamples
32
33 let skip = this.dht.nodes.length >= 8 ? 5 : 0
34 let pending = 0
35
36 // TODO: it would be best to pick the nodes to help us based on latency to us
37 // That should reduce connect latency in general. We should investigate tracking that later on.
38
39 // TODO 2: try to pick nodes with different IPs as well, as that'll help multi IP cell connections...
40 // If we expose this from the nat sampler then the DHT should be able to help us filter out scams as well...
41
42 for (
43 let node = this.dht.nodes.latest;
44 node && this.sampled + pending < maxPings;
45 node = node.prev
46 ) {
47 if (skip > 0) {
48 skip--
49 continue
50 }
51
52 const ref = node.host + ':' + node.port
53
54 if (this._visited.has(ref)) continue
55 this._visited.set(ref, 1)
56
57 pending++
58 this.session.ping(node, { socket, retry: false }).then(onpong, onskip)
59 }
60
61 pending++
62 onskip()
63
64 function onpong(res) {
65 self.add(res.to, res.from)
66 onskip()
67 }
68
69 function onskip() {
70 if (--pending === 0 && self.sampled < self._minSamples) {
71 if (retry) {
72 self._autoSampling = false
73 self.autoSample(false)
74 return
75 }
76 self._resolve()
77 }
78 }
79 }
80
81 destroy() {
82 this._autoSampling = true
83 this._minSamples = 0
84 this._resolve()
85 }
86
87 unfreeze() {
88 this.frozen = false
89 this._updateFirewall()
90 this._updateAddresses()
91 }
92
93 freeze() {
94 this.frozen = true
95 }
96
97 _updateFirewall() {
98 if (!this.dht.firewalled) {
99 this.firewall = FIREWALL.OPEN
100 return
101 }
102
103 if (this.sampled < 3) return
104
105 const max = this._samplesFull[0].hits
106
107 if (max >= 3) {
108 this.firewall = FIREWALL.CONSISTENT
109 return
110 }
111
112 if (max === 1) {
113 this.firewall = FIREWALL.RANDOM
114 return
115 }
116
117 // else max === 2
118
119 // 1 host, >= 4 total samples ie, 2 bad ones -> random
120 if (this._samplesHost.length === 1 && this.sampled > 3) {
121 this.firewall = FIREWALL.RANDOM
122 return
123 }
124
125 // double hit on two different ips -> assume consistent
126 if (this._samplesHost.length > 1 && this._samplesFull[1].hits > 1) {
127 this.firewall = FIREWALL.CONSISTENT
128 return
129 }
130
131 // (4 is just means - all the samples we expect) - no decision - assume random
132 if (this.sampled > 4) {
133 this.firewall = FIREWALL.RANDOM
134 }
135 }
136
137 _updateAddresses() {
138 if (this.firewall === FIREWALL.UNKNOWN) {
139 this.addresses = null
140 return
141 }
142
143 if (this.firewall === FIREWALL.RANDOM) {
144 this.addresses = [this._samplesHost[0]]
145 return
146 }
147
148 if (this.firewall === FIREWALL.CONSISTENT) {
149 this.addresses = []
150 for (const addr of this._samplesFull) {
151 if (addr.hits >= 2 || this.addresses.length < 2) this.addresses.push(addr)
152 }
153 }
154 }
155
156 update() {
157 if (this.dht.firewalled && this.firewall === FIREWALL.OPEN) {
158 this.firewall = FIREWALL.UNKNOWN
159 }
160 this._updateFirewall()
161 this._updateAddresses()
162 }
163
164 add(addr, from) {
165 const ref = from.host + ':' + from.port
166
167 if (this._visited.get(ref) === 2) return
168 this._visited.set(ref, 2)
169
170 addSample(this._samplesHost, addr.host, 0)
171 addSample(this._samplesFull, addr.host, addr.port)
172
173 if ((++this.sampled >= 3 || !this.dht.firewalled) && !this.frozen) {
174 this.update()
175 }
176
177 if (this.firewall === FIREWALL.CONSISTENT || this.firewall === FIREWALL.OPEN) {
178 this._resolve()
179 } else if (this.sampled >= this._minSamples) {
180 this._resolve()
181 }
182 }
183}
184
185function addSample(samples, host, port) {
186 for (let i = 0; i < samples.length; i++) {
187 const s = samples[i]
188
189 if (s.port !== port || s.host !== host) continue
190 s.hits++
191
192 for (; i > 0; i--) {
193 const prev = samples[i - 1]
194 if (prev.hits >= s.hits) return
195 samples[i - 1] = s
196 samples[i] = prev
197 }
198
199 return
200 }
201
202 samples.push({
203 host,
204 port,
205 hits: 1
206 })
207}
node_modules/hyperdht/lib/noise-wrap.js +52 -0
……@@ -0,0 +1,52 @@
1const NoiseSecretStream = require('@hyperswarm/secret-stream')
2const NoiseHandshake = require('noise-handshake')
3const curve = require('noise-curve-ed')
4const c = require('compact-encoding')
5const b4a = require('b4a')
6const sodium = require('sodium-universal')
7const m = require('./messages')
8const { NS } = require('./constants')
9const { HANDSHAKE_UNFINISHED } = require('./errors')
10
11const NOISE_PROLOUGE = NS.PEER_HANDSHAKE
12
13module.exports = class NoiseWrap {
14 constructor(keyPair, remotePublicKey) {
15 this.isInitiator = !!remotePublicKey
16 this.remotePublicKey = remotePublicKey
17 this.keyPair = keyPair
18 this.handshake = new NoiseHandshake('IK', this.isInitiator, keyPair, { curve })
19 this.handshake.initialise(NOISE_PROLOUGE, remotePublicKey)
20 }
21
22 send(payload) {
23 const buf = c.encode(m.noisePayload, payload)
24 return this.handshake.send(buf)
25 }
26
27 recv(buf) {
28 const payload = c.decode(m.noisePayload, this.handshake.recv(buf))
29 this.remotePublicKey = b4a.toBuffer(this.handshake.rs)
30 return payload
31 }
32
33 final() {
34 if (!this.handshake.complete) throw HANDSHAKE_UNFINISHED()
35
36 const holepunchSecret = b4a.allocUnsafe(32)
37
38 sodium.crypto_generichash(holepunchSecret, NS.PEER_HOLEPUNCH, this.handshake.hash)
39
40 return {
41 isInitiator: this.isInitiator,
42 publicKey: this.keyPair.publicKey,
43 streamId: this.streamId,
44 remotePublicKey: this.remotePublicKey,
45 remoteId: NoiseSecretStream.id(this.handshake.hash, !this.isInitiator),
46 holepunchSecret,
47 hash: b4a.toBuffer(this.handshake.hash),
48 rx: b4a.toBuffer(this.handshake.rx),
49 tx: b4a.toBuffer(this.handshake.tx)
50 }
51 }
52}
node_modules/hyperdht/lib/persistent.js +303 -0
……@@ -0,0 +1,303 @@
1const c = require('compact-encoding')
2const sodium = require('sodium-universal')
3const RecordCache = require('record-cache')
4const Cache = require('xache')
5const b4a = require('b4a')
6const unslab = require('unslab')
7
8const { encodeUnslab } = require('./encode')
9const m = require('./messages')
10const { NS, ERROR } = require('./constants')
11
12const EMPTY = b4a.alloc(0)
13const TMP = b4a.allocUnsafe(32)
14const MAX_BUMP_DRIFT = 60_000
15
16module.exports = class Persistent {
17 constructor(dht, opts) {
18 this.dht = dht
19 this.records = new RecordCache(opts.records)
20 this.bumps = new Cache(opts.bumps)
21 this.refreshes = new Cache(opts.refreshes)
22 this.mutables = new Cache(opts.mutables)
23 this.immutables = new Cache(opts.immutables)
24 }
25
26 onlookup(req) {
27 if (!req.target) return
28
29 const k = b4a.toString(req.target, 'hex')
30 const records = this.records.get(k, 20)
31 const bump = this.bumps.get(k) || 0
32 const fwd = this.dht._router.get(k)
33
34 if (fwd && records.length < 20) records.push(fwd.record)
35
36 req.reply(records.length ? c.encode(m.lookupRawReply, { peers: records, bump }) : null)
37 }
38
39 onfindpeer(req) {
40 if (!req.target) return
41 const fwd = this.dht._router.get(req.target)
42 req.reply(fwd ? fwd.record : null)
43 }
44
45 unannounce(target, publicKey) {
46 const k = b4a.toString(target, 'hex')
47 sodium.crypto_generichash(TMP, publicKey)
48
49 if (b4a.equals(TMP, target)) this.dht._router.delete(k)
50 this.records.remove(k, publicKey)
51 }
52
53 onunannounce(req) {
54 if (!req.target || !req.token) return
55
56 const unann = decode(m.announce, req.value)
57 if (unann === null) return
58
59 const { peer, signature } = unann
60 if (!peer || !signature) return
61
62 const signable = annSignable(req.target, req.token, this.dht.id, unann, NS.UNANNOUNCE)
63
64 if (!sodium.crypto_sign_verify_detached(signature, signable, peer.publicKey)) {
65 return
66 }
67
68 this.unannounce(req.target, peer.publicKey)
69 req.reply(null, { token: false, closerNodes: false })
70 }
71
72 _onrefresh(token, req) {
73 sodium.crypto_generichash(TMP, token)
74 const activeRefresh = b4a.toString(TMP, 'hex')
75
76 const r = this.refreshes.get(activeRefresh)
77 if (!r) return
78
79 const { announceSelf, k, record } = r
80 const publicKey = record.subarray(0, 32)
81
82 if (announceSelf) {
83 this.dht._router.set(k, {
84 relay: req.from,
85 record,
86 onconnect: null,
87 onholepunch: null
88 })
89 this.records.remove(k, publicKey)
90 } else {
91 this.records.add(k, publicKey, record)
92 }
93
94 this.refreshes.delete(activeRefresh)
95 this.refreshes.set(b4a.toString(token, 'hex'), r)
96
97 req.reply(null, { token: false, closerNodes: false })
98 }
99
100 onannounce(req) {
101 if (!req.target || !req.token || !this.dht.id) return
102
103 const ann = decode(m.announce, req.value)
104 if (ann === null) return
105
106 const { peer, refresh, signature, bump } = ann
107
108 if (!peer) {
109 if (!refresh) return
110 this._onrefresh(refresh, req)
111 return
112 }
113
114 const signable = annSignable(req.target, req.token, this.dht.id, ann, NS.ANNOUNCE)
115
116 if (!signature || !sodium.crypto_sign_verify_detached(signature, signable, peer.publicKey)) {
117 return
118 }
119
120 // TODO: it would be potentially be more optimal to allow more than 3 addresses here for a findPeer response
121 // and only use max 3 for a lookup reply
122 if (peer.relayAddresses.length > 3) {
123 peer.relayAddresses = peer.relayAddresses.slice(0, 3)
124 }
125
126 sodium.crypto_generichash(TMP, peer.publicKey)
127
128 const k = b4a.toString(req.target, 'hex')
129 const announceSelf = b4a.equals(TMP, req.target)
130 const record = encodeUnslab(m.peer, peer)
131
132 if (announceSelf) {
133 this.dht._router.set(k, {
134 relay: req.from,
135 record,
136 onconnect: null,
137 onholepunch: null
138 })
139 this.records.remove(k, peer.publicKey)
140 } else {
141 const currentBump = this.bumps.get(k) || 0
142 if (bump > currentBump && bump <= Date.now() + MAX_BUMP_DRIFT) this.bumps.set(k, bump)
143 this.records.add(k, peer.publicKey, record)
144 }
145
146 if (refresh) {
147 this.refreshes.set(b4a.toString(refresh, 'hex'), { k, record, announceSelf })
148 }
149
150 req.reply(null, { token: false, closerNodes: false })
151 }
152
153 onmutableget(req) {
154 if (!req.target || !req.value) return
155
156 let seq = 0
157 try {
158 seq = c.decode(c.uint, req.value)
159 } catch {
160 return
161 }
162
163 const k = b4a.toString(req.target, 'hex')
164 const value = this.mutables.get(k)
165
166 if (!value) {
167 req.reply(null)
168 return
169 }
170
171 const localSeq = c.decode(c.uint, value)
172 req.reply(localSeq < seq ? null : value)
173 }
174
175 onmutableput(req) {
176 if (!req.target || !req.token || !req.value) return
177
178 const p = decode(m.mutablePutRequest, req.value)
179 if (!p) return
180
181 const { publicKey, seq, value, signature } = p
182
183 const hash = b4a.allocUnsafe(32)
184 sodium.crypto_generichash(hash, publicKey)
185 if (!b4a.equals(hash, req.target)) return
186
187 if (!value || !verifyMutable(signature, seq, value, publicKey)) return
188
189 const k = b4a.toString(hash, 'hex')
190 const local = this.mutables.get(k)
191
192 if (local) {
193 const existing = c.decode(m.mutableGetResponse, local)
194 if (existing.value && existing.seq === seq && b4a.compare(value, existing.value) !== 0) {
195 req.error(ERROR.SEQ_REUSED)
196 return
197 }
198 if (seq < existing.seq) {
199 req.error(ERROR.SEQ_TOO_LOW)
200 return
201 }
202 }
203
204 this.mutables.set(k, encodeUnslab(m.mutableGetResponse, { seq, value, signature }))
205 req.reply(null)
206 }
207
208 onimmutableget(req) {
209 if (!req.target) return
210
211 const k = b4a.toString(req.target, 'hex')
212 const value = this.immutables.get(k)
213
214 req.reply(value || null)
215 }
216
217 onimmutableput(req) {
218 if (!req.target || !req.token || !req.value) return
219
220 const hash = b4a.alloc(32)
221 sodium.crypto_generichash(hash, req.value)
222 if (!b4a.equals(hash, req.target)) return
223
224 const k = b4a.toString(hash, 'hex')
225 this.immutables.set(k, unslab(req.value))
226
227 req.reply(null)
228 }
229
230 destroy() {
231 this.records.destroy()
232 this.refreshes.destroy()
233 this.mutables.destroy()
234 this.immutables.destroy()
235 }
236
237 static signMutable(seq, value, keyPair) {
238 const signable = b4a.allocUnsafe(32 + 32)
239 const hash = signable.subarray(32)
240
241 signable.set(NS.MUTABLE_PUT, 0)
242
243 sodium.crypto_generichash(hash, c.encode(m.mutableSignable, { seq, value }))
244 return sign(signable, keyPair)
245 }
246
247 static verifyMutable(signature, seq, value, publicKey) {
248 return verifyMutable(signature, seq, value, publicKey)
249 }
250
251 static signAnnounce(target, token, id, ann, keyPair) {
252 return sign(annSignable(target, token, id, ann, NS.ANNOUNCE), keyPair)
253 }
254
255 static signUnannounce(target, token, id, ann, keyPair) {
256 return sign(annSignable(target, token, id, ann, NS.UNANNOUNCE), keyPair)
257 }
258}
259
260function verifyMutable(signature, seq, value, publicKey) {
261 const signable = b4a.allocUnsafe(32 + 32)
262 const hash = signable.subarray(32)
263
264 signable.set(NS.MUTABLE_PUT, 0)
265
266 sodium.crypto_generichash(hash, c.encode(m.mutableSignable, { seq, value }))
267 return sodium.crypto_sign_verify_detached(signature, signable, publicKey)
268}
269
270function annSignable(target, token, id, ann, ns) {
271 const signable = b4a.allocUnsafe(32 + 32)
272 const hash = signable.subarray(32)
273
274 signable.set(ns, 0)
275
276 sodium.crypto_generichash_batch(hash, [
277 target,
278 id,
279 token,
280 c.encode(m.peer, ann.peer), // note that this is the partial encoding of the announce message so we could just use that for perf
281 ann.refresh || EMPTY
282 ])
283
284 return signable
285}
286
287function sign(signable, keyPair) {
288 if (keyPair.sign) {
289 return keyPair.sign(signable)
290 }
291 const secretKey = keyPair.secretKey ? keyPair.secretKey : keyPair
292 const signature = b4a.allocUnsafe(64)
293 sodium.crypto_sign_detached(signature, signable, secretKey)
294 return signature
295}
296
297function decode(enc, val) {
298 try {
299 return val && c.decode(enc, val)
300 } catch (err) {
301 return null
302 }
303}
node_modules/hyperdht/lib/raw-stream-set.js +66 -0
……@@ -0,0 +1,66 @@
1module.exports = class RawStreamSet {
2 constructor(dht) {
3 this._dht = dht
4
5 this._prefix = 16 - 1 // 16 is the default stream-set side in udx
6 this._streams = new Map()
7 }
8
9 get size() {
10 return this._streams.size
11 }
12
13 [Symbol.iterator]() {
14 return this._streams.values()
15 }
16
17 add(opts) {
18 const self = this
19
20 // TODO: we should prob have a udx helper for id generation, given the slight complexity
21 // of the below. requires a PRNG in udx tho.
22
23 let id = 0
24
25 while (true) {
26 id = (Math.random() * 0x100000000) >>> 0
27
28 if (this._streams.has(id & this._prefix)) continue
29 break
30 }
31
32 // always have ~50% change of rolling a free one
33 if (2 * this._streams.size >= this._prefix) {
34 // ie 0b11111 = 0b1111 + 1 + 0b1111
35 this._prefix = 2 * this._prefix + 1
36
37 // move the prefixes over
38 const next = new Map()
39 for (const stream of this._streams.values()) {
40 next.set(stream.id & this._prefix, stream)
41 }
42 this._streams = next
43 }
44
45 const stream = this._dht.udx.createStream(id, opts)
46 this._streams.set(id & this._prefix, stream)
47
48 stream.on('close', onclose)
49
50 return stream
51
52 function onclose() {
53 self._streams.delete(id & self._prefix)
54 }
55 }
56
57 async clear() {
58 const destroying = []
59
60 for (const stream of this._streams.values()) {
61 destroying.push(new Promise((resolve) => stream.once('close', resolve).destroy()))
62 }
63
64 await Promise.allSettled(destroying)
65 }
66}
node_modules/hyperdht/lib/refresh-chain.js +20 -0
……@@ -0,0 +1,20 @@
1const sodium = require('sodium-universal')
2const b4a = require('b4a')
3
4module.exports = function createRefreshChain(cnt) {
5 const blocks = new Array(cnt)
6 if (!blocks.length) return blocks
7
8 const all = b4a.allocUnsafe(cnt * 32 + 32)
9
10 let prev = all.subarray(all.byteLength - 32)
11 sodium.randombytes_buf(prev)
12
13 for (let i = cnt - 1; i >= 0; i--) {
14 blocks[i] = all.subarray(32 * i, 32 * i + 32)
15 sodium.crypto_generichash(blocks[i], prev)
16 prev = blocks[i]
17 }
18
19 return blocks
20}
node_modules/hyperdht/lib/router.js +261 -0
……@@ -0,0 +1,261 @@
1const c = require('compact-encoding')
2const Cache = require('xache')
3const safetyCatch = require('safety-catch')
4const b4a = require('b4a')
5const { handshake, holepunch } = require('./messages')
6const { COMMANDS } = require('./constants')
7const { BAD_HANDSHAKE_REPLY, BAD_HOLEPUNCH_REPLY } = require('./errors')
8
9const FROM_CLIENT = 0
10const FROM_SERVER = 1
11const FROM_RELAY = 2
12const FROM_SECOND_RELAY = 3
13const REPLY = 4
14
15// TODO: While the current design is very trustless in regards to clients/servers trusting the DHT,
16// we should add a bunch of rate limits everywhere, especially including here to avoid bad users
17// using a DHT node to relay traffic indiscriminately using the connect/holepunch messages.
18// That's mostly from an abuse POV as none of the messsages do amplication.
19
20module.exports = class Router {
21 constructor(dht, opts) {
22 this.dht = dht
23 this.forwards = new Cache(opts.forwards)
24 }
25
26 set(target, state) {
27 if (state.onpeerhandshake) {
28 this.forwards.retain(toString(target), state)
29 } else {
30 this.forwards.set(toString(target), state)
31 }
32 }
33
34 get(target) {
35 return this.forwards.get(toString(target))
36 }
37
38 delete(target) {
39 this.forwards.delete(toString(target))
40 }
41
42 destroy() {
43 this.forwards.destroy()
44 }
45
46 async peerHandshake(target, { noise, peerAddress, relayAddress, socket, session }, to) {
47 const dht = this.dht
48
49 const requestValue = c.encode(handshake, {
50 mode: FROM_CLIENT,
51 noise,
52 peerAddress,
53 relayAddress
54 })
55
56 const res = await dht.request(
57 { command: COMMANDS.PEER_HANDSHAKE, target, value: requestValue },
58 to,
59 { socket, session }
60 )
61
62 const hs = decode(handshake, res.value)
63 if (
64 !hs ||
65 hs.mode !== REPLY ||
66 to.host !== res.from.host ||
67 to.port !== res.from.port ||
68 !hs.noise
69 ) {
70 throw BAD_HANDSHAKE_REPLY()
71 }
72
73 return {
74 noise: hs.noise,
75 relayed: !!hs.peerAddress,
76 serverAddress: hs.peerAddress || to,
77 clientAddress: res.to
78 }
79 }
80
81 async onpeerhandshake(req) {
82 const hs = req.value && decode(handshake, req.value)
83 if (!hs) return
84
85 const { mode, noise, peerAddress, relayAddress } = hs
86
87 const state = req.target && this.get(req.target)
88 const isServer = !!(state && state.onpeerhandshake)
89 const relay = state && state.relay
90
91 if (isServer) {
92 let reply = null
93 try {
94 reply = noise && (await state.onpeerhandshake({ noise, peerAddress }, req))
95 } catch (e) {
96 safetyCatch(e)
97 return
98 }
99 if (!reply || !reply.noise) return
100 const opts = { socket: reply.socket, closerNodes: false, token: false }
101
102 switch (mode) {
103 case FROM_CLIENT: {
104 req.reply(
105 c.encode(handshake, { mode: REPLY, noise: reply.noise, peerAddress: null }),
106 opts
107 )
108 return
109 }
110 case FROM_RELAY: {
111 req.relay(
112 c.encode(handshake, { mode: FROM_SERVER, noise: reply.noise, peerAddress }),
113 req.from,
114 opts
115 )
116 return
117 }
118 case FROM_SECOND_RELAY: {
119 if (!relayAddress) return
120 req.relay(
121 c.encode(handshake, { mode: FROM_SERVER, noise: reply.noise, peerAddress }),
122 relayAddress,
123 opts
124 )
125 return // eslint-disable-line
126 }
127 }
128 } else {
129 switch (mode) {
130 case FROM_CLIENT: {
131 // TODO: if no relay is known route closer to the target instead of timing out
132 if (!noise) return
133 if (!relay && !relayAddress) {
134 // help the user route
135 req.reply(null, { token: false, closerNodes: true })
136 return
137 }
138 req.relay(
139 c.encode(handshake, {
140 mode: FROM_RELAY,
141 noise,
142 peerAddress: req.from,
143 relayAddress: null
144 }),
145 relayAddress || relay
146 )
147 return
148 }
149 case FROM_RELAY: {
150 if (!relay || !noise) return
151 req.relay(
152 c.encode(handshake, {
153 mode: FROM_SECOND_RELAY,
154 noise,
155 peerAddress,
156 relayAddress: req.from
157 }),
158 relay
159 )
160 return
161 }
162 case FROM_SERVER: {
163 if (!peerAddress || !noise) return
164 req.reply(
165 c.encode(handshake, { mode: REPLY, noise, peerAddress: req.from, relayAddress: null }),
166 { to: peerAddress, closerNodes: false, token: false }
167 )
168 return // eslint-disable-line
169 }
170 }
171 }
172 }
173
174 async peerHolepunch(target, { id, payload, peerAddress, socket, session }, to) {
175 const dht = this.dht
176 const requestValue = c.encode(holepunch, {
177 mode: FROM_CLIENT,
178 id,
179 payload,
180 peerAddress
181 })
182
183 const res = await dht.request(
184 { command: COMMANDS.PEER_HOLEPUNCH, target, value: requestValue },
185 to,
186 { socket, session }
187 )
188
189 const hp = decode(holepunch, res.value)
190 if (!hp || hp.mode !== REPLY || to.host !== res.from.host || to.port !== res.from.port) {
191 throw BAD_HOLEPUNCH_REPLY()
192 }
193
194 return {
195 from: res.from,
196 to: res.to,
197 payload: hp.payload,
198 peerAddress: hp.peerAddress || to
199 }
200 }
201
202 async onpeerholepunch(req) {
203 const hp = req.value && decode(holepunch, req.value)
204 if (!hp) return
205
206 const { mode, id, payload, peerAddress } = hp
207
208 const state = req.target && this.get(req.target)
209 const isServer = !!(state && state.onpeerholepunch)
210 const relay = state && state.relay
211
212 switch (mode) {
213 case FROM_CLIENT: {
214 if (!peerAddress && !relay) return
215 req.relay(
216 c.encode(holepunch, { mode: FROM_RELAY, id, payload, peerAddress: req.from }),
217 peerAddress || relay
218 )
219 return
220 }
221 case FROM_RELAY: {
222 if (!isServer || !peerAddress) return
223 let reply = null
224 try {
225 reply = await state.onpeerholepunch({ id, payload, peerAddress }, req)
226 } catch (e) {
227 safetyCatch(e)
228 return
229 }
230 if (!reply) return
231 const opts = { socket: reply.socket, closerNodes: false, token: false }
232 req.relay(
233 c.encode(holepunch, { mode: FROM_SERVER, id: 0, payload: reply.payload, peerAddress }),
234 req.from,
235 opts
236 )
237 return
238 }
239 case FROM_SERVER: {
240 req.reply(c.encode(holepunch, { mode: REPLY, id, payload, peerAddress: req.from }), {
241 to: peerAddress,
242 closerNodes: false,
243 token: false
244 })
245 return // eslint-disable-line
246 }
247 }
248 }
249}
250
251function decode(enc, val) {
252 try {
253 return c.decode(enc, val)
254 } catch {
255 return null
256 }
257}
258
259function toString(t) {
260 return typeof t === 'string' ? t : b4a.toString(t, 'hex')
261}
node_modules/hyperdht/lib/secure-payload.js +52 -0
……@@ -0,0 +1,52 @@
1const sodium = require('sodium-universal')
2const b4a = require('b4a')
3const { holepunchPayload } = require('./messages')
4
5module.exports = class HolepunchPayload {
6 constructor(holepunchSecret) {
7 this._sharedSecret = holepunchSecret
8 this._localSecret = b4a.allocUnsafe(32)
9
10 sodium.randombytes_buf(this._localSecret)
11 }
12
13 decrypt(buffer) {
14 const state = { start: 24, end: buffer.byteLength - 16, buffer }
15
16 if (state.end <= state.start) return null
17
18 const nonce = buffer.subarray(0, 24)
19 const msg = state.buffer.subarray(state.start, state.end)
20 const cipher = state.buffer.subarray(state.start)
21
22 if (!sodium.crypto_secretbox_open_easy(msg, cipher, nonce, this._sharedSecret)) return null
23
24 try {
25 return holepunchPayload.decode(state)
26 } catch {
27 return null
28 }
29 }
30
31 encrypt(payload) {
32 const state = { start: 24, end: 24, buffer: null }
33 holepunchPayload.preencode(state, payload)
34 state.buffer = b4a.allocUnsafe(state.end + 16)
35
36 const nonce = state.buffer.subarray(0, 24)
37 const msg = state.buffer.subarray(state.start, state.end)
38 const cipher = state.buffer.subarray(state.start)
39
40 holepunchPayload.encode(state, payload)
41 sodium.randombytes_buf(nonce)
42 sodium.crypto_secretbox_easy(cipher, msg, nonce, this._sharedSecret)
43
44 return state.buffer
45 }
46
47 token(addr) {
48 const out = b4a.allocUnsafe(32)
49 sodium.crypto_generichash(out, b4a.from(addr.host), this._localSecret)
50 return out
51 }
52}
node_modules/hyperdht/lib/semaphore.js +69 -0
……@@ -0,0 +1,69 @@
1const DONE = Promise.resolve(true)
2const DESTROYED = Promise.resolve(false)
3
4module.exports = class Semaphore {
5 constructor(limit = 1) {
6 this.limit = limit
7 this.active = 0
8 this.waiting = []
9
10 this.flushedPromise = null
11 this.flushedResolve = null
12
13 this.destroyed = false
14
15 this._onwait = this._queueWaiting.bind(this)
16 this._onflush = this._queueFlushed.bind(this)
17 }
18
19 _queueWaiting(resolve) {
20 this.waiting.push(resolve)
21 }
22
23 _queueFlushed(resolve) {
24 this.flushedResolve = resolve
25 }
26
27 wait() {
28 if (this.destroyed === true) return DESTROYED
29
30 if (this.active < this.limit && this.waiting.length === 0) {
31 this.active++
32 return DONE
33 }
34
35 return new Promise(this._onwait)
36 }
37
38 signal() {
39 if (this.destroyed === true) return
40
41 this.active--
42 while (this.active < this.limit && this.waiting.length > 0 && this.destroyed === false) {
43 this.active++
44 this.waiting.shift()(true)
45 }
46
47 if (this.active === 0 && this.flushedResolve) {
48 const resolve = this.flushedResolve
49 this.flushedResolve = null
50 this.flushedPromise = null
51 resolve(true)
52 }
53 }
54
55 async flush() {
56 if (this.destroyed === true) return
57 if (this.active === 0) return
58 if (this.flushedPromise) return this.flushedPromise
59 this.flushedPromise = new Promise(this._onflush)
60 return this.flushedPromise
61 }
62
63 destroy() {
64 this.destroyed = true
65 this.active = 0
66 while (this.waiting.length) this.waiting.pop()(false)
67 if (this.flushedResolve) this.flushedResolve(false)
68 }
69}
node_modules/hyperdht/lib/server.js +736 -0
……@@ -0,0 +1,736 @@
1const { EventEmitter } = require('events')
2const safetyCatch = require('safety-catch')
3const NoiseSecretStream = require('@hyperswarm/secret-stream')
4const b4a = require('b4a')
5const relay = require('blind-relay')
6const NoiseWrap = require('./noise-wrap')
7const Announcer = require('./announcer')
8const { FIREWALL, ERROR } = require('./constants')
9const { unslabbedHash } = require('./crypto')
10const SecurePayload = require('./secure-payload')
11const Holepuncher = require('./holepuncher')
12const { isPrivate } = require('bogon')
13const { ALREADY_LISTENING, NODE_DESTROYED, KEYPAIR_ALREADY_USED } = require('./errors')
14
15const HANDSHAKE_CLEAR_WAIT = 10000
16const HANDSHAKE_INITIAL_TIMEOUT = 10000
17
18module.exports = class Server extends EventEmitter {
19 constructor(dht, opts = {}) {
20 super()
21
22 this.dht = dht
23 this.target = null
24
25 this.closed = false
26 this.firewall = opts.firewall || (() => false)
27 this.holepunch = opts.holepunch || (() => true)
28 this.relayThrough = opts.relayThrough || null
29 this.relayKeepAlive = opts.relayKeepAlive || 5000
30 this.pool = opts.pool || null
31 this.createHandshake = opts.createHandshake || defaultCreateHandshake
32 this.createSecretStream = opts.createSecretStream || defaultCreateSecretStream
33 this.suspended = false
34 this.handshakeClearWait = opts.handshakeClearWait || HANDSHAKE_CLEAR_WAIT
35
36 this._shareLocalAddress = opts.shareLocalAddress !== false
37 this._reusableSocket = !!opts.reusableSocket
38 this._neverPunch = opts.holepunch === false // useful for fully disabling punching
39 this._keyPair = null
40 this._announcer = null
41 this._connects = new Map()
42 this._holepunches = []
43 this._listening = null
44 this._closing = null
45 }
46
47 get listening() {
48 return this._listening !== null
49 }
50
51 get publicKey() {
52 return this._keyPair && this._keyPair.publicKey
53 }
54
55 get relayAddresses() {
56 return this._announcer ? this._announcer.relayAddresses : []
57 }
58
59 onconnection(encryptedSocket) {
60 this.emit('connection', encryptedSocket)
61 }
62
63 async suspend({ log = noop } = {}) {
64 log('Suspending hyperdht server')
65 if (this._listening !== null) await this._listening
66 log('Suspending hyperdht server (post listening)')
67 this.suspended = true
68 this._clearAll()
69 return this._announcer ? this._announcer.suspend({ log }) : Promise.resolve()
70 }
71
72 async resume() {
73 if (this._listening !== null) await this._listening
74 this.suspended = false
75 return this._announcer ? this._announcer.resume() : Promise.resolve()
76 }
77
78 address() {
79 if (!this._keyPair) return null
80
81 return {
82 publicKey: this._keyPair.publicKey,
83 host: this.dht.host,
84 port: this.dht.port
85 }
86 }
87
88 close() {
89 if (this._closing) return this._closing
90 this._closing = this._close()
91 return this._closing
92 }
93
94 _gc() {
95 this.dht.listening.delete(this)
96 if (this.target) this.dht._router.delete(this.target)
97 }
98
99 async _stopListening() {
100 try {
101 if (this._announcer) await this._announcer.stop()
102 } catch {
103 // ignore
104 }
105
106 this._announcer = null
107 this._listening = null
108 this._keyPair = null
109 }
110
111 async _close() {
112 if (this._listening === null) {
113 this.closed = true
114 this.emit('close')
115 return
116 }
117
118 try {
119 await this._listening
120 } catch {}
121
122 this._gc()
123 this._clearAll()
124
125 await this._stopListening()
126
127 this.closed = true
128 this.emit('close')
129 }
130
131 _clearAll() {
132 while (this._holepunches.length > 0) {
133 const h = this._holepunches.pop()
134 if (h && h.puncher) h.puncher.destroy()
135 if (h && h.clearing) clearTimeout(h.clearing)
136 if (h && h.prepunching) clearTimeout(h.prepunching)
137 if (h && h.rawStream) h.rawStream.destroy()
138 }
139
140 this._connects.clear()
141 }
142
143 async listen(keyPair = this.dht.defaultKeyPair, opts = {}) {
144 if (this._listening !== null) throw ALREADY_LISTENING()
145 if (this.dht.destroyed) throw NODE_DESTROYED()
146
147 this._listening = this._listen(keyPair, opts)
148 await this._listening
149 return this
150 }
151
152 async _listen(keyPair, opts) {
153 // From now on, the DHT object which created me is responsible for closing me
154 this.dht.listening.add(this)
155
156 try {
157 await this.dht.bind()
158 if (this._closing) return
159
160 for (const s of this.dht.listening) {
161 if (s._keyPair && b4a.equals(s._keyPair.publicKey, keyPair.publicKey)) {
162 throw KEYPAIR_ALREADY_USED()
163 }
164 }
165
166 this.target = unslabbedHash(keyPair.publicKey)
167 this._keyPair = keyPair
168 this._announcer = new Announcer(this.dht, keyPair, this.target, opts)
169
170 this.dht._router.set(this.target, {
171 relay: null,
172 record: this._announcer.record,
173 onpeerhandshake: this._onpeerhandshake.bind(this),
174 onpeerholepunch: this._onpeerholepunch.bind(this)
175 })
176
177 // warm it up for now
178 this._localAddresses().catch(safetyCatch)
179
180 await this._announcer.start()
181 } catch (err) {
182 await this._stopListening()
183 this._gc()
184 throw err
185 }
186
187 if (this._closing) return
188 if (this.suspended) await this._announcer.suspend()
189
190 if (this._closing) return
191 if (this.dht.destroyed) throw NODE_DESTROYED()
192
193 if (this.pool) this.pool._attachServer(this)
194
195 this.emit('listening')
196 }
197
198 refresh() {
199 if (this._announcer && !this.suspended) this._announcer.refresh()
200 }
201
202 notifyOnline() {
203 if (this._announcer) this._announcer.online.notify()
204 }
205
206 _localAddresses() {
207 return this.dht.validateLocalAddresses(Holepuncher.localAddresses(this.dht.io.serverSocket))
208 }
209
210 async _addHandshake(k, noise, clientAddress, { from, to: serverAddress, socket }, direct) {
211 let id = this._holepunches.indexOf(null)
212 if (id === -1) id = this._holepunches.push(null) - 1
213
214 const hs = {
215 round: 0,
216 reply: null,
217 puncher: null,
218 payload: null,
219 rawStream: null,
220 encryptedSocket: null,
221 prepunching: null,
222 firewalled: true,
223 clearing: null,
224 onsocket: null,
225 aborted: false,
226
227 // Relay state
228 relayTimeout: null,
229 relayToken: null,
230 relaySocket: null,
231 relayClient: null,
232 relayPaired: false
233 }
234
235 this._holepunches[id] = hs
236
237 const handshake = this.createHandshake(this._keyPair, null)
238
239 let remotePayload
240 try {
241 remotePayload = await handshake.recv(noise)
242 } catch (err) {
243 safetyCatch(err)
244 this._clearLater(hs, id, k)
245 return null
246 }
247
248 if (this._closing || this.suspended) return null
249
250 try {
251 hs.firewalled = await this.firewall(handshake.remotePublicKey, remotePayload, clientAddress)
252 } catch (err) {
253 safetyCatch(err)
254 }
255
256 if (this._closing || this.suspended) return null
257
258 if (hs.firewalled) {
259 this._clearLater(hs, id, k)
260 return null
261 }
262
263 const error =
264 remotePayload.version === 1
265 ? remotePayload.udx
266 ? ERROR.NONE
267 : ERROR.ABORTED
268 : ERROR.VERSION_MISMATCH
269
270 const addresses = []
271 const ourRemoteAddr = this.dht.remoteAddress()
272 const ourLocalAddrs = this._shareLocalAddress ? await this._localAddresses() : null
273
274 if (this._closing || this.suspended) return null
275
276 if (ourRemoteAddr) addresses.push(ourRemoteAddr)
277 if (ourLocalAddrs) addresses.push(...ourLocalAddrs)
278
279 if (error === ERROR.NONE) {
280 hs.rawStream = this.dht.createRawStream({
281 framed: true,
282 firewall(socket, port, host) {
283 if (!(port > 0 && port < 65536)) return true
284
285 // Check if the traffic originated from the socket on which we're expecting relay traffic. If so,
286 // we haven't hole punched yet and the other side is just sending us traffic through the relay.
287 if (hs.relaySocket && isRelay(hs.relaySocket, socket, port, host)) {
288 return false
289 }
290
291 hs.onsocket(socket, port, host)
292 return false
293 }
294 })
295
296 hs.rawStream.on('error', autoDestroy)
297
298 // Handles the case where onsocket is never called, but the stream got setup
299 // This can happen on a relayed connection which never connects directly
300 // (onsocket is called there only when the direct connection is established)
301 const onrawstreamclose = () => {
302 if (this._closing) return
303 this._clearLater(hs, id, k)
304 }
305 hs.rawStream.on('close', onrawstreamclose)
306
307 hs.onsocket = (socket, port, host) => {
308 if (hs.rawStream === null) return // Already hole punched
309
310 this._clearLater(hs, id, k)
311
312 if (hs.prepunching) {
313 clearTimeout(hs.prepunching)
314 hs.prepunching = null
315 }
316
317 if (this._reusableSocket && remotePayload.udx.reusableSocket) {
318 this.dht._socketPool.routes.add(handshake.remotePublicKey, hs.rawStream)
319 }
320
321 hs.rawStream.removeListener('error', autoDestroy)
322 hs.rawStream.removeListener('close', onrawstreamclose)
323
324 if (hs.rawStream.connected) {
325 const remoteChanging = hs.rawStream.changeRemote(socket, remotePayload.udx.id, port, host)
326
327 if (remoteChanging) remoteChanging.catch(safetyCatch)
328 } else {
329 hs.rawStream.connect(socket, remotePayload.udx.id, port, host)
330 hs.encryptedSocket = this.createSecretStream(false, hs.rawStream, {
331 handshake: h,
332 keepAlive: this.dht.connectionKeepAlive
333 })
334
335 this.onconnection(hs.encryptedSocket)
336 }
337
338 if (hs.puncher) {
339 hs.puncher.onabort = noop
340 hs.puncher.destroy()
341 }
342
343 hs.rawStream = null
344 }
345
346 function autoDestroy() {
347 if (hs.puncher) hs.puncher.destroy()
348 }
349 }
350
351 const relayAddresses = this.relayAddresses
352 const relayThrough = selectRelay(this.relayThrough)
353
354 if (relayThrough) hs.relayToken = relay.token()
355
356 try {
357 hs.reply = await handshake.send({
358 error,
359 firewall: ourRemoteAddr ? FIREWALL.OPEN : FIREWALL.UNKNOWN,
360 holepunch: ourRemoteAddr ? null : { id, relays: this._announcer.relays },
361 addresses4: addresses,
362 addresses6: null,
363 udx: {
364 reusableSocket: this._reusableSocket,
365 id: hs.rawStream ? hs.rawStream.id : 0,
366 seq: 0
367 },
368 secretStream: {},
369 relayThrough: relayThrough ? { publicKey: relayThrough, token: hs.relayToken } : null,
370 relayAddresses: relayAddresses.length ? relayAddresses : null
371 })
372 } catch (err) {
373 safetyCatch(err)
374 if (hs.rawStream) hs.rawStream.destroy()
375 this._clearLater(hs, id, k)
376 return null
377 }
378
379 if (this._closing || this.suspended) {
380 if (hs.rawStream) hs.rawStream.destroy()
381 return null
382 }
383
384 const h = handshake.final()
385
386 if (error !== ERROR.NONE) {
387 if (hs.rawStream) hs.rawStream.destroy()
388 this._clearLater(hs, id, k)
389 return hs
390 }
391
392 if (remotePayload.firewall === FIREWALL.OPEN || direct) {
393 const sock = direct ? socket : this.dht.socket
394 this.dht.stats.punches.open++
395 hs.onsocket(sock, clientAddress.port, clientAddress.host)
396 return hs
397 }
398
399 if (relayThrough || remotePayload.relayThrough) {
400 this._relayConnection(hs, relayThrough, remotePayload, h)
401 }
402
403 const onabort = () => {
404 hs.aborted = true
405 if (hs.prepunching) clearTimeout(hs.prepunching)
406 hs.prepunching = null
407 if (hs.rawStream.destroyed) {
408 this._clearLater(hs, id, k)
409 return
410 }
411
412 hs.rawStream.on('close', () => this._clearLater(hs, id, k))
413 if (hs.relayToken === null) hs.rawStream.destroy()
414 }
415
416 if (!direct && clientAddress.host === serverAddress.host) {
417 const clientAddresses = remotePayload.addresses4.filter(onlyPrivateHosts)
418
419 if (clientAddresses.length > 0 && this._shareLocalAddress) {
420 const myAddresses = await this._localAddresses()
421 const addr = Holepuncher.matchAddress(myAddresses, clientAddresses)
422
423 if (addr) {
424 hs.prepunching = setTimeout(onabort, HANDSHAKE_INITIAL_TIMEOUT)
425 return hs
426 }
427 }
428 }
429
430 if (this._closing || this.suspended) return null
431
432 if (ourRemoteAddr || this._neverPunch) {
433 hs.prepunching = setTimeout(onabort, HANDSHAKE_INITIAL_TIMEOUT)
434 return hs
435 }
436
437 hs.payload = new SecurePayload(h.holepunchSecret)
438 hs.puncher = new Holepuncher(this.dht, this.dht.session(), false, remotePayload.firewall)
439
440 hs.puncher.onconnect = hs.onsocket
441 hs.puncher.onabort = onabort
442 hs.prepunching = setTimeout(hs.puncher.destroy.bind(hs.puncher), HANDSHAKE_INITIAL_TIMEOUT)
443
444 return hs
445 }
446
447 _clearLater(hs, id, k) {
448 if (hs.clearing) return
449 hs.clearing = setTimeout(() => this._clear(hs, id, k), this.handshakeClearWait)
450 }
451
452 _clear(hs, id, k) {
453 if (id >= this._holepunches.length || this._holepunches[id] !== hs) return
454 if (hs.clearing) clearTimeout(hs.clearing)
455
456 this._holepunches[id] = null
457 while (
458 this._holepunches.length > 0 &&
459 this._holepunches[this._holepunches.length - 1] === null
460 ) {
461 this._holepunches.pop()
462 }
463 this._connects.delete(k)
464 }
465
466 async _onpeerhandshake({ noise, peerAddress }, req) {
467 const k = b4a.toString(noise, 'hex')
468
469 // The next couple of statements MUST run within the same tick to prevent
470 // a malicious peer from flooding us with handshakes.
471 let p = this._connects.get(k)
472 if (!p) {
473 p = this._addHandshake(k, noise, peerAddress || req.from, req, !peerAddress)
474 this._connects.set(k, p)
475 }
476
477 const h = await p
478 if (!h) return null
479
480 if (this._closing !== null || this.suspended) return null
481
482 return { socket: h.puncher && h.puncher.socket, noise: h.reply }
483 }
484
485 async _onpeerholepunch({ id, peerAddress, payload }, req) {
486 const h = id < this._holepunches.length ? this._holepunches[id] : null
487 if (!h) return null
488
489 if (!peerAddress || this._closing !== null || this.suspended) return null
490
491 const p = h.puncher
492 if (!p || !p.socket) return this._abort(h) // not opened
493
494 const remotePayload = h.payload.decrypt(payload)
495 if (!remotePayload) return null
496
497 const isServerRelay = this._announcer.isRelay(req.from)
498 const { error, firewall, round, punching, addresses, remoteAddress, remoteToken } =
499 remotePayload
500
501 if (error !== ERROR.NONE) {
502 // We actually do not need to set the round here, but just do it for consistency.
503 if (round >= h.round) h.round = round
504 return this._abort(h)
505 }
506
507 const token = h.payload.token(peerAddress)
508 const echoed = isServerRelay && !!remoteToken && b4a.equals(token, remoteToken)
509
510 // Update our heuristics here
511 if (req.socket === p.socket) {
512 p.nat.add(req.to, req.from)
513 }
514
515 if (round >= h.round) {
516 h.round = round
517 p.updateRemote({ punching, firewall, addresses, verified: echoed ? peerAddress.host : null })
518 }
519
520 // Wait for the analyzer to reach a conclusion...
521 let stable = await p.analyze(false)
522 if (p.destroyed) return null
523
524 if (!p.remoteHolepunching && !stable) {
525 stable = await p.analyze(true)
526 if (p.destroyed) return null
527 if (!stable) return this._abort(h)
528 }
529
530 // Fast mode! If we are consistent and the remote has opened a session to us (remoteAddress)
531 // then fire a quick punch back. Note the await here just waits for the udp socket to flush.
532 if (
533 isConsistent(p.nat.firewall) &&
534 remoteAddress &&
535 hasSameAddr(p.nat.addresses, remoteAddress)
536 ) {
537 await p.ping(peerAddress)
538 if (p.destroyed) return null
539 }
540
541 // Remote said they are punching (or willing to), so we will punch as well.
542 // Note that this returns when the punching has STARTED, so no guarantee
543 // we will have a connection after this promise etc.
544 if (p.remoteHolepunching) {
545 // TODO: still continue here if a local connection might work, but then do not holepunch...
546 if (!this.holepunch(p.remoteFirewall, p.nat.firewall, p.remoteAddresses, p.nat.addresses)) {
547 return p.destroyed ? null : this._abort(h)
548 }
549
550 if (h.prepunching) {
551 clearTimeout(h.prepunching)
552 h.prepunching = null
553 }
554
555 if (p.remoteFirewall >= FIREWALL.RANDOM || p.nat.firewall >= FIREWALL.RANDOM) {
556 if (
557 this.dht._randomPunches >= this.dht._randomPunchLimit ||
558 Date.now() - this.dht._lastRandomPunch < this.dht._randomPunchInterval
559 ) {
560 if (!h.relayToken) return this._abort(h, ERROR.TRY_LATER)
561 return {
562 socket: p.socket,
563 payload: h.payload.encrypt({
564 error: ERROR.TRY_LATER,
565 firewall: p.nat.firewall,
566 round: h.round,
567 connected: p.connected,
568 punching: p.punching,
569 addresses: p.nat.addresses,
570 remoteAddress: null,
571 token: isServerRelay ? token : null,
572 remoteToken: remotePayload.token
573 })
574 }
575 }
576 }
577
578 const punching = await p.punch()
579 if (p.destroyed) return null
580 if (!punching) return this._abort(h)
581 }
582
583 // Freeze that analysis as soon as we have a result we are giving to the other peer
584 if (p.nat.firewall !== FIREWALL.UNKNOWN) {
585 p.nat.freeze()
586 }
587
588 return {
589 socket: p.socket,
590 payload: h.payload.encrypt({
591 error: ERROR.NONE,
592 firewall: p.nat.firewall,
593 round: h.round,
594 connected: p.connected,
595 punching: p.punching,
596 addresses: p.nat.addresses,
597 remoteAddress: null,
598 token: isServerRelay ? token : null,
599 remoteToken: remotePayload.token
600 })
601 }
602 }
603
604 _abort(h, error = ERROR.ABORTED) {
605 if (!h.payload) {
606 if (h.puncher) h.puncher.destroy()
607 return null
608 }
609
610 const payload = h.payload.encrypt({
611 error,
612 firewall: FIREWALL.UNKNOWN,
613 round: h.round,
614 connected: false,
615 punching: false,
616 addresses: null,
617 remoteAddress: null,
618 token: null,
619 remoteToken: null
620 })
621
622 h.puncher.destroy()
623
624 return { socket: this.dht.socket, payload }
625 }
626
627 _relayConnection(hs, relayThrough, remotePayload, h) {
628 this.dht.stats.relaying.attempts++
629
630 let isInitiator
631 let publicKey
632 let token
633
634 if (relayThrough) {
635 isInitiator = true
636 publicKey = relayThrough
637 token = hs.relayToken
638 } else {
639 isInitiator = false
640 publicKey = remotePayload.relayThrough.publicKey
641 token = remotePayload.relayThrough.token
642 }
643
644 hs.relayToken = token
645 hs.relaySocket = this.dht.connect(publicKey)
646 hs.relaySocket.setKeepAlive(this.relayKeepAlive)
647 hs.relayClient = relay.Client.from(hs.relaySocket, { id: hs.relaySocket.publicKey })
648 hs.relayTimeout = setTimeout(onabort, 15000)
649
650 hs.relayClient
651 .pair(isInitiator, token, hs.rawStream)
652 .on('error', onabort)
653 .on('data', (remoteId) => {
654 if (hs.relayTimeout) clearRelayTimeout(hs)
655 if (hs.rawStream === null) {
656 onabort(null)
657 return
658 }
659
660 hs.relayPaired = true
661 this.dht.stats.relaying.successes++
662
663 if (hs.prepunching) clearTimeout(hs.prepunching)
664 hs.prepunching = null
665
666 const { remotePort, remoteHost, socket } = hs.relaySocket.rawStream
667
668 hs.rawStream
669 .on('close', () => hs.relaySocket.destroy())
670 .connect(socket, remoteId, remotePort, remoteHost)
671
672 hs.encryptedSocket = this.createSecretStream(false, hs.rawStream, { handshake: h })
673
674 this.onconnection(hs.encryptedSocket)
675 })
676
677 const dht = this.dht
678 function onabort() {
679 if (!hs.relayPaired) dht.stats.relaying.aborts++
680 if (hs.relayTimeout) clearRelayTimeout(hs)
681 const socket = hs.relaySocket
682 hs.relayToken = null
683 hs.relaySocket = null
684 if (socket) socket.destroy()
685 if (hs.aborted && hs.rawStream) hs.rawStream.destroy()
686 }
687 }
688}
689
690function clearRelayTimeout(hs) {
691 clearTimeout(hs.relayTimeout)
692 hs.relayTimeout = null
693}
694
695function isConsistent(fw) {
696 return fw === FIREWALL.OPEN || fw === FIREWALL.CONSISTENT
697}
698
699function hasSameAddr(addrs, other) {
700 if (addrs === null) return false
701
702 for (const addr of addrs) {
703 if (addr.port === other.port && addr.host === other.host) return true
704 }
705 return false
706}
707
708function defaultCreateHandshake(keyPair, remotePublicKey) {
709 return new NoiseWrap(keyPair, remotePublicKey)
710}
711
712function defaultCreateSecretStream(isInitiator, rawStream, opts) {
713 return new NoiseSecretStream(isInitiator, rawStream, opts)
714}
715
716function onlyPrivateHosts(addr) {
717 return isPrivate(addr.host)
718}
719
720function isRelay(relaySocket, socket, port, host) {
721 const stream = relaySocket.rawStream
722 if (!stream) return false
723 if (stream.socket !== socket) return false
724 return port === stream.remotePort && host === stream.remoteHost
725}
726
727function selectRelay(relayThrough) {
728 if (typeof relayThrough === 'function') relayThrough = relayThrough()
729 if (relayThrough === null) return null
730 if (Array.isArray(relayThrough)) {
731 return relayThrough[Math.floor(Math.random() * relayThrough.length)]
732 }
733 return relayThrough
734}
735
736function noop() {}
node_modules/hyperdht/lib/sleeper.js +35 -0
……@@ -0,0 +1,35 @@
1module.exports = class Sleeper {
2 constructor() {
3 this._timeout = null
4 this._resolve = null
5
6 this._start = (resolve) => {
7 this._resolve = resolve
8 }
9
10 this._trigger = () => {
11 if (this._resolve === null) return
12 const resolve = this._resolve
13 this._timeout = null
14 this._resolve = null
15 resolve()
16 }
17 }
18
19 pause(ms) {
20 const p = new Promise(this._start)
21 if (this._timeout !== null) {
22 clearTimeout(this._timeout)
23 this._trigger()
24 }
25 this._timeout = setTimeout(this._trigger, ms)
26 return p
27 }
28
29 resume() {
30 if (this._timeout !== null) {
31 clearTimeout(this._timeout)
32 this._trigger()
33 }
34 }
35}
node_modules/hyperdht/lib/socket-pool.js +219 -0
……@@ -0,0 +1,219 @@
1const b4a = require('b4a')
2
3const LINGER_TIME = 3000
4
5module.exports = class SocketPool {
6 constructor(dht, host) {
7 this._dht = dht
8 this._sockets = new Map()
9 this._lingering = new Set() // updated by the ref
10 this._host = host
11
12 this.routes = new SocketRoutes(this)
13 }
14
15 _onmessage(ref, data, address) {
16 this._dht.onmessage(ref.socket, data, address)
17 }
18
19 _add(ref) {
20 this._sockets.set(ref.socket, ref)
21 }
22
23 _remove(ref) {
24 this._sockets.delete(ref.socket)
25 this._lingering.delete(ref)
26 }
27
28 lookup(socket) {
29 return this._sockets.get(socket) || null
30 }
31
32 setReusable(socket, bool) {
33 const ref = this.lookup(socket)
34 if (ref) ref.reusable = bool
35 }
36
37 acquire() {
38 // TODO: Enable socket reuse
39 return new SocketRef(this)
40 }
41
42 async destroy() {
43 const closing = []
44
45 for (const ref of this._sockets.values()) {
46 ref._unlinger()
47 closing.push(ref.socket.close())
48 }
49
50 await Promise.allSettled(closing)
51 }
52}
53
54class SocketRoutes {
55 constructor(pool) {
56 this._pool = pool
57 this._routes = new Map()
58 }
59
60 add(publicKey, rawStream) {
61 if (rawStream.socket) this._onconnect(publicKey, rawStream)
62 else rawStream.on('connect', this._onconnect.bind(this, publicKey, rawStream))
63 }
64
65 get(publicKey) {
66 const id = b4a.toString(publicKey, 'hex')
67 const route = this._routes.get(id)
68 if (!route) return null
69 return route
70 }
71
72 _onconnect(publicKey, rawStream) {
73 const id = b4a.toString(publicKey, 'hex')
74 const socket = rawStream.socket
75
76 let route = this._routes.get(id)
77
78 if (!route) {
79 const gc = () => {
80 if (this._routes.get(id) === route) this._routes.delete(id)
81 socket.removeListener('close', gc)
82 }
83
84 route = {
85 socket,
86 address: { host: rawStream.remoteHost, port: rawStream.remotePort },
87 gc
88 }
89
90 this._routes.set(id, route)
91 socket.on('close', gc)
92 }
93
94 this._pool.setReusable(socket, true)
95
96 rawStream.on('error', () => {
97 this._pool.setReusable(socket, false)
98 if (!route) route = this._routes.get(id)
99 if (route && route.socket === socket) route.gc()
100 })
101 }
102}
103
104// TODO: we should just make some "user data" object on udx to allow to attach this info
105class SocketRef {
106 constructor(pool) {
107 this._pool = pool
108
109 // Events
110 this.onholepunchmessage = noop
111
112 // Whether it should teardown immediately or wait a bit
113 this.reusable = false
114
115 this.socket = pool._dht.udx.createSocket()
116 this.socket
117 .on('close', this._onclose.bind(this))
118 .on('message', this._onmessage.bind(this))
119 .on('idle', this._onidle.bind(this))
120 .on('busy', this._onbusy.bind(this))
121 .bind(0, this._pool._host)
122
123 this._refs = 1
124 this._released = false
125 this._closed = false
126
127 this._timeout = null
128 this._wasBusy = false
129
130 this._pool._add(this)
131 }
132
133 _onclose() {
134 this._pool._remove(this)
135 }
136
137 _onmessage(data, address) {
138 if (data.byteLength > 1) {
139 this._pool._onmessage(this, data, address)
140 } else {
141 this.onholepunchmessage(data, address, this)
142 }
143 }
144
145 _onidle() {
146 this._closeMaybe()
147 }
148
149 _onbusy() {
150 this._wasBusy = true
151 this._unlinger()
152 }
153
154 _reset() {
155 this.onholepunchmessage = noop
156 }
157
158 _closeMaybe() {
159 if (this._refs === 0 && this.socket.idle && !this._timeout) this._close()
160 }
161
162 _lingeringClose() {
163 this._pool._lingering.delete(this)
164 this._timeout = null
165 this._closeMaybe()
166 }
167
168 _close() {
169 this._unlinger()
170
171 if (this.reusable && this._wasBusy) {
172 this._wasBusy = false
173 this._pool._lingering.add(this)
174 this._timeout = setTimeout(this._lingeringClose.bind(this), LINGER_TIME)
175 return
176 }
177
178 this._closed = true
179 this.socket.close()
180 }
181
182 _unlinger() {
183 if (this._timeout !== null) {
184 clearTimeout(this._timeout)
185 this._pool._lingering.delete(this)
186 this._timeout = null
187 }
188 }
189
190 get free() {
191 return this._refs === 0
192 }
193
194 active() {
195 this._refs++
196 this._unlinger()
197 }
198
199 inactive() {
200 this._refs--
201 this._closeMaybe()
202 }
203
204 address() {
205 return this.socket.address()
206 }
207
208 release() {
209 if (this._released) return
210
211 this._released = true
212 this._reset()
213
214 this._refs--
215 this._closeMaybe()
216 }
217}
218
219function noop() {}
node_modules/hyperdht/package.json +78 -0
……@@ -0,0 +1,78 @@
1{
2 "name": "hyperdht",
3 "version": "6.29.6",
4 "description": "The DHT powering Hyperswarm",
5 "main": "index.js",
6 "browser": "browser.js",
7 "bin": {
8 "hyperdht": "./bin.js"
9 },
10 "files": [
11 "index.js",
12 "browser.js",
13 "testnet.js",
14 "bin.js",
15 "lib/**.js"
16 ],
17 "imports": {
18 "events": {
19 "bare": "bare-events",
20 "default": "events"
21 },
22 "child_process": {
23 "bare": "bare-node-child-process",
24 "default": "child_process"
25 }
26 },
27 "dependencies": {
28 "@hyperswarm/secret-stream": "^6.6.2",
29 "b4a": "^1.3.1",
30 "bare-events": "^2.2.0",
31 "blind-relay": "^1.3.0",
32 "bogon": "^1.0.0",
33 "compact-encoding": "^2.4.1",
34 "dht-rpc": "^6.15.1",
35 "hypercore-crypto": "^3.3.0",
36 "hypercore-id-encoding": "^1.2.0",
37 "noise-curve-ed": "^2.0.0",
38 "noise-handshake": "^4.0.0",
39 "record-cache": "^1.1.1",
40 "safety-catch": "^1.0.1",
41 "signal-promise": "^1.0.3",
42 "sodium-universal": "^5.0.1",
43 "streamx": "^2.16.1",
44 "unslab": "^1.3.0",
45 "xache": "^1.1.0"
46 },
47 "devDependencies": {
48 "bare-node-child-process": "^1.0.1",
49 "brittle": "^3.0.0",
50 "graceful-goodbye": "^1.3.0",
51 "newline-decoder": "^1.0.2",
52 "prettier": "^3.6.2",
53 "prettier-config-holepunch": "^2.0.0"
54 },
55 "scripts": {
56 "format": "prettier --write .",
57 "test": "prettier --check . && node test/all.js",
58 "test:bare": "bare test/all.js",
59 "test:generate": "brittle -r test/all.js test/*.js",
60 "integration": "brittle test/integration/*.js",
61 "end-to-end": "brittle test/end-to-end/*.js"
62 },
63 "author": "Mathias Buus (@mafintosh)",
64 "license": "MIT",
65 "directories": {
66 "lib": "lib",
67 "test": "test"
68 },
69 "repository": {
70 "type": "git",
71 "url": "git+https://github.com/holepunchto/hyperdht.git"
72 },
73 "keywords": [],
74 "bugs": {
75 "url": "https://github.com/holepunchto/hyperdht/issues"
76 },
77 "homepage": "https://github.com/holepunchto/hyperdht#readme"
78}
node_modules/hyperdht/testnet.js +81 -0
……@@ -0,0 +1,81 @@
1const DHT = require('.')
2
3module.exports = async function createTestnet(size = 10, opts = {}) {
4 const swarm = []
5 const teardown =
6 typeof opts === 'function' ? opts : opts.teardown ? opts.teardown.bind(opts) : noop
7 const host = opts.host || '127.0.0.1'
8 const port = opts.port || 0
9 const bootstrap = opts.bootstrap ? [...opts.bootstrap] : []
10 const bindHost = host === '127.0.0.1' ? '127.0.0.1' : '0.0.0.0'
11
12 if (size === 0) return new Testnet(swarm)
13
14 const first = new DHT({
15 ephemeral: false,
16 firewalled: false,
17 bootstrap,
18 port,
19 host: bindHost
20 })
21
22 await first.fullyBootstrapped()
23
24 if (bootstrap.length === 0) bootstrap.push({ host, port: first.address().port })
25
26 swarm.push(first)
27
28 while (swarm.length < size) {
29 const node = new DHT({
30 ephemeral: false,
31 firewalled: false,
32 bootstrap,
33 host: bindHost
34 })
35
36 await node.fullyBootstrapped()
37 swarm.push(node)
38 }
39
40 const testnet = new Testnet(swarm, bootstrap)
41
42 teardown(() => testnet.destroy(), { order: Infinity })
43
44 return testnet
45}
46
47class Testnet {
48 constructor(nodes, bootstrap = []) {
49 this.nodes = nodes
50 this.bootstrap = bootstrap
51 }
52
53 createNode(opts = {}) {
54 const node = new DHT({
55 ephemeral: true,
56 bootstrap: this.bootstrap,
57 host: '127.0.0.1',
58 ...opts
59 })
60
61 this.nodes.push(node)
62
63 return node
64 }
65
66 async destroy() {
67 for (const node of this.nodes) {
68 for (const server of node.listening) await server.close()
69 }
70
71 for (let i = this.nodes.length - 1; i >= 0; i--) {
72 await this.nodes[i].destroy()
73 }
74 }
75
76 [Symbol.iterator]() {
77 return this.nodes[Symbol.iterator]()
78 }
79}
80
81function noop() {}
node_modules/hyperswarm/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2019 Mathias Buus, Paul Frazee, David Mark Clements and contributors
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
node_modules/hyperswarm/README.md +208 -0
……@@ -0,0 +1,208 @@
1# hyperswarm
2
3### [See the full API docs at docs.pears.com](https://docs.pears.com/building-blocks/hyperswarm)
4
5A high-level API for finding and connecting to peers who are interested in a "topic."
6
7## Installation
8
9```
10npm install hyperswarm
11```
12
13## Usage
14
15```js
16const Hyperswarm = require('hyperswarm')
17
18const swarm1 = new Hyperswarm()
19const swarm2 = new Hyperswarm()
20
21swarm1.on('connection', (conn, info) => {
22 // swarm1 will receive server connections
23 conn.write('this is a server connection')
24 conn.end()
25})
26
27swarm2.on('connection', (conn, info) => {
28 conn.on('data', (data) => console.log('client got message:', data.toString()))
29})
30
31const topic = Buffer.alloc(32).fill('hello world') // A topic must be 32 bytes
32const discovery = swarm1.join(topic, { server: true, client: false })
33await discovery.flushed() // Waits for the topic to be fully announced on the DHT
34
35swarm2.join(topic, { server: false, client: true })
36await swarm2.flush() // Waits for the swarm to connect to pending peers.
37
38// After this point, both client and server should have connections
39```
40
41## Hyperswarm API
42
43#### `const swarm = new Hyperswarm(opts = {})`
44
45Construct a new Hyperswarm instance.
46
47`opts` can include:
48
49- `keyPair`: A Noise keypair that will be used to listen/connect on the DHT. Defaults to a new key pair.
50- `seed`: A unique, 32-byte, random seed that can be used to deterministically generate the key pair.
51- `maxPeers`: The maximum number of peer connections to allow.
52- `firewall`: A sync function of the form `remotePublicKey => (true|false)`. If true, the connection will be rejected. Defaults to allowing all connections.
53- `dht`: A DHT instance. Defaults to a new instance.
54
55#### `swarm.connecting`
56
57Number that indicates connections in progress.
58
59#### `swarm.connections`
60
61A set of all active client/server connections.
62
63#### `swarm.peers`
64
65A Map containing all connected peers, of the form: `(Noise public key hex string) -> PeerInfo object`
66
67See the [`PeerInfo`](#peerinfo-api) API for more details.
68
69#### `swarm.dht`
70
71A [`hyperdht`](https://github.com/holepunchto/hyperdht) instance. Useful if you want lower-level control over Hyperswarm's networking.
72
73#### `swarm.on('connection', (socket, peerInfo) => {})`
74
75Emitted whenever the swarm connects to a new peer.
76
77`socket` is an end-to-end (Noise) encrypted Duplex stream
78
79`peerInfo` is a [`PeerInfo`](#peerinfo-api) instance
80
81#### `swarm.on('update', () => {})`
82
83Emitted when internal values are changed, useful for user interfaces.
84
85For example: emitted when `swarm.connecting` or `swarm.connections` changes.
86
87#### `const discovery = swarm.join(topic, opts = {})`
88
89Start discovering and connecting to peers sharing a common topic. As new peers are connected to, they will be emitted from the swarm as `connection` events.
90
91`topic` must be a 32-byte Buffer
92`opts` can include:
93
94- `server`: Accept server connections for this topic by announcing yourself to the DHT. Defaults to `true`.
95- `client`: Actively search for and connect to discovered servers. Defaults to `true`.
96- `limit`: Set the max number of peers to connect to when joining the topic. Defaults to `Infinity`.
97
98Returns a [`PeerDiscovery`](#peerdiscovery-api) object.
99
100#### Clients and Servers
101
102In Hyperswarm, there are two ways for peers to join the swarm: client mode and server mode. If you've previously used Hyperswarm v2, these were called "lookup" and "announce", but we now think "client" and "server" are more descriptive.
103
104When you join a topic as a server, the swarm will start accepting incoming connections from clients (peers that have joined the same topic in client mode). Server mode will announce your keypair to the DHT, so that other peers can discover your server. When server connections are emitted, they are not associated with a specific topic -- the server only knows it received an incoming connection.
105
106When you join a topic as a client, the swarm will do a query to discover available servers, and will eagerly connect to them. As with server mode, these connections will be emitted as `connection` events, but in client mode they **will** be associated with the topic (`info.topics` will be set in the `connection` event).
107
108#### `await swarm.leave(topic)`
109
110Stop discovering peers for the given topic.
111
112`topic` must be a 32-byte Buffer
113
114If a topic was previously joined in server mode, `leave` will stop announcing the topic on the DHT. If a topic was previously joined in client mode, `leave` will stop searching for servers announcing the topic.
115
116`leave` will **not** close any existing connections.
117
118#### `swarm.joinPeer(noisePublicKey)`
119
120Establish a direct connection to a known peer.
121
122`noisePublicKey` must be a 32-byte Buffer
123
124As with the standard `join` method, `joinPeer` will ensure that peer connections are reestablished in the event of failures.
125
126#### `swarm.leavePeer(noisePublicKey)`
127
128Stop attempting direct connections to a known peer.
129
130`noisePublicKey` must be a 32-byte Buffer
131
132If a direct connection is already established, that connection will **not** be destroyed by `leavePeer`.
133
134#### `const discovery = swarm.status(topic)`
135
136Get the [`PeerDiscovery`](#peerdiscovery-api) object associated with the topic, if it exists.
137
138#### `await swarm.listen()`
139
140Explicitly start listening for incoming connections. This will be called internally after the first `join`, so it rarely needs to be called manually.
141
142#### `await swarm.flush()`
143
144Wait for any pending DHT announces, and for the swarm to connect to any pending peers (peers that have been discovered, but are still in the queue awaiting processing).
145
146Once a `flush()` has completed, the swarm will have connected to every peer it can discover from the current set of topics it's managing.
147
148`flush()` is not topic-specific, so it will wait for every pending DHT operation and connection to be processed -- it's quite heavyweight, so it could take a while. In most cases, it's not necessary, as connections are emitted by `swarm.on('connection')` immediately after they're opened.
149
150#### `await swarm.suspend({ log: () => {} })`
151
152Suspend the swarm disconnecting all peers, suspends server listening and stops discovery of new peers. Useful for suspending when the runtime suspends to pause networking.
153
154`log` is a logging function, which defaults to a noop function.
155
156#### `await swarm.resume({ log: () => {} })`
157
158Resume a suspended swarm refreshing discovery of new peers and servers. Useful for reannouncing to the DHT and reconnecting to peers when the runtime resumes.
159
160`log` is a logging function, which defaults to a noop function.
161
162#### `swarm.on('ban', peerInfo, err)`
163
164Emitted when a peer gets banned. `err` is an error object describing the reason for the ban (e.g. firewalled).
165
166## PeerDiscovery API
167
168`swarm.join` returns a `PeerDiscovery` instance which allows you to both control discovery behavior, and respond to lifecycle changes during discovery.
169
170#### `await discovery.flushed()`
171
172Wait until the topic has been fully announced to the DHT. This method is only relevant in server mode. When `flushed()` has completed, the server will be available to the network.
173
174#### `await discovery.refresh({ client, server })`
175
176Update the `PeerDiscovery` configuration, optionally toggling client and server modes. This will also trigger an immediate re-announce of the topic, when the `PeerDiscovery` is in server mode.
177
178#### `await discovery.destroy()`
179
180Stop discovering peers for the given topic.
181
182If a topic was previously joined in server mode, `leave` will stop announcing the topic on the DHT. If a topic was previously joined in client mode, `leave` will stop searching for servers announcing the topic.
183
184## PeerInfo API
185
186`swarm.on('connection', ...)` emits a `PeerInfo` instance whenever a new connection is established.
187
188There is a one-to-one relationship between connections and `PeerInfo` objects -- if a single peer announces multiple topics, those topics will be multiplexed over a single connection.
189
190#### `peerInfo.publicKey`
191
192The peer's Noise public key.
193
194#### `peerInfo.topics`
195
196An Array of topics that this Peer is associated with -- `topics` will only be updated when the Peer is in client mode.
197
198#### `peerInfo.prioritized`
199
200If true, the swarm will rapidly attempt to reconnect to this peer.
201
202#### `peerInfo.ban(banStatus = false)`
203
204Ban or unban the peer. Banning will prevent any future reconnection attempts, but it will **not** close any existing connections.
205
206## License
207
208MIT
node_modules/hyperswarm/index.js +687 -0
……@@ -0,0 +1,687 @@
1const { EventEmitter } = require('events')
2const { getStreamError } = require('streamx')
3const DHT = require('hyperdht')
4const spq = require('shuffled-priority-queue')
5const b4a = require('b4a')
6const unslab = require('unslab')
7
8const PeerInfo = require('./lib/peer-info')
9const RetryTimer = require('./lib/retry-timer')
10const ConnectionSet = require('./lib/connection-set')
11const PeerDiscovery = require('./lib/peer-discovery')
12
13const MAX_PEERS = 64
14const MAX_PARALLEL = 3
15const MAX_CLIENT_CONNECTIONS = Infinity // TODO: Change
16const MAX_SERVER_CONNECTIONS = Infinity
17
18const ERR_MISSING_TOPIC = 'Topic is required and must be a 32-byte buffer'
19const ERR_DESTROYED = 'Swarm has been destroyed'
20const ERR_DUPLICATE = 'Duplicate connection'
21const ERR_FIREWALL = 'Peer is firewalled'
22
23module.exports = class Hyperswarm extends EventEmitter {
24 constructor(opts = {}) {
25 super()
26 const {
27 seed,
28 relayThrough,
29 keyPair = DHT.keyPair(seed),
30 maxPeers = MAX_PEERS,
31 maxClientConnections = MAX_CLIENT_CONNECTIONS,
32 maxServerConnections = MAX_SERVER_CONNECTIONS,
33 maxParallel = MAX_PARALLEL,
34 firewall = allowAll
35 } = opts
36 this.keyPair = keyPair
37
38 this.dht =
39 opts.dht ||
40 new DHT({
41 bootstrap: opts.bootstrap,
42 nodes: opts.nodes,
43 port: opts.port,
44 deferRandomPunch: opts.deferRandomPunch,
45 randomPunchInterval: opts.randomPunchInterval
46 })
47 this.server = this.dht.createServer(
48 {
49 firewall: this._handleFirewall.bind(this),
50 relayThrough: this._maybeRelayConnection.bind(this),
51 handshakeClearWait: opts.handshakeClearWait
52 },
53 this._handleServerConnection.bind(this)
54 )
55
56 this.destroyed = false
57 this.suspended = false
58 this.maxPeers = maxPeers
59 this.maxClientConnections = maxClientConnections
60 this.maxServerConnections = maxServerConnections
61 this.maxParallel = maxParallel
62 this.relayThrough = relayThrough ? toRelayFunction(relayThrough) : null
63
64 this.connecting = 0
65 this.connections = new Set()
66 this.peers = new Map()
67 this.explicitPeers = new Set()
68 this.listening = null
69 this.stats = {
70 updates: 0,
71 connects: {
72 client: {
73 opened: 0,
74 closed: 0,
75 attempted: 0
76 },
77 server: {
78 // Note: there is no notion of 'attempts' for server connections
79 opened: 0,
80 closed: 0
81 }
82 },
83 bannedPeers: 0
84 }
85
86 this._discovery = new Map()
87 this._timer = new RetryTimer(this._requeue.bind(this), {
88 backoffs: opts.backoffs,
89 jitter: opts.jitter
90 })
91 this._queue = spq()
92
93 this._allConnections = new ConnectionSet()
94 this._pendingFlushes = []
95 this._flushTick = 0
96
97 this._drainingQueue = false
98 this._clientConnections = 0
99 this._serverConnections = 0
100 this._firewall = firewall
101
102 this.dht.on('network-change', this._handleNetworkChange.bind(this))
103 this.dht.on('network-update', this._handleNetworkUpdate.bind(this))
104 this.on('update', this._handleUpdate)
105 }
106
107 _maybeRelayConnection(force) {
108 if (!this.relayThrough) return null
109 return this.relayThrough(force, this)
110 }
111
112 _enqueue(peerInfo) {
113 if (peerInfo.queued) return
114 peerInfo.queued = true
115 peerInfo._flushTick = this._flushTick
116 this._queue.add(peerInfo)
117
118 this._attemptClientConnections()
119 }
120
121 _requeue(batch) {
122 if (this.suspended) return
123 for (const peerInfo of batch) {
124 peerInfo.waiting = false
125
126 if (
127 peerInfo._updatePriority() === false ||
128 this._allConnections.has(peerInfo.publicKey) ||
129 peerInfo.queued
130 ) {
131 continue
132 }
133 peerInfo.queued = true
134 peerInfo._flushTick = this._flushTick
135 this._queue.add(peerInfo)
136 }
137
138 this._attemptClientConnections()
139 }
140
141 _flushMaybe(peerInfo) {
142 for (let i = 0; i < this._pendingFlushes.length; i++) {
143 const flush = this._pendingFlushes[i]
144 if (peerInfo._flushTick > flush.tick) continue
145 if (--flush.missing > 0) continue
146 flush.onflush(true)
147 this._pendingFlushes.splice(i--, 1)
148 }
149 }
150
151 _withinMaxPeers() {
152 const e = this.explicitPeers.size
153 const factor = e === 0 ? 1 : e < 2 ? 2 : e < 4 ? 3 : 4
154 return factor * this._allConnections.size < this.maxPeers
155 }
156
157 _flushAllMaybe() {
158 if (
159 this.connecting > 0 ||
160 (this._withinMaxPeers() && this._clientConnections < this.maxClientConnections)
161 ) {
162 return false
163 }
164
165 while (this._pendingFlushes.length) {
166 const flush = this._pendingFlushes.pop()
167 flush.onflush(true)
168 }
169
170 return true
171 }
172
173 _shouldConnectExplicit() {
174 return !this.destroyed && !this.suspended && this.connecting < this.maxParallel
175 }
176
177 _shouldConnect() {
178 return (
179 !this.destroyed &&
180 !this.suspended &&
181 this.connecting < this.maxParallel &&
182 this._withinMaxPeers() &&
183 this._clientConnections < this.maxClientConnections
184 )
185 }
186
187 _shouldRequeue(peerInfo) {
188 if (this.suspended) return false
189 if (peerInfo.explicit) return true
190 for (const topic of peerInfo.topics) {
191 if (this._discovery.has(b4a.toString(topic, 'hex')) && !this.destroyed) {
192 return true
193 }
194 }
195 return false
196 }
197
198 _connect(peerInfo, queued) {
199 if (peerInfo.banned || this._allConnections.has(peerInfo.publicKey)) {
200 if (queued) this._flushMaybe(peerInfo)
201 return
202 }
203
204 // TODO: Support async firewalling at some point.
205 if (this._handleFirewall(peerInfo.publicKey, null)) {
206 if (queued) this._flushMaybe(peerInfo)
207 return
208 }
209
210 const relayThrough = this._maybeRelayConnection(peerInfo.forceRelaying)
211 const conn = this.dht.connect(peerInfo.publicKey, {
212 relayAddresses: peerInfo.relayAddresses,
213 keyPair: this.keyPair,
214 relayThrough
215 })
216 this._allConnections.add(conn)
217
218 this.stats.connects.client.attempted++
219
220 this.connecting++
221 this._clientConnections++
222 let opened = false
223
224 const onerror = (err) => {
225 if (this.relayThrough && shouldForceRelaying(err.code)) {
226 peerInfo.forceRelaying = true
227 // Reset the attempts in order to fast connect to relay
228 peerInfo.attempts = 0
229 }
230 }
231
232 // Removed once a connection is opened
233 conn.on('error', onerror)
234
235 conn.on('open', () => {
236 opened = true
237 this.stats.connects.client.opened++
238
239 this._connectDone()
240 this.connections.add(conn)
241 conn.removeListener('error', onerror)
242 peerInfo._connected()
243 peerInfo.client = true
244 this.emit('connection', conn, peerInfo)
245 if (queued) this._flushMaybe(peerInfo)
246
247 this.emit('update')
248 })
249 conn.on('close', () => {
250 if (!opened) this._connectDone()
251 this.stats.connects.client.closed++
252
253 const err = getStreamError(conn)
254 if (shouldBan(err)) {
255 this._banPeer(peerInfo, true, err)
256 }
257
258 this.connections.delete(conn)
259 this._allConnections.delete(conn)
260 this._clientConnections--
261 peerInfo._disconnected()
262
263 peerInfo.waiting = this._shouldRequeue(peerInfo) && this._timer.add(peerInfo)
264 this._maybeDeletePeer(peerInfo)
265
266 if (!opened && queued) this._flushMaybe(peerInfo)
267
268 this._attemptClientConnections()
269
270 this.emit('update')
271 })
272
273 this.emit('update')
274 }
275
276 _connectDone() {
277 this.connecting--
278
279 if (this.connecting < this.maxParallel) this._attemptClientConnections()
280 if (this.connecting === 0) this._flushAllMaybe()
281 }
282
283 // Called when the PeerQueue indicates a connection should be attempted.
284 _attemptClientConnections() {
285 // Guard against re-entries - unsure if it still needed but doesn't hurt
286 if (this._drainingQueue || this.suspended) return
287 this._drainingQueue = true
288
289 for (const peerInfo of this.explicitPeers) {
290 if (!this._shouldConnectExplicit()) break
291 if (
292 peerInfo.attempts >= 5 ||
293 Date.now() - peerInfo.disconnectedTime < peerInfo.attempts * 1000
294 ) {
295 continue
296 }
297 this._connect(peerInfo, false)
298 }
299
300 while (this._queue.length && this._shouldConnect()) {
301 const peerInfo = this._queue.shift()
302 peerInfo.queued = false
303 this._connect(peerInfo, true)
304 }
305 this._drainingQueue = false
306 if (this.connecting === 0) this._flushAllMaybe()
307 }
308
309 _handleFirewall(remotePublicKey, payload) {
310 if (b4a.equals(remotePublicKey, this.keyPair.publicKey)) return true
311
312 let peerInfo = this.peers.get(b4a.toString(remotePublicKey, 'hex'))
313 if (peerInfo && peerInfo.banned) return true
314
315 const firewalled = this._firewall(remotePublicKey, payload)
316 if (firewalled) {
317 if (!peerInfo) peerInfo = this._upsertPeer(remotePublicKey)
318 this._banPeer(peerInfo, true, new Error(ERR_FIREWALL))
319 }
320
321 return firewalled
322 }
323
324 _handleServerConnectionSwap(existing, conn) {
325 let closed = false
326
327 existing.on('close', () => {
328 if (closed) return
329
330 conn.removeListener('error', noop)
331 conn.removeListener('close', onclose)
332
333 this._handleServerConnection(conn)
334 })
335
336 conn.on('error', noop)
337 conn.on('close', onclose)
338
339 function onclose() {
340 closed = true
341 }
342 }
343
344 // Called when the DHT receives a new server connection.
345 _handleServerConnection(conn) {
346 if (this.destroyed || this.suspended) {
347 // TODO: Investigate why a final server connection can be received after close
348 conn.on('error', noop)
349 return conn.destroy(ERR_DESTROYED)
350 }
351
352 const existing = this._allConnections.get(conn.remotePublicKey)
353
354 if (existing) {
355 // If both connections are from the same peer,
356 // - pick the new one if the existing stream is already established (has sent and received bytes),
357 // because the other client must have lost that connection and be reconnecting
358 // - otherwise, pick the one thats expected to initiate in a tie break
359 const existingIsOutdated = existing.rawBytesRead > 0 && existing.rawBytesWritten > 0
360 const expectedInitiator = b4a.compare(conn.publicKey, conn.remotePublicKey) > 0
361 const keepNew = existingIsOutdated || expectedInitiator === conn.isInitiator
362
363 if (keepNew === false) {
364 existing.sendKeepAlive()
365 conn.on('error', noop)
366 conn.destroy(new Error(ERR_DUPLICATE))
367 return
368 }
369
370 existing.on('error', noop)
371 existing.destroy(new Error(ERR_DUPLICATE))
372 this._handleServerConnectionSwap(existing, conn)
373 return
374 }
375
376 // When reaching here, the connection will always be 'opened' next tick
377 this.stats.connects.server.opened++
378
379 const peerInfo = this._upsertPeer(conn.remotePublicKey, null)
380
381 this.connections.add(conn)
382 this._allConnections.add(conn)
383 this._serverConnections++
384
385 conn.on('close', () => {
386 const err = getStreamError(conn)
387 if (shouldBan(err)) {
388 this._banPeer(peerInfo, true, err)
389 }
390
391 this.connections.delete(conn)
392 this._allConnections.delete(conn)
393 this._serverConnections--
394 this.stats.connects.server.closed++
395
396 this._maybeDeletePeer(peerInfo)
397
398 this._attemptClientConnections()
399
400 this.emit('update')
401 })
402 peerInfo.client = false
403 this.emit('connection', conn, peerInfo)
404
405 this.emit('update')
406 }
407
408 _upsertPeer(publicKey, relayAddresses) {
409 if (b4a.equals(publicKey, this.keyPair.publicKey)) return null
410 const keyString = b4a.toString(publicKey, 'hex')
411 let peerInfo = this.peers.get(keyString)
412
413 if (peerInfo) {
414 peerInfo.relayAddresses = relayAddresses // new is always better
415 return peerInfo
416 }
417
418 peerInfo = new PeerInfo({
419 publicKey,
420 relayAddresses
421 })
422
423 this.peers.set(keyString, peerInfo)
424 return peerInfo
425 }
426
427 _handleUpdate() {
428 this.stats.updates++
429 }
430
431 _maybeDeletePeer(peerInfo) {
432 if (!peerInfo.shouldGC()) return
433
434 const hasActiveConn = this._allConnections.has(peerInfo.publicKey)
435 if (hasActiveConn) return
436
437 const keyString = b4a.toString(peerInfo.publicKey, 'hex')
438 this.peers.delete(keyString)
439 }
440
441 /*
442 * Called when a peer is actively discovered during a lookup.
443 *
444 * Three conditions:
445 * 1. Not a known peer -- insert into queue
446 * 2. A known peer with normal priority -- do nothing
447 * 3. A known peer with low priority -- bump priority, because it's been rediscovered
448 */
449 _handlePeer(peer, topic) {
450 const peerInfo = this._upsertPeer(peer.publicKey, peer.relayAddresses)
451 if (peerInfo) peerInfo._topic(topic)
452 if (!peerInfo || this._allConnections.has(peer.publicKey)) return
453 if (!peerInfo.prioritized || peerInfo.server) peerInfo._reset()
454 if (peerInfo._updatePriority()) {
455 this._enqueue(peerInfo)
456 }
457 }
458
459 async _handleNetworkUpdate() {
460 if (!this.online) return
461 this._handleNetworkChange()
462 }
463
464 async _handleNetworkChange() {
465 if (this.suspended) return
466
467 // prioritize figuring out if existing connections are dead
468 for (const conn of this._allConnections) {
469 conn.sendKeepAlive()
470 }
471
472 const refreshes = []
473
474 for (const discovery of this._discovery.values()) {
475 refreshes.push(discovery.refresh())
476 }
477
478 await Promise.allSettled(refreshes)
479 }
480
481 _banPeer(peerInfo, banned, err) {
482 peerInfo.ban(banned)
483 this.stats.bannedPeers++
484 this.emit('ban', peerInfo, err)
485 }
486
487 status(key) {
488 return this._discovery.get(b4a.toString(key, 'hex')) || null
489 }
490
491 listen() {
492 if (!this.listening) {
493 if (this.destroyed) throw new Error('Swarm destroyed')
494 this.listening = this.server.listen(this.keyPair)
495 }
496 return this.listening
497 }
498
499 // Object that exposes a cancellation method (destroy)
500 // TODO: When you rejoin, it should reannounce + bump lookup priority
501 join(topic, opts = {}) {
502 if (this.destroyed) throw new Error('Swarm destroyed')
503 if (!topic) throw new Error(ERR_MISSING_TOPIC)
504 topic = unslab(topic)
505
506 const topicString = b4a.toString(topic, 'hex')
507
508 let discovery = this._discovery.get(topicString)
509
510 if (discovery && !discovery.destroyed) {
511 return discovery.session(opts)
512 }
513
514 discovery = new PeerDiscovery(this, topic, {
515 limit: opts.limit,
516 wait: discovery ? discovery.destroy() : null,
517 suspended: this.suspended,
518 onpeer: (peer) => this._handlePeer(peer, topic)
519 })
520 this._discovery.set(topicString, discovery)
521 return discovery.session(opts)
522 }
523
524 // Returns a promise
525 async leave(topic) {
526 if (!topic) throw new Error(ERR_MISSING_TOPIC)
527 const topicString = b4a.toString(topic, 'hex')
528 if (!this._discovery.has(topicString)) return Promise.resolve()
529
530 const discovery = this._discovery.get(topicString)
531
532 try {
533 await discovery.destroy()
534 } catch {
535 // ignore, prop network
536 }
537
538 if (this._discovery.get(topicString) === discovery) {
539 this._discovery.delete(topicString)
540 }
541 }
542
543 joinPeer(publicKey) {
544 const peerInfo = this._upsertPeer(publicKey, null)
545 if (!peerInfo) return
546 if (!this.explicitPeers.has(peerInfo)) {
547 peerInfo.explicit = true
548 this.explicitPeers.add(peerInfo)
549 }
550 if (this._allConnections.has(publicKey)) return
551 if (peerInfo._updatePriority()) {
552 this._enqueue(peerInfo)
553 }
554 }
555
556 leavePeer(publicKey) {
557 const keyString = b4a.toString(publicKey, 'hex')
558 if (!this.peers.has(keyString)) return
559
560 const peerInfo = this.peers.get(keyString)
561 peerInfo.explicit = false
562 this.explicitPeers.delete(peerInfo)
563 this._maybeDeletePeer(peerInfo)
564 }
565
566 // Returns a promise
567 async flush() {
568 const allFlushed = [...this._discovery.values()].map((v) => v.flushed())
569 await Promise.all(allFlushed)
570 if (this._flushAllMaybe()) return true
571 const pendingSize = this._allConnections.size - this.connections.size
572 if (!this._queue.length && !pendingSize) return true
573 return new Promise((resolve) => {
574 this._pendingFlushes.push({
575 onflush: resolve,
576 missing: this._queue.length + pendingSize,
577 tick: this._flushTick++
578 })
579 })
580 }
581
582 async clear() {
583 const cleared = Promise.allSettled([...this._discovery.values()].map((d) => d.destroy()))
584 this._discovery.clear()
585 return cleared
586 }
587
588 async destroy({ force } = {}) {
589 if (this.destroyed && !force) return
590 this.destroyed = true
591
592 this._timer.destroy()
593
594 if (!force) await this.clear()
595
596 await this.server.close()
597
598 while (this._pendingFlushes.length) {
599 const flush = this._pendingFlushes.pop()
600 flush.onflush(false)
601 }
602
603 await this.dht.destroy({ force })
604 }
605
606 async suspend({ log = noop } = {}) {
607 if (this.suspended) return
608
609 const promises = []
610
611 promises.push(this.server.suspend({ log }))
612
613 for (const discovery of this._discovery.values()) {
614 promises.push(discovery.suspend({ log }))
615 }
616
617 const pending = []
618 for (const connection of this._allConnections) {
619 connection.destroy()
620 pending.push(new Promise((resolve) => connection.on('close', resolve)))
621 }
622
623 this.suspended = true
624
625 log('Suspending server and discovery... (' + promises.length + ')')
626 await Promise.allSettled(promises)
627 log('Done, suspending the dht...')
628 await this.dht.suspend({ log })
629 log('Done, swarm fully suspended')
630
631 await Promise.all(pending)
632
633 // reset queue
634 this._timer.destroy()
635 this._timer = new RetryTimer(this._requeue.bind(this), {
636 backoffs: this._timer.backoffs,
637 jitter: this._timer.jitter
638 })
639 this._queue = spq()
640 }
641
642 async resume({ log = noop } = {}) {
643 if (!this.suspended) return
644
645 log('Resuming the dht')
646 await this.dht.resume()
647 log('Done, resuming the server')
648 await this.server.resume()
649 log('Done, all discovery')
650
651 for (const discovery of this._discovery.values()) {
652 discovery.resume()
653 }
654
655 this.suspended = false
656 this._attemptClientConnections()
657 }
658
659 topics() {
660 return this._discovery.values()
661 }
662}
663
664function noop() {}
665
666function allowAll() {
667 return false
668}
669
670function shouldForceRelaying(code) {
671 return (
672 code === 'HOLEPUNCH_ABORTED' ||
673 code === 'HOLEPUNCH_DOUBLE_RANDOMIZED_NATS' ||
674 code === 'REMOTE_NOT_HOLEPUNCHABLE'
675 )
676}
677
678function shouldBan() {
679 // return !!err && err.name === 'HypercoreError' && err.code === 'INVALID_OPERATION'
680 return false
681}
682
683function toRelayFunction(relayThrough) {
684 return typeof relayThrough === 'function'
685 ? relayThrough
686 : (force, swarm) => (force || swarm.dht.randomized ? relayThrough : null)
687}
node_modules/hyperswarm/lib/bulk-timer.js +33 -0
……@@ -0,0 +1,33 @@
1module.exports = class BulkTimer {
2 constructor(time, fn) {
3 this._time = time
4 this._fn = fn
5 this._interval = null
6 this._next = []
7 this._pending = []
8 this._destroyed = false
9 }
10
11 destroy() {
12 if (this._destroyed) return
13 this._destroyed = true
14 clearInterval(this._interval)
15 this._interval = null
16 }
17
18 _ontick() {
19 if (!this._next.length && !this._pending.length) return
20 if (this._next.length) this._fn(this._next)
21 this._next = this._pending
22 this._pending = []
23 }
24
25 add(info) {
26 if (this._destroyed) return
27 if (!this._interval) {
28 this._interval = setInterval(this._ontick.bind(this), Math.floor(this._time * 0.66))
29 }
30
31 this._pending.push(info)
32 }
33}
node_modules/hyperswarm/lib/connection-set.js +38 -0
……@@ -0,0 +1,38 @@
1const b4a = require('b4a')
2
3module.exports = class ConnectionSet {
4 constructor() {
5 this._byPublicKey = new Map()
6 }
7
8 [Symbol.iterator]() {
9 return this._byPublicKey.values()
10 }
11
12 get size() {
13 return this._byPublicKey.size
14 }
15
16 has(publicKey) {
17 return this._byPublicKey.has(toHex(publicKey))
18 }
19
20 get(publicKey) {
21 return this._byPublicKey.get(toHex(publicKey))
22 }
23
24 add(connection) {
25 this._byPublicKey.set(b4a.toString(connection.remotePublicKey, 'hex'), connection)
26 }
27
28 delete(connection) {
29 const keyString = b4a.toString(connection.remotePublicKey, 'hex')
30 const existing = this._byPublicKey.get(keyString)
31 if (existing !== connection) return
32 this._byPublicKey.delete(keyString)
33 }
34}
35
36function toHex(b) {
37 return typeof b === 'string' ? b : b4a.toString(b, 'hex')
38}
node_modules/hyperswarm/lib/peer-discovery.js +358 -0
……@@ -0,0 +1,358 @@
1const safetyCatch = require('safety-catch')
2const b4a = require('b4a')
3
4const REFRESH_INTERVAL = 1000 * 60 * 10 // 10 min
5const RANDOM_JITTER = 1000 * 60 * 2 // 2 min
6const DELAY_GRACE_PERIOD = 1000 * 30 // 30s
7
8const MAX_DISCOVERY_CACHE = 64
9
10module.exports = class PeerDiscovery {
11 constructor(
12 swarm,
13 topic,
14 { limit = Infinity, wait = null, suspended = false, onpeer = noop, onerror = safetyCatch }
15 ) {
16 this.limit = limit
17 this.swarm = swarm
18 this.topic = topic
19 this.isClient = false
20 this.isServer = false
21 this.destroyed = false
22 this.destroying = null
23 this.suspended = suspended
24
25 this._sessions = []
26 this._clientSessions = 0
27 this._serverSessions = 0
28
29 this._onpeer = onpeer
30 this._onerror = onerror
31
32 this._discovered = new Set()
33 this._activeQuery = null
34 this._timer = null
35 this._currentRefresh = null
36 this._closestNodes = null
37 this._firstAnnounce = true
38 this._needsUnannounce = false
39 this._refreshes = 0
40 this._wait = wait
41 }
42
43 session({ server = true, client = true, limit = Infinity, onerror = safetyCatch }) {
44 if (this.destroyed) throw new Error('PeerDiscovery is destroyed')
45 const session = new PeerDiscoverySession(this)
46 session.refresh({ server, client, limit }).catch(onerror)
47 this._sessions.push(session)
48 return session
49 }
50
51 _refreshLater(eager) {
52 const jitter = Math.round(Math.random() * RANDOM_JITTER)
53 const delay = !eager ? REFRESH_INTERVAL + jitter : jitter
54
55 if (this._timer) clearTimeout(this._timer)
56
57 const startTime = Date.now()
58 this._timer = setTimeout(() => {
59 // If your laptop went to sleep, and is coming back online...
60 const overdue = Date.now() - startTime > delay + DELAY_GRACE_PERIOD
61 if (overdue) this._refreshLater(true)
62 else this.refresh().catch(this._onerror)
63 }, delay)
64 }
65
66 _isActive() {
67 return !this.destroyed && !this.suspended
68 }
69
70 // TODO: Allow announce to be an argument to this
71 // TODO: Maybe announce should be a setter?
72 async _refresh() {
73 if (this.suspended) return
74 const clock = ++this._refreshes
75
76 if (this._wait) {
77 await this._wait
78 this._wait = null
79 if (clock !== this._refreshes || !this._isActive()) return
80 }
81
82 const clear = this.isServer && this._firstAnnounce
83 if (clear) this._firstAnnounce = false
84
85 const opts = {
86 clear,
87 closestNodes: this._closestNodes
88 }
89
90 if (this.isServer) {
91 await this.swarm.listen()
92 // if a parallel refresh is happening, yield to the new one
93 if (clock !== this._refreshes || !this._isActive()) return
94 this._needsUnannounce = true
95 }
96
97 let limit = this.limit
98
99 if (limit < Infinity && limit > 0) {
100 for (const id of this._discovered) {
101 if (!this.swarm.connections.has(id)) continue
102 if (--limit === 0) break
103 }
104 }
105
106 this._discovered.clear()
107
108 const announcing = this.isServer
109 const query = (this._activeQuery = announcing
110 ? this.swarm.dht.announce(
111 this.topic,
112 this.swarm.keyPair,
113 this.swarm.server.relayAddresses,
114 opts
115 )
116 : this._needsUnannounce
117 ? this.swarm.dht.lookupAndUnannounce(this.topic, this.swarm.keyPair, opts)
118 : this.swarm.dht.lookup(this.topic, opts))
119
120 try {
121 for await (const data of this._activeQuery) {
122 if (!this.isClient || !this._isActive()) continue
123 for (const peer of data.peers) {
124 if (limit < Infinity) {
125 const id = b4a.toString(peer.publicKey, 'hex')
126
127 if (this._discovered.size < MAX_DISCOVERY_CACHE) {
128 this._discovered.add(id)
129 }
130
131 if (limit === 0) continue
132
133 // there is a chance it has updated a connection during discovery and we go over
134 // the limit - thats acceptable to avoid a complexity spiral here.
135 if (!this.swarm.connections.has(id)) limit--
136 }
137
138 this._onpeer(peer, data)
139 }
140 }
141 } catch (err) {
142 if (this._isActive()) throw err
143 } finally {
144 if (this._activeQuery === query) {
145 this._activeQuery = null
146 if (!this.destroyed && !this.suspended) this._refreshLater(false)
147 }
148 }
149
150 // This is set at the very end, when the query completes successfully.
151 this._closestNodes = query.closestNodes
152
153 if (clock !== this._refreshes) return
154
155 // In this is the latest query, unannounce has been fulfilled as well
156 if (!announcing) this._needsUnannounce = false
157 }
158
159 async refresh() {
160 if (this.destroyed) throw new Error('PeerDiscovery is destroyed')
161
162 const server = this._serverSessions > 0
163 const client = this._clientSessions > 0
164
165 if (this.suspended) return
166
167 if (server === this.isServer && client === this.isClient) {
168 if (this._currentRefresh) return this._currentRefresh
169 this._currentRefresh = this._refresh()
170 } else {
171 if (this._activeQuery) this._activeQuery.destroy()
172 this.isServer = server
173 this.isClient = client
174 this._currentRefresh = this._refresh()
175 }
176
177 const refresh = this._currentRefresh
178 try {
179 await refresh
180 } catch {
181 return false
182 } finally {
183 if (refresh === this._currentRefresh) {
184 this._currentRefresh = null
185 }
186 }
187
188 return true
189 }
190
191 async flushed() {
192 if (this.swarm.listening) await this.swarm.listening
193
194 try {
195 await this._currentRefresh
196 return true
197 } catch {
198 return false
199 }
200 }
201
202 async _destroyMaybe() {
203 if (this.destroyed) return
204
205 try {
206 if (this._sessions.length === 0) await this.swarm.leave(this.topic)
207 else if (this._serverSessions === 0 && this._needsUnannounce) await this.refresh()
208 } catch (err) {
209 // ignore network failures here, as we are tearing down
210 safetyCatch(err)
211 }
212 }
213
214 destroy() {
215 if (this.destroying) return this.destroying
216 this.destroying = this._destroy()
217 return this.destroying
218 }
219
220 async _abort(log) {
221 const id = log === noop ? '' : b4a.toString(this.topic, 'hex')
222
223 log('Aborting discovery', id)
224 if (this._wait) await this._wait
225 log('Aborting discovery (post wait)', id)
226
227 if (this._activeQuery) {
228 this._activeQuery.destroy()
229 this._activeQuery = null
230 }
231 if (this._timer) {
232 clearTimeout(this._timer)
233 this._timer = null
234 }
235
236 let nodes = this._closestNodes
237
238 if (this._currentRefresh) {
239 try {
240 await this._currentRefresh
241 } catch {
242 // If the destroy causes the refresh to fail, suppress it.
243 }
244 }
245
246 log('Aborting discovery (post refresh)', id)
247 if (this._isActive()) return
248
249 if (!nodes) nodes = this._closestNodes
250 else if (this._closestNodes !== nodes) {
251 const len = nodes.length
252 for (const newer of this._closestNodes) {
253 if (newer.id && !hasNode(nodes, len, newer)) nodes.push(newer)
254 }
255 }
256
257 if (this._needsUnannounce) {
258 log('Unannouncing discovery', id)
259 if (nodes && nodes.length) {
260 await this.swarm.dht.unannounce(this.topic, this.swarm.keyPair, {
261 closestNodes: nodes,
262 onlyClosestNodes: true,
263 force: true
264 })
265 }
266 this._needsUnannounce = false
267 log('Unannouncing discovery (done)', id)
268 }
269 }
270
271 _destroy() {
272 if (this.destroyed) return
273 this.destroyed = true
274 return this._abort(noop)
275 }
276
277 async suspend({ log = noop } = {}) {
278 if (this.suspended) return
279 this.suspended = true
280 try {
281 await this._abort(log)
282 } catch {
283 // ignore
284 }
285 }
286
287 resume() {
288 if (!this.suspended) return
289 this.suspended = false
290 this.refresh().catch(noop)
291 }
292}
293
294class PeerDiscoverySession {
295 constructor(discovery) {
296 this.discovery = discovery
297 this.isClient = false
298 this.isServer = false
299 this.destroyed = false
300 }
301
302 get swarm() {
303 return this.discovery.swarm
304 }
305
306 get topic() {
307 return this.discovery.topic
308 }
309
310 async refresh({ client = this.isClient, server = this.isServer, limit = Infinity } = {}) {
311 if (this.destroyed) throw new Error('PeerDiscovery is destroyed')
312 if (!client && !server) throw new Error('Cannot refresh with neither client nor server option')
313
314 if (client !== this.isClient) {
315 this.isClient = client
316 this.discovery._clientSessions += client ? 1 : -1
317 }
318
319 if (server !== this.isServer) {
320 this.isServer = server
321 this.discovery._serverSessions += server ? 1 : -1
322 }
323
324 this.discovery.limit = limit
325
326 return this.discovery.refresh()
327 }
328
329 async flushed() {
330 return this.discovery.flushed()
331 }
332
333 async destroy() {
334 if (this.destroyed) return
335 this.destroyed = true
336
337 if (this.isClient) this.discovery._clientSessions--
338 if (this.isServer) this.discovery._serverSessions--
339
340 const index = this.discovery._sessions.indexOf(this)
341 const head = this.discovery._sessions.pop()
342
343 if (head !== this) this.discovery._sessions[index] = head
344
345 return this.discovery._destroyMaybe()
346 }
347}
348
349function hasNode(nodes, len, node) {
350 for (let i = 0; i < len; i++) {
351 const existing = nodes[i]
352 if (existing.id && b4a.equals(existing.id, node.id)) return true
353 }
354
355 return false
356}
357
358function noop() {}
node_modules/hyperswarm/lib/peer-info.js +116 -0
……@@ -0,0 +1,116 @@
1const { EventEmitter } = require('events')
2const b4a = require('b4a')
3const unslab = require('unslab')
4
5const MIN_CONNECTION_TIME = 15000
6
7const VERY_LOW_PRIORITY = 0
8const LOW_PRIORITY = 1
9const NORMAL_PRIORITY = 2
10const HIGH_PRIORITY = 3
11const VERY_HIGH_PRIORITY = 4
12
13module.exports = class PeerInfo extends EventEmitter {
14 constructor({ publicKey, relayAddresses }) {
15 super()
16
17 this.publicKey = unslab(publicKey)
18 this.relayAddresses = relayAddresses
19
20 this.reconnecting = true
21 this.proven = false
22 this.connectedTime = -1
23 this.disconnectedTime = 0
24 this.banned = false
25 this.tried = false
26 this.explicit = false
27 this.waiting = false
28 this.forceRelaying = false
29
30 // Set by the Swarm
31 this.queued = false
32 this.client = false
33 this.topics = [] // TODO: remove on next major (check with mafintosh for context)
34
35 this.attempts = 0
36 this.priority = NORMAL_PRIORITY
37
38 // Used by shuffled-priority-queue
39 this._index = 0
40
41 // Used for flush management
42 this._flushTick = 0
43
44 // Used for topic multiplexing
45 this._seenTopics = new Set()
46 }
47
48 get server() {
49 return !this.client
50 }
51
52 get prioritized() {
53 return this.priority >= NORMAL_PRIORITY
54 }
55
56 _getPriority() {
57 const peerIsStale = this.tried && !this.proven
58 if (peerIsStale || this.attempts > 3) return VERY_LOW_PRIORITY
59 if (this.attempts === 3) return LOW_PRIORITY
60 if (this.attempts === 2) return HIGH_PRIORITY
61 if (this.attempts === 1) return VERY_HIGH_PRIORITY
62 return NORMAL_PRIORITY
63 }
64
65 _connected() {
66 this.proven = true
67 this.connectedTime = Date.now()
68 }
69
70 _disconnected() {
71 this.disconnectedTime = Date.now()
72 if (this.connectedTime > -1) {
73 if (this.disconnectedTime - this.connectedTime >= MIN_CONNECTION_TIME) this.attempts = 0 // fast retry
74 this.connectedTime = -1
75 }
76 this.attempts++
77 }
78
79 _deprioritize() {
80 this.attempts = 3
81 }
82
83 _reset() {
84 this.client = false
85 this.proven = false
86 this.tried = false
87 this.attempts = 0
88 }
89
90 _updatePriority() {
91 if (this.explicit && this.attempts > 3) this._deprioritize()
92 if (this.banned || this.queued || this.attempts > 3) return false
93 this.priority = this._getPriority()
94 return true
95 }
96
97 _topic(topic) {
98 const topicString = b4a.toString(topic, 'hex')
99 if (this._seenTopics.has(topicString)) return
100 this._seenTopics.add(topicString)
101 this.topics.push(topic)
102 this.emit('topic', topic)
103 }
104
105 reconnect(val) {
106 this.reconnecting = !!val
107 }
108
109 ban(val) {
110 this.banned = !!val
111 }
112
113 shouldGC() {
114 return !(this.banned || this.queued || this.explicit || this.waiting)
115 }
116}
node_modules/hyperswarm/lib/retry-timer.js +68 -0
……@@ -0,0 +1,68 @@
1const BulkTimer = require('./bulk-timer')
2
3const BACKOFF_JITTER = 500
4const BACKOFF_S = 1000 + Math.round(BACKOFF_JITTER * Math.random())
5const BACKOFF_M = 5000 + Math.round(2 * BACKOFF_JITTER * Math.random())
6const BACKOFF_L = 15000 + Math.round(4 * BACKOFF_JITTER * Math.random())
7const BACKOFF_X = 1000 * 60 * 10 + Math.round(240 * BACKOFF_JITTER * Math.random())
8
9module.exports = class RetryTimer {
10 constructor(
11 push,
12 { backoffs = [BACKOFF_S, BACKOFF_M, BACKOFF_L, BACKOFF_X], jitter = BACKOFF_JITTER } = {}
13 ) {
14 this.jitter = jitter
15 this.backoffs = backoffs
16
17 this._sTimer = new BulkTimer(backoffs[0] + Math.round(jitter * Math.random()), push)
18 this._mTimer = new BulkTimer(backoffs[1] + Math.round(jitter * Math.random()), push)
19 this._lTimer = new BulkTimer(backoffs[2] + Math.round(jitter * Math.random()), push)
20 this._xTimer = new BulkTimer(backoffs[3] + Math.round(jitter * Math.random()), push)
21 }
22
23 _selectRetryTimer(peerInfo) {
24 if (peerInfo.banned || !peerInfo.reconnecting) return null
25
26 if (peerInfo.attempts > 3) {
27 return peerInfo.explicit ? this._xTimer : null
28 }
29
30 if (peerInfo.attempts === 0) return this._sTimer
31 if (peerInfo.proven) {
32 switch (peerInfo.attempts) {
33 case 1:
34 return this._sTimer
35 case 2:
36 return this._mTimer
37 case 3:
38 return this._lTimer
39 }
40 } else {
41 switch (peerInfo.attempts) {
42 case 1:
43 return this._mTimer
44 case 2:
45 return this._lTimer
46 case 3:
47 return this._lTimer
48 }
49 }
50
51 return null
52 }
53
54 add(peerInfo) {
55 const timer = this._selectRetryTimer(peerInfo)
56 if (!timer) return false
57
58 timer.add(peerInfo)
59 return true
60 }
61
62 destroy() {
63 this._sTimer.destroy()
64 this._mTimer.destroy()
65 this._lTimer.destroy()
66 this._xTimer.destroy()
67 }
68}
node_modules/hyperswarm/package.json +59 -0
……@@ -0,0 +1,59 @@
1{
2 "name": "hyperswarm",
3 "version": "4.17.0",
4 "description": "A distributed networking stack for connecting peers",
5 "files": [
6 "index.js",
7 "lib/**.js"
8 ],
9 "imports": {
10 "events": {
11 "bare": "bare-events",
12 "default": "events"
13 },
14 "process": {
15 "bare": "bare-process",
16 "default": "process"
17 }
18 },
19 "dependencies": {
20 "b4a": "^1.3.1",
21 "bare-events": "^2.2.0",
22 "hyperdht": "^6.21.0",
23 "safety-catch": "^1.0.2",
24 "shuffled-priority-queue": "^2.1.0",
25 "streamx": "^2.22.1",
26 "unslab": "^1.3.0"
27 },
28 "devDependencies": {
29 "bare-process": "^4.2.2",
30 "brittle": "^3.0.2",
31 "hypercore-crypto": "^3.4.0",
32 "lunte": "^1.3.0",
33 "prettier": "^3.6.2",
34 "prettier-config-holepunch": "^2.0.0",
35 "which-runtime": "^1.3.2"
36 },
37 "scripts": {
38 "format": "prettier --write .",
39 "lint": "prettier --check . && lunte",
40 "test": "npm run test:node && npm run test:bare",
41 "test:generate": "brittle -r test/all.js test/*.js",
42 "test:node": "brittle-node --coverage test/*.js",
43 "test:bare": "bare test/all.js"
44 },
45 "repository": {
46 "type": "git",
47 "url": "https://github.com/holepunchto/hyperswarm.git"
48 },
49 "author": "Mathias Buus (@mafintosh)",
50 "contributors": [
51 "David Mark Clements (@davidmarkclem)",
52 "Andrew Osheroff (@andrewosh)"
53 ],
54 "license": "MIT",
55 "bugs": {
56 "url": "https://github.com/holepunchto/hyperswarm/issues"
57 },
58 "homepage": "https://github.com/holepunchto/hyperswarm"
59}
node_modules/kademlia-routing-table/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2019 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/kademlia-routing-table/README.md +160 -0
……@@ -0,0 +1,160 @@
1# kademlia-routing-table
2
3XOR distance based routing table used for P2P networks such as a Kademlia DHT.
4
5```
6npm install kademlia-routing-table
7```
8
9Similar to k-buckets, but implemented using the simplifications described in https://github.com/ethereum/wiki/wiki/Kademlia-Peer-Selection
10
11To understand the concept behind peer routing, DHTs, and the terms used here,
12I recommend reading the [Kademlia DHT paper](https://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf) as well.
13
14## Usage
15
16``` js
17const RoutingTable = require('kademlia-routing-table')
18const { randomBytes } = require('crypto')
19
20// Create a new table that stores nodes "close" to the passed in id.
21// The id should be uniformily distributed, ie a hash, random bytes etc.
22const table = new RoutingTable(randomBytes(32))
23
24// Add a node to the routing table
25table.add({
26 id: randomBytes(32), // this field is required
27 // populate with any other data you want to store
28})
29
30table.on('row', function (row) {
31 // A new row has been added to the routing table
32 // This row represents row.index similar bits to the table.id
33
34 row.on('full', function (node) {
35 // The row is full and cannot be split, so node cannot be added.
36 // If any of the nodes in the row are "worse", based on
37 // some application specific metric then we should remove
38 // the worst node from the row and re-add the node.
39 })
40})
41
42// Get the 20 nodes "closest" to a passed in id
43const closest = table.closest(randomBytes(32), 20)
44```
45
46## API
47
48#### `table = new RoutingTable(id, [options])`
49
50Create a new routing table.
51
52`id` should be a Buffer that is uniformily distributed. `options` include:
53
54``` js
55{
56 k: 20 // The max row size
57}
58```
59
60#### `bool = table.add(node)`
61
62Insert a new node. `node.id` must be a Buffer of same length as `table.id`.
63When inserting a node the XOR distance between the node and the table.id is
64calculated and used to figure which table row this node should be inserted into.
65
66Returns `true` if the node could be added to the corresponding row or `false` if not.
67If `false` is returned the onfullrow function is invoked for the corresponding row and node.
68
69#### `node = table.get(id)`
70
71Get a node from the table using its id. Returns `null` if no node has the passed in `id`.
72
73#### `bool = table.has(id)`
74
75Returns `true` if a node exists for the passed in `id` and `false` otherwise.
76
77#### `nodes = table.closest(id, [maxNodes])`
78
79Returns an array of the closest (in XOR distance) nodes to the passed in id.
80
81`id` should be Buffer of same length as `table.id`. Per default at max `k`
82nodes are returned, but this can be configured using the `maxNodes` argument.
83
84This method is normally used in a routing context, i.e. figuring out which nodes
85in a DHT should store a value based on its id.
86
87#### `bool = table.remove(id)`
88
89Remove a node using its id. Returns `true` if a node existed for the id and
90was removed and `false` otherwise.
91
92#### `node = table.random()`
93
94Get a random node from the table.
95
96#### `nodes = table.toArray()`
97
98Returns all nodes from table as an array. If you create a new routing table
99from these nodes it will be identical to the used here.
100
101#### `table.on('row', row)`
102
103Emitted when a new row is added to the routing table. At max, `bitLength(table.id)`
104will exist.
105
106#### `table.rows`
107
108A fixed size array of all rows in the table. Normally you would not need to worry
109about accessing rows directly outside the row event.
110
111## Row API
112
113For the row passed in the the `onfullrow` function the following API exists.
114
115#### `row.index`
116
117The row index. Represents how many prefix bits are shared between nodes in the row
118and the table id.
119
120#### `row.nodes`
121
122A list of all the nodes in the row, sorted by their `id`.
123
124#### `row.data`
125
126Property set to null initially you can use if you want to store optional data on the row.
127
128#### `bool = row.add(node)`
129
130Same as `table.add` but for a specific row. Only use this to add the `newNode`
131passed in `onfullrow` function.
132
133#### `bool = row.remove(node)`
134
135Same as `table.remove` but for a specific row. Only use this to remove the
136"worst" node from the row when wanting to add the newNode.
137
138#### `row.on('add', node)`
139
140Emitted when a new node is added to this row.
141
142#### `row.on('remove', node)`
143
144Emitted when a node has been removed from this row.
145
146#### `row.on('full', node)`
147
148Emitted when a node wants to be added to this row, but the row is full (stores `k` nodes).
149
150When this happens you should check if any of the nodes already in the row (`row.nodes`) are
151"worse" than the passed node. If that is the case, remove the "worst" one and re-add the node passed in the arguments.
152
153Various algorithms can be implemented to handle full rows, which is why the routing table leaves most of this logic
154up to the user. These kind of algorithms include adding the rejected node to a cache and wait for another node in the
155row to be removed before trying to insert it again, or using an LRU cache to determine which node already in the row
156has been heard from yet.
157
158## License
159
160MIT
node_modules/kademlia-routing-table/index.js +202 -0
……@@ -0,0 +1,202 @@
1const { EventEmitter } = require('events')
2
3module.exports = class RoutingTable extends EventEmitter {
4 constructor (id, opts) {
5 if (!opts) opts = {}
6
7 super()
8
9 this.id = id
10 this.k = opts.k || 20
11 this.size = 0
12 this.rows = new Array(id.length * 8)
13 }
14
15 add (node) {
16 const i = this._diff(node.id)
17
18 let row = this.rows[i]
19
20 if (!row) {
21 row = this.rows[i] = new Row(this, i)
22 this.emit('row', row)
23 }
24
25 const len = row.nodes.length
26 if (!row.add(node, this.k)) return false
27
28 this.size += row.nodes.length - len
29 return true
30 }
31
32 remove (id) {
33 const i = this._diff(id)
34 const row = this.rows[i]
35 if (!row) return false
36 if (!row.remove(id)) return false
37 this.size--
38 return true
39 }
40
41 get (id) {
42 const i = this._diff(id)
43 const row = this.rows[i]
44 if (!row) return null
45 return row.get(id)
46 }
47
48 has (id) {
49 return this.get(id) !== null
50 }
51
52 random () {
53 let n = (Math.random() * this.size) | 0
54
55 for (let i = 0; i < this.rows.length; i++) {
56 const r = this.rows[i]
57 if (!r) continue
58 if (n < r.nodes.length) return r.nodes[n]
59 n -= r.nodes.length
60 }
61
62 return null
63 }
64
65 closest (id, k) {
66 if (!k) k = this.k
67
68 const result = []
69 const d = this._diff(id)
70
71 // push close nodes
72 for (let i = d; i >= 0 && result.length < k; i--) this._pushNodes(i, k, result)
73
74 // if we don't have enough close nodes, populate from other rows, re the paper
75 for (let i = d + 1; i < this.rows.length && result.length < k; i++) this._pushNodes(i, k, result)
76
77 return result
78 }
79
80 _pushNodes (i, k, result) {
81 const row = this.rows[i]
82 if (!row) return
83
84 const missing = Math.min(k - result.length, row.nodes.length)
85 for (let j = 0; j < missing; j++) result.push(row.nodes[j])
86 }
87
88 toArray () {
89 return this.closest(this.id, Infinity)
90 }
91
92 _diff (id) {
93 for (let i = 0; i < id.length; i++) {
94 const a = id[i]
95 const b = this.id[i]
96
97 if (a !== b) return i * 8 + Math.clz32(a ^ b) - 24
98 }
99
100 return this.rows.length - 1
101 }
102}
103
104class Row extends EventEmitter {
105 constructor (table, index) {
106 super()
107
108 this.data = null // can be used be upstream for whatevs
109 this.byteOffset = index >> 3
110 this.index = index
111 this.table = table
112 this.nodes = []
113 }
114
115 add (node) {
116 const id = node.id
117
118 let l = 0
119 let r = this.nodes.length - 1
120
121 while (l <= r) {
122 const m = (l + r) >> 1
123 const c = this.compare(id, this.nodes[m].id)
124
125 if (c === 0) {
126 this.nodes[m] = node
127 return true
128 }
129
130 if (c < 0) r = m - 1
131 else l = m + 1
132 }
133
134 if (this.nodes.length >= this.table.k) {
135 this.emit('full', node)
136 return false
137 }
138
139 this.insert(l, node)
140 return true
141 }
142
143 remove (id) {
144 let l = 0
145 let r = this.nodes.length - 1
146
147 while (l <= r) {
148 const m = (l + r) >> 1
149 const c = this.compare(id, this.nodes[m].id)
150
151 if (c === 0) {
152 this.splice(m)
153 return true
154 }
155
156 if (c < 0) r = m - 1
157 else l = m + 1
158 }
159
160 return false
161 }
162
163 get (id) {
164 let l = 0
165 let r = this.nodes.length - 1
166
167 while (l <= r) {
168 const m = (l + r) >> 1
169 const node = this.nodes[m]
170 const c = this.compare(id, node.id)
171
172 if (c === 0) return node
173 if (c < 0) r = m - 1
174 else l = m + 1
175 }
176
177 return null
178 }
179
180 insert (i, node) {
181 this.nodes.push(node) // push node or null or whatevs, just trying to not be polymorphic
182 for (let j = this.nodes.length - 1; j > i; j--) this.nodes[j] = this.nodes[j - 1]
183 this.nodes[i] = node
184 this.emit('add', node)
185 }
186
187 splice (i) {
188 for (; i < this.nodes.length - 1; i++) this.nodes[i] = this.nodes[i + 1]
189 this.emit('remove', this.nodes.pop())
190 }
191
192 // very likely they diverge after a couple of bytes so a simple impl, like this is prop fastest vs Buffer.compare
193 compare (a, b) {
194 for (let i = this.byteOffset; i < a.length; i++) {
195 const ai = a[i]
196 const bi = b[i]
197 if (ai === bi) continue
198 return ai < bi ? -1 : 1
199 }
200 return 0
201 }
202}
node_modules/kademlia-routing-table/package.json +45 -0
……@@ -0,0 +1,45 @@
1{
2 "name": "kademlia-routing-table",
3 "version": "1.0.6",
4 "description": "XOR based routing table used for P2P networks such as a Kademlia DHT.",
5 "main": "index.js",
6 "files": [
7 "index.js"
8 ],
9 "imports": {
10 "events": {
11 "bare": "bare-events",
12 "default": "events"
13 }
14 },
15 "dependencies": {
16 "bare-events": "^2.2.0"
17 },
18 "devDependencies": {
19 "brittle": "^3.3.2",
20 "standard": "^17.1.0"
21 },
22 "scripts": {
23 "test": "standard && brittle test.js"
24 },
25 "keywords": [
26 "kademlia",
27 "p2p",
28 "k-bucket",
29 "k-buckets",
30 "xor",
31 "routing",
32 "distributed",
33 "systems"
34 ],
35 "repository": {
36 "type": "git",
37 "url": "https://github.com/mafintosh/kademlia-routing-table.git"
38 },
39 "author": "Mathias Buus (@mafintosh)",
40 "license": "MIT",
41 "bugs": {
42 "url": "https://github.com/mafintosh/kademlia-routing-table/issues"
43 },
44 "homepage": "https://github.com/mafintosh/kademlia-routing-table"
45}
node_modules/nat-sampler/.github/workflows/test-node.yml +24 -0
……@@ -0,0 +1,24 @@
1name: Build Status
2
3on:
4 push:
5 branches:
6 - master
7 pull_request:
8 branches:
9 - master
10jobs:
11 build:
12 strategy:
13 matrix:
14 node-version: [14.x]
15 os: [ubuntu-16.04, macos-latest, windows-latest]
16 runs-on: ${{ matrix.os }}
17 steps:
18 - uses: actions/checkout@v2
19 - name: Use Node.js ${{ matrix.node-version }}
20 uses: actions/setup-node@v1
21 with:
22 node-version: ${{ matrix.node-version }}
23 - run: npm install
24 - run: npm test
node_modules/nat-sampler/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2021 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/nat-sampler/README.md +63 -0
……@@ -0,0 +1,63 @@
1# nat-sampler
2
3Sample addresses to figure out if a host + port is consistent
4
5```
6npm install nat-sampler
7```
8
9## Usage
10
11``` js
12const NatSampler = require('nat-sampler')
13
14const s = new NatSampler()
15
16// add a sample
17const hits = s.add('127.0.0.1', 9090)
18
19console.log('In there this many times:', hits)
20console.log('Estimated host + port', s.host, s.port)
21```
22
23## API
24
25#### `s = new NatSampler()`
26
27Make a new sampler.
28
29#### `hits = s.add(host, port)`
30
31Add a sample of your host and port.
32Returns how many hits this entry has.
33
34#### `s.host`
35
36What the sampler thinks your host is.
37
38If your host is unknown it will be `null`.
39
40#### `s.port`
41
42What the sampler thinks your port is.
43
44If your port is random or unknown it will be `0`.
45
46#### `s.size`
47
48How many samples the sampler is basing this on.
49
50## Error correction
51
52The sampler applies some simple error correction to make sure bad samples do not mess it up.
53
54* If it has `<=` 3 samples, it will disregard none outliers.
55* If it has `<=` 7 samples, it will disregard one outliers.
56* If it has `<=` 11 samples, it will disregard two outliers.
57* If it has `>` 11 samples, it will disregard three outliers.
58
59At max it keeps 16 samples of `{ host, port }` pairs for the analysis.
60
61## License
62
63MIT
node_modules/nat-sampler/index.js +64 -0
……@@ -0,0 +1,64 @@
1module.exports = class NatSampler {
2 constructor () {
3 this.host = null
4 this.port = 0
5 this.size = 0
6
7 this._a = null
8 this._b = null
9 this._threshold = 0
10 this._top = 0
11 this._samples = []
12 }
13
14 add (host, port) {
15 const a = this._bump(host, port, 2)
16 const b = this._bump(host, 0, 1)
17
18 if (this._samples.length < 32) {
19 this.size++
20 this._threshold = this.size - (this.size < 4 ? 0 : this.size < 8 ? 1 : this.size < 12 ? 2 : 3)
21 this._samples.push(a, b)
22 this._top += 2
23 } else {
24 if (this._top === 32) this._top = 0
25
26 const oa = this._samples[this._top]
27 this._samples[this._top++] = a
28 oa.hits--
29
30 const ob = this._samples[this._top]
31 this._samples[this._top++] = b
32 ob.hits--
33 }
34
35 if (this._a === null || this._a.hits < a.hits) this._a = a
36 if (this._b === null || this._b.hits < b.hits) this._b = b
37
38 if (this._a.hits >= this._threshold) {
39 this.host = this._a.host
40 this.port = this._a.port
41 } else if (this._b.hits >= this._threshold) {
42 this.host = this._b.host
43 this.port = 0
44 } else {
45 this.host = null
46 this.port = 0
47 }
48
49 return a.hits
50 }
51
52 _bump (host, port, inc) {
53 for (let i = 0; i < 4; i++) {
54 const j = (this._top - inc - (2 * i)) & 31
55 if (j >= this._samples.length) return { host, port, hits: 1 }
56 const s = this._samples[j]
57 if (s.port === port && s.host === host) {
58 s.hits++
59 return s
60 }
61 }
62 return { host, port, hits: 1 }
63 }
64}
node_modules/nat-sampler/package.json +24 -0
……@@ -0,0 +1,24 @@
1{
2 "name": "nat-sampler",
3 "version": "1.0.1",
4 "description": "Sample addresses to figure out if a host + port is consistent",
5 "main": "index.js",
6 "dependencies": {},
7 "devDependencies": {
8 "standard": "^16.0.3",
9 "tape": "^5.2.2"
10 },
11 "repository": {
12 "type": "git",
13 "url": "https://github.com/mafintosh/nat-sampler.git"
14 },
15 "scripts": {
16 "test": "standard && tape test.js"
17 },
18 "author": "Mathias Buus (@mafintosh)",
19 "license": "MIT",
20 "bugs": {
21 "url": "https://github.com/mafintosh/nat-sampler/issues"
22 },
23 "homepage": "https://github.com/mafintosh/nat-sampler"
24}
node_modules/nat-sampler/test.js +106 -0
……@@ -0,0 +1,106 @@
1const tape = require('tape')
2const NatSampler = require('./')
3
4tape('small consistent samples', function (t) {
5 const nat = new NatSampler()
6
7 t.same(nat.add('127.0.0.1', 9090), 1)
8 t.same(nat.host, '127.0.0.1')
9 t.same(nat.port, 9090)
10
11 t.same(nat.add('127.0.0.1', 9090), 2)
12 t.same(nat.host, '127.0.0.1')
13 t.same(nat.port, 9090)
14
15 t.same(nat.add('127.0.0.1', 9090), 3)
16 t.same(nat.host, '127.0.0.1')
17 t.same(nat.port, 9090)
18
19 t.end()
20})
21
22tape('small consistent samples with errors', function (t) {
23 const nat = new NatSampler()
24
25 t.same(nat.add('127.0.0.1', 9090), 1)
26 t.same(nat.host, '127.0.0.1')
27 t.same(nat.port, 9090)
28
29 t.same(nat.add('127.0.0.1', 9091), 1)
30 t.same(nat.host, '127.0.0.1')
31 t.same(nat.port, 0)
32
33 t.same(nat.add('127.0.0.1', 9090), 2)
34 t.same(nat.host, '127.0.0.1')
35 t.same(nat.port, 0)
36
37 t.same(nat.add('127.0.0.1', 9090), 3)
38 t.same(nat.host, '127.0.0.1')
39 t.same(nat.port, 9090)
40
41 t.same(nat.add('127.0.0.1', 9091), 2)
42 t.same(nat.host, '127.0.0.1')
43 t.same(nat.port, 0)
44
45 t.end()
46})
47
48tape('host consistency', function (t) {
49 const nat = new NatSampler()
50
51 t.same(nat.add('127.0.0.1', 9090), 1)
52 t.same(nat.add('127.0.0.2', 9090), 1)
53 t.same(nat.add('127.0.0.1', 9090), 2)
54 t.same(nat.add('127.0.0.2', 9090), 2)
55
56 t.same(nat.host, null)
57 t.same(nat.port, 0)
58
59 t.same(nat.add('127.0.0.1', 9090), 3)
60 t.same(nat.host, null)
61 t.same(nat.port, 0)
62
63 t.same(nat.add('127.0.0.1', 9090), 4)
64 t.same(nat.host, null)
65 t.same(nat.port, 0)
66
67 t.same(nat.add('127.0.0.1', 9090), 5)
68 t.same(nat.host, null)
69 t.same(nat.port, 0)
70
71 t.same(nat.add('127.0.0.1', 9091), 1)
72 t.same(nat.host, '127.0.0.1')
73 t.same(nat.port, 0)
74
75 t.end()
76})
77
78tape('can recover up to 3 errors', function (t) {
79 const nat = new NatSampler()
80
81 for (let i = 0; i < 20; i++) nat.add('127.0.0.1', 9090)
82
83 t.same(nat.add('127.0.0.1', 9091), 1)
84 t.same(nat.add('127.0.0.2', 9091), 1)
85 t.same(nat.add('127.0.0.3', 9091), 1)
86 t.same(nat.host, '127.0.0.1')
87 t.same(nat.port, 9090)
88
89 for (let i = 0; i < 5; i++) nat.add('127.0.0.1', 9090)
90 t.same(nat.host, '127.0.0.1')
91 t.same(nat.port, 9090)
92
93 nat.add('127.0.0.1', 9095)
94 t.same(nat.host, '127.0.0.1')
95 t.same(nat.port, 0)
96
97 nat.add('127.0.0.2', 9095)
98 t.same(nat.host, '127.0.0.1')
99 t.same(nat.port, 0)
100
101 nat.add('127.0.0.2', 9095)
102 t.same(nat.host, null)
103 t.same(nat.port, 0)
104
105 t.end()
106})
node_modules/picomatch/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2017-present, Jon Schlinkert.
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/picomatch/README.md +749 -0
……@@ -0,0 +1,749 @@
1<h1 align="center">Picomatch</h1>
2
3<p align="center">
4<a href="https://npmjs.org/package/picomatch">
5<img src="https://img.shields.io/npm/v/picomatch.svg" alt="version">
6</a>
7<a href="https://github.com/micromatch/picomatch/actions?workflow=Tests">
8<img src="https://github.com/micromatch/picomatch/workflows/Tests/badge.svg" alt="test status">
9</a>
10<a href="https://coveralls.io/github/micromatch/picomatch">
11<img src="https://img.shields.io/coveralls/github/micromatch/picomatch/master.svg" alt="coverage status">
12</a>
13<a href="https://npmjs.org/package/picomatch">
14<img src="https://img.shields.io/npm/dm/picomatch.svg" alt="downloads">
15</a>
16</p>
17
18<br>
19<br>
20
21<p align="center">
22<strong>Blazing fast and accurate glob matcher written in JavaScript.</strong></br>
23<em>No dependencies and full support for standard and extended Bash glob features, including braces, extglobs, POSIX brackets, and regular expressions.</em>
24</p>
25
26<br>
27<br>
28
29## Why picomatch?
30
31* **Lightweight** - No dependencies
32* **Minimal** - Tiny API surface. Main export is a function that takes a glob pattern and returns a matcher function.
33* **Fast** - Loads in about 2ms (that's several times faster than a [single frame of a HD movie](http://www.endmemo.com/sconvert/framespersecondframespermillisecond.php) at 60fps)
34* **Performant** - Use the returned matcher function to speed up repeat matching (like when watching files)
35* **Accurate matching** - Using wildcards (`*` and `?`), globstars (`**`) for nested directories, [advanced globbing](#advanced-globbing) with extglobs, braces, and POSIX brackets, and support for escaping special characters with `\` or quotes.
36* **Well tested** - Thousands of unit tests
37
38See the [library comparison](#library-comparisons) to other libraries.
39
40<br>
41<br>
42
43## Table of Contents
44
45<details><summary> Click to expand </summary>
46
47- [Install](#install)
48- [Usage](#usage)
49- [API](#api)
50 * [picomatch](#picomatch)
51 * [.test](#test)
52 * [.matchBase](#matchbase)
53 * [.isMatch](#ismatch)
54 * [.parse](#parse)
55 * [.scan](#scan)
56 * [.compileRe](#compilere)
57 * [.makeRe](#makere)
58 * [.toRegex](#toregex)
59- [Options](#options)
60 * [Picomatch options](#picomatch-options)
61 * [Scan Options](#scan-options)
62 * [Options Examples](#options-examples)
63- [Globbing features](#globbing-features)
64 * [Basic globbing](#basic-globbing)
65 * [Advanced globbing](#advanced-globbing)
66 * [Braces](#braces)
67 * [Matching special characters as literals](#matching-special-characters-as-literals)
68- [Library Comparisons](#library-comparisons)
69- [Benchmarks](#benchmarks)
70- [Philosophies](#philosophies)
71- [About](#about)
72 * [Author](#author)
73 * [License](#license)
74
75_(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_
76
77</details>
78
79<br>
80<br>
81
82## Install
83
84Install with [npm](https://www.npmjs.com/):
85
86```sh
87npm install --save picomatch
88```
89
90<br>
91
92## Usage
93
94The main export is a function that takes a glob pattern and an options object and returns a function for matching strings.
95
96```js
97const pm = require('picomatch');
98const isMatch = pm('*.js');
99
100console.log(isMatch('abcd')); //=> false
101console.log(isMatch('a.js')); //=> true
102console.log(isMatch('a.md')); //=> false
103console.log(isMatch('a/b.js')); //=> false
104```
105
106<br>
107
108## API
109
110### [picomatch](lib/picomatch.js#L31)
111
112Creates a matcher function from one or more glob patterns. The returned function takes a string to match as its first argument, and returns true if the string is a match. The returned matcher function also takes a boolean as the second argument that, when true, returns an object with additional information.
113
114**Params**
115
116* `globs` **{String|Array}**: One or more glob patterns.
117* `options` **{Object=}**
118* `returns` **{Function=}**: Returns a matcher function.
119
120**Example**
121
122```js
123const picomatch = require('picomatch');
124// picomatch(glob[, options]);
125
126const isMatch = picomatch('*.!(*a)');
127console.log(isMatch('a.a')); //=> false
128console.log(isMatch('a.b')); //=> true
129```
130
131**Example without node.js**
132
133For environments without `node.js`, `picomatch/posix` provides you a dependency-free matcher, without automatic OS detection.
134
135```js
136const picomatch = require('picomatch/posix');
137// the same API, defaulting to posix paths
138const isMatch = picomatch('a/*');
139console.log(isMatch('a\\b')); //=> false
140console.log(isMatch('a/b')); //=> true
141
142// you can still configure the matcher function to accept windows paths
143const isMatch = picomatch('a/*', { options: windows });
144console.log(isMatch('a\\b')); //=> true
145console.log(isMatch('a/b')); //=> true
146```
147
148### [.test](lib/picomatch.js#L116)
149
150Test `input` with the given `regex`. This is used by the main `picomatch()` function to test the input string.
151
152**Params**
153
154* `input` **{String}**: String to test.
155* `regex` **{RegExp}**
156* `returns` **{Object}**: Returns an object with matching info.
157
158**Example**
159
160```js
161const picomatch = require('picomatch');
162// picomatch.test(input, regex[, options]);
163
164console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
165// { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
166```
167
168### [.matchBase](lib/picomatch.js#L160)
169
170Match the basename of a filepath.
171
172**Params**
173
174* `input` **{String}**: String to test.
175* `glob` **{RegExp|String}**: Glob pattern or regex created by [.makeRe](#makeRe).
176* `returns` **{Boolean}**
177
178**Example**
179
180```js
181const picomatch = require('picomatch');
182// picomatch.matchBase(input, glob[, options]);
183console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
184```
185
186### [.isMatch](lib/picomatch.js#L182)
187
188Returns true if **any** of the given glob `patterns` match the specified `string`.
189
190**Params**
191
192* **{String|Array}**: str The string to test.
193* **{String|Array}**: patterns One or more glob patterns to use for matching.
194* **{Object}**: See available [options](#options).
195* `returns` **{Boolean}**: Returns true if any patterns match `str`
196
197**Example**
198
199```js
200const picomatch = require('picomatch');
201// picomatch.isMatch(string, patterns[, options]);
202
203console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
204console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
205```
206
207### [.parse](lib/picomatch.js#L198)
208
209Parse a glob pattern to create the source string for a regular expression.
210
211**Params**
212
213* `pattern` **{String}**
214* `options` **{Object}**
215* `returns` **{Object}**: Returns an object with useful properties and output to be used as a regex source string.
216
217**Example**
218
219```js
220const picomatch = require('picomatch');
221const result = picomatch.parse(pattern[, options]);
222```
223
224### [.scan](lib/picomatch.js#L230)
225
226Scan a glob pattern to separate the pattern into segments.
227
228**Params**
229
230* `input` **{String}**: Glob pattern to scan.
231* `options` **{Object}**
232* `returns` **{Object}**: Returns an object with
233
234**Example**
235
236```js
237const picomatch = require('picomatch');
238// picomatch.scan(input[, options]);
239
240const result = picomatch.scan('!./foo/*.js');
241console.log(result);
242{ prefix: '!./',
243 input: '!./foo/*.js',
244 start: 3,
245 base: 'foo',
246 glob: '*.js',
247 isBrace: false,
248 isBracket: false,
249 isGlob: true,
250 isExtglob: false,
251 isGlobstar: false,
252 negated: true }
253```
254
255### [.compileRe](lib/picomatch.js#L244)
256
257Compile a regular expression from the `state` object returned by the
258[parse()](#parse) method.
259
260**Params**
261
262* `state` **{Object}**
263* `options` **{Object}**
264* `returnOutput` **{Boolean}**: Intended for implementors, this argument allows you to return the raw output from the parser.
265* `returnState` **{Boolean}**: Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
266* `returns` **{RegExp}**
267
268**Example**
269
270```js
271const picomatch = require('picomatch');
272const state = picomatch.parse('*.js');
273// picomatch.compileRe(state[, options]);
274
275console.log(picomatch.compileRe(state));
276//=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
277```
278
279### [.makeRe](lib/picomatch.js#L285)
280
281Create a regular expression from a parsed glob pattern.
282
283**Params**
284
285* `state` **{String}**: The object returned from the `.parse` method.
286* `options` **{Object}**
287* `returnOutput` **{Boolean}**: Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result.
288* `returnState` **{Boolean}**: Implementors may use this argument to return the state from the parsed glob with the returned regular expression.
289* `returns` **{RegExp}**: Returns a regex created from the given pattern.
290
291**Example**
292
293```js
294const picomatch = require('picomatch');
295// picomatch.makeRe(state[, options]);
296
297const result = picomatch.makeRe('*.js');
298console.log(result);
299//=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
300```
301
302### [.toRegex](lib/picomatch.js#L320)
303
304Create a regular expression from the given regex source string.
305
306**Params**
307
308* `source` **{String}**: Regular expression source string.
309* `options` **{Object}**
310* `returns` **{RegExp}**
311
312**Example**
313
314```js
315const picomatch = require('picomatch');
316// picomatch.toRegex(source[, options]);
317
318const { output } = picomatch.parse('*.js');
319console.log(picomatch.toRegex(output));
320//=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
321```
322
323<br>
324
325## Options
326
327### Picomatch options
328
329The following options may be used with the main `picomatch()` function or any of the methods on the picomatch API.
330
331| **Option** | **Type** | **Default value** | **Description** |
332| --- | --- | --- | --- |
333| `basename` | `boolean` | `false` | If set, then patterns without slashes will be matched against the basename of the path if it contains slashes. For example, `a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`. |
334| `bash` | `boolean` | `false` | Follow bash matching rules more strictly - disallows backslashes as escape characters, and treats single stars as globstars (`**`). |
335| `capture` | `boolean` | `undefined` | Return regex matches in supporting methods. |
336| `contains` | `boolean` | `undefined` | Allows glob to match any part of the given string(s). |
337| `debug` | `boolean` | `undefined` | Debug regular expressions when an error is thrown. |
338| `dot` | `boolean` | `false` | Enable dotfile matching. By default, dotfiles are ignored unless a `.` is explicitly defined in the pattern, or `options.dot` is true |
339| `expandRange` | `function` | `undefined` | Custom function for expanding ranges in brace patterns, such as `{a..z}`. The function receives the range values as two arguments, and it must return a string to be used in the generated regex. It's recommended that returned strings be wrapped in parentheses. |
340| `fastpaths` | `boolean` | `true` | To speed up processing, full parsing is skipped for a handful common glob patterns. Disable this behavior by setting this option to `false`. |
341| `flags` | `string` | `undefined` | Regex flags to use in the generated regex. If defined, the `nocase` option will be overridden. |
342| [format](#optionsformat) | `function` | `undefined` | Custom function for formatting the returned string. This is useful for removing leading slashes, converting Windows paths to Posix paths, etc. |
343| `ignore` | `array\|string` | `undefined` | One or more glob patterns for excluding strings that should not be matched from the result. |
344| `keepQuotes` | `boolean` | `false` | Retain quotes in the generated regex, since quotes may also be used as an alternative to backslashes. |
345| `literalBrackets` | `boolean` | `undefined` | When `true`, brackets in the glob pattern will be escaped so that only literal brackets will be matched. |
346| `matchBase` | `boolean` | `false` | Alias for `basename` |
347| `maxLength` | `number` | `65536` | Limit the max length of the input string. An error is thrown if the input string is longer than this value. |
348| `maxExtglobRecursion` | `number\|boolean` | `0` | Limit nested quantified extglobs and other risky repeated extglob forms. When the limit is exceeded, the extglob is treated as a literal string instead of being compiled to regex. Set to `false` to disable this safeguard. |
349| `nobrace` | `boolean` | `false` | Disable brace matching, so that `{a,b}` and `{1..3}` would be treated as literal characters. |
350| `nobracket` | `boolean` | `undefined` | Disable matching with regex brackets. |
351| `nocase` | `boolean` | `false` | Make matching case-insensitive. Equivalent to the regex `i` flag. Note that this option is overridden by the `flags` option. |
352| `noext` | `boolean` | `false` | Alias for `noextglob` |
353| `noextglob` | `boolean` | `false` | Disable support for matching with extglobs (like `+(a\|b)`) |
354| `noglobstar` | `boolean` | `false` | Disable support for matching nested directories with globstars (`**`) |
355| `nonegate` | `boolean` | `false` | Disable support for negating with leading `!` |
356| [onIgnore](#optionsonIgnore) | `function` | `undefined` | Function to be called on ignored items. |
357| [onMatch](#optionsonMatch) | `function` | `undefined` | Function to be called on matched items. |
358| [onResult](#optionsonResult) | `function` | `undefined` | Function to be called on all items, regardless of whether or not they are matched or ignored. |
359| `posix` | `boolean` | `false` | Support POSIX character classes ("posix brackets"). |
360| `prepend` | `boolean` | `undefined` | String to prepend to the generated regex used for matching. |
361| `regex` | `boolean` | `false` | Use regular expression rules for `+` (instead of matching literal `+`), and for stars that follow closing parentheses or brackets (as in `)*` and `]*`). |
362| `strictBrackets` | `boolean` | `undefined` | Throw an error if brackets, braces, or parens are imbalanced. |
363| `strictSlashes` | `boolean` | `undefined` | When true, picomatch won't match trailing slashes with single stars. |
364| `unescape` | `boolean` | `undefined` | Remove backslashes preceding escaped characters in the glob pattern. By default, backslashes are retained. |
365| `windows` | `boolean` | `false` | Also accept backslashes as the path separator. |
366
367### Scan Options
368
369In addition to the main [picomatch options](#picomatch-options), the following options may also be used with the [.scan](#scan) method.
370
371| **Option** | **Type** | **Default value** | **Description** |
372| --- | --- | --- | --- |
373| `tokens` | `boolean` | `false` | When `true`, the returned object will include an array of tokens (objects), representing each path "segment" in the scanned glob pattern |
374| `parts` | `boolean` | `false` | When `true`, the returned object will include an array of strings representing each path "segment" in the scanned glob pattern. This is automatically enabled when `options.tokens` is true |
375
376**Example**
377
378```js
379const picomatch = require('picomatch');
380const result = picomatch.scan('!./foo/*.js', { tokens: true });
381console.log(result);
382// {
383// prefix: '!./',
384// input: '!./foo/*.js',
385// start: 3,
386// base: 'foo',
387// glob: '*.js',
388// isBrace: false,
389// isBracket: false,
390// isGlob: true,
391// isExtglob: false,
392// isGlobstar: false,
393// negated: true,
394// maxDepth: 2,
395// tokens: [
396// { value: '!./', depth: 0, isGlob: false, negated: true, isPrefix: true },
397// { value: 'foo', depth: 1, isGlob: false },
398// { value: '*.js', depth: 1, isGlob: true }
399// ],
400// slashes: [ 2, 6 ],
401// parts: [ 'foo', '*.js' ]
402// }
403```
404
405<br>
406
407### Options Examples
408
409#### options.expandRange
410
411**Type**: `function`
412
413**Default**: `undefined`
414
415Custom function for expanding ranges in brace patterns. The [fill-range](https://github.com/jonschlinkert/fill-range) library is ideal for this purpose, or you can use custom code to do whatever you need.
416
417**Example**
418
419The following example shows how to create a glob that matches a folder
420
421```js
422const fill = require('fill-range');
423const regex = pm.makeRe('foo/{01..25}/bar', {
424 expandRange(a, b) {
425 return `(${fill(a, b, { toRegex: true })})`;
426 }
427});
428
429console.log(regex);
430//=> /^(?:foo\/((?:0[1-9]|1[0-9]|2[0-5]))\/bar)$/
431
432console.log(regex.test('foo/00/bar')) // false
433console.log(regex.test('foo/01/bar')) // true
434console.log(regex.test('foo/10/bar')) // true
435console.log(regex.test('foo/22/bar')) // true
436console.log(regex.test('foo/25/bar')) // true
437console.log(regex.test('foo/26/bar')) // false
438```
439
440#### options.format
441
442**Type**: `function`
443
444**Default**: `undefined`
445
446Custom function for formatting strings before they're matched.
447
448**Example**
449
450```js
451// strip leading './' from strings
452const format = str => str.replace(/^\.\//, '');
453const isMatch = picomatch('foo/*.js', { format });
454console.log(isMatch('./foo/bar.js')); //=> true
455```
456
457#### options.onMatch
458
459```js
460const onMatch = ({ glob, regex, input, output }) => {
461 console.log({ glob, regex, input, output });
462};
463
464const isMatch = picomatch('*', { onMatch });
465isMatch('foo');
466isMatch('bar');
467isMatch('baz');
468```
469
470#### options.onIgnore
471
472```js
473const onIgnore = ({ glob, regex, input, output }) => {
474 console.log({ glob, regex, input, output });
475};
476
477const isMatch = picomatch('*', { onIgnore, ignore: 'f*' });
478isMatch('foo');
479isMatch('bar');
480isMatch('baz');
481```
482
483#### options.onResult
484
485```js
486const onResult = ({ glob, regex, input, output }) => {
487 console.log({ glob, regex, input, output });
488};
489
490const isMatch = picomatch('*', { onResult, ignore: 'f*' });
491isMatch('foo');
492isMatch('bar');
493isMatch('baz');
494```
495
496<br>
497<br>
498
499## Globbing features
500
501* [Basic globbing](#basic-globbing) (Wildcard matching)
502* [Advanced globbing](#advanced-globbing) (extglobs, posix brackets, brace matching)
503
504### Basic globbing
505
506| **Character** | **Description** |
507| --- | --- |
508| `*` | Matches any character zero or more times, excluding path separators. Does _not match_ path separators or hidden files or directories ("dotfiles"), unless explicitly enabled by setting the `dot` option to `true`. |
509| `**` | Matches any character zero or more times, including path separators. Note that `**` will only match path separators (`/`, and `\\` with the `windows` option) when they are the only characters in a path segment. Thus, `foo**/bar` is equivalent to `foo*/bar`, and `foo/a**b/bar` is equivalent to `foo/a*b/bar`, and _more than two_ consecutive stars in a glob path segment are regarded as _a single star_. Thus, `foo/***/bar` is equivalent to `foo/*/bar`. |
510| `?` | Matches any character excluding path separators one time. Does _not match_ path separators or leading dots. |
511| `[abc]` | Matches any characters inside the brackets. For example, `[abc]` would match the characters `a`, `b` or `c`, and nothing else. |
512
513#### Matching behavior vs. Bash
514
515Picomatch's matching features and expected results in unit tests are based on Bash's unit tests and the Bash 4.3 specification, with the following exceptions:
516
517* Bash will match `foo/bar/baz` with `*`. Picomatch only matches nested directories with `**`.
518* Bash greedily matches with negated extglobs. For example, Bash 4.3 says that `!(foo)*` should match `foo` and `foobar`, since the trailing `*` bracktracks to match the preceding pattern. This is very memory-inefficient, and IMHO, also incorrect. Picomatch would return `false` for both `foo` and `foobar`.
519
520<br>
521
522### Advanced globbing
523
524* [extglobs](#extglobs)
525* [POSIX brackets](#posix-brackets)
526* [Braces](#brace-expansion)
527
528#### Extglobs
529
530| **Pattern** | **Description** |
531| --- | --- |
532| `@(pattern)` | Match _only one_ consecutive occurrence of `pattern` |
533| `*(pattern)` | Match _zero or more_ consecutive occurrences of `pattern` |
534| `+(pattern)` | Match _one or more_ consecutive occurrences of `pattern` |
535| `?(pattern)` | Match _zero or **one**_ consecutive occurrences of `pattern` |
536| `!(pattern)` | Match _anything but_ `pattern` |
537
538**Examples**
539
540```js
541const pm = require('picomatch');
542
543// *(pattern) matches ZERO or more of "pattern"
544console.log(pm.isMatch('a', 'a*(z)')); // true
545console.log(pm.isMatch('az', 'a*(z)')); // true
546console.log(pm.isMatch('azzz', 'a*(z)')); // true
547
548// +(pattern) matches ONE or more of "pattern"
549console.log(pm.isMatch('a', 'a+(z)')); // false
550console.log(pm.isMatch('az', 'a+(z)')); // true
551console.log(pm.isMatch('azzz', 'a+(z)')); // true
552
553// supports multiple extglobs
554console.log(pm.isMatch('foo.bar', '!(foo).!(bar)')); // false
555
556// supports nested extglobs
557console.log(pm.isMatch('foo.bar', '!(!(foo)).!(!(bar))')); // true
558
559// risky quantified extglobs are treated literally by default
560console.log(pm.makeRe('+(a|aa)'));
561//=> /^(?:\+\(a\|aa\))$/
562
563// increase the limit to allow a small amount of nested quantified extglobs
564console.log(pm.isMatch('aaa', '+(+(a))', { maxExtglobRecursion: 1 })); // true
565```
566
567#### POSIX brackets
568
569POSIX classes are disabled by default. Enable this feature by setting the `posix` option to true.
570
571**Enable POSIX bracket support**
572
573```js
574console.log(pm.makeRe('[[:word:]]+', { posix: true }));
575//=> /^(?:(?=.)[A-Za-z0-9_]+\/?)$/
576```
577
578**Supported POSIX classes**
579
580The following named POSIX bracket expressions are supported:
581
582* `[:alnum:]` - Alphanumeric characters, equ `[a-zA-Z0-9]`
583* `[:alpha:]` - Alphabetical characters, equivalent to `[a-zA-Z]`.
584* `[:ascii:]` - ASCII characters, equivalent to `[\\x00-\\x7F]`.
585* `[:blank:]` - Space and tab characters, equivalent to `[ \\t]`.
586* `[:cntrl:]` - Control characters, equivalent to `[\\x00-\\x1F\\x7F]`.
587* `[:digit:]` - Numerical digits, equivalent to `[0-9]`.
588* `[:graph:]` - Graph characters, equivalent to `[\\x21-\\x7E]`.
589* `[:lower:]` - Lowercase letters, equivalent to `[a-z]`.
590* `[:print:]` - Print characters, equivalent to `[\\x20-\\x7E ]`.
591* `[:punct:]` - Punctuation and symbols, equivalent to `[\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~]`.
592* `[:space:]` - Extended space characters, equivalent to `[ \\t\\r\\n\\v\\f]`.
593* `[:upper:]` - Uppercase letters, equivalent to `[A-Z]`.
594* `[:word:]` - Word characters (letters, numbers and underscores), equivalent to `[A-Za-z0-9_]`.
595* `[:xdigit:]` - Hexadecimal digits, equivalent to `[A-Fa-f0-9]`.
596
597See the [Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html) for more information.
598
599### Braces
600
601Picomatch only does [brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html) of comma-delimited lists (e.g. `a/{b,c}/d`). For advanced matching with braces, use [micromatch](https://github.com/micromatch/micromatch), which supports advanced syntax such as ranges (e.g. `{01..03}`) and increments (e.g. `{2..10..2}`).
602
603### Matching special characters as literals
604
605If you wish to match the following special characters in a filepath, and you want to use these characters in your glob pattern, they must be escaped with backslashes or quotes:
606
607**Special Characters**
608
609Some characters that are used for matching in regular expressions are also regarded as valid file path characters on some platforms.
610
611To match any of the following characters as literals: `$^*+?()[]
612
613Examples:
614
615```js
616console.log(pm.makeRe('foo/bar \\(1\\)'));
617console.log(pm.makeRe('foo/bar \\(1\\)'));
618```
619
620<br>
621<br>
622
623## Library Comparisons
624
625The following table shows which features are supported by [minimatch](https://github.com/isaacs/minimatch), [micromatch](https://github.com/micromatch/micromatch), [picomatch](https://github.com/micromatch/picomatch), [nanomatch](https://github.com/micromatch/nanomatch), [extglob](https://github.com/micromatch/extglob), [braces](https://github.com/micromatch/braces), and [expand-brackets](https://github.com/micromatch/expand-brackets).
626
627| **Feature** | `minimatch` | `micromatch` | `picomatch` | `nanomatch` | `extglob` | `braces` | `expand-brackets` |
628| --- | --- | --- | --- | --- | --- | --- | --- |
629| Wildcard matching (`*?+`) | ✔ | ✔ | ✔ | ✔ | - | - | - |
630| Advancing globbing | ✔ | ✔ | ✔ | - | - | - | - |
631| Brace _matching_ | ✔ | ✔ | ✔ | - | - | ✔ | - |
632| Brace _expansion_ | ✔ | ✔ | - | - | - | ✔ | - |
633| Extglobs | partial | ✔ | ✔ | - | ✔ | - | - |
634| Posix brackets | - | ✔ | ✔ | - | - | - | ✔ |
635| Regular expression syntax | - | ✔ | ✔ | ✔ | ✔ | - | ✔ |
636| File system operations | - | - | - | - | - | - | - |
637
638<br>
639<br>
640
641## Benchmarks
642
643Performance comparison of picomatch and minimatch.
644
645```
646# .makeRe star (*)
647 picomatch x 3,251,247 ops/sec ±0.25% (95 runs sampled)
648 minimatch x 497,224 ops/sec ±0.11% (100 runs sampled)
649
650# .makeRe star; dot=true (*)
651 picomatch x 2,624,035 ops/sec ±0.16% (98 runs sampled)
652 minimatch x 446,244 ops/sec ±0.63% (99 runs sampled)
653
654# .makeRe globstar (**)
655 picomatch x 2,524,465 ops/sec ±0.13% (99 runs sampled)
656 minimatch x 1,396,257 ops/sec ±0.58% (96 runs sampled)
657
658# .makeRe globstars (**/**/**)
659 picomatch x 2,545,674 ops/sec ±0.10% (99 runs sampled)
660 minimatch x 1,196,835 ops/sec ±0.63% (98 runs sampled)
661
662# .makeRe with leading star (*.txt)
663 picomatch x 2,537,708 ops/sec ±0.11% (100 runs sampled)
664 minimatch x 345,284 ops/sec ±0.64% (96 runs sampled)
665
666# .makeRe - basic braces ({a,b,c}*.txt)
667 picomatch x 505,430 ops/sec ±1.04% (94 runs sampled)
668 minimatch x 107,991 ops/sec ±0.54% (99 runs sampled)
669
670# .makeRe - short ranges ({a..z}*.txt)
671 picomatch x 371,179 ops/sec ±2.91% (77 runs sampled)
672 minimatch x 14,104 ops/sec ±0.61% (99 runs sampled)
673
674# .makeRe - medium ranges ({1..100000}*.txt)
675 picomatch x 384,958 ops/sec ±1.70% (82 runs sampled)
676 minimatch x 2.55 ops/sec ±3.22% (11 runs sampled)
677
678# .makeRe - long ranges ({1..10000000}*.txt)
679 picomatch x 382,552 ops/sec ±1.52% (71 runs sampled)
680 minimatch x 0.83 ops/sec ±5.67% (7 runs sampled))
681```
682
683<br>
684<br>
685
686## Philosophies
687
688The goal of this library is to be blazing fast, without compromising on accuracy.
689
690**Accuracy**
691
692The number one of goal of this library is accuracy. However, it's not unusual for different glob implementations to have different rules for matching behavior, even with simple wildcard matching. It gets increasingly more complicated when combinations of different features are combined, like when extglobs are combined with globstars, braces, slashes, and so on: `!(**/{a,b,*/c})`.
693
694Thus, given that there is no canonical glob specification to use as a single source of truth when differences of opinion arise regarding behavior, sometimes we have to implement our best judgement and rely on feedback from users to make improvements.
695
696**Performance**
697
698Although this library performs well in benchmarks, and in most cases it's faster than other popular libraries we benchmarked against, we will always choose accuracy over performance. It's not helpful to anyone if our library is faster at returning the wrong answer.
699
700<br>
701<br>
702
703## About
704
705<details>
706<summary><strong>Contributing</strong></summary>
707
708Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
709
710Please read the [contributing guide](.github/contributing.md) for advice on opening issues, pull requests, and coding standards.
711
712</details>
713
714<details>
715<summary><strong>Running Tests</strong></summary>
716
717Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
718
719```sh
720npm install && npm test
721```
722
723</details>
724
725<details>
726<summary><strong>Building docs</strong></summary>
727
728_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
729
730To generate the readme, run the following command:
731
732```sh
733npm install -g verbose/verb#dev verb-generate-readme && verb
734```
735
736</details>
737
738### Author
739
740**Jon Schlinkert**
741
742* [GitHub Profile](https://github.com/jonschlinkert)
743* [Twitter Profile](https://twitter.com/jonschlinkert)
744* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
745
746### License
747
748Copyright © 2017-present, [Jon Schlinkert](https://github.com/jonschlinkert).
749Released under the [MIT License](LICENSE).
node_modules/picomatch/index.js +17 -0
……@@ -0,0 +1,17 @@
1'use strict';
2
3const pico = require('./lib/picomatch');
4const utils = require('./lib/utils');
5
6function picomatch(glob, options, returnState = false) {
7 // default to os.platform()
8 if (options && (options.windows === null || options.windows === undefined)) {
9 // don't mutate the original options object
10 options = { ...options, windows: utils.isWindows() };
11 }
12
13 return pico(glob, options, returnState);
14}
15
16Object.assign(picomatch, pico);
17module.exports = picomatch;
node_modules/picomatch/lib/constants.js +184 -0
……@@ -0,0 +1,184 @@
1'use strict';
2
3const WIN_SLASH = '\\\\/';
4const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
5
6const DEFAULT_MAX_EXTGLOB_RECURSION = 0;
7
8/**
9 * Posix glob regex
10 */
11
12const DOT_LITERAL = '\\.';
13const PLUS_LITERAL = '\\+';
14const QMARK_LITERAL = '\\?';
15const SLASH_LITERAL = '\\/';
16const ONE_CHAR = '(?=.)';
17const QMARK = '[^/]';
18const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`;
19const START_ANCHOR = `(?:^|${SLASH_LITERAL})`;
20const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`;
21const NO_DOT = `(?!${DOT_LITERAL})`;
22const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`;
23const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`;
24const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`;
25const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`;
26const STAR = `${QMARK}*?`;
27const SEP = '/';
28
29const POSIX_CHARS = {
30 DOT_LITERAL,
31 PLUS_LITERAL,
32 QMARK_LITERAL,
33 SLASH_LITERAL,
34 ONE_CHAR,
35 QMARK,
36 END_ANCHOR,
37 DOTS_SLASH,
38 NO_DOT,
39 NO_DOTS,
40 NO_DOT_SLASH,
41 NO_DOTS_SLASH,
42 QMARK_NO_DOT,
43 STAR,
44 START_ANCHOR,
45 SEP
46};
47
48/**
49 * Windows glob regex
50 */
51
52const WINDOWS_CHARS = {
53 ...POSIX_CHARS,
54
55 SLASH_LITERAL: `[${WIN_SLASH}]`,
56 QMARK: WIN_NO_SLASH,
57 STAR: `${WIN_NO_SLASH}*?`,
58 DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`,
59 NO_DOT: `(?!${DOT_LITERAL})`,
60 NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
61 NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`,
62 NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
63 QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
64 START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
65 END_ANCHOR: `(?:[${WIN_SLASH}]|$)`,
66 SEP: '\\'
67};
68
69/**
70 * POSIX Bracket Regex
71 */
72
73const POSIX_REGEX_SOURCE = {
74 __proto__: null,
75 alnum: 'a-zA-Z0-9',
76 alpha: 'a-zA-Z',
77 ascii: '\\x00-\\x7F',
78 blank: ' \\t',
79 cntrl: '\\x00-\\x1F\\x7F',
80 digit: '0-9',
81 graph: '\\x21-\\x7E',
82 lower: 'a-z',
83 print: '\\x20-\\x7E ',
84 punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~',
85 space: ' \\t\\r\\n\\v\\f',
86 upper: 'A-Z',
87 word: 'A-Za-z0-9_',
88 xdigit: 'A-Fa-f0-9'
89};
90
91module.exports = {
92 DEFAULT_MAX_EXTGLOB_RECURSION,
93 MAX_LENGTH: 1024 * 64,
94 POSIX_REGEX_SOURCE,
95
96 // regular expressions
97 REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g,
98 REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/,
99 REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/,
100 REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g,
101 REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g,
102 REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g,
103
104 // Replace globs with equivalent patterns to reduce parsing time.
105 REPLACEMENTS: {
106 __proto__: null,
107 '***': '*',
108 '**/**': '**',
109 '**/**/**': '**'
110 },
111
112 // Digits
113 CHAR_0: 48, /* 0 */
114 CHAR_9: 57, /* 9 */
115
116 // Alphabet chars.
117 CHAR_UPPERCASE_A: 65, /* A */
118 CHAR_LOWERCASE_A: 97, /* a */
119 CHAR_UPPERCASE_Z: 90, /* Z */
120 CHAR_LOWERCASE_Z: 122, /* z */
121
122 CHAR_LEFT_PARENTHESES: 40, /* ( */
123 CHAR_RIGHT_PARENTHESES: 41, /* ) */
124
125 CHAR_ASTERISK: 42, /* * */
126
127 // Non-alphabetic chars.
128 CHAR_AMPERSAND: 38, /* & */
129 CHAR_AT: 64, /* @ */
130 CHAR_BACKWARD_SLASH: 92, /* \ */
131 CHAR_CARRIAGE_RETURN: 13, /* \r */
132 CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */
133 CHAR_COLON: 58, /* : */
134 CHAR_COMMA: 44, /* , */
135 CHAR_DOT: 46, /* . */
136 CHAR_DOUBLE_QUOTE: 34, /* " */
137 CHAR_EQUAL: 61, /* = */
138 CHAR_EXCLAMATION_MARK: 33, /* ! */
139 CHAR_FORM_FEED: 12, /* \f */
140 CHAR_FORWARD_SLASH: 47, /* / */
141 CHAR_GRAVE_ACCENT: 96, /* ` */
142 CHAR_HASH: 35, /* # */
143 CHAR_HYPHEN_MINUS: 45, /* - */
144 CHAR_LEFT_ANGLE_BRACKET: 60, /* < */
145 CHAR_LEFT_CURLY_BRACE: 123, /* { */
146 CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */
147 CHAR_LINE_FEED: 10, /* \n */
148 CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */
149 CHAR_PERCENT: 37, /* % */
150 CHAR_PLUS: 43, /* + */
151 CHAR_QUESTION_MARK: 63, /* ? */
152 CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */
153 CHAR_RIGHT_CURLY_BRACE: 125, /* } */
154 CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */
155 CHAR_SEMICOLON: 59, /* ; */
156 CHAR_SINGLE_QUOTE: 39, /* ' */
157 CHAR_SPACE: 32, /* */
158 CHAR_TAB: 9, /* \t */
159 CHAR_UNDERSCORE: 95, /* _ */
160 CHAR_VERTICAL_LINE: 124, /* | */
161 CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */
162
163 /**
164 * Create EXTGLOB_CHARS
165 */
166
167 extglobChars(chars) {
168 return {
169 '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` },
170 '?': { type: 'qmark', open: '(?:', close: ')?' },
171 '+': { type: 'plus', open: '(?:', close: ')+' },
172 '*': { type: 'star', open: '(?:', close: ')*' },
173 '@': { type: 'at', open: '(?:', close: ')' }
174 };
175 },
176
177 /**
178 * Create GLOB_CHARS
179 */
180
181 globChars(win32) {
182 return win32 === true ? WINDOWS_CHARS : POSIX_CHARS;
183 }
184};
node_modules/picomatch/lib/parse.js +1386 -0
……@@ -0,0 +1,1386 @@
1'use strict';
2
3const constants = require('./constants');
4const utils = require('./utils');
5
6/**
7 * Constants
8 */
9
10const {
11 MAX_LENGTH,
12 POSIX_REGEX_SOURCE,
13 REGEX_NON_SPECIAL_CHARS,
14 REGEX_SPECIAL_CHARS_BACKREF,
15 REPLACEMENTS
16} = constants;
17
18/**
19 * Helpers
20 */
21
22const expandRange = (args, options) => {
23 if (typeof options.expandRange === 'function') {
24 return options.expandRange(...args, options);
25 }
26
27 args.sort();
28 const value = `[${args.join('-')}]`;
29
30 try {
31 /* eslint-disable-next-line no-new */
32 new RegExp(value);
33 } catch (ex) {
34 return args.map(v => utils.escapeRegex(v)).join('..');
35 }
36
37 return value;
38};
39
40/**
41 * Create the message for a syntax error
42 */
43
44const syntaxError = (type, char) => {
45 return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
46};
47
48const splitTopLevel = input => {
49 const parts = [];
50 let bracket = 0;
51 let paren = 0;
52 let quote = 0;
53 let value = '';
54 let escaped = false;
55
56 for (const ch of input) {
57 if (escaped === true) {
58 value += ch;
59 escaped = false;
60 continue;
61 }
62
63 if (ch === '\\') {
64 value += ch;
65 escaped = true;
66 continue;
67 }
68
69 if (ch === '"') {
70 quote = quote === 1 ? 0 : 1;
71 value += ch;
72 continue;
73 }
74
75 if (quote === 0) {
76 if (ch === '[') {
77 bracket++;
78 } else if (ch === ']' && bracket > 0) {
79 bracket--;
80 } else if (bracket === 0) {
81 if (ch === '(') {
82 paren++;
83 } else if (ch === ')' && paren > 0) {
84 paren--;
85 } else if (ch === '|' && paren === 0) {
86 parts.push(value);
87 value = '';
88 continue;
89 }
90 }
91 }
92
93 value += ch;
94 }
95
96 parts.push(value);
97 return parts;
98};
99
100const isPlainBranch = branch => {
101 let escaped = false;
102
103 for (const ch of branch) {
104 if (escaped === true) {
105 escaped = false;
106 continue;
107 }
108
109 if (ch === '\\') {
110 escaped = true;
111 continue;
112 }
113
114 if (/[?*+@!()[\]{}]/.test(ch)) {
115 return false;
116 }
117 }
118
119 return true;
120};
121
122const normalizeSimpleBranch = branch => {
123 let value = branch.trim();
124 let changed = true;
125
126 while (changed === true) {
127 changed = false;
128
129 if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
130 value = value.slice(2, -1);
131 changed = true;
132 }
133 }
134
135 if (!isPlainBranch(value)) {
136 return;
137 }
138
139 return value.replace(/\\(.)/g, '$1');
140};
141
142const hasRepeatedCharPrefixOverlap = branches => {
143 const values = branches.map(normalizeSimpleBranch).filter(Boolean);
144
145 for (let i = 0; i < values.length; i++) {
146 for (let j = i + 1; j < values.length; j++) {
147 const a = values[i];
148 const b = values[j];
149 const char = a[0];
150
151 if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) {
152 continue;
153 }
154
155 if (a === b || a.startsWith(b) || b.startsWith(a)) {
156 return true;
157 }
158 }
159 }
160
161 return false;
162};
163
164const parseRepeatedExtglob = (pattern, requireEnd = true) => {
165 if ((pattern[0] !== '+' && pattern[0] !== '*') || pattern[1] !== '(') {
166 return;
167 }
168
169 let bracket = 0;
170 let paren = 0;
171 let quote = 0;
172 let escaped = false;
173
174 for (let i = 1; i < pattern.length; i++) {
175 const ch = pattern[i];
176
177 if (escaped === true) {
178 escaped = false;
179 continue;
180 }
181
182 if (ch === '\\') {
183 escaped = true;
184 continue;
185 }
186
187 if (ch === '"') {
188 quote = quote === 1 ? 0 : 1;
189 continue;
190 }
191
192 if (quote === 1) {
193 continue;
194 }
195
196 if (ch === '[') {
197 bracket++;
198 continue;
199 }
200
201 if (ch === ']' && bracket > 0) {
202 bracket--;
203 continue;
204 }
205
206 if (bracket > 0) {
207 continue;
208 }
209
210 if (ch === '(') {
211 paren++;
212 continue;
213 }
214
215 if (ch === ')') {
216 paren--;
217
218 if (paren === 0) {
219 if (requireEnd === true && i !== pattern.length - 1) {
220 return;
221 }
222
223 return {
224 type: pattern[0],
225 body: pattern.slice(2, i),
226 end: i
227 };
228 }
229 }
230 }
231};
232
233const getStarExtglobSequenceOutput = pattern => {
234 let index = 0;
235 const chars = [];
236
237 while (index < pattern.length) {
238 const match = parseRepeatedExtglob(pattern.slice(index), false);
239
240 if (!match || match.type !== '*') {
241 return;
242 }
243
244 const branches = splitTopLevel(match.body).map(branch => branch.trim());
245 if (branches.length !== 1) {
246 return;
247 }
248
249 const branch = normalizeSimpleBranch(branches[0]);
250 if (!branch || branch.length !== 1) {
251 return;
252 }
253
254 chars.push(branch);
255 index += match.end + 1;
256 }
257
258 if (chars.length < 1) {
259 return;
260 }
261
262 const source = chars.length === 1
263 ? utils.escapeRegex(chars[0])
264 : `[${chars.map(ch => utils.escapeRegex(ch)).join('')}]`;
265
266 return `${source}*`;
267};
268
269const repeatedExtglobRecursion = pattern => {
270 let depth = 0;
271 let value = pattern.trim();
272 let match = parseRepeatedExtglob(value);
273
274 while (match) {
275 depth++;
276 value = match.body.trim();
277 match = parseRepeatedExtglob(value);
278 }
279
280 return depth;
281};
282
283const analyzeRepeatedExtglob = (body, options) => {
284 if (options.maxExtglobRecursion === false) {
285 return { risky: false };
286 }
287
288 const max =
289 typeof options.maxExtglobRecursion === 'number'
290 ? options.maxExtglobRecursion
291 : constants.DEFAULT_MAX_EXTGLOB_RECURSION;
292
293 const branches = splitTopLevel(body).map(branch => branch.trim());
294
295 if (branches.length > 1) {
296 if (
297 branches.some(branch => branch === '') ||
298 branches.some(branch => /^[*?]+$/.test(branch)) ||
299 hasRepeatedCharPrefixOverlap(branches)
300 ) {
301 return { risky: true };
302 }
303 }
304
305 for (const branch of branches) {
306 const safeOutput = getStarExtglobSequenceOutput(branch);
307 if (safeOutput) {
308 return { risky: true, safeOutput };
309 }
310
311 if (repeatedExtglobRecursion(branch) > max) {
312 return { risky: true };
313 }
314 }
315
316 return { risky: false };
317};
318
319/**
320 * Parse the given input string.
321 * @param {String} input
322 * @param {Object} options
323 * @return {Object}
324 */
325
326const parse = (input, options) => {
327 if (typeof input !== 'string') {
328 throw new TypeError('Expected a string');
329 }
330
331 input = REPLACEMENTS[input] || input;
332
333 const opts = { ...options };
334 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
335
336 let len = input.length;
337 if (len > max) {
338 throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
339 }
340
341 const bos = { type: 'bos', value: '', output: opts.prepend || '' };
342 const tokens = [bos];
343
344 const capture = opts.capture ? '' : '?:';
345
346 // create constants based on platform, for windows or posix
347 const PLATFORM_CHARS = constants.globChars(opts.windows);
348 const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);
349
350 const {
351 DOT_LITERAL,
352 PLUS_LITERAL,
353 SLASH_LITERAL,
354 ONE_CHAR,
355 DOTS_SLASH,
356 NO_DOT,
357 NO_DOT_SLASH,
358 NO_DOTS_SLASH,
359 QMARK,
360 QMARK_NO_DOT,
361 STAR,
362 START_ANCHOR
363 } = PLATFORM_CHARS;
364
365 const globstar = opts => {
366 return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
367 };
368
369 const nodot = opts.dot ? '' : NO_DOT;
370 const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
371 let star = opts.bash === true ? globstar(opts) : STAR;
372
373 if (opts.capture) {
374 star = `(${star})`;
375 }
376
377 // minimatch options support
378 if (typeof opts.noext === 'boolean') {
379 opts.noextglob = opts.noext;
380 }
381
382 const state = {
383 input,
384 index: -1,
385 start: 0,
386 dot: opts.dot === true,
387 consumed: '',
388 output: '',
389 prefix: '',
390 backtrack: false,
391 negated: false,
392 brackets: 0,
393 braces: 0,
394 parens: 0,
395 quotes: 0,
396 globstar: false,
397 tokens
398 };
399
400 input = utils.removePrefix(input, state);
401 len = input.length;
402
403 const extglobs = [];
404 const braces = [];
405 const stack = [];
406 let prev = bos;
407 let value;
408
409 /**
410 * Tokenizing helpers
411 */
412
413 const eos = () => state.index === len - 1;
414 const peek = state.peek = (n = 1) => input[state.index + n];
415 const advance = state.advance = () => input[++state.index] || '';
416 const remaining = () => input.slice(state.index + 1);
417 const consume = (value = '', num = 0) => {
418 state.consumed += value;
419 state.index += num;
420 };
421
422 const append = token => {
423 state.output += token.output != null ? token.output : token.value;
424 consume(token.value);
425 };
426
427 const negate = () => {
428 let count = 1;
429
430 while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) {
431 advance();
432 state.start++;
433 count++;
434 }
435
436 if (count % 2 === 0) {
437 return false;
438 }
439
440 state.negated = true;
441 state.start++;
442 return true;
443 };
444
445 const increment = type => {
446 state[type]++;
447 stack.push(type);
448 };
449
450 const decrement = type => {
451 state[type]--;
452 stack.pop();
453 };
454
455 /**
456 * Push tokens onto the tokens array. This helper speeds up
457 * tokenizing by 1) helping us avoid backtracking as much as possible,
458 * and 2) helping us avoid creating extra tokens when consecutive
459 * characters are plain text. This improves performance and simplifies
460 * lookbehinds.
461 */
462
463 const push = tok => {
464 if (prev.type === 'globstar') {
465 const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace');
466 const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren'));
467
468 if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) {
469 state.output = state.output.slice(0, -prev.output.length);
470 prev.type = 'star';
471 prev.value = '*';
472 prev.output = star;
473 state.output += prev.output;
474 }
475 }
476
477 if (extglobs.length && tok.type !== 'paren') {
478 extglobs[extglobs.length - 1].inner += tok.value;
479 }
480
481 if (tok.value || tok.output) append(tok);
482 if (prev && prev.type === 'text' && tok.type === 'text') {
483 prev.output = (prev.output || prev.value) + tok.value;
484 prev.value += tok.value;
485 return;
486 }
487
488 tok.prev = prev;
489 tokens.push(tok);
490 prev = tok;
491 };
492
493 const extglobOpen = (type, value) => {
494 const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' };
495
496 token.prev = prev;
497 token.parens = state.parens;
498 token.output = state.output;
499 token.startIndex = state.index;
500 token.tokensIndex = tokens.length;
501 const output = (opts.capture ? '(' : '') + token.open;
502
503 increment('parens');
504 push({ type, value, output: state.output ? '' : ONE_CHAR });
505 push({ type: 'paren', extglob: true, value: advance(), output });
506 extglobs.push(token);
507 };
508
509 const extglobClose = token => {
510 const literal = input.slice(token.startIndex, state.index + 1);
511 const body = input.slice(token.startIndex + 2, state.index);
512 const analysis = analyzeRepeatedExtglob(body, opts);
513
514 if ((token.type === 'plus' || token.type === 'star') && analysis.risky) {
515 const safeOutput = analysis.safeOutput
516 ? (token.output ? '' : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput)
517 : undefined;
518 const open = tokens[token.tokensIndex];
519
520 open.type = 'text';
521 open.value = literal;
522 open.output = safeOutput || utils.escapeRegex(literal);
523
524 for (let i = token.tokensIndex + 1; i < tokens.length; i++) {
525 tokens[i].value = '';
526 tokens[i].output = '';
527 delete tokens[i].suffix;
528 }
529
530 state.output = token.output + open.output;
531 state.backtrack = true;
532
533 push({ type: 'paren', extglob: true, value, output: '' });
534 decrement('parens');
535 return;
536 }
537
538 let output = token.close + (opts.capture ? ')' : '');
539 let rest;
540
541 if (token.type === 'negate') {
542 let extglobStar = star;
543
544 if (token.inner && token.inner.length > 1 && token.inner.includes('/')) {
545 extglobStar = globstar(opts);
546 }
547
548 if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) {
549 output = token.close = `)$))${extglobStar}`;
550 }
551
552 if (token.inner.includes('*') && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
553 // Any non-magical string (`.ts`) or even nested expression (`.{ts,tsx}`) can follow after the closing parenthesis.
554 // In this case, we need to parse the string and use it in the output of the original pattern.
555 // Suitable patterns: `/!(*.d).ts`, `/!(*.d).{ts,tsx}`, `**/!(*-dbg).@(js)`.
556 //
557 // Disabling the `fastpaths` option due to a problem with parsing strings as `.ts` in the pattern like `**/!(*.d).ts`.
558 const expression = parse(rest, { ...options, fastpaths: false }).output;
559
560 output = token.close = `)${expression})${extglobStar})`;
561 }
562
563 if (token.prev.type === 'bos') {
564 state.negatedExtglob = true;
565 }
566 }
567
568 push({ type: 'paren', extglob: true, value, output });
569 decrement('parens');
570 };
571
572 /**
573 * Fast paths
574 */
575
576 if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) {
577 let backslashes = false;
578
579 let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => {
580 if (first === '\\') {
581 backslashes = true;
582 return m;
583 }
584
585 if (first === '?') {
586 if (esc) {
587 return esc + first + (rest ? QMARK.repeat(rest.length) : '');
588 }
589 if (index === 0) {
590 return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : '');
591 }
592 return QMARK.repeat(chars.length);
593 }
594
595 if (first === '.') {
596 return DOT_LITERAL.repeat(chars.length);
597 }
598
599 if (first === '*') {
600 if (esc) {
601 return esc + first + (rest ? star : '');
602 }
603 return star;
604 }
605 return esc ? m : `\\${m}`;
606 });
607
608 if (backslashes === true) {
609 if (opts.unescape === true) {
610 output = output.replace(/\\/g, '');
611 } else {
612 output = output.replace(/\\+/g, m => {
613 return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : '');
614 });
615 }
616 }
617
618 if (output === input && opts.contains === true) {
619 state.output = input;
620 return state;
621 }
622
623 state.output = utils.wrapOutput(output, state, options);
624 return state;
625 }
626
627 /**
628 * Tokenize input until we reach end-of-string
629 */
630
631 while (!eos()) {
632 value = advance();
633
634 if (value === '\u0000') {
635 continue;
636 }
637
638 /**
639 * Escaped characters
640 */
641
642 if (value === '\\') {
643 const next = peek();
644
645 if (next === '/' && opts.bash !== true) {
646 continue;
647 }
648
649 if (next === '.' || next === ';') {
650 continue;
651 }
652
653 if (!next) {
654 value += '\\';
655 push({ type: 'text', value });
656 continue;
657 }
658
659 // collapse slashes to reduce potential for exploits
660 const match = /^\\+/.exec(remaining());
661 let slashes = 0;
662
663 if (match && match[0].length > 2) {
664 slashes = match[0].length;
665 state.index += slashes;
666 if (slashes % 2 !== 0) {
667 value += '\\';
668 }
669 }
670
671 if (opts.unescape === true) {
672 value = advance();
673 } else {
674 value += advance();
675 }
676
677 if (state.brackets === 0) {
678 push({ type: 'text', value });
679 continue;
680 }
681 }
682
683 /**
684 * If we're inside a regex character class, continue
685 * until we reach the closing bracket.
686 */
687
688 if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) {
689 if (opts.posix !== false && value === ':') {
690 const inner = prev.value.slice(1);
691 if (inner.includes('[')) {
692 prev.posix = true;
693
694 if (inner.includes(':')) {
695 const idx = prev.value.lastIndexOf('[');
696 const pre = prev.value.slice(0, idx);
697 const rest = prev.value.slice(idx + 2);
698 const posix = POSIX_REGEX_SOURCE[rest];
699 if (posix) {
700 prev.value = pre + posix;
701 state.backtrack = true;
702 advance();
703
704 if (!bos.output && tokens.indexOf(prev) === 1) {
705 bos.output = ONE_CHAR;
706 }
707 continue;
708 }
709 }
710 }
711 }
712
713 if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) {
714 value = `\\${value}`;
715 }
716
717 if (value === ']' && (prev.value === '[' || prev.value === '[^')) {
718 value = `\\${value}`;
719 }
720
721 if (opts.posix === true && value === '!' && prev.value === '[') {
722 value = '^';
723 }
724
725 prev.value += value;
726 append({ value });
727 continue;
728 }
729
730 /**
731 * If we're inside a quoted string, continue
732 * until we reach the closing double quote.
733 */
734
735 if (state.quotes === 1 && value !== '"') {
736 value = utils.escapeRegex(value);
737 prev.value += value;
738 append({ value });
739 continue;
740 }
741
742 /**
743 * Double quotes
744 */
745
746 if (value === '"') {
747 state.quotes = state.quotes === 1 ? 0 : 1;
748 if (opts.keepQuotes === true) {
749 push({ type: 'text', value });
750 }
751 continue;
752 }
753
754 /**
755 * Parentheses
756 */
757
758 if (value === '(') {
759 increment('parens');
760 push({ type: 'paren', value });
761 continue;
762 }
763
764 if (value === ')') {
765 if (state.parens === 0 && opts.strictBrackets === true) {
766 throw new SyntaxError(syntaxError('opening', '('));
767 }
768
769 const extglob = extglobs[extglobs.length - 1];
770 if (extglob && state.parens === extglob.parens + 1) {
771 extglobClose(extglobs.pop());
772 continue;
773 }
774
775 push({ type: 'paren', value, output: state.parens ? ')' : '\\)' });
776 decrement('parens');
777 continue;
778 }
779
780 /**
781 * Square brackets
782 */
783
784 if (value === '[') {
785 if (opts.nobracket === true || !remaining().includes(']')) {
786 if (opts.nobracket !== true && opts.strictBrackets === true) {
787 throw new SyntaxError(syntaxError('closing', ']'));
788 }
789
790 value = `\\${value}`;
791 } else {
792 increment('brackets');
793 }
794
795 push({ type: 'bracket', value });
796 continue;
797 }
798
799 if (value === ']') {
800 if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) {
801 push({ type: 'text', value, output: `\\${value}` });
802 continue;
803 }
804
805 if (state.brackets === 0) {
806 if (opts.strictBrackets === true) {
807 throw new SyntaxError(syntaxError('opening', '['));
808 }
809
810 push({ type: 'text', value, output: `\\${value}` });
811 continue;
812 }
813
814 decrement('brackets');
815
816 const prevValue = prev.value.slice(1);
817 if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) {
818 value = `/${value}`;
819 }
820
821 prev.value += value;
822 append({ value });
823
824 // when literal brackets are explicitly disabled
825 // assume we should match with a regex character class
826 if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) {
827 continue;
828 }
829
830 const escaped = utils.escapeRegex(prev.value);
831 state.output = state.output.slice(0, -prev.value.length);
832
833 // when literal brackets are explicitly enabled
834 // assume we should escape the brackets to match literal characters
835 if (opts.literalBrackets === true) {
836 state.output += escaped;
837 prev.value = escaped;
838 continue;
839 }
840
841 // when the user specifies nothing, try to match both
842 prev.value = `(${capture}${escaped}|${prev.value})`;
843 state.output += prev.value;
844 continue;
845 }
846
847 /**
848 * Braces
849 */
850
851 if (value === '{' && opts.nobrace !== true) {
852 increment('braces');
853
854 const open = {
855 type: 'brace',
856 value,
857 output: '(',
858 outputIndex: state.output.length,
859 tokensIndex: state.tokens.length
860 };
861
862 braces.push(open);
863 push(open);
864 continue;
865 }
866
867 if (value === '}') {
868 const brace = braces[braces.length - 1];
869
870 if (opts.nobrace === true || !brace) {
871 push({ type: 'text', value, output: value });
872 continue;
873 }
874
875 let output = ')';
876
877 if (brace.dots === true) {
878 const arr = tokens.slice();
879 const range = [];
880
881 for (let i = arr.length - 1; i >= 0; i--) {
882 tokens.pop();
883 if (arr[i].type === 'brace') {
884 break;
885 }
886 if (arr[i].type !== 'dots') {
887 range.unshift(arr[i].value);
888 }
889 }
890
891 output = expandRange(range, opts);
892 state.backtrack = true;
893 }
894
895 if (brace.comma !== true && brace.dots !== true) {
896 const out = state.output.slice(0, brace.outputIndex);
897 const toks = state.tokens.slice(brace.tokensIndex);
898 brace.value = brace.output = '\\{';
899 value = output = '\\}';
900 state.output = out;
901 for (const t of toks) {
902 state.output += (t.output || t.value);
903 }
904 }
905
906 push({ type: 'brace', value, output });
907 decrement('braces');
908 braces.pop();
909 continue;
910 }
911
912 /**
913 * Pipes
914 */
915
916 if (value === '|') {
917 if (extglobs.length > 0) {
918 extglobs[extglobs.length - 1].conditions++;
919 }
920 push({ type: 'text', value });
921 continue;
922 }
923
924 /**
925 * Commas
926 */
927
928 if (value === ',') {
929 let output = value;
930
931 const brace = braces[braces.length - 1];
932 if (brace && stack[stack.length - 1] === 'braces') {
933 brace.comma = true;
934 output = '|';
935 }
936
937 push({ type: 'comma', value, output });
938 continue;
939 }
940
941 /**
942 * Slashes
943 */
944
945 if (value === '/') {
946 // if the beginning of the glob is "./", advance the start
947 // to the current index, and don't add the "./" characters
948 // to the state. This greatly simplifies lookbehinds when
949 // checking for BOS characters like "!" and "." (not "./")
950 if (prev.type === 'dot' && state.index === state.start + 1) {
951 state.start = state.index + 1;
952 state.consumed = '';
953 state.output = '';
954 tokens.pop();
955 prev = bos; // reset "prev" to the first token
956 continue;
957 }
958
959 push({ type: 'slash', value, output: SLASH_LITERAL });
960 continue;
961 }
962
963 /**
964 * Dots
965 */
966
967 if (value === '.') {
968 if (state.braces > 0 && prev.type === 'dot') {
969 if (prev.value === '.') prev.output = DOT_LITERAL;
970 const brace = braces[braces.length - 1];
971 prev.type = 'dots';
972 prev.output += value;
973 prev.value += value;
974 brace.dots = true;
975 continue;
976 }
977
978 if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') {
979 push({ type: 'text', value, output: DOT_LITERAL });
980 continue;
981 }
982
983 push({ type: 'dot', value, output: DOT_LITERAL });
984 continue;
985 }
986
987 /**
988 * Question marks
989 */
990
991 if (value === '?') {
992 const isGroup = prev && prev.value === '(';
993 if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
994 extglobOpen('qmark', value);
995 continue;
996 }
997
998 if (prev && prev.type === 'paren') {
999 const next = peek();
1000 let output = value;
1001
1002 if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) {
1003 output = `\\${value}`;
1004 }
1005
1006 push({ type: 'text', value, output });
1007 continue;
1008 }
1009
1010 if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) {
1011 push({ type: 'qmark', value, output: QMARK_NO_DOT });
1012 continue;
1013 }
1014
1015 push({ type: 'qmark', value, output: QMARK });
1016 continue;
1017 }
1018
1019 /**
1020 * Exclamation
1021 */
1022
1023 if (value === '!') {
1024 if (opts.noextglob !== true && peek() === '(') {
1025 if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) {
1026 extglobOpen('negate', value);
1027 continue;
1028 }
1029 }
1030
1031 if (opts.nonegate !== true && state.index === 0) {
1032 negate();
1033 continue;
1034 }
1035 }
1036
1037 /**
1038 * Plus
1039 */
1040
1041 if (value === '+') {
1042 if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
1043 extglobOpen('plus', value);
1044 continue;
1045 }
1046
1047 if ((prev && prev.value === '(') || opts.regex === false) {
1048 push({ type: 'plus', value, output: PLUS_LITERAL });
1049 continue;
1050 }
1051
1052 if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) {
1053 push({ type: 'plus', value });
1054 continue;
1055 }
1056
1057 push({ type: 'plus', value: PLUS_LITERAL });
1058 continue;
1059 }
1060
1061 /**
1062 * Plain text
1063 */
1064
1065 if (value === '@') {
1066 if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
1067 push({ type: 'at', extglob: true, value, output: '' });
1068 continue;
1069 }
1070
1071 push({ type: 'text', value });
1072 continue;
1073 }
1074
1075 /**
1076 * Plain text
1077 */
1078
1079 if (value !== '*') {
1080 if (value === '$' || value === '^') {
1081 value = `\\${value}`;
1082 }
1083
1084 const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
1085 if (match) {
1086 value += match[0];
1087 state.index += match[0].length;
1088 }
1089
1090 push({ type: 'text', value });
1091 continue;
1092 }
1093
1094 /**
1095 * Stars
1096 */
1097
1098 if (prev && (prev.type === 'globstar' || prev.star === true)) {
1099 prev.type = 'star';
1100 prev.star = true;
1101 prev.value += value;
1102 prev.output = star;
1103 state.backtrack = true;
1104 state.globstar = true;
1105 consume(value);
1106 continue;
1107 }
1108
1109 let rest = remaining();
1110 if (opts.noextglob !== true && /^\([^?]/.test(rest)) {
1111 extglobOpen('star', value);
1112 continue;
1113 }
1114
1115 if (prev.type === 'star') {
1116 if (opts.noglobstar === true) {
1117 consume(value);
1118 continue;
1119 }
1120
1121 const prior = prev.prev;
1122 const before = prior.prev;
1123 const isStart = prior.type === 'slash' || prior.type === 'bos';
1124 const afterStar = before && (before.type === 'star' || before.type === 'globstar');
1125
1126 if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) {
1127 push({ type: 'star', value, output: '' });
1128 continue;
1129 }
1130
1131 const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace');
1132 const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren');
1133 if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) {
1134 push({ type: 'star', value, output: '' });
1135 continue;
1136 }
1137
1138 // strip consecutive `/**/`
1139 while (rest.slice(0, 3) === '/**') {
1140 const after = input[state.index + 4];
1141 if (after && after !== '/') {
1142 break;
1143 }
1144 rest = rest.slice(3);
1145 consume('/**', 3);
1146 }
1147
1148 if (prior.type === 'bos' && eos()) {
1149 prev.type = 'globstar';
1150 prev.value += value;
1151 prev.output = globstar(opts);
1152 state.output = prev.output;
1153 state.globstar = true;
1154 consume(value);
1155 continue;
1156 }
1157
1158 if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) {
1159 state.output = state.output.slice(0, -(prior.output + prev.output).length);
1160 prior.output = `(?:${prior.output}`;
1161
1162 prev.type = 'globstar';
1163 prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)');
1164 prev.value += value;
1165 state.globstar = true;
1166 state.output += prior.output + prev.output;
1167 consume(value);
1168 continue;
1169 }
1170
1171 if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') {
1172 const end = rest[1] !== void 0 ? '|$' : '';
1173
1174 state.output = state.output.slice(0, -(prior.output + prev.output).length);
1175 prior.output = `(?:${prior.output}`;
1176
1177 prev.type = 'globstar';
1178 prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
1179 prev.value += value;
1180
1181 state.output += prior.output + prev.output;
1182 state.globstar = true;
1183
1184 consume(value + advance());
1185
1186 push({ type: 'slash', value: '/', output: '' });
1187 continue;
1188 }
1189
1190 if (prior.type === 'bos' && rest[0] === '/') {
1191 prev.type = 'globstar';
1192 prev.value += value;
1193 prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
1194 state.output = prev.output;
1195 state.globstar = true;
1196 consume(value + advance());
1197 push({ type: 'slash', value: '/', output: '' });
1198 continue;
1199 }
1200
1201 // remove single star from output
1202 state.output = state.output.slice(0, -prev.output.length);
1203
1204 // reset previous token to globstar
1205 prev.type = 'globstar';
1206 prev.output = globstar(opts);
1207 prev.value += value;
1208
1209 // reset output with globstar
1210 state.output += prev.output;
1211 state.globstar = true;
1212 consume(value);
1213 continue;
1214 }
1215
1216 const token = { type: 'star', value, output: star };
1217
1218 if (opts.bash === true) {
1219 token.output = '.*?';
1220 if (prev.type === 'bos' || prev.type === 'slash') {
1221 token.output = nodot + token.output;
1222 }
1223 push(token);
1224 continue;
1225 }
1226
1227 if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) {
1228 token.output = value;
1229 push(token);
1230 continue;
1231 }
1232
1233 if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') {
1234 if (prev.type === 'dot') {
1235 state.output += NO_DOT_SLASH;
1236 prev.output += NO_DOT_SLASH;
1237
1238 } else if (opts.dot === true) {
1239 state.output += NO_DOTS_SLASH;
1240 prev.output += NO_DOTS_SLASH;
1241
1242 } else {
1243 state.output += nodot;
1244 prev.output += nodot;
1245 }
1246
1247 if (peek() !== '*') {
1248 state.output += ONE_CHAR;
1249 prev.output += ONE_CHAR;
1250 }
1251 }
1252
1253 push(token);
1254 }
1255
1256 while (state.brackets > 0) {
1257 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']'));
1258 state.output = utils.escapeLast(state.output, '[');
1259 decrement('brackets');
1260 }
1261
1262 while (state.parens > 0) {
1263 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')'));
1264 state.output = utils.escapeLast(state.output, '(');
1265 decrement('parens');
1266 }
1267
1268 while (state.braces > 0) {
1269 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}'));
1270 state.output = utils.escapeLast(state.output, '{');
1271 decrement('braces');
1272 }
1273
1274 if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) {
1275 push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` });
1276 }
1277
1278 // rebuild the output if we had to backtrack at any point
1279 if (state.backtrack === true) {
1280 state.output = '';
1281
1282 for (const token of state.tokens) {
1283 state.output += token.output != null ? token.output : token.value;
1284
1285 if (token.suffix) {
1286 state.output += token.suffix;
1287 }
1288 }
1289 }
1290
1291 return state;
1292};
1293
1294/**
1295 * Fast paths for creating regular expressions for common glob patterns.
1296 * This can significantly speed up processing and has very little downside
1297 * impact when none of the fast paths match.
1298 */
1299
1300parse.fastpaths = (input, options) => {
1301 const opts = { ...options };
1302 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
1303 const len = input.length;
1304 if (len > max) {
1305 throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
1306 }
1307
1308 input = REPLACEMENTS[input] || input;
1309
1310 // create constants based on platform, for windows or posix
1311 const {
1312 DOT_LITERAL,
1313 SLASH_LITERAL,
1314 ONE_CHAR,
1315 DOTS_SLASH,
1316 NO_DOT,
1317 NO_DOTS,
1318 NO_DOTS_SLASH,
1319 STAR,
1320 START_ANCHOR
1321 } = constants.globChars(opts.windows);
1322
1323 const nodot = opts.dot ? NO_DOTS : NO_DOT;
1324 const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
1325 const capture = opts.capture ? '' : '?:';
1326 const state = { negated: false, prefix: '' };
1327 let star = opts.bash === true ? '.*?' : STAR;
1328
1329 if (opts.capture) {
1330 star = `(${star})`;
1331 }
1332
1333 const globstar = opts => {
1334 if (opts.noglobstar === true) return star;
1335 return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
1336 };
1337
1338 const create = str => {
1339 switch (str) {
1340 case '*':
1341 return `${nodot}${ONE_CHAR}${star}`;
1342
1343 case '.*':
1344 return `${DOT_LITERAL}${ONE_CHAR}${star}`;
1345
1346 case '*.*':
1347 return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
1348
1349 case '*/*':
1350 return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`;
1351
1352 case '**':
1353 return nodot + globstar(opts);
1354
1355 case '**/*':
1356 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`;
1357
1358 case '**/*.*':
1359 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
1360
1361 case '**/.*':
1362 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`;
1363
1364 default: {
1365 const match = /^(.*?)\.(\w+)$/.exec(str);
1366 if (!match) return;
1367
1368 const source = create(match[1]);
1369 if (!source) return;
1370
1371 return source + DOT_LITERAL + match[2];
1372 }
1373 }
1374 };
1375
1376 const output = utils.removePrefix(input, state);
1377 let source = create(output);
1378
1379 if (source && opts.strictSlashes !== true) {
1380 source += `${SLASH_LITERAL}?`;
1381 }
1382
1383 return source;
1384};
1385
1386module.exports = parse;
node_modules/picomatch/lib/picomatch.js +349 -0
……@@ -0,0 +1,349 @@
1'use strict';
2
3const scan = require('./scan');
4const parse = require('./parse');
5const utils = require('./utils');
6const constants = require('./constants');
7const isObject = val => val && typeof val === 'object' && !Array.isArray(val);
8
9/**
10 * Creates a matcher function from one or more glob patterns. The
11 * returned function takes a string to match as its first argument,
12 * and returns true if the string is a match. The returned matcher
13 * function also takes a boolean as the second argument that, when true,
14 * returns an object with additional information.
15 *
16 * ```js
17 * const picomatch = require('picomatch');
18 * // picomatch(glob[, options]);
19 *
20 * const isMatch = picomatch('*.!(*a)');
21 * console.log(isMatch('a.a')); //=> false
22 * console.log(isMatch('a.b')); //=> true
23 * ```
24 * @name picomatch
25 * @param {String|Array} `globs` One or more glob patterns.
26 * @param {Object=} `options`
27 * @return {Function=} Returns a matcher function.
28 * @api public
29 */
30
31const picomatch = (glob, options, returnState = false) => {
32 if (Array.isArray(glob)) {
33 const fns = glob.map(input => picomatch(input, options, returnState));
34 const arrayMatcher = str => {
35 for (const isMatch of fns) {
36 const state = isMatch(str);
37 if (state) return state;
38 }
39 return false;
40 };
41 return arrayMatcher;
42 }
43
44 const isState = isObject(glob) && glob.tokens && glob.input;
45
46 if (glob === '' || (typeof glob !== 'string' && !isState)) {
47 throw new TypeError('Expected pattern to be a non-empty string');
48 }
49
50 const opts = options || {};
51 const posix = opts.windows;
52 const regex = isState
53 ? picomatch.compileRe(glob, options)
54 : picomatch.makeRe(glob, options, false, true);
55
56 const state = regex.state;
57 delete regex.state;
58
59 let isIgnored = () => false;
60 if (opts.ignore) {
61 const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null };
62 isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
63 }
64
65 const matcher = (input, returnObject = false) => {
66 const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
67 const result = { glob, state, regex, posix, input, output, match, isMatch };
68
69 if (typeof opts.onResult === 'function') {
70 opts.onResult(result);
71 }
72
73 if (isMatch === false) {
74 result.isMatch = false;
75 return returnObject ? result : false;
76 }
77
78 if (isIgnored(input)) {
79 if (typeof opts.onIgnore === 'function') {
80 opts.onIgnore(result);
81 }
82 result.isMatch = false;
83 return returnObject ? result : false;
84 }
85
86 if (typeof opts.onMatch === 'function') {
87 opts.onMatch(result);
88 }
89 return returnObject ? result : true;
90 };
91
92 if (returnState) {
93 matcher.state = state;
94 }
95
96 return matcher;
97};
98
99/**
100 * Test `input` with the given `regex`. This is used by the main
101 * `picomatch()` function to test the input string.
102 *
103 * ```js
104 * const picomatch = require('picomatch');
105 * // picomatch.test(input, regex[, options]);
106 *
107 * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
108 * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
109 * ```
110 * @param {String} `input` String to test.
111 * @param {RegExp} `regex`
112 * @return {Object} Returns an object with matching info.
113 * @api public
114 */
115
116picomatch.test = (input, regex, options, { glob, posix } = {}) => {
117 if (typeof input !== 'string') {
118 throw new TypeError('Expected input to be a string');
119 }
120
121 if (input === '') {
122 return { isMatch: false, output: '' };
123 }
124
125 const opts = options || {};
126 const format = opts.format || (posix ? utils.toPosixSlashes : null);
127 let match = input === glob;
128 let output = (match && format) ? format(input) : input;
129
130 if (match === false) {
131 output = format ? format(input) : input;
132 match = output === glob;
133 }
134
135 if (match === false || opts.capture === true) {
136 if (opts.matchBase === true || opts.basename === true) {
137 match = picomatch.matchBase(input, regex, options, posix);
138 } else {
139 match = regex.exec(output);
140 }
141 }
142
143 return { isMatch: Boolean(match), match, output };
144};
145
146/**
147 * Match the basename of a filepath.
148 *
149 * ```js
150 * const picomatch = require('picomatch');
151 * // picomatch.matchBase(input, glob[, options]);
152 * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
153 * ```
154 * @param {String} `input` String to test.
155 * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe).
156 * @return {Boolean}
157 * @api public
158 */
159
160picomatch.matchBase = (input, glob, options) => {
161 const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
162 return regex.test(utils.basename(input));
163};
164
165/**
166 * Returns true if **any** of the given glob `patterns` match the specified `string`.
167 *
168 * ```js
169 * const picomatch = require('picomatch');
170 * // picomatch.isMatch(string, patterns[, options]);
171 *
172 * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
173 * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
174 * ```
175 * @param {String|Array} str The string to test.
176 * @param {String|Array} patterns One or more glob patterns to use for matching.
177 * @param {Object} [options] See available [options](#options).
178 * @return {Boolean} Returns true if any patterns match `str`
179 * @api public
180 */
181
182picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
183
184/**
185 * Parse a glob pattern to create the source string for a regular
186 * expression.
187 *
188 * ```js
189 * const picomatch = require('picomatch');
190 * const result = picomatch.parse(pattern[, options]);
191 * ```
192 * @param {String} `pattern`
193 * @param {Object} `options`
194 * @return {Object} Returns an object with useful properties and output to be used as a regex source string.
195 * @api public
196 */
197
198picomatch.parse = (pattern, options) => {
199 if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options));
200 return parse(pattern, { ...options, fastpaths: false });
201};
202
203/**
204 * Scan a glob pattern to separate the pattern into segments.
205 *
206 * ```js
207 * const picomatch = require('picomatch');
208 * // picomatch.scan(input[, options]);
209 *
210 * const result = picomatch.scan('!./foo/*.js');
211 * console.log(result);
212 * { prefix: '!./',
213 * input: '!./foo/*.js',
214 * start: 3,
215 * base: 'foo',
216 * glob: '*.js',
217 * isBrace: false,
218 * isBracket: false,
219 * isGlob: true,
220 * isExtglob: false,
221 * isGlobstar: false,
222 * negated: true }
223 * ```
224 * @param {String} `input` Glob pattern to scan.
225 * @param {Object} `options`
226 * @return {Object} Returns an object with
227 * @api public
228 */
229
230picomatch.scan = (input, options) => scan(input, options);
231
232/**
233 * Compile a regular expression from the `state` object returned by the
234 * [parse()](#parse) method.
235 *
236 * ```js
237 * const picomatch = require('picomatch');
238 * const state = picomatch.parse('*.js');
239 * // picomatch.compileRe(state[, options]);
240 *
241 * console.log(picomatch.compileRe(state));
242 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
243 * ```
244 * @param {Object} `state`
245 * @param {Object} `options`
246 * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
247 * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
248 * @return {RegExp}
249 * @api public
250 */
251
252picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
253 if (returnOutput === true) {
254 return state.output;
255 }
256
257 const opts = options || {};
258 const prepend = opts.contains ? '' : '^';
259 const append = opts.contains ? '' : '$';
260
261 let source = `${prepend}(?:${state.output})${append}`;
262 if (state && state.negated === true) {
263 source = `^(?!${source}).*$`;
264 }
265
266 const regex = picomatch.toRegex(source, options);
267 if (returnState === true) {
268 regex.state = state;
269 }
270
271 return regex;
272};
273
274/**
275 * Create a regular expression from a parsed glob pattern.
276 *
277 * ```js
278 * const picomatch = require('picomatch');
279 * // picomatch.makeRe(state[, options]);
280 *
281 * const result = picomatch.makeRe('*.js');
282 * console.log(result);
283 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
284 * ```
285 * @param {String} `state` The object returned from the `.parse` method.
286 * @param {Object} `options`
287 * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result.
288 * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression.
289 * @return {RegExp} Returns a regex created from the given pattern.
290 * @api public
291 */
292
293picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => {
294 if (!input || typeof input !== 'string') {
295 throw new TypeError('Expected a non-empty string');
296 }
297
298 let parsed = { negated: false, fastpaths: true };
299
300 if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) {
301 parsed.output = parse.fastpaths(input, options);
302 }
303
304 if (!parsed.output) {
305 parsed = parse(input, options);
306 }
307
308 return picomatch.compileRe(parsed, options, returnOutput, returnState);
309};
310
311/**
312 * Create a regular expression from the given regex source string.
313 *
314 * ```js
315 * const picomatch = require('picomatch');
316 * // picomatch.toRegex(source[, options]);
317 *
318 * const { output } = picomatch.parse('*.js');
319 * console.log(picomatch.toRegex(output));
320 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
321 * ```
322 * @param {String} `source` Regular expression source string.
323 * @param {Object} `options`
324 * @return {RegExp}
325 * @api public
326 */
327
328picomatch.toRegex = (source, options) => {
329 try {
330 const opts = options || {};
331 return new RegExp(source, opts.flags || (opts.nocase ? 'i' : ''));
332 } catch (err) {
333 if (options && options.debug === true) throw err;
334 return /$^/;
335 }
336};
337
338/**
339 * Picomatch constants.
340 * @return {Object}
341 */
342
343picomatch.constants = constants;
344
345/**
346 * Expose "picomatch"
347 */
348
349module.exports = picomatch;
node_modules/picomatch/lib/scan.js +391 -0
……@@ -0,0 +1,391 @@
1'use strict';
2
3const utils = require('./utils');
4const {
5 CHAR_ASTERISK, /* * */
6 CHAR_AT, /* @ */
7 CHAR_BACKWARD_SLASH, /* \ */
8 CHAR_COMMA, /* , */
9 CHAR_DOT, /* . */
10 CHAR_EXCLAMATION_MARK, /* ! */
11 CHAR_FORWARD_SLASH, /* / */
12 CHAR_LEFT_CURLY_BRACE, /* { */
13 CHAR_LEFT_PARENTHESES, /* ( */
14 CHAR_LEFT_SQUARE_BRACKET, /* [ */
15 CHAR_PLUS, /* + */
16 CHAR_QUESTION_MARK, /* ? */
17 CHAR_RIGHT_CURLY_BRACE, /* } */
18 CHAR_RIGHT_PARENTHESES, /* ) */
19 CHAR_RIGHT_SQUARE_BRACKET /* ] */
20} = require('./constants');
21
22const isPathSeparator = code => {
23 return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
24};
25
26const depth = token => {
27 if (token.isPrefix !== true) {
28 token.depth = token.isGlobstar ? Infinity : 1;
29 }
30};
31
32/**
33 * Quickly scans a glob pattern and returns an object with a handful of
34 * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists),
35 * `glob` (the actual pattern), `negated` (true if the path starts with `!` but not
36 * with `!(`) and `negatedExtglob` (true if the path starts with `!(`).
37 *
38 * ```js
39 * const pm = require('picomatch');
40 * console.log(pm.scan('foo/bar/*.js'));
41 * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' }
42 * ```
43 * @param {String} `str`
44 * @param {Object} `options`
45 * @return {Object} Returns an object with tokens and regex source string.
46 * @api public
47 */
48
49const scan = (input, options) => {
50 const opts = options || {};
51
52 const length = input.length - 1;
53 const scanToEnd = opts.parts === true || opts.scanToEnd === true;
54 const slashes = [];
55 const tokens = [];
56 const parts = [];
57
58 let str = input;
59 let index = -1;
60 let start = 0;
61 let lastIndex = 0;
62 let isBrace = false;
63 let isBracket = false;
64 let isGlob = false;
65 let isExtglob = false;
66 let isGlobstar = false;
67 let braceEscaped = false;
68 let backslashes = false;
69 let negated = false;
70 let negatedExtglob = false;
71 let finished = false;
72 let braces = 0;
73 let prev;
74 let code;
75 let token = { value: '', depth: 0, isGlob: false };
76
77 const eos = () => index >= length;
78 const peek = () => str.charCodeAt(index + 1);
79 const advance = () => {
80 prev = code;
81 return str.charCodeAt(++index);
82 };
83
84 while (index < length) {
85 code = advance();
86 let next;
87
88 if (code === CHAR_BACKWARD_SLASH) {
89 backslashes = token.backslashes = true;
90 code = advance();
91
92 if (code === CHAR_LEFT_CURLY_BRACE) {
93 braceEscaped = true;
94 }
95 continue;
96 }
97
98 if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) {
99 braces++;
100
101 while (eos() !== true && (code = advance())) {
102 if (code === CHAR_BACKWARD_SLASH) {
103 backslashes = token.backslashes = true;
104 advance();
105 continue;
106 }
107
108 if (code === CHAR_LEFT_CURLY_BRACE) {
109 braces++;
110 continue;
111 }
112
113 if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) {
114 isBrace = token.isBrace = true;
115 isGlob = token.isGlob = true;
116 finished = true;
117
118 if (scanToEnd === true) {
119 continue;
120 }
121
122 break;
123 }
124
125 if (braceEscaped !== true && code === CHAR_COMMA) {
126 isBrace = token.isBrace = true;
127 isGlob = token.isGlob = true;
128 finished = true;
129
130 if (scanToEnd === true) {
131 continue;
132 }
133
134 break;
135 }
136
137 if (code === CHAR_RIGHT_CURLY_BRACE) {
138 braces--;
139
140 if (braces === 0) {
141 braceEscaped = false;
142 isBrace = token.isBrace = true;
143 finished = true;
144 break;
145 }
146 }
147 }
148
149 if (scanToEnd === true) {
150 continue;
151 }
152
153 break;
154 }
155
156 if (code === CHAR_FORWARD_SLASH) {
157 slashes.push(index);
158 tokens.push(token);
159 token = { value: '', depth: 0, isGlob: false };
160
161 if (finished === true) continue;
162 if (prev === CHAR_DOT && index === (start + 1)) {
163 start += 2;
164 continue;
165 }
166
167 lastIndex = index + 1;
168 continue;
169 }
170
171 if (opts.noext !== true) {
172 const isExtglobChar = code === CHAR_PLUS
173 || code === CHAR_AT
174 || code === CHAR_ASTERISK
175 || code === CHAR_QUESTION_MARK
176 || code === CHAR_EXCLAMATION_MARK;
177
178 if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) {
179 isGlob = token.isGlob = true;
180 isExtglob = token.isExtglob = true;
181 finished = true;
182 if (code === CHAR_EXCLAMATION_MARK && index === start) {
183 negatedExtglob = true;
184 }
185
186 if (scanToEnd === true) {
187 while (eos() !== true && (code = advance())) {
188 if (code === CHAR_BACKWARD_SLASH) {
189 backslashes = token.backslashes = true;
190 code = advance();
191 continue;
192 }
193
194 if (code === CHAR_RIGHT_PARENTHESES) {
195 isGlob = token.isGlob = true;
196 finished = true;
197 break;
198 }
199 }
200 continue;
201 }
202 break;
203 }
204 }
205
206 if (code === CHAR_ASTERISK) {
207 if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true;
208 isGlob = token.isGlob = true;
209 finished = true;
210
211 if (scanToEnd === true) {
212 continue;
213 }
214 break;
215 }
216
217 if (code === CHAR_QUESTION_MARK) {
218 isGlob = token.isGlob = true;
219 finished = true;
220
221 if (scanToEnd === true) {
222 continue;
223 }
224 break;
225 }
226
227 if (code === CHAR_LEFT_SQUARE_BRACKET) {
228 while (eos() !== true && (next = advance())) {
229 if (next === CHAR_BACKWARD_SLASH) {
230 backslashes = token.backslashes = true;
231 advance();
232 continue;
233 }
234
235 if (next === CHAR_RIGHT_SQUARE_BRACKET) {
236 isBracket = token.isBracket = true;
237 isGlob = token.isGlob = true;
238 finished = true;
239 break;
240 }
241 }
242
243 if (scanToEnd === true) {
244 continue;
245 }
246
247 break;
248 }
249
250 if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) {
251 negated = token.negated = true;
252 start++;
253 continue;
254 }
255
256 if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) {
257 isGlob = token.isGlob = true;
258
259 if (scanToEnd === true) {
260 while (eos() !== true && (code = advance())) {
261 if (code === CHAR_LEFT_PARENTHESES) {
262 backslashes = token.backslashes = true;
263 code = advance();
264 continue;
265 }
266
267 if (code === CHAR_RIGHT_PARENTHESES) {
268 finished = true;
269 break;
270 }
271 }
272 continue;
273 }
274 break;
275 }
276
277 if (isGlob === true) {
278 finished = true;
279
280 if (scanToEnd === true) {
281 continue;
282 }
283
284 break;
285 }
286 }
287
288 if (opts.noext === true) {
289 isExtglob = false;
290 isGlob = false;
291 }
292
293 let base = str;
294 let prefix = '';
295 let glob = '';
296
297 if (start > 0) {
298 prefix = str.slice(0, start);
299 str = str.slice(start);
300 lastIndex -= start;
301 }
302
303 if (base && isGlob === true && lastIndex > 0) {
304 base = str.slice(0, lastIndex);
305 glob = str.slice(lastIndex);
306 } else if (isGlob === true) {
307 base = '';
308 glob = str;
309 } else {
310 base = str;
311 }
312
313 if (base && base !== '' && base !== '/' && base !== str) {
314 if (isPathSeparator(base.charCodeAt(base.length - 1))) {
315 base = base.slice(0, -1);
316 }
317 }
318
319 if (opts.unescape === true) {
320 if (glob) glob = utils.removeBackslashes(glob);
321
322 if (base && backslashes === true) {
323 base = utils.removeBackslashes(base);
324 }
325 }
326
327 const state = {
328 prefix,
329 input,
330 start,
331 base,
332 glob,
333 isBrace,
334 isBracket,
335 isGlob,
336 isExtglob,
337 isGlobstar,
338 negated,
339 negatedExtglob
340 };
341
342 if (opts.tokens === true) {
343 state.maxDepth = 0;
344 if (!isPathSeparator(code)) {
345 tokens.push(token);
346 }
347 state.tokens = tokens;
348 }
349
350 if (opts.parts === true || opts.tokens === true) {
351 let prevIndex;
352
353 for (let idx = 0; idx < slashes.length; idx++) {
354 const n = prevIndex ? prevIndex + 1 : start;
355 const i = slashes[idx];
356 const value = input.slice(n, i);
357 if (opts.tokens) {
358 if (idx === 0 && start !== 0) {
359 tokens[idx].isPrefix = true;
360 tokens[idx].value = prefix;
361 } else {
362 tokens[idx].value = value;
363 }
364 depth(tokens[idx]);
365 state.maxDepth += tokens[idx].depth;
366 }
367 if (idx !== 0 || value !== '') {
368 parts.push(value);
369 }
370 prevIndex = i;
371 }
372
373 if (prevIndex && prevIndex + 1 < input.length) {
374 const value = input.slice(prevIndex + 1);
375 parts.push(value);
376
377 if (opts.tokens) {
378 tokens[tokens.length - 1].value = value;
379 depth(tokens[tokens.length - 1]);
380 state.maxDepth += tokens[tokens.length - 1].depth;
381 }
382 }
383
384 state.slashes = slashes;
385 state.parts = parts;
386 }
387
388 return state;
389};
390
391module.exports = scan;
node_modules/picomatch/lib/utils.js +72 -0
……@@ -0,0 +1,72 @@
1/*global navigator*/
2'use strict';
3
4const {
5 REGEX_BACKSLASH,
6 REGEX_REMOVE_BACKSLASH,
7 REGEX_SPECIAL_CHARS,
8 REGEX_SPECIAL_CHARS_GLOBAL
9} = require('./constants');
10
11exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
12exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str);
13exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str);
14exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1');
15exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/');
16
17exports.isWindows = () => {
18 if (typeof navigator !== 'undefined' && navigator.platform) {
19 const platform = navigator.platform.toLowerCase();
20 return platform === 'win32' || platform === 'windows';
21 }
22
23 if (typeof process !== 'undefined' && process.platform) {
24 return process.platform === 'win32';
25 }
26
27 return false;
28};
29
30exports.removeBackslashes = str => {
31 return str.replace(REGEX_REMOVE_BACKSLASH, match => {
32 return match === '\\' ? '' : match;
33 });
34};
35
36exports.escapeLast = (input, char, lastIdx) => {
37 const idx = input.lastIndexOf(char, lastIdx);
38 if (idx === -1) return input;
39 if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1);
40 return `${input.slice(0, idx)}\\${input.slice(idx)}`;
41};
42
43exports.removePrefix = (input, state = {}) => {
44 let output = input;
45 if (output.startsWith('./')) {
46 output = output.slice(2);
47 state.prefix = './';
48 }
49 return output;
50};
51
52exports.wrapOutput = (input, state = {}, options = {}) => {
53 const prepend = options.contains ? '' : '^';
54 const append = options.contains ? '' : '$';
55
56 let output = `${prepend}(?:${input})${append}`;
57 if (state.negated === true) {
58 output = `(?:^(?!${output}).*$)`;
59 }
60 return output;
61};
62
63exports.basename = (path, { windows } = {}) => {
64 const segs = path.split(windows ? /[\\/]/ : '/');
65 const last = segs[segs.length - 1];
66
67 if (last === '') {
68 return segs[segs.length - 2];
69 }
70
71 return last;
72};
node_modules/picomatch/package.json +82 -0
……@@ -0,0 +1,82 @@
1{
2 "name": "picomatch",
3 "description": "Blazing fast and accurate glob matcher written in JavaScript, with no dependencies and full support for standard and extended Bash glob features, including braces, extglobs, POSIX brackets, and regular expressions.",
4 "version": "4.0.4",
5 "homepage": "https://github.com/micromatch/picomatch",
6 "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
7 "funding": "https://github.com/sponsors/jonschlinkert",
8 "repository": "micromatch/picomatch",
9 "bugs": {
10 "url": "https://github.com/micromatch/picomatch/issues"
11 },
12 "license": "MIT",
13 "files": [
14 "index.js",
15 "posix.js",
16 "lib"
17 ],
18 "sideEffects": false,
19 "main": "index.js",
20 "engines": {
21 "node": ">=12"
22 },
23 "scripts": {
24 "lint": "eslint --cache --cache-location node_modules/.cache/.eslintcache --report-unused-disable-directives --ignore-path .gitignore .",
25 "mocha": "mocha --reporter dot",
26 "test": "npm run lint && npm run mocha",
27 "test:ci": "npm run test:cover",
28 "test:cover": "nyc npm run mocha"
29 },
30 "devDependencies": {
31 "eslint": "^8.57.0",
32 "fill-range": "^7.0.1",
33 "gulp-format-md": "^2.0.0",
34 "mocha": "^10.4.0",
35 "nyc": "^15.1.0"
36 },
37 "keywords": [
38 "glob",
39 "match",
40 "picomatch"
41 ],
42 "nyc": {
43 "reporter": [
44 "html",
45 "lcov",
46 "text-summary"
47 ]
48 },
49 "verb": {
50 "toc": {
51 "render": true,
52 "method": "preWrite",
53 "maxdepth": 3
54 },
55 "layout": "empty",
56 "tasks": [
57 "readme"
58 ],
59 "plugins": [
60 "gulp-format-md"
61 ],
62 "lint": {
63 "reflinks": true
64 },
65 "related": {
66 "list": [
67 "braces",
68 "micromatch"
69 ]
70 },
71 "reflinks": [
72 "braces",
73 "expand-brackets",
74 "extglob",
75 "fill-range",
76 "micromatch",
77 "minimatch",
78 "nanomatch",
79 "picomatch"
80 ]
81 }
82}
node_modules/picomatch/posix.js +3 -0
……@@ -0,0 +1,3 @@
1'use strict';
2
3module.exports = require('./lib/picomatch');
node_modules/record-cache/.travis.yml +6 -0
……@@ -0,0 +1,6 @@
1language: node_js
2sudo: false
3node_js:
4 - 6
5 - 8
6 - 9
node_modules/record-cache/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2018 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/record-cache/README.md +83 -0
……@@ -0,0 +1,83 @@
1# record-cache
2
3Cache optimised for record like things like `host:port` or `domain.names`.
4
5```
6npm install record-cache
7```
8
9[![build status](https://travis-ci.org/mafintosh/record-cache.svg?branch=master)](https://travis-ci.org/mafintosh/record-cache)
10
11## Usage
12
13``` js
14var recordCache = require('record-cache')
15
16var cache = recordCache({
17 maxSize: 1000 // store ~1000 values at max
18 maxAge: 1000 // gc values older than ~1000ms
19})
20
21cache.add('hello', '127.0.0.1')
22cache.add('hello', '127.0.1.1')
23cache.add('hello', '127.0.0.2')
24
25console.log(cache.get('hello', 2)) // prints two of the above
26
27// wait 2s
28setTimeout(function () {
29 console.log(cache.get('hello', 2)) // prints []
30}, 2000)
31```
32
33## API
34
35#### `var cache = recordCache([options])`
36
37Create a new record cache.
38
39Options include:
40
41``` js
42{
43 maxSize: 1000, // approximate max size
44 maxAge: 1000, // approximate max age in ms
45 onStale: false // function called when evicting stale records
46}
47```
48
49In the worst case the cache will be `2 * maxSize` large, and
50if `maxAge` is used old values are gc'ed every `0.66 * maxAge - 1.33 * maxAge` with an optional callback to the `onStale` function upon record eviction.
51
52This is to greatly simplify the data structures and also gives us a pretty decent
53perf boost compared to other cache modules out there.
54
55#### `cache.add(recordName, value)`
56
57Push a new value to the record set. `value` should be serialisable.
58
59#### `cache.remove(recordName, value)`
60
61Remove a value from the record set. `value` should be a previously added value.
62
63#### `var list = cache.get(recordName, [maxCount])`
64
65Get a list of values from the record set. The list will be randomised.
66Specify `maxCount` to only get this many values at max.
67
68#### `cache.size`
69
70Get the actual size of the cache.
71
72#### `cache.clear()`
73
74Clear all values from the cache.
75
76#### `cache.destroy()`
77
78Completely destroy the cache. Needed if you are using the `maxAge` option to
79cancel the gc timer.
80
81## License
82
83MIT
node_modules/record-cache/example.js +13 -0
……@@ -0,0 +1,13 @@
1var recordCache = require('./')
2
3var rc = recordCache({
4 maxAge: 10,
5 maxSize: 100
6})
7
8rc.add('hello', 'world')
9rc.add('hello', 'welt')
10rc.add('hello', 'verden')
11
12console.log(rc.get('hello', 2))
13setTimeout(() => console.log(rc.get('hello', 2)), 200)
node_modules/record-cache/index.js +170 -0
……@@ -0,0 +1,170 @@
1const b4a = require('b4a')
2
3var EMPTY = []
4
5module.exports = RecordCache
6
7function RecordSet () {
8 this.list = []
9 this.map = new Map()
10}
11
12RecordSet.prototype.add = function (record, value) {
13 var k = toString(record)
14 var r = this.map.get(k)
15 if (r) return false
16
17 r = {index: this.list.length, record: value || record}
18 this.list.push(r)
19 this.map.set(k, r)
20 return true
21}
22
23RecordSet.prototype.remove = function (record) {
24 var k = toString(record)
25 var r = this.map.get(k)
26 if (!r) return false
27
28 swap(this.list, r.index, this.list.length - 1)
29 this.list.pop()
30 this.map.delete(k)
31 return true
32}
33
34function RecordStore () {
35 this.records = new Map()
36 this.size = 0
37}
38
39RecordStore.prototype.add = function (name, record, value) {
40 var r = this.records.get(name)
41
42 if (!r) {
43 r = new RecordSet()
44 this.records.set(name, r)
45 }
46
47 if (r.add(record, value)) {
48 this.size++
49 return true
50 }
51
52 return false
53}
54
55RecordStore.prototype.remove = function (name, record, value) {
56 var r = this.records.get(name)
57 if (!r) return false
58
59 if (r.remove(record, value)) {
60 this.size--
61 if (!r.map.size) this.records.delete(name)
62 return true
63 }
64
65 return false
66}
67
68RecordStore.prototype.get = function (name) {
69 var r = this.records.get(name)
70 return r ? r.list : EMPTY
71}
72
73function RecordCache (opts) {
74 if (!(this instanceof RecordCache)) return new RecordCache(opts)
75 if (!opts) opts = {}
76
77 this.maxSize = opts.maxSize || Infinity
78 this.maxAge = opts.maxAge || 0
79
80 this._onstale = opts.onStale || opts.onstale || null
81 this._fresh = new RecordStore()
82 this._stale = new RecordStore()
83 this._interval = null
84 this._gced = false
85
86 if (this.maxAge && this.maxAge < Infinity) {
87 // 2/3 gives us a span of 0.66-1.33 maxAge or avg maxAge
88 var tick = Math.ceil(2 / 3 * this.maxAge)
89 this._interval = setInterval(this._gcAuto.bind(this), tick)
90 if (this._interval.unref) this._interval.unref()
91 }
92}
93
94Object.defineProperty(RecordCache.prototype, 'size', {
95 get: function () {
96 return this._fresh.size + this._stale.size
97 }
98})
99
100RecordCache.prototype.add = function (name, record, value) {
101 this._stale.remove(name, record, value)
102 if (this._fresh.add(name, record, value) && this._fresh.size > this.maxSize) {
103 this._gc()
104 }
105}
106
107RecordCache.prototype.remove = function (name, record, value) {
108 this._fresh.remove(name, record, value)
109 this._stale.remove(name, record, value)
110}
111
112RecordCache.prototype.get = function (name, n) {
113 var a = this._fresh.get(name)
114 var b = this._stale.get(name)
115 var aLen = a.length
116 var bLen = b.length
117 var len = aLen + bLen
118
119 if (n > len || !n) n = len
120 var result = new Array(n)
121
122 for (var i = 0; i < n; i++) {
123 var j = Math.floor(Math.random() * (aLen + bLen))
124 if (j < aLen) {
125 result[i] = a[j].record
126 swap(a, j, --aLen)
127 } else {
128 j -= aLen
129 result[i] = b[j].record
130 swap(b, j, --bLen)
131 }
132 }
133
134 return result
135}
136
137RecordCache.prototype._gcAuto = function () {
138 if (!this._gced) this._gc()
139 this._gced = false
140}
141
142RecordCache.prototype._gc = function () {
143 if (this._onstale && this._stale.size > 0) this._onstale(this._stale)
144 this._stale = this._fresh
145 this._fresh = new RecordStore()
146 this._gced = true
147}
148
149RecordCache.prototype.clear = function () {
150 this._gc()
151 this._gc()
152}
153
154RecordCache.prototype.destroy = function () {
155 this.clear()
156 clearInterval(this._interval)
157 this._interval = null
158}
159
160function toString (record) {
161 return b4a.isBuffer(record) ? b4a.toString(record, 'hex') : record
162}
163
164function swap (list, a, b) {
165 var tmp = list[a]
166 tmp.index = b
167 list[b].index = a
168 list[a] = list[b]
169 list[b] = tmp
170}
node_modules/record-cache/package.json +26 -0
……@@ -0,0 +1,26 @@
1{
2 "name": "record-cache",
3 "version": "1.2.0",
4 "description": "Cache optimised for record like things",
5 "main": "index.js",
6 "dependencies": {
7 "b4a": "^1.3.1"
8 },
9 "devDependencies": {
10 "standard": "^10.0.3",
11 "tape": "^4.8.0"
12 },
13 "scripts": {
14 "test": "standard && tape test.js"
15 },
16 "repository": {
17 "type": "git",
18 "url": "https://github.com/mafintosh/record-cache.git"
19 },
20 "author": "Mathias Buus (@mafintosh)",
21 "license": "MIT",
22 "bugs": {
23 "url": "https://github.com/mafintosh/record-cache/issues"
24 },
25 "homepage": "https://github.com/mafintosh/record-cache"
26}
node_modules/record-cache/test.js +185 -0
……@@ -0,0 +1,185 @@
1var tape = require('tape')
2var recordCache = require('./')
3
4tape('add and get', function (t) {
5 var rc = recordCache()
6 rc.add('hello', 'world')
7 t.same(rc.get('hello'), ['world'])
8 t.end()
9})
10
11tape('add and get buffer', function (t) {
12 var rc = recordCache()
13 rc.add('hello', Buffer.from('world'))
14 t.same(rc.get('hello'), [Buffer.from('world')])
15 t.end()
16})
17
18tape('add and get (more than one)', function (t) {
19 var rc = recordCache()
20 rc.add('hello', 'world')
21 rc.add('hello', 'verden')
22 rc.add('hello', 'welt')
23 t.same(rc.get('hello').sort(), ['verden', 'welt', 'world'])
24
25 var list = rc.get('hello', 2)
26 t.ok(list[0] !== list[1])
27 t.ok(['verden', 'welt', 'world'].includes(list[0]))
28 t.ok(['verden', 'welt', 'world'].includes(list[1]))
29 t.end()
30})
31
32tape('get is randomised', function (t) {
33 var rc = recordCache()
34
35 rc.add('hello', 'a')
36 rc.add('hello', 'b')
37 rc.add('hello', 'c')
38
39 var map = {}
40
41 for (var i = 0; i < 1000; i++) {
42 map[rc.get('hello', 2).join('')] = true
43 }
44
45 t.same(map, {ab: true, ba: true, cb: true, bc: true, ac: true, ca: true})
46 t.end()
47})
48
49tape('get capped', function (t) {
50 var rc = recordCache({maxSize: 10})
51
52 for (var i = 0; i < 50; i++) {
53 rc.add('hello', '' + i)
54 }
55
56 t.ok(rc.get('hello').length <= 20)
57 t.ok(rc.size <= 20)
58 t.notOk(rc.get('hello').includes('0'))
59 t.notOk(rc.get('hello').includes('29'))
60 t.end()
61})
62
63tape('get capped with many record sets', function (t) {
64 var rc = recordCache({maxSize: 10})
65
66 for (var i = 0; i < 50; i++) {
67 rc.add('' + i, 'hello')
68 }
69
70 t.ok(rc.size <= 20)
71 t.same(rc.get('0'), [])
72 t.same(rc.get('29'), [])
73 t.same(rc.get('49'), ['hello'])
74 t.end()
75})
76
77tape('many updates is fine when capped', function (t) {
78 var rc = recordCache({maxSize: 10})
79
80 for (var i = 0; i < 10; i++) {
81 rc.add('hello', '' + i)
82 }
83 for (var j = 0; j < 100; j++) {
84 rc.add('hello', '9')
85 }
86
87 t.same(rc.get('hello').sort().join(''), '0123456789')
88 t.end()
89})
90
91tape('remove', function (t) {
92 var rc = recordCache()
93
94 t.same(rc.get('hello'), [])
95 rc.remove('hello', 'world')
96 t.same(rc.get('hello'), [])
97 rc.add('hello', 'world')
98 t.same(rc.get('hello'), ['world'])
99 rc.remove('hello', 'world')
100 t.same(rc.get('hello'), [])
101 t.end()
102})
103
104tape('remove with other value', function (t) {
105 var rc = recordCache()
106
107 rc.add('hello', 'hi')
108 t.same(rc.get('hello'), ['hi'])
109 rc.remove('hello', 'world')
110 t.same(rc.get('hello'), ['hi'])
111 rc.add('hello', 'world')
112 t.same(rc.get('hello').sort(), ['hi', 'world'])
113 rc.remove('hello', 'world')
114 t.same(rc.get('hello'), ['hi'])
115 t.end()
116})
117
118tape('clear', function (t) {
119 var rc = recordCache()
120
121 rc.clear()
122 t.same(rc.get('hello'), [])
123 rc.add('hello', 'a')
124 rc.add('hello', 'b')
125 rc.add('foo', 'bar')
126 t.same(rc.get('hello').sort(), ['a', 'b'])
127 rc.clear()
128 t.same(rc.get('hello'), [])
129 t.same(rc.get('foo'), [])
130 t.end()
131})
132
133tape('maxAge', function (t) {
134 var rc = recordCache({maxAge: 20})
135
136 rc.add('hello', 'world')
137 rc.add('hello', 'verden')
138 setTimeout(function () {
139 t.same(rc.get('hello').sort(), ['verden', 'world'])
140 setTimeout(function () {
141 t.same(rc.get('hello'), [])
142 rc.destroy()
143 t.end()
144 }, 35)
145 }, 5)
146})
147
148tape('maxAge but one value is staying alive', function (t) {
149 var rc = recordCache({maxAge: 20})
150
151 rc.add('hello', 'world')
152 rc.add('hello', 'verden')
153 var interval = setInterval(function () {
154 rc.add('hello', 'verden')
155 }, 5)
156 setTimeout(function () {
157 t.same(rc.get('hello').sort(), ['verden', 'world'])
158 setTimeout(function () {
159 clearInterval(interval)
160 t.same(rc.get('hello'), ['verden'])
161 rc.destroy()
162 t.end()
163 }, 35)
164 }, 5)
165})
166
167tape('add dedups buffers', function (t) {
168 var rc = recordCache()
169
170 rc.add('hello', Buffer.from('world'))
171 rc.add('hello', Buffer.from('world'))
172
173 t.same(rc.get('hello'), [Buffer.from('world')])
174 t.end()
175})
176
177tape('add and remove buffer', function (t) {
178 var rc = recordCache()
179
180 rc.add('hello', Buffer.from('world'))
181 rc.remove('hello', Buffer.from('world'))
182
183 t.same(rc.get('hello'), [])
184 t.end()
185})
node_modules/same-object/.github/workflows/test-node.yml +23 -0
……@@ -0,0 +1,23 @@
1name: Build Status
2on:
3 push:
4 branches:
5 - main
6 pull_request:
7 branches:
8 - main
9jobs:
10 build:
11 strategy:
12 matrix:
13 node-version: [lts/*]
14 os: [ubuntu-latest, macos-latest, windows-latest]
15 runs-on: ${{ matrix.os }}
16 steps:
17 - uses: actions/checkout@v2
18 - name: Use Node.js ${{ matrix.node-version }}
19 uses: actions/setup-node@v2
20 with:
21 node-version: ${{ matrix.node-version }}
22 - run: npm install
23 - run: npm test
node_modules/same-object/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1MIT License
2
3Copyright (c) 2023 Contributors
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
node_modules/same-object/README.md +53 -0
……@@ -0,0 +1,53 @@
1# same-object
2
3Determine if two objects are deeply equal
4
5```
6npm install same-object
7```
8
9Supports circular references, Maps, Symbols, etc.
10
11Aims for ~99% compatibility with `deep-equal` or `assert.deepEqual` without requiring native dependencies.\
12Useful for JavaScript runtimes without native Node modules like `util`, etc.
13
14## Usage
15``` js
16const sameObject = require('same-object')
17
18console.log(sameObject(1, '1')) // true
19console.log(sameObject(1, '1', { strict: true })) // false
20
21console.log(sameObject({ a: 1 }, { a: 1 })) // true
22console.log(sameObject({ a: 1 }, { a: 1, b: 2 })) // false
23
24console.log(sameObject(
25 new Set(['a', 1, 'b', 2]),
26 new Set(['b', 2, 'a', 1])
27)) // true
28```
29
30## API
31
32#### `const bool = sameObject(a, b, [options])`
33
34Compares `a` and `b`, returning whether they are equal or not.
35
36Available `options`:
37```js
38{
39 strict: false
40}
41```
42
43Loosely comparison (`==`) by default.\
44Use `{ strict: true }` for a stronger equality check (`===`).
45
46## References
47The source code is based on:\
48[node/comparisons.js](https://github.com/nodejs/node/blob/2adea16e394448c4c87b0639514f8babbeb7a080/lib/internal/util/comparisons.js)\
49[inspect-js/node-deep-equal](https://github.com/inspect-js/node-deep-equal)\
50[chaijs/deep-eql](https://github.com/chaijs/deep-eql)
51
52## License
53MIT
node_modules/same-object/index.js +116 -0
……@@ -0,0 +1,116 @@
1module.exports = same
2
3const isPrimitive = require('./lib/is-primitive.js')
4const sameKeys = require('./lib/same-keys.js')
5const sameKeyValues = require('./lib/same-key-values.js')
6const sameIterable = require('./lib/same-iterable.js')
7const sameSet = require('./lib/same-set.js')
8const sameMap = require('./lib/same-map.js')
9const sameArray = require('./lib/same-array.js')
10const sameRegExp = require('./lib/same-regexp.js')
11
12function same (a, b, opts, memos) {
13 // Short path optimization
14 if (a === b) {
15 if (a !== 0) return true
16 return opts && opts.strict ? Object.is(a, b) : true
17 }
18
19 const aIsPrimitive = isPrimitive(a)
20 const bIsPrimitive = isPrimitive(b)
21
22 if (aIsPrimitive && bIsPrimitive) {
23 if (opts && opts.strict) {
24 return typeof a === 'number' ? (Number.isNaN(a) && Number.isNaN(b)) : a === b
25 }
26 return a == b || (Number.isNaN(a) && Number.isNaN(b)) // eslint-disable-line eqeqeq
27 }
28
29 if (aIsPrimitive !== bIsPrimitive) return false
30
31 if (opts && opts.strict) {
32 if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false
33 }
34
35 const aType = getType(a)
36 const bType = getType(b)
37
38 if (aType !== bType) return false
39
40 if (!sameKeys(a, b, opts, memos)) return false
41
42 switch (aType) {
43 case 'String':
44 case 'Number':
45 case 'Boolean':
46 case 'Date':
47 return same(a.valueOf(), b.valueOf(), opts, memos)
48 }
49
50 if (aType === 'Error') {
51 return sameKeyValues(a, b, opts, memos, ['name', 'message'])
52 }
53
54 switch (aType) {
55 case 'Int8Array':
56 case 'Uint8Array':
57 case 'Uint8ClampedArray':
58 case 'Int16Array':
59 case 'Uint16Array':
60 case 'Int32Array':
61 case 'Uint32Array':
62 case 'Float32Array':
63 case 'Float64Array':
64 return sameIterable(a, b, opts, memos)
65 case 'DataView':
66 return sameIterable(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength), opts, memos)
67 case 'ArrayBuffer':
68 return sameIterable(new Uint8Array(a), new Uint8Array(b), opts, memos)
69 }
70
71 if (aType === 'RegExp') return sameRegExp(a, b)
72
73 if (!memos) {
74 memos = { a: new Map(), b: new Map(), position: 0 }
75 } else {
76 const memoA = memos.a.get(a)
77 if (memoA !== undefined) {
78 const memoB = memos.b.get(b)
79 if (memoB !== undefined) return memoA === memoB
80 }
81 memos.position++
82 }
83
84 memos.a.set(a, memos.position)
85 memos.b.set(b, memos.position)
86
87 const equals = sameObject(a, b, opts, memos, aType)
88
89 memos.a.delete(a)
90 memos.b.delete(b)
91
92 return equals
93}
94
95function sameObject (a, b, opts, memos, aType) {
96 if (aType === 'Array' || aType === 'Arguments') {
97 if (!sameArray(a, b, opts, memos)) return false
98 }
99
100 if (aType === 'Set') {
101 if (!sameSet(a, b, opts, memos)) return false
102 }
103
104 if (aType === 'Map') {
105 if (!sameMap(a, b, opts, memos)) return false
106 }
107
108 if (!sameKeyValues(a, b, opts, memos)) return false
109
110 return true
111}
112
113function getType (o) {
114 // Note: it returns 'Null' for null prototypes
115 return Object.prototype.toString.call(o).slice(8, -1)
116}
node_modules/same-object/lib/find-loose-matching-primitives.js +18 -0
……@@ -0,0 +1,18 @@
1module.exports = function findLooseMatchingPrimitives (primitive) {
2 switch (typeof primitive) {
3 case 'undefined':
4 return null
5 case 'object':
6 return undefined
7 case 'symbol':
8 return false
9 case 'string':
10 primitive = +primitive
11 // Falls through
12 case 'number':
13 if (Number.isNaN(primitive)) {
14 return false
15 }
16 }
17 return true
18}
node_modules/same-object/lib/is-primitive.js +3 -0
……@@ -0,0 +1,3 @@
1module.exports = function isPrimitive (value) {
2 return value === null || typeof value !== 'object'
3}
node_modules/same-object/lib/same-array.js +35 -0
……@@ -0,0 +1,35 @@
1const same = require('../index.js')
2
3module.exports = function sameArray (a, b, opts, memos) {
4 if (a.length !== b.length) return false
5
6 for (let i = 0; i < a.length; i++) {
7 const aHasProperty = Object.prototype.hasOwnProperty.call(a, i)
8 const bHasProperty = Object.prototype.hasOwnProperty.call(b, i)
9
10 if (aHasProperty) {
11 if (!bHasProperty || !same(a[i], b[i], opts, memos)) {
12 return false
13 }
14 } else if (bHasProperty) {
15 return false
16 } else {
17 // Array is sparse
18 const aKeys = Object.keys(a)
19
20 for (; i < aKeys.length; i++) {
21 const key = aKeys[i]
22 if (!Object.prototype.hasOwnProperty.call(b, key) ||
23 !same(a[key], b[key], opts, memos)) {
24 return false
25 }
26 }
27
28 if (aKeys.length !== Object.keys(b).length) return false
29
30 return true
31 }
32 }
33
34 return true
35}
node_modules/same-object/lib/same-iterable.js +13 -0
……@@ -0,0 +1,13 @@
1const same = require('../index.js')
2
3module.exports = function sameIterable (a, b, opts, memos) {
4 if (a.length !== b.length) return false
5
6 for (let i = 0; i < a.length; i++) {
7 if (!same(a[i], b[i], opts, memos)) {
8 return false
9 }
10 }
11
12 return true
13}
node_modules/same-object/lib/same-key-values.js +11 -0
……@@ -0,0 +1,11 @@
1const same = require('../index.js')
2
3module.exports = function sameKeyValues (a, b, opts, memos, keys = null) {
4 if (keys === null) keys = Object.keys(a)
5
6 for (const key of keys) {
7 if (!same(a[key], b[key], opts, memos)) return false
8 }
9
10 return true
11}
node_modules/same-object/lib/same-keys.js +13 -0
……@@ -0,0 +1,13 @@
1module.exports = function sameKeys (a, b, opts, memos) {
2 const aKeys = Object.keys(a)
3 const bKeys = Object.keys(b)
4 if (aKeys.length !== bKeys.length) return false
5
6 for (let i = 0; i < aKeys.length; i++) {
7 if (!Object.prototype.propertyIsEnumerable.call(b, aKeys[i])) return false
8 }
9
10 // + if strict, then check symbol properties: https://github.com/nodejs/node/blob/2adea16e394448c4c87b0639514f8babbeb7a080/lib/internal/util/comparisons.js#L290
11
12 return true
13}
node_modules/same-object/lib/same-map.js +70 -0
……@@ -0,0 +1,70 @@
1const same = require('../index.js')
2const isPrimitive = require('./is-primitive.js')
3const findLooseMatchingPrimitives = require('./find-loose-matching-primitives.js')
4
5module.exports = function sameMap (a, b, opts, memos) {
6 if (a.size !== b.size) return false
7
8 const set = new Set()
9
10 for (const [key, item1] of a) {
11 if (!isPrimitive(key)) {
12 set.add(key)
13 } else {
14 const item2 = b.get(key)
15 if (((item2 === undefined && !b.has(key)) || !same(item1, item2, opts, memos))) {
16 if (opts && opts.strict) return false
17
18 // Discard string, symbol, undefined, and null keys
19 if (!mapMightHaveLoosePrim(a, b, key, item1, memos)) return false
20
21 set.add(key)
22 }
23 }
24 }
25
26 if (set.size > 0) {
27 for (const [key, item] of b) {
28 if (!isPrimitive(key)) {
29 if (!mapHasEqualEntry(set, a, key, item, opts, memos)) {
30 return false
31 }
32 continue
33 }
34
35 if (opts && opts.strict) continue
36
37 if (a.has(key) && same(a.get(key), item, { strict: false }, memos)) continue
38
39 if (mapHasEqualEntry(set, a, key, item, { strict: false }, memos)) continue
40
41 return false
42 }
43
44 return set.size === 0
45 }
46
47 return true
48}
49
50function mapHasEqualEntry (set, a, key, bValue, opts, memos) {
51 for (const key2 of set) {
52 if (same(key, key2, opts, memos) && same(bValue, a.get(key2), opts, memos)) {
53 set.delete(key2)
54 return true
55 }
56 }
57
58 return false
59}
60
61function mapMightHaveLoosePrim (a, b, primitive, item, memos) {
62 const altValue = findLooseMatchingPrimitives(primitive)
63 if (altValue != null) return altValue
64
65 const bValue = b.get(altValue)
66 if (bValue === undefined && !b.has(altValue)) return false
67 if (!same(item, bValue, { strict: false }, memos)) return false
68
69 return !a.has(altValue) && same(item, bValue, { strict: false }, memos)
70}
node_modules/same-object/lib/same-regexp.js +3 -0
……@@ -0,0 +1,3 @@
1module.exports = function sameRegExp (a, b) {
2 return a.source === b.source && a.flags === b.flags
3}
node_modules/same-object/lib/same-set.js +64 -0
……@@ -0,0 +1,64 @@
1const same = require('../index.js')
2const isPrimitive = require('./is-primitive.js')
3const findLooseMatchingPrimitives = require('./find-loose-matching-primitives.js')
4
5module.exports = function sameSet (a, b, opts, memos) {
6 if (a.size !== b.size) return false
7
8 const set = new Set()
9
10 for (const aValue of a) {
11 if (!isPrimitive(aValue)) {
12 // Non-null object (non strict only: a not matching primitive)
13 set.add(aValue)
14 } else if (!b.has(aValue)) {
15 if (opts && opts.strict) return false
16
17 // Discard string, symbol, undefined, and null values
18 if (!setMightHaveLoosePrim(a, b, aValue)) return false
19
20 set.add(aValue)
21 }
22 }
23
24 if (set.size > 0) {
25 for (const bValue of b) {
26 if (!isPrimitive(bValue)) {
27 if (!setHasEqualElement(set, bValue, opts, memos)) {
28 return false
29 }
30 continue
31 }
32
33 if (opts && opts.strict) continue
34
35 if (a.has(bValue)) continue
36
37 if (setHasEqualElement(set, bValue, opts, memos)) continue
38
39 return false
40 }
41
42 return set.size === 0
43 }
44
45 return true
46}
47
48function setMightHaveLoosePrim (a, b, primitive) {
49 const altValue = findLooseMatchingPrimitives(primitive)
50 if (altValue != null) return altValue
51
52 return b.has(altValue) && !a.has(altValue)
53}
54
55function setHasEqualElement (set, val1, opts, memos) {
56 for (const val2 of set) {
57 if (same(val1, val2, opts, memos)) {
58 set.delete(val2)
59 return true
60 }
61 }
62
63 return false
64}
node_modules/same-object/package.json +24 -0
……@@ -0,0 +1,24 @@
1{
2 "name": "same-object",
3 "version": "1.0.2",
4 "description": "Determine if two objects are deeply equal",
5 "main": "index.js",
6 "scripts": {
7 "test": "standard && brittle test.js --coverage"
8 },
9 "repository": {
10 "type": "git",
11 "url": "https://github.com/holepunchto/same-object.git"
12 },
13 "author": "Lucas Barrena (LuKks)",
14 "license": "MIT",
15 "bugs": {
16 "url": "https://github.com/holepunchto/same-object/issues"
17 },
18 "homepage": "https://github.com/holepunchto/same-object",
19 "devDependencies": {
20 "brittle": "^3.1.1",
21 "deep-equal": "^2.2.0",
22 "standard": "^17.0.0"
23 }
24}
node_modules/same-object/test.js +1399 -0
……@@ -0,0 +1,1399 @@
1const test = require('brittle')
2const sameObject = require('./')
3const deepEqual = require('deep-equal')
4
5test.configure({ bail: true })
6
7// NOTE: most tests were copied and adapted from deep-equal library
8
9const safeBuffer = typeof Buffer === 'function' ? Buffer.from : null
10const buffersAreTypedArrays = typeof Buffer === 'function' && safeBuffer('') instanceof Uint8Array
11
12test('basic', function (t) {
13 t.ok(sameObject(1, '1'))
14 t.absent(sameObject(1, '1', { strict: true }))
15})
16
17test('basic helper', function (t) {
18 unlike(t, 1, '1')
19 alikeLoosely(t, 1, '1')
20})
21
22test('equal', function (t) {
23 alike(t,
24 { a: [2, 3], b: [4] },
25 { a: [2, 3], b: [4] },
26 'two equal objects'
27 )
28
29 alikeLoosely(t,
30 { a: 2, b: '4' },
31 { a: 2, b: 4 },
32 'two loosely equal, strictly inequal objects'
33 )
34
35 unlikeLoosely(t,
36 { a: 2, b: 4 },
37 { a: 2, B: 4 },
38 'two inequal objects'
39 )
40
41 alikeLoosely(t,
42 '-000',
43 false,
44 '`false` and `"-000"`'
45 )
46})
47
48test('Maps', function (t) {
49 alike(t,
50 new Map([['a', 1], ['b', 2]]),
51 new Map([['b', 2], ['a', 1]]),
52 'two equal Maps'
53 )
54
55 unlikeLoosely(t,
56 new Map([['a', [1, 2]]]),
57 new Map([['a', [2, 1]]]),
58 'two Maps with inequal values on the same key'
59 )
60
61 unlikeLoosely(t,
62 new Map([['a', 1]]),
63 new Map([['b', 1]]),
64 'two inequal Maps'
65 )
66
67 alike(t,
68 new Map([[{}, 3], [{}, 2], [{}, 1]]),
69 new Map([[{}, 1], [{}, 2], [{}, 3]]),
70 'two equal Maps in different orders with object keys'
71 )
72
73 alikeLoosely(t,
74 new Map([[undefined, undefined]]),
75 new Map([[undefined, null]]),
76 'undefined keys, nullish values, loosely equal, strictly inequal'
77 )
78
79 alike(t,
80 new Map([[{}, null], [true, 2], [{}, 1], [undefined, {}]]),
81 new Map([[{}, 1], [true, 2], [{}, null], [undefined, {}]]),
82 'two equal Maps in different orders with primitive keys'
83 )
84
85 alike(t,
86 new Map([[false, 3], [{}, 2], [{}, 1]]),
87 new Map([[{}, 1], [{}, 2], [false, 3]]),
88 'two equal Maps in different orders with a mix of keys'
89 )
90
91 alikeLoosely(t,
92 new Map([[null, undefined]]),
93 new Map([[null, null]]),
94 'null keys, nullish values, loosely equal, strictly inequal'
95 )
96
97 alikeLoosely(t,
98 new Map([[undefined, 3]]),
99 new Map([[null, 3]]),
100 'nullish keys, loosely equal, strictly inequal'
101 )
102
103 alike(t,
104 new Map([[{}, null], [true, 2], [{}, 1], [undefined, {}]]),
105 new Map([[{}, 1], [true, 2], [{}, null], [undefined, {}]]),
106 'two equal Maps in different orders with primitive keys'
107 )
108
109 alike(t,
110 new Map([[false, 3], [{}, 2], [{}, 1]]),
111 new Map([[{}, 1], [{}, 2], [false, 3]]),
112 'two equal Maps in different orders with a mix of keys'
113 )
114
115 unlikeLoosely(t,
116 new Map(),
117 new Map([[{}, 1]]),
118 'two inequal Maps'
119 )
120
121 unlikeLoosely(t,
122 new Map([[{}, null], [false, 3]]),
123 new Map([[{}, null], [true, 2]]),
124 'two inequal maps, same size, primitive key, start with object key'
125 )
126
127 unlikeLoosely(t,
128 new Map([[false, 3], [{}, null]]),
129 new Map([[true, 2], [{}, null]]),
130 'two inequal maps, same size, primitive key, start with primitive key'
131 )
132
133 alikeLoosely(t,
134 new Map([[undefined, null], ['+000', 2]]),
135 new Map([[null, undefined], [false, '2']]),
136 'primitive comparisons'
137 )
138})
139
140// +
141test('WeakMaps', function (t) {
142 alike(t,
143 new WeakMap([[Object, null], [Function, true]]),
144 new WeakMap([[Function, true], [Object, null]]),
145 'two equal WeakMaps'
146 )
147
148 alike(t,
149 new WeakMap([[Object, null]]),
150 new WeakMap([[Object, true]]),
151 'two WeakMaps with inequal values on the same key'
152 )
153
154 alike(t,
155 new WeakMap([[Object, null], [Function, true]]),
156 new WeakMap([[Object, null]]),
157 'two inequal WeakMaps'
158 )
159})
160
161test('Sets', function (t) {
162 alike(t,
163 new Set(['a', 1, 'b', 2]),
164 new Set(['b', 2, 'a', 1]),
165 'two equal Sets'
166 )
167
168 unlikeLoosely(t,
169 new Set(['a', 1]),
170 new Set(['b', 1]),
171 'two inequal Sets'
172 )
173
174 alike(t,
175 new Set([{}, 1, {}, {}, 2]),
176 new Set([{}, 1, {}, 2, {}]),
177 'two equal Sets in different orders'
178 )
179
180 unlikeLoosely(t,
181 new Set(),
182 new Set([1]),
183 'two inequally sized Sets'
184 )
185
186 alikeLoosely(t,
187 new Set([{ a: 1 }, 2]),
188 new Set(['2', { a: '1' }]),
189 'two loosely equal, strictly inequal Sets'
190 )
191
192 unlikeLoosely(t,
193 new Set([{ a: 1 }, 2]),
194 new Set(['2', { a: 2 }]),
195 'two inequal Sets'
196 )
197
198 alikeLoosely(t,
199 new Set([null, '', 1, 5, 2, false]),
200 new Set([undefined, 0, '5', true, '2', '-000']),
201 'more primitive comparisons'
202 )
203
204 alike(t,
205 new Set([1, 2]),
206 new Set([2, 1]),
207 'primitives in different keys'
208 )
209
210 alike(t,
211 new Set([{ a: 1 }, { b: 2 }]),
212 new Set([{ b: 2 }, { a: 1 }]),
213 'object values in different keys'
214 )
215
216 alike(t,
217 new Set([new Set([1, 2]), new Set([3, 4])]),
218 new Set([new Set([4, 3]), new Set([2, 1])]),
219 'Set of Sets, all in different keys'
220 )
221
222 unlikeLoosely(t,
223 new Set([{ a: 1 }, 1]),
224 new Set([{ a: 1 }, 2]),
225 'non primitive first, and non alike primitive later'
226 )
227
228 alikeLoosely(t,
229 new Set([{ a: 1 }, Infinity]),
230 new Set([{ a: 1 }, Infinity]),
231 'primitive that is not loose'
232 )
233
234 unlikeLoosely(t,
235 new Set([Symbol.for('hi')]),
236 new Set([Symbol.for('hi2')]),
237 'different symbols in a Set'
238 )
239})
240
241test('Set and Map', function (t) {
242 unlikeLoosely(t,
243 new Set(),
244 new Map(),
245 'Map and Set'
246 )
247
248 // +
249 /* const maplikeSet = new Set()
250 Object.defineProperty(maplikeSet, 'constructor', { enumerable: false, value: Map })
251 maplikeSet.__proto__ = Map.prototype // eslint-disable-line no-proto
252 unlikeLoosely(t,
253 maplikeSet,
254 new Map(),
255 'Map-like Set, and Map'
256 ) */
257})
258
259// +
260test('WeakSets', function (t) {
261 alike(t,
262 new WeakSet([Object, Function]),
263 new WeakSet([Function, Object]),
264 'two equal WeakSets'
265 )
266
267 alike(t,
268 new WeakSet([Object, Function]),
269 new WeakSet([Object]),
270 'two inequal WeakSets'
271 )
272})
273
274test('not equal', function (t) {
275 unlikeLoosely(t,
276 { x: 5, y: [6] },
277 { x: 5, y: 6 },
278 'two inequal objects are'
279 )
280})
281
282test('nested nulls', function (t) {
283 alike(t,
284 [null, null, null],
285 [null, null, null],
286 'same-length arrays of nulls'
287 )
288})
289
290test('objects with strings vs numbers', function (t) {
291 alikeLoosely(t,
292 [{ a: 3 }, { b: 4 }],
293 [{ a: '3' }, { b: '4' }],
294 'objects with equivalent string/number values'
295 )
296})
297
298test('non-objects', function (t) {
299 alike(t, 3, 3, 'same numbers', true, true, true)
300 alike(t, 'beep', 'beep', 'same strings', true, true, true)
301 alikeLoosely(t, '3', 3, 'numeric string and number', true, false)
302 unlikeLoosely(t, '3', [3], 'numeric string and array containing number', false, false)
303 unlikeLoosely(t, 3, [3], 'number and array containing number', false, false)
304})
305
306test('infinities', function (t) {
307 alike(t, Infinity, Infinity, '∞ and ∞', true, true, true)
308 alike(t, -Infinity, -Infinity, '-∞ and -∞', true, true, true)
309 unlikeLoosely(t, Infinity, -Infinity, '∞ and -∞', false, false)
310})
311
312test('arguments class', function (t) {
313 function getArgs () {
314 return arguments
315 }
316
317 alike(t,
318 getArgs(1, 2, 3),
319 getArgs(1, 2, 3),
320 'equivalent arguments objects are equal'
321 )
322
323 unlikeLoosely(t,
324 getArgs(1, 2, 3),
325 [1, 2, 3],
326 'array and arguments with same contents'
327 )
328
329 const args = getArgs()
330 const notArgs = tag({ length: 0 }, 'Arguments')
331 unlikeLoosely(t,
332 args,
333 notArgs,
334 'args and similar arraylike object'
335 )
336})
337
338test('Dates', function (t) {
339 const d0 = new Date(1387585278000)
340 const d1 = new Date('Fri Dec 20 2013 16:21:18 GMT-0800 (PST)')
341
342 alike(t, d0, d1, 'two Dates with the same timestamp', true, true)
343
344 d1.a = true
345
346 unlikeLoosely(t, d0, d1, 'two Dates with the same timestamp but different own properties', false, false)
347
348 t.test('overriding `getTime`', function (st) {
349 const a = new Date('2000')
350 const b = new Date('2000')
351 Object.defineProperty(a, 'getTime', { value: function () { return 5 } })
352 alike(st, a, b, 'two Dates with the same timestamp but one has overridden `getTime`', true, true)
353 })
354
355 // +
356 /* t.test('fake Date', { skip: !hasDunderProto }, function (st) {
357 const a = new Date(2000)
358 const b = tag(Object.create(
359 a.__proto__, // eslint-disable-line no-proto
360 Object.getOwnPropertyDescriptors(a)
361 ), 'Date')
362
363 unlikeLoosely(st,
364 a,
365 b,
366 'Date, and fake Date'
367 )
368 }) */
369
370 const a = new Date('2000')
371 const b = new Date('2000')
372 b.foo = true
373 unlikeLoosely(t,
374 a,
375 b,
376 'two identical Dates, one with an extra property'
377 )
378
379 unlikeLoosely(t,
380 new Date('2000'),
381 new Date('2001'),
382 'two inequal Dates'
383 )
384})
385
386test('buffers', { skip: typeof Buffer !== 'function' }, function (t) {
387 alike(t,
388 safeBuffer('xyz'),
389 safeBuffer('xyz'),
390 'buffers with same contents are equal'
391 )
392
393 unlikeLoosely(t,
394 safeBuffer('xyz'),
395 safeBuffer('xyy'),
396 'buffers with same length and different contents are inequal'
397 )
398
399 unlikeLoosely(t,
400 safeBuffer('xyz'),
401 safeBuffer('xy'),
402 'buffers with different length are inequal'
403 )
404
405 unlikeLoosely(t,
406 safeBuffer('abc'),
407 safeBuffer('xyz'),
408 'buffers with different contents'
409 )
410
411 const emptyBuffer = safeBuffer('')
412
413 unlikeLoosely(t,
414 emptyBuffer,
415 [],
416 'empty buffer and empty array'
417 )
418
419 t.test('bufferlikes', function (st) {
420 const fakeBuffer = {
421 0: 'a',
422 length: 1,
423 __proto__: emptyBuffer.__proto__, // eslint-disable-line no-proto
424 copy: emptyBuffer.copy,
425 slice: emptyBuffer.slice
426 }
427 Object.defineProperty(fakeBuffer, '0', { enumerable: false })
428 Object.defineProperty(fakeBuffer, 'length', { enumerable: false })
429 Object.defineProperty(fakeBuffer, 'copy', { enumerable: false })
430 Object.defineProperty(fakeBuffer, 'slice', { enumerable: false })
431
432 unlikeLoosely(st,
433 safeBuffer('a'),
434 fakeBuffer,
435 'real buffer, and mildly fake buffer'
436 )
437
438 st.test('bufferlike', function (s2t) {
439 const bufferlike = buffersAreTypedArrays ? new Uint8Array() : {}
440 Object.defineProperty(bufferlike, 'length', {
441 enumerable: false,
442 value: bufferlike.length || 0
443 })
444 Object.defineProperty(bufferlike, 'copy', {
445 enumerable: false,
446 value: emptyBuffer.copy
447 })
448 bufferlike.__proto__ = emptyBuffer.__proto__ // eslint-disable-line no-proto
449
450 alike(s2t,
451 emptyBuffer,
452 bufferlike,
453 'empty buffer and empty bufferlike'
454 )
455 s2t.end()
456 })
457
458 st.end()
459 })
460
461 t.end()
462})
463
464test('DataView', function (t) {
465 const view1 = new DataView(new ArrayBuffer(10))
466 const view2 = new DataView(new ArrayBuffer(10))
467
468 alike(t,
469 view1,
470 view2,
471 'two equals DataViews'
472 )
473
474 view1[3] = 7
475
476 unlike(t,
477 view1,
478 view2,
479 'two inequal DataViews'
480 )
481})
482
483test('Arrays', function (t) {
484 const a = []
485 const b = []
486 b.foo = true
487
488 unlikeLoosely(t,
489 a,
490 b,
491 'two identical arrays, one with an extra property'
492 )
493
494 const c = [undefined, 'test']
495 const d = []
496 d[1] = 'test'
497 unlikeLoosely(t, c, d, 'sparse array')
498
499 const e = [undefined, 'test', undefined, undefined, 'test2', undefined]
500 const f = []
501 e[1] = 'test'
502 e[4] = 'test2'
503 unlikeLoosely(t, e, f, 'sparse array')
504
505 const g = new Array(10)
506 const h = new Array(10)
507 g[2] = 'test'
508 g[5] = 'test2'
509 g[8] = 'test3'
510 h[2] = 'test'
511 h[5] = 'test2'
512 h[8] = 'test3'
513 alike(t, g, h, 'sparse array')
514
515 t.end()
516})
517
518test('booleans', function (t) {
519 alike(t,
520 true,
521 true,
522 'trues'
523 )
524
525 alike(t,
526 false,
527 false,
528 'falses'
529 )
530
531 unlikeLoosely(t,
532 true,
533 false,
534 'true and false'
535 )
536
537 t.end()
538})
539
540test('booleans and arrays', function (t) {
541 unlikeLoosely(t,
542 true,
543 [],
544 'true and an empty array',
545 false,
546 false
547 )
548 unlikeLoosely(t,
549 false,
550 [],
551 'false and an empty array'
552 )
553 t.end()
554})
555
556test('arrays initiated', function (t) {
557 const a0 = [
558 undefined,
559 null,
560 -1,
561 0,
562 1,
563 false,
564 true,
565 undefined,
566 '',
567 'abc',
568 null,
569 undefined
570 ]
571 const a1 = [
572 undefined,
573 null,
574 -1,
575 0,
576 1,
577 false,
578 true,
579 undefined,
580 '',
581 'abc',
582 null,
583 undefined
584 ]
585
586 alike(t,
587 a0,
588 a1,
589 'arrays with equal contents are equal'
590 )
591 t.end()
592})
593
594test('arrays assigned', function (t) {
595 const a0 = [
596 undefined,
597 null,
598 -1,
599 0,
600 1,
601 false,
602 true,
603 undefined,
604 '',
605 'abc',
606 null,
607 undefined
608 ]
609 const a1 = []
610
611 a1[0] = undefined
612 a1[1] = null
613 a1[2] = -1
614 a1[3] = 0
615 a1[4] = 1
616 a1[5] = false
617 a1[6] = true
618 a1[7] = undefined
619 a1[8] = ''
620 a1[9] = 'abc'
621 a1[10] = null
622 a1[11] = undefined
623 a1.length = 12
624
625 alike(t, a0, a1, 'a literal array and an assigned array', true, true)
626 t.end()
627})
628
629test('arrays push', function (t) {
630 const a0 = [
631 undefined,
632 null,
633 -1,
634 0,
635 1,
636 false,
637 true,
638 undefined,
639 '',
640 'abc',
641 null,
642 undefined
643 ]
644 const a1 = []
645
646 a1.push(undefined)
647 a1.push(null)
648 a1.push(-1)
649 a1.push(0)
650 a1.push(1)
651 a1.push(false)
652 a1.push(true)
653 a1.push(undefined)
654 a1.push('')
655 a1.push('abc')
656 a1.push(null)
657 a1.push(undefined)
658 a1.length = 12
659
660 alike(t, a0, a1, 'a literal array and a pushed array', true, true)
661 t.end()
662})
663
664test('null == undefined', function (t) {
665 alikeLoosely(t, null, undefined, 'null and undefined', true, false)
666 alikeLoosely(t, [null], [undefined], '[null] and [undefined]', true, false)
667
668 t.end()
669})
670
671// node 14 changed `deepEqual` to make two NaNs loosely equal
672test('NaNs', function (t) {
673 alike(t,
674 NaN,
675 NaN,
676 'two NaNs'
677 )
678
679 alike(t,
680 { a: NaN },
681 { a: NaN },
682 'two equiv objects with a NaN value'
683 )
684
685 unlikeLoosely(t, NaN, 1, 'NaN and 1', false, false)
686
687 t.end()
688})
689
690test('zeroes', function (t) {
691 alikeLoosely(t, 0, -0, '0 and -0', true, false)
692 unlike(t, 0, -0, '0 and -0', true, false)
693
694 alikeLoosely(t, { a: 0 }, { a: -0 }, 'two objects with a same-keyed 0/-0 value', true, false)
695 unlike(t, { a: 0 }, { a: -0 }, 'two objects with a same-keyed 0/-0 value', true, false)
696
697 t.end()
698})
699
700test('Object.create', function (t) {
701 const a = { a: 'A' }
702 const b = Object.create(a)
703 b.b = 'B'
704 const c = Object.create(a)
705 c.b = 'C'
706
707 unlikeLoosely(t,
708 b,
709 c,
710 'two objects with the same [[Prototype]] but a different own property'
711 )
712
713 t.end()
714})
715
716test('Object.create(null)', function (t) {
717 alike(t,
718 Object.create(null),
719 Object.create(null),
720 'two empty null objects'
721 )
722
723 alike(t,
724 Object.create(null, { a: { value: 'b' } }),
725 Object.create(null, { a: { value: 'b' } }),
726 'two null objects with the same property pair'
727 )
728
729 t.end()
730})
731
732test('regexes vs dates', function (t) {
733 const d = new Date(1387585278000)
734 const r = /abc/
735
736 unlikeLoosely(t, d, r, 'Date and RegExp', false, false)
737
738 t.end()
739})
740
741test('regexp', function (t) {
742 unlikeLoosely(t, /abc/, /xyz/, 'two different regexes', false, false)
743 alike(t, /abc/, /abc/, 'two abc regexes', true, true, false)
744 alike(t, /xyz/, /xyz/, 'two xyz regexes', true, true, false)
745 unlike(t, /abc/i, /def/g, 'two xyz regexes')
746
747 // +
748 /* t.test('fake RegExp', function (st) {
749 const a = /abc/g
750 const b = tag(Object.create(
751 a.__proto__, // eslint-disable-line no-proto
752 Object.getOwnPropertyDescriptors(a)
753 ), 'RegExp')
754
755 unlikeLoosely(st,a, b, 'regex and fake regex', false, false)
756
757 st.end()
758 }) */
759
760 const a = /abc/gi
761 const b = /abc/gi
762 b.foo = true
763 unlikeLoosely(t,
764 a,
765 b,
766 'two identical regexes, one with an extra property'
767 )
768
769 const c = /abc/g
770 const d = /abc/i
771 unlikeLoosely(t,
772 c,
773 d,
774 'two regexes with the same source but different flags'
775 )
776
777 t.end()
778})
779
780test('object literals', function (t) {
781 alikeLoosely(t,
782 { prototype: 2 },
783 { prototype: '2' },
784 'two loosely equal, strictly inequal prototype properties'
785 )
786
787 t.end()
788})
789
790test('arrays and objects', function (t) {
791 unlikeLoosely(t, [], {}, 'empty array and empty object', false, false)
792 unlikeLoosely(t, [], { length: 0 }, 'empty array and empty arraylike object', false, false)
793 unlikeLoosely(t, [1], { 0: 1 }, 'array and similar object', false, false)
794
795 t.end()
796})
797
798test('functions', function (t) {
799 function f () {}
800
801 alike(t, f, f, 'a function and itself', true, true, true)
802 alike(t, [f], [f], 'a function and itself in an array', true, true, true)
803
804 unlikeLoosely(t, function () {}, function () {}, 'two distinct functions', false, false, true)
805 unlikeLoosely(t, [function () {}], [function () {}], 'two distinct functions in an array', false, false, true)
806
807 unlikeLoosely(t, f, {}, 'function and object', false, false, true)
808 unlikeLoosely(t, [f], [{}], 'function and object in an array', false, false, true)
809
810 t.end()
811})
812
813test('Errors', function (t) {
814 alike(t, new Error('xyz'), new Error('xyz'), 'two errors of the same type with the same message', true, true, false)
815 unlikeLoosely(t, new Error('xyz'), new TypeError('xyz'), 'two errors of different types with the same message', false, false)
816 unlikeLoosely(t, new Error('xyz'), new Error('zyx'), 'two errors of the same type with a different message', false, false)
817
818 // +
819 /* t.test('errorlike', { skip: !Object.defineProperty }, function (st) {
820 const err = new Error('foo')
821 // TODO: add `__proto__` when brand check is available
822 const errorlike = tag({ message: err.message, stack: err.stack, name: err.name, constructor: err.constructor }, 'Error')
823 Object.defineProperty(errorlike, 'message', { enumerable: false })
824 Object.defineProperty(errorlike, 'stack', { enumerable: false })
825 Object.defineProperty(errorlike, 'name', { enumerable: false })
826 Object.defineProperty(errorlike, 'constructor', { enumerable: false })
827 st.absent(errorlike instanceof Error)
828 st.ok(err instanceof Error)
829 unlikeLoosely(st,
830 err,
831 errorlike,
832 'error, and errorlike object'
833 )
834
835 st.end()
836 }) */
837
838 // +
839 unlikeLoosely(t,
840 new Error('a'),
841 Object.assign(new Error('a'), { code: 10 }),
842 'two otherwise equal errors with different own properties'
843 )
844
845 // +
846 /* t.test('fake error', { skip: !process.env.ASSERT || !hasDunderProto }, function (st) {
847 const a = tag({
848 __proto__: null
849 }, 'Error')
850 const b = new RangeError('abc')
851 b.__proto__ = null // eslint-disable-line no-proto
852
853 unlikeLoosely(st,
854 a,
855 b,
856 'null object faking as an Error, RangeError with null proto'
857 )
858 st.end()
859 }) */
860
861 t.end()
862})
863
864test('object and null', function (t) {
865 unlikeLoosely(t,
866 {},
867 null,
868 'null and an object'
869 )
870
871 t.end()
872})
873
874test('error = Object', function (t) {
875 unlikeLoosely(t,
876 new Error('a'),
877 { message: 'a' }
878 )
879
880 t.end()
881})
882
883test('[[Prototypes]]', function (t) {
884 function C () {}
885 const instance = new C()
886 delete instance.constructor
887
888 alikeLoosely(t, {}, instance, 'two identical objects with different [[Prototypes]]', true, false)
889
890 t.test('Dates with different prototypes', function (st) {
891 const d1 = new Date(0)
892 const d2 = new Date(0)
893
894 alike(st, d1, d2, 'two dates with the same timestamp', true, true)
895
896 const newProto = {
897 __proto__: Date.prototype
898 }
899 d2.__proto__ = newProto // eslint-disable-line no-proto
900 st.ok(d2 instanceof Date, 'd2 is still a Date instance after tweaking [[Prototype]]')
901
902 alikeLoosely(st, d1, d2, 'two dates with the same timestamp and different [[Prototype]]', true, false)
903
904 st.end()
905 })
906
907 t.end()
908})
909
910test('toStringTag', function (t) {
911 const o1 = {}
912 t.is(Object.prototype.toString.call(o1), '[object Object]', 'o1: Symbol.toStringTag works')
913
914 const o2 = {}
915 t.is(Object.prototype.toString.call(o2), '[object Object]', 'o2: original Symbol.toStringTag works')
916
917 alike(t, o1, o2, 'two normal empty objects', true, true)
918
919 o2[Symbol.toStringTag] = 'jifasnif'
920 t.is(Object.prototype.toString.call(o2), '[object jifasnif]', 'o2: modified Symbol.toStringTag works')
921
922 unlikeLoosely(t, o1, o2, 'two normal empty objects with different toStringTags', false, false)
923
924 t.end()
925})
926
927test('boxed primitives', function (t) {
928 unlikeLoosely(t, Object(false), false, 'boxed and primitive `false`', false, false)
929 unlikeLoosely(t, Object(true), true, 'boxed and primitive `true`', false, false)
930 unlikeLoosely(t, Object(3), 3, 'boxed and primitive `3`', false, false)
931 unlikeLoosely(t, Object(NaN), NaN, 'boxed and primitive `NaN`', false, false)
932 unlikeLoosely(t, Object(''), '', 'boxed and primitive `""`', false, false)
933 unlikeLoosely(t, Object('str'), 'str', 'boxed and primitive `"str"`', false, false)
934
935 t.test('symbol', function (st) {
936 const s = Symbol('')
937 unlikeLoosely(st, Object(s), s, 'boxed and primitive `Symbol()`', false, false)
938 st.end()
939 })
940
941 t.test('bigint', function (st) {
942 const hhgtg = BigInt(42)
943 unlikeLoosely(st, Object(hhgtg), hhgtg, 'boxed and primitive `BigInt(42)`', false, false)
944 st.end()
945 })
946
947 // +
948 /* t.test('`valueOf` is called for boxed primitives', function (st) {
949 const a = Object(5)
950 a.valueOf = function () { throw new Error('failed') }
951 const b = Object(5)
952 b.valueOf = function () { throw new Error('failed') }
953
954 unlikeLoosely(st, a, b, 'two boxed numbers with a thrower valueOf', false, false)
955
956 st.end()
957 }) */
958
959 t.end()
960})
961
962test('getters', function (t) {
963 const a = {}
964 Object.defineProperty(a, 'a', { enumerable: true, get: function () { return 5 } })
965 const b = {}
966 Object.defineProperty(b, 'a', { enumerable: true, get: function () { return 6 } })
967
968 unlikeLoosely(t, a, b, 'two objects with the same getter but producing different values', false, false)
969
970 t.end()
971})
972
973test('fake arrays: extra keys will be tested', function (t) {
974 const a = tag({
975 __proto__: Array.prototype,
976 0: 1,
977 1: 1,
978 2: 'broken',
979 length: 2
980 }, 'Array')
981
982 if (Object.defineProperty) {
983 Object.defineProperty(a, 'length', {
984 enumerable: false
985 })
986 }
987
988 unlikeLoosely(t, a, [1, 1], 'fake and real array with same contents and [[Prototype]]', false, false)
989
990 const b = tag(/abc/, 'Array')
991 b.__proto__ = Array.prototype // eslint-disable-line no-proto
992 b.length = 3
993 if (Object.defineProperty) {
994 Object.defineProperty(b, 'length', {
995 enumerable: false
996 })
997 }
998 unlikeLoosely(t, b, ['a', 'b', 'c'], 'regex faking as array, and array', false, false)
999
1000 t.end()
1001})
1002
1003test('circular references', function (t) {
1004 const b = {}
1005 b.b = b
1006
1007 const c = {}
1008 c.b = c
1009
1010 alike(t,
1011 b,
1012 c,
1013 'two self-referencing objects'
1014 )
1015
1016 const d = {}
1017 d.a = 1
1018 d.b = d
1019
1020 const e = {}
1021 e.a = 1
1022 e.b = e.a
1023
1024 unlikeLoosely(t,
1025 d,
1026 e,
1027 'two deeply self-referencing objects'
1028 )
1029
1030 t.end()
1031})
1032
1033test('TypedArrays', function (t) {
1034 // +
1035 /* t.test('Buffer faked as Uint8Array', function (st) {
1036 const a = safeBuffer('test')
1037 const b = tag(Object.create(
1038 a.__proto__, // eslint-disable-line no-proto
1039 Object.assign(Object.getOwnPropertyDescriptors(a), {
1040 length: {
1041 enumerable: false,
1042 value: 4
1043 }
1044 })
1045 ), 'Uint8Array')
1046
1047 unlikeLoosely(st,
1048 a,
1049 b,
1050 'Buffer and Uint8Array'
1051 )
1052
1053 st.end()
1054 }) */
1055
1056 // +
1057 /* t.test('one TypedArray faking as another', { skip: !hasDunderProto }, function (st) {
1058 const a = new Uint8Array(10)
1059 const b = tag(new Int8Array(10), 'Uint8Array')
1060 b.__proto__ = Uint8Array.prototype // eslint-disable-line no-proto
1061
1062 unlikeLoosely(st,
1063 a,
1064 b,
1065 'Uint8Array, and Int8Array pretending to be a Uint8Array'
1066 )
1067
1068 st.end()
1069 }) */
1070
1071 t.test('ArrayBuffers', { skip: typeof ArrayBuffer !== 'function' }, function (st) {
1072 const buffer1 = new ArrayBuffer(8) // initial value of 0's
1073 const buffer2 = new ArrayBuffer(8) // initial value of 0's
1074
1075 const view1 = new Int8Array(buffer1)
1076 const view2 = new Int8Array(buffer2)
1077
1078 alike(st,
1079 view1,
1080 view2,
1081 'Int8Arrays of similar ArrayBuffers'
1082 )
1083
1084 alike(st,
1085 buffer1,
1086 buffer2,
1087 'similar ArrayBuffers'
1088 )
1089
1090 for (let i = 0; i < view1.byteLength; i += 1) {
1091 view1[i] = 9 // change all values to 9's
1092 }
1093
1094 unlikeLoosely(st,
1095 view1,
1096 view2,
1097 'Int8Arrays of different ArrayBuffers'
1098 )
1099
1100 unlikeLoosely(st,
1101 buffer1,
1102 buffer2,
1103 'different ArrayBuffers'
1104 )
1105
1106 // node < 0.11 has a nonconfigurable own byteLength property
1107 t.test('lies about byteLength', { skip: !('byteLength' in ArrayBuffer.prototype) }, function (s2t) {
1108 const empty4 = new ArrayBuffer(4)
1109 const empty6 = new ArrayBuffer(6)
1110 Object.defineProperty(empty6, 'byteLength', { value: 4 })
1111
1112 unlikeLoosely(s2t,
1113 empty4,
1114 empty6,
1115 'different-length ArrayBuffers, one lying'
1116 )
1117 s2t.end()
1118 })
1119
1120 st.end()
1121 })
1122
1123 t.test('SharedArrayBuffers', { skip: typeof SharedArrayBuffer !== 'function' }, function (st) {
1124 const buffer1 = new SharedArrayBuffer(8) // initial value of 0's
1125 const buffer2 = new SharedArrayBuffer(8) // initial value of 0's
1126
1127 const view1 = new Int8Array(buffer1)
1128 const view2 = new Int8Array(buffer2)
1129
1130 alike(st,
1131 view1,
1132 view2,
1133 'Int8Arrays of similar SharedArrayBuffers'
1134 )
1135
1136 alike(st,
1137 buffer1,
1138 buffer2,
1139 'similar SharedArrayBuffers'
1140 )
1141
1142 for (let i = 0; i < view1.byteLength; i += 1) {
1143 view1[i] = 9 // change all values to 9's
1144 }
1145
1146 unlikeLoosely(st,
1147 view1,
1148 view2,
1149 'Int8Arrays of different SharedArrayBuffers'
1150 )
1151
1152 // +
1153 /* unlikeLoosely(st,
1154 buffer1,
1155 buffer2,
1156 'different SharedArrayBuffers'
1157 ) */
1158
1159 // +
1160 /* t.test('lies about byteLength', { skip: !('byteLength' in SharedArrayBuffer.prototype) }, function (s2t) {
1161 const empty4 = new SharedArrayBuffer(4)
1162 const empty6 = new SharedArrayBuffer(6)
1163 Object.defineProperty(empty6, 'byteLength', { value: 4 })
1164
1165 unlikeLoosely(s2t,
1166 empty4,
1167 empty6,
1168 'different-length SharedArrayBuffers, one lying'
1169 )
1170 s2t.end()
1171 }) */
1172
1173 st.end()
1174 })
1175
1176 t.end()
1177})
1178
1179test('String object', function (t) {
1180 alike(t,
1181 new String('hi'), // eslint-disable-line no-new-wrappers
1182 new String('hi'), // eslint-disable-line no-new-wrappers
1183 'two same String objects'
1184 )
1185
1186 unlike(t,
1187 new String('hi'), // eslint-disable-line no-new-wrappers
1188 new String('hi2'), // eslint-disable-line no-new-wrappers
1189 'two different String objects'
1190 )
1191})
1192
1193test('Number object', function (t) {
1194 alike(t,
1195 new Number(1), // eslint-disable-line no-new-wrappers
1196 new Number(1), // eslint-disable-line no-new-wrappers
1197 'two same Number objects'
1198 )
1199
1200 t.absent(sameObject(
1201 new Number(1), // eslint-disable-line no-new-wrappers
1202 new Number(2) // eslint-disable-line no-new-wrappers
1203 ), 'two different Number objects')
1204})
1205
1206test('Boolean object', function (t) {
1207 alike(t,
1208 new Boolean(true), // eslint-disable-line no-new-wrappers
1209 new Boolean(true), // eslint-disable-line no-new-wrappers
1210 'two same Boolean objects'
1211 )
1212
1213 t.absent(sameObject(
1214 new Boolean(true), // eslint-disable-line no-new-wrappers
1215 new Boolean(false) // eslint-disable-line no-new-wrappers
1216 ), 'two different Boolean objects')
1217})
1218
1219test('objects', function (t) {
1220 t.is(sameObject({ foo: 1 }, { foo: 1 }), true)
1221 t.is(sameObject({ foo: 1 }, { foo: 1, bar: true }), false)
1222 t.is(sameObject({ foo: 1, nested: { a: 1 } }, { foo: 1, nested: { a: 1 } }), true)
1223 t.is(sameObject([{ a: 1 }, { b: 1 }], [{ a: 1 }, { b: 1 }]), true)
1224})
1225
1226test('typed arrays', function (t) {
1227 t.is(sameObject(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3])), true)
1228 t.is(sameObject(new Uint8Array([1, 2, 1]), new Uint8Array([1, 2, 3])), false)
1229})
1230
1231test('symbols', function (t) {
1232 alike(t, Symbol.for('hello'), Symbol.for('hello'), 'same symbol', true, true)
1233 unlike(t, Symbol.for('hello'), Symbol.for('holas'), 'diff symbol', false, true)
1234
1235 alike(t, [Symbol.for('hello')], [Symbol.for('hello')], 'symbol inside object', true, true)
1236 alike(t, { sym: Symbol.for('hello') }, { sym: Symbol.for('hello') }, 'symbol inside object', true, true)
1237
1238 unlike(t, { sym: Symbol.for('hello') }, { sym: Symbol.for('holas') }, 'diff symbol inside object', false, true)
1239})
1240
1241test('numbers', function (t) {
1242 alike(t, BigInt('9007199254740991'), BigInt('9007199254740991'), 'BigInt', true, true)
1243 alike(t, Infinity, Infinity, 'Infinity', true, true)
1244
1245 // Note: deep-equal library fails, but Node's assert version passes, so we follow Node standard
1246 t.ok(sameObject(NaN, NaN, { strict: true }), 'NaN (alike)')
1247 t.ok(sameObject(NaN, NaN, { strict: false }), 'NaN (alike loosely)')
1248})
1249
1250// +
1251test.skip('symbol as key', function (t) {
1252 alike(t, { a: true, [Symbol.for('aa')]: true }, { a: true, [Symbol.for('aa')]: true })
1253 unlike(t, { a: true, [Symbol.for('aa')]: true }, { a: true, [Symbol.for('cc')]: true })
1254})
1255
1256test('promises', function (t) {
1257 const promise = new Promise(noop)
1258 alike(t, promise, promise, 'two promises with same reference')
1259
1260 // +
1261 /* alike(t,
1262 new Promise(noop),
1263 new Promise(noop),
1264 'two promises'
1265 )
1266
1267 alike(t,
1268 Promise.resolve('hi'),
1269 Promise.resolve('hi'),
1270 'resolve with same primitive'
1271 )
1272
1273 unlike(t,
1274 Promise.resolve('hi1'),
1275 Promise.resolve('hi2'),
1276 'resolve with different primitive'
1277 )
1278
1279 alike(t,
1280 Promise.resolve({ a: 1 }),
1281 Promise.resolve({ a: 1 }),
1282 'resolve with same objects'
1283 )
1284
1285 unlike(t,
1286 Promise.resolve({ a: 1 }),
1287 Promise.resolve({ a: 2 }),
1288 'resolve with different objects'
1289 ) */
1290
1291 function noop (resolve, reject) {}
1292})
1293
1294test('functions', function (t) {
1295 unlike(t, function () {}, function () {}, 'two different functions', true, true)
1296
1297 const fn = function () {}
1298 alike(t, fn, fn, 'two same functions', true, true)
1299})
1300
1301// + merge this case with the other one
1302test('circular references x2', function (t) {
1303 const obj = { root: null }
1304 obj.root = obj
1305 const obj2 = { root: null }
1306 obj2.root = obj2
1307 alike(t, obj, obj2)
1308
1309 const obj3 = [{ root: null }]
1310 obj3.root = obj3
1311 const obj4 = [{ root: null }]
1312 obj4.root = obj4
1313 alike(t, obj3, obj4)
1314
1315 const obj5 = { sub: { root: null, sub2: { obj2, obj3 } } }
1316 obj5.sub.root = obj5
1317 const obj6 = { sub: { root: null, sub2: { obj2, obj3 } } }
1318 obj6.sub.root = obj6
1319 alike(t, obj5, obj6)
1320
1321 const obj7 = [{ root: null }]
1322 obj7[0].root = obj7
1323 const obj8 = [{ root: null }]
1324 obj8[0].root = obj8
1325 alike(t, obj7, obj8)
1326
1327 const o = {}
1328 const obj9 = { a: o, b: o }
1329 const o2 = {}
1330 const obj10 = { a: o2, b: o2 }
1331 alike(t, obj9, obj10)
1332
1333 const obj11 = [o, o]
1334 const obj12 = [o, o]
1335 alike(t, obj11, obj12)
1336
1337 const obj13 = [o, obj, o]
1338 obj13.obj = obj
1339 const obj14 = [o, obj, o]
1340 obj14.obj = obj
1341 alike(t, obj13, obj14)
1342})
1343
1344function alike (t, a, b, comment = '') {
1345 try {
1346 t.ok(deepEqual(a, b, { strict: true }), '[deep-equal normal] ' + comment)
1347 t.ok(deepEqual(b, a, { strict: true }), '[deep-equal reversed] ' + comment)
1348 } catch (error) {
1349 if (error.message === 'Cannot convert a Symbol value to a string') t.comment('alike => ' + error.message + ' [deep-equal] ' + comment)
1350 else throw error
1351 }
1352
1353 t.ok(sameObject(a, b, { strict: true }), '[same-object normal] ' + comment)
1354 t.ok(sameObject(b, a, { strict: true }), '[same-object reversed] ' + comment)
1355}
1356
1357function alikeLoosely (t, a, b, comment = '') { // eslint-disable-line no-unused-vars
1358 try {
1359 t.ok(deepEqual(a, b, { strict: false }), '[deep-equal normal] ' + comment)
1360 t.ok(deepEqual(b, a, { strict: false }), '[deep-equal reversed] ' + comment)
1361 } catch (error) {
1362 if (error.message === 'Cannot convert a Symbol value to a string') t.comment('alike loosely => ' + error.message + ' [deep-equal] ' + comment)
1363 else throw error
1364 }
1365
1366 t.ok(sameObject(a, b, { strict: false }), '[same-object normal] ' + comment)
1367 t.ok(sameObject(b, a, { strict: false }), '[same-object reversed] ' + comment)
1368}
1369
1370function unlike (t, a, b, comment = '') {
1371 try {
1372 t.absent(deepEqual(a, b, { strict: true }), '[deep-equal normal] ' + comment)
1373 t.absent(deepEqual(b, a, { strict: true }), '[deep-equal reversed] ' + comment)
1374 } catch (error) {
1375 if (error.message === 'Cannot convert a Symbol value to a string') t.comment('unlike => ' + error.message + ' [deep-equal] ' + comment)
1376 else throw error
1377 }
1378
1379 t.absent(sameObject(a, b, { strict: true }), '[same-object normal] ' + comment)
1380 t.absent(sameObject(b, a, { strict: true }), '[same-object reversed] ' + comment)
1381}
1382
1383function unlikeLoosely (t, a, b, comment = '') { // eslint-disable-line no-unused-vars
1384 try {
1385 t.absent(deepEqual(a, b, { strict: false }), '[deep-equal normal] ' + comment)
1386 t.absent(deepEqual(b, a, { strict: false }), '[deep-equal reversed] ' + comment)
1387 } catch (error) {
1388 if (error.message === 'Cannot convert a Symbol value to a string') t.comment('unlike loosely => ' + error.message + ' [deep-equal] ' + comment)
1389 else throw error
1390 }
1391
1392 t.absent(sameObject(a, b, { strict: false }), '[same-object normal] ' + comment)
1393 t.absent(sameObject(b, a, { strict: false }), '[same-object reversed] ' + comment)
1394}
1395
1396function tag (obj, value) {
1397 Object.defineProperty(obj, Symbol.toStringTag, { value })
1398 return obj
1399}
node_modules/shuffled-priority-queue/.travis.yml +6 -0
……@@ -0,0 +1,6 @@
1language: node_js
2node_js:
3 - '6'
4 - '8'
5 - '10'
6
node_modules/shuffled-priority-queue/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2017 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/shuffled-priority-queue/README.md +116 -0
……@@ -0,0 +1,116 @@
1# shuffled-priority-queue
2
3A priority queue that shuffles elements with the same priority.
4
5```
6npm install shuffled-priority-queue
7```
8
9[![Build Status](https://travis-ci.org/mafintosh/shuffled-priority-queue.svg?branch=master)](https://travis-ci.org/mafintosh/shuffled-priority-queue)
10
11## Usage
12
13``` js
14const spq = require('shuffled-priority-queue')
15const queue = spq()
16
17queue.add({
18 priority: 0,
19 value: 'hello'
20})
21
22queue.add({
23 priority: 0,
24 value: 'world'
25})
26
27queue.add({
28 priority: 1,
29 value: 'welt'
30})
31
32queue.add({
33 priority: 2,
34 value: 'verden'
35})
36
37console.log(queue.shift()) // returns {value: 'verden'}
38console.log(queue.shift()) // returns {value: 'welt'}
39console.log(queue.shift()) // returns {value: 'hello'} or {value: 'world'}
40console.log(queue.shift()) // returns {value: 'hello'} or {value: 'world'}
41console.log(queue.shift()) // returns null (empty queue)
42```
43
44## API
45
46#### `const queue = spq()`
47
48Create a new queue.
49
50#### `value = queue.add(value)`
51
52Add a new value to the queue. The value is returned for convenience
53If you set `value.priority` to a number, it'll be added to the queue at that priority.
54
55#### `queue.remove(value)`
56
57Remove a value from the queue.
58
59#### `bool = queue.has(value)`
60
61Check if a value is in the queue.
62
63#### `value = queue.shift()`
64
65Shift the next value off the queue.
66
67The value returned will have the highest priority off the queue.
68If multiple values have the same priority a random one is returned.
69
70#### `value = queue.head()`
71
72Same as `shift()` but does not mutate the queue.
73
74#### `value = queue.pop()`
75
76Same as `shift()` but returns a value with the lowest priority.
77
78#### `value = queue.tail()`
79
80Same as `pop()` but does not mutate the queue.
81
82#### `queue.length`
83
84Property containing how many items are in the queue
85
86#### `for (const value of queue)`
87
88Iterate the queue from highest priority to lowest using the `for of` syntax
89
90#### `value = queue.next([prevValue])`
91
92Iterate the queue from highest priority to lowest.
93
94``` js
95let prevValue = null
96
97while (prevValue = queue.next(prevValue)) {
98 console.log('value:', prevValue)
99}
100```
101
102#### `value = queue.prev([prevValue])`
103
104Iterate the queue from lowest priority to highest.
105
106``` js
107let prevValue = null
108
109while (prevValue = queue.prev(prevValue)) {
110 console.log('value:', prevValue)
111}
112```
113
114## License
115
116MIT
node_modules/shuffled-priority-queue/example.js +28 -0
……@@ -0,0 +1,28 @@
1var spq = require('./')
2var queue = spq()
3
4queue.add({
5 priority: 0,
6 value: 'hello'
7})
8
9queue.add({
10 priority: 0,
11 value: 'world'
12})
13
14queue.add({
15 priority: 1,
16 value: 'welt'
17})
18
19queue.add({
20 priority: 2,
21 value: 'verden'
22})
23
24console.log(queue.pop()) // returns {value: 'verden'}
25console.log(queue.pop()) // returns {value: 'welt'}
26console.log(queue.pop()) // returns {value: 'hello'} or {value: 'world'}
27console.log(queue.pop()) // returns {value: 'hello'} or {value: 'world'}
28console.log(queue.pop()) // returns null (empty queue)
node_modules/shuffled-priority-queue/index.js +134 -0
……@@ -0,0 +1,134 @@
1const set = require('unordered-set')
2
3module.exports = opts => new ShuffledPriorityQueue(opts)
4
5class ShuffledPriorityQueue {
6 constructor (opts) {
7 this.priorities = []
8 this.equals = (opts && opts.equals) || null
9 }
10
11 get length () {
12 return this.priorities.reduce(add, 0)
13 }
14
15 [Symbol.iterator] () {
16 return new Iterator(this)
17 }
18
19 head () {
20 for (let i = this.priorities.length - 1; i >= 0; i--) {
21 const q = this.priorities[i]
22 if (q.length) return shuffle(q, 0)
23 }
24 return null
25 }
26
27 tail () {
28 for (let i = 0; i < this.priorities.length; i++) {
29 const q = this.priorities[i]
30 if (q.length) return shuffle(q, 0)
31 }
32 return null
33 }
34
35 prev (prev) {
36 if (!prev) return this.tail()
37 return next(this.priorities, prev, 1)
38 }
39
40 next (prev) {
41 if (!prev) return this.head()
42 return next(this.priorities, prev, -1)
43 }
44
45 shift () {
46 return this.remove(this.head())
47 }
48
49 pop () {
50 return this.remove(this.tail())
51 }
52
53 add (val) {
54 const prio = val.priority || 0
55 while (prio >= this.priorities.length) this.priorities.push([])
56 set.add(this.priorities[prio], val)
57 return val
58 }
59
60 remove (val) {
61 if (!val) return null
62
63 if (val._index === undefined) {
64 val = this.find(val)
65 if (!val) return null
66 }
67
68 return set.remove(this.priorities[val.priority || 0], val)
69 }
70
71 has (val) {
72 if (val._index === undefined) return this.find(val)
73 const priority = val.priority || 0
74 if (priority >= this.priorities.length) return false
75 return set.has(this.priorities[priority], val)
76 }
77
78 find (val) {
79 if (val._index !== undefined) return val
80
81 const prio = val.priority || 0
82 const qs = this.priorities
83 if (prio >= qs.length) return null
84
85 const q = qs[prio]
86
87 for (let i = 0; i < q.length; i++) {
88 if (this.equals(q[i], val)) return q[i]
89 }
90
91 return null
92 }
93}
94
95class Iterator {
96 constructor (queue) {
97 this.prev = null
98 this.queue = queue
99 }
100
101 next () {
102 const next = this.queue.next(this.prev)
103 this.prev = next
104 return { done: !next, value: next }
105 }
106}
107
108function shuffle (q, i) {
109 const ran = i + Math.floor(Math.random() * (q.length - i))
110 set.swap(q, q[ran], q[i])
111 return q[i]
112}
113
114function next (queues, prev, inc) {
115 let i = prev.priority || 0
116 let j = (prev._index || 0) + 1
117
118 while (true) {
119 if (i < 0 || i >= queues.length) return null
120 const q = queues[i]
121
122 if (j >= q.length) {
123 i += inc
124 j = 0
125 continue
126 }
127
128 return shuffle(q, j)
129 }
130}
131
132function add (len, b) {
133 return len + b.length
134}
node_modules/shuffled-priority-queue/package.json +26 -0
……@@ -0,0 +1,26 @@
1{
2 "name": "shuffled-priority-queue",
3 "version": "2.1.0",
4 "description": "A priority queue that shuffles elements with the same priority.",
5 "main": "index.js",
6 "scripts": {
7 "test": "standard && tape test.js"
8 },
9 "dependencies": {
10 "unordered-set": "^2.0.1"
11 },
12 "devDependencies": {
13 "standard": "^12.0.1",
14 "tape": "^4.9.1"
15 },
16 "repository": {
17 "type": "git",
18 "url": "https://github.com/mafintosh/shuffled-priority-queue.git"
19 },
20 "author": "Mathias Buus (@mafintosh)",
21 "license": "MIT",
22 "bugs": {
23 "url": "https://github.com/mafintosh/shuffled-priority-queue/issues"
24 },
25 "homepage": "https://github.com/mafintosh/shuffled-priority-queue"
26}
node_modules/shuffled-priority-queue/test.js +164 -0
……@@ -0,0 +1,164 @@
1const spq = require('./')
2const tape = require('tape')
3
4tape('different prios', function (t) {
5 const queue = spq()
6
7 const a = queue.add({
8 hello: 'world',
9 priority: 0
10 })
11
12 const b = queue.add({
13 hej: 'verden',
14 priority: 1
15 })
16
17 t.ok(queue.has(b))
18 t.same(queue.length, 2)
19 t.same(queue.shift(), b)
20 t.ok(!queue.has(b))
21 t.same(queue.length, 1)
22 t.same(queue.shift(), a)
23 t.same(queue.length, 0)
24 t.same(queue.shift(), null)
25 t.end()
26})
27
28tape('same prios', function (t) {
29 const queue = spq()
30
31 const a = queue.add({
32 hello: 'world',
33 priority: 0
34 })
35
36 const b = queue.add({
37 hello: 'verden',
38 priority: 0
39 })
40
41 const c = queue.add({
42 hej: 'verden',
43 priority: 1
44 })
45
46 t.same(queue.shift(), c)
47
48 let head = queue.shift()
49 t.ok(head === a || head === b)
50
51 head = queue.shift()
52 t.ok(head === a || head === b)
53
54 t.same(queue.shift(), null)
55 t.end()
56})
57
58tape('next', function (t) {
59 const queue = spq()
60
61 const a = queue.add({
62 hello: 'world',
63 priority: 0
64 })
65
66 const b = queue.add({
67 hello: 'verden',
68 priority: 0
69 })
70
71 const c = queue.add({
72 hej: 'verden',
73 priority: 1
74 })
75
76 t.same(queue.next(), c)
77
78 let value = queue.next(c)
79 t.ok(value === a || value === b)
80
81 const old = value
82 value = queue.next(value)
83 t.ok(old !== value)
84 t.ok(value === a || value === b)
85
86 t.same(queue.next(value), null)
87 t.end()
88})
89
90tape('prev', function (t) {
91 const queue = spq()
92
93 const a = queue.add({
94 hello: 'world',
95 priority: 0
96 })
97
98 const b = queue.add({
99 hello: 'verden',
100 priority: 0
101 })
102
103 const c = queue.add({
104 hej: 'verden',
105 priority: 1
106 })
107
108 let tail = queue.prev()
109 t.ok(tail === a || tail === b)
110
111 const old = tail
112 tail = queue.prev(tail)
113 t.ok(old !== tail)
114 t.ok(tail === a || tail === b)
115
116 tail = queue.prev(tail)
117 t.same(tail, c)
118
119 t.same(queue.prev(tail), null)
120 t.end()
121})
122
123tape('equals', function (t) {
124 const queue = spq({
125 equals: function (a, b) {
126 return a.hello === b.hello
127 }
128 })
129
130 queue.add({
131 hello: 'world'
132 })
133
134 t.same(queue.head().hello, 'world')
135
136 queue.remove({
137 hello: 'world'
138 })
139
140 t.same(queue.head(), null)
141 t.end()
142})
143
144tape('iterator', function (t) {
145 t.plan(5)
146
147 const queue = spq()
148 const seen = {}
149
150 queue.add({ priority: 0, hi: 'a' })
151 queue.add({ priority: 0, hi: 'b' })
152 queue.add({ priority: 1, hi: 'c' })
153 queue.add({ priority: 2, hi: 'd' })
154
155 let prev = 3
156
157 for (const value of queue) {
158 t.ok(prev >= value.priority)
159 prev = value.priority
160 seen[value.hi] = true
161 }
162
163 t.same(seen, { a: true, b: true, c: true, d: true })
164})
node_modules/stackframe/LICENSE +19 -0
……@@ -0,0 +1,19 @@
1Copyright (c) 2017 Eric Wendelin and other contributors
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7of the Software, and to permit persons to whom the Software is furnished to do
8so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
node_modules/stackframe/README.md +79 -0
……@@ -0,0 +1,79 @@
1stackframe
2==========
3## JS Object representation of a stack frame
4
5[![Build Status](https://img.shields.io/github/workflow/status/stacktracejs/stackframe/Continuous%20Integration/master?logo=github&style=flat-square)](https://github.com/stacktracejs/stackframe/actions?query=workflow%3AContinuous+Integration+branch%3Amaster)
6[![Coverage Status](https://img.shields.io/coveralls/stacktracejs/stackframe.svg?style=flat-square)](https://coveralls.io/r/stacktracejs/stackframe?branch=master)
7[![GitHub license](https://img.shields.io/github/license/stacktracejs/stackframe.svg?style=flat-square)](https://opensource.org/licenses/MIT)
8[![dependencies](https://img.shields.io/badge/dependencies-0-green.svg?style=flat-square)](https://github.com/stacktracejs/stackframe/releases)
9[![gzip size](https://img.shields.io/badge/gzipped-0.96k-green.svg?style=flat-square)](https://github.com/stacktracejs/stackframe/releases)
10[![module format](https://img.shields.io/badge/module%20format-umd-lightgrey.svg?style=flat-square&colorB=ff69b4)](https://github.com/stacktracejs/stackframe/releases)
11[![code of conduct](https://img.shields.io/badge/code%20of-conduct-lightgrey.svg?style=flat-square&colorB=ff69b4)](http://todogroup.org/opencodeofconduct/#stacktrace.js/me@eriwen.com)
12
13Underlies functionality of other modules within [stacktrace.js](https://www.stacktracejs.com).
14
15Written to closely resemble StackFrame representations in [Gecko](http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14) and [V8](https://github.com/v8/v8/wiki/Stack%20Trace%20API)
16
17## Usage
18```js
19// Create StackFrame and set properties
20var stackFrame = new StackFrame({
21 functionName: 'funName',
22 args: ['args'],
23 fileName: 'http://localhost:3000/file.js',
24 lineNumber: 1,
25 columnNumber: 3288,
26 isEval: true,
27 isNative: false,
28 source: 'ORIGINAL_STACK_LINE'
29 evalOrigin: new StackFrame({functionName: 'withinEval', lineNumber: 2, columnNumber: 43})
30});
31
32stackFrame.functionName // => "funName"
33stackFrame.setFunctionName('newName')
34stackFrame.getFunctionName() // => "newName"
35
36stackFrame.args // => ["args"]
37stackFrame.setArgs([])
38stackFrame.getArgs() // => []
39
40stackFrame.fileName // => 'http://localhost:3000/file.min.js'
41stackFrame.setFileName('http://localhost:3000/file.js')
42stackFrame.getFileName() // => 'http://localhost:3000/file.js'
43
44stackFrame.lineNumber // => 1
45stackFrame.setLineNumber(325)
46stackFrame.getLineNumber() // => 325
47
48stackFrame.columnNumber // => 3288
49stackFrame.setColumnNumber(20)
50stackFrame.getColumnNumber() // => 20
51
52stackFrame.source // => 'ORIGINAL_STACK_LINE'
53stackFrame.setSource('NEW_SOURCE')
54stackFrame.getSource() // => 'NEW_SOURCE'
55
56stackFrame.isEval // => true
57stackFrame.setIsEval(false)
58stackFrame.getIsEval() // => false
59
60stackFrame.isNative // => false
61stackFrame.setIsNative(true)
62stackFrame.getIsNative() // => true
63
64stackFrame.evalOrigin // => StackFrame({functionName: 'withinEval', lineNumber: ...})
65stackFrame.setEvalOrigin({functionName: 'evalFn', fileName: 'anonymous'})
66stackFrame.getEvalOrigin().getFunctionName() // => 'evalFn'
67
68stackFrame.toString() // => 'funName(args)@http://localhost:3000/file.js:325:20'
69```
70
71## Browser Support
72[![Sauce Test Status](https://saucelabs.com/browser-matrix/stacktracejs.svg)](https://saucelabs.com/u/stacktracejs)
73
74## Installation
75```
76npm install stackframe
77bower install stackframe
78https://raw.githubusercontent.com/stacktracejs/stackframe/master/dist/stackframe.min.js
79```
node_modules/stackframe/dist/stackframe.js +143 -0
……@@ -0,0 +1,143 @@
1(function(root, factory) {
2 'use strict';
3 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
4
5 /* istanbul ignore next */
6 if (typeof define === 'function' && define.amd) {
7 define('stackframe', [], factory);
8 } else if (typeof exports === 'object') {
9 module.exports = factory();
10 } else {
11 root.StackFrame = factory();
12 }
13}(this, function() {
14 'use strict';
15 function _isNumber(n) {
16 return !isNaN(parseFloat(n)) && isFinite(n);
17 }
18
19 function _capitalize(str) {
20 return str.charAt(0).toUpperCase() + str.substring(1);
21 }
22
23 function _getter(p) {
24 return function() {
25 return this[p];
26 };
27 }
28
29 var booleanProps = ['isConstructor', 'isEval', 'isNative', 'isToplevel'];
30 var numericProps = ['columnNumber', 'lineNumber'];
31 var stringProps = ['fileName', 'functionName', 'source'];
32 var arrayProps = ['args'];
33 var objectProps = ['evalOrigin'];
34
35 var props = booleanProps.concat(numericProps, stringProps, arrayProps, objectProps);
36
37 function StackFrame(obj) {
38 if (!obj) return;
39 for (var i = 0; i < props.length; i++) {
40 if (obj[props[i]] !== undefined) {
41 this['set' + _capitalize(props[i])](obj[props[i]]);
42 }
43 }
44 }
45
46 StackFrame.prototype = {
47 getArgs: function() {
48 return this.args;
49 },
50 setArgs: function(v) {
51 if (Object.prototype.toString.call(v) !== '[object Array]') {
52 throw new TypeError('Args must be an Array');
53 }
54 this.args = v;
55 },
56
57 getEvalOrigin: function() {
58 return this.evalOrigin;
59 },
60 setEvalOrigin: function(v) {
61 if (v instanceof StackFrame) {
62 this.evalOrigin = v;
63 } else if (v instanceof Object) {
64 this.evalOrigin = new StackFrame(v);
65 } else {
66 throw new TypeError('Eval Origin must be an Object or StackFrame');
67 }
68 },
69
70 toString: function() {
71 var fileName = this.getFileName() || '';
72 var lineNumber = this.getLineNumber() || '';
73 var columnNumber = this.getColumnNumber() || '';
74 var functionName = this.getFunctionName() || '';
75 if (this.getIsEval()) {
76 if (fileName) {
77 return '[eval] (' + fileName + ':' + lineNumber + ':' + columnNumber + ')';
78 }
79 return '[eval]:' + lineNumber + ':' + columnNumber;
80 }
81 if (functionName) {
82 return functionName + ' (' + fileName + ':' + lineNumber + ':' + columnNumber + ')';
83 }
84 return fileName + ':' + lineNumber + ':' + columnNumber;
85 }
86 };
87
88 StackFrame.fromString = function StackFrame$$fromString(str) {
89 var argsStartIndex = str.indexOf('(');
90 var argsEndIndex = str.lastIndexOf(')');
91
92 var functionName = str.substring(0, argsStartIndex);
93 var args = str.substring(argsStartIndex + 1, argsEndIndex).split(',');
94 var locationString = str.substring(argsEndIndex + 1);
95
96 if (locationString.indexOf('@') === 0) {
97 var parts = /@(.+?)(?::(\d+))?(?::(\d+))?$/.exec(locationString, '');
98 var fileName = parts[1];
99 var lineNumber = parts[2];
100 var columnNumber = parts[3];
101 }
102
103 return new StackFrame({
104 functionName: functionName,
105 args: args || undefined,
106 fileName: fileName,
107 lineNumber: lineNumber || undefined,
108 columnNumber: columnNumber || undefined
109 });
110 };
111
112 for (var i = 0; i < booleanProps.length; i++) {
113 StackFrame.prototype['get' + _capitalize(booleanProps[i])] = _getter(booleanProps[i]);
114 StackFrame.prototype['set' + _capitalize(booleanProps[i])] = (function(p) {
115 return function(v) {
116 this[p] = Boolean(v);
117 };
118 })(booleanProps[i]);
119 }
120
121 for (var j = 0; j < numericProps.length; j++) {
122 StackFrame.prototype['get' + _capitalize(numericProps[j])] = _getter(numericProps[j]);
123 StackFrame.prototype['set' + _capitalize(numericProps[j])] = (function(p) {
124 return function(v) {
125 if (!_isNumber(v)) {
126 throw new TypeError(p + ' must be a Number');
127 }
128 this[p] = Number(v);
129 };
130 })(numericProps[j]);
131 }
132
133 for (var k = 0; k < stringProps.length; k++) {
134 StackFrame.prototype['get' + _capitalize(stringProps[k])] = _getter(stringProps[k]);
135 StackFrame.prototype['set' + _capitalize(stringProps[k])] = (function(p) {
136 return function(v) {
137 this[p] = String(v);
138 };
139 })(stringProps[k]);
140 }
141
142 return StackFrame;
143}));
node_modules/stackframe/dist/stackframe.min.js +2 -0
……@@ -0,0 +1,2 @@
1!function(t,e){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],e):"object"==typeof exports?module.exports=e():t.StackFrame=e()}(this,function(){"use strict";function t(t){return t.charAt(0).toUpperCase()+t.substring(1)}function e(t){return function(){return this[t]}}var r=["isConstructor","isEval","isNative","isToplevel"],n=["columnNumber","lineNumber"],i=["fileName","functionName","source"],o=r.concat(n,i,["args"],["evalOrigin"]);function s(e){if(e)for(var r=0;r<o.length;r++)void 0!==e[o[r]]&&this["set"+t(o[r])](e[o[r]])}s.prototype={getArgs:function(){return this.args},setArgs:function(t){if("[object Array]"!==Object.prototype.toString.call(t))throw new TypeError("Args must be an Array");this.args=t},getEvalOrigin:function(){return this.evalOrigin},setEvalOrigin:function(t){if(t instanceof s)this.evalOrigin=t;else{if(!(t instanceof Object))throw new TypeError("Eval Origin must be an Object or StackFrame");this.evalOrigin=new s(t)}},toString:function(){var t=this.getFileName()||"",e=this.getLineNumber()||"",r=this.getColumnNumber()||"",n=this.getFunctionName()||"";return this.getIsEval()?t?"[eval] ("+t+":"+e+":"+r+")":"[eval]:"+e+":"+r:n?n+" ("+t+":"+e+":"+r+")":t+":"+e+":"+r}},s.fromString=function(t){var e=t.indexOf("("),r=t.lastIndexOf(")"),n=t.substring(0,e),i=t.substring(e+1,r).split(","),o=t.substring(r+1);if(0===o.indexOf("@"))var u=/@(.+?)(?::(\d+))?(?::(\d+))?$/.exec(o,""),a=u[1],f=u[2],c=u[3];return new s({functionName:n,args:i||void 0,fileName:a,lineNumber:f||void 0,columnNumber:c||void 0})};for(var u=0;u<r.length;u++)s.prototype["get"+t(r[u])]=e(r[u]),s.prototype["set"+t(r[u])]=function(t){return function(e){this[t]=Boolean(e)}}(r[u]);for(var a=0;a<n.length;a++)s.prototype["get"+t(n[a])]=e(n[a]),s.prototype["set"+t(n[a])]=function(t){return function(e){if(r=e,isNaN(parseFloat(r))||!isFinite(r))throw new TypeError(t+" must be a Number");var r;this[t]=Number(e)}}(n[a]);for(var f=0;f<i.length;f++)s.prototype["get"+t(i[f])]=e(i[f]),s.prototype["set"+t(i[f])]=function(t){return function(e){this[t]=String(e)}}(i[f]);return s});
2//# sourceMappingURL=stackframe.min.js.map
node_modules/stackframe/dist/stackframe.min.js.map +1 -0
……@@ -0,0 +1 @@
1{"version":3,"sources":["stackframe.js"],"names":["root","factory","define","amd","exports","module","StackFrame","this","_capitalize","str","charAt","toUpperCase","substring","_getter","p","booleanProps","numericProps","stringProps","props","concat","obj","i","length","undefined","prototype","getArgs","args","setArgs","v","Object","toString","call","TypeError","getEvalOrigin","evalOrigin","setEvalOrigin","fileName","getFileName","lineNumber","getLineNumber","columnNumber","getColumnNumber","functionName","getFunctionName","getIsEval","fromString","argsStartIndex","indexOf","argsEndIndex","lastIndexOf","split","locationString","parts","exec","Boolean","j","n","isNaN","parseFloat","isFinite","Number","k","String"],"mappings":"CAAC,SAASA,EAAMC,GACZ,aAIsB,mBAAXC,QAAyBA,OAAOC,IACvCD,OAAO,gBAAkBD,GACC,iBAAZG,QACdC,OAAOD,QAAUH,IAEjBD,EAAKM,WAAaL,IAV1B,CAYEM,KAAM,WACJ,aAKA,SAASC,EAAYC,GACjB,OAAOA,EAAIC,OAAO,GAAGC,cAAgBF,EAAIG,UAAU,GAGvD,SAASC,EAAQC,GACb,OAAO,WACH,OAAOP,KAAKO,IAIpB,IAAIC,GAAgB,gBAAiB,SAAU,WAAY,cACvDC,GAAgB,eAAgB,cAChCC,GAAe,WAAY,eAAgB,UAI3CC,EAAQH,EAAaI,OAAOH,EAAcC,GAH5B,SACC,eAInB,SAASX,EAAWc,GAChB,GAAKA,EACL,IAAK,IAAIC,EAAI,EAAGA,EAAIH,EAAMI,OAAQD,SACRE,IAAlBH,EAAIF,EAAMG,KACVd,KAAK,MAAQC,EAAYU,EAAMG,KAAKD,EAAIF,EAAMG,KAK1Df,EAAWkB,WACPC,QAAS,WACL,OAAOlB,KAAKmB,MAEhBC,QAAS,SAASC,GACd,GAA0C,mBAAtCC,OAAOL,UAAUM,SAASC,KAAKH,GAC/B,MAAM,IAAII,UAAU,yBAExBzB,KAAKmB,KAAOE,GAGhBK,cAAe,WACX,OAAO1B,KAAK2B,YAEhBC,cAAe,SAASP,GACpB,GAAIA,aAAatB,EACbC,KAAK2B,WAAaN,MACf,CAAA,KAAIA,aAAaC,QAGpB,MAAM,IAAIG,UAAU,+CAFpBzB,KAAK2B,WAAa,IAAI5B,EAAWsB,KAMzCE,SAAU,WACN,IAAIM,EAAW7B,KAAK8B,eAAiB,GACjCC,EAAa/B,KAAKgC,iBAAmB,GACrCC,EAAejC,KAAKkC,mBAAqB,GACzCC,EAAenC,KAAKoC,mBAAqB,GAC7C,OAAIpC,KAAKqC,YACDR,EACO,WAAaA,EAAW,IAAME,EAAa,IAAME,EAAe,IAEpE,UAAYF,EAAa,IAAME,EAEtCE,EACOA,EAAe,KAAON,EAAW,IAAME,EAAa,IAAME,EAAe,IAE7EJ,EAAW,IAAME,EAAa,IAAME,IAInDlC,EAAWuC,WAAa,SAAgCpC,GACpD,IAAIqC,EAAiBrC,EAAIsC,QAAQ,KAC7BC,EAAevC,EAAIwC,YAAY,KAE/BP,EAAejC,EAAIG,UAAU,EAAGkC,GAChCpB,EAAOjB,EAAIG,UAAUkC,EAAiB,EAAGE,GAAcE,MAAM,KAC7DC,EAAiB1C,EAAIG,UAAUoC,EAAe,GAElD,GAAoC,IAAhCG,EAAeJ,QAAQ,KACvB,IAAIK,EAAQ,gCAAgCC,KAAKF,EAAgB,IAC7Df,EAAWgB,EAAM,GACjBd,EAAac,EAAM,GACnBZ,EAAeY,EAAM,GAG7B,OAAO,IAAI9C,GACPoC,aAAcA,EACdhB,KAAMA,QAAQH,EACda,SAAUA,EACVE,WAAYA,QAAcf,EAC1BiB,aAAcA,QAAgBjB,KAItC,IAAK,IAAIF,EAAI,EAAGA,EAAIN,EAAaO,OAAQD,IACrCf,EAAWkB,UAAU,MAAQhB,EAAYO,EAAaM,KAAOR,EAAQE,EAAaM,IAClFf,EAAWkB,UAAU,MAAQhB,EAAYO,EAAaM,KAAO,SAAUP,GACnE,OAAO,SAASc,GACZrB,KAAKO,GAAKwC,QAAQ1B,IAFmC,CAI1Db,EAAaM,IAGpB,IAAK,IAAIkC,EAAI,EAAGA,EAAIvC,EAAaM,OAAQiC,IACrCjD,EAAWkB,UAAU,MAAQhB,EAAYQ,EAAauC,KAAO1C,EAAQG,EAAauC,IAClFjD,EAAWkB,UAAU,MAAQhB,EAAYQ,EAAauC,KAAO,SAAUzC,GACnE,OAAO,SAASc,GACZ,GA9GO4B,EA8GQ5B,EA7Gf6B,MAAMC,WAAWF,MAAOG,SAASH,GA8G7B,MAAM,IAAIxB,UAAUlB,EAAI,qBA/GxC,IAAmB0C,EAiHPjD,KAAKO,GAAK8C,OAAOhC,IALoC,CAO1DZ,EAAauC,IAGpB,IAAK,IAAIM,EAAI,EAAGA,EAAI5C,EAAYK,OAAQuC,IACpCvD,EAAWkB,UAAU,MAAQhB,EAAYS,EAAY4C,KAAOhD,EAAQI,EAAY4C,IAChFvD,EAAWkB,UAAU,MAAQhB,EAAYS,EAAY4C,KAAO,SAAU/C,GAClE,OAAO,SAASc,GACZrB,KAAKO,GAAKgD,OAAOlC,IAFmC,CAIzDX,EAAY4C,IAGnB,OAAOvD"}
node_modules/stackframe/package.json +59 -0
……@@ -0,0 +1,59 @@
1{
2 "name": "stackframe",
3 "description": "JS Object representation of a stack frame",
4 "maintainers": [
5 "Eric Wendelin <me@eriwen.com> (https://www.eriwen.com)",
6 "Victor Homyakov <vkhomyackov@gmail.com> (https://github.com/victor-homyakov)",
7 "Oliver Salzburg (https://github.com/oliversalzburg)"
8 ],
9 "version": "1.3.4",
10 "license": "MIT",
11 "keywords": [
12 "stacktrace",
13 "error",
14 "debugger",
15 "stack frame"
16 ],
17 "homepage": "https://www.stacktracejs.com",
18 "repository": {
19 "type": "git",
20 "url": "git://github.com/stacktracejs/stackframe.git"
21 },
22 "devDependencies": {
23 "eslint": "^8.17.0",
24 "jasmine": "^4.1.0",
25 "jasmine-core": "^4.1.1",
26 "karma": "^6.3.20",
27 "karma-chrome-launcher": "^3.1.1",
28 "karma-coverage": "^2.2.0",
29 "karma-coveralls": "^2.1.0",
30 "karma-firefox-launcher": "^2.1.2",
31 "karma-ie-launcher": "^1.0.0",
32 "karma-jasmine": "^4.0.2",
33 "karma-opera-launcher": "^1.0.0",
34 "karma-phantomjs-launcher": "^1.0.4",
35 "karma-safari-launcher": "^1.0.0",
36 "karma-sauce-launcher": "^4.3.6",
37 "karma-spec-reporter": "^0.0.34",
38 "uglify-es": "^3.3.9"
39 },
40 "bugs": {
41 "url": "https://github.com/stacktracejs/stackframe/issues"
42 },
43 "main": "./stackframe.js",
44 "typings": "./stackframe.d.ts",
45 "files": [
46 "LICENSE",
47 "README.md",
48 "stackframe.js",
49 "stackframe.d.ts",
50 "dist/"
51 ],
52 "scripts": {
53 "lint": "eslint",
54 "test": "karma start karma.conf.js --single-run",
55 "test-pr": "karma start karma.conf.js --single-run --browsers Firefox,Chrome_No_Sandbox",
56 "test-ci": "karma start karma.conf.ci.js --single-run",
57 "prepare": "cp stackframe.js dist/ && uglifyjs stackframe.js -o dist/stackframe.min.js --compress --mangle --source-map \"url=stackframe.min.js.map\""
58 }
59}
node_modules/stackframe/stackframe.d.ts +74 -0
……@@ -0,0 +1,74 @@
1// Type definitions for StackFrame v1.3
2// Project: https://github.com/stacktracejs/stackframe
3// Definitions by: Eric Wendelin <https://www.eriwen.com>
4// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5
6export as namespace StackFrame; // global for non-module UMD users
7
8export = StackFrame;
9
10declare namespace StackFrame {
11 export interface StackFrameOptions {
12 isConstructor?: boolean;
13 isEval?: boolean;
14 isNative?: boolean;
15 isToplevel?: boolean;
16 columnNumber?: number;
17 lineNumber?: number;
18 fileName?: string;
19 functionName?: string;
20 source?: string;
21 args?: any[];
22 evalOrigin?: StackFrame;
23 }
24}
25
26declare class StackFrame {
27 constructor(obj: StackFrame.StackFrameOptions);
28
29 args?: any[];
30 getArgs(): any[] | undefined;
31 setArgs(args: any[]): void;
32
33 evalOrigin?: StackFrame;
34 getEvalOrigin(): StackFrame | undefined;
35 setEvalOrigin(stackframe: StackFrame): void;
36
37 isConstructor?: boolean;
38 getIsConstructor(): boolean | undefined;
39 setIsConstructor(isConstructor: boolean): void;
40
41 isEval?: boolean;
42 getIsEval(): boolean | undefined;
43 setIsEval(isEval: boolean): void;
44
45 isNative?: boolean;
46 getIsNative(): boolean | undefined;
47 setIsNative(isNative: boolean): void;
48
49 isToplevel?: boolean;
50 getIsToplevel(): boolean | undefined;
51 setIsToplevel(isToplevel: boolean): void;
52
53 columnNumber?: number;
54 getColumnNumber(): number | undefined;
55 setColumnNumber(columnNumber: number): void;
56
57 lineNumber?: number;
58 getLineNumber(): number | undefined;
59 setLineNumber(lineNumber: number): void;
60
61 fileName?: string;
62 getFileName(): string | undefined;
63 setFileName(fileName: string): void;
64
65 functionName?: string;
66 getFunctionName(): string | undefined;
67 setFunctionName(functionName: string): void;
68
69 source?: string;
70 getSource(): string | undefined;
71 setSource(source: string): void;
72
73 toString(): string;
74}
node_modules/stackframe/stackframe.js +143 -0
……@@ -0,0 +1,143 @@
1(function(root, factory) {
2 'use strict';
3 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
4
5 /* istanbul ignore next */
6 if (typeof define === 'function' && define.amd) {
7 define('stackframe', [], factory);
8 } else if (typeof exports === 'object') {
9 module.exports = factory();
10 } else {
11 root.StackFrame = factory();
12 }
13}(this, function() {
14 'use strict';
15 function _isNumber(n) {
16 return !isNaN(parseFloat(n)) && isFinite(n);
17 }
18
19 function _capitalize(str) {
20 return str.charAt(0).toUpperCase() + str.substring(1);
21 }
22
23 function _getter(p) {
24 return function() {
25 return this[p];
26 };
27 }
28
29 var booleanProps = ['isConstructor', 'isEval', 'isNative', 'isToplevel'];
30 var numericProps = ['columnNumber', 'lineNumber'];
31 var stringProps = ['fileName', 'functionName', 'source'];
32 var arrayProps = ['args'];
33 var objectProps = ['evalOrigin'];
34
35 var props = booleanProps.concat(numericProps, stringProps, arrayProps, objectProps);
36
37 function StackFrame(obj) {
38 if (!obj) return;
39 for (var i = 0; i < props.length; i++) {
40 if (obj[props[i]] !== undefined) {
41 this['set' + _capitalize(props[i])](obj[props[i]]);
42 }
43 }
44 }
45
46 StackFrame.prototype = {
47 getArgs: function() {
48 return this.args;
49 },
50 setArgs: function(v) {
51 if (Object.prototype.toString.call(v) !== '[object Array]') {
52 throw new TypeError('Args must be an Array');
53 }
54 this.args = v;
55 },
56
57 getEvalOrigin: function() {
58 return this.evalOrigin;
59 },
60 setEvalOrigin: function(v) {
61 if (v instanceof StackFrame) {
62 this.evalOrigin = v;
63 } else if (v instanceof Object) {
64 this.evalOrigin = new StackFrame(v);
65 } else {
66 throw new TypeError('Eval Origin must be an Object or StackFrame');
67 }
68 },
69
70 toString: function() {
71 var fileName = this.getFileName() || '';
72 var lineNumber = this.getLineNumber() || '';
73 var columnNumber = this.getColumnNumber() || '';
74 var functionName = this.getFunctionName() || '';
75 if (this.getIsEval()) {
76 if (fileName) {
77 return '[eval] (' + fileName + ':' + lineNumber + ':' + columnNumber + ')';
78 }
79 return '[eval]:' + lineNumber + ':' + columnNumber;
80 }
81 if (functionName) {
82 return functionName + ' (' + fileName + ':' + lineNumber + ':' + columnNumber + ')';
83 }
84 return fileName + ':' + lineNumber + ':' + columnNumber;
85 }
86 };
87
88 StackFrame.fromString = function StackFrame$$fromString(str) {
89 var argsStartIndex = str.indexOf('(');
90 var argsEndIndex = str.lastIndexOf(')');
91
92 var functionName = str.substring(0, argsStartIndex);
93 var args = str.substring(argsStartIndex + 1, argsEndIndex).split(',');
94 var locationString = str.substring(argsEndIndex + 1);
95
96 if (locationString.indexOf('@') === 0) {
97 var parts = /@(.+?)(?::(\d+))?(?::(\d+))?$/.exec(locationString, '');
98 var fileName = parts[1];
99 var lineNumber = parts[2];
100 var columnNumber = parts[3];
101 }
102
103 return new StackFrame({
104 functionName: functionName,
105 args: args || undefined,
106 fileName: fileName,
107 lineNumber: lineNumber || undefined,
108 columnNumber: columnNumber || undefined
109 });
110 };
111
112 for (var i = 0; i < booleanProps.length; i++) {
113 StackFrame.prototype['get' + _capitalize(booleanProps[i])] = _getter(booleanProps[i]);
114 StackFrame.prototype['set' + _capitalize(booleanProps[i])] = (function(p) {
115 return function(v) {
116 this[p] = Boolean(v);
117 };
118 })(booleanProps[i]);
119 }
120
121 for (var j = 0; j < numericProps.length; j++) {
122 StackFrame.prototype['get' + _capitalize(numericProps[j])] = _getter(numericProps[j]);
123 StackFrame.prototype['set' + _capitalize(numericProps[j])] = (function(p) {
124 return function(v) {
125 if (!_isNumber(v)) {
126 throw new TypeError(p + ' must be a Number');
127 }
128 this[p] = Number(v);
129 };
130 })(numericProps[j]);
131 }
132
133 for (var k = 0; k < stringProps.length; k++) {
134 StackFrame.prototype['get' + _capitalize(stringProps[k])] = _getter(stringProps[k]);
135 StackFrame.prototype['set' + _capitalize(stringProps[k])] = (function(p) {
136 return function(v) {
137 this[p] = String(v);
138 };
139 })(stringProps[k]);
140 }
141
142 return StackFrame;
143}));
node_modules/test-tmp/.github/workflows/test-node.yml +23 -0
……@@ -0,0 +1,23 @@
1name: Build Status
2on:
3 push:
4 branches:
5 - master
6 pull_request:
7 branches:
8 - master
9jobs:
10 build:
11 strategy:
12 matrix:
13 node-version: [lts/*]
14 os: [ubuntu-latest, macos-latest, windows-latest]
15 runs-on: ${{ matrix.os }}
16 steps:
17 - uses: actions/checkout@v2
18 - name: Use Node.js ${{ matrix.node-version }}
19 uses: actions/setup-node@v2
20 with:
21 node-version: ${{ matrix.node-version }}
22 - run: npm install
23 - run: npm test
node_modules/test-tmp/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2023 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/test-tmp/README.md +23 -0
……@@ -0,0 +1,23 @@
1# test-tmp
2
3Get a fresh tmpdir for tests
4
5```
6npm install test-tmp
7```
8
9## Usage
10
11``` js
12const test = require('brittle')
13const tmp = require('test-tmp')
14
15test('my test', async function (t) {
16 const dir = await tmp(t)
17 console.log('fresh dir for this test', dir)
18})
19```
20
21## License
22
23MIT
node_modules/test-tmp/index.js +37 -0
……@@ -0,0 +1,37 @@
1const os = require('os')
2const path = require('path')
3const fs = require('fs')
4
5module.exports = tmp
6
7async function tmp (t, { dir = null, name = null, order = Infinity, force = true } = {}) {
8 if (!valid(name)) name = Math.random().toString(16).slice(2)
9
10 if (dir) {
11 await fs.promises.mkdir(dir, { recursive: true })
12 }
13
14 const tmpdir = path.join(await fs.promises.realpath(dir || os.tmpdir()), 'tmp-test-' + name)
15
16 try {
17 await gc(tmpdir)
18 } catch {}
19
20 await fs.promises.mkdir(tmpdir, { recursive: true })
21
22 if (t) t.teardown(gc, { order, force })
23 return tmpdir
24
25 async function gc () {
26 await fs.promises.rm(tmpdir, { recursive: true })
27 }
28
29 function valid (name) {
30 if (typeof name !== 'string') return false
31
32 const chars = /[<>:/\\|?*]/
33 const max = 64
34
35 return !chars.test(name) && name.length <= max
36 }
37}
node_modules/test-tmp/package.json +42 -0
……@@ -0,0 +1,42 @@
1{
2 "name": "test-tmp",
3 "version": "1.4.0",
4 "description": "Get a fresh tmpdir for tests",
5 "main": "index.js",
6 "imports": {
7 "os": {
8 "bare": "bare-os",
9 "default": "os"
10 },
11 "path": {
12 "bare": "bare-path",
13 "default": "path"
14 },
15 "fs": {
16 "bare": "bare-fs",
17 "default": "fs"
18 }
19 },
20 "scripts": {
21 "test": "standard && brittle test.js"
22 },
23 "devDependencies": {
24 "brittle": "^3.3.2",
25 "standard": "^17.1.0"
26 },
27 "repository": {
28 "type": "git",
29 "url": "https://github.com/mafintosh/test-tmp.git"
30 },
31 "author": "Mathias Buus (@mafintosh)",
32 "license": "MIT",
33 "bugs": {
34 "url": "https://github.com/mafintosh/test-tmp/issues"
35 },
36 "homepage": "https://github.com/mafintosh/test-tmp",
37 "dependencies": {
38 "bare-fs": "^4.0.1",
39 "bare-os": "^3.3.0",
40 "bare-path": "^3.0.0"
41 }
42}
node_modules/test-tmp/test.js +47 -0
……@@ -0,0 +1,47 @@
1const test = require('brittle')
2const tmp = require('./')
3const fs = require('fs')
4const os = require('os')
5const path = require('path')
6
7test('basic', async function (t) {
8 const dir = await tmp(t)
9
10 t.alike(await fs.promises.readdir(dir), [])
11})
12
13test('specified name', async function (t) {
14 const name = 'testdir'
15 const dir = await tmp(t, { name })
16 t.ok(dir.includes(name), 'directory contains specified name')
17 t.alike(await fs.promises.readdir(dir), [])
18})
19
20test('invalid directory name', async function (t) {
21 const name = '<>:/\\|?*'
22 try {
23 await tmp(t, { name })
24 t.pass('should default to a random name when an invalid input is provided')
25 } catch (error) {
26 t.fail('expected to handle an invalid directory name')
27 }
28})
29
30test('reuse directory', async function (t) {
31 const name = 'existing-dir'
32 const existing = path.join(await fs.promises.realpath(os.tmpdir()), 'tmp-test-' + name)
33
34 await fs.promises.mkdir(existing, { recursive: true })
35
36 const dir = await tmp(t, { name })
37 t.is(dir, existing, 'uses the existing directory when it already exists')
38})
39
40test('specify root directory', async function (t) {
41 const dir = await tmp(t, { dir: './tmp-storage' })
42
43 const children = await fs.promises.readdir('./tmp-storage')
44 t.is(children.length, 1)
45
46 t.alike(await fs.promises.readdir(dir), [])
47})
node_modules/time-ordered-set/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2017 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/time-ordered-set/README.md +72 -0
……@@ -0,0 +1,72 @@
1# time-ordered-set
2
3Efficiently maintain a set of nodes ordered by the time they were added to the set
4
5```
6npm install time-ordered-set
7```
8
9## Usage
10
11``` js
12const TOS = require('time-ordered-set')
13const s = new TOS()
14
15// add 3 nodes
16
17s.add({
18 hello: 'world'
19})
20
21const node = s.add({
22 hello: 'welt'
23})
24
25s.add({
26 hello: 'verden'
27})
28
29// re-add the 2nd one
30
31s.add(node)
32console.log(s.toArray().map(node => node.hello)) // ['world', 'verden', 'welt']
33```
34
35## API
36
37#### `const s = new TOS()`
38
39Create a new set
40
41#### `node = s.add(node)`
42
43Add a new node to the set. Will add the properties `node.next` and `node.prev` to the node.
44Re-adding the same node will move to the latest node.
45
46#### `node = s.remove(node)`
47
48Remove a node. Will set `node.next` and `node.prev` to `null`.
49
50#### `bool = s.has(node)`
51
52Check if a node has been added.
53
54#### `const array = s.toArray([options])`
55
56Get an ordered array out of all the nodes, ordered from oldest to newest. Use `options.reverse: true` to get from newest to oldest. Set `options.limit: number` if you only want to get a subset.
57
58#### `s.oldest`
59
60Property containing the oldest node.
61
62#### `s.latest`
63
64Property containing the newest node.
65
66#### `s.length`
67
68Property containing how many nodes are in the set.
69
70## License
71
72MIT
node_modules/time-ordered-set/index.js +72 -0
……@@ -0,0 +1,72 @@
1module.exports = class TimeOrderedSet {
2 constructor () {
3 this.oldest = null
4 this.latest = null
5 this.length = 0
6 }
7
8 has (node) {
9 return !!(node.next || node.prev) || node === this.oldest
10 }
11
12 add (node) {
13 if (this.has(node)) this.remove(node)
14
15 if (!this.latest && !this.oldest) {
16 this.latest = this.oldest = node
17 node.prev = node.next = null
18 } else {
19 this.latest.next = node
20 node.prev = this.latest
21 node.next = null
22 this.latest = node
23 }
24
25 this.length++
26
27 return node
28 }
29
30 remove (node) {
31 if (!this.has(node)) return node
32
33 if (this.oldest !== node && this.latest !== node) {
34 node.prev.next = node.next
35 node.next.prev = node.prev
36 } else {
37 if (this.oldest === node) {
38 this.oldest = node.next
39 if (this.oldest) this.oldest.prev = null
40 }
41 if (this.latest === node) {
42 this.latest = node.prev
43 if (this.latest) this.latest.next = null
44 }
45 }
46
47 node.next = node.prev = null
48 this.length--
49
50 return node
51 }
52
53 toArray ({ limit = Infinity, reverse = false } = {}) {
54 const list = []
55
56 if (reverse) {
57 let node = this.latest
58 while (node && limit--) {
59 list.push(node)
60 node = node.prev
61 }
62 } else {
63 let node = this.oldest
64 while (node && limit--) {
65 list.push(node)
66 node = node.next
67 }
68 }
69
70 return list
71 }
72}
node_modules/time-ordered-set/package.json +26 -0
……@@ -0,0 +1,26 @@
1{
2 "name": "time-ordered-set",
3 "version": "2.0.1",
4 "description": "Efficiently maintain a set of nodes ordered by the time they were added to the set",
5 "main": "index.js",
6 "files": [
7 "index.js"
8 ],
9 "devDependencies": {
10 "brittle": "^3.0.0",
11 "standard": "^17.1.2"
12 },
13 "scripts": {
14 "test": "standard && brittle test.js"
15 },
16 "repository": {
17 "type": "git",
18 "url": "https://github.com/mafintosh/time-ordered-set.git"
19 },
20 "author": "Mathias Buus (@mafintosh)",
21 "license": "MIT",
22 "bugs": {
23 "url": "https://github.com/mafintosh/time-ordered-set/issues"
24 },
25 "homepage": "https://github.com/mafintosh/time-ordered-set"
26}
node_modules/tmatch/LICENSE +15 -0
……@@ -0,0 +1,15 @@
1The ISC License
2
3Copyright (c) Isaac Z. Schlueter and Contributors
4
5Permission to use, copy, modify, and/or distribute this software for any
6purpose with or without fee is hereby granted, provided that the above
7copyright notice and this permission notice appear in all copies.
8
9THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
node_modules/tmatch/README.md +96 -0
……@@ -0,0 +1,96 @@
1# tmatch
2
3This module exists to facilitate the `t.match()` method in
4[`tap`](http://npm.im/tap).
5
6It checks whether a value matches a given "pattern". A pattern is an
7object with a set of fields that must be in the test object, or a
8regular expression that a test string must match, or any combination
9thereof.
10
11The algorithm is borrowed heavily from
12[`only-shallow`](http://npm.im/only-shallow), with some notable
13differences with respect to the handling of missing properties and the
14way that regular expressions are compared to strings.
15
16## usage
17
18```javascript
19var matches = require('tmatch')
20
21if (!matches(testObject, pattern)) console.log("yay! diversity!");
22
23// somewhat more realistic example..
24http.get(someUrl).on('response', function (res) {
25 var expect = {
26 statusCode: 200,
27 headers: {
28 server: /express/
29 }
30 }
31
32 if (!tmatch(res, expect)) {
33 throw new Error('Expect 200 status code from express server')
34 }
35})
36```
37
38## details
39
40Copied from the source, here are the details of `tmatch`'s algorithm:
41
421. If the object loosely equals the pattern, and either they're both
43 objects or neither objects, then return true. Note that this
44 covers object identity, some type coercion, and matching `null`
45 against `undefined`, and avoids some stuff like `1 == [1]`.
462. If the object is a RegExp and the pattern is also a RegExp, return
47 true if their source, global, multiline, lastIndex, and ignoreCase
48 fields all match.
493. If the pattern is a RegExp, then return true if
50 `pattern.test(object)`, casting the object to a string if it is not
51 already a string.
524. If the pattern is a `Set`, then return true if all the keys in
53 `pattern` appear in `object`.
545. If the pattern is a `Map`, then return true if all the keys in
55 `pattern` are in `object`, and the values match as well.
566. If the object is a string and the pattern is a non-empty string,
57 then return true if the string occurs within the object.
587. If the object and the pattern are both Date objects, then return
59 true if they represent the same date.
608. If the object is a Date object, and the pattern is a string, then
61 return true if the pattern is parseable as a date that is the same
62 date as the object.
639. If the object is an `arguments` object, or the pattern is an
64 `arguments` object, then cast them to arrays and compare their
65 contents.
6610. If the pattern is the `Buffer` constructor, then return true if
67 the object is a Buffer.
6811. If the pattern is the `Function` constructor, then return true if
69 the object is a function.
7012. If the pattern is the String constructor, then return true if the
71 pattern is a string.
7213. If the pattern is the Boolean constructor, then return true if the
73 pattern is a boolean.
7414. If the pattern is the Array constructor, then return true if the
75 pattern is an array.
7615. If the pattern is any function, and then object is an object, then
77 return true if the object is an `instanceof` the pattern.
7816. At this point, if the object or the pattern are not objects, then
79 return false (because they would have matched earlier).
8017. If the object is a buffer, and the pattern is also a buffer, then
81 return true if they contain the same bytes.
8218. At this point, both object and pattern are object type values, so
83 compare their keys:
84 1. Get list of all iterable keys in pattern and object. If both
85 are zero (two empty objects), return true.
86 2. Check to see if this pattern and this object have been tested
87 already (to handle cycles). If so, return true, since the
88 check higher up in the stack will catch any mismatch.
89 3. For each key in the pattern, match it against the corresponding
90 key in object. Missing keys in object will be resolved to
91 `undefined`, so it's possible to use `{foo:null}` as a pattern
92 to ensure that the object *doesn't* have a `foo` property.
93
94## license
95
96ISC. Go nuts.
node_modules/tmatch/index.js +189 -0
……@@ -0,0 +1,189 @@
1'use strict'
2
3module.exports = match
4
5function isArguments (obj) {
6 return Object.prototype.toString.call(obj) === '[object Arguments]'
7}
8
9function regexpSame (a, b) {
10 return a.source === b.source &&
11 a.global === b.global &&
12 a.multiline === b.multiline &&
13 a.lastIndex === b.lastIndex &&
14 a.ignoreCase === b.ignoreCase
15}
16
17function arrayFrom (obj) {
18 return Array.isArray(obj) ? obj
19 : Array.from(obj)
20}
21
22function isSet (object) {
23 return object instanceof Set
24}
25
26function isMap (object) {
27 return object instanceof Map
28}
29
30function bufferSame (a, b) {
31 var ret
32 if (a.equals) {
33 ret = a.equals(b)
34 } else if (a.length !== b.length) {
35 ret = false
36 } else {
37 ret = true
38 for (var j = 0; j < a.length && ret; j++) {
39 if (a[j] != b[j])
40 ret = false
41 }
42 }
43 return ret
44}
45
46function match (obj, pattern) {
47 return match_(obj, pattern, [], [])
48}
49
50function setMatch (obj, pattern, ca, cb) {
51 var ret = true
52 if (!isSet(obj))
53 ret = false
54 else if (pattern.size === 0)
55 ret = true
56 else {
57 var seen = new Set()
58 pattern.forEach(function (entry) {
59 if (!ret)
60 return
61
62 if (obj.has(entry) && !seen.has(entry)) {
63 seen.add(entry)
64 return
65 }
66
67 // see if obj anything that matches
68 // but don't allow anything to match more than once.
69 var done = false
70 obj.forEach(function (objentry) {
71 if (done || seen.has(objentry))
72 return
73
74 if (match_(objentry, entry, ca, cb)) {
75 seen.add(objentry)
76 ret = true
77 done = true
78 }
79 })
80
81 // didn't find the match by walking the object
82 // not a match!
83 if (!done)
84 ret = false
85 })
86 }
87 return ret
88}
89
90function mapMatch (obj, pattern, ca, cb) {
91 var ret = true
92 if (!isMap(obj))
93 ret = false
94 else if (pattern.size === 0)
95 ret = true
96 else {
97 pattern.forEach(function (value, key) {
98 if (ret)
99 ret = obj.has(key)
100 if (ret)
101 ret = match_(value, obj.get(key), ca, cb)
102 })
103 }
104 return ret
105}
106
107
108function match_ (obj, pattern, ca, cb) {
109 return obj == pattern ? (
110 obj === null || pattern === null ? true
111 : typeof obj === 'object' && typeof pattern === 'object' ? true
112 : typeof obj === 'object' && typeof pattern !== 'object' ? false
113 : typeof obj !== 'object' && typeof pattern === 'object' ? false
114 : true
115 )
116 : obj === null || pattern === null ? false
117 : typeof pattern === 'symbol' ?
118 typeof obj === 'symbol' && obj.toString() === pattern.toString()
119 : pattern instanceof RegExp ? (
120 typeof obj === 'string' ? pattern.test(obj)
121 : obj instanceof RegExp ? regexpSame(obj, pattern)
122 : pattern.test('' + obj)
123 )
124 : isSet(pattern) ? setMatch(obj, pattern, ca, cb)
125 : isMap(pattern) ? mapMatch(obj, pattern, ca, cb)
126 : typeof obj === 'string' && typeof pattern === 'string' && pattern ?
127 obj.indexOf(pattern) !== -1
128 : obj instanceof Date && pattern instanceof Date ?
129 obj.getTime() === pattern.getTime()
130 : obj instanceof Date && typeof pattern === 'string' ?
131 obj.getTime() === new Date(pattern).getTime()
132 : isArguments(obj) || isArguments(pattern) ?
133 match_(arrayFrom(obj), arrayFrom(pattern), ca, cb)
134 : pattern === Buffer ? Buffer.isBuffer(obj)
135 : pattern === Function ? typeof obj === 'function'
136 : pattern === Number ?
137 typeof obj === 'number' && obj === obj && isFinite(obj)
138 : pattern !== pattern ? obj !== obj
139 : pattern === String ? typeof obj === 'string'
140 : pattern === Symbol ? typeof obj === 'symbol'
141 : pattern === Boolean ? typeof obj === 'boolean'
142 : pattern === Array ? Array.isArray(obj)
143 : typeof pattern === 'function' && typeof obj === 'object' ?
144 obj instanceof pattern
145 : typeof obj !== 'object' || typeof pattern !== 'object' ? false
146 : Buffer.isBuffer(obj) && Buffer.isBuffer(pattern) ?
147 bufferSame(obj, pattern)
148 : matchObj(obj, pattern, Object.keys(obj), Object.keys(pattern), ca, cb)
149}
150
151function matchObj (obj, pattern, kobj, kpat, ca, cb) {
152 var ret = true
153
154 // don't bother with stack acrobatics if there's nothing there
155 if (kobj.length === 0 && kpat.length === 0)
156 ret = true
157 else {
158 // if we've seen this exact pattern and object already, then
159 // it means that pattern and obj have matching cyclicalness
160 // however, non-cyclical patterns can match cyclical objects
161 var cal = ca.length
162 var go = true
163 while (cal-- && go) {
164 if (ca[cal] === obj && cb[cal] === pattern) {
165 ret = true
166 go = false
167 }
168 }
169
170 if (go) {
171 ca.push(obj)
172 cb.push(pattern)
173
174 var key
175 for (var l = kpat.length - 1; l >= 0 && ret; l--) {
176 key = kpat[l]
177 if (!match_(obj[key], pattern[key], ca, cb))
178 ret = false
179 }
180
181 if (ret) {
182 ca.pop()
183 cb.pop()
184 }
185 }
186 }
187
188 return ret
189}
node_modules/tmatch/package.json +31 -0
……@@ -0,0 +1,31 @@
1{
2 "name": "tmatch",
3 "version": "5.0.0",
4 "description": "This module exists to facilitate the `t.match()` method in [`tap`](http://npm.im/tap).",
5 "main": "index.js",
6 "scripts": {
7 "test": "tap --100 test/*.js -J",
8 "preversion": "npm test",
9 "postversion": "npm publish",
10 "postpublish": "git push origin --all; git push origin --tags"
11 },
12 "repository": {
13 "type": "git",
14 "url": "git+https://github.com/isaacs/tmatch.git"
15 },
16 "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
17 "license": "ISC",
18 "bugs": {
19 "url": "https://github.com/isaacs/tmatch/issues"
20 },
21 "homepage": "https://github.com/isaacs/tmatch#readme",
22 "devDependencies": {
23 "tap": "^12.5.1"
24 },
25 "files": [
26 "index.js"
27 ],
28 "engines": {
29 "node": ">=8"
30 }
31}
node_modules/udx-native/CMakeLists.txt +81 -0
……@@ -0,0 +1,81 @@
1cmake_minimum_required(VERSION 3.25)
2
3find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
4find_package(cmake-fetch REQUIRED PATHS node_modules/cmake-fetch)
5find_package(cmake-napi REQUIRED PATHS node_modules/cmake-napi)
6find_package(cmake-npm REQUIRED PATHS node_modules/cmake-npm)
7
8project(udx_native C CXX)
9
10bare_target(target)
11
12if(target MATCHES "win32")
13 add_compile_options(/MT$<$<CONFIG:Debug>:d>)
14endif()
15
16fetch_package("github:holepunchto/libudx#25b063b")
17fetch_package("github:holepunchto/libjstl#098664c")
18
19add_bare_module(udx_native_bare)
20
21target_sources(
22 ${udx_native_bare}
23 PRIVATE
24 binding.cc
25)
26
27target_link_libraries(
28 ${udx_native_bare}
29 PRIVATE
30 $<TARGET_OBJECTS:udx>
31 jstl
32 PUBLIC
33 udx
34)
35
36if(target MATCHES "win32")
37 target_link_libraries(
38 ${udx_native_bare}
39 PUBLIC
40 ws2_32
41 )
42endif()
43
44add_napi_module(udx_native_napi)
45
46target_sources(
47 ${udx_native_napi}
48 PRIVATE
49 binding.cc
50)
51
52target_compile_definitions(
53 ${udx_native_napi}
54 PRIVATE
55 NAPI_VERSION=9
56)
57
58target_link_libraries(
59 ${udx_native_napi}
60 PRIVATE
61 $<TARGET_OBJECTS:udx>
62 jstl
63 PUBLIC
64 udx
65)
66
67if(target MATCHES "win32")
68 target_link_libraries(
69 ${udx_native_napi}
70 PUBLIC
71 ws2_32
72 )
73endif()
74
75resolve_node_module(bare-compat-napi compat)
76
77target_include_directories(
78 ${udx_native_napi}
79 PRIVATE
80 "${compat}/include"
81)
node_modules/udx-native/LICENSE +201 -0
……@@ -0,0 +1,201 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
node_modules/udx-native/README.md +403 -0
……@@ -0,0 +1,403 @@
1# udx-native
2
3udx is reliable, multiplexed, and congestion-controlled streams over udp.
4
5```
6npm i udx-native
7```
8
9It's a transport protocol, made only for peer-to-peer networking.
10
11No handshakes. No encryption. No features. This is good for P2P.\
12Just fast streams and messages that are composable into powerful things.
13
14## Usage
15
16```js
17const UDX = require('udx-native')
18
19const u = new UDX()
20const a = u.createSocket()
21const b = u.createSocket()
22
23b.on('message', function (message) {
24 console.log('received', message.toString())
25 a.close()
26 b.close()
27})
28
29b.bind(0)
30a.send(Buffer.from('hello'), b.address().port)
31```
32
33```js
34const UDX = require('udx-native')
35
36const u = new UDX()
37
38const socket1 = u.createSocket()
39const socket2 = u.createSocket()
40
41socket1.bind()
42socket2.bind()
43
44const stream1 = u.createStream(1)
45const stream2 = u.createStream(2)
46
47stream1.connect(socket1, stream2.id, socket2.address().port, '127.0.0.1')
48stream2.connect(socket2, stream1.id, socket1.address().port, '127.0.0.1')
49
50stream1.write(Buffer.from('hello'))
51stream1.end()
52
53stream2.on('data', function (data) {
54 console.log(data)
55})
56
57stream2.on('end', function () {
58 stream2.end()
59})
60
61stream1.on('close', function () {
62 console.log('stream1 closed')
63 socket1.close()
64})
65
66stream2.on('close', function () {
67 console.log('stream2 closed')
68 socket2.close()
69})
70```
71
72## API
73
74#### `const udx = new UDX()`
75
76Creates a new UDX instance.
77
78#### `const bool = UDX.isIPv4(host)`
79
80Returns `true` if host is an IPv4 address.
81
82#### `const bool = UDX.isIPv6(host)`
83
84Returns `true` if host is an IPv6 address.
85
86#### `const family = UDX.isIP(host)`
87
88Returns the address family (`4` or `6`). Returns `0` if invalid.
89
90## Sockets
91
92#### `const socket = udx.createSocket([options])`
93
94Creates a new socket instance.
95
96Available `options`:
97
98```js
99{
100 ipv6Only: false,
101 reuseAddress: false
102}
103```
104
105#### `socket.udx`
106
107It's the UDX instance from where the socket was created.
108
109#### `socket.streams`
110
111It's a `Set` that tracks active streams (connected to the socket but not closed).
112
113#### `socket.userData`
114
115Optional custom userData. Default is `null`.
116
117#### `socket.bound`
118
119Indicates if it's bound to any port. It will be `true` after a successful `bind()`.
120
121#### `socket.closing`
122
123It will be `true` after `close()` is called.
124
125#### `socket.idle`
126
127Indicates that the socket doesn't have any connected stream.
128
129#### `socket.busy`
130
131Indicates that the socket have at least one connected stream.
132
133#### `socket.address()`
134
135Returns an object like `{ host, family, port }`. Only available after `bind()`.
136
137#### `socket.bind([port], [host])`
138
139The default port is `0`.\
140If no host specified: it binds to IPv6 `::`. If fails then IPv4 `0.0.0.0`.
141
142#### `await socket.close()`
143
144It unbinds the socket so it stops listening for messages.
145
146#### `socket.setTTL(ttl)`
147
148Sets the amount of times that a packet is allowed to be forwarded through each router or gateway before being discarded.
149
150#### `socket.getRecvBufferSize()`
151
152#### `socket.setRecvBufferSize()`
153
154#### `socket.getSendBufferSize()`
155
156#### `socket.setSendBufferSize()`
157
158#### `await socket.send(buffer, port, [host], [ttl])`
159
160Sends a message to port and host destination. Default host is `127.0.0.1`.
161
162#### `socket.trySend(buffer, port, [host], [ttl])`
163
164Same behaviour as `send()` but no promise.
165
166#### `socket.on('message', (msg, from) => {})`
167
168`msg` is a buffer that containts the message.\
169`from` is an object like `{ host, family, port }`.
170
171#### `socket.on('close', onclose)`
172
173Emitted if the socket was ever bound and it got closed.
174
175#### `socket.on('idle', onidle)`
176
177Emitted if the socket becomes idle (no active streams).
178
179#### `socket.on('busy', onbusy)`
180
181Emitted if the socket becomes busy (at least one active stream).
182
183#### `socket.on('listening', onlistening)`
184
185Emitted after a succesfull `bind()` call.
186
187## Streams
188
189#### `const stream = udx.createStream(id, [options])`
190
191Creates a new stream instance that is a Duplex stream.
192
193Available `options`:
194
195```js
196{
197 firewall: (socket, port, host) => true,
198 framed: false,
199 seq: 0
200}
201```
202
203#### `stream.udx`
204
205It's the UDX instance from where the stream was created.
206
207#### `stream.socket`
208
209Refers to the socket that is connected to. Setted when you `connect()` the stream.
210
211#### `stream.id`
212
213Custom stream id.
214
215#### `stream.remoteId`
216
217Remote stream id. Setted when you `connect()` the stream.
218
219#### `stream.remoteId`
220
221Remote stream id. Setted when you `connect()` the stream.
222
223#### `stream.remoteHost`
224
225Remote host. Setted when you `connect()` the stream.
226
227#### `stream.remoteFamily`
228
229Remote family (`4` or `6`). Setted when you `connect()` the stream.
230
231#### `stream.remotePort`
232
233Remote port. Setted when you `connect()` the stream.
234
235#### `stream.userData`
236
237Optional custom userData. Default is `null`.
238
239#### `stream.connected`
240
241Indicates if the stream is connected to a socket. It becomes `false` if the stream is closed.
242
243#### `stream.mtu`
244
245Indicates the maximum size of each packet.
246
247#### `stream.rtt`
248
249#### `stream.cwnd`
250
251#### `stream.inflight`
252
253#### `stream.localHost`
254
255Indicates the connected socket host address. By default `null` if not connected.
256
257#### `stream.localFamily`
258
259Indicates the connected socket family address (`4` o `6`). By default `0` if not connected.
260
261#### `stream.localPort`
262
263Indicates the connected socket port. By default `0` if not connected.
264
265#### `stream.setInteractive(bool)`
266
267#### `stream.connect(socket, remoteId, port, [host], [options])`
268
269Connects the stream using a socket to a: remote stream id, and remote socket port/host.
270
271If no host specified it uses `127.0.0.1` by default.
272
273Available `options`:
274
275```js
276{
277 ack
278}
279```
280
281#### `await stream.changeRemote(remoteId, port, [host])`
282
283Change the remote end of the stream.
284
285If no host specified it uses `127.0.0.1` by default.
286
287#### `stream.relayTo(destination)`
288
289Relay stream to another stream.
290
291#### `await stream.send(buffer)`
292
293Send a message to another stream. Returns a promise.
294
295#### `stream.trySend(buffer)`
296
297Send a message to another stream.
298
299#### `const drained = await stream.flush()`
300
301Wait for pending stream writes to have been explicitly acknowledged by the other side of the connection.
302
303#### `stream.on('connect', onconnect)`
304
305Emitted after the stream is connected to a socket.
306
307#### `stream.on('message', onmessage)`
308
309Emitted if the stream receives a message.
310
311#### `stream.on('remote-changed', onremotechanged)`
312
313Emitted when the remote end of the stream changes.
314
315#### `stream.on('mtu-exceeded', onmtuexceeded)`
316
317Emitted only once if you write data that exceeds the MTU.
318
319## Network interfaces
320
321#### `const interfaces = udx.networkInterfaces()`
322
323Returns an array of network interfaces, for example:
324
325```js
326;[
327 { name: 'lo', host: '127.0.0.1', family: 4, internal: true },
328 { name: 'enp4s0', host: '192.168.0.20', family: 4, internal: false },
329 { name: 'lo', host: '::1', family: 6, internal: true },
330 {
331 name: 'enp4s0',
332 host: 'df08::c8df:bf61:95c1:352b',
333 family: 6,
334 internal: false
335 }
336]
337```
338
339#### `const watcher = udx.watchNetworkInterfaces([onchange])`
340
341Listens to changes in the network interfaces. The `watcher` object is iterable.
342
343#### `watcher.interfaces`
344
345Array of network interfaces.
346
347#### `watcher.watch()`
348
349Starts watching for changes. By default it already does it. This is only useful after you `unwatch()`.
350
351#### `watcher.unwatch()`
352
353Stops watching for changes.
354
355#### `await watcher.destroy()`
356
357Closes the watcher.
358
359#### `watcher.on('change', onchange)`
360
361Emitted after a network interface change.
362
363#### `watcher.on('close', onclose)`
364
365Emitted after the watcher is closed.
366
367## DNS
368
369#### `const address = await udx.lookup(host, [options])`
370
371It does a DNS lookup for the IP address. Returns `{ host, family }`.
372
373Available `options`:
374
375```js
376{
377 family: 0 // => 0, 4 or 6
378}
379```
380
381## Dev Setup
382
383To develop UDX locally, you need to create a libudx prebuild. [bare-make](https://github.com/holepunchto/bare-make) is used for this.
384
385Requirements: The Clang C-compiler should be installed.
386
387The other setup steps are:
388
389- `npm install -g bare-runtime bare-make`
390- `npm install`
391- `bare-make generate`
392- `bare-make build`
393- `bare-make install`
394
395When testing changes, rebuild the prebuilds:
396
397- `bare-make generate`
398- `bare-make build`
399- `bare-make install`
400
401## License
402
403Apache-2.0
node_modules/udx-native/binding.cc +1781 -0
……@@ -0,0 +1,1781 @@
1#include <bare.h>
2#include <js.h>
3#include <jstl.h>
4#include <stdlib.h>
5#include <string.h>
6#include <udx.h>
7
8#define UDX_NAPI_INTERACTIVE 0
9#define UDX_NAPI_NON_INTERACTIVE 1
10#define UDX_NAPI_FRAMED 2
11
12namespace {
13// socket
14using cb_socket_send_t = js_function_t<void, js_receiver_t, uint64_t, int>;
15using cb_socket_message_t = js_function_t<js_typedarray_span_t<>, js_receiver_t, int64_t, int, std::string, int>;
16using cb_socket_close_t = js_function_t<void, js_receiver_t>;
17using cb_socket_realloc_message_t = js_function_t<js_typedarray_span_t<>, js_receiver_t>;
18
19// stream
20using cb_stream_end_t = js_function_t<void, js_receiver_t, uint32_t>;
21using cb_stream_data_t = js_function_t<js_typedarray_span_t<>, js_receiver_t, uint32_t>;
22using cb_stream_drain_t = js_function_t<void, js_receiver_t>;
23using cb_stream_ack_t = js_function_t<void, js_receiver_t, uint32_t>;
24using cb_stream_send_t = js_function_t<void, js_receiver_t, int32_t, int32_t>;
25using cb_stream_message_t = js_function_t<js_typedarray_span_t<>, js_receiver_t, uint32_t>;
26using cb_stream_realloc_data_t = js_function_t<js_typedarray_span_t<>, js_receiver_t>;
27using cb_stream_realloc_message_t = js_function_t<js_typedarray_span_t<>, js_receiver_t>;
28using cb_stream_close_t = js_function_t<void, js_receiver_t, std::optional<js_object_t>>;
29using cb_stream_firewall_t = js_function_t<uint32_t, js_receiver_t, js_receiver_t, uint32_t, std::string, uint32_t>;
30using cb_stream_remote_changed_t = js_function_t<void, js_receiver_t>;
31
32// udx
33using cb_udx_lookup_t = js_function_t<void, js_receiver_t, std::optional<js_object_t>, std::optional<std::string>, int32_t>;
34
35// interface
36using cb_interface_event_t = js_function_t<void, js_receiver_t>;
37using cb_interface_close_t = js_function_t<void, js_receiver_t>;
38}; // namespace
39
40struct udx_napi_t {
41 udx_t udx;
42
43 uint8_t *read_buf;
44 size_t read_buf_free;
45
46 js_deferred_teardown_t *teardown;
47 bool exiting;
48};
49
50struct udx_napi_socket_t {
51 udx_socket_t socket;
52 udx_napi_t *udx;
53
54 js_env_t *env;
55
56 js_persistent_t<js_receiver_t> ctx;
57
58 js_persistent_t<cb_socket_send_t> on_send;
59 js_persistent_t<cb_socket_message_t> on_message;
60 js_persistent_t<cb_socket_close_t> on_close;
61 js_persistent_t<cb_socket_realloc_message_t> realloc_message; // TODO: deprecate
62};
63
64struct udx_napi_stream_t {
65 udx_stream_t stream;
66 udx_napi_t *udx;
67
68 int mode;
69
70 uint8_t *read_buf;
71 uint8_t *read_buf_head;
72 size_t read_buf_free;
73
74 ssize_t frame_len;
75
76 js_env_t *env;
77 js_persistent_t<js_receiver_t> ctx;
78 js_persistent_t<cb_stream_data_t> on_data;
79 js_persistent_t<cb_stream_end_t> on_end;
80 js_persistent_t<cb_stream_drain_t> on_drain;
81 js_persistent_t<cb_stream_ack_t> on_ack;
82 js_persistent_t<cb_stream_send_t> on_send;
83 js_persistent_t<cb_stream_message_t> on_message;
84 js_persistent_t<cb_stream_close_t> on_close;
85 js_persistent_t<cb_stream_firewall_t> on_firewall;
86 js_persistent_t<cb_stream_remote_changed_t> on_remote_changed;
87 js_persistent_t<cb_stream_realloc_data_t> realloc_data;
88 js_persistent_t<cb_stream_realloc_message_t> realloc_message; // TODO: deprecate
89};
90
91struct udx_napi_lookup_t {
92 udx_lookup_t handle;
93 udx_napi_t *udx;
94
95 js_env_t *env;
96 js_persistent_t<js_receiver_t> ctx;
97 js_persistent_t<cb_udx_lookup_t> on_lookup;
98};
99
100struct udx_napi_interface_event_t {
101 udx_interface_event_t handle;
102 udx_napi_t *udx;
103
104 js_env_t *env;
105 js_persistent_t<js_receiver_t> ctx;
106 js_persistent_t<cb_interface_event_t> on_event;
107 js_persistent_t<cb_interface_close_t> on_close;
108};
109
110inline static void
111parse_address (const struct sockaddr *name, char *ip, size_t size, int *port, int *family) {
112 if (name->sa_family == AF_INET) {
113 auto name_v4 = reinterpret_cast<const struct sockaddr_in *>(name);
114
115 if (port) *port = ntohs(name_v4->sin_port);
116 if (family) *family = 4;
117
118 uv_ip4_name(name_v4, ip, size);
119 } else if (name->sa_family == AF_INET6) {
120 auto name_v6 = reinterpret_cast<const struct sockaddr_in6 *>(name);
121
122 if (port) *port = ntohs(name_v6->sin6_port);
123 if (family) *family = 6;
124
125 uv_ip6_name(name_v6, ip, size);
126 }
127}
128
129inline static int
130load_address (js_env_t *env, char *addr, std::string str) {
131 memset(addr, 0, INET6_ADDRSTRLEN);
132
133 const char *val = str.c_str();
134
135 size_t len = INET6_ADDRSTRLEN;
136 if (str.length() < INET6_ADDRSTRLEN) len = str.length();
137
138 strncpy(addr, val, len);
139
140 return len;
141}
142
143static void
144on_udx_send (udx_socket_send_t *req, int status) {
145 int err;
146
147 auto *n = reinterpret_cast<udx_napi_socket_t *>(req->socket);
148
149 if (n->udx->exiting) return;
150
151 js_env_t *env = n->env;
152
153 js_handle_scope_t *scope;
154 err = js_open_handle_scope(env, &scope);
155 assert(err == 0);
156
157 js_receiver_t ctx;
158 err = js_get_reference_value(env, n->ctx, ctx);
159 assert(err == 0);
160
161 cb_socket_send_t callback;
162 err = js_get_reference_value(env, n->on_send, callback);
163 assert(err == 0);
164
165 auto id = reinterpret_cast<uintptr_t>(req->data);
166
167 err = js_call_function_with_checkpoint(env, callback, ctx, uint64_t(id), status);
168 assert(err == 0);
169
170 err = js_close_handle_scope(env, scope);
171 assert(err == 0);
172}
173
174static void
175on_udx_message (udx_socket_t *self, ssize_t read_len, const uv_buf_t *buf, const struct sockaddr *from) {
176 auto *n = reinterpret_cast<udx_napi_socket_t *>(self);
177
178 if (n->udx->exiting) return;
179
180 int err;
181 int port = 0;
182 char ip[INET6_ADDRSTRLEN];
183 int family = 0;
184 parse_address(from, ip, INET6_ADDRSTRLEN, &port, &family);
185
186 if (buf->len > n->udx->read_buf_free) return;
187
188 memcpy(n->udx->read_buf, buf->base, buf->len);
189
190 js_env_t *env = n->env;
191
192 js_handle_scope_t *scope;
193 err = js_open_handle_scope(env, &scope);
194 assert(err == 0);
195
196 js_receiver_t ctx;
197 err = js_get_reference_value(env, n->ctx, ctx);
198 assert(err == 0);
199
200 cb_socket_message_t callback;
201 err = js_get_reference_value(env, n->on_message, callback);
202 assert(err == 0);
203
204 std::string ip_str;
205 ip_str = ip;
206
207 js_typedarray_span_t<> res;
208 err = js_call_function_with_checkpoint<js_type_options_t{}, js_typedarray_span_t<>, js_receiver_t, int64_t, int, std::string, int>(
209 env,
210 callback,
211 ctx,
212 int64_t(read_len),
213 port,
214 ip_str,
215 family,
216 res
217 );
218
219 if (err == 0) {
220 n->udx->read_buf = res.data();
221 n->udx->read_buf_free = res.size();
222 } else {
223 // avoid reentry
224 if (!(n->udx->exiting)) {
225 int err;
226 js_env_t *env = n->env;
227
228 js_handle_scope_t *scope;
229 err = js_open_handle_scope(env, &scope);
230 assert(err == 0);
231
232 js_receiver_t ctx;
233 err = js_get_reference_value(env, n->ctx, ctx);
234 assert(err == 0);
235
236 cb_socket_realloc_message_t callback;
237 err = js_get_reference_value(env, n->realloc_message, callback);
238 assert(err == 0);
239
240 err = js_call_function_with_checkpoint<js_type_options_t{}, js_typedarray_span_t<>, js_receiver_t>(env, callback, ctx, res);
241 assert(err == 0);
242
243 n->udx->read_buf = res.data();
244 n->udx->read_buf_free = res.size();
245
246 err = js_close_handle_scope(env, scope);
247 assert(err == 0);
248 }
249 }
250
251 err = js_close_handle_scope(env, scope);
252 assert(err == 0);
253}
254
255static void
256on_udx_close (udx_socket_t *self) {
257 auto n = reinterpret_cast<udx_napi_socket_t *>(self);
258 int err;
259 js_env_t *env = n->env;
260
261 if (!(n->udx->exiting)) {
262 js_handle_scope_t *scope;
263 err = js_open_handle_scope(env, &scope);
264 assert(err == 0);
265
266 js_receiver_t ctx;
267 err = js_get_reference_value(env, n->ctx, ctx);
268 assert(err == 0);
269
270 cb_socket_close_t callback;
271 err = js_get_reference_value(env, n->on_close, callback);
272 assert(err == 0);
273
274 err = js_call_function_with_checkpoint(env, callback, ctx);
275 assert(err == 0);
276
277 err = js_close_handle_scope(env, scope);
278 assert(err == 0);
279 }
280
281 n->on_send.reset();
282 n->on_message.reset();
283 n->on_close.reset();
284 n->realloc_message.reset();
285 n->ctx.reset();
286}
287
288static void
289on_udx_teardown (js_deferred_teardown_t *handle, void *data) {
290 auto self = reinterpret_cast<udx_napi_t *>(data);
291
292 self->exiting = true;
293
294 udx_teardown(&self->udx);
295}
296
297static void
298ensure_teardown (js_env_t *env, udx_napi_t *udx) {
299 if (udx->teardown) return;
300
301 int err = js_add_deferred_teardown_callback(
302 env,
303 on_udx_teardown,
304 reinterpret_cast<void *>(udx),
305 &udx->teardown
306 );
307
308 if (err != 0) abort();
309}
310
311static void
312on_udx_stream_end (udx_stream_t *stream) {
313 int err;
314 auto n = reinterpret_cast<udx_napi_stream_t *>(stream);
315 if (n->udx->exiting) return;
316
317 size_t read = n->read_buf_head - n->read_buf;
318
319 js_env_t *env = n->env;
320
321 js_handle_scope_t *scope;
322 err = js_open_handle_scope(env, &scope);
323 assert(err == 0);
324
325 js_receiver_t ctx;
326 err = js_get_reference_value(env, n->ctx, ctx);
327 assert(err == 0);
328
329 cb_stream_end_t callback;
330 err = js_get_reference_value(env, n->on_end, callback);
331 assert(err == 0);
332
333 err = js_call_function_with_checkpoint(env, callback, ctx, uint32_t(read));
334 assert(err == 0);
335
336 err = js_close_handle_scope(env, scope);
337 assert(err == 0);
338}
339
340static void
341on_udx_stream_read (udx_stream_t *stream, ssize_t read_len, const uv_buf_t *buf) {
342 if (read_len == UV_EOF) return on_udx_stream_end(stream);
343
344 auto n = reinterpret_cast<udx_napi_stream_t *>(stream);
345 if (n->udx->exiting) return;
346
347 // ignore the message if it doesn't fit in the read buffer
348 if (buf->len > n->read_buf_free) return;
349
350 if (n->mode == UDX_NAPI_FRAMED && n->frame_len == -1) {
351 if (buf->len < 3) {
352 n->mode = UDX_NAPI_INTERACTIVE;
353 } else {
354 auto b = reinterpret_cast<uint8_t *>(buf->base);
355 n->frame_len = 3 + (b[0] | (b[1] << 8) | (b[2] << 16));
356 }
357 }
358
359 memcpy(n->read_buf_head, buf->base, buf->len);
360
361 n->read_buf_head += buf->len;
362 n->read_buf_free -= buf->len;
363
364 if (n->mode == UDX_NAPI_NON_INTERACTIVE && n->read_buf_free >= 2 * stream->mtu) {
365 return;
366 }
367
368 ssize_t read = n->read_buf_head - n->read_buf;
369
370 if (n->mode == UDX_NAPI_FRAMED) {
371 if (n->frame_len < read) {
372 n->mode = UDX_NAPI_INTERACTIVE;
373 } else if (n->frame_len == read) {
374 n->frame_len = -1;
375 } else if (n->read_buf_free < 2 * stream->mtu) {
376 n->frame_len -= read;
377 } else {
378 return; // wait for more data
379 }
380 }
381
382 js_env_t *env = n->env;
383
384 js_handle_scope_t *scope;
385 int err = js_open_handle_scope(env, &scope);
386 assert(err == 0);
387
388 js_receiver_t ctx;
389 err = js_get_reference_value(env, n->ctx, ctx);
390 assert(err == 0);
391
392 cb_stream_data_t callback;
393 err = js_get_reference_value(env, n->on_data, callback);
394 assert(err == 0);
395
396 js_typedarray_span_t<> res;
397 err = js_call_function_with_checkpoint<js_type_options_t{}, js_typedarray_span_t<>, js_receiver_t, uint32_t>(env, callback, ctx, uint32_t(read), res);
398
399 if (err == 0) {
400 n->read_buf = res.data();
401 n->read_buf_free = res.size();
402 n->read_buf_head = n->read_buf;
403 } else {
404 // avoid re-entry
405 if (!(n->udx->exiting)) {
406 js_handle_scope_t *inner_scope;
407 err = js_open_handle_scope(env, &inner_scope);
408 assert(err == 0);
409
410 js_receiver_t ctx;
411 err = js_get_reference_value(env, n->ctx, ctx);
412 assert(err == 0);
413
414 cb_stream_realloc_data_t callback;
415 err = js_get_reference_value(env, n->realloc_data, callback);
416 assert(err == 0);
417
418 err = js_call_function_with_checkpoint<js_type_options_t{}, js_typedarray_span_t<>, js_receiver_t>(env, callback, ctx, res);
419 assert(err == 0);
420
421 n->read_buf = res.data();
422 n->read_buf_free = res.size();
423 n->read_buf_head = n->read_buf;
424
425 err = js_close_handle_scope(env, inner_scope);
426 assert(err == 0);
427 }
428 }
429
430 err = js_close_handle_scope(env, scope);
431 assert(err == 0);
432}
433
434static void
435on_udx_stream_drain (udx_stream_t *stream) {
436 auto n = reinterpret_cast<udx_napi_stream_t *>(stream);
437 if (n->udx->exiting) return;
438
439 js_env_t *env = n->env;
440
441 js_handle_scope_t *scope;
442 int err = js_open_handle_scope(env, &scope);
443 assert(err == 0);
444
445 js_receiver_t ctx;
446 err = js_get_reference_value(env, n->ctx, ctx);
447 assert(err == 0);
448
449 cb_stream_drain_t callback;
450 err = js_get_reference_value(env, n->on_drain, callback);
451 assert(err == 0);
452
453 err = js_call_function_with_checkpoint(env, callback, ctx);
454 assert(err == 0);
455
456 err = js_close_handle_scope(env, scope);
457 assert(err == 0);
458}
459
460static void
461on_udx_stream_ack (udx_stream_write_t *req, int status, int unordered) {
462 int err = 0;
463
464 auto n = reinterpret_cast<udx_napi_stream_t *>(req->stream);
465 if (n->udx->exiting) return;
466
467 js_env_t *env = n->env;
468
469 js_handle_scope_t *scope;
470 err = js_open_handle_scope(env, &scope);
471 assert(err == 0);
472
473 js_receiver_t ctx;
474 err = js_get_reference_value(env, n->ctx, ctx);
475 assert(err == 0);
476
477 cb_stream_ack_t callback;
478 err = js_get_reference_value(env, n->on_ack, callback);
479 assert(err == 0);
480
481 auto offset = reinterpret_cast<uintptr_t>(req->data);
482
483 err = js_call_function_with_checkpoint(env, callback, ctx, uint32_t(offset));
484 assert(err == 0);
485
486 err = js_close_handle_scope(env, scope);
487 assert(err == 0);
488}
489
490static void
491on_udx_stream_send (udx_stream_send_t *req, int status) {
492 int err;
493
494 auto n = reinterpret_cast<udx_napi_stream_t *>(req->stream);
495
496 if (n->udx->exiting) return;
497
498 js_env_t *env = n->env;
499
500 js_handle_scope_t *scope;
501 err = js_open_handle_scope(env, &scope);
502 assert(err == 0);
503
504 js_receiver_t ctx;
505 err = js_get_reference_value(env, n->ctx, ctx);
506 assert(err == 0);
507
508 cb_stream_send_t callback;
509 err = js_get_reference_value(env, n->on_send, callback);
510 assert(err == 0);
511
512 auto id = reinterpret_cast<uintptr_t>(req->data);
513
514 err = js_call_function_with_checkpoint(env, callback, ctx, int32_t(id), status);
515 assert(err == 0);
516
517 err = js_close_handle_scope(env, scope);
518 assert(err == 0);
519}
520
521static void
522on_udx_stream_recv (udx_stream_t *stream, ssize_t read_len, const uv_buf_t *buf) {
523 int err;
524
525 auto n = reinterpret_cast<udx_napi_stream_t *>(stream);
526
527 if (n->udx->exiting) return;
528
529 if (buf->len > n->udx->read_buf_free) return;
530
531 memcpy(n->udx->read_buf, buf->base, buf->len);
532
533 js_env_t *env = n->env;
534
535 js_handle_scope_t *scope;
536 err = js_open_handle_scope(env, &scope);
537 assert(err == 0);
538
539 js_receiver_t ctx;
540 err = js_get_reference_value(env, n->ctx, ctx);
541 assert(err == 0);
542
543 cb_stream_message_t callback;
544 err = js_get_reference_value(env, n->on_message, callback);
545 assert(err == 0);
546
547 js_typedarray_span_t<> res;
548 err = js_call_function_with_checkpoint<js_type_options_t{}, js_typedarray_span_t<>, js_receiver_t, uint32_t>(env, callback, ctx, uint32_t(read_len), res);
549
550 if (err == 0) {
551 n->udx->read_buf = res.data();
552 n->udx->read_buf_free = res.size();
553 } else {
554 // avoid re-entry
555 if (!(n->udx->exiting)) {
556 js_handle_scope_t *inner_scope;
557 err = js_open_handle_scope(env, &inner_scope);
558 assert(err == 0);
559
560 js_receiver_t ctx;
561 err = js_get_reference_value(env, n->ctx, ctx);
562 assert(err == 0);
563
564 cb_stream_realloc_message_t callback;
565 err = js_get_reference_value(env, n->realloc_message, callback);
566 assert(err == 0);
567
568 err = js_call_function_with_checkpoint<js_type_options_t{}, js_typedarray_span_t<>, js_receiver_t>(env, callback, ctx, res);
569 assert(err == 0);
570
571 n->udx->read_buf = res.data();
572 n->udx->read_buf_free = res.size();
573
574 err = js_close_handle_scope(env, inner_scope);
575 assert(err == 0);
576 }
577 }
578
579 err = js_close_handle_scope(env, scope);
580 assert(err == 0);
581}
582
583static void
584on_udx_stream_finalize (udx_stream_t *stream) {
585 auto n = reinterpret_cast<udx_napi_stream_t *>(stream);
586
587 n->on_data.reset();
588 n->on_end.reset();
589 n->on_drain.reset();
590 n->on_ack.reset();
591 n->on_send.reset();
592 n->on_message.reset();
593 n->on_close.reset();
594 n->on_firewall.reset();
595 n->on_remote_changed.reset();
596 n->realloc_data.reset();
597 n->realloc_message.reset();
598 n->ctx.reset();
599}
600
601static void
602on_udx_stream_close (udx_stream_t *stream, int status) {
603 int err;
604
605 auto n = reinterpret_cast<udx_napi_stream_t *>(stream);
606
607 if (n->udx->exiting) return;
608
609 js_env_t *env = n->env;
610
611 js_handle_scope_t *scope;
612 err = js_open_handle_scope(env, &scope);
613 assert(err == 0);
614
615 js_receiver_t ctx;
616 err = js_get_reference_value(env, n->ctx, ctx);
617 assert(err == 0);
618
619 cb_stream_close_t callback;
620 err = js_get_reference_value(env, n->on_close, callback);
621 assert(err == 0);
622
623 std::optional<js_object_t> res;
624
625 if (status < 0) {
626 js_string_t code;
627 err = js_create_string(env, uv_err_name(status), code);
628 assert(err == 0);
629
630 res.emplace(); // init
631
632 err = js_create_error(env, code, uv_strerror(status), *res);
633 assert(err == 0);
634 }
635
636 err = js_call_function_with_checkpoint(env, callback, ctx, res);
637 assert(err == 0);
638
639 err = js_close_handle_scope(env, scope);
640 assert(err == 0);
641}
642
643static int
644on_udx_stream_firewall (udx_stream_t *stream, udx_socket_t *socket, const struct sockaddr *from) {
645 int err;
646 auto *n = reinterpret_cast<udx_napi_stream_t *>(stream);
647 auto *s = reinterpret_cast<udx_napi_socket_t *>(socket);
648
649 uint32_t fw = 1; // assume error means firewall it, whilst reporting the uncaught
650 if (n->udx->exiting) return fw;
651
652 int port = 0;
653 char ip[INET6_ADDRSTRLEN];
654 int family = 0;
655 parse_address(from, ip, INET6_ADDRSTRLEN, &port, &family);
656
657 js_env_t *env = n->env;
658
659 js_handle_scope_t *scope;
660 err = js_open_handle_scope(env, &scope);
661 assert(err == 0);
662
663 js_receiver_t ctx;
664 err = js_get_reference_value(env, n->ctx, ctx);
665 assert(err == 0);
666
667 cb_stream_firewall_t callback;
668 err = js_get_reference_value(env, n->on_firewall, callback);
669 assert(err == 0);
670
671 js_receiver_t socket_ctx;
672 err = js_get_reference_value(env, s->ctx, socket_ctx);
673 assert(err == 0);
674
675 err = js_call_function_with_checkpoint<js_type_options_t{}, uint32_t, js_receiver_t, js_receiver_t, uint32_t, std::string, uint32_t>(
676 env,
677 callback,
678 ctx,
679 socket_ctx,
680 uint32_t(port),
681 std::string(ip),
682 uint32_t(family),
683 fw
684 );
685 assert(err == 0);
686
687 err = js_close_handle_scope(env, scope);
688 assert(err == 0);
689
690 return fw;
691}
692
693static void
694on_udx_stream_remote_changed (udx_stream_t *stream) {
695 int err;
696
697 auto n = reinterpret_cast<udx_napi_stream_t *>(stream);
698
699 if (n->udx->exiting) return;
700
701 js_env_t *env = n->env;
702
703 js_handle_scope_t *scope;
704 err = js_open_handle_scope(env, &scope);
705 assert(err == 0);
706
707 js_receiver_t ctx;
708 err = js_get_reference_value(env, n->ctx, ctx);
709 assert(err == 0);
710
711 cb_stream_remote_changed_t callback;
712 err = js_get_reference_value(env, n->on_remote_changed, callback);
713 assert(err == 0);
714
715 err = js_call_function_with_checkpoint(env, callback, ctx);
716 assert(err == 0);
717
718 err = js_close_handle_scope(env, scope);
719 assert(err == 0);
720}
721
722static void
723on_udx_lookup (udx_lookup_t *lookup, int status, const struct sockaddr *addr, int addr_len) {
724 int err;
725
726 auto n = reinterpret_cast<udx_napi_lookup_t *>(lookup);
727 if (n->udx->exiting) return;
728
729 js_env_t *env = n->env;
730
731 char ip[INET6_ADDRSTRLEN] = "";
732 int family = 0;
733
734 js_handle_scope_t *scope;
735 err = js_open_handle_scope(env, &scope);
736 assert(err == 0);
737
738 js_receiver_t ctx;
739 err = js_get_reference_value(env, n->ctx, ctx);
740 assert(err == 0);
741
742 cb_udx_lookup_t callback;
743 err = js_get_reference_value(env, n->on_lookup, callback);
744 assert(err == 0);
745
746 std::optional<js_object_t> error;
747 std::optional<std::string> ip_str;
748
749 if (status >= 0) {
750 parse_address(addr, ip, addr_len, nullptr, &family);
751
752 ip_str = ip;
753 } else {
754 js_string_t code;
755 err = js_create_string(env, uv_err_name(status), code);
756 assert(err == 0);
757
758 error.emplace(); // init
759
760 err = js_create_error(env, code, uv_strerror(status), *error);
761 assert(err == 0);
762 }
763
764 err = js_call_function_with_checkpoint(env, callback, ctx, error, ip_str, family);
765 assert(err == 0);
766
767 err = js_close_handle_scope(env, scope);
768 assert(err == 0);
769
770 n->on_lookup.reset();
771 n->ctx.reset();
772}
773
774static void
775on_udx_interface_event (udx_interface_event_t *handle, int status) {
776 auto e = reinterpret_cast<udx_napi_interface_event_t *>(handle);
777 if (e->udx->exiting) return;
778
779 js_env_t *env = e->env;
780
781 js_handle_scope_t *scope;
782 int err = js_open_handle_scope(env, &scope);
783 assert(err == 0);
784
785 js_receiver_t ctx;
786 err = js_get_reference_value(env, e->ctx, ctx);
787 assert(err == 0);
788
789 cb_interface_event_t callback;
790 err = js_get_reference_value(env, e->on_event, callback);
791 assert(err == 0);
792
793 err = js_call_function_with_checkpoint(env, callback, ctx);
794 assert(err == 0);
795
796 err = js_close_handle_scope(env, scope);
797 assert(err == 0);
798}
799
800static void
801on_udx_interface_event_close (udx_interface_event_t *handle) {
802 auto e = reinterpret_cast<udx_napi_interface_event_t *>(handle);
803
804 if (e->udx->exiting) return;
805
806 js_env_t *env = e->env;
807
808 js_handle_scope_t *scope;
809 int err = js_open_handle_scope(env, &scope);
810 assert(err == 0);
811
812 js_receiver_t ctx;
813 err = js_get_reference_value(env, e->ctx, ctx);
814 assert(err == 0);
815
816 cb_interface_close_t callback;
817 err = js_get_reference_value(env, e->on_close, callback);
818 assert(err == 0);
819
820 err = js_call_function_with_checkpoint(env, callback, ctx);
821 assert(err == 0);
822
823 err = js_close_handle_scope(env, scope);
824 assert(err == 0);
825
826 e->on_event.reset();
827 e->on_close.reset();
828 e->ctx.reset();
829}
830
831static void
832on_udx_idle (udx_t *u) {
833 auto self = reinterpret_cast<udx_napi_t *>(u);
834
835 if (!self->teardown) return;
836
837 int err = js_finish_deferred_teardown_callback(self->teardown);
838
839 self->teardown = nullptr;
840
841 if (err != 0) abort();
842}
843
844static inline void
845udx_napi_init (
846 js_env_t *env,
847 js_typedarray_span_of_t<udx_napi_t, 1> self,
848 js_typedarray_span_t<> read_buf
849) {
850 int err;
851
852 *self = {};
853
854 uv_loop_t *loop;
855 err = js_get_env_loop(env, &loop);
856 assert(err == 0);
857
858 err = udx_init(loop, &self->udx, on_udx_idle);
859 assert(err == 0);
860
861 self->read_buf = read_buf.data();
862 self->read_buf_free = read_buf.size();
863
864 self->exiting = false;
865 self->teardown = nullptr;
866}
867
868static inline void
869udx_napi_socket_init (
870 js_env_t *env,
871 js_typedarray_span_of_t<udx_napi_t, 1> udx,
872 js_typedarray_span_of_t<udx_napi_socket_t, 1> self,
873
874 js_receiver_t ctx,
875
876 cb_socket_send_t on_send,
877 cb_socket_message_t on_message,
878 cb_socket_close_t on_close,
879 cb_socket_realloc_message_t realloc_message
880) {
881 int err;
882
883 *self = {};
884
885 udx_socket_t *socket = &self->socket;
886 self->udx = &*udx;
887 self->env = env;
888
889 err = udx_socket_init(&udx->udx, socket, on_udx_close);
890
891 if (err < 0) {
892 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
893 assert(err == 0);
894
895 return;
896 }
897
898 err = js_create_reference(env, ctx, self->ctx);
899 assert(err == 0);
900 err = js_create_reference(env, on_send, self->on_send);
901 assert(err == 0);
902 err = js_create_reference(env, on_message, self->on_message);
903 assert(err == 0);
904 err = js_create_reference(env, on_close, self->on_close);
905 assert(err == 0);
906 err = js_create_reference(env, realloc_message, self->realloc_message);
907 assert(err == 0);
908
909 ensure_teardown(env, udx);
910}
911
912static inline int32_t
913udx_napi_socket_bind (
914 js_env_t *env,
915 js_typedarray_span_of_t<udx_napi_socket_t, 1> self,
916 uint32_t port,
917 std::string ip_str,
918 uint32_t family,
919 uint32_t flags
920) {
921 int err;
922
923 auto socket = &self->socket;
924
925 char ip[INET6_ADDRSTRLEN];
926 load_address(env, ip, ip_str);
927
928 struct sockaddr_storage addr;
929 int addr_len;
930
931 if (family == 4) {
932 addr_len = sizeof(struct sockaddr_in);
933 err = uv_ip4_addr(ip, port, (struct sockaddr_in *) &addr);
934 } else {
935 addr_len = sizeof(struct sockaddr_in6);
936 err = uv_ip6_addr(ip, port, (struct sockaddr_in6 *) &addr);
937 }
938
939 if (err < 0) {
940 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
941 assert(err == 0);
942
943 return -1;
944 }
945
946 err = udx_socket_bind(socket, (struct sockaddr *) &addr, flags);
947 if (err < 0) {
948 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
949 assert(err == 0);
950 return -1;
951 }
952
953 // TODO: move the bottom stuff into another function, start, so error handling is easier
954
955 struct sockaddr_storage name;
956
957 // wont error in practice
958 err = udx_socket_getsockname(socket, (struct sockaddr *) &name, &addr_len);
959 if (err < 0) {
960 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
961 assert(err == 0);
962 return -1;
963 }
964
965 int local_port;
966
967 if (family == 4) {
968 local_port = ntohs(((struct sockaddr_in *) &name)->sin_port);
969 } else {
970 local_port = ntohs(((struct sockaddr_in6 *) &name)->sin6_port);
971 }
972
973 // wont error in practice
974 err = udx_socket_recv_start(socket, on_udx_message);
975 if (err < 0) {
976 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
977 assert(err == 0);
978 return -1;
979 }
980
981 return local_port;
982}
983
984static inline void
985udx_napi_socket_set_ttl (
986 js_env_t *env,
987 js_typedarray_span_of_t<udx_napi_socket_t, 1> self,
988 uint32_t ttl
989) {
990 int err;
991
992 err = udx_socket_set_ttl(&self->socket, ttl);
993
994 if (err < 0) {
995 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
996 assert(err == 0);
997 }
998}
999
1000static inline void
1001udx_napi_socket_set_membership (
1002 js_env_t *env,
1003 js_typedarray_span_of_t<udx_napi_socket_t, 1> socket,
1004 std::string mcast_addr_str,
1005 std::string iface_addr_str,
1006 bool join
1007) {
1008 int err;
1009
1010 char mcast_addr[INET6_ADDRSTRLEN];
1011 load_address(env, mcast_addr, mcast_addr_str);
1012
1013 char iface_addr[INET6_ADDRSTRLEN];
1014 size_t iface_addr_len = load_address(env, iface_addr, iface_addr_str);
1015
1016 char *iface_param = iface_addr_len > 0 ? iface_addr : NULL;
1017
1018 err = udx_socket_set_membership(&socket->socket, mcast_addr, iface_param, join ? UV_JOIN_GROUP : UV_LEAVE_GROUP);
1019
1020 if (err < 0) {
1021 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1022 assert(err == 0);
1023 }
1024}
1025
1026static inline uint32_t
1027udx_napi_socket_get_recv_buffer_size (
1028 js_env_t *env,
1029 js_typedarray_span_of_t<udx_napi_socket_t, 1> self
1030) {
1031 int err;
1032
1033 int size = 0;
1034
1035 err = udx_socket_get_recv_buffer_size(&self->socket, &size);
1036
1037 if (err < 0) {
1038 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1039 assert(err == 0);
1040 }
1041
1042 return size;
1043}
1044
1045static inline void
1046udx_napi_socket_set_recv_buffer_size (
1047 js_env_t *env,
1048 js_typedarray_span_of_t<udx_napi_socket_t, 1> self,
1049 uint32_t size
1050) {
1051 int err = udx_socket_set_recv_buffer_size(&self->socket, size);
1052
1053 if (err < 0) {
1054 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1055 assert(err == 0);
1056 }
1057}
1058
1059static inline uint32_t
1060udx_napi_socket_get_send_buffer_size (
1061 js_env_t *env,
1062 js_typedarray_span_of_t<udx_napi_socket_t, 1> self
1063) {
1064 int size = 0;
1065
1066 int err = udx_socket_get_send_buffer_size(&self->socket, &size);
1067
1068 if (err < 0) {
1069 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1070 assert(err == 0);
1071 }
1072
1073 return size;
1074}
1075
1076static inline uint32_t
1077udx_napi_socket_set_send_buffer_size (
1078 js_env_t *env,
1079 js_typedarray_span_of_t<udx_napi_socket_t, 1> self,
1080 uint32_t size
1081) {
1082 int err = udx_socket_set_send_buffer_size(&self->socket, size);
1083
1084 if (err < 0) {
1085 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1086 assert(err == 0);
1087 }
1088
1089 return size;
1090}
1091
1092static inline void
1093udx_napi_socket_send_ttl (
1094 js_env_t *env,
1095 js_typedarray_span_of_t<udx_napi_socket_t, 1> self,
1096 js_typedarray_span_of_t<udx_socket_send_t, 1> req,
1097 uint32_t rid,
1098 js_typedarray_span_of_t<char> buf,
1099 uint32_t port,
1100 std::string ip_str,
1101 uint32_t family,
1102 uint32_t ttl
1103) {
1104 int err;
1105
1106 char ip[INET6_ADDRSTRLEN];
1107 load_address(env, ip, ip_str);
1108
1109 req->data = reinterpret_cast<void *>(static_cast<uintptr_t>(rid));
1110
1111 struct sockaddr_storage addr;
1112
1113 if (family == 4) {
1114 err = uv_ip4_addr(ip, port, (struct sockaddr_in *) &addr);
1115 } else {
1116 err = uv_ip6_addr(ip, port, (struct sockaddr_in6 *) &addr);
1117 }
1118
1119 if (err < 0) {
1120 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1121 assert(err == 0);
1122 return;
1123 }
1124
1125 uv_buf_t b = uv_buf_init(buf.data(), buf.size());
1126
1127 err = udx_socket_send_ttl(req, &self->socket, &b, 1, (const struct sockaddr *) &addr, ttl, on_udx_send);
1128
1129 if (err < 0) {
1130 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1131 assert(err == 0);
1132 }
1133}
1134
1135static inline void
1136udx_napi_socket_close (
1137 js_env_t *env,
1138 js_typedarray_span_of_t<udx_napi_socket_t, 1> self
1139) {
1140 int err;
1141
1142 err = udx_socket_close(&self->socket);
1143
1144 if (err < 0) {
1145 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1146 assert(err == 0);
1147 }
1148}
1149
1150static inline void
1151udx_napi_stream_init (
1152 js_env_t *env,
1153 js_typedarray_span_of_t<udx_napi_t, 1> udx,
1154 js_typedarray_span_of_t<udx_napi_stream_t, 1> self,
1155
1156 uint32_t id,
1157 uint32_t framed,
1158 js_receiver_t ctx,
1159
1160 cb_stream_data_t on_data,
1161 cb_stream_end_t on_end,
1162 cb_stream_drain_t on_drain,
1163 cb_stream_ack_t on_ack,
1164 cb_stream_send_t on_send,
1165 cb_stream_message_t on_message,
1166 cb_stream_close_t on_close,
1167 cb_stream_firewall_t on_firewall,
1168 cb_stream_remote_changed_t on_remote_changed,
1169 cb_stream_realloc_data_t realloc_data,
1170 cb_stream_realloc_message_t realloc_message
1171) {
1172 int err;
1173
1174 *self = {};
1175
1176 self->mode = framed ? UDX_NAPI_FRAMED : UDX_NAPI_INTERACTIVE;
1177
1178 self->frame_len = -1;
1179
1180 self->read_buf = NULL;
1181 self->read_buf_head = NULL;
1182 self->read_buf_free = 0;
1183
1184 self->udx = udx;
1185 self->env = env;
1186
1187 auto stream = &self->stream;
1188
1189 err = udx_stream_init(&udx->udx, stream, id, on_udx_stream_close, on_udx_stream_finalize);
1190
1191 if (err < 0) {
1192 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1193 assert(err == 0);
1194
1195 return;
1196 }
1197
1198 err = js_create_reference(env, ctx, self->ctx);
1199 assert(err == 0);
1200 err = js_create_reference(env, on_data, self->on_data);
1201 assert(err == 0);
1202 err = js_create_reference(env, on_end, self->on_end);
1203 assert(err == 0);
1204 err = js_create_reference(env, on_drain, self->on_drain);
1205 assert(err == 0);
1206 err = js_create_reference(env, on_ack, self->on_ack);
1207 assert(err == 0);
1208 err = js_create_reference(env, on_send, self->on_send);
1209 assert(err == 0);
1210 err = js_create_reference(env, on_message, self->on_message);
1211 assert(err == 0);
1212 err = js_create_reference(env, on_close, self->on_close);
1213 assert(err == 0);
1214 err = js_create_reference(env, on_firewall, self->on_firewall);
1215 assert(err == 0);
1216 err = js_create_reference(env, on_remote_changed, self->on_remote_changed);
1217 assert(err == 0);
1218 err = js_create_reference(env, realloc_data, self->realloc_data);
1219 assert(err == 0);
1220 err = js_create_reference(env, realloc_message, self->realloc_message);
1221 assert(err == 0);
1222
1223 udx_stream_firewall(stream, on_udx_stream_firewall);
1224 udx_stream_write_resume(stream, on_udx_stream_drain);
1225
1226 ensure_teardown(env, udx);
1227}
1228
1229static inline void
1230udx_napi_stream_set_seq (
1231 js_env_t *env,
1232 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1233 uint32_t seq
1234) {
1235 int err = udx_stream_set_seq(&stream->stream, seq);
1236
1237 if (err < 0) {
1238 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1239 assert(err == 0);
1240 }
1241}
1242
1243static inline void
1244udx_napi_stream_set_ack (
1245 js_env_t *env,
1246 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1247 uint32_t ack
1248) {
1249 int err = udx_stream_set_ack(&stream->stream, ack);
1250
1251 if (err < 0) {
1252 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1253 assert(err == 0);
1254 }
1255}
1256
1257static inline void
1258udx_napi_stream_set_mode (
1259 js_env_t *env,
1260 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1261 uint32_t mode
1262) {
1263 stream->mode = mode;
1264}
1265
1266static inline void
1267udx_napi_stream_recv_start (
1268 js_env_t *env,
1269 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1270 js_typedarray_span_t<> read_buf
1271) {
1272 int err;
1273
1274 stream->read_buf = read_buf.data();
1275 stream->read_buf_head = read_buf.data();
1276 stream->read_buf_free = read_buf.size();
1277
1278 err = udx_stream_read_start(&stream->stream, on_udx_stream_read);
1279 assert(err == 0);
1280 err = udx_stream_recv_start(&stream->stream, on_udx_stream_recv);
1281 assert(err == 0);
1282}
1283
1284static inline void
1285udx_napi_stream_connect (
1286 js_env_t *env,
1287 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1288 js_typedarray_span_of_t<udx_napi_socket_t, 1> socket,
1289 uint32_t remote_id,
1290 uint32_t port,
1291 std::string ip_str,
1292 uint32_t family
1293) {
1294 int err;
1295
1296 char ip[INET6_ADDRSTRLEN];
1297 load_address(env, ip, ip_str);
1298
1299 struct sockaddr_storage addr;
1300
1301 if (family == 4) {
1302 err = uv_ip4_addr(ip, port, (struct sockaddr_in *) &addr);
1303 } else {
1304 err = uv_ip6_addr(ip, port, (struct sockaddr_in6 *) &addr);
1305 }
1306
1307 if (err < 0) {
1308 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1309 assert(err == 0);
1310 return;
1311 }
1312
1313 err = udx_stream_connect(&stream->stream, &socket->socket, remote_id, (const struct sockaddr *) &addr);
1314
1315 if (err < 0) {
1316 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1317 assert(err == 0);
1318 }
1319}
1320
1321static inline void
1322udx_napi_stream_change_remote (
1323 js_env_t *env,
1324 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1325 js_typedarray_span_of_t<udx_napi_socket_t, 1> socket,
1326 uint32_t remote_id,
1327 uint32_t port,
1328 std::string ip_str,
1329 uint32_t family
1330) {
1331 int err;
1332
1333 char ip[INET6_ADDRSTRLEN];
1334 load_address(env, ip, ip_str);
1335
1336 struct sockaddr_storage addr;
1337
1338 if (family == 4) {
1339 err = uv_ip4_addr(ip, port, (struct sockaddr_in *) &addr);
1340 } else {
1341 err = uv_ip6_addr(ip, port, (struct sockaddr_in6 *) &addr);
1342 }
1343
1344 if (err < 0) {
1345 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1346 assert(err == 0);
1347 return;
1348 }
1349
1350 int immediate = err = udx_stream_change_remote(&stream->stream, &socket->socket, remote_id, (const struct sockaddr *) &addr, on_udx_stream_remote_changed);
1351
1352 if (err < 0) {
1353 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1354 assert(err == 0);
1355 return;
1356 }
1357
1358 if (immediate == 1) {
1359 js_receiver_t ctx;
1360 err = js_get_reference_value(env, stream->ctx, ctx);
1361 assert(err == 0);
1362
1363 cb_stream_remote_changed_t callback;
1364 err = js_get_reference_value(env, stream->on_remote_changed, callback);
1365 assert(err == 0);
1366
1367 err = js_call_function(env, callback, ctx);
1368 assert(err == 0);
1369 }
1370}
1371
1372static inline void
1373udx_napi_stream_relay_to (
1374 js_env_t *env,
1375 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1376 js_typedarray_span_of_t<udx_napi_stream_t, 1> destination
1377) {
1378 int err = udx_stream_relay_to(&stream->stream, &destination->stream);
1379
1380 if (err < 0) {
1381 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1382 assert(err == 0);
1383 }
1384}
1385
1386static inline uint32_t
1387udx_napi_stream_send (
1388 js_env_t *env,
1389 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1390 js_typedarray_span_of_t<udx_stream_send_t, 1> req,
1391 uint32_t rid,
1392 js_typedarray_span_of_t<char> buf
1393) {
1394 req->data = reinterpret_cast<void *>(static_cast<uintptr_t>(rid));
1395
1396 uv_buf_t b = uv_buf_init(buf.data(), buf.size());
1397
1398 int res = udx_stream_send(req, &stream->stream, &b, 1, on_udx_stream_send);
1399
1400 if (res < 0) {
1401 int err = js_throw_error(env, uv_err_name(res), uv_strerror(res));
1402 assert(err == 0);
1403 }
1404
1405 return res;
1406}
1407
1408static inline int64_t
1409udx_napi_stream_write (
1410 js_env_t *env,
1411 js_receiver_t,
1412 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1413 js_typedarray_span_t<> req_handle,
1414 uint32_t rid,
1415 js_typedarray_span_of_t<char> buf
1416) {
1417 int err;
1418
1419 auto req = reinterpret_cast<udx_stream_write_t *>(req_handle.data());
1420
1421 req->data = reinterpret_cast<void *>(static_cast<uintptr_t>(rid));
1422
1423 auto b = uv_buf_init(buf.data(), buf.size());
1424
1425 int res = udx_stream_write(&*req, &stream->stream, &b, 1, on_udx_stream_ack);
1426
1427 if (res < 0) {
1428 err = js_throw_error(env, uv_err_name(res), uv_strerror(res));
1429 assert(err == 0);
1430 }
1431
1432 return res;
1433}
1434
1435// TODO: use only on platforms without fastcall support
1436static inline int64_t
1437udx_napi_stream_writev (
1438 js_env_t *env,
1439 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1440 js_typedarray_span_t<> req_handle,
1441 uint32_t rid,
1442 std::vector<js_typedarray_span_of_t<char>> buffers
1443) {
1444 int err;
1445
1446 auto req = reinterpret_cast<udx_stream_write_t *>(req_handle.data());
1447
1448 req->data = reinterpret_cast<void *>(static_cast<uintptr_t>(rid));
1449
1450 const auto len = buffers.size();
1451
1452 std::vector<uv_buf_t> batch(len);
1453
1454 for (int i = 0; i < len; i++) {
1455 auto buf = buffers[i];
1456 batch[i] = uv_buf_init(buf.data(), buf.size());
1457 }
1458
1459 int res = udx_stream_write(req, &stream->stream, batch.data(), len, on_udx_stream_ack);
1460
1461 if (res < 0) {
1462 err = js_throw_error(env, uv_err_name(res), uv_strerror(res));
1463 assert(err == 0);
1464 }
1465
1466 return res;
1467}
1468
1469static inline uint32_t
1470udx_napi_stream_write_sizeof (uint32_t bufs) {
1471 return udx_stream_write_sizeof(bufs);
1472}
1473
1474static inline uint32_t
1475udx_napi_stream_write_end (
1476 js_env_t *env,
1477 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream,
1478 js_typedarray_span_t<> req_handle,
1479 uint32_t rid,
1480 js_typedarray_span_of_t<char> buf
1481) {
1482
1483 auto req = reinterpret_cast<udx_stream_write_t *>(req_handle.data());
1484
1485 req->data = reinterpret_cast<void *>(static_cast<uintptr_t>(rid));
1486
1487 uv_buf_t b = uv_buf_init(buf.data(), buf.size());
1488
1489 int res = udx_stream_write_end(req, &stream->stream, &b, 1, on_udx_stream_ack);
1490
1491 if (res < 0) {
1492 int err = js_throw_error(env, uv_err_name(res), uv_strerror(res));
1493 assert(err == 0);
1494 }
1495
1496 return res;
1497}
1498
1499static inline uint32_t
1500udx_napi_stream_destroy (
1501 js_env_t *env,
1502 js_typedarray_span_of_t<udx_napi_stream_t, 1> stream
1503) {
1504 int res = udx_stream_destroy(&stream->stream);
1505
1506 if (res < 0) {
1507 int err = js_throw_error(env, uv_err_name(res), uv_strerror(res));
1508 assert(err == 0);
1509 }
1510
1511 return res;
1512}
1513
1514static inline void
1515udx_napi_lookup (
1516 js_env_t *env,
1517 js_typedarray_span_of_t<udx_napi_t, 1> udx,
1518 js_typedarray_span_of_t<udx_napi_lookup_t, 1> self,
1519 js_string_t host_str,
1520 uint32_t family,
1521 js_receiver_t ctx, // TODO: use auto receiver
1522 cb_udx_lookup_t on_lookup
1523) {
1524 int err;
1525
1526 *self = {};
1527
1528 self->udx = udx;
1529
1530 std::string host;
1531 err = js_get_value_string(env, host_str, host);
1532 assert(err == 0);
1533
1534 udx_lookup_t *lookup = &self->handle;
1535
1536 self->env = env;
1537
1538 int flags = 0;
1539
1540 if (family == 4) flags |= UDX_LOOKUP_FAMILY_IPV4;
1541 if (family == 6) flags |= UDX_LOOKUP_FAMILY_IPV6;
1542
1543 err = udx_lookup(&udx->udx, lookup, host.c_str(), flags, on_udx_lookup);
1544
1545 if (err < 0) {
1546 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1547 assert(err == 0);
1548
1549 return;
1550 }
1551
1552 err = js_create_reference(env, ctx, self->ctx);
1553 assert(err == 0);
1554 err = js_create_reference(env, on_lookup, self->on_lookup);
1555 assert(err == 0);
1556
1557 ensure_teardown(env, udx);
1558}
1559
1560static inline void
1561udx_napi_interface_event_init (
1562 js_env_t *env,
1563 js_typedarray_span_of_t<udx_napi_t, 1> udx,
1564 js_typedarray_span_of_t<udx_napi_interface_event_t, 1> self,
1565 js_receiver_t ctx,
1566 cb_interface_event_t on_event,
1567 cb_interface_close_t on_close
1568) {
1569 int err;
1570
1571 *self = {};
1572
1573 self->udx = udx;
1574 self->env = env;
1575
1576 err = udx_interface_event_init(&udx->udx, &self->handle, on_udx_interface_event_close);
1577
1578 if (err < 0) {
1579 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1580 assert(err == 0);
1581
1582 return;
1583 }
1584
1585 err = udx_interface_event_start(&self->handle, on_udx_interface_event, 5000);
1586
1587 if (err < 0) {
1588 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1589 assert(err == 0);
1590
1591 return;
1592 }
1593
1594 err = js_create_reference(env, ctx, self->ctx);
1595 assert(err == 0);
1596 err = js_create_reference(env, on_event, self->on_event);
1597 assert(err == 0);
1598 err = js_create_reference(env, on_close, self->on_close);
1599 assert(err == 0);
1600
1601 ensure_teardown(env, udx);
1602}
1603
1604static inline void
1605udx_napi_interface_event_start (
1606 js_env_t *env,
1607 js_typedarray_span_of_t<udx_napi_interface_event_t, 1> self
1608) {
1609 int err = udx_interface_event_start(&self->handle, on_udx_interface_event, 5000);
1610
1611 if (err < 0) {
1612 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1613 assert(err == 0);
1614 }
1615}
1616
1617static inline void
1618udx_napi_interface_event_stop (
1619 js_env_t *env,
1620 js_typedarray_span_of_t<udx_napi_interface_event_t, 1> self
1621) {
1622 int err;
1623
1624 err = udx_interface_event_stop(&self->handle);
1625
1626 if (err < 0) {
1627 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1628 assert(err == 0);
1629 }
1630}
1631
1632static inline void
1633udx_napi_interface_event_close (
1634 js_env_t *env,
1635 js_typedarray_span_of_t<udx_napi_interface_event_t, 1> self
1636) {
1637 int err;
1638
1639 err = udx_interface_event_close(&self->handle);
1640
1641 if (err < 0) {
1642 err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
1643 assert(err == 0);
1644 }
1645}
1646
1647static inline std::vector<js_object_t>
1648udx_napi_interface_event_get_addrs (
1649 js_env_t *env,
1650 js_typedarray_span_of_t<udx_napi_interface_event_t, 1> self
1651) {
1652 int err;
1653
1654 auto event = &self->handle;
1655
1656 char ip[INET6_ADDRSTRLEN];
1657 int family = 0;
1658
1659 std::vector<js_object_t> result;
1660
1661 for (int i = 0; i < event->addrs_len; i++) {
1662 uv_interface_address_t addr = event->addrs[i];
1663
1664 if (addr.address.address4.sin_family == AF_INET) {
1665 uv_ip4_name(&addr.address.address4, ip, sizeof(ip));
1666 family = 4;
1667 } else if (addr.address.address4.sin_family == AF_INET6) {
1668 uv_ip6_name(&addr.address.address6, ip, sizeof(ip));
1669 family = 6;
1670 } else {
1671 continue;
1672 }
1673
1674 js_object_t item;
1675 err = js_create_object(env, item);
1676 assert(err == 0);
1677
1678 err = js_set_property(env, item, "name", addr.name);
1679 assert(err == 0);
1680
1681 err = js_set_property(env, item, "host", ip);
1682 assert(err == 0);
1683
1684 err = js_set_property(env, item, "family", family);
1685 assert(err == 0);
1686
1687 err = js_set_property(env, item, "internal", bool(addr.is_internal));
1688 assert(err == 0);
1689
1690 result.push_back(item);
1691 }
1692
1693 return result;
1694}
1695
1696static js_value_t *
1697udx_native_exports (js_env_t *env, js_value_t *exports) {
1698 int err;
1699
1700 // uint32
1701#define V(name, value) \
1702 err = js_set_property(env, exports, name, uint32_t(value)); \
1703 assert(err == 0);
1704
1705 V("UV_UDP_IPV6ONLY", UV_UDP_IPV6ONLY);
1706 V("UV_UDP_REUSEADDR", UV_UDP_REUSEADDR);
1707
1708 V("offsetof_udx_stream_t_inflight", offsetof(udx_stream_t, inflight));
1709 V("offsetof_udx_stream_t_mtu", offsetof(udx_stream_t, mtu));
1710 V("offsetof_udx_stream_t_cwnd", offsetof(udx_stream_t, cwnd));
1711 V("offsetof_udx_stream_t_srtt", offsetof(udx_stream_t, srtt));
1712 V("offsetof_udx_stream_t_bytes_rx", offsetof(udx_stream_t, bytes_rx));
1713 V("offsetof_udx_stream_t_packets_rx", offsetof(udx_stream_t, packets_rx));
1714 V("offsetof_udx_stream_t_bytes_tx", offsetof(udx_stream_t, bytes_tx));
1715 V("offsetof_udx_stream_t_packets_tx", offsetof(udx_stream_t, packets_tx));
1716 V("offsetof_udx_stream_t_rto_count", offsetof(udx_stream_t, rto_count));
1717 V("offsetof_udx_stream_t_retransmit_count", offsetof(udx_stream_t, retransmit_count));
1718 V("offsetof_udx_stream_t_fast_recovery_count", offsetof(udx_stream_t, fast_recovery_count));
1719 V("offsetof_udx_socket_t_bytes_rx", offsetof(udx_socket_t, bytes_rx));
1720 V("offsetof_udx_socket_t_packets_rx", offsetof(udx_socket_t, packets_rx));
1721 V("offsetof_udx_socket_t_bytes_tx", offsetof(udx_socket_t, bytes_tx));
1722 V("offsetof_udx_socket_t_packets_tx", offsetof(udx_socket_t, packets_tx));
1723 V("offsetof_udx_socket_t_packets_dropped_by_kernel", offsetof(udx_socket_t, packets_dropped_by_kernel));
1724
1725 V("offsetof_udx_t_bytes_rx", offsetof(udx_t, bytes_rx));
1726 V("offsetof_udx_t_packets_rx", offsetof(udx_t, packets_rx));
1727 V("offsetof_udx_t_bytes_tx", offsetof(udx_t, bytes_tx));
1728 V("offsetof_udx_t_packets_tx", offsetof(udx_t, packets_tx));
1729 V("offsetof_udx_t_packets_dropped_by_kernel", offsetof(udx_t, packets_dropped_by_kernel));
1730
1731 V("sizeof_udx_napi_t", sizeof(udx_napi_t));
1732 V("sizeof_udx_napi_socket_t", sizeof(udx_napi_socket_t));
1733 V("sizeof_udx_napi_stream_t", sizeof(udx_napi_stream_t));
1734 V("sizeof_udx_napi_lookup_t", sizeof(udx_napi_lookup_t));
1735 V("sizeof_udx_napi_interface_event_t", sizeof(udx_napi_interface_event_t));
1736 V("sizeof_udx_socket_send_t", sizeof(udx_socket_send_t));
1737 V("sizeof_udx_stream_send_t", sizeof(udx_stream_send_t));
1738#undef V
1739
1740 // functions
1741#define V(name, fn) \
1742 err = js_set_property<fn>(env, exports, name); \
1743 assert(err == 0);
1744
1745 V("udx_napi_init", udx_napi_init);
1746 V("udx_napi_socket_init", udx_napi_socket_init);
1747 V("udx_napi_socket_bind", udx_napi_socket_bind);
1748 V("udx_napi_socket_set_ttl", udx_napi_socket_set_ttl);
1749 V("udx_napi_socket_get_recv_buffer_size", udx_napi_socket_get_recv_buffer_size);
1750 V("udx_napi_socket_set_recv_buffer_size", udx_napi_socket_set_recv_buffer_size);
1751 V("udx_napi_socket_get_send_buffer_size", udx_napi_socket_get_send_buffer_size);
1752 V("udx_napi_socket_set_send_buffer_size", udx_napi_socket_set_send_buffer_size);
1753 V("udx_napi_socket_set_membership", udx_napi_socket_set_membership);
1754 V("udx_napi_socket_send_ttl", udx_napi_socket_send_ttl);
1755 V("udx_napi_socket_close", udx_napi_socket_close);
1756 V("udx_napi_stream_init", udx_napi_stream_init);
1757 V("udx_napi_stream_set_seq", udx_napi_stream_set_seq);
1758 V("udx_napi_stream_set_ack", udx_napi_stream_set_ack);
1759 V("udx_napi_stream_set_mode", udx_napi_stream_set_mode);
1760 V("udx_napi_stream_connect", udx_napi_stream_connect);
1761 V("udx_napi_stream_change_remote", udx_napi_stream_change_remote);
1762 V("udx_napi_stream_relay_to", udx_napi_stream_relay_to);
1763 V("udx_napi_stream_send", udx_napi_stream_send);
1764 V("udx_napi_stream_recv_start", udx_napi_stream_recv_start);
1765 V("udx_napi_stream_write", udx_napi_stream_write);
1766 V("udx_napi_stream_writev", udx_napi_stream_writev);
1767 V("udx_napi_stream_write_sizeof", udx_napi_stream_write_sizeof);
1768 V("udx_napi_stream_write_end", udx_napi_stream_write_end);
1769 V("udx_napi_stream_destroy", udx_napi_stream_destroy);
1770 V("udx_napi_lookup", udx_napi_lookup);
1771 V("udx_napi_interface_event_init", udx_napi_interface_event_init);
1772 V("udx_napi_interface_event_start", udx_napi_interface_event_start);
1773 V("udx_napi_interface_event_stop", udx_napi_interface_event_stop);
1774 V("udx_napi_interface_event_close", udx_napi_interface_event_close);
1775 V("udx_napi_interface_event_get_addrs", udx_napi_interface_event_get_addrs);
1776#undef V
1777
1778 return exports;
1779}
1780
1781BARE_MODULE(udx_native, udx_native_exports)
node_modules/udx-native/binding.js +3 -0
……@@ -0,0 +1,3 @@
1require.addon = require('require-addon')
2
3module.exports = require.addon('.', __filename)
node_modules/udx-native/lib/ip.js +52 -0
……@@ -0,0 +1,52 @@
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22const v4Seg = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
23const v4Str = `(${v4Seg}[.]){3}${v4Seg}`
24const IPv4Pattern = new RegExp(`^${v4Str}$`)
25
26const v6Seg = '(?:[0-9a-fA-F]{1,4})'
27const IPv6Pattern = new RegExp(
28 '^(' +
29 `(?:${v6Seg}:){7}(?:${v6Seg}|:)|` +
30 `(?:${v6Seg}:){6}(?:${v4Str}|:${v6Seg}|:)|` +
31 `(?:${v6Seg}:){5}(?::${v4Str}|(:${v6Seg}){1,2}|:)|` +
32 `(?:${v6Seg}:){4}(?:(:${v6Seg}){0,1}:${v4Str}|(:${v6Seg}){1,3}|:)|` +
33 `(?:${v6Seg}:){3}(?:(:${v6Seg}){0,2}:${v4Str}|(:${v6Seg}){1,4}|:)|` +
34 `(?:${v6Seg}:){2}(?:(:${v6Seg}){0,3}:${v4Str}|(:${v6Seg}){1,5}|:)|` +
35 `(?:${v6Seg}:){1}(?:(:${v6Seg}){0,4}:${v4Str}|(:${v6Seg}){1,6}|:)|` +
36 `(?::((?::${v6Seg}){0,5}:${v4Str}|(?::${v6Seg}){1,7}|:))` +
37 ')(%[0-9a-zA-Z-.:]{1,})?$'
38)
39
40const isIPv4 = (exports.isIPv4 = function isIPv4(host) {
41 return IPv4Pattern.test(host)
42})
43
44const isIPv6 = (exports.isIPv6 = function isIPv6(host) {
45 return IPv6Pattern.test(host)
46})
47
48exports.isIP = function isIP(host) {
49 if (isIPv4(host)) return 4
50 if (isIPv6(host)) return 6
51 return 0
52}
node_modules/udx-native/lib/network-interfaces.js +64 -0
……@@ -0,0 +1,64 @@
1const events = require('events')
2const b4a = require('b4a')
3const binding = require('../binding')
4
5module.exports = class NetworkInterfaces extends events.EventEmitter {
6 constructor(udx) {
7 super()
8
9 this._handle = b4a.alloc(binding.sizeof_udx_napi_interface_event_t)
10 this._watching = false
11 this._destroying = null
12
13 binding.udx_napi_interface_event_init(
14 udx._handle,
15 this._handle,
16 this,
17 this._onevent,
18 this._onclose
19 )
20
21 this.interfaces = binding.udx_napi_interface_event_get_addrs(this._handle)
22 }
23
24 _onclose() {
25 this.emit('close')
26 }
27
28 _onevent() {
29 this.interfaces = binding.udx_napi_interface_event_get_addrs(this._handle)
30
31 this.emit('change', this.interfaces)
32 }
33
34 watch() {
35 if (this._watching) return this
36 this._watching = true
37
38 binding.udx_napi_interface_event_start(this._handle)
39
40 return this
41 }
42
43 unwatch() {
44 if (!this._watching) return this
45 this._watching = false
46
47 binding.udx_napi_interface_event_stop(this._handle)
48
49 return this
50 }
51
52 async destroy() {
53 if (this._destroying) return this._destroying
54 this._destroying = events.once(this, 'close')
55
56 binding.udx_napi_interface_event_close(this._handle)
57
58 return this._destroying
59 }
60
61 [Symbol.iterator]() {
62 return this.interfaces[Symbol.iterator]()
63 }
64}
node_modules/udx-native/lib/socket.js +331 -0
……@@ -0,0 +1,331 @@
1const events = require('events')
2const b4a = require('b4a')
3const binding = require('../binding')
4const ip = require('./ip')
5
6module.exports = class UDXSocket extends events.EventEmitter {
7 constructor(udx, opts = {}) {
8 super()
9
10 this.udx = udx
11
12 this._handle = b4a.alloc(binding.sizeof_udx_napi_socket_t)
13 this._inited = false
14 this._host = null
15 this._family = 0
16 this._ipv6Only = opts.ipv6Only === true
17 this._reuseAddress = opts.reuseAddress === true
18 this._port = 0
19 this._reqs = []
20 this._free = []
21 this._closing = null
22 this._closed = false
23
24 this._view64 = new BigUint64Array(
25 this._handle.buffer,
26 this._handle.byteOffset,
27 this._handle.byteLength >> 3
28 )
29
30 this.streams = new Set()
31
32 this.userData = null
33 }
34
35 get bound() {
36 return this._port !== 0
37 }
38
39 get closing() {
40 return this._closing !== null
41 }
42
43 get idle() {
44 return this.streams.size === 0
45 }
46
47 get busy() {
48 return this.streams.size > 0
49 }
50
51 get bytesTransmitted() {
52 if (this._inited !== true) return 0
53 return Number(this._view64[binding.offsetof_udx_socket_t_bytes_tx >> 3])
54 }
55
56 get packetsTransmitted() {
57 if (this._inited !== true) return 0
58 return Number(this._view64[binding.offsetof_udx_socket_t_packets_tx >> 3])
59 }
60
61 get bytesReceived() {
62 if (this._inited !== true) return 0
63 return Number(this._view64[binding.offsetof_udx_socket_t_bytes_rx >> 3])
64 }
65
66 get packetsReceived() {
67 if (this._inited !== true) return 0
68 return Number(this._view64[binding.offsetof_udx_socket_t_packets_rx >> 3])
69 }
70
71 get packetsDroppedByKernel() {
72 if (this._inited !== true) return 0
73 return Number(this._view64[binding.offsetof_udx_socket_t_packets_dropped_by_kernel >> 3])
74 }
75
76 toJSON() {
77 return {
78 bound: this.bound,
79 closing: this.closing,
80 streams: this.streams.size,
81 address: this.address(),
82 ipv6Only: this._ipv6Only,
83 reuseAddress: this._reuseAddress,
84 idle: this.idle,
85 busy: this.busy
86 }
87 }
88
89 _init() {
90 if (this._inited) return
91
92 binding.udx_napi_socket_init(
93 this.udx._handle,
94 this._handle,
95 this,
96 this._onsend,
97 this._onmessage,
98 this._onclose,
99 this._reallocMessage
100 )
101
102 this._inited = true
103 }
104
105 _onsend(id, err) {
106 const req = this._reqs[id]
107
108 const onflush = req.onflush
109
110 req.buffer = null
111 req.onflush = null
112
113 this._free.push(id)
114
115 onflush(err >= 0)
116
117 // gc the free list
118 if (this._free.length >= 16 && this._free.length === this._reqs.length) {
119 this._free = []
120 this._reqs = []
121 }
122 }
123
124 _onmessage(len, port, host, family) {
125 this.emit('message', this.udx._consumeMessage(len), { host, family, port })
126 return this.udx._buffer
127 }
128
129 _onclose() {
130 this.emit('close')
131 }
132
133 _reallocMessage() {
134 return this.udx._reallocMessage()
135 }
136
137 _onidle() {
138 this.emit('idle')
139 }
140
141 _onbusy() {
142 this.emit('busy')
143 }
144
145 _addStream(stream) {
146 if (this.streams.has(stream)) return false
147 this.streams.add(stream)
148 if (this.streams.size === 1) this._onbusy()
149 return true
150 }
151
152 _removeStream(stream) {
153 if (!this.streams.has(stream)) return false
154 this.streams.delete(stream)
155 const closed = this._closeMaybe()
156 if (this.idle && !closed) this._onidle()
157 return true
158 }
159
160 address() {
161 if (!this.bound) return null
162 return { host: this._host, family: this._family, port: this._port }
163 }
164
165 bind(port, host) {
166 if (this.bound) throw new Error('Already bound')
167 if (this.closing) throw new Error('Socket is closed')
168
169 if (!port) port = 0
170
171 let flags = 0
172 if (this._ipv6Only) flags |= binding.UV_UDP_IPV6ONLY
173 if (this._reuseAddress) flags |= binding.UV_UDP_REUSEADDR
174
175 let family
176
177 if (host) {
178 family = ip.isIP(host)
179 if (!family) throw new Error(`${host} is not a valid IP address`)
180
181 if (!this._inited) this._init()
182
183 this._port = binding.udx_napi_socket_bind(this._handle, port, host, family, flags)
184 } else {
185 if (!this._inited) this._init()
186
187 try {
188 host = '::'
189 family = 6
190 this._port = binding.udx_napi_socket_bind(this._handle, port, host, family, flags)
191 } catch {
192 host = '0.0.0.0'
193 family = 4
194 this._port = binding.udx_napi_socket_bind(this._handle, port, host, family, flags)
195 }
196 }
197
198 this._host = host
199 this._family = family
200
201 this.emit('listening')
202 }
203
204 async close() {
205 if (this._closing) return this._closing
206 this._closing = new Promise((resolve) => this.once('close', resolve))
207 this._closeMaybe()
208 return this._closing
209 }
210
211 _closeMaybe() {
212 if (this._closed || this._closing === null) return this._closed
213
214 if (!this._inited) {
215 this._closed = true
216 this.emit('close')
217 return true
218 }
219
220 if (this.idle) {
221 binding.udx_napi_socket_close(this._handle)
222 this._closed = true
223 }
224
225 return this._closed
226 }
227
228 setTTL(ttl) {
229 if (!this._inited) throw new Error('Socket not active')
230 binding.udx_napi_socket_set_ttl(this._handle, ttl)
231 }
232
233 getRecvBufferSize() {
234 if (!this._inited) throw new Error('Socket not active')
235 return binding.udx_napi_socket_get_recv_buffer_size(this._handle)
236 }
237
238 setRecvBufferSize(size) {
239 if (!this._inited) throw new Error('Socket not active')
240 return binding.udx_napi_socket_set_recv_buffer_size(this._handle, size)
241 }
242
243 getSendBufferSize() {
244 if (!this._inited) throw new Error('Socket not active')
245 return binding.udx_napi_socket_get_send_buffer_size(this._handle)
246 }
247
248 setSendBufferSize(size) {
249 if (!this._inited) throw new Error('Socket not active')
250 return binding.udx_napi_socket_set_send_buffer_size(this._handle, size)
251 }
252
253 addMembership(group, ifaceAddress) {
254 if (!this._inited) throw new Error('Socket not active')
255 return binding.udx_napi_socket_set_membership(this._handle, group, ifaceAddress || '', true)
256 }
257
258 dropMembership(group, ifaceAddress) {
259 if (!this._inited) throw new Error('Socket not active')
260 return binding.udx_napi_socket_set_membership(this._handle, group, ifaceAddress || '', false)
261 }
262
263 async send(buffer, port, host, ttl) {
264 if (this.closing) return false
265
266 if (!host) host = '127.0.0.1'
267
268 const family = ip.isIP(host)
269 if (!family) throw new Error(`${host} is not a valid IP address`)
270
271 if (!this.bound) this.bind(0)
272
273 const id = this._allocSend()
274 const req = this._reqs[id]
275
276 req.buffer = buffer
277
278 const promise = new Promise((resolve) => {
279 req.onflush = resolve
280 })
281
282 binding.udx_napi_socket_send_ttl(
283 this._handle,
284 req.handle,
285 id,
286 buffer,
287 port,
288 host,
289 family,
290 ttl || 0
291 )
292
293 return promise
294 }
295
296 trySend(buffer, port, host, ttl) {
297 if (this.closing) return
298
299 if (!host) host = '127.0.0.1'
300
301 const family = ip.isIP(host)
302 if (!family) throw new Error(`${host} is not a valid IP address`)
303
304 if (!this.bound) this.bind(0)
305
306 const id = this._allocSend()
307 const req = this._reqs[id]
308
309 req.buffer = buffer
310 req.onflush = noop
311
312 binding.udx_napi_socket_send_ttl(
313 this._handle,
314 req.handle,
315 id,
316 buffer,
317 port,
318 host,
319 family,
320 ttl || 0
321 )
322 }
323
324 _allocSend() {
325 if (this._free.length > 0) return this._free.pop()
326 const handle = b4a.allocUnsafe(binding.sizeof_udx_socket_send_t)
327 return this._reqs.push({ handle, buffer: null, onflush: null }) - 1
328 }
329}
330
331function noop() {}
node_modules/udx-native/lib/stream.js +545 -0
……@@ -0,0 +1,545 @@
1const streamx = require('streamx')
2const b4a = require('b4a')
3const binding = require('../binding')
4const ip = require('./ip')
5
6const MAX_PACKET = 2048
7const BUFFER_SIZE = 65536 + MAX_PACKET
8
9module.exports = class UDXStream extends streamx.Duplex {
10 constructor(udx, id, opts = {}) {
11 super({ mapWritable: toBuffer, eagerOpen: true })
12
13 this.udx = udx
14 this.socket = null
15
16 this._handle = b4a.alloc(binding.sizeof_udx_napi_stream_t)
17 this._view = new Uint32Array(
18 this._handle.buffer,
19 this._handle.byteOffset,
20 this._handle.byteLength >> 2
21 )
22 this._view16 = new Uint16Array(
23 this._handle.buffer,
24 this._handle.byteOffset,
25 this._handle.byteLength >> 1
26 )
27 this._view64 = new BigUint64Array(
28 this._handle.buffer,
29 this._handle.byteOffset,
30 this._handle.byteLength >> 3
31 )
32
33 this._wreqs = []
34 this._wfree = []
35
36 this._sreqs = []
37 this._sfree = []
38 this._closed = false
39
40 this._flushing = 0
41 this._flushes = []
42
43 this._buffer = null
44 this._reallocData()
45
46 this._onwrite = null
47 this._ondestroy = null
48 this._firewall = opts.firewall || firewallAll
49
50 this._remoteChanging = null
51 this._previousSocket = null
52
53 this.id = id
54 this.remoteId = 0
55 this.remoteHost = null
56 this.remoteFamily = 0
57 this.remotePort = 0
58
59 this.userData = null
60
61 binding.udx_napi_stream_init(
62 this.udx._handle,
63 this._handle,
64 id,
65 opts.framed ? 1 : 0,
66 this,
67 this._ondata,
68 this._onend,
69 this._ondrain,
70 this._onack,
71 this._onsend,
72 this._onmessage,
73 this._onclose,
74 this._onfirewall,
75 this._onremotechanged,
76 this._reallocData,
77 this._reallocMessage
78 )
79
80 if (opts.seq) binding.udx_napi_stream_set_seq(this._handle, opts.seq)
81
82 binding.udx_napi_stream_recv_start(this._handle, this._buffer)
83 }
84
85 get connected() {
86 return this.socket !== null
87 }
88
89 get mtu() {
90 return this._view16[binding.offsetof_udx_stream_t_mtu >> 1]
91 }
92
93 get rtt() {
94 return this._view[binding.offsetof_udx_stream_t_srtt >> 2]
95 }
96
97 get cwnd() {
98 return this._view[binding.offsetof_udx_stream_t_cwnd >> 2]
99 }
100
101 get rtoCount() {
102 return this._view16[binding.offsetof_udx_stream_t_rto_count >> 1]
103 }
104
105 get retransmits() {
106 return this._view16[binding.offsetof_udx_stream_t_retransmit_count >> 1]
107 }
108
109 get fastRecoveries() {
110 return this._view16[binding.offsetof_udx_stream_t_fast_recovery_count >> 1]
111 }
112
113 get inflight() {
114 return this._view[binding.offsetof_udx_stream_t_inflight >> 2]
115 }
116
117 get bytesTransmitted() {
118 return Number(this._view64[binding.offsetof_udx_stream_t_bytes_tx >> 3])
119 }
120
121 get packetsTransmitted() {
122 return Number(this._view64[binding.offsetof_udx_stream_t_packets_tx >> 3])
123 }
124
125 get bytesReceived() {
126 return Number(this._view64[binding.offsetof_udx_stream_t_bytes_rx >> 3])
127 }
128
129 get packetsReceived() {
130 return Number(this._view64[binding.offsetof_udx_stream_t_packets_rx >> 3])
131 }
132
133 get localHost() {
134 return this.socket ? this.socket.address().host : null
135 }
136
137 get localFamily() {
138 return this.socket ? this.socket.address().family : 0
139 }
140
141 get localPort() {
142 return this.socket ? this.socket.address().port : 0
143 }
144
145 setInteractive(bool) {
146 if (!this._closed) return
147 binding.udx_napi_stream_set_mode(this._handle, bool ? 0 : 1)
148 }
149
150 connect(socket, remoteId, port, host, opts = {}) {
151 if (this._closed) return
152
153 if (this.connected) throw new Error('Already connected')
154 if (socket.closing) throw new Error('Socket is closed')
155
156 if (typeof host === 'object') {
157 opts = host
158 host = null
159 }
160
161 if (!host) host = '127.0.0.1'
162
163 const family = ip.isIP(host)
164 if (!family) throw new Error(`${host} is not a valid IP address`)
165 if (!(port > 0 && port < 65536)) throw new Error(`${port} is not a valid port`)
166
167 if (!socket.bound) socket.bind(0)
168
169 this.remoteId = remoteId
170 this.remotePort = port
171 this.remoteHost = host
172 this.remoteFamily = family
173 this.socket = socket
174
175 if (opts.ack) binding.udx_napi_stream_set_ack(this._handle, opts.ack)
176
177 binding.udx_napi_stream_connect(this._handle, socket._handle, remoteId, port, host, family)
178
179 this.socket._addStream(this)
180
181 this.emit('connect')
182 }
183
184 changeRemote(socket, remoteId, port, host) {
185 if (this._remoteChanging) throw new Error('Remote already changing')
186
187 if (!this.connected) throw new Error('Not yet connected')
188 if (socket.closing) throw new Error('Socket is closed')
189
190 if (this.socket.udx !== socket.udx) {
191 throw new Error('Cannot change to a socket on another UDX instance')
192 }
193
194 if (!host) host = '127.0.0.1'
195
196 const family = ip.isIP(host)
197 if (!family) throw new Error(`${host} is not a valid IP address`)
198 if (!(port > 0 && port < 65536)) throw new Error(`${port} is not a valid port`)
199
200 if (this.socket !== socket) this._previousSocket = this.socket
201
202 this.remoteId = remoteId
203 this.remotePort = port
204 this.remoteHost = host
205 this.remoteFamily = family
206 this.socket = socket
207
208 this._remoteChanging = new Promise((resolve, reject) => {
209 const onchanged = () => {
210 this.off('close', onclose)
211 resolve()
212 }
213
214 const onclose = () => {
215 this.off('remote-changed', onchanged)
216 reject(new Error('Stream is closed'))
217 }
218
219 this.once('remote-changed', onchanged).once('close', onclose)
220 })
221
222 binding.udx_napi_stream_change_remote(
223 this._handle,
224 socket._handle,
225 remoteId,
226 port,
227 host,
228 family
229 )
230
231 this.socket._addStream(this)
232
233 return this._remoteChanging
234 }
235
236 relayTo(destination) {
237 if (this._closed) return
238
239 binding.udx_napi_stream_relay_to(this._handle, destination._handle)
240 }
241
242 async send(buffer) {
243 if (!this.connected || this._closed) return false
244
245 const id = this._allocSend()
246 const req = this._sreqs[id]
247
248 req.buffer = buffer
249
250 const promise = new Promise((resolve) => {
251 req.onflush = resolve
252 })
253
254 binding.udx_napi_stream_send(this._handle, req.handle, id, buffer)
255
256 return promise
257 }
258
259 trySend(buffer) {
260 if (!this.connected || this._closed) return
261
262 const id = this._allocSend()
263 const req = this._sreqs[id]
264
265 req.buffer = buffer
266 req.onflush = noop
267
268 binding.udx_napi_stream_send(this._handle, req.handle, id, buffer)
269 }
270
271 async flush() {
272 if ((await streamx.Writable.drained(this)) === false) return false
273 if (this.destroying) return false
274
275 const missing = this._wreqs.length - this._wfree.length
276 if (missing === 0) return true
277
278 return new Promise((resolve) => {
279 this._flushes.push({ flush: this._flushing++, missing, resolve })
280 })
281 }
282
283 toJSON() {
284 return {
285 id: this.id,
286 connected: this.connected,
287 destroying: this.destroying,
288 destroyed: this.destroyed,
289 remoteId: this.remoteId,
290 remoteHost: this.remoteHost,
291 remoteFamily: this.remoteFamily,
292 remotePort: this.remotePort,
293 mtu: this.mtu,
294 rtt: this.rtt,
295 cwnd: this.cwnd,
296 inflight: this.inflight,
297 socket: this.socket ? this.socket.toJSON() : null
298 }
299 }
300
301 _read(cb) {
302 cb(null)
303 }
304
305 _writeContinue(err) {
306 if (this._onwrite === null) return
307 const cb = this._onwrite
308 this._onwrite = null
309 cb(err)
310 }
311
312 _destroyContinue(err) {
313 if (this._ondestroy === null) return
314 const cb = this._ondestroy
315 this._ondestroy = null
316 cb(err)
317 }
318
319 _writev(buffers, cb) {
320 if (!this.connected)
321 throw customError('Writing while not connected not currently supported', 'ERR_ASSERTION')
322
323 let drained = true
324
325 if (buffers.length === 1) {
326 const id = this._allocWrite(1)
327 const req = this._wreqs[id]
328
329 req.flush = this._flushing
330 req.buffer = buffers[0]
331
332 drained = binding.udx_napi_stream_write(this._handle, req.handle, id, req.buffer) !== 0
333 } else {
334 const id = this._allocWrite(nextBatchSize(buffers.length))
335 const req = this._wreqs[id]
336
337 req.flush = this._flushing
338 req.buffers = buffers
339
340 drained = binding.udx_napi_stream_writev(this._handle, req.handle, id, req.buffers) !== 0
341 }
342
343 if (drained) cb(null)
344 else this._onwrite = cb
345 }
346
347 _final(cb) {
348 const id = this._allocWrite(1)
349 const req = this._wreqs[id]
350
351 req.flush = this._flushes
352 req.buffer = b4a.allocUnsafe(0)
353
354 const drained =
355 binding.udx_napi_stream_write_end(this._handle, req.handle, id, req.buffer) !== 0
356
357 if (drained) cb(null)
358 else this._onwrite = cb
359 }
360
361 _predestroy() {
362 if (!this._closed) binding.udx_napi_stream_destroy(this._handle)
363 this._closed = true
364 this._writeContinue(null)
365 }
366
367 _destroy(cb) {
368 if (this.connected) this._ondestroy = cb
369 else cb(null)
370 }
371
372 _ondata(read) {
373 this.push(this._consumeData(read))
374 return this._buffer
375 }
376
377 _onend(read) {
378 if (read > 0) this.push(this._consumeData(read))
379 this.push(null)
380 }
381
382 _ondrain() {
383 this._writeContinue(null)
384 }
385
386 _flushAck(flush) {
387 for (let i = this._flushes.length - 1; i >= 0; i--) {
388 const f = this._flushes[i]
389 if (f.flush < flush) break
390 f.missing--
391 }
392
393 while (this._flushes.length > 0 && this._flushes[0].missing === 0) {
394 this._flushes.shift().resolve(true)
395 }
396 }
397
398 _onack(id) {
399 const req = this._wreqs[id]
400
401 req.buffers = req.buffer = null
402 this._wfree.push(id)
403
404 if (this._flushes.length > 0) this._flushAck(req.flush)
405
406 // gc the free list
407 if (this._wfree.length >= 64 && this._wfree.length === this._wreqs.length) {
408 this._wfree = []
409 this._wreqs = []
410 }
411 }
412
413 _onsend(id, err) {
414 const req = this._sreqs[id]
415
416 const onflush = req.onflush
417
418 req.buffer = null
419 req.onflush = null
420
421 this._sfree.push(id)
422
423 onflush(err >= 0)
424
425 // gc the free list
426 if (this._sfree.length >= 16 && this._sfree.length === this._sreqs.length) {
427 this._sfree = []
428 this._sreqs = []
429 }
430 }
431
432 _onmessage(len) {
433 this.emit('message', this.udx._consumeMessage(len))
434 return this.udx._buffer
435 }
436
437 _onclose(err) {
438 this._closed = true
439
440 if (this.socket) {
441 this.socket._removeStream(this)
442 this.socket = null
443 }
444
445 if (this._previousSocket) {
446 this._previousSocket._removeStream(this)
447 this._previousSocket = null
448 }
449
450 // no error, we don't need to do anything
451 if (!err) return this._destroyContinue(null)
452
453 if (this._ondestroy === null) this.destroy(err)
454 else this._destroyContinue(err)
455 }
456
457 _onfirewall(socket, port, host, family) {
458 return this._firewall(socket, port, host, family) ? 1 : 0
459 }
460
461 _onremotechanged() {
462 if (this._previousSocket) {
463 this._previousSocket._removeStream(this)
464 this._previousSocket = null
465 }
466
467 this._remoteChanging = null
468 this.emit('remote-changed')
469 }
470
471 _consumeData(len) {
472 const next = this._buffer.subarray(0, len)
473 this._buffer = this._buffer.subarray(len)
474 if (this._buffer.byteLength < MAX_PACKET) this._reallocData()
475 return next
476 }
477
478 _reallocData() {
479 this._buffer = b4a.allocUnsafe(BUFFER_SIZE)
480 return this._buffer
481 }
482
483 _reallocMessage() {
484 return this.udx._reallocMessage()
485 }
486
487 _allocWrite(size) {
488 if (this._wfree.length === 0) {
489 const handle = b4a.allocUnsafe(binding.udx_napi_stream_write_sizeof(size))
490 return (
491 this._wreqs.push({
492 handle,
493 size,
494 buffers: null,
495 buffer: null,
496 flush: 0
497 }) - 1
498 )
499 }
500
501 const free = this._wfree.pop()
502 if (size === 1) return free
503
504 const next = this._wreqs[free]
505 if (next.size < size) {
506 next.handle = b4a.allocUnsafe(binding.udx_napi_stream_write_sizeof(size))
507 next.size = size
508 }
509
510 return free
511 }
512
513 _allocSend() {
514 if (this._sfree.length > 0) return this._sfree.pop()
515 const handle = b4a.allocUnsafe(binding.sizeof_udx_stream_send_t)
516 return this._sreqs.push({ handle, buffer: null, resolve: null, reject: null }) - 1
517 }
518}
519
520function noop() {}
521
522function toBuffer(data) {
523 return typeof data === 'string' ? b4a.from(data) : data
524}
525
526function firewallAll(socket, port, host) {
527 return true
528}
529
530function customError(message, code) {
531 const error = new Error(message)
532 error.code = code
533 return error
534}
535
536function nextBatchSize(n) {
537 // try to coerce the the writevs into sameish size
538 if (n === 1) return 1
539 // group all < 8 to the same size, low mem overhead but save some small allocs
540 if (n < 8) return 8
541 if (n < 16) return 16
542 if (n < 32) return 32
543 if (n < 64) return 64
544 return n
545}
node_modules/udx-native/lib/udx.js +127 -0
……@@ -0,0 +1,127 @@
1const b4a = require('b4a')
2const binding = require('../binding')
3const ip = require('./ip')
4const Socket = require('./socket')
5const Stream = require('./stream')
6const NetworkInterfaces = require('./network-interfaces')
7
8const MAX_MESSAGE = 4096
9const BUFFER_SIZE = 65536 + MAX_MESSAGE
10
11module.exports = class UDX {
12 constructor() {
13 this._handle = b4a.alloc(binding.sizeof_udx_napi_t)
14 this._watchers = new Set()
15 this._view64 = new BigUint64Array(
16 this._handle.buffer,
17 this._handle.byteOffset,
18 this._handle.byteLength >> 3
19 )
20
21 this._buffer = null
22 this._reallocMessage()
23
24 binding.udx_napi_init(this._handle, this._buffer)
25 }
26
27 static isIPv4(host) {
28 return ip.isIPv4(host)
29 }
30
31 static isIPv6(host) {
32 return ip.isIPv6(host)
33 }
34
35 static isIP(host) {
36 return ip.isIP(host)
37 }
38
39 get bytesTransmitted() {
40 return Number(this._view64[binding.offsetof_udx_t_bytes_tx >> 3])
41 }
42
43 get packetsTransmitted() {
44 return Number(this._view64[binding.offsetof_udx_t_packets_tx >> 3])
45 }
46
47 get bytesReceived() {
48 return Number(this._view64[binding.offsetof_udx_t_bytes_rx >> 3])
49 }
50
51 get packetsReceived() {
52 return Number(this._view64[binding.offsetof_udx_t_packets_rx >> 3])
53 }
54
55 get packetsDroppedByKernel() {
56 return Number(this._view64[binding.offsetof_udx_t_packets_dropped_by_kernel >> 3])
57 }
58
59 _consumeMessage(len) {
60 const next = this._buffer.subarray(0, len)
61 this._buffer = this._buffer.subarray(len)
62 if (this._buffer.byteLength < MAX_MESSAGE) this._reallocMessage()
63 return next
64 }
65
66 _reallocMessage() {
67 // TODO: move reallocation to native
68 this._buffer = b4a.allocUnsafe(BUFFER_SIZE)
69 return this._buffer
70 }
71
72 createSocket(opts) {
73 return new Socket(this, opts)
74 }
75
76 createStream(id, opts) {
77 return new Stream(this, id, opts)
78 }
79
80 networkInterfaces() {
81 let [watcher = null] = this._watchers
82 if (watcher) return watcher.interfaces
83
84 watcher = new NetworkInterfaces(this)
85 watcher.destroy()
86
87 return watcher.interfaces
88 }
89
90 watchNetworkInterfaces(onchange) {
91 const watcher = new NetworkInterfaces(this)
92
93 this._watchers.add(watcher)
94 watcher.on('close', () => {
95 this._watchers.delete(watcher)
96 })
97
98 if (onchange) watcher.on('change', onchange)
99
100 return watcher.watch()
101 }
102
103 async lookup(host, opts = {}) {
104 const { family = 0 } = opts
105
106 const req = b4a.alloc(binding.sizeof_udx_napi_lookup_t)
107 const ctx = {
108 req,
109 resolve: null,
110 reject: null
111 }
112
113 const promise = new Promise((resolve, reject) => {
114 ctx.resolve = resolve
115 ctx.reject = reject
116 })
117
118 binding.udx_napi_lookup(this._handle, req, host, family, ctx, onlookup)
119
120 return promise
121 }
122}
123
124function onlookup(err, host, family) {
125 if (err) this.reject(err)
126 else this.resolve({ host, family })
127}
node_modules/udx-native/package.json +66 -0
……@@ -0,0 +1,66 @@
1{
2 "name": "udx-native",
3 "version": "1.19.2",
4 "description": "udx is reliable, multiplexed, and congestion-controlled streams over udp",
5 "main": "lib/udx.js",
6 "files": [
7 "lib",
8 "prebuilds",
9 "binding.cc",
10 "binding.js",
11 "CMakeLists.txt"
12 ],
13 "imports": {
14 "events": {
15 "bare": "bare-events",
16 "default": "events"
17 }
18 },
19 "addon": true,
20 "scripts": {
21 "format": "prettier --write .",
22 "lint": "prettier --check .",
23 "test": "npm run lint && npm run test:bare && npm run test:node",
24 "test:node": "node test/all.js",
25 "test:bare": "bare test/all.js",
26 "test:all": "brittle test/*.js test/slow/*.js",
27 "test:generate": "brittle -r test/all.js test/*.js",
28 "bench": "brittle test/bench/*.js"
29 },
30 "repository": {
31 "type": "git",
32 "url": "git+https://github.com/holepunchto/udx-native.git"
33 },
34 "keywords": [
35 "tcp",
36 "udp",
37 "stream",
38 "reliable"
39 ],
40 "author": "Holepunch Inc.",
41 "license": "Apache-2.0",
42 "bugs": {
43 "url": "https://github.com/holepunchto/udx-native/issues"
44 },
45 "homepage": "https://github.com/holepunchto/udx-native#readme",
46 "engines": {
47 "bare": ">=1.17.4"
48 },
49 "dependencies": {
50 "b4a": "^1.5.0",
51 "bare-events": "^2.2.0",
52 "require-addon": "^1.1.0",
53 "streamx": "^2.22.0"
54 },
55 "devDependencies": {
56 "bare-compat-napi": "^1.3.0",
57 "brittle": "^3.1.0",
58 "cmake-bare": "^1.1.10",
59 "cmake-fetch": "^1.0.1",
60 "cmake-napi": "^1.0.5",
61 "is-ci": "^3.0.1",
62 "prettier": "^3.6.2",
63 "prettier-config-holepunch": "^2.0.0",
64 "tiny-byte-size": "^1.1.0"
65 }
66}
node_modules/udx-native/prebuilds/android-arm/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/android-arm/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/android-arm64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/android-arm64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/android-ia32/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/android-ia32/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/android-x64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/android-x64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/darwin-arm64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/darwin-arm64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/darwin-x64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/darwin-x64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/ios-arm64-simulator/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/ios-arm64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/ios-x64-simulator/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/linux-arm64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/linux-arm64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/linux-x64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/linux-x64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/win32-arm64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/win32-arm64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/win32-x64/udx-native.bare +0 -0
(no content changes — binary or rename)
node_modules/udx-native/prebuilds/win32-x64/udx-native.node +0 -0
(no content changes — binary or rename)
node_modules/unordered-set/.travis.yml +9 -0
……@@ -0,0 +1,9 @@
1sudo: false
2
3language: node_js
4
5node_js:
6 - "5"
7 - "4"
8 - "0.12"
9 - "0.10"
node_modules/unordered-set/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2016 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/unordered-set/README.md +53 -0
……@@ -0,0 +1,53 @@
1# unordered-set
2
3A couple of functions that make it easy to maintain an unordered set as an array in an efficient way
4
5```
6npm install unordered-set
7```
8
9[![build status](https://travis-ci.org/mafintosh/unordered-set.svg?branch=master)](https://travis-ci.org/mafintosh/unordered-set)
10
11## Usage
12
13``` js
14var set = require('unordered-set')
15var list = []
16
17var a = {hello: 'world'}
18var b = {hej: 'verden'}
19
20set.add(list, a)
21set.add(list, b)
22
23console.log(list) // prints a and b
24
25set.remove(list, a)
26
27console.log(list) // prints b
28```
29
30Items are removed and added using the same technique as in [unordered-array-remove](https://github.com/mafintosh/unordered-array-remove)
31making the removal/additions run in O(1).
32
33## API
34
35#### `set.add(list, item)`
36
37Add an item. Notes that this sets the property `._index` to a number. If you control the items you insert and this is performance critical it might be benefitial to set `item._index = 0` in the item constructor as v8 tends to like that.
38
39#### `set.remove(list, item)`
40
41Remove an item from the set. Might change the order of the list as well.
42
43#### `bool = set.has(list, item)`
44
45Returns `true` if the item is in the list and `false` otherwise
46
47#### `set.swap(list, a, b)`
48
49Swap the positions of two elements in the set
50
51## License
52
53MIT
node_modules/unordered-set/index.js +36 -0
……@@ -0,0 +1,36 @@
1exports.add = add
2exports.has = has
3exports.remove = remove
4exports.swap = swap
5
6function add (list, item) {
7 if (has(list, item)) return item
8 item._index = list.length
9 list.push(item)
10 return item
11}
12
13function has (list, item) {
14 return item._index < list.length && list[item._index] === item
15}
16
17function remove (list, item) {
18 if (!has(list, item)) return null
19
20 var last = list.pop()
21 if (last !== item) {
22 list[item._index] = last
23 last._index = item._index
24 }
25
26 return item
27}
28
29function swap (list, a, b) {
30 if (!has(list, a) || !has(list, b)) return
31 var tmp = a._index
32 a._index = b._index
33 list[a._index] = a
34 b._index = tmp
35 list[b._index] = b
36}
node_modules/unordered-set/package.json +24 -0
……@@ -0,0 +1,24 @@
1{
2 "name": "unordered-set",
3 "version": "2.0.1",
4 "description": "A couple of functions that make it easy to maintain an unordered set as an array in an efficient way",
5 "main": "index.js",
6 "dependencies": {},
7 "devDependencies": {
8 "standard": "^6.0.4",
9 "tape": "^4.4.0"
10 },
11 "scripts": {
12 "test": "standard && tape test.js"
13 },
14 "repository": {
15 "type": "git",
16 "url": "https://github.com/mafintosh/unordered-set.git"
17 },
18 "author": "Mathias Buus (@mafintosh)",
19 "license": "MIT",
20 "bugs": {
21 "url": "https://github.com/mafintosh/unordered-set/issues"
22 },
23 "homepage": "https://github.com/mafintosh/unordered-set"
24}
node_modules/unordered-set/test.js +126 -0
……@@ -0,0 +1,126 @@
1var tape = require('tape')
2var set = require('./')
3
4tape('add', function (t) {
5 var list = []
6 var a = {hello: 'world'}
7 var b = {hello: 'verden'}
8
9 set.add(list, a)
10 set.add(list, b)
11
12 t.same(list, [a, b])
13 t.end()
14})
15
16tape('add twice', function (t) {
17 var list = []
18 var a = {hello: 'world'}
19 var b = {hello: 'verden'}
20
21 set.add(list, a)
22 set.add(list, b)
23 set.add(list, b)
24
25 t.same(list, [a, b])
26 t.end()
27})
28
29tape('remove', function (t) {
30 var list = []
31 var a = {hello: 'world'}
32 var b = {hello: 'verden'}
33
34 set.add(list, a)
35 set.add(list, b)
36 set.remove(list, a)
37
38 t.same(list, [b])
39 t.end()
40})
41
42tape('remove twice', function (t) {
43 var list = []
44 var a = {hello: 'world'}
45 var b = {hello: 'verden'}
46
47 set.add(list, a)
48 set.add(list, b)
49 set.remove(list, a)
50 set.remove(list, a)
51
52 t.same(list, [b])
53 t.end()
54})
55
56tape('remove all', function (t) {
57 var list = []
58 var a = {hello: 'world'}
59 var b = {hello: 'verden'}
60
61 set.add(list, a)
62 set.add(list, b)
63 set.remove(list, a)
64 set.remove(list, b)
65
66 t.same(list, [])
67 t.end()
68})
69
70tape('re-add', function (t) {
71 var list = []
72 var a = {hello: 'world'}
73 var b = {hello: 'verden'}
74
75 set.add(list, a)
76 set.add(list, b)
77 set.remove(list, a)
78 set.remove(list, b)
79 set.add(list, b)
80 set.add(list, a)
81
82 t.same(list, [b, a])
83 t.end()
84})
85
86tape('has', function (t) {
87 var list = []
88 var a = {hello: 'world'}
89 var b = {hello: 'verden'}
90
91 set.add(list, a)
92 set.add(list, b)
93 set.remove(list, a)
94
95 t.ok(!set.has(list, a))
96 t.ok(set.has(list, b))
97 t.end()
98})
99
100tape('swap', function (t) {
101 var list = []
102 var a = {hello: 'world'}
103 var b = {hello: 'verden'}
104
105 set.add(list, a)
106 set.add(list, b)
107
108 set.swap(list, a, b)
109 t.same(list, [b, a])
110
111 set.swap(list, a, b)
112 t.same(list, [a, b])
113
114 t.end()
115})
116
117tape('swap same', function (t) {
118 var list = []
119 var a = {hello: 'world'}
120
121 set.add(list, a)
122
123 set.swap(list, a, a)
124 t.same(list, [a])
125 t.end()
126})
node_modules/v8-to-istanbul/CHANGELOG.md +445 -0
……@@ -0,0 +1,445 @@
1# Changelog
2
3All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
5## [9.3.0](https://github.com/istanbuljs/v8-to-istanbul/compare/v9.2.0...v9.3.0) (2024-06-22)
6
7
8### Features
9
10* respect node:coverage comments ([#252](https://github.com/istanbuljs/v8-to-istanbul/issues/252)) ([92d593e](https://github.com/istanbuljs/v8-to-istanbul/commit/92d593e6ad7ad38bfacb3c9d237667df5c452fcb))
11
12## [9.2.0](https://github.com/istanbuljs/v8-to-istanbul/compare/v9.1.3...v9.2.0) (2023-11-22)
13
14
15### Features
16
17* support `/* v8 ignore` ignore hints ([#228](https://github.com/istanbuljs/v8-to-istanbul/issues/228)) ([f8757c0](https://github.com/istanbuljs/v8-to-istanbul/commit/f8757c0c25084a6c60c96a7d9699e67a6e358b14))
18
19## [9.1.3](https://github.com/istanbuljs/v8-to-istanbul/compare/v9.1.2...v9.1.3) (2023-10-05)
20
21
22### Bug Fixes
23
24* no wrapperLength for empty coverage ([#210](https://github.com/istanbuljs/v8-to-istanbul/issues/210)) ([bde6de2](https://github.com/istanbuljs/v8-to-istanbul/commit/bde6de2f0c32c1b14e7eda850d2e6b65f8278ed5))
25
26## [9.1.2](https://github.com/istanbuljs/v8-to-istanbul/compare/v9.1.1...v9.1.2) (2023-10-04)
27
28
29### Bug Fixes
30
31* upgrade `convert-source-map` ([#224](https://github.com/istanbuljs/v8-to-istanbul/issues/224)) ([d2cc490](https://github.com/istanbuljs/v8-to-istanbul/commit/d2cc49094ee4ed20a0df1a2e441b83e8dbb64c22))
32
33## [9.1.1](https://github.com/istanbuljs/v8-to-istanbul/compare/v9.1.0...v9.1.1) (2023-10-04)
34
35
36### Bug Fixes
37
38* ignore hint to mark uncovered files statements and lines ([#218](https://github.com/istanbuljs/v8-to-istanbul/issues/218)) ([c425413](https://github.com/istanbuljs/v8-to-istanbul/commit/c425413a2811311c3bd732a819543f1240cf2e28))
39
40## [9.1.0](https://github.com/istanbuljs/v8-to-istanbul/compare/v9.0.1...v9.1.0) (2023-02-14)
41
42
43### Features
44
45* ignore hint more now accepts more suffixes ([#203](https://github.com/istanbuljs/v8-to-istanbul/issues/203)) ([65e70d1](https://github.com/istanbuljs/v8-to-istanbul/commit/65e70d14fd9977dc987d7ae2f6085895e3bc3cdb))
46
47## [9.0.1](https://github.com/istanbuljs/v8-to-istanbul/compare/v9.0.0...v9.0.1) (2022-06-20)
48
49
50### Bug Fixes
51
52* update `@jridgewell/trace-mapping` ([#194](https://github.com/istanbuljs/v8-to-istanbul/issues/194)) ([83d3ea2](https://github.com/istanbuljs/v8-to-istanbul/commit/83d3ea29648012fef3a5c379fa04d8bfc53f3fd2))
53
54## [9.0.0](https://github.com/istanbuljs/v8-to-istanbul/compare/v8.1.1...v9.0.0) (2022-04-20)
55
56
57### ⚠ BREAKING CHANGES
58
59* migrate from source-map to TraceMap
60
61### Bug Fixes
62
63* address issues with line selection for Node 10 ([12d01c6](https://github.com/istanbuljs/v8-to-istanbul/commit/12d01c6f1abc6d5a01a1a8cbdfaabed4b43cf05f))
64
65
66### Code Refactoring
67
68* migrate from source-map to TraceMap ([c39ac4c](https://github.com/istanbuljs/v8-to-istanbul/commit/c39ac4cb636f3f9f92ff4375f377414d2ff93c16))
69
70### [8.1.1](https://github.com/istanbuljs/v8-to-istanbul/compare/v8.1.0...v8.1.1) (2022-01-10)
71
72
73### Bug Fixes
74
75* handle undefined sourcesContent and null sourcesContent entry ([6c2e2ec](https://github.com/istanbuljs/v8-to-istanbul/commit/6c2e2ecd2aece8b01543f75dfa203744f8a785b9))
76* **perf:** optimize hit counting and source map performance ([3f83226](https://github.com/istanbuljs/v8-to-istanbul/commit/3f83226212e9fd26231bb313b36db4f2d0661970)), closes [#159](https://github.com/istanbuljs/v8-to-istanbul/issues/159)
77
78## [8.1.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v8.0.0...v8.1.0) (2021-09-27)
79
80
81### Features
82
83* function to cleanup allocated resources after usage ([#161](https://www.github.com/istanbuljs/v8-to-istanbul/issues/161)) ([a3925e9](https://www.github.com/istanbuljs/v8-to-istanbul/commit/a3925e9951fa88daee0aae5a7d35546b10f063a8))
84
85## [8.0.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v7.1.2...v8.0.0) (2021-06-03)
86
87
88### ⚠ BREAKING CHANGES
89
90* minimum Node version now 10.12.
91
92### Bug Fixes
93
94* address file URL path regression on Windows ([#146](https://www.github.com/istanbuljs/v8-to-istanbul/issues/146)) ([bb04c56](https://www.github.com/istanbuljs/v8-to-istanbul/commit/bb04c561bffe9802b7d2e7e91216aa1d9230490a))
95
96### [7.1.2](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v7.1.1...v7.1.2) (2021-05-05)
97
98
99### Bug Fixes
100
101* fix undefined line in branches and functions ([#139](https://www.github.com/istanbuljs/v8-to-istanbul/issues/139)) ([f5ed83d](https://www.github.com/istanbuljs/v8-to-istanbul/commit/f5ed83d185129db48e5c05c5225470ad114c7609))
102
103### [7.1.1](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v7.1.0...v7.1.1) (2021-03-30)
104
105
106### Bug Fixes
107
108* use original source path if no sources ([#135](https://www.github.com/istanbuljs/v8-to-istanbul/issues/135)) ([64b2c86](https://www.github.com/istanbuljs/v8-to-istanbul/commit/64b2c86099afe3ea9d484324902d4ec4c3965347))
109
110## [7.1.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v7.0.0...v7.1.0) (2020-12-22)
111
112
113### Features
114
115* support comment c8 ignore start/stop ([#130](https://www.github.com/istanbuljs/v8-to-istanbul/issues/130)) ([591126b](https://www.github.com/istanbuljs/v8-to-istanbul/commit/591126b102244465b27906cdb8cdb82df1f4e760))
116
117## [7.0.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v6.0.1...v7.0.0) (2020-10-25)
118
119
120### ⚠ BREAKING CHANGES
121
122* address off by one error processing branches (#127)
123
124### Bug Fixes
125
126* address off by one error processing branches ([#127](https://www.github.com/istanbuljs/v8-to-istanbul/issues/127)) ([746390f](https://www.github.com/istanbuljs/v8-to-istanbul/commit/746390f871fb2d1c6ec9738892a605a9ea59af5c))
127* drop special shebang handling ([#125](https://www.github.com/istanbuljs/v8-to-istanbul/issues/125)) ([0d3b57f](https://www.github.com/istanbuljs/v8-to-istanbul/commit/0d3b57f245003d934c0a824f1b6fe54dcebacdb7))
128* shebang handling supported in Node v12 ([#128](https://www.github.com/istanbuljs/v8-to-istanbul/issues/128)) ([522e4c2](https://www.github.com/istanbuljs/v8-to-istanbul/commit/522e4c25e6693e31191b47fc5729b6aff9909ce3))
129
130### [6.0.1](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v6.0.0...v6.0.1) (2020-10-08)
131
132
133### Bug Fixes
134
135* **build:** use new relese-please strategy ([c8edd37](https://www.github.com/istanbuljs/v8-to-istanbul/commit/c8edd3741f803dd7485d01ee6f4fcf6a73570700))
136* **source-maps:** reverts off by one fix for ignore ([#123](https://www.github.com/istanbuljs/v8-to-istanbul/issues/123)) ([a886fb8](https://www.github.com/istanbuljs/v8-to-istanbul/commit/a886fb82d7e2c5332c6e507e201a9378dda84f50))
137
138## [6.0.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v5.0.1...v6.0.0) (2020-10-08)
139
140
141### ⚠ BREAKING CHANGES
142
143* address off by one error processing branches (#118)
144
145### Features
146
147* add support for 1:1 sourcesContent ([ac3c79a](https://www.github.com/istanbuljs/v8-to-istanbul/commit/ac3c79a688665e9f3f05aafe9295a3d71a21267d))
148
149
150### Bug Fixes
151
152* address off by one error processing branches ([#118](https://www.github.com/istanbuljs/v8-to-istanbul/issues/118)) ([abe51ea](https://www.github.com/istanbuljs/v8-to-istanbul/commit/abe51ea344171c827a014a8c86b3d3a2be5370ce))
153* favor mapping at 0th column ([#120](https://www.github.com/istanbuljs/v8-to-istanbul/issues/120)) ([770f17f](https://www.github.com/istanbuljs/v8-to-istanbul/commit/770f17f49e2bf323bdc26f55f91adfedcbb94e25))
154
155### [5.0.1](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v5.0.0...v5.0.1) (2020-08-07)
156
157
158### Bug Fixes
159
160* add missing type in TS definition ([#113](https://www.github.com/istanbuljs/v8-to-istanbul/issues/113)) ([a14ebc2](https://www.github.com/istanbuljs/v8-to-istanbul/commit/a14ebc2f3c71cb854dacb06490ea3e0f9bc17dbd))
161
162## [5.0.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v4.1.4...v5.0.0) (2020-08-02)
163
164
165### ⚠ BREAKING CHANGES
166
167* drop Node 8 support (#110)
168* source map files with multiple sources will now be parsed differently than source map files with a single source.
169
170### Features
171
172* support source map with multiple sources ([#102](https://www.github.com/istanbuljs/v8-to-istanbul/issues/102)) ([d1f435c](https://www.github.com/istanbuljs/v8-to-istanbul/commit/d1f435cf183c510188ec5e43781d5bc10989a4e0)), closes [#21](https://www.github.com/istanbuljs/v8-to-istanbul/issues/21)
173
174
175### Bug Fixes
176
177* address path related bugs with 1:many source maps ([#108](https://www.github.com/istanbuljs/v8-to-istanbul/issues/108)) ([9a618bc](https://www.github.com/istanbuljs/v8-to-istanbul/commit/9a618bc374ef6e2205c26c5ebf728bc69f4a9288))
178
179
180### Build System
181
182* drop Node 8 support ([#110](https://www.github.com/istanbuljs/v8-to-istanbul/issues/110)) ([c8bf7a1](https://www.github.com/istanbuljs/v8-to-istanbul/commit/c8bf7a1bdcf8b911943bb1ffc97e401d979aa11f))
183
184### [4.1.4](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v4.1.3...v4.1.4) (2020-05-06)
185
186
187### Bug Fixes
188
189* handle relative sourceRoots in source map files ([#100](https://www.github.com/istanbuljs/v8-to-istanbul/issues/100)) ([16ad3aa](https://www.github.com/istanbuljs/v8-to-istanbul/commit/16ad3aabd6144e2bf15fb4065e697bf40d1caaf4))
190
191### [4.1.3](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v4.1.2...v4.1.3) (2020-03-27)
192
193
194### Bug Fixes
195
196* handle sourcemap `sources` emtpy edge case ([#94](https://www.github.com/istanbuljs/v8-to-istanbul/issues/94)) ([628af48](https://www.github.com/istanbuljs/v8-to-istanbul/commit/628af48e2f7ab279c52f4355c0ccb92ac16b2c1a))
197* v8 coverage ranges that fall on \n characters cause exceptions ([#96](https://www.github.com/istanbuljs/v8-to-istanbul/issues/96)) ([c5731a3](https://www.github.com/istanbuljs/v8-to-istanbul/commit/c5731a3b2fe4dccfae9ee581a5bf7a6e362f5cb8))
198
199### [4.1.2](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v4.1.1...v4.1.2) (2020-02-09)
200
201
202### Bug Fixes
203
204* protect against undefined sourcesContent ([#89](https://www.github.com/istanbuljs/v8-to-istanbul/issues/89)) ([5b94fe3](https://www.github.com/istanbuljs/v8-to-istanbul/commit/5b94fe37f9b86686386ad01f1fb8a42182f35ad8))
205
206### [4.1.1](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v4.1.0...v4.1.1) (2020-02-07)
207
208
209### Bug Fixes
210
211* **build:** repository field should have type ([#87](https://www.github.com/istanbuljs/v8-to-istanbul/issues/87)) ([f064542](https://www.github.com/istanbuljs/v8-to-istanbul/commit/f064542844c333d83fc25e0ad7f989f0999f8ceb))
212
213## [4.1.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v4.0.1...v4.1.0) (2020-02-06)
214
215
216### Features
217
218* use the inline source content if available ([#85](https://www.github.com/istanbuljs/v8-to-istanbul/issues/85)) ([1a6d47f](https://www.github.com/istanbuljs/v8-to-istanbul/commit/1a6d47f1412d7c2b072fe794b6bd08bfbf4bbd55))
219
220### [4.0.1](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v4.0.0...v4.0.1) (2019-12-12)
221
222
223### Bug Fixes
224
225* loosen engine requirement so it can be installed on node 8 ([#82](https://www.github.com/istanbuljs/v8-to-istanbul/issues/82)) ([18f2587](https://www.github.com/istanbuljs/v8-to-istanbul/commit/18f2587481617e4db5ae1565c4f7052a8314af92))
226
227## [4.0.0](https://www.github.com/istanbuljs/v8-to-istanbul/compare/v3.2.6...v4.0.0) (2019-11-23)
228
229
230### ⚠ BREAKING CHANGES
231
232* paths are now consistently absolute.
233
234### Features
235
236* adds special (empty-report) block ([#74](https://www.github.com/istanbuljs/v8-to-istanbul/issues/74)) ([e981cc1](https://www.github.com/istanbuljs/v8-to-istanbul/commit/e981cc156b447ce7a936114dafac591126fd65dd))
237
238
239### Bug Fixes
240
241* consistently resolve paths to absolute form ([#72](https://www.github.com/istanbuljs/v8-to-istanbul/issues/72)) ([55f4116](https://www.github.com/istanbuljs/v8-to-istanbul/commit/55f411624841f89f8309dc460387f8dd15c8b8f4))
242
243### [3.2.6](https://github.com/bcoe/v8-to-istanbul/compare/v3.2.5...v3.2.6) (2019-10-24)
244
245
246### Bug Fixes
247
248* remove scheme from paths before joining ([#69](https://github.com/bcoe/v8-to-istanbul/issues/69)) ([10612fa](https://github.com/bcoe/v8-to-istanbul/commit/10612fa))
249
250### [3.2.5](https://github.com/bcoe/v8-to-istanbul/compare/v3.2.4...v3.2.5) (2019-10-07)
251
252
253### Bug Fixes
254
255* fs.promises was not introduced until 10 ([#67](https://github.com/bcoe/v8-to-istanbul/issues/67)) ([cdcc225](https://github.com/bcoe/v8-to-istanbul/commit/cdcc225))
256
257### [3.2.4](https://github.com/bcoe/v8-to-istanbul/compare/v3.2.3...v3.2.4) (2019-10-06)
258
259### [3.2.3](https://github.com/bcoe/v8-to-istanbul/compare/v3.2.2...v3.2.3) (2019-06-24)
260
261
262### Bug Fixes
263
264* regex for detecting Node < 10.16 was off ([4ca7220](https://github.com/bcoe/v8-to-istanbul/commit/4ca7220))
265
266
267
268### [3.2.2](https://github.com/bcoe/v8-to-istanbul/compare/v3.2.1...v3.2.2) (2019-06-24)
269
270
271### Bug Fixes
272
273* Node >10.16.0 now uses new module wrap API ([7d7c9cb](https://github.com/bcoe/v8-to-istanbul/commit/7d7c9cb))
274
275
276
277### [3.2.1](https://github.com/bcoe/v8-to-istanbul/compare/v3.2.0...v3.2.1) (2019-06-23)
278
279
280### Bug Fixes
281
282* logic for handling sourceRoot did not take into account process.cwd() ([#39](https://github.com/bcoe/v8-to-istanbul/issues/39)) ([6ed9524](https://github.com/bcoe/v8-to-istanbul/commit/6ed9524))
283
284
285
286## [3.2.0](https://github.com/bcoe/v8-to-istanbul/compare/v3.1.3...v3.2.0) (2019-06-23)
287
288
289### Build System
290
291* update testing matrix and deps ([#34](https://github.com/bcoe/v8-to-istanbul/issues/34)) ([204afca](https://github.com/bcoe/v8-to-istanbul/commit/204afca))
292
293
294### Features
295
296* add a sources option allowing to bypass fs operations ([#36](https://github.com/bcoe/v8-to-istanbul/issues/36)) ([4f5a681](https://github.com/bcoe/v8-to-istanbul/commit/4f5a681))
297* add TS typings ([#35](https://github.com/bcoe/v8-to-istanbul/issues/35)) ([5251108](https://github.com/bcoe/v8-to-istanbul/commit/5251108))
298* allow sourceMaps with sourceRoot ([#32](https://github.com/bcoe/v8-to-istanbul/issues/32)) ([8eb2ed0](https://github.com/bcoe/v8-to-istanbul/commit/8eb2ed0))
299
300
301
302### [3.1.3](https://github.com/bcoe/v8-to-istanbul/compare/v3.1.2...v3.1.3) (2019-05-11)
303
304
305### Bug Fixes
306
307* **deps:** source-map should be dependency not dev-dependency ([3f6208e](https://github.com/bcoe/v8-to-istanbul/commit/3f6208e))
308
309
310
311## [3.1.2](https://github.com/bcoe/v8-to-istanbul/compare/v3.1.1...v3.1.2) (2019-05-02)
312
313
314### Bug Fixes
315
316* the line with the ignore comment itself should be skipped ([#25](https://github.com/bcoe/v8-to-istanbul/issues/25)) ([e939594](https://github.com/bcoe/v8-to-istanbul/commit/e939594))
317
318
319
320## [3.1.1](https://github.com/bcoe/v8-to-istanbul/compare/v3.1.0...v3.1.1) (2019-05-02)
321
322
323### Bug Fixes
324
325* we should ignore functions and branches ([#24](https://github.com/bcoe/v8-to-istanbul/issues/24)) ([d468559](https://github.com/bcoe/v8-to-istanbul/commit/d468559))
326
327
328
329# [3.1.0](https://github.com/bcoe/v8-to-istanbul/compare/v3.0.1...v3.1.0) (2019-05-02)
330
331
332### Features
333
334* allow uncovered lines to be ignored with special comment ([#23](https://github.com/bcoe/v8-to-istanbul/issues/23)) ([f585cfa](https://github.com/bcoe/v8-to-istanbul/commit/f585cfa))
335
336
337
338## [3.0.1](https://github.com/bcoe/v8-to-istanbul/compare/v3.0.0...v3.0.1) (2019-05-01)
339
340
341### Bug Fixes
342
343* initial column could be 0 on Node 10, after wrapper taken into account ([#22](https://github.com/bcoe/v8-to-istanbul/issues/22)) ([aa3f73b](https://github.com/bcoe/v8-to-istanbul/commit/aa3f73b))
344
345
346
347# [3.0.0](https://github.com/bcoe/v8-to-istanbul/compare/v2.0.2...v3.0.0) (2019-04-29)
348
349### Features
350
351* initial support for source-maps ([#19](https://github.com/bcoe/v8-to-istanbul/issues/19)) ([ab0fcdd](https://github.com/bcoe/v8-to-istanbul/commit/ab0fcdd))
352
353### BREAKING CHANGES
354
355* v8-to-istanbul is now async, making it possible to use the latest source-map library
356
357
358# [2.1.0](https://github.com/bcoe/v8-to-istanbul/compare/v2.0.5...v2.1.0) (2019-04-21)
359
360
361### Features
362
363* store source so that it can be used by SourceMaps ([#18](https://github.com/bcoe/v8-to-istanbul/issues/18)) ([5afafd6](https://github.com/bcoe/v8-to-istanbul/commit/5afafd6))
364
365
366
367## [2.0.5](https://github.com/bcoe/v8-to-istanbul/compare/v2.0.4...v2.0.5) (2019-04-18)
368
369
370### Bug Fixes
371
372* don't assume files to have CR characters on Windows ([#16](https://github.com/bcoe/v8-to-istanbul/issues/16)) ([c59a21a](https://github.com/bcoe/v8-to-istanbul/commit/c59a21a))
373
374
375
376## [2.0.4](https://github.com/bcoe/v8-to-istanbul/compare/v2.0.3...v2.0.4) (2019-04-07)
377
378
379### Bug Fixes
380
381* Node 11 no longer wraps scripts by default ([#15](https://github.com/bcoe/v8-to-istanbul/issues/15)) ([fbbd113](https://github.com/bcoe/v8-to-istanbul/commit/fbbd113))
382
383
384
385## [2.0.3](https://github.com/bcoe/v8-to-istanbul/compare/v2.0.2...v2.0.3) (2019-04-07)
386
387
388
389<a name="2.0.2"></a>
390## [2.0.2](https://github.com/bcoe/v8-to-istanbul/compare/v2.0.1...v2.0.2) (2019-01-20)
391
392
393### Bug Fixes
394
395* windows has \r\n line separator ([#11](https://github.com/bcoe/v8-to-istanbul/issues/11)) ([c10b888](https://github.com/bcoe/v8-to-istanbul/commit/c10b888))
396
397
398
399<a name="2.0.1"></a>
400## [2.0.1](https://github.com/bcoe/v8-to-istanbul/compare/v2.0.0...v2.0.1) (2019-01-20)
401
402
403### Bug Fixes
404
405* functions were not always counted ([#10](https://github.com/bcoe/v8-to-istanbul/issues/10)) ([464a1f0](https://github.com/bcoe/v8-to-istanbul/commit/464a1f0))
406
407
408
409<a name="2.0.0"></a>
410# [2.0.0](https://github.com/bcoe/v8-to-istanbul/compare/v1.2.1...v2.0.0) (2018-12-21)
411
412
413### Features
414
415* allow wrapper length to be configured ([#9](https://github.com/bcoe/v8-to-istanbul/issues/9)) ([5e76198](https://github.com/bcoe/v8-to-istanbul/commit/5e76198))
416
417
418### BREAKING CHANGES
419
420* we no longer attempt to detect ESM modules, rather the consumer sets a wrapper length
421
422
423
424<a name="1.2.1"></a>
425## [1.2.1](https://github.com/bcoe/v8-to-istanbul/compare/v1.2.0...v1.2.1) (2018-09-12)
426
427
428
429<a name="1.2.0"></a>
430# [1.2.0](https://github.com/bcoe/v8-to-istanbul/compare/v1.1.0...v1.2.0) (2017-12-05)
431
432
433### Features
434
435* support ESM modules ([#3](https://github.com/bcoe/v8-to-istanbul/issues/3)) ([992d13a](https://github.com/bcoe/v8-to-istanbul/commit/992d13a))
436
437
438
439<a name="1.1.0"></a>
440# 1.1.0 (2017-12-01)
441
442
443### Features
444
445* initial implementation ([6140c6c](https://github.com/bcoe/v8-to-istanbul/commit/6140c6c))
node_modules/v8-to-istanbul/LICENSE.txt +14 -0
……@@ -0,0 +1,14 @@
1Copyright (c) 2017, Contributors
2
3Permission to use, copy, modify, and/or distribute this software
4for any purpose with or without fee is hereby granted, provided
5that the above copyright notice and this permission notice
6appear in all copies.
7
8THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
11LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
12OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
13WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
14ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
node_modules/v8-to-istanbul/README.md +88 -0
……@@ -0,0 +1,88 @@
1# v8-to-istanbul
2
3[![Build Status](https://img.shields.io/github/actions/workflow/status/istanbuljs/v8-to-istanbul/ci.yaml?branch=master)](https://github.com/istanbuljs/v8-to-istanbul/actions)
4[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)
5![nycrc config on GitHub](https://img.shields.io/nycrc/istanbuljs/v8-to-istanbul)
6
7converts from v8 coverage format to [istanbul's coverage format](https://github.com/gotwarlost/istanbul/blob/master/coverage.json.md).
8
9## Usage
10
11```js
12const v8toIstanbul = require('v8-to-istanbul')
13// the path to the original source-file is required, as its contents are
14// used during the conversion algorithm.
15const converter = v8toIstanbul('./path-to-instrumented-file.js')
16await converter.load() // this is required due to async file reading.
17// provide an array of coverage information in v8 format.
18converter.applyCoverage([
19 {
20 "functionName": "",
21 "ranges": [
22 {
23 "startOffset": 0,
24 "endOffset": 520,
25 "count": 1
26 }
27 ],
28 "isBlockCoverage": true
29 },
30 // ...
31])
32// output coverage information in a form that can
33// be consumed by Istanbul.
34console.info(JSON.stringify(converter.toIstanbul()))
35```
36
37## Ignoring Uncovered Lines
38
39Sometimes you might find yourself wanting to ignore uncovered lines
40in your application (for example, perhaps you run your tests in Linux, but
41there's code that only executes on Windows).
42
43To ignore lines, use the special comment `/* v8 ignore next */`.
44
45**NOTE**: Before version `9.2.0` the ignore hint had to contain `c8` keyword, e.g. `/* c8 ignore ...`.
46
47### ignoring the next line
48
49```js
50const myVariable = 99
51/* v8 ignore next */
52if (process.platform === 'win32') console.info('hello world')
53```
54
55### ignoring the next N lines
56
57```js
58const myVariable = 99
59/* v8 ignore next 3 */
60if (process.platform === 'win32') {
61 console.info('hello world')
62}
63```
64
65### ignoring all lines until told
66
67```js
68/* v8 ignore start */
69function dontMindMe() {
70 // ...
71}
72/* v8 ignore stop */
73```
74
75### ignoring the same line as the comment
76
77```js
78const myVariable = 99
79const os = process.platform === 'darwin' ? 'OSXy' /* v8 ignore next */ : 'Windowsy'
80```
81
82## Testing
83
84To execute tests, simply run:
85
86```bash
87npm test
88```
node_modules/v8-to-istanbul/index.d.ts +25 -0
……@@ -0,0 +1,25 @@
1/// <reference types="node" />
2
3import { Profiler } from 'inspector'
4import { CoverageMapData } from 'istanbul-lib-coverage'
5import { SourceMapInput } from '@jridgewell/trace-mapping'
6
7declare type Sources =
8 | {
9 source: string
10 }
11 | {
12 source: string
13 originalSource: string
14 sourceMap: { sourcemap: SourceMapInput }
15 }
16declare class V8ToIstanbul {
17 load(): Promise<void>
18 destroy(): void
19 applyCoverage(blocks: ReadonlyArray<Profiler.FunctionCoverage>): void
20 toIstanbul(): CoverageMapData
21}
22
23declare function v8ToIstanbul(scriptPath: string, wrapperLength?: number, sources?: Sources, excludePath?: (path: string) => boolean): V8ToIstanbul
24
25export = v8ToIstanbul
node_modules/v8-to-istanbul/index.js +5 -0
……@@ -0,0 +1,5 @@
1const V8ToIstanbul = require('./lib/v8-to-istanbul')
2
3module.exports = function (path, wrapperLength, sources, excludePath) {
4 return new V8ToIstanbul(path, wrapperLength, sources, excludePath)
5}
node_modules/v8-to-istanbul/lib/branch.js +28 -0
……@@ -0,0 +1,28 @@
1module.exports = class CovBranch {
2 constructor (startLine, startCol, endLine, endCol, count) {
3 this.startLine = startLine
4 this.startCol = startCol
5 this.endLine = endLine
6 this.endCol = endCol
7 this.count = count
8 }
9
10 toIstanbul () {
11 const location = {
12 start: {
13 line: this.startLine,
14 column: this.startCol
15 },
16 end: {
17 line: this.endLine,
18 column: this.endCol
19 }
20 }
21 return {
22 type: 'branch',
23 line: this.startLine,
24 loc: location,
25 locations: [Object.assign({}, location)]
26 }
27 }
28}
node_modules/v8-to-istanbul/lib/function.js +29 -0
……@@ -0,0 +1,29 @@
1module.exports = class CovFunction {
2 constructor (name, startLine, startCol, endLine, endCol, count) {
3 this.name = name
4 this.startLine = startLine
5 this.startCol = startCol
6 this.endLine = endLine
7 this.endCol = endCol
8 this.count = count
9 }
10
11 toIstanbul () {
12 const loc = {
13 start: {
14 line: this.startLine,
15 column: this.startCol
16 },
17 end: {
18 line: this.endLine,
19 column: this.endCol
20 }
21 }
22 return {
23 name: this.name,
24 decl: loc,
25 loc,
26 line: this.startLine
27 }
28 }
29}
node_modules/v8-to-istanbul/lib/line.js +34 -0
……@@ -0,0 +1,34 @@
1module.exports = class CovLine {
2 constructor (line, startCol, lineStr) {
3 this.line = line
4 // note that startCol and endCol are absolute positions
5 // within a file, not relative to the line.
6 this.startCol = startCol
7
8 // the line length itself does not include the newline characters,
9 // these are however taken into account when enumerating absolute offset.
10 const matchedNewLineChar = lineStr.match(/\r?\n$/u)
11 const newLineLength = matchedNewLineChar ? matchedNewLineChar[0].length : 0
12 this.endCol = startCol + lineStr.length - newLineLength
13
14 // we start with all lines having been executed, and work
15 // backwards zeroing out lines based on V8 output.
16 this.count = 1
17
18 // set by source.js during parsing, if /* c8 ignore next */ is found.
19 this.ignore = false
20 }
21
22 toIstanbul () {
23 return {
24 start: {
25 line: this.line,
26 column: 0
27 },
28 end: {
29 line: this.line,
30 column: this.endCol - this.startCol
31 }
32 }
33 }
34}
node_modules/v8-to-istanbul/lib/range.js +35 -0
……@@ -0,0 +1,35 @@
1/**
2 * ...something resembling a binary search, to find the lowest line within the range.
3 * And then you could break as soon as the line is longer than the range...
4 */
5module.exports.sliceRange = (lines, startCol, endCol, inclusive = false) => {
6 let start = 0
7 let end = lines.length
8
9 if (inclusive) {
10 // I consider this a temporary solution until I find an alternaive way to fix the "off by one issue"
11 --startCol
12 }
13
14 while (start < end) {
15 let mid = (start + end) >> 1
16 if (startCol >= lines[mid].endCol) {
17 start = mid + 1
18 } else if (endCol < lines[mid].startCol) {
19 end = mid - 1
20 } else {
21 end = mid
22 while (mid >= 0 && startCol < lines[mid].endCol && endCol >= lines[mid].startCol) {
23 --mid
24 }
25 start = mid + 1
26 break
27 }
28 }
29
30 while (end < lines.length && startCol < lines[end].endCol && endCol >= lines[end].startCol) {
31 ++end
32 }
33
34 return lines.slice(start, end)
35}
node_modules/v8-to-istanbul/lib/source.js +254 -0
……@@ -0,0 +1,254 @@
1const CovLine = require('./line')
2const { sliceRange } = require('./range')
3const { originalPositionFor, generatedPositionFor, GREATEST_LOWER_BOUND, LEAST_UPPER_BOUND } = require('@jridgewell/trace-mapping')
4
5module.exports = class CovSource {
6 constructor (sourceRaw, wrapperLength) {
7 sourceRaw = sourceRaw ? sourceRaw.trimEnd() : ''
8 this.lines = []
9 this.eof = sourceRaw.length
10 this.shebangLength = getShebangLength(sourceRaw)
11 this.wrapperLength = wrapperLength - this.shebangLength
12 this._buildLines(sourceRaw)
13 }
14
15 _buildLines (source) {
16 let position = 0
17 let ignoreCount = 0
18 let ignoreAll = false
19 for (const [i, lineStr] of source.split(/(?<=\r?\n)/u).entries()) {
20 const line = new CovLine(i + 1, position, lineStr)
21 if (ignoreCount > 0) {
22 line.ignore = true
23 ignoreCount--
24 } else if (ignoreAll) {
25 line.ignore = true
26 }
27 this.lines.push(line)
28 position += lineStr.length
29
30 const ignoreToken = this._parseIgnore(lineStr)
31 if (!ignoreToken) continue
32
33 line.ignore = true
34 if (ignoreToken.count !== undefined) {
35 ignoreCount = ignoreToken.count
36 }
37 if (ignoreToken.start || ignoreToken.stop) {
38 ignoreAll = ignoreToken.start
39 ignoreCount = 0
40 }
41 }
42 }
43
44 /**
45 * Parses for comments:
46 * c8 ignore next
47 * c8 ignore next 3
48 * c8 ignore start
49 * c8 ignore stop
50 * And equivalent ones for v8, e.g. v8 ignore next.
51 * @param {string} lineStr
52 * @return {{count?: number, start?: boolean, stop?: boolean}|undefined}
53 */
54 _parseIgnore (lineStr) {
55 const testIgnoreNextLines = lineStr.match(/^\W*\/\* (?:[cv]8|node:coverage) ignore next (?<count>[0-9]+)/)
56 if (testIgnoreNextLines) {
57 return { count: Number(testIgnoreNextLines.groups.count) }
58 }
59
60 // Check if comment is on its own line.
61 if (lineStr.match(/^\W*\/\* (?:[cv]8|node:coverage) ignore next/)) {
62 return { count: 1 }
63 }
64
65 if (lineStr.match(/\/\* ([cv]8|node:coverage) ignore next/)) {
66 // Won't ignore successive lines, but the current line will be ignored.
67 return { count: 0 }
68 }
69
70 const testIgnoreStartStop = lineStr.match(/\/\* [c|v]8 ignore (?<mode>start|stop)/)
71 if (testIgnoreStartStop) {
72 if (testIgnoreStartStop.groups.mode === 'start') return { start: true }
73 if (testIgnoreStartStop.groups.mode === 'stop') return { stop: true }
74 }
75
76 const testNodeIgnoreStartStop = lineStr.match(/\/\* node:coverage (?<mode>enable|disable)/)
77 if (testNodeIgnoreStartStop) {
78 if (testNodeIgnoreStartStop.groups.mode === 'disable') return { start: true }
79 if (testNodeIgnoreStartStop.groups.mode === 'enable') return { stop: true }
80 }
81 }
82
83 // given a start column and end column in absolute offsets within
84 // a source file (0 - EOF), returns the relative line column positions.
85 offsetToOriginalRelative (sourceMap, startCol, endCol) {
86 const lines = sliceRange(this.lines, startCol, endCol, true)
87 if (!lines.length) return {}
88
89 const start = originalPositionTryBoth(
90 sourceMap,
91 lines[0].line,
92 Math.max(0, startCol - lines[0].startCol)
93 )
94 if (!(start && start.source)) {
95 return {}
96 }
97
98 let end = originalEndPositionFor(
99 sourceMap,
100 lines[lines.length - 1].line,
101 endCol - lines[lines.length - 1].startCol
102 )
103 if (!(end && end.source)) {
104 return {}
105 }
106
107 if (start.source !== end.source) {
108 return {}
109 }
110
111 if (start.line === end.line && start.column === end.column) {
112 end = originalPositionFor(sourceMap, {
113 line: lines[lines.length - 1].line,
114 column: endCol - lines[lines.length - 1].startCol,
115 bias: LEAST_UPPER_BOUND
116 })
117 end.column -= 1
118 }
119
120 return {
121 source: start.source,
122 startLine: start.line,
123 relStartCol: start.column,
124 endLine: end.line,
125 relEndCol: end.column
126 }
127 }
128
129 relativeToOffset (line, relCol) {
130 line = Math.max(line, 1)
131 if (this.lines[line - 1] === undefined) return this.eof
132 return Math.min(this.lines[line - 1].startCol + relCol, this.lines[line - 1].endCol)
133 }
134}
135
136// this implementation is pulled over from istanbul-lib-sourcemap:
137// https://github.com/istanbuljs/istanbuljs/blob/master/packages/istanbul-lib-source-maps/lib/get-mapping.js
138//
139/**
140 * AST ranges are inclusive for start positions and exclusive for end positions.
141 * Source maps are also logically ranges over text, though interacting with
142 * them is generally achieved by working with explicit positions.
143 *
144 * When finding the _end_ location of an AST item, the range behavior is
145 * important because what we're asking for is the _end_ of whatever range
146 * corresponds to the end location we seek.
147 *
148 * This boils down to the following steps, conceptually, though the source-map
149 * library doesn't expose primitives to do this nicely:
150 *
151 * 1. Find the range on the generated file that ends at, or exclusively
152 * contains the end position of the AST node.
153 * 2. Find the range on the original file that corresponds to
154 * that generated range.
155 * 3. Find the _end_ location of that original range.
156 */
157function originalEndPositionFor (sourceMap, line, column) {
158 // Given the generated location, find the original location of the mapping
159 // that corresponds to a range on the generated file that overlaps the
160 // generated file end location. Note however that this position on its
161 // own is not useful because it is the position of the _start_ of the range
162 // on the original file, and we want the _end_ of the range.
163 const beforeEndMapping = originalPositionTryBoth(
164 sourceMap,
165 line,
166 Math.max(column - 1, 1)
167 )
168
169 if (beforeEndMapping.source === null) {
170 return null
171 }
172
173 // Convert that original position back to a generated one, with a bump
174 // to the right, and a rightward bias. Since 'generatedPositionFor' searches
175 // for mappings in the original-order sorted list, this will find the
176 // mapping that corresponds to the one immediately after the
177 // beforeEndMapping mapping.
178 const afterEndMapping = generatedPositionFor(sourceMap, {
179 source: beforeEndMapping.source,
180 line: beforeEndMapping.line,
181 column: beforeEndMapping.column + 1,
182 bias: LEAST_UPPER_BOUND
183 })
184 if (
185 // If this is null, it means that we've hit the end of the file,
186 // so we can use Infinity as the end column.
187 afterEndMapping.line === null ||
188 // If these don't match, it means that the call to
189 // 'generatedPositionFor' didn't find any other original mappings on
190 // the line we gave, so consider the binding to extend to infinity.
191 originalPositionFor(sourceMap, afterEndMapping).line !==
192 beforeEndMapping.line
193 ) {
194 return {
195 source: beforeEndMapping.source,
196 line: beforeEndMapping.line,
197 column: Infinity
198 }
199 }
200
201 // Convert the end mapping into the real original position.
202 return originalPositionFor(sourceMap, afterEndMapping)
203}
204
205function originalPositionTryBoth (sourceMap, line, column) {
206 let original = originalPositionFor(sourceMap, {
207 line,
208 column,
209 bias: GREATEST_LOWER_BOUND
210 })
211 if (original.line === null) {
212 original = originalPositionFor(sourceMap, {
213 line,
214 column,
215 bias: LEAST_UPPER_BOUND
216 })
217 }
218 // The source maps generated by https://github.com/istanbuljs/istanbuljs
219 // (using @babel/core 7.7.5) have behavior, such that a mapping
220 // mid-way through a line maps to an earlier line than a mapping
221 // at position 0. Using the line at positon 0 seems to provide better reports:
222 //
223 // if (true) {
224 // cov_y5divc6zu().b[1][0]++;
225 // cov_y5divc6zu().s[3]++;
226 // console.info('reachable');
227 // } else { ... }
228 // ^ ^
229 // l5 l3
230 const min = originalPositionFor(sourceMap, {
231 line,
232 column: 0,
233 bias: GREATEST_LOWER_BOUND
234 })
235 if (min.line > original.line) {
236 original = min
237 }
238 return original
239}
240
241// Not required since Node 12, see: https://github.com/nodejs/node/pull/27375
242const isPreNode12 = /^v1[0-1]\./u.test(process.version)
243function getShebangLength (source) {
244 /* c8 ignore start - platform-specific */
245 if (isPreNode12 && source.indexOf('#!') === 0) {
246 const match = source.match(/(?<shebang>#!.*)/)
247 if (match) {
248 return match.groups.shebang.length
249 }
250 } else {
251 /* c8 ignore stop - platform-specific */
252 return 0
253 }
254}
node_modules/v8-to-istanbul/lib/v8-to-istanbul.js +323 -0
……@@ -0,0 +1,323 @@
1const assert = require('assert')
2const convertSourceMap = require('convert-source-map')
3const util = require('util')
4const debuglog = util.debuglog('c8')
5const { dirname, isAbsolute, join, resolve } = require('path')
6const { fileURLToPath } = require('url')
7const CovBranch = require('./branch')
8const CovFunction = require('./function')
9const CovSource = require('./source')
10const { sliceRange } = require('./range')
11const compatError = Error(`requires Node.js ${require('../package.json').engines.node}`)
12const { readFileSync } = require('fs')
13let readFile = () => { throw compatError }
14try {
15 readFile = require('fs').promises.readFile
16} catch (_err) {
17 // most likely we're on an older version of Node.js.
18}
19const { TraceMap } = require('@jridgewell/trace-mapping')
20const isOlderNode10 = /^v10\.(([0-9]\.)|(1[0-5]\.))/u.test(process.version)
21const isNode8 = /^v8\./.test(process.version)
22
23// Injected when Node.js is loading script into isolate pre Node 10.16.x.
24// see: https://github.com/nodejs/node/pull/21573.
25const cjsWrapperLength = isOlderNode10 ? require('module').wrapper[0].length : 0
26
27module.exports = class V8ToIstanbul {
28 constructor (scriptPath, wrapperLength, sources, excludePath) {
29 assert(typeof scriptPath === 'string', 'scriptPath must be a string')
30 assert(!isNode8, 'This module does not support node 8 or lower, please upgrade to node 10')
31 this.path = parsePath(scriptPath)
32 this.wrapperLength = wrapperLength === undefined ? cjsWrapperLength : wrapperLength
33 this.excludePath = excludePath || (() => false)
34 this.sources = sources || {}
35 this.generatedLines = []
36 this.branches = {}
37 this.functions = {}
38 this.covSources = []
39 this.rawSourceMap = undefined
40 this.sourceMap = undefined
41 this.sourceTranspiled = undefined
42 // Indicate that this report was generated with placeholder data from
43 // running --all:
44 this.all = false
45 }
46
47 async load () {
48 const rawSource = this.sources.source || await readFile(this.path, 'utf8')
49 this.rawSourceMap = this.sources.sourceMap ||
50 // if we find a source-map (either inline, or a .map file) we load
51 // both the transpiled and original source, both of which are used during
52 // the backflips we perform to remap absolute to relative positions.
53 convertSourceMap.fromSource(rawSource) || convertSourceMap.fromMapFileSource(rawSource, this._readFileFromDir.bind(this))
54
55 if (this.rawSourceMap) {
56 if (this.rawSourceMap.sourcemap.sources.length > 1) {
57 this.sourceMap = new TraceMap(this.rawSourceMap.sourcemap)
58 if (!this.sourceMap.sourcesContent) {
59 this.sourceMap.sourcesContent = await this.sourcesContentFromSources()
60 }
61 this.covSources = this.sourceMap.sourcesContent.map((rawSource, i) => ({ source: new CovSource(rawSource, this.wrapperLength), path: this.sourceMap.sources[i] }))
62 this.sourceTranspiled = new CovSource(rawSource, this.wrapperLength)
63 } else {
64 const candidatePath = this.rawSourceMap.sourcemap.sources.length >= 1 ? this.rawSourceMap.sourcemap.sources[0] : this.rawSourceMap.sourcemap.file
65 this.path = this._resolveSource(this.rawSourceMap, candidatePath || this.path)
66 this.sourceMap = new TraceMap(this.rawSourceMap.sourcemap)
67
68 let originalRawSource
69 if (this.sources.sourceMap && this.sources.sourceMap.sourcemap && this.sources.sourceMap.sourcemap.sourcesContent && this.sources.sourceMap.sourcemap.sourcesContent.length === 1) {
70 // If the sourcesContent field has been provided, return it rather than attempting
71 // to load the original source from disk.
72 // TODO: investigate whether there's ever a case where we hit this logic with 1:many sources.
73 originalRawSource = this.sources.sourceMap.sourcemap.sourcesContent[0]
74 } else if (this.sources.originalSource) {
75 // Original source may be populated on the sources object.
76 originalRawSource = this.sources.originalSource
77 } else if (this.sourceMap.sourcesContent && this.sourceMap.sourcesContent[0]) {
78 // perhaps we loaded sourcesContent was populated by an inline source map, or .map file?
79 // TODO: investigate whether there's ever a case where we hit this logic with 1:many sources.
80 originalRawSource = this.sourceMap.sourcesContent[0]
81 } else {
82 // We fallback to reading the original source from disk.
83 originalRawSource = await readFile(this.path, 'utf8')
84 }
85 this.covSources = [{ source: new CovSource(originalRawSource, this.wrapperLength), path: this.path }]
86 this.sourceTranspiled = new CovSource(rawSource, this.wrapperLength)
87 }
88 } else {
89 this.covSources = [{ source: new CovSource(rawSource, this.wrapperLength), path: this.path }]
90 }
91 }
92
93 _readFileFromDir (filename) {
94 return readFileSync(resolve(dirname(this.path), filename), 'utf-8')
95 }
96
97 async sourcesContentFromSources () {
98 const fileList = this.sourceMap.sources.map(relativePath => {
99 const realPath = this._resolveSource(this.rawSourceMap, relativePath)
100 return readFile(realPath, 'utf-8')
101 .then(result => result)
102 .catch(err => {
103 debuglog(`failed to load ${realPath}: ${err.message}`)
104 })
105 })
106 return await Promise.all(fileList)
107 }
108
109 destroy () {
110 // no longer necessary, but preserved for backwards compatibility.
111 }
112
113 _resolveSource (rawSourceMap, sourcePath) {
114 if (sourcePath.startsWith('file://')) {
115 return fileURLToPath(sourcePath)
116 }
117 sourcePath = sourcePath.replace(/^webpack:\/\//, '')
118 const sourceRoot = rawSourceMap.sourcemap.sourceRoot ? rawSourceMap.sourcemap.sourceRoot.replace('file://', '') : ''
119 const candidatePath = join(sourceRoot, sourcePath)
120
121 if (isAbsolute(candidatePath)) {
122 return candidatePath
123 } else {
124 return resolve(dirname(this.path), candidatePath)
125 }
126 }
127
128 applyCoverage (blocks) {
129 blocks.forEach(block => {
130 block.ranges.forEach((range, i) => {
131 const isEmptyCoverage = block.functionName === '(empty-report)'
132 const { startCol, endCol, path, covSource } = this._maybeRemapStartColEndCol(range, isEmptyCoverage)
133 if (this.excludePath(path)) {
134 return
135 }
136 let lines
137 if (isEmptyCoverage) {
138 // (empty-report), this will result in a report that has all lines zeroed out.
139 lines = covSource.lines.filter((line) => {
140 line.count = 0
141 return true
142 })
143 this.all = lines.length > 0
144 } else {
145 lines = sliceRange(covSource.lines, startCol, endCol)
146 }
147 if (!lines.length) {
148 return
149 }
150
151 const startLineInstance = lines[0]
152 const endLineInstance = lines[lines.length - 1]
153
154 if (block.isBlockCoverage) {
155 this.branches[path] = this.branches[path] || []
156 // record branches.
157 this.branches[path].push(new CovBranch(
158 startLineInstance.line,
159 startCol - startLineInstance.startCol,
160 endLineInstance.line,
161 endCol - endLineInstance.startCol,
162 range.count
163 ))
164
165 // if block-level granularity is enabled, we still create a single
166 // CovFunction tracking object for each set of ranges.
167 if (block.functionName && i === 0) {
168 this.functions[path] = this.functions[path] || []
169 this.functions[path].push(new CovFunction(
170 block.functionName,
171 startLineInstance.line,
172 startCol - startLineInstance.startCol,
173 endLineInstance.line,
174 endCol - endLineInstance.startCol,
175 range.count
176 ))
177 }
178 } else if (block.functionName) {
179 this.functions[path] = this.functions[path] || []
180 // record functions.
181 this.functions[path].push(new CovFunction(
182 block.functionName,
183 startLineInstance.line,
184 startCol - startLineInstance.startCol,
185 endLineInstance.line,
186 endCol - endLineInstance.startCol,
187 range.count
188 ))
189 }
190
191 // record the lines (we record these as statements, such that we're
192 // compatible with Istanbul 2.0).
193 lines.forEach(line => {
194 // make sure branch spans entire line; don't record 'goodbye'
195 // branch in `const foo = true ? 'hello' : 'goodbye'` as a
196 // 0 for line coverage.
197 //
198 // All lines start out with coverage of 1, and are later set to 0
199 // if they are not invoked; line.ignore prevents a line from being
200 // set to 0, and is set if the special comment /* c8 ignore next */
201 // is used.
202
203 if (startCol <= line.startCol && endCol >= line.endCol && !line.ignore) {
204 line.count = range.count
205 }
206 })
207 })
208 })
209 }
210
211 _maybeRemapStartColEndCol (range, isEmptyCoverage) {
212 let covSource = this.covSources[0].source
213 const covSourceWrapperLength = isEmptyCoverage ? 0 : covSource.wrapperLength
214 let startCol = Math.max(0, range.startOffset - covSourceWrapperLength)
215 let endCol = Math.min(covSource.eof, range.endOffset - covSourceWrapperLength)
216 let path = this.path
217
218 if (this.sourceMap) {
219 const sourceTranspiledWrapperLength = isEmptyCoverage ? 0 : this.sourceTranspiled.wrapperLength
220 startCol = Math.max(0, range.startOffset - sourceTranspiledWrapperLength)
221 endCol = Math.min(this.sourceTranspiled.eof, range.endOffset - sourceTranspiledWrapperLength)
222
223 const { startLine, relStartCol, endLine, relEndCol, source } = this.sourceTranspiled.offsetToOriginalRelative(
224 this.sourceMap,
225 startCol,
226 endCol
227 )
228
229 const matchingSource = this.covSources.find(covSource => covSource.path === source)
230 covSource = matchingSource ? matchingSource.source : this.covSources[0].source
231 path = matchingSource ? matchingSource.path : this.covSources[0].path
232
233 // next we convert these relative positions back to absolute positions
234 // in the original source (which is the format expected in the next step).
235 startCol = covSource.relativeToOffset(startLine, relStartCol)
236 endCol = covSource.relativeToOffset(endLine, relEndCol)
237 }
238
239 return {
240 path,
241 covSource,
242 startCol,
243 endCol
244 }
245 }
246
247 getInnerIstanbul (source, path) {
248 // We apply the "Resolving Sources" logic (as defined in
249 // sourcemaps.info/spec.html) as a final step for 1:many source maps.
250 // for 1:1 source maps, the resolve logic is applied while loading.
251 //
252 // TODO: could we move the resolving logic for 1:1 source maps to the final
253 // step as well? currently this breaks some tests in c8.
254 let resolvedPath = path
255 if (this.rawSourceMap && this.rawSourceMap.sourcemap.sources.length > 1) {
256 resolvedPath = this._resolveSource(this.rawSourceMap, path)
257 }
258
259 if (this.excludePath(resolvedPath)) {
260 return
261 }
262
263 return {
264 [resolvedPath]: {
265 path: resolvedPath,
266 all: this.all,
267 ...this._statementsToIstanbul(source, path),
268 ...this._branchesToIstanbul(source, path),
269 ...this._functionsToIstanbul(source, path)
270 }
271 }
272 }
273
274 toIstanbul () {
275 return this.covSources.reduce((istanbulOuter, { source, path }) => Object.assign(istanbulOuter, this.getInnerIstanbul(source, path)), {})
276 }
277
278 _statementsToIstanbul (source, path) {
279 const statements = {
280 statementMap: {},
281 s: {}
282 }
283 source.lines.forEach((line, index) => {
284 statements.statementMap[`${index}`] = line.toIstanbul()
285 statements.s[`${index}`] = line.ignore ? 1 : line.count
286 })
287 return statements
288 }
289
290 _branchesToIstanbul (source, path) {
291 const branches = {
292 branchMap: {},
293 b: {}
294 }
295 this.branches[path] = this.branches[path] || []
296 this.branches[path].forEach((branch, index) => {
297 const srcLine = source.lines[branch.startLine - 1]
298 const ignore = srcLine === undefined ? true : srcLine.ignore
299 branches.branchMap[`${index}`] = branch.toIstanbul()
300 branches.b[`${index}`] = [ignore ? 1 : branch.count]
301 })
302 return branches
303 }
304
305 _functionsToIstanbul (source, path) {
306 const functions = {
307 fnMap: {},
308 f: {}
309 }
310 this.functions[path] = this.functions[path] || []
311 this.functions[path].forEach((fn, index) => {
312 const srcLine = source.lines[fn.startLine - 1]
313 const ignore = srcLine === undefined ? true : srcLine.ignore
314 functions.fnMap[`${index}`] = fn.toIstanbul()
315 functions.f[`${index}`] = ignore ? 1 : fn.count
316 })
317 return functions
318 }
319}
320
321function parsePath (scriptPath) {
322 return scriptPath.startsWith('file://') ? fileURLToPath(scriptPath) : scriptPath
323}
node_modules/v8-to-istanbul/package.json +49 -0
……@@ -0,0 +1,49 @@
1{
2 "name": "v8-to-istanbul",
3 "version": "9.3.0",
4 "description": "convert from v8 coverage format to istanbul's format",
5 "main": "index.js",
6 "types": "index.d.ts",
7 "scripts": {
8 "fix": "standard --fix",
9 "snapshot": "TAP_SNAPSHOT=1 tap test/*.js",
10 "test": "c8 --reporter=html --reporter=text tap --no-coverage test/*.js",
11 "posttest": "standard",
12 "coverage": "c8 report --check-coverage"
13 },
14 "repository": "istanbuljs/v8-to-istanbul",
15 "keywords": [
16 "istanbul",
17 "v8",
18 "coverage"
19 ],
20 "standard": {
21 "ignore": [
22 "**/test/fixtures"
23 ]
24 },
25 "author": "Ben Coe <ben@npmjs.com>",
26 "license": "ISC",
27 "dependencies": {
28 "@jridgewell/trace-mapping": "^0.3.12",
29 "@types/istanbul-lib-coverage": "^2.0.1",
30 "convert-source-map": "^2.0.0"
31 },
32 "devDependencies": {
33 "@types/node": "^20.0.0",
34 "c8": "^7.2.1",
35 "semver": "^7.3.2",
36 "should": "13.2.3",
37 "source-map": "^0.7.3",
38 "standard": "^17.0.0",
39 "tap": "^16.0.0"
40 },
41 "engines": {
42 "node": ">=10.12.0"
43 },
44 "files": [
45 "lib/*.js",
46 "index.js",
47 "index.d.ts"
48 ]
49}
node_modules/xache/LICENSE +21 -0
……@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2021 Mathias Buus
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
node_modules/xache/README.md +35 -0
……@@ -0,0 +1,35 @@
1# xache
2
3Yet another auto expiring, max sizable cache
4
5```
6npm install xache
7```
8
9## Usage
10
11``` js
12const Xache = require('xache')
13
14const cache = new Xache({
15 maxSize: 10, // at max (ish) have 10 entries
16 maxAge: 100, // auto expire entries after (ish) 100ms
17 createMap () { // optional function to create backing storage
18 return new Map()
19 }
20})
21
22// When maxSize is hit, the oldest entries are removed
23// cache has the same api as a map
24
25cache.set('hello', 'world')
26console.log(cache.get('hello'))
27
28console.log(...cache) // iterable!
29```
30
31That's it, nice and simple.
32
33## License
34
35MIT
node_modules/xache/index.js +108 -0
……@@ -0,0 +1,108 @@
1module.exports = class MaxCache {
2 constructor ({ maxSize, maxAge, createMap, ongc }) {
3 this.maxSize = maxSize
4 this.maxAge = maxAge
5 this.ongc = ongc || null
6
7 this._createMap = createMap || defaultCreateMap
8 this._latest = this._createMap()
9 this._oldest = this._createMap()
10 this._retained = this._createMap()
11 this._gced = false
12 this._interval = null
13
14 if (this.maxAge > 0 && this.maxAge < Infinity) {
15 const tick = Math.ceil(2 / 3 * this.maxAge)
16 this._interval = setInterval(this._gcAuto.bind(this), tick)
17 if (this._interval.unref) this._interval.unref()
18 }
19 }
20
21 * [Symbol.iterator] () {
22 for (const it of [this._latest, this._oldest, this._retained]) {
23 yield * it
24 }
25 }
26
27 * keys () {
28 for (const it of [this._latest, this._oldest, this._retained]) {
29 yield * it.keys()
30 }
31 }
32
33 * values () {
34 for (const it of [this._latest, this._oldest, this._retained]) {
35 yield * it.values()
36 }
37 }
38
39 destroy () {
40 this.clear()
41 clearInterval(this._interval)
42 this._interval = null
43 }
44
45 clear () {
46 this._gced = true
47 this._latest.clear()
48 this._oldest.clear()
49 this._retained.clear()
50 }
51
52 set (k, v) {
53 if (this._retained.has(k)) return this
54 this._latest.set(k, v)
55 this._oldest.delete(k) || this._retained.delete(k)
56 if (this._latest.size >= this.maxSize) this._gc()
57 return this
58 }
59
60 retain (k, v) {
61 this._retained.set(k, v)
62 this._latest.delete(k) || this._oldest.delete(k)
63 return this
64 }
65
66 delete (k) {
67 return this._latest.delete(k) || this._oldest.delete(k) || this._retained.delete(k)
68 }
69
70 has (k) {
71 return this._latest.has(k) || this._oldest.has(k) || this._retained.has(k)
72 }
73
74 get (k) {
75 if (this._latest.has(k)) {
76 return this._latest.get(k)
77 }
78
79 if (this._oldest.has(k)) {
80 const v = this._oldest.get(k)
81 this._latest.set(k, v)
82 this._oldest.delete(k)
83 return v
84 }
85
86 if (this._retained.has(k)) {
87 return this._retained.get(k)
88 }
89
90 return null
91 }
92
93 _gcAuto () {
94 if (!this._gced) this._gc()
95 this._gced = false
96 }
97
98 _gc () {
99 this._gced = true
100 if (this.ongc !== null && this._oldest.size > 0) this.ongc(this._oldest)
101 this._oldest = this._latest
102 this._latest = this._createMap()
103 }
104}
105
106function defaultCreateMap () {
107 return new Map()
108}
node_modules/xache/package.json +26 -0
……@@ -0,0 +1,26 @@
1{
2 "name": "xache",
3 "version": "1.2.1",
4 "description": "Yet another auto expiring, max sizable cache",
5 "main": "index.js",
6 "files": [
7 "index.js"
8 ],
9 "devDependencies": {
10 "brittle": "^3.3.2",
11 "standard": "^17.1.0"
12 },
13 "scripts": {
14 "test": "standard && brittle test.js"
15 },
16 "repository": {
17 "type": "git",
18 "url": "https://github.com/mafintosh/xache.git"
19 },
20 "author": "Mathias Buus (@mafintosh)",
21 "license": "MIT",
22 "bugs": {
23 "url": "https://github.com/mafintosh/xache/issues"
24 },
25 "homepage": "https://github.com/mafintosh/xache"
26}
package-lock.json +691 -0
……@@ -8,12 +8,16 @@
88 "name": "autobase-doctor",
99 "version": "1.0.0",
1010 "dependencies": {
11 "@hyperswarm/testnet": "^3.1.4",
1112 "autobase": "^7.27.3",
13 "autobase-test-helpers": "^3.1.0",
1214 "bare-path": "^3.0.0",
1315 "bare-process": "^4.3.0",
16 "brittle": "^3.19.1",
1417 "corestore": "^7.9.2",
1518 "hyperbee": "^2.22.5",
1619 "hypercore": "^11.7.3",
20 "hyperswarm": "^4.17.0",
1721 "paparam": "^1.10.1"
1822 },
1923 "bin": {
……@@ -37,6 +41,58 @@
3741 "unslab": "^1.3.0"
3842 }
3943 },
44 "node_modules/@hyperswarm/testnet": {
45 "version": "3.1.4",
46 "resolved": "https://registry.npmjs.org/@hyperswarm/testnet/-/testnet-3.1.4.tgz",
47 "integrity": "sha512-Jw8JIZ9kdZ4R9jwJHsqctj5YeRqecw3aeCg2NS12HBXCqMioQIYzVqHs/8BWdOQCf34+BEXkwMQjba9CzaLwkg==",
48 "license": "Apache-2.0",
49 "dependencies": {
50 "hyperdht": "^6.6.0"
51 },
52 "bin": {
53 "hyperswarm-testnet": "bin.js"
54 }
55 },
56 "node_modules/@jridgewell/resolve-uri": {
57 "version": "3.1.2",
58 "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
59 "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
60 "license": "MIT",
61 "engines": {
62 "node": ">=6.0.0"
63 }
64 },
65 "node_modules/@jridgewell/sourcemap-codec": {
66 "version": "1.5.5",
67 "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
68 "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
69 "license": "MIT"
70 },
71 "node_modules/@jridgewell/trace-mapping": {
72 "version": "0.3.31",
73 "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
74 "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
75 "license": "MIT",
76 "dependencies": {
77 "@jridgewell/resolve-uri": "^3.1.0",
78 "@jridgewell/sourcemap-codec": "^1.4.14"
79 }
80 },
81 "node_modules/@types/istanbul-lib-coverage": {
82 "version": "2.0.6",
83 "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
84 "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
85 "license": "MIT"
86 },
87 "node_modules/adaptive-timeout": {
88 "version": "1.0.1",
89 "resolved": "https://registry.npmjs.org/adaptive-timeout/-/adaptive-timeout-1.0.1.tgz",
90 "integrity": "sha512-+seGiBtHqbnyZ0Quq/ZGxxwP66153WBABawa07/QeyuPFzbduPBjiGQAyCiriiLDzt3dkbMBskSlfqtRwblK8Q==",
91 "license": "Apache-2.0",
92 "dependencies": {
93 "xache": "^1.2.1"
94 }
95 },
4096 "node_modules/autobase": {
4197 "version": "7.27.3",
4298 "resolved": "https://registry.npmjs.org/autobase/-/autobase-7.27.3.tgz",
……@@ -67,6 +123,15 @@
67123 "tiny-buffer-map": "^1.1.1"
68124 }
69125 },
126 "node_modules/autobase-test-helpers": {
127 "version": "3.1.0",
128 "resolved": "https://registry.npmjs.org/autobase-test-helpers/-/autobase-test-helpers-3.1.0.tgz",
129 "integrity": "sha512-3Jk1nWEcMxYOtU6rt4ujpchLz0W/Uv7S6v0tea53wW9rZqwFzgffEYbufNak53/93DBbp3gwX+AgHdfHtpx4RQ==",
130 "license": "Apache-2.0",
131 "dependencies": {
132 "b4a": "^1.6.4"
133 }
134 },
70135 "node_modules/b4a": {
71136 "version": "1.8.0",
72137 "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
……@@ -131,6 +196,90 @@
131196 "bare-inspect": "^3.1.2"
132197 }
133198 },
199 "node_modules/bare-bundle": {
200 "version": "1.10.0",
201 "resolved": "https://registry.npmjs.org/bare-bundle/-/bare-bundle-1.10.0.tgz",
202 "integrity": "sha512-4LVlnJAHr00Hh6Vu6ZUJS38rcEtJT3b3vChXSsBsJ2mk1TN0lQ+gzd+Dw5L0aV7uqDZv84smuwW+O02X7PfDlw==",
203 "license": "Apache-2.0",
204 "peerDependencies": {
205 "bare-buffer": "*",
206 "bare-url": "*"
207 },
208 "peerDependenciesMeta": {
209 "bare-buffer": {
210 "optional": true
211 },
212 "bare-url": {
213 "optional": true
214 }
215 }
216 },
217 "node_modules/bare-cov": {
218 "version": "1.2.1",
219 "resolved": "https://registry.npmjs.org/bare-cov/-/bare-cov-1.2.1.tgz",
220 "integrity": "sha512-SHNqb/WG9udUEj8m5qGSehoUQ9o0Xzv8nrf4HIdmG+KNU/XdhPLhTP5VPrHnSAMAXhAzEB4Q+2IYZ0x9qPzN1g==",
221 "license": "Apache-2.0",
222 "dependencies": {
223 "bare-fs": "^4.1.2",
224 "bare-inspector": "^4.0.1",
225 "bare-path": "^3.0.0",
226 "bare-process": "^4.2.1",
227 "bare-url": "^2.1.5",
228 "bare-v8-to-istanbul": "^1.0.2",
229 "picomatch": "^4.0.2",
230 "which-runtime": "^1.2.1"
231 }
232 },
233 "node_modules/bare-crypto": {
234 "version": "1.13.4",
235 "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.13.4.tgz",
236 "integrity": "sha512-JiCZ5l2YOG1y8J7yy1BCAKTCZrPnHLb7pDRIdurBTOn5oIwBQDIv8iH5Pl2V85vzjl1NZXRfNY4HZLsE942jJA==",
237 "license": "Apache-2.0",
238 "dependencies": {
239 "bare-assert": "^1.2.0",
240 "bare-stream": "^2.6.3"
241 },
242 "peerDependencies": {
243 "bare-buffer": "*"
244 },
245 "peerDependenciesMeta": {
246 "bare-buffer": {
247 "optional": true
248 }
249 }
250 },
251 "node_modules/bare-debug-log": {
252 "version": "2.0.0",
253 "resolved": "https://registry.npmjs.org/bare-debug-log/-/bare-debug-log-2.0.0.tgz",
254 "integrity": "sha512-Vi42PkMQsNV9PUpx2Gl1hikshx5O9FzMJ6o9Nnopseg7qLBBK7Nl31d0RHcfwLEAfmcPApytpc0ZFfq68u22FQ==",
255 "license": "Apache-2.0",
256 "dependencies": {
257 "bare-os": "^3.0.1"
258 }
259 },
260 "node_modules/bare-dns": {
261 "version": "2.1.4",
262 "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz",
263 "integrity": "sha512-abwjHmpWqSRNB7V5615QxPH92L71AVzFm/kKTs8VYiNTAi2xVdonpv0BjJ0hwXLwomoW+xsSOPjW6PZPO14asg==",
264 "license": "Apache-2.0",
265 "engines": {
266 "bare": ">=1.7.0"
267 }
268 },
269 "node_modules/bare-encoding": {
270 "version": "1.0.3",
271 "resolved": "https://registry.npmjs.org/bare-encoding/-/bare-encoding-1.0.3.tgz",
272 "integrity": "sha512-Kqf+t/azs13lUeyK4Tb7ha4wdLRXKWCXQ8w1rVmt7KtoPCPdHD/Xwt7LBIsCSwwGglrcmblo5VOLa5avkJqULA==",
273 "license": "Apache-2.0",
274 "peerDependencies": {
275 "bare-buffer": "*"
276 },
277 "peerDependenciesMeta": {
278 "bare-buffer": {
279 "optional": true
280 }
281 }
282 },
134283 "node_modules/bare-env": {
135284 "version": "3.0.0",
136285 "resolved": "https://registry.npmjs.org/bare-env/-/bare-env-3.0.0.tgz",
……@@ -154,6 +303,15 @@
154303 }
155304 }
156305 },
306 "node_modules/bare-format": {
307 "version": "1.0.2",
308 "resolved": "https://registry.npmjs.org/bare-format/-/bare-format-1.0.2.tgz",
309 "integrity": "sha512-GswdhnOnP9QtwRbrf4wLApw5widkaLMsLe2XOs35fQD2YfEN1ApoGka+cZ7PfvzxMgfYXmMhj/2OGlVn5/Dxgw==",
310 "license": "Apache-2.0",
311 "dependencies": {
312 "bare-inspect": "^3.0.0"
313 }
314 },
157315 "node_modules/bare-fs": {
158316 "version": "4.5.6",
159317 "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.6.tgz",
……@@ -184,6 +342,47 @@
184342 "integrity": "sha512-VMb3tHo05gsnbu3OXTmkDiwTjMlOsbQmKoysKqKEyR09m77TuDrYFbj3Q5GGk10dAKsUHrnXmwCaeJqzVpB5ZA==",
185343 "license": "Apache-2.0"
186344 },
345 "node_modules/bare-http-parser": {
346 "version": "1.1.3",
347 "resolved": "https://registry.npmjs.org/bare-http-parser/-/bare-http-parser-1.1.3.tgz",
348 "integrity": "sha512-+dhVvQi6brHq14L/XHNRQ+TLuVE76VjRmMt61wVEtS+Od8xUslfMHWJN/ZjIIt3RtTG6vPuA+x9cOh7KrkBJsA==",
349 "license": "Apache-2.0"
350 },
351 "node_modules/bare-http1": {
352 "version": "4.5.5",
353 "resolved": "https://registry.npmjs.org/bare-http1/-/bare-http1-4.5.5.tgz",
354 "integrity": "sha512-ADITiRo0huP76JGMbv6Arsh9KehHqjEBoYcmjvAo67IY78+/9mV2MeKLLCkiJSFxA85T/m8cTaE44OwJQCcwdw==",
355 "license": "Apache-2.0",
356 "dependencies": {
357 "bare-events": "^2.6.0",
358 "bare-http-parser": "^1.1.1",
359 "bare-stream": "^2.10.0",
360 "bare-tcp": "^2.2.0"
361 },
362 "peerDependencies": {
363 "bare-buffer": "*",
364 "bare-url": "*"
365 },
366 "peerDependenciesMeta": {
367 "bare-buffer": {
368 "optional": true
369 },
370 "bare-url": {
371 "optional": true
372 }
373 }
374 },
375 "node_modules/bare-https": {
376 "version": "2.1.3",
377 "resolved": "https://registry.npmjs.org/bare-https/-/bare-https-2.1.3.tgz",
378 "integrity": "sha512-0TI/mJXQGYXmG7UUyWEG+KCJusayIAQLywUjFAskDoKuxfqVnGF+M/mTMrEV8J64DaIdU+5x761FvgmT7M68tA==",
379 "license": "Apache-2.0",
380 "dependencies": {
381 "bare-http1": "^4.4.0",
382 "bare-tcp": "^2.2.0",
383 "bare-tls": "^2.0.0"
384 }
385 },
187386 "node_modules/bare-inspect": {
188387 "version": "3.1.4",
189388 "resolved": "https://registry.npmjs.org/bare-inspect/-/bare-inspect-3.1.4.tgz",
……@@ -197,6 +396,71 @@
197396 "bare": ">=1.18.0"
198397 }
199398 },
399 "node_modules/bare-inspector": {
400 "version": "4.0.3",
401 "resolved": "https://registry.npmjs.org/bare-inspector/-/bare-inspector-4.0.3.tgz",
402 "integrity": "sha512-yYk6+7tTVKJKHOja5+QBn989ETv8oVsmwoH0nCM+QYC6w5MC03GC4aQNK+lipAZSz1EaAj42WZ8Wewjpy0L9TA==",
403 "license": "Apache-2.0",
404 "dependencies": {
405 "bare-events": "^2.1.0",
406 "bare-http1": "^4.0.0",
407 "bare-stream": "^2.0.0",
408 "bare-url": "^2.0.0",
409 "bare-ws": "^2.0.0"
410 },
411 "engines": {
412 "bare": ">=1.2.0"
413 },
414 "peerDependencies": {
415 "bare-tcp": "*"
416 },
417 "peerDependenciesMeta": {
418 "bare-tcp": {
419 "optional": true
420 }
421 }
422 },
423 "node_modules/bare-module": {
424 "version": "6.1.3",
425 "resolved": "https://registry.npmjs.org/bare-module/-/bare-module-6.1.3.tgz",
426 "integrity": "sha512-5XWsVHsvtWMH4tK4DQWgpNTV0t/sg3ZrAaQLIxrwjrS5+u8Q9vEgc/zQ4QaDPWDse/y/5h+d+YG1Q0JfSMt0zA==",
427 "license": "Apache-2.0",
428 "dependencies": {
429 "bare-bundle": "^1.3.0",
430 "bare-module-lexer": "^1.0.0",
431 "bare-module-resolve": "^1.8.0",
432 "bare-path": "^3.0.0",
433 "bare-url": "^2.0.1"
434 },
435 "engines": {
436 "bare": ">=1.23.0"
437 },
438 "peerDependencies": {
439 "bare-buffer": "*"
440 },
441 "peerDependenciesMeta": {
442 "bare-buffer": {
443 "optional": true
444 }
445 }
446 },
447 "node_modules/bare-module-lexer": {
448 "version": "1.4.7",
449 "resolved": "https://registry.npmjs.org/bare-module-lexer/-/bare-module-lexer-1.4.7.tgz",
450 "integrity": "sha512-0klU4eMsjh/wcxi8FdHmNom2j2F4kmkXOhyJFL9qTaSFp2lE3m6BtbKgMHY8R5miqC9r8/IfA8wzXnC5Os14WA==",
451 "license": "Apache-2.0",
452 "dependencies": {
453 "require-addon": "^1.0.2"
454 },
455 "peerDependencies": {
456 "bare-buffer": "*"
457 },
458 "peerDependenciesMeta": {
459 "bare-buffer": {
460 "optional": true
461 }
462 }
463 },
200464 "node_modules/bare-module-resolve": {
201465 "version": "1.12.1",
202466 "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz",
……@@ -214,6 +478,18 @@
214478 }
215479 }
216480 },
481 "node_modules/bare-net": {
482 "version": "2.3.1",
483 "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.1.tgz",
484 "integrity": "sha512-MypSqDKpDU2Xt7FIfazn5yGvRnV09gFcIPHGWstW0gxuzA4tucTcwJSZeos97C4F89vtU5oGwXDN/HrGN6Y4Jw==",
485 "license": "Apache-2.0",
486 "dependencies": {
487 "bare-events": "^2.2.2",
488 "bare-pipe": "^4.0.0",
489 "bare-stream": "^2.0.0",
490 "bare-tcp": "^2.0.0"
491 }
492 },
217493 "node_modules/bare-os": {
218494 "version": "3.8.0",
219495 "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.0.tgz",
……@@ -306,6 +582,67 @@
306582 }
307583 }
308584 },
585 "node_modules/bare-stylize": {
586 "version": "0.0.1",
587 "resolved": "https://registry.npmjs.org/bare-stylize/-/bare-stylize-0.0.1.tgz",
588 "integrity": "sha512-l3MjmIl476bWijYWf3RbE+osl4iuXSOMudzp0vAqzIK7gPgn/+G3oAxp8Oin9CFF911KBP0LO9kts8Ci8mGZaQ==",
589 "license": "Apache-2.0",
590 "dependencies": {
591 "bare-ansi-escapes": "^2.2.3",
592 "bare-process": "^4.2.1"
593 }
594 },
595 "node_modules/bare-subprocess": {
596 "version": "5.2.3",
597 "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-5.2.3.tgz",
598 "integrity": "sha512-07wwswlV7M3sC9IykbZRZ/jHAkrXFWVLqdBWGv1y0ojCimtRD9hGwxdHmR5FUFmDUZLNsBmTYJNQqgio5+A85Q==",
599 "license": "Apache-2.0",
600 "dependencies": {
601 "bare-env": "^3.0.0",
602 "bare-events": "^2.5.4",
603 "bare-os": "^3.0.1",
604 "bare-pipe": "^4.0.0",
605 "bare-url": "^2.2.2"
606 },
607 "engines": {
608 "bare": ">=1.7.0"
609 },
610 "peerDependencies": {
611 "bare-buffer": "*"
612 },
613 "peerDependenciesMeta": {
614 "bare-buffer": {
615 "optional": true
616 }
617 }
618 },
619 "node_modules/bare-tcp": {
620 "version": "2.2.7",
621 "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.2.7.tgz",
622 "integrity": "sha512-rjpqNQ2cOCkNo3NeYA/W4GTK3DRkl8sDHO3uos+AEswUjLC8XXMQF8WrJCSjlIowCbS6NUVxKE92X5RGXjyefg==",
623 "license": "Apache-2.0",
624 "dependencies": {
625 "bare-dns": "^2.0.4",
626 "bare-events": "^2.5.4",
627 "bare-stream": "^2.6.4"
628 },
629 "engines": {
630 "bare": ">=1.16.0"
631 }
632 },
633 "node_modules/bare-tls": {
634 "version": "2.2.1",
635 "resolved": "https://registry.npmjs.org/bare-tls/-/bare-tls-2.2.1.tgz",
636 "integrity": "sha512-hZ+ZqwrUO4dyH7/6WYkYWjgAFNJKjzwEYJiDaMnMs+eRleBDjQ3CvNZawpkw0Ar9jnM9NZK6+f6GqjkZ2FLGmQ==",
637 "license": "Apache-2.0",
638 "dependencies": {
639 "bare-net": "^2.0.1",
640 "bare-stream": "^2.6.4"
641 },
642 "engines": {
643 "bare": ">=1.7.0"
644 }
645 },
309646 "node_modules/bare-tty": {
310647 "version": "5.0.3",
311648 "resolved": "https://registry.npmjs.org/bare-tty/-/bare-tty-5.0.3.tgz",
……@@ -334,16 +671,137 @@
334671 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz",
335672 "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==",
336673 "license": "Apache-2.0",
674 "peer": true,
337675 "dependencies": {
338676 "bare-path": "^3.0.0"
339677 }
340678 },
679 "node_modules/bare-utils": {
680 "version": "1.6.0",
681 "resolved": "https://registry.npmjs.org/bare-utils/-/bare-utils-1.6.0.tgz",
682 "integrity": "sha512-WhQEIkkAxkSnW7u1QgrI0AfNm5JpMruETXeYsb5qnkBJ0TTfNKygZmsh6rkoHBANaV+C/7Jed7bJP9OmEHG7rQ==",
683 "license": "Apache-2.0",
684 "dependencies": {
685 "bare-debug-log": "^2.0.0",
686 "bare-encoding": "^1.0.0",
687 "bare-format": "^1.0.0",
688 "bare-inspect": "^3.0.0",
689 "bare-stylize": "^0.0.1",
690 "bare-type": "^1.0.6"
691 }
692 },
693 "node_modules/bare-v8-to-istanbul": {
694 "version": "1.0.2",
695 "resolved": "https://registry.npmjs.org/bare-v8-to-istanbul/-/bare-v8-to-istanbul-1.0.2.tgz",
696 "integrity": "sha512-CM0wPgyQtXTQ7h4q8NjbTZ/FH5he0Jkiwgpq0lFZZA5tkVZzmQ/9ul4R7E+cNlGZJIZlQZ9v4CwbgVaFG3zOAA==",
697 "license": "Apache-2.0",
698 "dependencies": {
699 "bare-assert": "^1.0.2",
700 "bare-fs": "^4.1.2",
701 "bare-module": "^6.1.2",
702 "bare-path": "^3.0.0",
703 "bare-process": "^4.2.0",
704 "bare-url": "^2.1.5",
705 "bare-utils": "^1.2.0",
706 "v8-to-istanbul": "^9.3.0",
707 "which-runtime": "^1.2.1"
708 }
709 },
710 "node_modules/bare-ws": {
711 "version": "2.1.0",
712 "resolved": "https://registry.npmjs.org/bare-ws/-/bare-ws-2.1.0.tgz",
713 "integrity": "sha512-2gEWlPK9iyBchACdIY6oQXgmDz3KLrChdwrPgmU3IVXOFTnxTqSUT27WE/+izd4QojHj/SsqDkQiD2HDvuTdAA==",
714 "license": "Apache-2.0",
715 "dependencies": {
716 "bare-crypto": "^1.2.0",
717 "bare-events": "^2.3.1",
718 "bare-http1": "^4.0.0",
719 "bare-https": "^2.0.0",
720 "bare-stream": "^2.1.2"
721 },
722 "peerDependencies": {
723 "bare-buffer": "*",
724 "bare-url": "*"
725 },
726 "peerDependenciesMeta": {
727 "bare-buffer": {
728 "optional": true
729 },
730 "bare-url": {
731 "optional": true
732 }
733 }
734 },
341735 "node_modules/big-sparse-array": {
342736 "version": "1.0.3",
343737 "resolved": "https://registry.npmjs.org/big-sparse-array/-/big-sparse-array-1.0.3.tgz",
344738 "integrity": "sha512-6RjV/3mSZORlMdpUaQ6rUSpG637cZm0//E54YYGtQg1c1O+AbZP8UTdJ/TchsDZcTVLmyWZcseBfp2HBeXUXOQ==",
345739 "license": "MIT"
346740 },
741 "node_modules/bits-to-bytes": {
742 "version": "1.3.0",
743 "resolved": "https://registry.npmjs.org/bits-to-bytes/-/bits-to-bytes-1.3.0.tgz",
744 "integrity": "sha512-OJoHTpFXS9bXHBCekGTByf3MqM8CGblBDIduKQeeVVeiU9dDWywSSirXIBYGgg3d1zbVuvnMa1vD4r6PA0kOKg==",
745 "license": "ISC",
746 "dependencies": {
747 "b4a": "^1.5.0"
748 }
749 },
750 "node_modules/blind-relay": {
751 "version": "1.4.0",
752 "resolved": "https://registry.npmjs.org/blind-relay/-/blind-relay-1.4.0.tgz",
753 "integrity": "sha512-6xt7fDfCs6eGmNNym6I9N42jmjcMQn2qwwOVnkP9ZnrkXFk6c4/tdO1xqRmDEzKzV8gigd+DVdCUG/RUYnen7Q==",
754 "license": "Apache-2.0",
755 "dependencies": {
756 "b4a": "^1.6.4",
757 "bare-events": "^2.2.0",
758 "bits-to-bytes": "^1.3.0",
759 "compact-encoding": "^2.12.0",
760 "compact-encoding-bitfield": "^1.0.0",
761 "protomux": "^3.5.1",
762 "sodium-universal": "^5.0.0",
763 "streamx": "^2.15.1"
764 }
765 },
766 "node_modules/bogon": {
767 "version": "1.2.0",
768 "resolved": "https://registry.npmjs.org/bogon/-/bogon-1.2.0.tgz",
769 "integrity": "sha512-FqOBr/1VMzCOsoJd+fzNUMarUYki2+TKt07A2+xaulsNx4r53iJ7MV5k0jbqg7W2U0CsLqxCZOrFibdG6h6HSg==",
770 "license": "MIT",
771 "dependencies": {
772 "compact-encoding": "^2.11.0",
773 "compact-encoding-net": "^1.2.0"
774 }
775 },
776 "node_modules/brittle": {
777 "version": "3.19.1",
778 "resolved": "https://registry.npmjs.org/brittle/-/brittle-3.19.1.tgz",
779 "integrity": "sha512-4Ted1Mt9o9B6oIA6ImJJCtB/Fv++ZO3IDNQgRcHOXWSYGRUidgxchaGrUBaRn+4mlneXrgInPkCPzi0jO8qKbA==",
780 "license": "Apache-2.0",
781 "dependencies": {
782 "b4a": "^1.6.0",
783 "bare-assert": "^1.0.2",
784 "bare-cov": "^1.1.0",
785 "bare-fs": "^4.1.6",
786 "bare-os": "^3.6.1",
787 "bare-path": "^3.0.0",
788 "bare-process": "^4.2.1",
789 "bare-subprocess": "^5.0.0",
790 "bare-url": "^2.1.6",
791 "error-stack-parser": "^2.1.4",
792 "globbie": "^1.0.2",
793 "paparam": "^1.6.2",
794 "same-object": "^1.0.2",
795 "test-tmp": "^1.4.0",
796 "tmatch": "^5.0.0"
797 },
798 "bin": {
799 "brittle": "bin/node.js",
800 "brittle-bare": "bin/bare.js",
801 "brittle-node": "bin/node.js",
802 "brittle-pear": "bin/pear.js"
803 }
804 },
347805 "node_modules/codecs": {
348806 "version": "3.1.0",
349807 "resolved": "https://registry.npmjs.org/codecs/-/codecs-3.1.0.tgz",
……@@ -362,6 +820,30 @@
362820 "b4a": "^1.3.0"
363821 }
364822 },
823 "node_modules/compact-encoding-bitfield": {
824 "version": "1.0.0",
825 "resolved": "https://registry.npmjs.org/compact-encoding-bitfield/-/compact-encoding-bitfield-1.0.0.tgz",
826 "integrity": "sha512-3nMVKUg+PF72UHfainmCL8uKvyWfxsjqOtUY+HiMPGLPCTjnwzoKfFAMo1Ad7nwTPdjBqtGK5b3BOFTFW4EBTg==",
827 "license": "ISC",
828 "dependencies": {
829 "compact-encoding": "^2.4.1"
830 }
831 },
832 "node_modules/compact-encoding-net": {
833 "version": "1.2.0",
834 "resolved": "https://registry.npmjs.org/compact-encoding-net/-/compact-encoding-net-1.2.0.tgz",
835 "integrity": "sha512-LVXpNpF7PGQeHRVVLGgYWzuVoYAaDZvKUsUxRioGfkotzvOh4AzoQF1HBH3zMNaSnx7gJXuUr3hkjnijaH/Eng==",
836 "license": "ISC",
837 "dependencies": {
838 "compact-encoding": "^2.4.1"
839 }
840 },
841 "node_modules/convert-source-map": {
842 "version": "2.0.0",
843 "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
844 "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
845 "license": "MIT"
846 },
365847 "node_modules/core-coupler": {
366848 "version": "2.0.0",
367849 "resolved": "https://registry.npmjs.org/core-coupler/-/core-coupler-2.0.0.tgz",
……@@ -407,6 +889,26 @@
407889 "ready-resource": "^1.2.0"
408890 }
409891 },
892 "node_modules/dht-rpc": {
893 "version": "6.26.3",
894 "resolved": "https://registry.npmjs.org/dht-rpc/-/dht-rpc-6.26.3.tgz",
895 "integrity": "sha512-KuLfRv/hecUHipQcTXHpVv4/N4Jhpww5sLdsrn3Edm5oHwzK9SgNV34hNt7a2aVZCOcG5SfP4AvcQ7pI+y9YNg==",
896 "license": "MIT",
897 "dependencies": {
898 "adaptive-timeout": "^1.0.1",
899 "b4a": "^1.6.1",
900 "bare-events": "^2.2.0",
901 "compact-encoding": "^2.11.0",
902 "compact-encoding-net": "^1.2.0",
903 "fast-fifo": "^1.1.0",
904 "kademlia-routing-table": "^1.0.1",
905 "nat-sampler": "^1.0.1",
906 "sodium-universal": "^5.0.0",
907 "streamx": "^2.13.2",
908 "time-ordered-set": "^2.0.0",
909 "udx-native": "^1.5.3"
910 }
911 },
410912 "node_modules/encryption-encoding": {
411913 "version": "1.0.3",
412914 "resolved": "https://registry.npmjs.org/encryption-encoding/-/encryption-encoding-1.0.3.tgz",
……@@ -416,6 +918,15 @@
416918 "hyperschema": "^1.19.0"
417919 }
418920 },
921 "node_modules/error-stack-parser": {
922 "version": "2.1.4",
923 "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
924 "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
925 "license": "MIT",
926 "dependencies": {
927 "stackframe": "^1.3.4"
928 }
929 },
419930 "node_modules/events-universal": {
420931 "version": "1.0.1",
421932 "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
……@@ -474,6 +985,18 @@
474985 "integrity": "sha512-IfTY0dKZM43ACyGvXkbG7De7WY7MxTS5VO6Juhe8oJKpCmrYYXoqp/cJMskkpi0k9H8wuXq0H+eI898/BCqvXg==",
475986 "license": "MIT"
476987 },
988 "node_modules/globbie": {
989 "version": "1.0.3",
990 "resolved": "https://registry.npmjs.org/globbie/-/globbie-1.0.3.tgz",
991 "integrity": "sha512-hcryJmKcftf82xfBWTWxuUITWIIoYO3ec104V17SMHGFl6VLbm1d1Ju9LX9L+jyJTwICpemX/dmPI/HGYoKr1A==",
992 "license": "Apache-2.0",
993 "dependencies": {
994 "bare-fs": "^4.1.2",
995 "bare-path": "^3.0.0",
996 "bare-process": "^4.2.1",
997 "picomatch": "^4.0.2"
998 }
999 },
4771000 "node_modules/hyperbee": {
4781001 "version": "2.27.3",
4791002 "resolved": "https://registry.npmjs.org/hyperbee/-/hyperbee-2.27.3.tgz",
……@@ -574,6 +1097,35 @@
5741097 "streamx": "^2.21.1"
5751098 }
5761099 },
1100 "node_modules/hyperdht": {
1101 "version": "6.29.6",
1102 "resolved": "https://registry.npmjs.org/hyperdht/-/hyperdht-6.29.6.tgz",
1103 "integrity": "sha512-bMMtw02fhiALdsTVLNZ/VFmMZuEY8kxb0/Rprl6oYF4/TCS653i3FDjtJeRbqtnAzwAj6dVZ/EwhoNOSCFGaYQ==",
1104 "license": "MIT",
1105 "dependencies": {
1106 "@hyperswarm/secret-stream": "^6.6.2",
1107 "b4a": "^1.3.1",
1108 "bare-events": "^2.2.0",
1109 "blind-relay": "^1.3.0",
1110 "bogon": "^1.0.0",
1111 "compact-encoding": "^2.4.1",
1112 "dht-rpc": "^6.15.1",
1113 "hypercore-crypto": "^3.3.0",
1114 "hypercore-id-encoding": "^1.2.0",
1115 "noise-curve-ed": "^2.0.0",
1116 "noise-handshake": "^4.0.0",
1117 "record-cache": "^1.1.1",
1118 "safety-catch": "^1.0.1",
1119 "signal-promise": "^1.0.3",
1120 "sodium-universal": "^5.0.1",
1121 "streamx": "^2.16.1",
1122 "unslab": "^1.3.0",
1123 "xache": "^1.1.0"
1124 },
1125 "bin": {
1126 "hyperdht": "bin.js"
1127 }
1128 },
5771129 "node_modules/hyperschema": {
5781130 "version": "1.20.1",
5791131 "resolved": "https://registry.npmjs.org/hyperschema/-/hyperschema-1.20.1.tgz",
……@@ -586,6 +1138,21 @@
5861138 "generate-string": "^1.0.1"
5871139 }
5881140 },
1141 "node_modules/hyperswarm": {
1142 "version": "4.17.0",
1143 "resolved": "https://registry.npmjs.org/hyperswarm/-/hyperswarm-4.17.0.tgz",
1144 "integrity": "sha512-oe86sK961Ueg7rvDN/veFwG8xH+Iv6vObPhGDkPJcDVxk/NduW41ZhAcVDnHzRbm7S0eLU7WaDUvehOYoKSpRQ==",
1145 "license": "MIT",
1146 "dependencies": {
1147 "b4a": "^1.3.1",
1148 "bare-events": "^2.2.0",
1149 "hyperdht": "^6.21.0",
1150 "safety-catch": "^1.0.2",
1151 "shuffled-priority-queue": "^2.1.0",
1152 "streamx": "^2.22.1",
1153 "unslab": "^1.3.0"
1154 }
1155 },
5891156 "node_modules/index-encoder": {
5901157 "version": "3.5.0",
5911158 "resolved": "https://registry.npmjs.org/index-encoder/-/index-encoder-3.5.0.tgz",
……@@ -610,6 +1177,15 @@
6101177 "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
6111178 "license": "MIT"
6121179 },
1180 "node_modules/kademlia-routing-table": {
1181 "version": "1.0.6",
1182 "resolved": "https://registry.npmjs.org/kademlia-routing-table/-/kademlia-routing-table-1.0.6.tgz",
1183 "integrity": "sha512-Ve6jwIlUCYvUzBnXnzVRHDZCFgXURW9gmF3r7n05kZs/2rNbLHXwGdcq0qIaSwdmJCvtosgR4JensnVU65hzNQ==",
1184 "license": "MIT",
1185 "dependencies": {
1186 "bare-events": "^2.2.0"
1187 }
1188 },
6131189 "node_modules/mutexify": {
6141190 "version": "1.4.0",
6151191 "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.4.0.tgz",
……@@ -625,6 +1201,12 @@
6251201 "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==",
6261202 "license": "ISC"
6271203 },
1204 "node_modules/nat-sampler": {
1205 "version": "1.0.1",
1206 "resolved": "https://registry.npmjs.org/nat-sampler/-/nat-sampler-1.0.1.tgz",
1207 "integrity": "sha512-yQvyNN7xbqR8crTKk3U8gRgpcV1Az+vfCEijiHu9oHHsnIl8n3x+yXNHl42M6L3czGynAVoOT9TqBfS87gDdcw==",
1208 "license": "MIT"
1209 },
6281210 "node_modules/noise-curve-ed": {
6291211 "version": "2.1.0",
6301212 "resolved": "https://registry.npmjs.org/noise-curve-ed/-/noise-curve-ed-2.1.0.tgz",
……@@ -653,6 +1235,18 @@
6531235 "integrity": "sha512-viyQI64VIja0Za3njIzhoEP8ZVkgPowhZPuG0E96NwBfYJ6ZIyrrlhWGtFPkdN7eYLl2L8CTWL+wla0evm1KKQ==",
6541236 "license": "Apache-2.0"
6551237 },
1238 "node_modules/picomatch": {
1239 "version": "4.0.4",
1240 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
1241 "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
1242 "license": "MIT",
1243 "engines": {
1244 "node": ">=12"
1245 },
1246 "funding": {
1247 "url": "https://github.com/sponsors/jonschlinkert"
1248 }
1249 },
6561250 "node_modules/protocol-buffers-encodings": {
6571251 "version": "1.2.0",
6581252 "resolved": "https://registry.npmjs.org/protocol-buffers-encodings/-/protocol-buffers-encodings-1.2.0.tgz",
……@@ -739,6 +1333,15 @@
7391333 "bare-events": "^2.2.0"
7401334 }
7411335 },
1336 "node_modules/record-cache": {
1337 "version": "1.2.0",
1338 "resolved": "https://registry.npmjs.org/record-cache/-/record-cache-1.2.0.tgz",
1339 "integrity": "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw==",
1340 "license": "MIT",
1341 "dependencies": {
1342 "b4a": "^1.3.1"
1343 }
1344 },
7421345 "node_modules/refcounter": {
7431346 "version": "1.0.0",
7441347 "resolved": "https://registry.npmjs.org/refcounter/-/refcounter-1.0.0.tgz",
……@@ -793,12 +1396,27 @@
7931396 "integrity": "sha512-Zq+J1TefpoEq/HTUabo0YXX5MNvttjWYODGohgPBO2jfko8Wqx3JYMgE823szDFVamdH5PlpByvfiWScTdSYDA==",
7941397 "license": "MIT"
7951398 },
1399 "node_modules/same-object": {
1400 "version": "1.0.2",
1401 "resolved": "https://registry.npmjs.org/same-object/-/same-object-1.0.2.tgz",
1402 "integrity": "sha512-csHWhvUsLbIOHDM/nP+KHWM+BLPsIzWkFa8HbzaI0G7BqKXgx+7FJpKTGgLXyz5amfdY2OVBcmXTqYOMEk04og==",
1403 "license": "MIT"
1404 },
7961405 "node_modules/scope-lock": {
7971406 "version": "1.2.4",
7981407 "resolved": "https://registry.npmjs.org/scope-lock/-/scope-lock-1.2.4.tgz",
7991408 "integrity": "sha512-BpSd8VCuCxW9ZitcdIC/vjs3gMaP9bRBL5nkHcyfX2VrS52n13/rHuBA2xJ/S/4DPuRdAO/Bk8pWd8eD/gHCIA==",
8001409 "license": "Apache-2.0"
8011410 },
1411 "node_modules/shuffled-priority-queue": {
1412 "version": "2.1.0",
1413 "resolved": "https://registry.npmjs.org/shuffled-priority-queue/-/shuffled-priority-queue-2.1.0.tgz",
1414 "integrity": "sha512-xhdh7fHyMsr0m/w2kDfRJuBFRS96b9l8ZPNWGaQ+PMvnUnZ/Eh+gJJ9NsHBd7P9k0399WYlCLzsy18EaMfyadA==",
1415 "license": "MIT",
1416 "dependencies": {
1417 "unordered-set": "^2.0.1"
1418 }
1419 },
8021420 "node_modules/signal-promise": {
8031421 "version": "1.0.3",
8041422 "resolved": "https://registry.npmjs.org/signal-promise/-/signal-promise-1.0.3.tgz",
……@@ -878,6 +1496,12 @@
8781496 }
8791497 }
8801498 },
1499 "node_modules/stackframe": {
1500 "version": "1.3.4",
1501 "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
1502 "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
1503 "license": "MIT"
1504 },
8811505 "node_modules/streamx": {
8821506 "version": "2.25.0",
8831507 "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz",
……@@ -908,6 +1532,17 @@
9081532 "streamx": "^2.12.5"
9091533 }
9101534 },
1535 "node_modules/test-tmp": {
1536 "version": "1.4.0",
1537 "resolved": "https://registry.npmjs.org/test-tmp/-/test-tmp-1.4.0.tgz",
1538 "integrity": "sha512-GVggxGg+jXqP2Wbju50JVLo+9E+nIOPPyWqgr63EbOnNItIKu1cEbJpTWAJeflnyGqXOtcMI7ijHRp88GUkfDA==",
1539 "license": "MIT",
1540 "dependencies": {
1541 "bare-fs": "^4.0.1",
1542 "bare-os": "^3.3.0",
1543 "bare-path": "^3.0.0"
1544 }
1545 },
9111546 "node_modules/text-decoder": {
9121547 "version": "1.2.7",
9131548 "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
……@@ -917,6 +1552,12 @@
9171552 "b4a": "^1.6.4"
9181553 }
9191554 },
1555 "node_modules/time-ordered-set": {
1556 "version": "2.0.1",
1557 "resolved": "https://registry.npmjs.org/time-ordered-set/-/time-ordered-set-2.0.1.tgz",
1558 "integrity": "sha512-VJEKmgSN2UiOLB8BpN8Sh2b9LGMHTP5OPrQRpnKjvOheOyzk0mufbjzjKTIG2gO4A+Y+vDJ+0TcLbpUmMLsg8A==",
1559 "license": "MIT"
1560 },
9201561 "node_modules/timeout-refresh": {
9211562 "version": "2.0.1",
9221563 "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-2.0.1.tgz",
……@@ -932,6 +1573,36 @@
9321573 "b4a": "^1.6.0"
9331574 }
9341575 },
1576 "node_modules/tmatch": {
1577 "version": "5.0.0",
1578 "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-5.0.0.tgz",
1579 "integrity": "sha512-Ib9OtBkpHn07tXP04SlN1SYRxFgTk6wSM2EBmjjxug4u5RXPRVLkdFJSS1PmrQidaSB8Lru9nRtViQBsbxzE5Q==",
1580 "license": "ISC",
1581 "engines": {
1582 "node": ">=8"
1583 }
1584 },
1585 "node_modules/udx-native": {
1586 "version": "1.19.2",
1587 "resolved": "https://registry.npmjs.org/udx-native/-/udx-native-1.19.2.tgz",
1588 "integrity": "sha512-RNYh+UhfryCsF5hE2ZOuIqcZ+qdipXK3UsarwxWJwsUQZFE3ybwz0mPjwb5ev1PMBcjFahWiepS/q0wwL51c2g==",
1589 "license": "Apache-2.0",
1590 "dependencies": {
1591 "b4a": "^1.5.0",
1592 "bare-events": "^2.2.0",
1593 "require-addon": "^1.1.0",
1594 "streamx": "^2.22.0"
1595 },
1596 "engines": {
1597 "bare": ">=1.17.4"
1598 }
1599 },
1600 "node_modules/unordered-set": {
1601 "version": "2.0.1",
1602 "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz",
1603 "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==",
1604 "license": "MIT"
1605 },
9351606 "node_modules/unslab": {
9361607 "version": "1.3.0",
9371608 "resolved": "https://registry.npmjs.org/unslab/-/unslab-1.3.0.tgz",
……@@ -941,6 +1612,20 @@
9411612 "b4a": "^1.6.6"
9421613 }
9431614 },
1615 "node_modules/v8-to-istanbul": {
1616 "version": "9.3.0",
1617 "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
1618 "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
1619 "license": "ISC",
1620 "dependencies": {
1621 "@jridgewell/trace-mapping": "^0.3.12",
1622 "@types/istanbul-lib-coverage": "^2.0.1",
1623 "convert-source-map": "^2.0.0"
1624 },
1625 "engines": {
1626 "node": ">=10.12.0"
1627 }
1628 },
9441629 "node_modules/varint": {
9451630 "version": "5.0.0",
9461631 "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
……@@ -953,6 +1638,12 @@
9531638 "integrity": "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw==",
9541639 "license": "Apache-2.0"
9551640 },
1641 "node_modules/xache": {
1642 "version": "1.2.1",
1643 "resolved": "https://registry.npmjs.org/xache/-/xache-1.2.1.tgz",
1644 "integrity": "sha512-igRS6jPreJ54ABdzhh4mCDXcz+XMaWO2q1ABRV2yWYuk29jlp8VT7UBdCqNkX7rpYBbXsebVVKkwIuYZjyZNqA==",
1645 "license": "MIT"
1646 },
9561647 "node_modules/z32": {
9571648 "version": "1.1.0",
9581649 "resolved": "https://registry.npmjs.org/z32/-/z32-1.1.0.tgz",
package.json +4 -0
……@@ -8,12 +8,16 @@
88 "autobase-doctor": "./bin/autobase-doctor.js"
99 },
1010 "dependencies": {
11 "@hyperswarm/testnet": "^3.1.4",
1112 "autobase": "^7.27.3",
13 "autobase-test-helpers": "^3.1.0",
1214 "bare-path": "^3.0.0",
1315 "bare-process": "^4.3.0",
16 "brittle": "^3.19.1",
1417 "corestore": "^7.9.2",
1518 "hyperbee": "^2.22.5",
1619 "hypercore": "^11.7.3",
20 "hyperswarm": "^4.17.0",
1721 "paparam": "^1.10.1"
1822 }
1923}
test/multi-writer-edge-cases.js +422 -0
……@@ -0,0 +1,422 @@
1#!/usr/bin/env bare
2
3/**
4 * Edge case tests for Autobase multi-writer over Hyperswarm.
5 * These cover scenarios that could break in production.
6 */
7
8import test from 'brittle'
9import Corestore from 'corestore'
10import Autobase from 'autobase'
11import Hyperbee from 'hyperbee'
12import Hyperswarm from 'hyperswarm'
13import createTestnet from '@hyperswarm/testnet'
14import os from 'bare-os'
15import path from 'bare-path'
16import fs from 'bare-fs'
17
18const tmpdir = os.tmpdir()
19let idx = 0
20function tmpPath (name) {
21 return path.join(tmpdir, 'ab-edge-' + name + '-' + (idx++) + '-' + Date.now())
22}
23async function cleanup (...dirs) {
24 for (const d of dirs) await fs.promises.rm(d, { recursive: true }).catch(() => {})
25}
26
27function open (store) {
28 return new Hyperbee(store.get('view', { valueEncoding: 'json' }), {
29 keyEncoding: 'utf-8',
30 valueEncoding: 'json'
31 })
32}
33
34// Mimics pear-git LinkedRepo apply — with probe validation
35async function peerGitApply (batch, view, host) {
36 const b = view.batch()
37 for (const node of batch) {
38 const op = node.value
39 if (!op || !op.type) continue
40
41 switch (op.type) {
42 case 'create-issue': {
43 await b.put('issue:' + op.id, {
44 id: op.id,
45 title: op.title,
46 body: op.body || '',
47 author: op.author || 'unknown',
48 status: 'open',
49 createdAt: op.timestamp || Date.now()
50 })
51 const counter = await b.get('counter:issues')
52 const next = counter ? counter.value.next : 0
53 if (op.id >= next) await b.put('counter:issues', { next: op.id + 1 })
54 break
55 }
56 case 'update-issue': {
57 const entry = await b.get('issue:' + op.id)
58 if (entry) {
59 const issue = entry.value
60 if (op.status) issue.status = op.status
61 if (op.title) issue.title = op.title
62 await b.put('issue:' + op.id, issue)
63 }
64 break
65 }
66 case 'add-writer': {
67 if (op.key) {
68 try {
69 await host.addWriter(Buffer.from(op.key, 'hex'), { indexer: op.indexer !== false })
70 } catch {}
71 }
72 break
73 }
74 }
75 }
76 await b.flush()
77}
78
79function createBase (store, key) {
80 return new Autobase(store.session(), key, {
81 open,
82 apply: peerGitApply,
83 valueEncoding: 'json',
84 ackInterval: 0,
85 ackThreshold: 0
86 })
87}
88
89async function swarmReplicate (storeA, storeB, topic, testnet) {
90 const { bootstrap } = testnet
91 const swarmA = new Hyperswarm({ bootstrap })
92 const swarmB = new Hyperswarm({ bootstrap })
93 swarmA.on('connection', (conn) => storeA.replicate(conn))
94 swarmB.on('connection', (conn) => storeB.replicate(conn))
95 await swarmA.join(topic, { server: true, client: false }).flushed()
96 swarmB.join(topic, { client: true, server: false })
97 await swarmB.flush()
98 return { swarmA, swarmB }
99}
100
101async function waitForKey (bases, key, maxWait = 10000) {
102 const start = Date.now()
103 while (Date.now() - start < maxWait) {
104 for (const b of bases) await b.update()
105 let allHave = true
106 for (const b of bases) {
107 if (!(await b.view.get(key))) { allHave = false; break }
108 }
109 if (allHave) return true
110 await new Promise(r => setTimeout(r, 300))
111 }
112 return false
113}
114
115// ─────────────────────────────────────────────────────────────
116// Test 1: Reboot persistence — close, reopen, verify multi-writer state
117// ─────────────────────────────────────────────────────────────
118
119test('reboot: multi-writer state persists after close+reopen', async (t) => {
120 t.timeout(30000)
121 const testnet = await createTestnet(3)
122 const dirA = tmpPath('a')
123 const dirB = tmpPath('b')
124
125 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
126 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
127
128 // Setup multi-writer
129 const a = createBase(storeA, null)
130 await a.ready()
131 const bootstrapKey = a.local.key
132
133 const b = createBase(storeB, bootstrapKey)
134 await b.ready()
135
136 const { swarmA, swarmB } = await swarmReplicate(storeA, storeB, a.discoveryKey, testnet)
137
138 await a.append({ type: 'create-issue', id: 1, title: 'from A before writer add', author: 'serverA' })
139 await a.append({ type: 'add-writer', key: b.local.key.toString('hex'), indexer: true })
140
141 await waitForKey([a, b], 'issue:1')
142
143 // Confirm writer set
144 for (let i = 0; i < 3; i++) {
145 if (a.writable) await a.append(null)
146 if (b.writable) await b.append(null)
147 for (const base of [a, b]) await base.update()
148 await new Promise(r => setTimeout(r, 300))
149 }
150
151 t.ok(b.writable, 'B writable before reboot')
152
153 // B writes an issue
154 await b.append({ type: 'create-issue', id: 2, title: 'from B before reboot', author: 'serverB' })
155 await waitForKey([a, b], 'issue:2')
156
157 // Close everything
158 await swarmA.destroy()
159 await swarmB.destroy()
160 await a.close()
161 await b.close()
162 await storeA.close()
163 await storeB.close()
164
165 // Reopen — simulates server reboot
166 const storeA2 = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
167 const storeB2 = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
168
169 const a2 = createBase(storeA2, bootstrapKey)
170 await a2.ready()
171
172 const b2 = createBase(storeB2, bootstrapKey)
173 await b2.ready()
174
175 t.comment('A2 writable: ' + a2.writable + ', members: ' + a2.system.members)
176 t.comment('B2 writable: ' + b2.writable + ', members: ' + b2.system.members)
177
178 // Reconnect
179 const testnet2 = await createTestnet(3)
180 const { swarmA: sw2A, swarmB: sw2B } = await swarmReplicate(storeA2, storeB2, a2.discoveryKey, testnet2)
181
182 await waitForKey([a2, b2], 'issue:2')
183
184 // Verify all data survived reboot
185 const i1a = await a2.view.get('issue:1')
186 const i2a = await a2.view.get('issue:2')
187 const i1b = await b2.view.get('issue:1')
188 const i2b = await b2.view.get('issue:2')
189
190 t.ok(i1a, 'A2 has issue:1')
191 t.ok(i2a, 'A2 has issue:2')
192 t.ok(i1b, 'B2 has issue:1')
193 t.ok(i2b, 'B2 has issue:2')
194 t.is(i1a.value.author, 'serverA')
195 t.is(i2a.value.author, 'serverB')
196
197 // B is still writable after reboot
198 t.ok(b2.writable, 'B2 still writable after reboot')
199
200 // B can still write new issues after reboot
201 await b2.append({ type: 'create-issue', id: 3, title: 'from B after reboot', author: 'serverB' })
202 await waitForKey([a2, b2], 'issue:3')
203
204 const i3a = await a2.view.get('issue:3')
205 t.ok(i3a, 'A2 sees B2 issue written after reboot')
206 t.is(i3a.value.author, 'serverB')
207
208 await sw2A.destroy()
209 await sw2B.destroy()
210 await a2.close()
211 await b2.close()
212 await storeA2.close()
213 await storeB2.close()
214 await testnet.destroy()
215 await testnet2.destroy()
216 await cleanup(dirA, dirB)
217})
218
219// ─────────────────────────────────────────────────────────────
220// Test 2: Concurrent writes — both append before syncing
221// ─────────────────────────────────────────────────────────────
222
223test('concurrent: both writers append simultaneously, linearization converges', async (t) => {
224 t.timeout(30000)
225 const testnet = await createTestnet(3)
226 const dirA = tmpPath('a')
227 const dirB = tmpPath('b')
228
229 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
230 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
231
232 const a = createBase(storeA, null)
233 await a.ready()
234 const b = createBase(storeB, a.local.key)
235 await b.ready()
236
237 // Add B as writer via pipe (fast, reliable setup)
238 const s1 = a.replicate(true)
239 const s2 = b.replicate(false)
240 s1.pipe(s2).pipe(s1)
241
242 await a.append({ type: 'add-writer', key: b.local.key.toString('hex'), indexer: true })
243
244 for (let i = 0; i < 5; i++) {
245 for (const base of [a, b]) await base.update()
246 if (a.writable) await a.append(null)
247 if (b.writable) await b.append(null)
248 await new Promise(r => setTimeout(r, 200))
249 }
250
251 t.ok(b.writable, 'B is writable')
252
253 s1.destroy()
254 s2.destroy()
255 await new Promise(r => setTimeout(r, 500))
256
257 // Both write issues CONCURRENTLY while disconnected
258 for (let i = 1; i <= 5; i++) {
259 await a.append({ type: 'create-issue', id: i, title: 'A-issue-' + i, author: 'A' })
260 }
261 for (let i = 6; i <= 10; i++) {
262 await b.append({ type: 'create-issue', id: i, title: 'B-issue-' + i, author: 'B' })
263 }
264
265 // Reconnect via Hyperswarm
266 const { swarmA, swarmB } = await swarmReplicate(storeA, storeB, a.discoveryKey, testnet)
267
268 // Wait for convergence
269 await waitForKey([a, b], 'issue:10')
270
271 // Verify all 10 issues present on both sides
272 for (let i = 1; i <= 10; i++) {
273 const ia = await a.view.get('issue:' + i)
274 const ib = await b.view.get('issue:' + i)
275 t.ok(ia, 'A has issue:' + i)
276 t.ok(ib, 'B has issue:' + i)
277 }
278
279 t.comment('A members: ' + a.system.members)
280 t.comment('B members: ' + b.system.members)
281
282 await swarmA.destroy()
283 await swarmB.destroy()
284 await a.close()
285 await b.close()
286 await storeA.close()
287 await storeB.close()
288 await testnet.destroy()
289 await cleanup(dirA, dirB)
290})
291
292// ─────────────────────────────────────────────────────────────
293// Test 3: Disconnect + reconnect — offline writes converge
294// ─────────────────────────────────────────────────────────────
295
296test('disconnect: offline writes on both sides converge on reconnect', async (t) => {
297 t.timeout(30000)
298 const testnet = await createTestnet(3)
299 const dirA = tmpPath('a')
300 const dirB = tmpPath('b')
301
302 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
303 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
304
305 const a = createBase(storeA, null)
306 await a.ready()
307 const b = createBase(storeB, a.local.key)
308 await b.ready()
309
310 // Setup multi-writer and initial sync
311 const { swarmA, swarmB } = await swarmReplicate(storeA, storeB, a.discoveryKey, testnet)
312
313 await a.append({ type: 'add-writer', key: b.local.key.toString('hex'), indexer: true })
314 await a.append({ type: 'create-issue', id: 1, title: 'initial sync test', author: 'A' })
315
316 await waitForKey([a, b], 'issue:1')
317
318 // Confirm
319 for (let i = 0; i < 3; i++) {
320 if (a.writable) await a.append(null)
321 if (b.writable) await b.append(null)
322 for (const base of [a, b]) await base.update()
323 await new Promise(r => setTimeout(r, 300))
324 }
325
326 t.ok(b.writable, 'B writable')
327
328 // Disconnect
329 await swarmA.destroy()
330 await swarmB.destroy()
331 await new Promise(r => setTimeout(r, 500))
332
333 // Both write while disconnected
334 await a.append({ type: 'create-issue', id: 2, title: 'A wrote offline', author: 'A' })
335 await a.append({ type: 'create-issue', id: 3, title: 'A also wrote this offline', author: 'A' })
336 await b.append({ type: 'create-issue', id: 4, title: 'B wrote offline', author: 'B' })
337
338 // Reconnect
339 const testnet2 = await createTestnet(3)
340 const { swarmA: sw2A, swarmB: sw2B } = await swarmReplicate(storeA, storeB, a.discoveryKey, testnet2)
341
342 await waitForKey([a, b], 'issue:4')
343
344 // All issues present on both sides
345 for (let i = 1; i <= 4; i++) {
346 const ia = await a.view.get('issue:' + i)
347 const ib = await b.view.get('issue:' + i)
348 t.ok(ia, 'A has issue:' + i)
349 t.ok(ib, 'B has issue:' + i)
350 }
351
352 await sw2A.destroy()
353 await sw2B.destroy()
354 await a.close()
355 await b.close()
356 await storeA.close()
357 await storeB.close()
358 await testnet.destroy()
359 await testnet2.destroy()
360 await cleanup(dirA, dirB)
361})
362
363// ─────────────────────────────────────────────────────────────
364// Test 4: Probe validation blocks bogus key in real apply
365// ─────────────────────────────────────────────────────────────
366
367test('probe validation: bogus key skipped in pear-git apply, real key works', async (t) => {
368 t.timeout(20000)
369 const testnet = await createTestnet(3)
370 const dirA = tmpPath('a')
371 const dirB = tmpPath('b')
372
373 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
374 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
375
376 const a = createBase(storeA, null)
377 await a.ready()
378 const b = createBase(storeB, a.local.key)
379 await b.ready()
380
381 const { swarmA, swarmB } = await swarmReplicate(storeA, storeB, a.discoveryKey, testnet)
382
383 // First: add bogus key (simulates the old bug)
384 const bogusKey = Buffer.alloc(32, 0xde).toString('hex')
385 await a.append({ type: 'add-writer', key: bogusKey, indexer: true })
386
387 // Then: add correct key
388 await a.append({ type: 'add-writer', key: b.local.key.toString('hex'), indexer: true })
389
390 // Issue before and after
391 await a.append({ type: 'create-issue', id: 1, title: 'survives bogus writer', author: 'A' })
392
393 // Sync
394 await waitForKey([a, b], 'issue:1')
395
396 // Confirm
397 for (let i = 0; i < 3; i++) {
398 if (a.writable) await a.append(null)
399 if (b.writable) await b.append(null)
400 for (const base of [a, b]) await base.update()
401 await new Promise(r => setTimeout(r, 300))
402 }
403
404 t.ok(b.writable, 'B writable (correct key worked despite bogus key in log)')
405 t.comment('A members: ' + a.system.members)
406
407 // B can write
408 await b.append({ type: 'create-issue', id: 2, title: 'B writes after bogus+correct', author: 'B' })
409 await waitForKey([a, b], 'issue:2')
410
411 const i2 = await a.view.get('issue:2')
412 t.ok(i2, 'A sees B issue written after bogus key was skipped')
413
414 await swarmA.destroy()
415 await swarmB.destroy()
416 await a.close()
417 await b.close()
418 await storeA.close()
419 await storeB.close()
420 await testnet.destroy()
421 await cleanup(dirA, dirB)
422})
test/multi-writer-hyperswarm.js +391 -0
……@@ -0,0 +1,391 @@
1#!/usr/bin/env bare
2
3/**
4 * Integration test: two-way Autobase multi-writer over Hyperswarm.
5 *
6 * Proves the correct flow for federation issue sync:
7 * 1. Server A creates an Autobase, writes issues
8 * 2. Server B adopts the same Autobase (same bootstrap key)
9 * 3. Both connect via Hyperswarm testnet and replicate
10 * 4. Server A adds Server B as a writer using B's base.local.key
11 * 5. Server B writes issues
12 * 6. Both servers see all issues from both writers
13 *
14 * This is the pattern pear-git needs for LinkedRepo federation.
15 */
16
17import test from 'brittle'
18import Corestore from 'corestore'
19import Autobase from 'autobase'
20import Hyperbee from 'hyperbee'
21import Hyperswarm from 'hyperswarm'
22import createTestnet from '@hyperswarm/testnet'
23import os from 'bare-os'
24import path from 'bare-path'
25import fs from 'bare-fs'
26
27const tmpdir = os.tmpdir()
28let idx = 0
29
30function tmpPath (name) {
31 return path.join(tmpdir, 'ab-mw-' + name + '-' + (idx++) + '-' + Date.now())
32}
33
34async function cleanup (...dirs) {
35 for (const d of dirs) await fs.promises.rm(d, { recursive: true }).catch(() => {})
36}
37
38function open (store) {
39 return new Hyperbee(store.get('view', { valueEncoding: 'json' }), {
40 keyEncoding: 'utf-8',
41 valueEncoding: 'json'
42 })
43}
44
45async function apply (batch, view, host) {
46 const b = view.batch()
47 for (const node of batch) {
48 const op = node.value
49 if (op.type === 'put') {
50 await b.put(op.key, op.value)
51 }
52 if (op.type === 'add-writer') {
53 await host.addWriter(Buffer.from(op.key, 'hex'), {
54 indexer: op.indexer !== false
55 })
56 }
57 }
58 await b.flush()
59}
60
61function createBase (store, key) {
62 return new Autobase(store.session(), key, {
63 open,
64 apply,
65 valueEncoding: 'json',
66 ackInterval: 0,
67 ackThreshold: 0
68 })
69}
70
71async function swarmReplicate (storeA, storeB, topic, testnet) {
72 const { bootstrap } = testnet
73 const swarmA = new Hyperswarm({ bootstrap })
74 const swarmB = new Hyperswarm({ bootstrap })
75
76 swarmA.on('connection', (conn) => storeA.replicate(conn))
77 swarmB.on('connection', (conn) => storeB.replicate(conn))
78
79 await swarmA.join(topic, { server: true, client: false }).flushed()
80 swarmB.join(topic, { client: true, server: false })
81
82 await swarmB.flush()
83
84 return { swarmA, swarmB }
85}
86
87async function waitForSync (bases, checkKey, maxWait = 10000) {
88 const start = Date.now()
89 while (Date.now() - start < maxWait) {
90 for (const b of bases) await b.update()
91 if (checkKey) {
92 let allHave = true
93 for (const b of bases) {
94 const entry = await b.view.get(checkKey)
95 if (!entry) { allHave = false; break }
96 }
97 if (allHave) return true
98 }
99 await new Promise(r => setTimeout(r, 300))
100 }
101 return false
102}
103
104// ─────────────────────────────────────────────────────────────
105// Test 1: One-way replication over Hyperswarm (adoption only)
106// ─────────────────────────────────────────────────────────────
107
108test('one-way: server B reads server A issues via Hyperswarm', async (t) => {
109 t.timeout(30000)
110 const testnet = await createTestnet(3)
111 const dirA = tmpPath('a')
112 const dirB = tmpPath('b')
113
114 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
115 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
116
117 // Server A creates Autobase and writes issues
118 const baseA = createBase(storeA, null)
119 await baseA.ready()
120 const bootstrapKey = baseA.local.key
121
122 await baseA.append({ type: 'put', key: 'issue:1', value: { title: 'first issue' } })
123 await baseA.append({ type: 'put', key: 'issue:2', value: { title: 'second issue' } })
124 await baseA.update()
125
126 const check1 = await baseA.view.get('issue:1')
127 t.ok(check1, 'A has issue:1')
128
129 // Server B adopts with same bootstrap key (like _adoptIssueAutobase)
130 const baseB = createBase(storeB, bootstrapKey)
131 await baseB.ready()
132
133 // Connect via Hyperswarm
134 const { swarmA, swarmB } = await swarmReplicate(storeA, storeB, baseA.discoveryKey, testnet)
135
136 // Wait for B to sync A's data
137 await waitForSync([baseA, baseB], 'issue:2')
138
139 const e1 = await baseB.view.get('issue:1')
140 const e2 = await baseB.view.get('issue:2')
141 t.ok(e1, 'B sees issue:1')
142 t.ok(e2, 'B sees issue:2')
143 t.is(e1.value.title, 'first issue')
144 t.is(e2.value.title, 'second issue')
145
146 // B is NOT writable (not added as writer)
147 t.is(baseB.writable, false, 'B is read-only')
148
149 await swarmA.destroy()
150 await swarmB.destroy()
151 await baseA.close()
152 await baseB.close()
153 await storeA.close()
154 await storeB.close()
155 await testnet.destroy()
156 await cleanup(dirA, dirB)
157})
158
159// ─────────────────────────────────────────────────────────────
160// Test 2: Two-way multi-writer over Hyperswarm
161// ─────────────────────────────────────────────────────────────
162
163test('two-way: A adds B as writer, both write issues via Hyperswarm', async (t) => {
164 t.timeout(30000)
165 const testnet = await createTestnet(3)
166 const dirA = tmpPath('a')
167 const dirB = tmpPath('b')
168
169 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
170 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
171
172 // Server A creates Autobase
173 const baseA = createBase(storeA, null)
174 await baseA.ready()
175 const bootstrapKey = baseA.local.key
176
177 // Server B adopts
178 const baseB = createBase(storeB, bootstrapKey)
179 await baseB.ready()
180
181 t.comment('A local key: ' + baseA.local.key.toString('hex').slice(0, 16))
182 t.comment('B local key: ' + baseB.local.key.toString('hex').slice(0, 16))
183
184 // Connect via Hyperswarm
185 const { swarmA, swarmB } = await swarmReplicate(storeA, storeB, baseA.discoveryKey, testnet)
186
187 // Wait for initial connection
188 await new Promise(r => setTimeout(r, 2000))
189
190 // A writes initial issue
191 await baseA.append({ type: 'put', key: 'issue:1', value: { title: 'from server A' } })
192
193 // A adds B as a writer — using B's ACTUAL local core key
194 // This is the critical part: must be base.local.key, not a server identity key
195 await baseA.append({
196 type: 'add-writer',
197 key: baseB.local.key.toString('hex'),
198 indexer: true
199 })
200
201 // Sync so B gets the add-writer op
202 await waitForSync([baseA, baseB], 'issue:1')
203
204 // Ack from both sides to confirm the writer set
205 if (baseA.writable) await baseA.append(null)
206 await new Promise(r => setTimeout(r, 1000))
207 for (const b of [baseA, baseB]) await b.update()
208
209 if (baseB.writable) await baseB.append(null)
210 await new Promise(r => setTimeout(r, 1000))
211 for (const b of [baseA, baseB]) await b.update()
212
213 t.comment('B writable after add-writer: ' + baseB.writable)
214 t.comment('A members: ' + baseA.system.members)
215 t.comment('B members: ' + baseB.system.members)
216
217 t.ok(baseB.writable, 'B is writable after being added')
218 t.is(baseA.system.members, 2, 'A sees 2 members')
219
220 // Now B writes an issue
221 if (baseB.writable) {
222 await baseB.append({ type: 'put', key: 'issue:2', value: { title: 'from server B' } })
223 }
224
225 // Sync again
226 await waitForSync([baseA, baseB], 'issue:2')
227
228 // Both should see both issues
229 const a1 = await baseA.view.get('issue:1')
230 const a2 = await baseA.view.get('issue:2')
231 const b1 = await baseB.view.get('issue:1')
232 const b2 = await baseB.view.get('issue:2')
233
234 t.ok(a1, 'A sees issue:1')
235 t.ok(b1, 'B sees issue:1')
236 t.is(a1.value.title, 'from server A')
237 t.is(b1.value.title, 'from server A')
238
239 if (baseB.writable) {
240 t.ok(a2, 'A sees issue:2 from B')
241 t.ok(b2, 'B sees issue:2 from B')
242 t.is(a2.value.title, 'from server B')
243 t.is(b2.value.title, 'from server B')
244 }
245
246 await swarmA.destroy()
247 await swarmB.destroy()
248 await baseA.close()
249 await baseB.close()
250 await storeA.close()
251 await storeB.close()
252 await testnet.destroy()
253 await cleanup(dirA, dirB)
254})
255
256// ─────────────────────────────────────────────────────────────
257// Test 3: Wrong key type causes writable=false (the bug we hit)
258// ─────────────────────────────────────────────────────────────
259
260test('wrong key: using identity key instead of local.key fails gracefully', async (t) => {
261 t.timeout(30000)
262 const testnet = await createTestnet(3)
263 const dirA = tmpPath('a')
264 const dirB = tmpPath('b')
265
266 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
267 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
268
269 const baseA = createBase(storeA, null)
270 await baseA.ready()
271 const bootstrapKey = baseA.local.key
272
273 const baseB = createBase(storeB, bootstrapKey)
274 await baseB.ready()
275
276 const { swarmA, swarmB } = await swarmReplicate(storeA, storeB, baseA.discoveryKey, testnet)
277 await new Promise(r => setTimeout(r, 2000))
278
279 // Simulate the bug: use a random key (like an Ed25519 identity key)
280 // instead of baseB.local.key
281 const fakeIdentityKey = Buffer.alloc(32, 0xf5).toString('hex')
282 t.comment('fake key: ' + fakeIdentityKey.slice(0, 16))
283 t.comment('correct key would be: ' + baseB.local.key.toString('hex').slice(0, 16))
284
285 await baseA.append({
286 type: 'add-writer',
287 key: fakeIdentityKey,
288 indexer: true
289 })
290
291 // Sync
292 for (let i = 0; i < 10; i++) {
293 for (const b of [baseA, baseB]) await b.update()
294 await new Promise(r => setTimeout(r, 300))
295 }
296
297 // B should still NOT be writable — wrong key was used
298 t.is(baseB.writable, false, 'B is NOT writable (wrong key used)')
299
300 // A should still have member count reflecting the bogus key
301 t.comment('A members: ' + baseA.system.members + ' (includes bogus)')
302
303 await swarmA.destroy()
304 await swarmB.destroy()
305 await baseA.close()
306 await baseB.close()
307 await storeA.close()
308 await storeB.close()
309 await testnet.destroy()
310 await cleanup(dirA, dirB)
311})
312
313// ─────────────────────────────────────────────────────────────
314// Test 4: Correct key vs wrong key — side by side
315// ─────────────────────────────────────────────────────────────
316
317test('correct key = writable, wrong key = not writable', async (t) => {
318 t.timeout(15000)
319
320 // Correct: use base.local.key
321 const dirA = tmpPath('a')
322 const dirB = tmpPath('b')
323 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
324 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
325
326 const a = createBase(storeA, null)
327 await a.ready()
328 const b = createBase(storeB, a.local.key)
329 await b.ready()
330
331 // Add B with correct key
332 await a.append({ type: 'add-writer', key: b.local.key.toString('hex'), indexer: true })
333
334 // Pipe replicate (fast, no swarm needed for this test)
335 const s1 = a.replicate(true)
336 const s2 = b.replicate(false)
337 s1.pipe(s2).pipe(s1)
338
339 // Confirm
340 for (let i = 0; i < 3; i++) {
341 for (const base of [a, b]) await base.update()
342 if (a.writable) await a.append(null)
343 if (b.writable) await b.append(null)
344 await new Promise(r => setTimeout(r, 200))
345 for (const base of [a, b]) await base.update()
346 }
347
348 t.ok(b.writable, 'correct key → writable')
349 t.is(a.system.members, 2, '2 members')
350
351 s1.destroy()
352 s2.destroy()
353 await a.close()
354 await b.close()
355 await storeA.close()
356 await storeB.close()
357
358 // Wrong: use random key
359 const dirC = tmpPath('c')
360 const dirD = tmpPath('d')
361 const storeC = new Corestore(dirC, { primaryKey: Buffer.alloc(32, 2), unsafe: true })
362 const storeD = new Corestore(dirD, { primaryKey: Buffer.alloc(32, 3), unsafe: true })
363
364 const c = createBase(storeC, null)
365 await c.ready()
366 const d = createBase(storeD, c.local.key)
367 await d.ready()
368
369 // Add D with WRONG key
370 const wrongKey = Buffer.alloc(32, 0xab).toString('hex')
371 await c.append({ type: 'add-writer', key: wrongKey, indexer: true })
372
373 const s3 = c.replicate(true)
374 const s4 = d.replicate(false)
375 s3.pipe(s4).pipe(s3)
376
377 for (let i = 0; i < 3; i++) {
378 for (const base of [c, d]) await base.update()
379 await new Promise(r => setTimeout(r, 200))
380 }
381
382 t.is(d.writable, false, 'wrong key → NOT writable')
383
384 s3.destroy()
385 s4.destroy()
386 await c.close()
387 await d.close()
388 await storeC.close()
389 await storeD.close()
390 await cleanup(dirA, dirB, dirC, dirD)
391})
test/poison-replication.js +242 -0
……@@ -0,0 +1,242 @@
1#!/usr/bin/env bare
2
3/**
4 * Integration test: reproduce Autobase corruption from poisoned addWriter
5 * and verify the drain loop patch prevents infinite hang.
6 *
7 * Uses autobase-test-helpers for replication (same as upstream tests).
8 */
9
10import test from 'brittle'
11import Corestore from 'corestore'
12import Autobase from 'autobase'
13import Hyperbee from 'hyperbee'
14import crypto from 'hypercore-crypto'
15import os from 'bare-os'
16import path from 'bare-path'
17import fs from 'bare-fs'
18import { replicate, replicateAndSync } from 'autobase-test-helpers'
19
20const tmpdir = os.tmpdir()
21let idx = 0
22
23function tmpPath (name) {
24 return path.join(tmpdir, 'ab-poison-' + name + '-' + (idx++) + '-' + Date.now())
25}
26
27function open (store) {
28 return new Hyperbee(store.get('view', { valueEncoding: 'json' }), {
29 keyEncoding: 'utf-8',
30 valueEncoding: 'json'
31 })
32}
33
34async function cleanup (...dirs) {
35 for (const d of dirs) await fs.promises.rm(d, { recursive: true }).catch(() => {})
36}
37
38// Apply that validates before calling host.addWriter (our fix)
39async function safeApply (nodes, view, host) {
40 const batch = view.batch()
41 for (const node of nodes) {
42 const op = node.value
43 if (op.type === 'put') {
44 await batch.put(op.key, op.value)
45 }
46 if (op.type === 'add-writer' && op.writerKey) {
47 const writerKey = Buffer.from(op.writerKey, 'hex')
48 try {
49 const probe = host.base.store.get({ key: writerKey, active: false })
50 await probe.ready()
51 const valid = probe.manifest !== null || probe.length > 0
52 await probe.close()
53 if (valid) {
54 await host.addWriter(writerKey, { indexer: false })
55 }
56 } catch {}
57 }
58 }
59 await batch.flush()
60}
61
62// Apply that blindly calls host.addWriter (the old broken behavior)
63async function unsafeApply (nodes, view, host) {
64 const batch = view.batch()
65 for (const node of nodes) {
66 const op = node.value
67 if (op.type === 'put') {
68 await batch.put(op.key, op.value)
69 }
70 if (op.type === 'add-writer' && op.writerKey) {
71 await host.addWriter(Buffer.from(op.writerKey, 'hex'), { indexer: false })
72 }
73 }
74 await batch.flush()
75}
76
77function createBase (store, key, apply) {
78 return new Autobase(store.session(), key, {
79 open,
80 apply,
81 valueEncoding: 'json',
82 ackInterval: 0,
83 ackThreshold: 0,
84 fastForward: false
85 })
86}
87
88// ─────────────────────────────────────────────────────────────
89
90test('baseline: two peers replicate and sync', async (t) => {
91 t.timeout(15000)
92 const dirA = tmpPath('a')
93 const dirB = tmpPath('b')
94
95 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
96 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
97
98 const a = createBase(storeA, null, safeApply)
99 await a.ready()
100
101 const b = createBase(storeB, a.local.key, safeApply)
102 await b.ready()
103
104 await a.append({ type: 'put', key: 'msg:1', value: { text: 'hello' } })
105
106 await replicateAndSync([a, b])
107
108 const entry = await b.view.get('msg:1')
109 t.ok(entry, 'replicated')
110 t.is(entry.value.text, 'hello')
111
112 await a.close()
113 await b.close()
114 await storeA.close()
115 await storeB.close()
116 await cleanup(dirA, dirB)
117})
118
119// ─────────────────────────────────────────────────────────────
120
121test('safe apply: poisoned add-writer does not hang on replication', async (t) => {
122 t.timeout(15000)
123 const dirA = tmpPath('a')
124 const dirB = tmpPath('b')
125
126 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
127 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
128
129 const a = createBase(storeA, null, safeApply)
130 await a.ready()
131
132 const b = createBase(storeB, a.local.key, safeApply)
133 await b.ready()
134
135 // Write data + poisoned add-writer + more data
136 await a.append({ type: 'put', key: 'msg:1', value: { text: 'before' } })
137 const bogusKey = crypto.randomBytes(32).toString('hex')
138 await a.append({ type: 'add-writer', writerKey: bogusKey })
139 await a.append({ type: 'put', key: 'msg:2', value: { text: 'after' } })
140
141 await replicateAndSync([a, b])
142
143 const e1 = await b.view.get('msg:1')
144 const e2 = await b.view.get('msg:2')
145 t.ok(e1, 'msg:1 replicated')
146 t.ok(e2, 'msg:2 replicated past poison')
147 t.is(e1.value.text, 'before')
148 t.is(e2.value.text, 'after')
149
150 await a.close()
151 await b.close()
152 await storeA.close()
153 await storeB.close()
154 await cleanup(dirA, dirB)
155})
156
157// ─────────────────────────────────────────────────────────────
158
159test('unsafe apply: poisoned add-writer — reopen must not hang', async (t) => {
160 t.timeout(15000)
161 const dirA = tmpPath('a')
162
163 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
164 const a = createBase(storeA, null, unsafeApply)
165 await a.ready()
166 const key = a.local.key
167
168 // Poison it
169 await a.append({ type: 'put', key: 'msg:1', value: { text: 'before' } })
170 const bogusKey = crypto.randomBytes(32).toString('hex')
171 await a.append({ type: 'add-writer', writerKey: bogusKey })
172 await a.update()
173
174 await a.close()
175 await storeA.close()
176
177 // Reopen — this is where the drain loop used to hang
178 const storeA2 = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
179 const a2 = createBase(storeA2, key, unsafeApply)
180 await a2.ready()
181
182 t.comment('writable: ' + a2.writable)
183
184 const timer = setTimeout(() => {
185 t.fail('update() hung for 10 seconds')
186 t.end()
187 }, 10000)
188
189 await a2.update()
190 clearTimeout(timer)
191 t.pass('update() did not hang on reopen')
192
193 await a2.close()
194 await storeA2.close()
195 await cleanup(dirA)
196})
197
198// ─────────────────────────────────────────────────────────────
199
200test('unsafe apply: poisoned writer replicated to peer — peer must not hang', async (t) => {
201 t.timeout(15000)
202 const dirA = tmpPath('a')
203 const dirB = tmpPath('b')
204
205 const storeA = new Corestore(dirA, { primaryKey: Buffer.alloc(32, 0), unsafe: true })
206 const storeB = new Corestore(dirB, { primaryKey: Buffer.alloc(32, 1), unsafe: true })
207
208 const a = createBase(storeA, null, unsafeApply)
209 await a.ready()
210
211 const b = createBase(storeB, a.local.key, unsafeApply)
212 await b.ready()
213
214 // Write data + poison
215 await a.append({ type: 'put', key: 'msg:1', value: { text: 'hello' } })
216 const bogusKey = crypto.randomBytes(32).toString('hex')
217 await a.append({ type: 'add-writer', writerKey: bogusKey })
218
219 // Replicate — peer B receives the poison
220 const done = replicate([a, b])
221
222 const timer = setTimeout(() => {
223 t.fail('sync hung for 10 seconds')
224 t.end()
225 }, 10000)
226
227 // Try to update B — should not hang with the drain loop patch
228 for (let i = 0; i < 5; i++) {
229 await b.update()
230 await new Promise(r => setTimeout(r, 200))
231 }
232
233 clearTimeout(timer)
234 t.pass('peer B update() did not hang despite receiving poisoned writer')
235
236 await done()
237 await a.close()
238 await b.close()
239 await storeA.close()
240 await storeB.close()
241 await cleanup(dirA, dirB)
242})