@freedomofpress/webcat 0.0.0-stage → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/Readme.md +45 -0
  2. package/data/block.json +101 -0
  3. package/data/list.json +80 -0
  4. package/dist/hooks/content.js +1 -0
  5. package/dist/lib/browser/chrome.d.ts +86 -0
  6. package/dist/lib/browser/chrome.js +138 -0
  7. package/dist/lib/browser/kvstore.d.ts +70 -0
  8. package/dist/lib/browser/kvstore.js +241 -0
  9. package/dist/lib/browser/permissions.d.ts +113 -0
  10. package/dist/lib/browser/permissions.js +182 -0
  11. package/dist/lib/browser/requests.d.ts +145 -0
  12. package/dist/lib/browser/requests.js +292 -0
  13. package/dist/lib/browser/scripting.d.ts +19 -0
  14. package/dist/lib/browser/scripting.js +92 -0
  15. package/dist/lib/browser/sync.d.ts +68 -0
  16. package/dist/lib/browser/sync.js +114 -0
  17. package/dist/lib/browser/utils.d.ts +5 -0
  18. package/dist/lib/browser/utils.js +11 -0
  19. package/dist/lib/config.d.ts +45 -0
  20. package/dist/lib/config.js +45 -0
  21. package/dist/lib/validator_set.d.ts +4 -0
  22. package/dist/lib/validator_set.js +20 -0
  23. package/dist/lib/webcat/cache.d.ts +200 -0
  24. package/dist/lib/webcat/cache.js +308 -0
  25. package/dist/lib/webcat/canonicalize.d.ts +1 -0
  26. package/dist/lib/webcat/canonicalize.js +58 -0
  27. package/dist/lib/webcat/db.d.ts +30 -0
  28. package/dist/lib/webcat/db.js +131 -0
  29. package/dist/lib/webcat/encoding.d.ts +8 -0
  30. package/dist/lib/webcat/encoding.js +57 -0
  31. package/dist/lib/webcat/handler.d.ts +26 -0
  32. package/dist/lib/webcat/handler.js +419 -0
  33. package/dist/lib/webcat/hookbuilder.d.ts +47 -0
  34. package/dist/lib/webcat/hookbuilder.js +170 -0
  35. package/dist/lib/webcat/interfaces/bundle.d.ts +46 -0
  36. package/dist/lib/webcat/interfaces/bundle.js +8 -0
  37. package/dist/lib/webcat/interfaces/database.d.ts +68 -0
  38. package/dist/lib/webcat/interfaces/database.js +1 -0
  39. package/dist/lib/webcat/interfaces/errors.d.ts +451 -0
  40. package/dist/lib/webcat/interfaces/errors.js +109 -0
  41. package/dist/lib/webcat/interfaces/log.d.ts +14 -0
  42. package/dist/lib/webcat/interfaces/log.js +10 -0
  43. package/dist/lib/webcat/interfaces/originstate.d.ts +40 -0
  44. package/dist/lib/webcat/interfaces/originstate.js +1 -0
  45. package/dist/lib/webcat/interfaces/requeststate.d.ts +10 -0
  46. package/dist/lib/webcat/interfaces/requeststate.js +1 -0
  47. package/dist/lib/webcat/logger.d.ts +64 -0
  48. package/dist/lib/webcat/logger.js +112 -0
  49. package/dist/lib/webcat/originstate.d.ts +45 -0
  50. package/dist/lib/webcat/originstate.js +302 -0
  51. package/dist/lib/webcat/parsers.d.ts +21 -0
  52. package/dist/lib/webcat/parsers.js +36 -0
  53. package/dist/lib/webcat/request.d.ts +11 -0
  54. package/dist/lib/webcat/request.js +78 -0
  55. package/dist/lib/webcat/resources.d.ts +3 -0
  56. package/dist/lib/webcat/resources.js +41 -0
  57. package/dist/lib/webcat/response.d.ts +39 -0
  58. package/dist/lib/webcat/response.js +394 -0
  59. package/dist/lib/webcat/ui.d.ts +70 -0
  60. package/dist/lib/webcat/ui.js +282 -0
  61. package/dist/lib/webcat/updater.d.ts +115 -0
  62. package/dist/lib/webcat/updater.js +296 -0
  63. package/dist/lib/webcat/utils.d.ts +8 -0
  64. package/dist/lib/webcat/utils.js +74 -0
  65. package/dist/lib/webcat/validators.d.ts +16 -0
  66. package/dist/lib/webcat/validators.js +457 -0
  67. package/dist/lib/webcat.d.ts +11 -0
  68. package/dist/lib/webcat.js +130 -0
  69. package/icons/dark/webcat-error.SVG +1 -0
  70. package/icons/dark/webcat-ok.SVG +1 -0
  71. package/icons/dark/webcat.SVG +1 -0
  72. package/icons/light/webcat-error.SVG +1 -0
  73. package/icons/light/webcat-ok.SVG +1 -0
  74. package/icons/light/webcat.SVG +1 -0
  75. package/package.json +72 -4
  76. package/pages/error.css +9 -0
  77. package/pages/error.html +70 -0
  78. package/pages/error.js +51 -0
  79. package/pages/popup.css +16 -0
  80. package/pages/popup.html +14 -0
  81. package/pages/popup.js +48 -0
  82. package/README.md +0 -3
