monkeypatchlist 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +61 -0
  3. package/README.md +183 -2
  4. package/catalog/catalog.json +552211 -0
  5. package/catalog/catalog.schema.json +787 -0
  6. package/catalog/changelog.json +3 -0
  7. package/dist/bin/monkeypatchlist.d.ts +2 -0
  8. package/dist/bin/monkeypatchlist.js +3 -0
  9. package/dist/catalog.d.ts +561 -0
  10. package/dist/catalog.js +58 -0
  11. package/dist/cli.d.ts +84 -0
  12. package/dist/cli.js +470 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +1 -0
  15. package/dist/lockfile-input.d.ts +9 -0
  16. package/dist/lockfile-input.js +91 -0
  17. package/dist/packages/analysis/binding.d.ts +2 -0
  18. package/dist/packages/analysis/binding.js +5 -0
  19. package/dist/packages/analysis/index.d.ts +10 -0
  20. package/dist/packages/analysis/index.js +13 -0
  21. package/dist/packages/analysis/job.d.ts +33 -0
  22. package/dist/packages/analysis/job.js +85 -0
  23. package/dist/packages/analysis/lib/absence-tags.d.ts +34 -0
  24. package/dist/packages/analysis/lib/absence-tags.js +340 -0
  25. package/dist/packages/analysis/lib/ast.d.ts +28 -0
  26. package/dist/packages/analysis/lib/ast.js +64 -0
  27. package/dist/packages/analysis/lib/binding.d.ts +36 -0
  28. package/dist/packages/analysis/lib/binding.js +66 -0
  29. package/dist/packages/analysis/lib/budget.d.ts +80 -0
  30. package/dist/packages/analysis/lib/budget.js +31 -0
  31. package/dist/packages/analysis/lib/catch-arms.d.ts +19 -0
  32. package/dist/packages/analysis/lib/catch-arms.js +351 -0
  33. package/dist/packages/analysis/lib/chunk-loads.d.ts +160 -0
  34. package/dist/packages/analysis/lib/chunk-loads.js +882 -0
  35. package/dist/packages/analysis/lib/chunk-registry.d.ts +45 -0
  36. package/dist/packages/analysis/lib/chunk-registry.js +334 -0
  37. package/dist/packages/analysis/lib/code-routes.d.ts +52 -0
  38. package/dist/packages/analysis/lib/code-routes.js +921 -0
  39. package/dist/packages/analysis/lib/collisions.d.ts +22 -0
  40. package/dist/packages/analysis/lib/collisions.js +103 -0
  41. package/dist/packages/analysis/lib/definitions.d.ts +76 -0
  42. package/dist/packages/analysis/lib/definitions.js +782 -0
  43. package/dist/packages/analysis/lib/early-exits.d.ts +39 -0
  44. package/dist/packages/analysis/lib/early-exits.js +161 -0
  45. package/dist/packages/analysis/lib/effect.d.ts +138 -0
  46. package/dist/packages/analysis/lib/effect.js +800 -0
  47. package/dist/packages/analysis/lib/global-object.d.ts +581 -0
  48. package/dist/packages/analysis/lib/global-object.js +8240 -0
  49. package/dist/packages/analysis/lib/keys.d.ts +33 -0
  50. package/dist/packages/analysis/lib/keys.js +82 -0
  51. package/dist/packages/analysis/lib/line-starts.d.ts +41 -0
  52. package/dist/packages/analysis/lib/line-starts.js +79 -0
  53. package/dist/packages/analysis/lib/link-group.d.ts +51 -0
  54. package/dist/packages/analysis/lib/link-group.js +487 -0
  55. package/dist/packages/analysis/lib/module-links.d.ts +117 -0
  56. package/dist/packages/analysis/lib/module-links.js +1060 -0
  57. package/dist/packages/analysis/lib/nested-code.d.ts +38 -0
  58. package/dist/packages/analysis/lib/nested-code.js +200 -0
  59. package/dist/packages/analysis/lib/numeric.d.ts +16 -0
  60. package/dist/packages/analysis/lib/numeric.js +216 -0
  61. package/dist/packages/analysis/lib/once-flags.d.ts +12 -0
  62. package/dist/packages/analysis/lib/once-flags.js +190 -0
  63. package/dist/packages/analysis/lib/parameter-arguments.d.ts +12 -0
  64. package/dist/packages/analysis/lib/parameter-arguments.js +34 -0
  65. package/dist/packages/analysis/lib/parse.d.ts +10 -0
  66. package/dist/packages/analysis/lib/parse.js +39 -0
  67. package/dist/packages/analysis/lib/partial.d.ts +60 -0
  68. package/dist/packages/analysis/lib/partial.js +518 -0
  69. package/dist/packages/analysis/lib/print.d.ts +3 -0
  70. package/dist/packages/analysis/lib/print.js +150 -0
  71. package/dist/packages/analysis/lib/reachability.d.ts +137 -0
  72. package/dist/packages/analysis/lib/reachability.js +1295 -0
  73. package/dist/packages/analysis/lib/resolver.d.ts +13 -0
  74. package/dist/packages/analysis/lib/resolver.js +2886 -0
  75. package/dist/packages/analysis/lib/restores.d.ts +42 -0
  76. package/dist/packages/analysis/lib/restores.js +482 -0
  77. package/dist/packages/analysis/lib/rewritten-deletes.d.ts +6 -0
  78. package/dist/packages/analysis/lib/rewritten-deletes.js +142 -0
  79. package/dist/packages/analysis/lib/scope.d.ts +110 -0
  80. package/dist/packages/analysis/lib/scope.js +443 -0
  81. package/dist/packages/analysis/lib/script-loads.d.ts +56 -0
  82. package/dist/packages/analysis/lib/script-loads.js +359 -0
  83. package/dist/packages/analysis/lib/summaries.d.ts +177 -0
  84. package/dist/packages/analysis/lib/summaries.js +498 -0
  85. package/dist/packages/analysis/lib/types.d.ts +632 -0
  86. package/dist/packages/analysis/lib/types.js +128 -0
  87. package/dist/packages/analysis/lib/wrap.d.ts +34 -0
  88. package/dist/packages/analysis/lib/wrap.js +407 -0
  89. package/dist/packages/analysis/lib/writes.d.ts +358 -0
  90. package/dist/packages/analysis/lib/writes.js +1612 -0
  91. package/dist/packages/analysis/visit-order.d.ts +3 -0
  92. package/dist/packages/analysis/visit-order.js +23 -0
  93. package/dist/packages/attribution/index.d.ts +233 -0
  94. package/dist/packages/attribution/index.js +444 -0
  95. package/dist/packages/attribution/lib/containing-package.d.ts +76 -0
  96. package/dist/packages/attribution/lib/containing-package.js +304 -0
  97. package/dist/packages/attribution/lib/first-party.d.ts +37 -0
  98. package/dist/packages/attribution/lib/first-party.js +153 -0
  99. package/dist/packages/attribution/lib/lockfile-graph.d.ts +99 -0
  100. package/dist/packages/attribution/lib/lockfile-graph.js +158 -0
  101. package/dist/packages/attribution/lib/lockfile.d.ts +33 -0
  102. package/dist/packages/attribution/lib/lockfile.js +330 -0
  103. package/dist/packages/attribution/lib/path-rules.d.ts +29 -0
  104. package/dist/packages/attribution/lib/path-rules.js +84 -0
  105. package/dist/packages/attribution/lib/pnpm.d.ts +4 -0
  106. package/dist/packages/attribution/lib/pnpm.js +133 -0
  107. package/dist/packages/attribution/lib/remote-url.d.ts +7 -0
  108. package/dist/packages/attribution/lib/remote-url.js +24 -0
  109. package/dist/packages/attribution/lib/source-map.d.ts +51 -0
  110. package/dist/packages/attribution/lib/source-map.js +125 -0
  111. package/dist/packages/attribution/lib/yaml.d.ts +9 -0
  112. package/dist/packages/attribution/lib/yaml.js +277 -0
  113. package/dist/packages/attribution/lib/yarn.d.ts +7 -0
  114. package/dist/packages/attribution/lib/yarn.js +227 -0
  115. package/dist/packages/baseline/index.d.ts +45 -0
  116. package/dist/packages/baseline/index.js +41 -0
  117. package/dist/packages/baseline/lib/error.d.ts +15 -0
  118. package/dist/packages/baseline/lib/error.js +25 -0
  119. package/dist/packages/baseline/lib/format.d.ts +49 -0
  120. package/dist/packages/baseline/lib/format.js +22 -0
  121. package/dist/packages/baseline/lib/migrations.d.ts +19 -0
  122. package/dist/packages/baseline/lib/migrations.js +7 -0
  123. package/dist/packages/baseline/lib/previous.d.ts +23 -0
  124. package/dist/packages/baseline/lib/previous.js +64 -0
  125. package/dist/packages/baseline/lib/read.d.ts +39 -0
  126. package/dist/packages/baseline/lib/read.js +219 -0
  127. package/dist/packages/baseline/lib/report.d.ts +25 -0
  128. package/dist/packages/baseline/lib/report.js +104 -0
  129. package/dist/packages/baseline/lib/skew.d.ts +51 -0
  130. package/dist/packages/baseline/lib/skew.js +75 -0
  131. package/dist/packages/compare/index.d.ts +120 -0
  132. package/dist/packages/compare/index.js +274 -0
  133. package/dist/packages/compare/lib/catalog-notes.d.ts +73 -0
  134. package/dist/packages/compare/lib/catalog-notes.js +224 -0
  135. package/dist/packages/completeness/index.d.ts +246 -0
  136. package/dist/packages/completeness/index.js +249 -0
  137. package/dist/packages/confidence/index.d.ts +54 -0
  138. package/dist/packages/confidence/index.js +71 -0
  139. package/dist/packages/config/index.d.ts +107 -0
  140. package/dist/packages/config/index.js +95 -0
  141. package/dist/packages/config/lib/command-line.d.ts +23 -0
  142. package/dist/packages/config/lib/command-line.js +239 -0
  143. package/dist/packages/config/lib/config-file.d.ts +11 -0
  144. package/dist/packages/config/lib/config-file.js +119 -0
  145. package/dist/packages/config/lib/scan-config-id.d.ts +28 -0
  146. package/dist/packages/config/lib/scan-config-id.js +54 -0
  147. package/dist/packages/config/lib/schema.d.ts +2 -0
  148. package/dist/packages/config/lib/schema.js +31 -0
  149. package/dist/packages/config/lib/types.d.ts +64 -0
  150. package/dist/packages/config/lib/types.js +6 -0
  151. package/dist/packages/config/lib/urls.d.ts +6 -0
  152. package/dist/packages/config/lib/urls.js +9 -0
  153. package/dist/packages/discovery/index.d.ts +277 -0
  154. package/dist/packages/discovery/index.js +1950 -0
  155. package/dist/packages/discovery/lib/import-map.d.ts +68 -0
  156. package/dist/packages/discovery/lib/import-map.js +180 -0
  157. package/dist/packages/discovery/lib/requests.d.ts +58 -0
  158. package/dist/packages/discovery/lib/requests.js +591 -0
  159. package/dist/packages/discovery/lib/scopes.d.ts +6 -0
  160. package/dist/packages/discovery/lib/scopes.js +286 -0
  161. package/dist/packages/discovery/lib/source-maps.d.ts +56 -0
  162. package/dist/packages/discovery/lib/source-maps.js +209 -0
  163. package/dist/packages/discovery/lib/swept-code.d.ts +27 -0
  164. package/dist/packages/discovery/lib/swept-code.js +107 -0
  165. package/dist/packages/discovery/lib/syntax.d.ts +17 -0
  166. package/dist/packages/discovery/lib/syntax.js +39 -0
  167. package/dist/packages/findings/index.d.ts +106 -0
  168. package/dist/packages/findings/index.js +254 -0
  169. package/dist/packages/findings/lib/scope.d.ts +38 -0
  170. package/dist/packages/findings/lib/scope.js +110 -0
  171. package/dist/packages/parallel/index.d.ts +2 -0
  172. package/dist/packages/parallel/index.js +5 -0
  173. package/dist/packages/parallel/lib/protocol.d.ts +15 -0
  174. package/dist/packages/parallel/lib/protocol.js +2 -0
  175. package/dist/packages/parallel/lib/runner.d.ts +36 -0
  176. package/dist/packages/parallel/lib/runner.js +96 -0
  177. package/dist/packages/parallel/lib/schedule.d.ts +16 -0
  178. package/dist/packages/parallel/lib/schedule.js +52 -0
  179. package/dist/packages/parallel/lib/worker.d.ts +1 -0
  180. package/dist/packages/parallel/lib/worker.js +18 -0
  181. package/dist/packages/policy/index.d.ts +36 -0
  182. package/dist/packages/policy/index.js +22 -0
  183. package/dist/packages/report/explain.d.ts +26 -0
  184. package/dist/packages/report/explain.js +99 -0
  185. package/dist/packages/report/index.d.ts +210 -0
  186. package/dist/packages/report/index.js +388 -0
  187. package/dist/packages/report/terminal.d.ts +11 -0
  188. package/dist/packages/report/terminal.js +331 -0
  189. package/dist/packages/source-store/fixture.d.ts +22 -0
  190. package/dist/packages/source-store/fixture.js +58 -0
  191. package/dist/packages/source-store/index.d.ts +278 -0
  192. package/dist/packages/source-store/index.js +322 -0
  193. package/dist/packages/source-store/lib/addresses.d.ts +6 -0
  194. package/dist/packages/source-store/lib/addresses.js +91 -0
  195. package/dist/packages/source-store/lib/connection.d.ts +15 -0
  196. package/dist/packages/source-store/lib/connection.js +135 -0
  197. package/dist/packages/source-store/lib/content-types.d.ts +16 -0
  198. package/dist/packages/source-store/lib/content-types.js +75 -0
  199. package/dist/packages/source-store/lib/data-urls.d.ts +10 -0
  200. package/dist/packages/source-store/lib/data-urls.js +85 -0
  201. package/dist/packages/source-store/lib/deadline.d.ts +18 -0
  202. package/dist/packages/source-store/lib/deadline.js +44 -0
  203. package/dist/packages/source-store/lib/exchange.d.ts +29 -0
  204. package/dist/packages/source-store/lib/exchange.js +112 -0
  205. package/dist/packages/source-store/lib/integrity.d.ts +19 -0
  206. package/dist/packages/source-store/lib/integrity.js +86 -0
  207. package/dist/packages/source-store/lib/outcomes.d.ts +12 -0
  208. package/dist/packages/source-store/lib/outcomes.js +22 -0
  209. package/dist/packages/source-store/lib/proxy.d.ts +11 -0
  210. package/dist/packages/source-store/lib/proxy.js +53 -0
  211. package/dist/packages/source-store/lib/session.d.ts +12 -0
  212. package/dist/packages/source-store/lib/session.js +139 -0
  213. package/dist/packages/source-store/lib/urls.d.ts +6 -0
  214. package/dist/packages/source-store/lib/urls.js +15 -0
  215. package/dist/packages/source-store/resolve.d.ts +59 -0
  216. package/dist/packages/source-store/resolve.js +45 -0
  217. package/dist/scan.d.ts +65 -0
  218. package/dist/scan.js +592 -0
  219. package/package.json +95 -4
  220. package/schema/config.schema.json +133 -0
  221. package/schema/report.schema.json +1905 -0