package/Readme.md ADDED
@@ -0,0 +1,45 @@
1
+ ## WEBCAT Browser Extension
2
+
3
+ The extension is written in TypeScript, using the Manifest V3 API. Chromium is not supported, as the extension relies heavily on intercepting and modifying network requests and responses, which Chromium does not allow in Manifest V3. There are no external runtime dependencies: the Sigsum, Sigstore and CometBFT clients are maintained by the Freedom of the Press Foundation and, like the rest of the extension, use only the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). The only exception is in the WebAssembly hooks, where a synchronous SHA256 function is needed in order to hook synchronous WebAssembly methods and Worklets, where `crypto` is not available.
4
+
5
+ The latest tagged release is generally published on the [Mozilla Add-ons store](https://addons.mozilla.org/en-US/firefox/addon/webcat/).
6
+
7
+ ### Build
8
+
9
+ Install build dependencies:
10
+
11
+ `npm install`
12
+
13
+ Compile the TypeScript and bundle it with [Vite](https://vite.dev):
14
+
15
+ `npm run build`
16
+
17
+ The output will be in `./dist/bundle.js` and `./dist/hooks/`. Everything else in the extension folder does not need any action.
18
+
19
+ Alternatively, `make package` will install, build, fetch the current enrollment list and package the extension, saving the archive as `../dist/webcat-extension.zip`. The archive can then be loaded in `about:debugging` as a temporary add-on. `make package-test` builds with `VITE_TESTING=true`, which disables minification and mocks the light client, and is what the integration tests use.
20
+
21
+ The extension can also be built as an npm library with `npm run build:lib`. API docs are generated with [Typedoc](https://typedoc.org).
22
+
23
+ ### Tests
24
+
25
+ Unit tests use [vitest](https://vitest.dev/) and run natively, with the browser APIs mocked:
26
+
27
+ `npm run test`
28
+
29
+ Tests in `tests/webcat/` cover the verification logic, tests in `tests/browser/` the wrappers around the WebExtension APIs. `npm run coverage` also prints a coverage report.
30
+
31
+ Integration tests are in [`../test/`](../test/README.md). They use pytest to run Firefox and Tor Browser with the `package-test` archive (or the library build) installed, and check the test apps. CI runs them on Firefox, Firefox ESR and Tor Browser at the Standard, Safer and Safest security levels.
32
+
33
+ ### Linting
34
+
35
+ The project uses [dpdm](https://github.com/acrazing/dpdm) to catch circular imports, [eslint](eslint.config.mjs) for linting and [prettier](https://prettier.io/) for sorting imports and style consistency. All three are run together with:
36
+
37
+ `npm run lint`
38
+
39
+ To check for issues without auto-fixing (this is what CI runs):
40
+
41
+ `npm run lint:check`
42
+
43
+ ### How it works
44
+
45
+ For an overview of the verification flow and the response validation logic, see [Towards auditable web application runtimes](https://securedrop.org/news/webcat-towards-auditable-web-application-runtimes/) and the [specifications](https://github.com/freedomofpress/webcat-spec).
@@ -0,0 +1,101 @@
1
+ {
2
+ "signed_header": {
3
+ "header": {
4
+ "version": {
5
+ "block": "11",
6
+ "app": "0"
7
+ },
8
+ "chain_id": "webcat-test-02",
9
+ "height": "330644",
10
+ "time": "2026-10-14T13:00:53.8169638Z",
11
+ "last_block_id": {
12
+ "hash": "E54776034F308197AA0112DFEDB54EB0C64AD294FCEC1BA4A4C88F7F9F497872",
13
+ "parts": {
14
+ "total": 1,
15
+ "hash": "2446521004F6194EF5C5DCC82A1DB8D7C1CDE92D068800098733F77E8C9F7267"
16
+ }
17
+ },
18
+ "last_commit_hash": "9049801B0E90DB5E299730F4890C3D58E3A5BBAD1C50C47161F248CE340FA939",
19
+ "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
20
+ "validators_hash": "166D75D14EE1555615C57D2F013454152214BDB143D458C00A02B2AC0F2AC128",
21
+ "next_validators_hash": "166D75D14EE1555615C57D2F013454152214BDB143D458C00A02B2AC0F2AC128",
22
+ "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F",
23
+ "app_hash": "CC69EBA2887F829EF2670DF9D43FD035C60DCCFCE6543FE292C28C46E7A50E76",
24
+ "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
25
+ "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
26
+ "proposer_address": "A39CFEBE6E8CA10B6101C46884A6EB8E62D04417"
27
+ },
28
+ "commit": {
29
+ "height": "330644",
30
+ "round": 0,
31
+ "block_id": {
32
+ "hash": "DB939428FF9FBA2D65EA42FD14A1E1AF3E87101E671D4541E3A35C536E8E4EC3",
33
+ "parts": {
34
+ "total": 1,
35
+ "hash": "94FF793011CB30A5F38C87CE20DF8334EF1DDCE9C328B74094596CEED45EDF78"
36
+ }
37
+ },
38
+ "signatures": [
39
+ {
40
+ "block_id_flag": 2,
41
+ "validator_address": "48926DF1CC10DBBFAA78953F9BE38E59020DE01D",
42
+ "timestamp": "2026-10-14T13:01:54.718663088Z",
43
+ "signature": "gjC8v87ugu+Sf8vVm56NmapJ/O7+1oE/m9ivmVEQJhIPPUTsNg2L0VPGwI2+cqM5FebzQE2666Ffnv1i/dQUAw=="
44
+ },
45
+ {
46
+ "block_id_flag": 2,
47
+ "validator_address": "A39CFEBE6E8CA10B6101C46884A6EB8E62D04417",
48
+ "timestamp": "2026-10-14T13:01:54.801194901Z",
49
+ "signature": "veHQpG9BTRM+22yljMnbx0NjSjw3vWJkOY9B7Xn4IQZDtarh/5UdAKICQZtiaabhWtHXeUxMpURmPVvGnp/UCQ=="
50
+ },
51
+ {
52
+ "block_id_flag": 2,
53
+ "validator_address": "B734AC6CC1F14AAC8315FE8DBB07402ED4E45D72",
54
+ "timestamp": "2026-10-14T13:01:54.679594575Z",
55
+ "signature": "ZzKX9UDVNTmeUkIi6zwYBq942LZbrjlfBGhCTw6P+RmyZDWdRAKnAO+w/KPB1BKFHRWZ4okKRd+pnXcTggXFDA=="
56
+ }
57
+ ]
58
+ }
59
+ },
60
+ "validator_set": {
61
+ "validators": [
62
+ {
63
+ "address": "48926DF1CC10DBBFAA78953F9BE38E59020DE01D",
64
+ "pub_key": {
65
+ "type": "tendermint/PubKeyEd25519",
66
+ "value": "zEK+pyAEhhCaoHYhhT+rrorJoc9kZbfY+JkbMtF8u5Y="
67
+ },
68
+ "power": "1",
69
+ "name": null
70
+ },
71
+ {
72
+ "address": "A39CFEBE6E8CA10B6101C46884A6EB8E62D04417",
73
+ "pub_key": {
74
+ "type": "tendermint/PubKeyEd25519",
75
+ "value": "8dZUej72UriKCPIDvk01c6yLaAB2ssYIli3fT3jKwSM="
76
+ },
77
+ "power": "1",
78
+ "name": null
79
+ },
80
+ {
81
+ "address": "B734AC6CC1F14AAC8315FE8DBB07402ED4E45D72",
82
+ "pub_key": {
83
+ "type": "tendermint/PubKeyEd25519",
84
+ "value": "WBK6Af3uKtC+VTv8x48f2TPoNnsebSXSBTIsJku/nQw="
85
+ },
86
+ "power": "1",
87
+ "name": null
88
+ }
89
+ ],
90
+ "proposer": {
91
+ "address": "A39CFEBE6E8CA10B6101C46884A6EB8E62D04417",
92
+ "pub_key": {
93
+ "type": "tendermint/PubKeyEd25519",
94
+ "value": "8dZUej72UriKCPIDvk01c6yLaAB2ssYIli3fT3jKwSM="
95
+ },
96
+ "power": "1",
97
+ "name": null
98
+ },
99
+ "total_voting_power": "3"
100
+ }
101
+ }
package/data/list.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "block_height": 330643,
3
+ "leaves": [
4
+ [
5
+ "canonical/.app.riskmapper",
6
+ "0a205bc15fa3cf1bbe8cd7550bd988e48020da0c32689ee4fd7f02fa7a9485268476"
7
+ ],
8
+ [
9
+ "canonical/.build.rick",
10
+ "0a20af7b41b46aabc27ffbae7f3ad22234706f3e497cc7d53d714913f41792cc86e0"
11
+ ],
12
+ [
13
+ "canonical/.cat.lsd",
14
+ "0a20b1de98823019eb9e8ce01dfe8d27f72e99e0b7826e8163086d08ec6285d826c3"
15
+ ],
16
+ [
17
+ "canonical/.com.legoktm.git",
18
+ "0a20ef903936a3167942c49ccee664b7bfc8400c036b52f0263066d621718a9529ec"
19
+ ],
20
+ [
21
+ "canonical/.llc.micrographia",
22
+ "0a20d3e1d66add2d2ed3cf15f23d740e48ee7567922ad0dc3e67a379588cfef24b19"
23
+ ],
24
+ [
25
+ "canonical/.net.strongphrase",
26
+ "0a20db2b798219451a47d04a9c3b03d5f0873facefe5b2bab42791e81ebfa342473d"
27
+ ],
28
+ [
29
+ "canonical/.org.endeixis.www",
30
+ "0a20ff788a2293dbc439882d65d18a51e81444b5354f92d6f375791a7f014faa54a0"
31
+ ],
32
+ [
33
+ "canonical/.org.osservatorionessuno.upload",
34
+ "0a20b82cb5694148e4f05cc98a66bd00adc0baaba21dd4f96867e4d6f6e707ac7dae"
35
+ ],
36
+ [
37
+ "canonical/.sh.tinfoil.verification-center",
38
+ "0a2029a12b3e97dc6746cebc18c4ce03acf27ff53c324ee7e26b2c70182191bd2d2c"
39
+ ],
40
+ [
41
+ "canonical/.sh.tinfoil.verification-center-preview",
42
+ "0a20676f6fd20ae82cabeb8a13a320af9ce8be5323af439b538d852fe8c089e4cc64"
43
+ ],
44
+ [
45
+ "canonical/.solutions.hacked",
46
+ "0a20c869dc60104f61e89360f80bc8ea07ac6837b20d9e22098206dd90f47ff6c959"
47
+ ],
48
+ [
49
+ "canonical/.tech.webcat.demo.element",
50
+ "0a2024955e41f46221d79fcbb3370abd2219a3a7be13d3fb6341f2cf150788d3311e"
51
+ ],
52
+ [
53
+ "canonical/.tech.webcat.demo.enrollment-error",
54
+ "0a2049278ed1c0dce64b6f417ef47ef8c464caaaa66896f1bf903c170b90cc85af18"
55
+ ],
56
+ [
57
+ "canonical/.tech.webcat.demo.integrity-error",
58
+ "0a206909132ad0fe3779eb59b61af318ae60c06cd78cdff39c31d1d0db61043a24af"
59
+ ],
60
+ [
61
+ "canonical/.tech.webcat.demo.manifest-error",
62
+ "0a20dd8be8c859a0995a8326a19e145e2756c0c9bd98df88be501bdd73a4b17d67b0"
63
+ ],
64
+ [
65
+ "canonical/.tech.webcat.demo.test",
66
+ "0a208904d6d804470443a14eaa24edcf78041a7606e2b194d0105c4e2c2d5cf53821"
67
+ ]
68
+ ],
69
+ "proof": {
70
+ "app_hash": "cc69eba2887f829ef2670df9d43fd035c60dccfce6543fe292c28c46e7a50e76",
71
+ "canonical_root_hash": "5ef5175877cd6395edb37d16cd75563a2755856aaae0e45e882af6429bac9c0a",
72
+ "merkle_proof": {
73
+ "proof_bytes": [
74
+ "0ad7030a162e746563682e7765626361742e64656d6f2e7465737412220a208904d6d804470443a14eaa24edcf78041a7606e2b194d0105c4e2c2d5cf538211a150801100118012a0d4a4d543a3a4c6561664e6f64652236080112104a4d543a3a496e74726e616c4e6f64651a2051ab1571299e2c3fc4a9bea2ef7d957c49f9e809e7568e948c400ea111a66a952236080112104a4d543a3a496e74726e616c4e6f64651a205350415253455f4d45524b4c455f504c414345484f4c4445525f484153485f5f2234080112304a4d543a3a496e74726e616c4e6f64655350415253455f4d45524b4c455f504c414345484f4c4445525f484153485f5f2236080112104a4d543a3a496e74726e616c4e6f64651a205350415253455f4d45524b4c455f504c414345484f4c4445525f484153485f5f2236080112104a4d543a3a496e74726e616c4e6f64651a20fbf809557d948b48663301baf50cbcaea85626cf032ad94dc26ac49ee506f30d2234080112304a4d543a3a496e74726e616c4e6f64652cfd256ee4f9a769eedd2ff8165c665dcd52ab3245e7cf6fbb0d3c2652fd43c42236080112104a4d543a3a496e74726e616c4e6f64651a20f492db53692b860ecc0aff2b1e48d16a6089b66db3c844ac6766e6c0e6059031",
75
+ "0aec010a0963616e6f6e6963616c12205ef5175877cd6395edb37d16cd75563a2755856aaae0e45e882af6429bac9c0a1a150801100118012a0d4a4d543a3a4c6561664e6f64652236080112104a4d543a3a496e74726e616c4e6f64651a20f4b689332e69b27264c62b8bd05261e95090f3b5370cd05874eef504ea75d9052236080112104a4d543a3a496e74726e616c4e6f64651a205350415253455f4d45524b4c455f504c414345484f4c4445525f484153485f5f2236080112104a4d543a3a496e74726e616c4e6f64651a205350415253455f4d45524b4c455f504c414345484f4c4445525f484153485f5f"
76
+ ],
77
+ "representative_key": "canonical/.tech.webcat.demo.test"
78
+ }
79
+ }
80
+ }
@@ -0,0 +1 @@
1
+ (function(){"use strict";const o=Symbol("WEBCAT internal"),H=Symbol("WEBCAT hooked"),s=globalThis.self||globalThis,P=Reflect.apply,U=typeof globalThis.exportFunction=="function";function n(r){return U?XPCNativeWrapper.unwrap(r):r}function b(r,e=s,t=void 0){if(U){const i={};return t!==void 0&&(i.defineAs=t),exportFunction(r,XPCNativeWrapper.unwrap(e),i)}else t!==void 0&&(e[t]=r);return r}function R(r){const e=n(new s.Object);for(const t of Object.keys(r))e[t]=r[t];return e.listeners=new Map,e}function j(r,e){return function(t,i){const c=t;if(c.hooks||(c.hooks={}),r in c.hooks){console.log(`[WEBCAT] Hook already injected: ${r}`),c.hooks[r].data=i;return}const{promise:l,resolve:a}=s.Promise.withResolvers();c.hooks[r]={ready:l,data:i},Object.defineProperty(c.hooks[r],"data",{set:d=>{i=d,a()},get:()=>i}),typeof i=="object"&&(c.hooks[r].data=i),e(l.then(()=>i),c.hooks[r])}}function $(r,e,t){return r.has(e)?r.get(e):(r.set(e,t),t)}function B(r){const e=n(r);return e&&(typeof e=="object"||typeof e=="function")?e:{capture:!!e}}function _(r,e){return b((...t)=>P(r,e,t))}function q(r,e,t,i){const c=n(e[1]),{once:l}=B(e[2]);return e[1]=b((...a)=>{l&&t[i]===e&&delete t[i];const d=typeof c=="function"?c:c?.handleEvent;return d&&P(d,r,a)}),e}function C(r,e){const{get:t,set:i}=Object.getOwnPropertyDescriptor(r,e);function c(){return o in n(this)?n(this)[o][e]:t&&P(t,this,[])}function l(a){o in n(this)?(n(this)[o][e]=a,n(this)[o].instance&&(n(this)[o].instance[e]=typeof a=="function"?_(a,n(this)):null)):i&&P(i,this,[a])}Object.defineProperty(r,e,{get:b(c),set:b(l)})}function x(r){const e=Object.keys(r[o]).filter(t=>t.startsWith("on"));for(const t of e){const i=r[o][t];r[o].instance[t]=typeof i=="function"?_(i,r):null}for(const t of r[o].listeners.values())for(const{nonCapturingArgs:i,capturingArgs:c}of t.values())i&&r[o].instance.addEventListener(...i),c&&r[o].instance.addEventListener(...c)}const z=j("EventTarget",function(){const{value:r}=Object.getOwnPropertyDescriptor(n(s.EventTarget.prototype),"addEventListener");function e(...a){const[d,w,u]=a;if(this&&o in n(this)){const{capture:f,once:m,passive:k,signal:p}=B(u),h=n(new s.Object);h.capture=!!f,h.once=!!m,h.passive=k===void 0?void 0:!!k,h.signal=p;const W=$($(n(this)[o].listeners,d,new Map),w,{}),O=f?"capturingArgs":"nonCapturingArgs",E=W[O];if(!E||B(E[2]).signal?.aborted){const L=q(n(this),[d,w,h],W,O);W[O]=L,n(this)[o].instance&&n(this)[o].instance.addEventListener(...L)}}else P(r,this,a)}Object.defineProperty(n(s.EventTarget.prototype),"addEventListener",{value:b(e)});const{value:t}=Object.getOwnPropertyDescriptor(n(s.EventTarget.prototype),"removeEventListener");function i(...a){const[d,w,u]=a;if(this&&o in n(this)){const f=n(this)[o].listeners.get(d)?.get(w),m=B(u).capture?"capturingArgs":"nonCapturingArgs";f?.[m]&&(n(this)[o].instance&&n(this)[o].instance.removeEventListener(...f[m]),delete f[m])}else P(t,this,a)}Object.defineProperty(n(s.EventTarget.prototype),"removeEventListener",{value:b(i)});const{value:c}=Object.getOwnPropertyDescriptor(n(s.EventTarget.prototype),"dispatchEvent");function l(...a){return this&&o in n(this)?n(this)[o].instance?n(this)[o].instance.dispatchEvent(...a):!0:P(c,this,a)}Object.defineProperty(n(s.EventTarget.prototype),"dispatchEvent",{value:b(l)})}),G=j("Event",function(){for(const t of["target","currentTarget","originalTarget","explicitOriginalTarget","srcElement"]){let i=function(){const l=n(P(c,this,[]));return l?.[H]??l};const{get:c}=Object.getOwnPropertyDescriptor(n(s.Event.prototype),t)??{};c&&Object.defineProperty(n(s.Event.prototype),t,{get:b(i)})}const{value:r}=Object.getOwnPropertyDescriptor(n(s.Event.prototype),"composedPath");function e(){const t=n(P(r,this,[]));for(let i=0;i<t.length;i++){const c=t[i];t[i]=c?.[H]??c}return t}Object.defineProperty(n(s.Event.prototype),"composedPath",{value:b(e)})}),N=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]);function I(r,e,t,i,c){let l,a,d,w,u,f,m,k,p,h,W,O,E;for(;c>=64;){for(l=e[0],a=e[1],d=e[2],w=e[3],u=e[4],f=e[5],m=e[6],k=e[7],h=0;h<16;h++)W=i+h*4,r[h]=(t[W]&255)<<24|(t[W+1]&255)<<16|(t[W+2]&255)<<8|t[W+3]&255;for(h=16;h<64;h++)p=r[h-2],O=(p>>>17|p<<15)^(p>>>19|p<<13)^p>>>10,p=r[h-15],E=(p>>>7|p<<25)^(p>>>18|p<<14)^p>>>3,r[h]=(O+r[h-7]|0)+(E+r[h-16]|0);for(h=0;h<64;h++)O=(((u>>>6|u<<26)^(u>>>11|u<<21)^(u>>>25|u<<7))+(u&f^~u&m)|0)+(k+(N[h]+r[h]|0)|0)|0,E=((l>>>2|l<<30)^(l>>>13|l<<19)^(l>>>22|l<<10))+(l&a^l&d^a&d)|0,k=m,m=f,f=u,u=w+O|0,w=d,d=a,a=l,l=O+E|0;e[0]+=l,e[1]+=a,e[2]+=d,e[3]+=w,e[4]+=u,e[5]+=f,e[6]+=m,e[7]+=k,i+=64,c-=64}return i}class V{constructor(){this.digestLength=32,this.blockSize=64,this.state=new Int32Array(8),this.temp=new Int32Array(64),this.buffer=new Uint8Array(128),this.bufferLength=0,this.bytesHashed=0,this.finished=!1,this.reset()}reset(){return this.state[0]=1779033703,this.state[1]=3144134277,this.state[2]=1013904242,this.state[3]=2773480762,this.state[4]=1359893119,this.state[5]=2600822924,this.state[6]=528734635,this.state[7]=1541459225,this.bufferLength=0,this.bytesHashed=0,this.finished=!1,this}clean(){for(let e=0;e<this.buffer.length;e++)this.buffer[e]=0;for(let e=0;e<this.temp.length;e++)this.temp[e]=0;this.reset()}update(e,t=e.length){if(this.finished)throw new Error("SHA256: can't update because hash was finished.");let i=0;if(this.bytesHashed+=t,this.bufferLength>0){for(;this.bufferLength<64&&t>0;)this.buffer[this.bufferLength++]=e[i++],t--;this.bufferLength===64&&(I(this.temp,this.state,this.buffer,0,64),this.bufferLength=0)}for(t>=64&&(i=I(this.temp,this.state,e,i,t),t%=64);t>0;)this.buffer[this.bufferLength++]=e[i++],t--;return this}finish(e){if(!this.finished){const t=this.bytesHashed,i=this.bufferLength,c=t/536870912|0,l=t<<3,a=t%64<56?64:128;this.buffer[i]=128;for(let d=i+1;d<a-8;d++)this.buffer[d]=0;this.buffer[a-8]=c>>>24&255,this.buffer[a-7]=c>>>16&255,this.buffer[a-6]=c>>>8&255,this.buffer[a-5]=c>>>0&255,this.buffer[a-4]=l>>>24&255,this.buffer[a-3]=l>>>16&255,this.buffer[a-2]=l>>>8&255,this.buffer[a-1]=l>>>0&255,I(this.temp,this.state,this.buffer,0,a),this.finished=!0}for(let t=0;t<8;t++)e[t*4+0]=this.state[t]>>>24&255,e[t*4+1]=this.state[t]>>>16&255,e[t*4+2]=this.state[t]>>>8&255,e[t*4+3]=this.state[t]>>>0&255;return this}digest(){const e=new Uint8Array(this.digestLength);return this.finish(e),e}_saveState(e){for(let t=0;t<this.state.length;t++)e[t]=this.state[t]}_restoreState(e,t){for(let i=0;i<this.state.length;i++)this.state[i]=e[i];this.bytesHashed=t,this.finished=!1,this.bufferLength=0}}function F(r){const e=new V().update(new Uint8Array(r)),t=e.digest();return e.clean(),t}const J=j("WASM",function(r,e){const t=n(s.WebAssembly);if(!t)return;function i(y){const v=y instanceof Uint8Array?y:new Uint8Array(y),g=new s.Object;return g.alphabet="base64url",g.omitPadding=!0,v.toBase64(g)}function c(y){return r.then(({hashes:v})=>{if(!("crypto"in globalThis))return Promise.resolve(l(y));const g=a(y);return crypto.subtle.digest("SHA-256",g).then(A=>{const T=i(A);if(!v?.includes(T))throw new s.Error(`[WEBCAT] Unauthorized WebAssembly bytecode: ${T}`);return console.log(`[WEBCAT] Verified WASM (async) ${T}`),g})})}function l(y){const v=a(y),g=i(F(v));if(!e.data.hashes?.includes(g))throw new s.Error(`[WEBCAT] Unauthorized WebAssembly bytecode: ${g}`);return console.log(`[WEBCAT] Verified WASM (sync) ${g}`),v}function a(y){return s.ArrayBuffer.isView(y)?y.buffer.slice():y.slice()}const d=t.instantiate;function w(y,v,g){return y instanceof t.Module?d.call(this,y,v,g):c(y).then(A=>d.call(this,A,v,g))}b(w,t,"instantiate");const u=t.compile;function f(y,v){return c(y).then(g=>u.call(this,g,v))}b(f,t,"compile");const m=t.validate;function k(y){const v=l(y);return m.call(this,v)}b(k,t,"validate");const p=t.instantiateStreaming;function h(y,v,g){return s.Promise.resolve(y).then(A=>Promise.all([A.clone().arrayBuffer(),A.headers])).then(([A,T])=>Promise.all([c(A),T])).then(([A,T])=>p.call(this,new Response(A,{headers:T}),v,g))}b(h,t,"instantiateStreaming");const W=t.compileStreaming;function O(y,v){return s.Promise.resolve(y).then(g=>Promise.all([g.clone().arrayBuffer(),g.headers])).then(([g,A])=>Promise.all([c(g),A])).then(([g,A])=>W.call(this,new Response(g,{headers:A}),v))}b(O,t,"compileStreaming");const E=t.Module;function L(y){if(!(this instanceof L))throw new s.TypeError("[WEBCAT] Constructor WebAssembly.Module requires 'new'");const v=l(y);return new E(v)}const D=L;D.customSections=E.customSections.bind(E),D.exports=E.exports.bind(E),D.imports=E.imports.bind(E),b(D,t,"Module"),E.prototype.constructor=t.Module,t.Module.prototype=E.prototype,console.log("[WEBCAT] WebAssembly successfully hooked: all bytecode entry points now require authorization.")}),X=j("SharedWorker",function(r){if(!s.SharedWorker)return;const e=n(s.MessagePort),t=e.prototype.postMessage;function i(...k){if(o in n(this))if(n(this)[o].instance)t.call(n(this)[o].instance,...k);else{let p=k[1];if(p&&s.Symbol.iterator in p){const h=p;p=new s.Object,p.transfer=h}k[0]=s.structuredClone(k[0],p),n(this)[o].messages.push(k)}else t.call(this,...k)}b(i,e.prototype,"postMessage");const c=e.prototype.start;function l(){o in n(this)?n(this)[o].instance?c.call(n(this)[o].instance):n(this)[o].started=!0:c.call(this)}b(l,e.prototype,"start");const a=e.prototype.close;function d(){o in n(this)?n(this)[o].instance?a.call(n(this)[o].instance):n(this)[o].closed=!0:a.call(this)}b(d,e.prototype,"close"),C(e.prototype,"onmessage"),C(e.prototype,"onmessageerror");const w=n(s.SharedWorker);function u(...k){if(!(this instanceof u))throw new s.TypeError("SharedWorker constructor: 'new' is required");if(k.length===0)throw new s.TypeError("SharedWorker constructor: At least 1 argument required, but only 0 passed");const p=n(s.Object).create(w.prototype),h=n(s.Object).create(e.prototype);return h[o]=R({onmessage:null,messages:[],onmessageerror:null,started:!1,closed:!1}),p[o]=R({port:h,onerror:null}),r.then(({firstParty:W})=>{k[0]=`${k[0]}#${W}`,p[o].instance=new w(...k),p[o].instance[H]=p,x(p),h[o].instance=p[o].instance.port,h[o].instance[H]=h,x(h),h[o].started&&h[o].instance.start(),h[o].closed&&h[o].instance.close(),h[o].messages.forEach(O=>{h[o].instance?.postMessage(...O)})}),p}b(u,s,"SharedWorker"),w.prototype.constructor=n(s.SharedWorker),n(s).SharedWorker.prototype=w.prototype;const{get:f}=Object.getOwnPropertyDescriptor(w.prototype,"port");function m(){return o in this?this[o].port:f?.apply(this)}Object.defineProperty(w.prototype,"port",{get:b(m,s)}),C(w.prototype,"onerror")}),K=j("ServiceWorker",function(r,{data:e}){if(typeof e=="string")try{Object.hasOwn(s.top||{},"name");return}catch{}else if(e===!0)return;delete n((s.Navigator||s.WorkerNavigator||s.Object).prototype).serviceWorker,delete n(s).ServiceWorker,delete n(s).ServiceWorkerContainer,delete n(s).ServiceWorkerRegistration}),Q=j("Worker",function(r){if(!s.SharedWorker)return;const e=n(s.Worker),t=n(s.EventTarget),i=n(s.Reflect).construct.bind(n(s.Reflect));function c(...u){if(!(this instanceof c))throw new TypeError("Worker constructor: 'new' is required");if(u.length===0)throw new s.TypeError("Worker constructor: At least 1 argument required, but only 0 passed");const f=i(t,new s.Array,e);return f[o]=R({onmessage:null,messages:[],onerror:null}),r.then(({firstParty:m})=>{u[0]=`${u[0]}#${m}`,f[o].instance=new e(...u),f[o].instance[H]=f,f[o].terminated&&f[o].instance.terminate(),x(f),f[o].messages.forEach(k=>{f[o].instance?.postMessage(...k)})}),f}b(c,s,"Worker"),e.prototype.constructor=n(s.Worker),n(s).Worker.prototype=e.prototype;const l=e.prototype.postMessage;function a(...u){if(o in n(this))if(n(this)[o].instance)l.call(n(this)[o].instance,...u);else{let f=u[1];if(f&&s.Symbol.iterator in f){const m=f;f=new s.Object,f.transfer=m}u[0]=s.structuredClone(u[0],f),n(this)[o].messages.push(u)}else l.call(this,...u)}b(a,e.prototype,"postMessage");const d=e.prototype.terminate;function w(){o in n(this)?n(this)[o].instance?d.call(n(this)[o].instance):n(this)[o].terminated=!0:d.call(this)}b(w,e.prototype,"terminate"),C(e.prototype,"onmessage"),C(e.prototype,"onerror"),C(e.prototype,"onmessageerror")});console.log("[WEBCAT] Installing content script hook");const M="__DATA_PLACEHOLDER__";let S=window;for(;!S.location.protocol.startsWith("http")&&S.parent!==S;){try{Object.hasOwn(S.parent,"name")}catch{break}S=S.parent}S!==window?window.wrappedJSObject.WebAssembly=S.wrappedJSObject.WebAssembly:J(window,M),X(window,M),K(window,M),Q(window,M),z(window,M),G(window,M)})();
@@ -0,0 +1,86 @@
1
+ /** @inline */
2
+ type ColorScheme = "dark" | "light";
3
+ /** Properties passed to {@link PathTemplate} functions. */
4
+ export type PathTemplateProperties = {
5
+ /** The name of the resource. */
6
+ name: string;
7
+ /** The current color scheme of the browser. */
8
+ colorScheme: ColorScheme;
9
+ };
10
+ /**
11
+ * A template for a file path.
12
+ *
13
+ * @example
14
+ * const icons: PathTemplate = ({ name, colorScheme }) => `icons/${name}-${colorScheme}.png`;
15
+ */
16
+ export type PathTemplate = (p: PathTemplateProperties) => string;
17
+ /** @internal @inline */
18
+ export type IconOptions = {
19
+ /** The name of the icon. */
20
+ name?: string;
21
+ /** The title displayed in the icon's tooltip. */
22
+ title?: string;
23
+ /** The popup page to display on click. */
24
+ popup?: {
25
+ name: string;
26
+ query?: string | URLSearchParams;
27
+ fragment?: string | URLSearchParams;
28
+ };
29
+ };
30
+ /** @internal @inline */
31
+ export type BrowserChromeControllerConfig = {
32
+ /** Template for icon paths. */
33
+ iconPaths: PathTemplate;
34
+ /** Template for page paths. */
35
+ pagePaths: PathTemplate;
36
+ };
37
+ /**
38
+ * A class for interacting with browser chrome and extension internal pages.
39
+ */
40
+ export declare class BrowserChromeController {
41
+ #private;
42
+ constructor(config: BrowserChromeControllerConfig);
43
+ /**
44
+ * Determines the browser color scheme currently in use.
45
+ *
46
+ * @returns The current color scheme.
47
+ */
48
+ getColorScheme(): ColorScheme;
49
+ /**
50
+ * Computes the URL of a named page.
51
+ *
52
+ * @param name The name of the page.
53
+ * @param options
54
+ * @returns The absolute URL of the page.
55
+ */
56
+ getPageURL(name: string, options?: {
57
+ query?: string | URLSearchParams;
58
+ fragment?: string | URLSearchParams;
59
+ }): string;
60
+ /**
61
+ * Displays an icon in the browser's URL bar.
62
+ *
63
+ * @param tabId The ID of the tab to display the icon in.
64
+ * @param options
65
+ */
66
+ showIcon(tabId: number, options?: IconOptions): Promise<void>;
67
+ /**
68
+ * Hides the icon shown on a specific tab.
69
+ *
70
+ * @param tabId The ID of the tab to hide the icon from.
71
+ */
72
+ hideIcon(tabId: number): Promise<void>;
73
+ /**
74
+ * Loads a named page in the specified tab.
75
+ *
76
+ * @param tabId The ID of the tab to load the page in.
77
+ * @param name The name of the page.
78
+ * @param options
79
+ */
80
+ loadPage(tabId: number, name: string, options?: {
81
+ replace?: boolean;
82
+ query?: string | URLSearchParams;
83
+ fragment?: string | URLSearchParams;
84
+ }): Promise<void>;
85
+ }
86
+ export {};
@@ -0,0 +1,138 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+ var _iconPaths, _pagePaths;
9
+ import permissions from "./permissions.js";
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
14
+ var __typeError2 = (msg) => {
15
+ throw TypeError(msg);
16
+ };
17
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
18
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
19
+ var __decoratorStart = (base) => [, , , __create(null)];
20
+ var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
21
+ var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError2("Function expected") : fn;
22
+ var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError2("Already initialized") : fns.push(__expectFn(fn || null)) });
23
+ var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
24
+ var __runInitializers = (array, flags, self, value) => {
25
+ for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) fns[i].call(self);
26
+ return value;
27
+ };
28
+ var __decorateElement = (array, flags, name, decorators, target, extra) => {
29
+ var it, done, ctx, k = flags & 7, p = false;
30
+ var j = 0;
31
+ var extraInitializers = array[j] || (array[j] = []);
32
+ var desc = k && (target = target.prototype, k < 5 && (k > 3 || !p) && __getOwnPropDesc(target, name));
33
+ __name(target, name);
34
+ for (var i = decorators.length - 1; i >= 0; i--) {
35
+ ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
36
+ it = (0, decorators[i])(target, ctx), done._ = 1;
37
+ __expectFn(it) && (target = it);
38
+ }
39
+ return __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
40
+ };
41
+ var _BrowserChromeController_decorators, _init;
42
+ _BrowserChromeController_decorators = [permissions.require("tabs")];
43
+ class BrowserChromeController {
44
+ constructor(config) {
45
+ __privateAdd(this, _iconPaths);
46
+ __privateAdd(this, _pagePaths);
47
+ __privateSet(this, _iconPaths, config.iconPaths);
48
+ __privateSet(this, _pagePaths, config.pagePaths);
49
+ }
50
+ /**
51
+ * Determines the browser color scheme currently in use.
52
+ *
53
+ * @returns The current color scheme.
54
+ */
55
+ getColorScheme() {
56
+ if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
57
+ return "dark";
58
+ }
59
+ return "light";
60
+ }
61
+ /**
62
+ * Computes the URL of a named page.
63
+ *
64
+ * @param name The name of the page.
65
+ * @param options
66
+ * @returns The absolute URL of the page.
67
+ */
68
+ getPageURL(name, options) {
69
+ let url = browser.runtime.getURL(
70
+ __privateGet(this, _pagePaths).call(this, { name, colorScheme: this.getColorScheme() })
71
+ );
72
+ if (options?.query) {
73
+ url += `?${options.query.toString()}`;
74
+ }
75
+ if (options?.fragment) {
76
+ url += `#${options.fragment.toString()}`;
77
+ }
78
+ return url;
79
+ }
80
+ /**
81
+ * Displays an icon in the browser's URL bar.
82
+ *
83
+ * @param tabId The ID of the tab to display the icon in.
84
+ * @param options
85
+ */
86
+ async showIcon(tabId, options) {
87
+ if (tabId < 0) {
88
+ return;
89
+ }
90
+ if (options?.title) {
91
+ browser.pageAction.setTitle({ tabId, title: options.title });
92
+ }
93
+ if (options?.name) {
94
+ const path = __privateGet(this, _iconPaths).call(this, {
95
+ name: options.name,
96
+ colorScheme: this.getColorScheme()
97
+ });
98
+ await browser.pageAction.setIcon({ tabId, path });
99
+ }
100
+ if (options?.popup) {
101
+ const popup = this.getPageURL(options.popup.name, options.popup);
102
+ browser.pageAction.setPopup({ tabId, popup });
103
+ }
104
+ await browser.pageAction.show(tabId);
105
+ }
106
+ /**
107
+ * Hides the icon shown on a specific tab.
108
+ *
109
+ * @param tabId The ID of the tab to hide the icon from.
110
+ */
111
+ async hideIcon(tabId) {
112
+ await browser.pageAction.hide(tabId);
113
+ }
114
+ /**
115
+ * Loads a named page in the specified tab.
116
+ *
117
+ * @param tabId The ID of the tab to load the page in.
118
+ * @param name The name of the page.
119
+ * @param options
120
+ */
121
+ async loadPage(tabId, name, options) {
122
+ if (tabId < 0) {
123
+ return;
124
+ }
125
+ await browser.tabs.update(tabId, {
126
+ url: this.getPageURL(name, options),
127
+ loadReplace: options?.replace ?? false
128
+ });
129
+ }
130
+ }
131
+ _iconPaths = new WeakMap();
132
+ _pagePaths = new WeakMap();
133
+ _init = __decoratorStart();
134
+ BrowserChromeController = __decorateElement(_init, 0, "BrowserChromeController", _BrowserChromeController_decorators, BrowserChromeController);
135
+ __runInitializers(_init, 1, BrowserChromeController);
136
+ export {
137
+ BrowserChromeController
138
+ };
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Persistent key-value storage backed by the {@link browser.storage} API.
3
+ */
4
+ export declare class KVStore {
5
+ /**
6
+ * Reads a persisted value.
7
+ *
8
+ * @param key The key to read.
9
+ * @param area The name of the {@link browser.storage.StorageArea | storage area} to read from.
10
+ * @returns A Promise that resolves to the value read.
11
+ */
12
+ get(key: string, area?: "local" | "session"): Promise<any>;
13
+ /**
14
+ * Stores values.
15
+ *
16
+ * @param items An object consisting of one or more key/value pairs to store.
17
+ * @param area The name of the {@link browser.storage.StorageArea | storage area} to use.
18
+ */
19
+ set(items: {
20
+ [key: string]: unknown;
21
+ }, area?: "local" | "session"): Promise<void>;
22
+ /**
23
+ * Clears all values whose key matches the specified prefix.
24
+ *
25
+ * @param prefix The prefix to match against.
26
+ * @param area The name of the {@link browser.storage.StorageArea | storage area} to use.
27
+ */
28
+ clear(prefix?: string, area?: "local" | "session"): Promise<void>;
29
+ /**
30
+ * Retrieves a list of stored keys matching the specified prefix.
31
+ *
32
+ * @param prefix The prefix to match against.
33
+ * @param area The name of the {@link browser.storage.StorageArea | storage area} to read from.
34
+ * @returns A Promise that resolves to an array of matching keys.
35
+ */
36
+ getKeys(prefix?: string, area?: "local" | "session"): Promise<string[]>;
37
+ /**
38
+ * Clears a single persisted value.
39
+ *
40
+ * @param key The key to clear.
41
+ * @param area The name of the {@link browser.storage.StorageArea | storage area} to use.
42
+ */
43
+ remove(key: string, area?: "local" | "session"): Promise<void>;
44
+ }
45
+ /**
46
+ * Namespaced key-value storage. Operations are atomic within
47
+ * an instance; distinct instances of the same namespace may
48
+ * access the same data in an unsafe manner.
49
+ */
50
+ export declare class NamespacedKVStore implements KVStore {
51
+ #private;
52
+ /**
53
+ * @param namespace The namespace prefix to use for this store.
54
+ * @param store A backing {@link KVStore} instance to use for persistence.
55
+ */
56
+ constructor(namespace: string, store?: KVStore);
57
+ get(key: string, area?: "local" | "session"): Promise<any>;
58
+ set(items: {
59
+ [key: string]: unknown;
60
+ }, area?: "local" | "session"): Promise<void>;
61
+ clear(prefix?: string, area?: "local" | "session"): Promise<void>;
62
+ getKeys(prefix?: string, area?: "local" | "session"): Promise<string[]>;
63
+ remove(key: string, area?: "local" | "session"): Promise<void>;
64
+ /**
65
+ * Creates a new subnamespace within this namespace.
66
+ *
67
+ * @param namespace A new namespace prefix to append to the existing prefix.
68
+ */
69
+ namespace(namespace: string): NamespacedKVStore;
70
+ }