@@ -0,0 +1,91 @@
1
+ // The addresses the safety floor refuses to connect to (§17 Safety floor: Addresses).
2
+ import { isIPv4, isIPv6 } from 'node:net';
3
+ /** Refused IPv4 ranges. A single cloud-metadata address comes before the range that holds it, so that it is named. */
4
+ const refused4 = [
5
+ [ipv4('169.254.169.254'), 32, 'cloud-metadata'],
6
+ [ipv4('100.100.100.200'), 32, 'cloud-metadata'],
7
+ [ipv4('168.63.129.16'), 32, 'cloud-metadata'],
8
+ [ipv4('192.0.0.192'), 32, 'cloud-metadata'],
9
+ [ipv4('0.0.0.0'), 8, 'unspecified'],
10
+ [ipv4('127.0.0.0'), 8, 'loopback'],
11
+ [ipv4('10.0.0.0'), 8, 'private'],
12
+ [ipv4('172.16.0.0'), 12, 'private'],
13
+ [ipv4('192.168.0.0'), 16, 'private'],
14
+ [ipv4('169.254.0.0'), 16, 'link-local'],
15
+ [ipv4('100.64.0.0'), 10, 'carrier-grade NAT'],
16
+ [ipv4('224.0.0.0'), 4, 'multicast'],
17
+ [ipv4('255.255.255.255'), 32, 'broadcast'],
18
+ ];
19
+ /**
20
+ * Why the floor refuses to connect to `address`, as the kind of address it is, or null when it doesn't. Refused:
21
+ * loopback, private, link-local, unique-local, carrier-grade NAT, multicast, cloud-metadata and unspecified addresses,
22
+ * and an IPv6 address that carries a refused IPv4 one (IPv4-mapped, IPv4-compatible, NAT64 or 6to4).
23
+ */
24
+ export function refusedAddress(scoped) {
25
+ // A link-local IPv6 address may carry a zone (`fe80::1%en0`).
26
+ const address = scoped.replace(/%.*$/, '');
27
+ if (isIPv4(address))
28
+ return refused4Of(ipv4(address));
29
+ if (!isIPv6(address))
30
+ return 'not an IP';
31
+ const words = ipv6(address);
32
+ const all = (from, to, value) => words.slice(from, to).every((word) => word === value);
33
+ const embedded = (high, low) => (((words[high] << 16) | words[low]) >>> 0);
34
+ if (all(0, 8, 0))
35
+ return 'unspecified';
36
+ if (all(0, 7, 0) && words[7] === 1)
37
+ return 'loopback';
38
+ // An IPv4 address in IPv6 form: IPv4-mapped (::ffff:0:0/96), IPv4-compatible (::/96), NAT64 (64:ff9b::/96) and
39
+ // 6to4 (2002::/16).
40
+ const carried = all(0, 5, 0) && words[5] === 0xffff
41
+ ? ['IPv4-mapped', embedded(6, 7)]
42
+ : all(0, 6, 0)
43
+ ? ['IPv4-compatible', embedded(6, 7)]
44
+ : words[0] === 0x64 && words[1] === 0xff9b && all(2, 6, 0)
45
+ ? ['NAT64', embedded(6, 7)]
46
+ : words[0] === 0x2002
47
+ ? ['6to4', embedded(1, 2)]
48
+ : null;
49
+ if (carried !== null) {
50
+ const inner = refused4Of(carried[1]);
51
+ return inner === null ? null : `${carried[0]} ${inner}`;
52
+ }
53
+ const first = words[0];
54
+ if (first === 0xfd00 && words[1] === 0x0ec2 && all(2, 7, 0) && words[7] === 0x254)
55
+ return 'cloud-metadata';
56
+ if ((first & 0xfe00) === 0xfc00)
57
+ return 'unique-local';
58
+ if ((first & 0xffc0) === 0xfe80)
59
+ return 'link-local';
60
+ if ((first & 0xffc0) === 0xfec0)
61
+ return 'site-local';
62
+ if ((first & 0xff00) === 0xff00)
63
+ return 'multicast';
64
+ return null;
65
+ }
66
+ function refused4Of(value) {
67
+ for (const [first, prefix, name] of refused4) {
68
+ const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
69
+ if (((value & mask) >>> 0) === first)
70
+ return name;
71
+ }
72
+ return null;
73
+ }
74
+ /** A dotted-quad IPv4 address as a 32-bit number. */
75
+ function ipv4(address) {
76
+ return address.split('.').reduce((value, part) => ((value << 8) | Number(part)) >>> 0, 0);
77
+ }
78
+ /** An IPv6 address as its eight 16-bit words. A trailing dotted quad is two words. */
79
+ function ipv6(address) {
80
+ const quad = /(\d+\.\d+\.\d+\.\d+)$/.exec(address);
81
+ let text = address;
82
+ if (quad !== null) {
83
+ const value = ipv4(quad[1]);
84
+ text = `${address.slice(0, quad.index)}${(value >>> 16).toString(16)}:${(value & 0xffff).toString(16)}`;
85
+ }
86
+ const [head = '', tail] = text.split('::');
87
+ const parse = (part) => (part === '' ? [] : part.split(':').map((word) => parseInt(word, 16)));
88
+ const [before, after] = [parse(head), parse(tail ?? '')];
89
+ const zeros = tail === undefined ? [] : new Array(8 - before.length - after.length).fill(0);
90
+ return [...before, ...zeros, ...after];
91
+ }
@@ -0,0 +1,15 @@
1
+ import type { Duplex } from 'node:stream';
2
+ import type { Sockets } from './deadline.ts';
3
+ import type { SessionOptions } from './session.ts';
4
+ type ConnectionOptions = Pick<SessionOptions, 'lookup' | 'connect' | 'ca' | 'env'>;
5
+ /**
6
+ * Opens a connection to the URL's host: a TCP connection, with verified TLS over it for `https:`. The host's addresses
7
+ * are resolved once, here, and checked (§17 Addresses): the floor refuses a host when any of them is refused, and
8
+ * connects only to an address it has checked, so a second answer from DNS never reaches a connection (DNS rebinding).
9
+ *
10
+ * Through a proxy (§17 Proxies), the proxy connects to the host, and resolves it. The floor still refuses an IP-literal
11
+ * host in a refused range, and a host that resolves here to a refused address; a host that doesn't resolve here is
12
+ * left to the proxy. TLS runs to the host itself, through the tunnel, and is verified as without one.
13
+ */
14
+ export declare function open(url: URL, options: ConnectionOptions, sockets: Sockets): Promise<Duplex>;
15
+ export {};
@@ -0,0 +1,135 @@
1
+ // Opening the connection for one request (§17 Safety floor): the address check, the proxy tunnel, and verified TLS.
2
+ import { request as httpRequest } from 'node:http';
3
+ import { isIP, isIPv6 } from 'node:net';
4
+ import { connect as tlsConnect } from 'node:tls';
5
+ import { refusedAddress } from "./addresses.js";
6
+ import { Failure, reason, Refusal } from "./outcomes.js";
7
+ import { proxyFor } from "./proxy.js";
8
+ import { hostOf, portOf } from "./urls.js";
9
+ /**
10
+ * Opens a connection to the URL's host: a TCP connection, with verified TLS over it for `https:`. The host's addresses
11
+ * are resolved once, here, and checked (§17 Addresses): the floor refuses a host when any of them is refused, and
12
+ * connects only to an address it has checked, so a second answer from DNS never reaches a connection (DNS rebinding).
13
+ *
14
+ * Through a proxy (§17 Proxies), the proxy connects to the host, and resolves it. The floor still refuses an IP-literal
15
+ * host in a refused range, and a host that resolves here to a refused address; a host that doesn't resolve here is
16
+ * left to the proxy. TLS runs to the host itself, through the tunnel, and is verified as without one.
17
+ */
18
+ export async function open(url, options, sockets) {
19
+ const host = hostOf(url);
20
+ const port = portOf(url);
21
+ const proxy = proxyFor(url, options.env);
22
+ if (proxy === null) {
23
+ const addresses = checked(host, await addressesOf(host, options));
24
+ const socket = await connectToAny(host, addresses, port, options, sockets);
25
+ return url.protocol === 'https:' ? secure(socket, host, options, sockets) : socket;
26
+ }
27
+ if (isIP(host) === 0) {
28
+ const here = await addressesOf(host, options).catch(() => null);
29
+ if (here !== null)
30
+ checked(host, here);
31
+ }
32
+ else
33
+ checked(host, [{ address: host, family: isIP(host) }]);
34
+ const proxyHost = hostOf(proxy.url);
35
+ let socket = await connectToAny(proxyHost, await addressesOf(proxyHost, options), portOf(proxy.url), options, sockets);
36
+ if (proxy.url.protocol === 'https:')
37
+ socket = await secure(socket, proxyHost, options, sockets);
38
+ const tunnel = await tunnelThrough(socket, `${isIPv6(host) ? `[${host}]` : host}:${port}`, proxy.authorization);
39
+ return secure(sockets.add(tunnel), host, options, sockets);
40
+ }
41
+ /** The addresses of a host: an IP literal's own, or what the DNS hook resolves its name to. */
42
+ async function addressesOf(host, options) {
43
+ return isIP(host) === 0 ? resolve(host, options) : [{ address: host, family: isIP(host) }];
44
+ }
45
+ /** The host's addresses, when the floor refuses none of them (§17 Addresses). */
46
+ function checked(host, addresses) {
47
+ for (const { address } of addresses) {
48
+ const refused = refusedAddress(address);
49
+ if (refused !== null) {
50
+ const resolved = address === host ? host : `${host} resolves to ${address}`;
51
+ throw new Refusal(`the safety floor refuses the address: ${resolved} (${refused})`);
52
+ }
53
+ }
54
+ return addresses;
55
+ }
56
+ /**
57
+ * A tunnel to `target` (`host:port`) through the proxy connected to over `socket`: an HTTP `CONNECT`, with the
58
+ * credentials of the proxy's URL, if any.
59
+ */
60
+ function tunnelThrough(socket, target, authorization) {
61
+ return new Promise((resolve, reject) => {
62
+ const request = httpRequest({
63
+ createConnection: () => socket,
64
+ method: 'CONNECT',
65
+ path: target,
66
+ setHost: false,
67
+ headers: { Host: target, ...(authorization === null ? {} : { 'Proxy-Authorization': authorization }) },
68
+ });
69
+ const refused = (status) => new Failure(`the proxy answered ${status} to CONNECT ${target}`);
70
+ request.once('connect', (response, tunnel, head) => {
71
+ if (response.statusCode !== 200) {
72
+ tunnel.destroy();
73
+ reject(refused(response.statusCode));
74
+ return;
75
+ }
76
+ if (head.length > 0)
77
+ tunnel.unshift(head);
78
+ resolve(tunnel);
79
+ });
80
+ request.once('response', (response) => {
81
+ socket.destroy();
82
+ reject(refused(response.statusCode));
83
+ });
84
+ request.on('error', (error) => reject(new Failure(`the proxy's tunnel to ${target} failed: ${reason(error)}`)));
85
+ request.end();
86
+ });
87
+ }
88
+ /**
89
+ * Connects to the first of `addresses` that accepts a connection, in order. Once the request has ended, because a time
90
+ * limit ran out, the connection being opened is given up, and no other address is tried.
91
+ */
92
+ async function connectToAny(host, addresses, port, { connect }, sockets) {
93
+ const { signal } = sockets;
94
+ let last;
95
+ for (const { address, family } of addresses) {
96
+ if (signal.aborted)
97
+ break;
98
+ try {
99
+ return sockets.add(await connect({ address, family, port, signal }));
100
+ }
101
+ catch (error) {
102
+ last = error;
103
+ }
104
+ }
105
+ throw new Failure(`can't connect to ${host}: ${reason(last)}`);
106
+ }
107
+ async function resolve(host, options) {
108
+ try {
109
+ const addresses = await options.lookup(host);
110
+ if (addresses.length === 0)
111
+ throw new Error('no addresses');
112
+ return addresses;
113
+ }
114
+ catch (error) {
115
+ throw new Failure(`DNS lookup of ${host} failed: ${reason(error)}`);
116
+ }
117
+ }
118
+ /** Verified TLS over `socket` to `host`. Verification is never turned off, whatever the environment says. */
119
+ function secure(socket, host, { ca }, sockets) {
120
+ return new Promise((resolve, reject) => {
121
+ const tls = sockets.add(tlsConnect({
122
+ socket,
123
+ ...(isIP(host) === 0 ? { servername: host } : { host }),
124
+ rejectUnauthorized: true,
125
+ ALPNProtocols: ['http/1.1'],
126
+ ...(ca === null ? {} : { ca }),
127
+ }));
128
+ tls.once('secureConnect', () => {
129
+ tls.off('error', fail);
130
+ resolve(tls);
131
+ });
132
+ const fail = (error) => reject(new Failure(`TLS with ${host} failed: ${reason(error)}`));
133
+ tls.once('error', fail);
134
+ });
135
+ }
@@ -0,0 +1,16 @@
1
+ import type { FetchRequest } from '../index.ts';
2
+ type Destination = FetchRequest['destination'];
3
+ /**
4
+ * Why a browser blocks a response of `contentType` for `destination` before it checks integrity, or null when it
5
+ * doesn't (Fetch § main fetch: § Should response to request be blocked due to its MIME type? and § due to nosniff?).
6
+ * Every script destination is blocked for an `image/*`, `audio/*`, `video/*` or `text/csv` type, or for a type that
7
+ * isn't JavaScript's with `X-Content-Type-Options: nosniff`.
8
+ */
9
+ export declare function blockedTypeRefusal(destination: Destination, contentType: string | null, nosniff: string | null): string | null;
10
+ /**
11
+ * Why a browser refuses a response of `contentType` for `destination` once its integrity is checked, or null when it
12
+ * doesn't (HTML § Fetching scripts): a module script, a worker's script and a script `importScripts` loads need a
13
+ * JavaScript MIME type. A classic script of the window doesn't.
14
+ */
15
+ export declare function javascriptTypeRefusal(destination: Destination, contentType: string | null): string | null;
16
+ export {};
@@ -0,0 +1,75 @@
1
+ // The MIME types the floor fetches each destination with (§17 Content types): what a browser would execute. The
2
+ // checks come in two parts, which a fetch runs in the browser's order for each destination: `blockedTypeRefusal`
3
+ // first, then the integrity check, then `javascriptTypeRefusal`. A source map is read as JSON whatever its type, so
4
+ // neither part refuses one.
5
+ /** JavaScript MIME type essences (MIME Sniffing § JavaScript MIME type). */
6
+ const javascriptTypes = new Set([
7
+ 'application/ecmascript',
8
+ 'application/javascript',
9
+ 'application/x-ecmascript',
10
+ 'application/x-javascript',
11
+ 'text/ecmascript',
12
+ 'text/javascript',
13
+ 'text/javascript1.0',
14
+ 'text/javascript1.1',
15
+ 'text/javascript1.2',
16
+ 'text/javascript1.3',
17
+ 'text/javascript1.4',
18
+ 'text/javascript1.5',
19
+ 'text/jscript',
20
+ 'text/livescript',
21
+ 'text/x-ecmascript',
22
+ 'text/x-javascript',
23
+ ]);
24
+ /**
25
+ * Why a browser blocks a response of `contentType` for `destination` before it checks integrity, or null when it
26
+ * doesn't (Fetch § main fetch: § Should response to request be blocked due to its MIME type? and § due to nosniff?).
27
+ * Every script destination is blocked for an `image/*`, `audio/*`, `video/*` or `text/csv` type, or for a type that
28
+ * isn't JavaScript's with `X-Content-Type-Options: nosniff`.
29
+ */
30
+ export function blockedTypeRefusal(destination, contentType, nosniff) {
31
+ if (destination === 'map')
32
+ return null;
33
+ const essence = mimeEssence(contentType);
34
+ if (essence !== null && (/^(image|audio|video)\//.test(essence) || essence === 'text/csv')) {
35
+ return `the safety floor refuses ${named[destination]} served with ${served(contentType)}, which a browser blocks`;
36
+ }
37
+ if (!isJavascript(essence) && isNosniff(nosniff)) {
38
+ const what = `${named[destination]} served with ${served(contentType)}`;
39
+ return `the safety floor refuses ${what} and X-Content-Type-Options: nosniff`;
40
+ }
41
+ return null;
42
+ }
43
+ /**
44
+ * Why a browser refuses a response of `contentType` for `destination` once its integrity is checked, or null when it
45
+ * doesn't (HTML § Fetching scripts): a module script, a worker's script and a script `importScripts` loads need a
46
+ * JavaScript MIME type. A classic script of the window doesn't.
47
+ */
48
+ export function javascriptTypeRefusal(destination, contentType) {
49
+ if (destination === 'map' || destination === 'script' || isJavascript(mimeEssence(contentType)))
50
+ return null;
51
+ const what = `${named[destination]} served with ${served(contentType)}`;
52
+ return `the safety floor refuses ${what}: it needs a JavaScript MIME type`;
53
+ }
54
+ const named = {
55
+ script: 'a classic script',
56
+ module: 'a module script',
57
+ worker: "a worker's script",
58
+ };
59
+ function served(contentType) {
60
+ return contentType === null ? 'no Content-Type' : `Content-Type ${contentType}`;
61
+ }
62
+ function isJavascript(essence) {
63
+ return essence !== null && javascriptTypes.has(essence);
64
+ }
65
+ /** The essence of a `Content-Type` (`type/subtype`, in ASCII lowercase), or null when it has none that parses. */
66
+ function mimeEssence(contentType) {
67
+ if (contentType === null)
68
+ return null;
69
+ const essence = contentType.split(';')[0].trim().toLowerCase();
70
+ return /^[!#$%&'*+.^_`|~\da-z-]+\/[!#$%&'*+.^_`|~\da-z-]+$/.test(essence) ? essence : null;
71
+ }
72
+ /** Whether `X-Content-Type-Options` says `nosniff` (Fetch § determine nosniff): its first value, ignoring case. */
73
+ function isNosniff(value) {
74
+ return value !== null && value.split(',')[0].trim().toLowerCase() === 'nosniff';
75
+ }
@@ -0,0 +1,10 @@
1
+ import type { FetchRequest, ReadResult } from '../index.ts';
2
+ /**
3
+ * Reads the `data:` URL `url` as `request` asks for it (§2 Other script URLs). Its body is the script, and its MIME
4
+ * type the response's `Content-Type`. It is `refused` when a browser would not run it: a malformed base64 body, a MIME
5
+ * type a browser blocks for any script (`image/*`, `audio/*`, `video/*`, `text/csv`), bytes that don't match the
6
+ * request's integrity value, or a module or a script `importScripts` loads whose MIME type isn't JavaScript's, checked
7
+ * in the browser's order (§17 Content types). A classic script of the window needs no JavaScript MIME type, and nor
8
+ * does a worker's own classic script, whose URL isn't HTTP(S) (HTML § Fetch a classic worker script).
9
+ */
10
+ export declare function readDataUrl(url: string, request: FetchRequest): ReadResult;
@@ -0,0 +1,85 @@
1
+ // `data:` URLs (§2 Other script URLs): code a page carries in the reference itself. The store reads one as the Fetch
2
+ // standard's data: URL processor does, with no fetcher, and refuses it where a browser would refuse to run the
3
+ // script: then nothing of it is an artifact.
4
+ import { blockedTypeRefusal, javascriptTypeRefusal } from "./content-types.js";
5
+ import { checkIntegrity } from "./integrity.js";
6
+ /**
7
+ * Reads the `data:` URL `url` as `request` asks for it (§2 Other script URLs). Its body is the script, and its MIME
8
+ * type the response's `Content-Type`. It is `refused` when a browser would not run it: a malformed base64 body, a MIME
9
+ * type a browser blocks for any script (`image/*`, `audio/*`, `video/*`, `text/csv`), bytes that don't match the
10
+ * request's integrity value, or a module or a script `importScripts` loads whose MIME type isn't JavaScript's, checked
11
+ * in the browser's order (§17 Content types). A classic script of the window needs no JavaScript MIME type, and nor
12
+ * does a worker's own classic script, whose URL isn't HTTP(S) (HTML § Fetch a classic worker script).
13
+ */
14
+ export function readDataUrl(url, request) {
15
+ const processed = processDataUrl(url);
16
+ if (processed === null)
17
+ return refused(url, 'its base64 body is malformed');
18
+ const { contentType, body } = processed;
19
+ if (blockedTypeRefusal(request.destination, contentType, null) !== null) {
20
+ return refused(url, `a browser blocks a script of the MIME type ${contentType}`);
21
+ }
22
+ const sri = checkIntegrity(request.integrity ?? '', body);
23
+ if (sri !== 'none' && sri.result === 'mismatch') {
24
+ return refused(url, `its digest is ${sri.actual}, and the integrity value expects ${sri.expected.join(' or ')}`);
25
+ }
26
+ const ownWorkerScript = request.destination === 'worker' && request.imported !== true;
27
+ if (!ownWorkerScript && javascriptTypeRefusal(request.destination, contentType) !== null) {
28
+ return refused(url, `it needs a JavaScript MIME type, and it has ${contentType}`);
29
+ }
30
+ const retrieval = { status: 'ok', requestedUrl: url, finalUrl: url, contentType, sri };
31
+ return { status: 'ok', url, path: null, bytes: body, retrieval, sourceMap: null };
32
+ }
33
+ function refused(url, why) {
34
+ return { status: 'refused', url, detail: `a browser refuses to run the data: script: ${why}` };
35
+ }
36
+ /**
37
+ * The MIME type and body of a `data:` URL (Fetch § data: URL processor), or null when its body is malformed base64. A
38
+ * MIME type that doesn't parse, an empty one included, is `text/plain;charset=US-ASCII`.
39
+ */
40
+ function processDataUrl(url) {
41
+ // The URL serialized without its fragment: its first `#` starts the fragment.
42
+ const fragment = url.indexOf('#');
43
+ const input = url.slice('data:'.length, fragment === -1 ? undefined : fragment);
44
+ const comma = input.indexOf(',');
45
+ if (comma === -1)
46
+ return null;
47
+ let mimeType = input.slice(0, comma).replace(/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g, '');
48
+ let body = percentDecode(input.slice(comma + 1));
49
+ const base64 = /; *base64$/i.exec(mimeType);
50
+ if (base64 !== null) {
51
+ try {
52
+ // Forgiving-base64 decode, of the body's isomorphic decoding.
53
+ body = Uint8Array.from(atob(Buffer.from(body).toString('latin1')), (character) => character.charCodeAt(0));
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ mimeType = mimeType.slice(0, base64.index);
59
+ }
60
+ if (mimeType.startsWith(';'))
61
+ mimeType = `text/plain${mimeType}`;
62
+ return { contentType: parsesAsMimeType(mimeType) ? mimeType : 'text/plain;charset=US-ASCII', body };
63
+ }
64
+ /**
65
+ * Whether `text` parses as a MIME type (MIME Sniffing § parse a MIME type): a token type and subtype, then any
66
+ * parameters.
67
+ */
68
+ function parsesAsMimeType(text) {
69
+ return /^[\t\n\r ]*[!#$%&'*+.^_`|~\dA-Za-z-]+\/[!#$%&'*+.^_`|~\dA-Za-z-]+[\t\n\r ]*(?:;|$)/.test(text);
70
+ }
71
+ /** The bytes of a URL's percent-encoding (URL § percent-decode): an invalid escape is left as it is. */
72
+ function percentDecode(text) {
73
+ const bytes = new TextEncoder().encode(text);
74
+ const out = [];
75
+ for (let i = 0; i < bytes.length; i++) {
76
+ const hex = String.fromCharCode(bytes[i + 1] ?? 0, bytes[i + 2] ?? 0);
77
+ if (bytes[i] === 0x25 && /^[\dA-Fa-f]{2}$/.test(hex)) {
78
+ out.push(Number.parseInt(hex, 16));
79
+ i += 2;
80
+ }
81
+ else
82
+ out.push(bytes[i]);
83
+ }
84
+ return Uint8Array.from(out);
85
+ }
@@ -0,0 +1,18 @@
1
+ import type { Duplex } from 'node:stream';
2
+ /**
3
+ * The sockets one request opens: all of them are closed when it ends, however it ends. A connection still being opened
4
+ * then is given up through `signal`, so that it neither goes on connecting nor keeps the process alive.
5
+ */
6
+ export declare class Sockets {
7
+ #private;
8
+ /** Aborts when the request ends: a connect hook given it stops connecting, and rejects. */
9
+ get signal(): AbortSignal;
10
+ /**
11
+ * Keeps `socket` to close with the rest, or closes it now when the request has already ended. An error on it between
12
+ * two steps of the request, when no step is listening, is left for the next step to find: it never crashes the scan.
13
+ */
14
+ add<T extends Duplex>(socket: T): T;
15
+ close(): void;
16
+ }
17
+ /** Settles as `work` does, or rejects with `failure()` once `ms` have passed without it settling. */
18
+ export declare function within<T>(work: Promise<T>, ms: number, failure: () => Error): Promise<T>;
@@ -0,0 +1,44 @@
1
+ // Time limits for the resolve fetcher's steps (§17 Safety floor: Time), and the sockets a step leaves open when one
2
+ // runs out.
3
+ /**
4
+ * The sockets one request opens: all of them are closed when it ends, however it ends. A connection still being opened
5
+ * then is given up through `signal`, so that it neither goes on connecting nor keeps the process alive.
6
+ */
7
+ export class Sockets {
8
+ #open = [];
9
+ #ended = new AbortController();
10
+ /** Aborts when the request ends: a connect hook given it stops connecting, and rejects. */
11
+ get signal() {
12
+ return this.#ended.signal;
13
+ }
14
+ /**
15
+ * Keeps `socket` to close with the rest, or closes it now when the request has already ended. An error on it between
16
+ * two steps of the request, when no step is listening, is left for the next step to find: it never crashes the scan.
17
+ */
18
+ add(socket) {
19
+ socket.on('error', () => { });
20
+ if (this.signal.aborted)
21
+ socket.destroy();
22
+ else
23
+ this.#open.push(socket);
24
+ return socket;
25
+ }
26
+ close() {
27
+ this.#ended.abort();
28
+ for (const socket of this.#open)
29
+ socket.destroy();
30
+ }
31
+ }
32
+ /** Settles as `work` does, or rejects with `failure()` once `ms` have passed without it settling. */
33
+ export function within(work, ms, failure) {
34
+ return new Promise((resolve, reject) => {
35
+ const timer = setTimeout(() => reject(failure()), ms);
36
+ work.then((value) => {
37
+ clearTimeout(timer);
38
+ resolve(value);
39
+ }, (error) => {
40
+ clearTimeout(timer);
41
+ reject(error);
42
+ });
43
+ });
44
+ }
@@ -0,0 +1,29 @@
1
+ import { type Duplex } from 'node:stream';
2
+ import type { FetchedResponse } from '../index.ts';
3
+ import type { SessionOptions } from './session.ts';
4
+ /**
5
+ * What one request got: the response's status and recorded headers, its `Location` and `X-Content-Type-Options`, and a
6
+ * 2xx response's body.
7
+ */
8
+ export interface Answer {
9
+ response: FetchedResponse;
10
+ status: number;
11
+ location: string | null;
12
+ nosniff: string | null;
13
+ bytes: Uint8Array | null;
14
+ }
15
+ /** How many bytes a response's body may hold, decompressed (§17 Size). */
16
+ export interface ByteLimits {
17
+ /** The most one response may have. */
18
+ responseBytes: number;
19
+ /** The most all the responses of the scan may have. */
20
+ scanBytes: number;
21
+ /** The bytes the scan's earlier responses had. */
22
+ scanned: number;
23
+ }
24
+ /**
25
+ * Sends a `GET` for `url` over `connection`: with monkeypatchlist's `User-Agent`, and without cookies, credentials or
26
+ * conditional headers (§17 Requests). Only a 2xx response's body is read, decompressed from `gzip` or `br`, and it is
27
+ * refused as soon as it holds more bytes than `limits` allow.
28
+ */
29
+ export declare function exchange(url: URL, connection: Duplex, { version }: Pick<SessionOptions, 'version'>, limits: ByteLimits): Promise<Answer>;
@@ -0,0 +1,112 @@
1
+ // One request and its response, over a connection the floor has opened (§17 Safety floor: Requests, Size).
2
+ import { request as httpRequest } from 'node:http';
3
+ import { Writable } from 'node:stream';
4
+ import { pipeline } from 'node:stream/promises';
5
+ import { createBrotliDecompress, createGunzip, createInflate } from 'node:zlib';
6
+ import { Failure, reason, Refusal } from "./outcomes.js";
7
+ /**
8
+ * Sends a `GET` for `url` over `connection`: with monkeypatchlist's `User-Agent`, and without cookies, credentials or
9
+ * conditional headers (§17 Requests). Only a 2xx response's body is read, decompressed from `gzip` or `br`, and it is
10
+ * refused as soon as it holds more bytes than `limits` allow.
11
+ */
12
+ export function exchange(url, connection, { version }, limits) {
13
+ return new Promise((resolve, reject) => {
14
+ const request = httpRequest({
15
+ createConnection: () => connection,
16
+ method: 'GET',
17
+ path: `${url.pathname}${url.search}`,
18
+ setHost: false,
19
+ headers: {
20
+ Host: url.host,
21
+ 'User-Agent': `monkeypatchlist/${version}`,
22
+ Accept: '*/*',
23
+ 'Accept-Encoding': 'gzip, br',
24
+ Connection: 'close',
25
+ },
26
+ });
27
+ request.on('error', (error) => reject(new Failure(`the request for ${url.href} failed: ${reason(error)}`)));
28
+ request.once('response', (message) => {
29
+ const status = message.statusCode ?? 0;
30
+ const response = recorded(url, message);
31
+ const location = header(message, 'location');
32
+ const nosniff = header(message, 'x-content-type-options');
33
+ if (status < 200 || status > 299) {
34
+ message.destroy();
35
+ connection.destroy();
36
+ resolve({ response, status, location, nosniff, bytes: null });
37
+ return;
38
+ }
39
+ body(url, message, response, limits)
40
+ .then((bytes) => resolve({ response, status, location, nosniff, bytes }), reject)
41
+ .finally(() => connection.destroy());
42
+ });
43
+ request.end();
44
+ });
45
+ }
46
+ /** Reads a response's body, decoded, refusing it once it holds more bytes than `limits` allow. */
47
+ async function body(url, message, response, { responseBytes, scanBytes, scanned }) {
48
+ const decoders = decodersFor(header(message, 'content-encoding'));
49
+ const chunks = [];
50
+ let size = 0;
51
+ const sink = new Writable({
52
+ write(chunk, _, callback) {
53
+ size += chunk.length;
54
+ if (size > responseBytes) {
55
+ callback(new Refusal(`the safety floor refuses a response of more than ${responseBytes} bytes`, response));
56
+ }
57
+ else if (scanned + size > scanBytes) {
58
+ callback(new Refusal(`the safety floor refuses more than ${scanBytes} bytes of responses in a scan`, response));
59
+ }
60
+ else {
61
+ chunks.push(chunk);
62
+ callback();
63
+ }
64
+ },
65
+ });
66
+ try {
67
+ await pipeline([message, ...decoders, sink]);
68
+ }
69
+ catch (error) {
70
+ if (error instanceof Refusal || error instanceof Failure)
71
+ throw error;
72
+ throw new Failure(`reading ${url.href} failed: ${reason(error)}`);
73
+ }
74
+ return new Uint8Array(Buffer.concat(chunks));
75
+ }
76
+ /**
77
+ * The decoders a `Content-Encoding` needs, in the order to apply them: the codings are listed in the order they were
78
+ * applied. A coding the floor can't decode fails the fetch.
79
+ */
80
+ function decodersFor(encoding) {
81
+ const codings = (encoding ?? '')
82
+ .split(',')
83
+ .map((coding) => coding.trim().toLowerCase())
84
+ .filter((coding) => coding !== '' && coding !== 'identity');
85
+ return codings.reverse().map((coding) => {
86
+ switch (coding) {
87
+ case 'gzip':
88
+ case 'x-gzip':
89
+ return createGunzip();
90
+ case 'br':
91
+ return createBrotliDecompress();
92
+ case 'deflate':
93
+ return createInflate();
94
+ default:
95
+ throw new Failure(`the response has a content coding monkeypatchlist can't decode: ${coding}`);
96
+ }
97
+ });
98
+ }
99
+ /** The response's URL and the headers that are recorded (§17 What is recorded). */
100
+ function recorded(url, message) {
101
+ return {
102
+ finalUrl: url.href,
103
+ contentType: header(message, 'content-type'),
104
+ etag: header(message, 'etag'),
105
+ lastModified: header(message, 'last-modified'),
106
+ sourceMap: header(message, 'sourcemap') ?? header(message, 'x-sourcemap'),
107
+ };
108
+ }
109
+ function header(message, name) {
110
+ const value = message.headers[name];
111
+ return typeof value === 'string' ? value : null;
112
+ }
@@ -0,0 +1,19 @@
1
+ import type { FetchedResponse, FetchResult, Sri } from '../index.ts';
2
+ /**
3
+ * The result of fetching `bytes` with the integrity metadata `integrity` (the empty string for none): `ok` with the
4
+ * check, or `sri-mismatch` with it, and without the bytes, which are never analyzed (§17 Integrity).
5
+ */
6
+ export declare function verified(bytes: Uint8Array, response: FetchedResponse, integrity: string): FetchResult;
7
+ /**
8
+ * One integrity value that stands for several (§17 Integrity): code sets an element's `integrity` to one of
9
+ * several constants, and the bytes pass when they match any. A single value is returned as it is.
10
+ */
11
+ export declare function alternativeIntegrity(values: readonly string[]): string;
12
+ /**
13
+ * Checks `bytes` against an integrity value, which is integrity metadata or alternatives of it
14
+ * (`alternativeIntegrity`). The bytes match when they match any alternative, and the check is that alternative's. When
15
+ * none does, the check expects every alternative's digests, and `actual` is the bytes' digest in the strongest
16
+ * algorithm any of them names. An alternative that checks nothing makes the value check nothing (`none`), as in a
17
+ * browser.
18
+ */
19
+ export declare function checkIntegrity(integrity: string, bytes: Uint8Array): Sri;