diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 91% rename from .eslintrc.js rename to .eslintrc.cjs index b751ebc8c42..7e70255af37 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -49,6 +49,22 @@ module.exports = { }, ], + "no-restricted-properties": [ + "error", + { + object: "window", + property: "setImmediate", + message: "Use setTimeout instead.", + }, + ], + "no-restricted-globals": [ + "error", + { + name: "setImmediate", + message: "Use setTimeout instead.", + }, + ], + "import/no-restricted-paths": [ "error", { diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 10870d97175..830c31be497 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,6 +2,7 @@ /.github/workflows/** @matrix-org/element-web-team /package.json @matrix-org/element-web-team /yarn.lock @matrix-org/element-web-team +/scripts/** @matrix-org/element-web-team /src/webrtc @matrix-org/element-call-reviewers /src/matrixrtc @matrix-org/element-call-reviewers /spec/*/webrtc @matrix-org/element-call-reviewers diff --git a/.github/actions/sign-release-tarball/action.yml b/.github/actions/sign-release-tarball/action.yml index e249b92dd09..1ac666c4008 100644 --- a/.github/actions/sign-release-tarball/action.yml +++ b/.github/actions/sign-release-tarball/action.yml @@ -22,7 +22,7 @@ runs: - name: Upload tarball signature if: ${{ inputs.upload-url }} - uses: shogo82148/actions-upload-release-asset@8f032eff0255912cc9c8455797fd6d72f25c7ab7 # v1 + uses: shogo82148/actions-upload-release-asset@6d4fd50e333ee797e83ae380e6bc55b048baec41 # v1 with: upload_url: ${{ inputs.upload-url }} asset_path: ${{ env.VERSION }}.tar.gz.asc diff --git a/.github/actions/upload-release-assets/action.yml b/.github/actions/upload-release-assets/action.yml index b11be5a8a86..ef95a4a891e 100644 --- a/.github/actions/upload-release-assets/action.yml +++ b/.github/actions/upload-release-assets/action.yml @@ -29,13 +29,13 @@ runs: - name: Upload asset signatures if: inputs.gpg-fingerprint - uses: shogo82148/actions-upload-release-asset@8f032eff0255912cc9c8455797fd6d72f25c7ab7 # v1 + uses: shogo82148/actions-upload-release-asset@6d4fd50e333ee797e83ae380e6bc55b048baec41 # v1 with: upload_url: ${{ inputs.upload-url }} asset_path: ${{ inputs.asset-path }}.asc - name: Upload assets - uses: shogo82148/actions-upload-release-asset@8f032eff0255912cc9c8455797fd6d72f25c7ab7 # v1 + uses: shogo82148/actions-upload-release-asset@6d4fd50e333ee797e83ae380e6bc55b048baec41 # v1 with: upload_url: ${{ inputs.upload-url }} asset_path: ${{ inputs.asset-path }} diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 00000000000..88fecb62ea6 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,43 @@ +- name: "A-Element-R" + description: "Issues affecting the port of Element's crypto layer to Rust" + color: "bfd4f2" +- name: "A-Packaging" + description: "Packaging, signing, releasing" + color: "bfd4f2" +- name: "A-Technical-Debt" + color: "bfd4f2" +- name: "A-Testing" + description: "Testing, code coverage, etc." + color: "bfd4f2" +- name: "backport staging" + description: "Label to automatically backport PR to staging branch" + color: "B60205" +- name: "Dependencies" + description: "Pull requests that update a dependency file" + color: "0366d6" +- name: "Easy" + color: "5dc9f7" +- name: "Sponsored" + color: "ffc8f4" +- name: "T-Deprecation" + description: "A pull request that makes something deprecated" + color: "98e6ae" +- name: "T-Other" + description: "Questions, user support, anything else" + color: "98e6ae" +- name: "X-Blocked" + color: "ff7979" +- name: "X-Breaking-Change" + color: "ff7979" +- name: "X-Reverted" + description: "PR has been reverted" + color: "F68AA3" +- name: "X-Upcoming-Release-Blocker" + description: "This does not affect the current release cycle but will affect the next one" + color: "e99695" +- name: "Z-Community-PR" + description: "Issue is solved by a community member's PR" + color: "ededed" +- name: "Z-Flaky-Test" + description: "A test is raising false alarms" + color: "ededed" diff --git a/.github/workflows/release-drafter-workflow.yml b/.github/workflows/release-drafter-workflow.yml index b61bce064a9..052d8473912 100644 --- a/.github/workflows/release-drafter-workflow.yml +++ b/.github/workflows/release-drafter-workflow.yml @@ -56,7 +56,7 @@ jobs: script: | const { RELEASE_ID: releaseId, DEPENDENCY, VERSION } = process.env; const { owner, repo } = context.repo; - const script = require("./.action-repo/scripts/release/merge-release-notes.js"); + const script = require("./.action-repo/scripts/release/merge-release-notes.cjs"); let deps = []; if (DEPENDENCY.includes("/")) { diff --git a/.github/workflows/release-gitflow.yml b/.github/workflows/release-gitflow.yml index b82c61aec3c..05e16a6b236 100644 --- a/.github/workflows/release-gitflow.yml +++ b/.github/workflows/release-gitflow.yml @@ -34,6 +34,7 @@ jobs: - uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: Install Deps run: "yarn install --frozen-lockfile" diff --git a/.github/workflows/release-make.yml b/.github/workflows/release-make.yml index 87419f03352..831055a0030 100644 --- a/.github/workflows/release-make.yml +++ b/.github/workflows/release-make.yml @@ -24,10 +24,6 @@ on: description: List of github projects (owner/repo) which should have their dependency bumped to the newly released version (in JSON string array string syntax) type: string required: false - include-changes: - description: Project to include changelog entries from in this release. - type: string - required: false gpg-fingerprint: description: Fingerprint of the GPG key to use for signing the git tag and assets, if any. type: string @@ -120,6 +116,7 @@ jobs: - uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: Install dependencies run: "yarn install --frozen-lockfile" @@ -319,6 +316,11 @@ jobs: ref: staging token: ${{ secrets.ELEMENT_BOT_TOKEN }} + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + - name: Bump dependency env: DEPENDENCY: ${{ needs.npm.outputs.id }} diff --git a/.github/workflows/release-npm.yml b/.github/workflows/release-npm.yml index eda19b442c1..905d9c2bc06 100644 --- a/.github/workflows/release-npm.yml +++ b/.github/workflows/release-npm.yml @@ -25,6 +25,7 @@ jobs: with: cache: "yarn" registry-url: "https://registry.npmjs.org" + node-version-file: package.json - name: 🔨 Install dependencies run: "yarn install --frozen-lockfile" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7cf7044b280..cdd54d29c78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,6 +43,7 @@ jobs: uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: 🔨 Install dependencies run: "yarn install --frozen-lockfile" diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 016dfa7c219..7507f9d8528 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -30,7 +30,7 @@ jobs: target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - name: "🧮 Checkout code" - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 with: repository: ${{ github.event.workflow_run.head_repository.full_name }} ref: ${{ github.event.workflow_run.head_branch }} # checkout commit that triggered this workflow diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 0dbcf4a2678..128626620a9 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -18,6 +18,7 @@ jobs: - uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: Install Deps run: "yarn install" @@ -44,6 +45,7 @@ jobs: - uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: Install Deps run: "yarn install" @@ -60,6 +62,7 @@ jobs: - uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: Install Deps run: "yarn install --frozen-lockfile" @@ -76,12 +79,13 @@ jobs: - uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: Install Deps run: "yarn install" - name: Generate Docs - run: "yarn run gendoc --treatWarningsAsErrors" + run: "yarn run gendoc --treatWarningsAsErrors --suppressCommentWarningsInDeclarationFiles" - name: Upload Artifact uses: actions/upload-artifact@v4 @@ -100,6 +104,7 @@ jobs: - uses: actions/setup-node@v4 with: cache: "yarn" + node-version-file: package.json - name: Install Deps run: "yarn install --frozen-lockfile" diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 00000000000..bb22292a64f --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,21 @@ +name: Sync labels +on: + workflow_dispatch: {} + schedule: + - cron: "0 1 * * *" # 1am every day + push: + branches: + - develop + paths: + - .github/labels.yml +jobs: + sync-labels: + uses: element-hq/element-meta/.github/workflows/sync-labels.yml@develop + with: + LABELS: | + element-hq/element-meta + .github/labels.yml + DELETE: true + WET: true + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 83e770fe71d..dc8adca6d26 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: specs: [integ, unit] - node: [18, "lts/*", 21] + node: ["lts/*", 22] steps: - name: Checkout code uses: actions/checkout@v4 @@ -63,6 +63,16 @@ jobs: coverage !coverage/lcov-report + # Dummy completion job to simplify branch protections + jest-complete: + name: Jest tests + needs: jest + if: always() + runs-on: ubuntu-latest + steps: + - if: needs.jest.result != 'skipped' && needs.jest.result != 'success' + run: exit 1 + matrix-react-sdk: name: Downstream test matrix-react-sdk if: github.event_name == 'merge_group' diff --git a/.prettierrc.js b/.prettierrc.cjs similarity index 100% rename from .prettierrc.js rename to .prettierrc.cjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c190ae9c67..d85bce05a0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,109 @@ +Changes in [34.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.5.0) (2024-09-10) +================================================================================================== +## 🦖 Deprecations + +* Deprecate unused callback hooks `CryptoCallbacks.onSecretRequested` and `CryptoCallbacks.getDehydrationKey` ([#4376](https://github.com/matrix-org/matrix-js-sdk/pull/4376)). Contributed by @richvdh. + + +Changes in [34.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.4.0) (2024-08-27) +================================================================================================== +## ✨ Features + +* Use non-legacy calls if any are found ([#4337](https://github.com/matrix-org/matrix-js-sdk/pull/4337)). Contributed by @AndrewFerr. + +## 🐛 Bug Fixes + +* Retry event decryption failures on first failure ([#4346](https://github.com/matrix-org/matrix-js-sdk/pull/4346)). Contributed by @hughns. +* Ensure "type" = "module" ES declaration in pre-release.sh ([#4350](https://github.com/matrix-org/matrix-js-sdk/pull/4350)). Contributed by @BLCK-B. +* Handle MatrixRTC encryption keys arriving out of order ([#4345](https://github.com/matrix-org/matrix-js-sdk/pull/4345)). Contributed by @hughns. +* Resend MatrixRTC encryption keys if a membership has changed ([#4343](https://github.com/matrix-org/matrix-js-sdk/pull/4343)). Contributed by @hughns. + + +Changes in [34.3.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.3.1) (2024-08-20) +================================================================================================== +# Security +- Fixes for [CVE-2024-42369](https://nvd.nist.gov/vuln/detail/CVE-2024-42369) / [GHSA-vhr5-g3pm-49fm](https://github.com/matrix-org/matrix-js-sdk/security/advisories/GHSA-vhr5-g3pm-49fm). + +Changes in [34.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.3.0) (2024-08-13) +================================================================================================== +## ✨ Features + +* Bump matrix-widget-api ([#4336](https://github.com/matrix-org/matrix-js-sdk/pull/4336)). Contributed by @AndrewFerr. +* Also check for MSC3757 for session state keys ([#4334](https://github.com/matrix-org/matrix-js-sdk/pull/4334)). Contributed by @AndrewFerr. +* Support Futures via widgets ([#4311](https://github.com/matrix-org/matrix-js-sdk/pull/4311)). Contributed by @AndrewFerr. +* Support MSC4140: Delayed events (Futures) ([#4294](https://github.com/matrix-org/matrix-js-sdk/pull/4294)). Contributed by @AndrewFerr. +* Handle late-arriving `m.room_key.withheld` messages ([#4310](https://github.com/matrix-org/matrix-js-sdk/pull/4310)). Contributed by @richvdh. +* Be specific about what is considered a MSC4143 call member event. ([#4328](https://github.com/matrix-org/matrix-js-sdk/pull/4328)). Contributed by @toger5. +* Add index.ts for matrixrtc module ([#4314](https://github.com/matrix-org/matrix-js-sdk/pull/4314)). Contributed by @toger5. + +## 🐛 Bug Fixes + +* Fix hashed ID server lookups with no Olm ([#4333](https://github.com/matrix-org/matrix-js-sdk/pull/4333)). Contributed by @dbkr. + + +Changes in [34.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.2.0) (2024-07-30) +================================================================================================== +## 🐛 Bug Fixes + +* Element-R: detect "withheld key" UTD errors, and mark them as such ([#4302](https://github.com/matrix-org/matrix-js-sdk/pull/4302)). Contributed by @richvdh. + + +Changes in [34.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.1.0) (2024-07-16) +================================================================================================== +## ✨ Features + +* Add ability to choose how many timeline events to sync when peeking ([#4300](https://github.com/matrix-org/matrix-js-sdk/pull/4300)). Contributed by @jgarplind. +* Remove redundant hack for using the old pickle key in rust crypto ([#4282](https://github.com/matrix-org/matrix-js-sdk/pull/4282)). Contributed by @richvdh. +* Add fetching the well known in embedded mode. ([#4259](https://github.com/matrix-org/matrix-js-sdk/pull/4259)). Contributed by @toger5. + +## 🐛 Bug Fixes + +* Fix room state being updated with old (now overwritten) state and emitting for those updates. ([#4242](https://github.com/matrix-org/matrix-js-sdk/pull/4242)). Contributed by @toger5. +* Fix incorrect "Olm is not available" errors ([#4301](https://github.com/matrix-org/matrix-js-sdk/pull/4301)). Contributed by @richvdh. +* Fix build for example script ([#4286](https://github.com/matrix-org/matrix-js-sdk/pull/4286)). Contributed by @richvdh. +* Declare matrix-js-sdk as an ES module ([#4285](https://github.com/matrix-org/matrix-js-sdk/pull/4285)). Contributed by @richvdh. + + +Changes in [34.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.0.0) (2024-07-08) +================================================================================================== +## 🚨 BREAKING CHANGES + +* Fetch capabilities in the background ([#4246](https://github.com/matrix-org/matrix-js-sdk/pull/4246)). Contributed by @dbkr. + +## ✨ Features + +* Prefix the user+device state key if needed ([#4262](https://github.com/matrix-org/matrix-js-sdk/pull/4262)). Contributed by @AndrewFerr. +* Use legacy call membership if anyone else is ([#4260](https://github.com/matrix-org/matrix-js-sdk/pull/4260)). Contributed by @AndrewFerr. +* Fetch capabilities in the background ([#4246](https://github.com/matrix-org/matrix-js-sdk/pull/4246)). Contributed by @dbkr. +* Use server name instead of homeserver url to allow well-known lookups during QR OIDC reciprocation ([#4233](https://github.com/matrix-org/matrix-js-sdk/pull/4233)). Contributed by @t3chguy. +* Add via parameter for MSC4156 ([#4247](https://github.com/matrix-org/matrix-js-sdk/pull/4247)). Contributed by @Johennes. +* Make the js-sdk compatible with MSC preferred foci and active focus. ([#4195](https://github.com/matrix-org/matrix-js-sdk/pull/4195)). Contributed by @toger5. +* Replace usages of setImmediate with setTimeout for wider compatibility ([#4240](https://github.com/matrix-org/matrix-js-sdk/pull/4240)). Contributed by @t3chguy. + +## 🐛 Bug Fixes + +* [Backport staging] Fix "Unable to restore session" error ([#4299](https://github.com/matrix-org/matrix-js-sdk/pull/4299)). Contributed by @RiotRobot. +* [Backport staging] Fix error when sending encrypted messages in large rooms ([#4297](https://github.com/matrix-org/matrix-js-sdk/pull/4297)). Contributed by @RiotRobot. +* Element-R: Fix resource leaks in verification logic ([#4263](https://github.com/matrix-org/matrix-js-sdk/pull/4263)). Contributed by @richvdh. +* Upgrade Rust Crypto SDK to 6.1.0 ([#4261](https://github.com/matrix-org/matrix-js-sdk/pull/4261)). Contributed by @richvdh. +* Correctly transform base64 with multiple instances of + or / ([#4252](https://github.com/matrix-org/matrix-js-sdk/pull/4252)). Contributed by @robintown. +* Work around spec bug for m.room.avatar state event content type ([#4245](https://github.com/matrix-org/matrix-js-sdk/pull/4245)). Contributed by @t3chguy. + + +Changes in [33.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v33.1.0) (2024-06-18) +================================================================================================== +## ✨ Features + +* MSC4108 support OIDC QR code login ([#4134](https://github.com/matrix-org/matrix-js-sdk/pull/4134)). Contributed by @t3chguy. +* Add crypto methods for export and import of secrets bundle ([#4227](https://github.com/matrix-org/matrix-js-sdk/pull/4227)). Contributed by @t3chguy. + +## 🐛 Bug Fixes + +* Fix screen sharing in recent Chrome ([#4243](https://github.com/matrix-org/matrix-js-sdk/pull/4243)). Contributed by @RiotRobot. +* Fix incorrect assumptions about required fields in /search response ([#4228](https://github.com/matrix-org/matrix-js-sdk/pull/4228)). Contributed by @t3chguy. +* Fix the queueToDevice tests for the new fakeindexeddb ([#4225](https://github.com/matrix-org/matrix-js-sdk/pull/4225)). Contributed by @dbkr. + + Changes in [33.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v33.0.0) (2024-06-04) ================================================================================================== ## 🚨 BREAKING CHANGES diff --git a/README.md b/README.md index f958333276d..338012c9f50 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ client.publicRooms(function (err, data) { ``` See below for how to include libolm to enable end-to-end-encryption. Please check -[the Node.js terminal app](examples/node) for a more complex example. +[the Node.js terminal app](examples/node/README.md) for a more complex example. To start the client: @@ -95,7 +95,7 @@ Object.keys(client.store.rooms).forEach((roomId) => { ## Authenticated media -Servers supporting [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916) will require clients, like +Servers supporting [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916) (Matrix 1.11) will require clients, like yours, to include an `Authorization` header when `/download`ing or `/thumbnail`ing media. For NodeJS environments this may be as easy as the following code snippet, though web browsers may need to use [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) to append the header when using the endpoints in `` elements and similar. diff --git a/babel.config.cjs b/babel.config.cjs new file mode 100644 index 00000000000..d5c314af157 --- /dev/null +++ b/babel.config.cjs @@ -0,0 +1,35 @@ +module.exports = { + sourceMaps: true, + presets: [ + [ + "@babel/preset-env", + { + targets: { + esmodules: true, + }, + // We want to output ES modules for the final build (mostly to ensure that + // async imports work correctly). However, jest doesn't support ES modules very + // well yet (see https://github.com/jestjs/jest/issues/9430), so we use commonjs + // when testing. + modules: process.env.NODE_ENV === "test" ? "commonjs" : false, + }, + ], + [ + "@babel/preset-typescript", + { + // When using the transpiled javascript in `lib`, Node.js requires `.js` extensions on any `import` + // specifiers. However, Jest uses the TS source (via babel) and fails to resolve the `.js` names. + // To resolve this,we use the `.ts` names in the source, and rewrite the `import` specifiers to use + // `.js` during transpilation, *except* when we are targetting Jest. + rewriteImportExtensions: process.env.NODE_ENV !== "test", + }, + ], + ], + plugins: [ + "@babel/plugin-transform-numeric-separator", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-object-rest-spread", + "@babel/plugin-syntax-dynamic-import", + "@babel/plugin-transform-runtime", + ], +}; diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 6b39ec8271b..00000000000 --- a/babel.config.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - sourceMaps: true, - presets: [ - [ - "@babel/preset-env", - { - targets: { - esmodules: true, - }, - // We want to output ES modules for the final build (mostly to ensure that - // async imports work correctly). However, jest doesn't support ES modules very - // well yet (see https://github.com/jestjs/jest/issues/9430), so we use commonjs - // when testing. - modules: process.env.NODE_ENV === "test" ? "commonjs" : false, - }, - ], - "@babel/preset-typescript", - ], - plugins: [ - "@babel/plugin-proposal-numeric-separator", - "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-object-rest-spread", - "@babel/plugin-syntax-dynamic-import", - "@babel/plugin-transform-runtime", - ], -}; diff --git a/examples/node/package.json b/examples/node/package.json index dc81b0e0071..130fad9214e 100644 --- a/examples/node/package.json +++ b/examples/node/package.json @@ -3,12 +3,10 @@ "version": "0.0.0", "description": "", "main": "app.js", - "scripts": { - "preinstall": "npm install ../.." - }, "author": "", "license": "Apache 2.0", "dependencies": { - "cli-color": "^1.0.0" + "cli-color": "^1.0.0", + "matrix-js-sdk": "^32.0.0" } } diff --git a/jest.config.ts b/jest.config.ts index d541b67a06b..1e6833a586d 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -39,7 +39,7 @@ if (env["GITHUB_ACTIONS"] !== undefined) { // if we're running against the develop branch, also enable the slow test reporter if (env["GITHUB_REF"] == "refs/heads/develop") { - reporters.push("/spec/slowReporter.js"); + reporters.push("/spec/slowReporter.cjs"); } config.reporters = reporters; } diff --git a/package.json b/package.json index 9011449fb29..93b5d36f183 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "matrix-js-sdk", - "version": "33.0.0", + "version": "34.5.0", "description": "Matrix Client-Server SDK for Javascript", "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "scripts": { "prepack": "yarn build", @@ -31,13 +31,10 @@ "keywords": [ "matrix-org" ], + "type": "module", "main": "./lib/index.js", "browser": "./lib/browser-index.js", - "matrix_src_main": "./src/index.ts", - "matrix_src_browser": "./src/browser-index.ts", - "matrix_lib_main": "./lib/index.js", - "matrix_lib_browser": "./lib/browser-index.js", - "matrix_lib_typings": "./lib/index.d.ts", + "typings": "./lib/index.d.ts", "author": "matrix.org", "license": "Apache-2.0", "files": [ @@ -53,19 +50,20 @@ ], "dependencies": { "@babel/runtime": "^7.12.5", - "@matrix-org/matrix-sdk-crypto-wasm": "^5.0.0", + "@matrix-org/matrix-sdk-crypto-wasm": "^7.0.0", + "@matrix-org/olm": "3.2.15", "another-json": "^0.2.0", - "bs58": "^5.0.0", + "bs58": "^6.0.0", "content-type": "^1.0.4", "jwt-decode": "^4.0.0", "loglevel": "^1.7.1", "matrix-events-sdk": "0.0.1", - "matrix-widget-api": "^1.6.0", + "matrix-widget-api": "^1.8.2", "oidc-client-ts": "^3.0.1", "p-retry": "4", "sdp-transform": "^2.14.1", "unhomoglyph": "^1.0.6", - "uuid": "9" + "uuid": "10" }, "devDependencies": { "@action-validator/cli": "^0.6.0", @@ -74,41 +72,38 @@ "@babel/core": "^7.12.10", "@babel/eslint-parser": "^7.12.10", "@babel/eslint-plugin": "^7.12.10", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-numeric-separator": "^7.12.7", - "@babel/plugin-proposal-object-rest-spread": "^7.12.1", "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-class-properties": "^7.12.1", + "@babel/plugin-transform-numeric-separator": "^7.12.7", + "@babel/plugin-transform-object-rest-spread": "^7.12.1", "@babel/plugin-transform-runtime": "^7.12.10", "@babel/preset-env": "^7.12.11", "@babel/preset-typescript": "^7.12.7", "@casualbot/jest-sonar-reporter": "2.2.7", - "@matrix-org/olm": "3.2.15", "@peculiar/webcrypto": "^1.4.5", "@types/bs58": "^4.0.1", "@types/content-type": "^1.1.5", "@types/debug": "^4.1.7", - "@types/domexception": "^4.0.0", "@types/jest": "^29.0.0", "@types/node": "18", "@types/sdp-transform": "^2.4.5", - "@types/uuid": "9", + "@types/uuid": "10", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", "babel-jest": "^29.0.0", "debug": "^4.3.4", - "domexception": "^4.0.0", "eslint": "8.57.0", "eslint-config-google": "^0.14.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-typescript": "^3.5.1", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jest": "^28.0.0", - "eslint-plugin-jsdoc": "^48.0.0", + "eslint-plugin-jsdoc": "^50.0.0", "eslint-plugin-matrix-org": "^1.0.0", - "eslint-plugin-tsdoc": "^0.2.17", - "eslint-plugin-unicorn": "^53.0.0", + "eslint-plugin-tsdoc": "^0.3.0", + "eslint-plugin-unicorn": "^55.0.0", "fake-indexeddb": "^5.0.2", - "fetch-mock": "9.11.0", + "fetch-mock": "11.1.1", "fetch-mock-jest": "^1.5.1", "husky": "^9.0.0", "jest": "^29.0.0", @@ -119,19 +114,18 @@ "lint-staged": "^15.0.2", "matrix-mock-request": "^2.5.0", "node-fetch": "^2.7.0", - "prettier": "3.2.5", - "rimraf": "^5.0.0", + "prettier": "3.3.3", + "rimraf": "^6.0.0", "ts-node": "^10.9.2", - "typedoc": "^0.25.10", + "typedoc": "^0.26.0", "typedoc-plugin-coverage": "^3.0.0", "typedoc-plugin-mdn-links": "^3.0.3", - "typedoc-plugin-missing-exports": "^2.0.0", + "typedoc-plugin-missing-exports": "^3.0.0", "typescript": "^5.3.3" }, "@casualbot/jest-sonar-reporter": { "outputDirectory": "coverage", "outputName": "jest-sonar-report.xml", "relativePaths": true - }, - "typings": "./lib/index.d.ts" + } } diff --git a/scripts/release/merge-release-notes.js b/scripts/release/merge-release-notes.cjs similarity index 99% rename from scripts/release/merge-release-notes.js rename to scripts/release/merge-release-notes.cjs index 06228492392..c1aaed7ef73 100755 --- a/scripts/release/merge-release-notes.js +++ b/scripts/release/merge-release-notes.cjs @@ -112,7 +112,14 @@ const main = async ({ github, releaseId, dependencies }) => { const { GITHUB_REPOSITORY } = process.env; const [owner, repo] = GITHUB_REPOSITORY.split("/"); + const { data: release } = await github.rest.repos.getRelease({ + owner, + repo, + release_id: releaseId, + }); + const sections = Object.fromEntries(categories.map((cat) => [cat, []])); + parseReleaseNotes(release.body, sections); for (const dependency of dependencies) { const releases = await getReleases(github, dependency); for (const release of releases) { @@ -120,12 +127,6 @@ const main = async ({ github, releaseId, dependencies }) => { } } - const { data: release } = await github.rest.repos.getRelease({ - owner, - repo, - release_id: releaseId, - }); - const intro = release.body.split(HEADING_PREFIX, 2)[0].trim(); let output = ""; diff --git a/scripts/switch_package_to_release.cjs b/scripts/switch_package_to_release.cjs new file mode 100755 index 00000000000..6d857a4070a --- /dev/null +++ b/scripts/switch_package_to_release.cjs @@ -0,0 +1,18 @@ +#!/usr/bin/env node + +const fsProm = require("fs/promises"); + +const PKGJSON = "package.json"; + +async function main() { + const pkgJson = JSON.parse(await fsProm.readFile(PKGJSON, "utf8")); + for (const field of ["main", "typings"]) { + if (pkgJson["matrix_lib_" + field] !== undefined) { + pkgJson[field] = pkgJson["matrix_lib_" + field]; + } + } + + await fsProm.writeFile(PKGJSON, JSON.stringify(pkgJson, null, 2)); +} + +main(); diff --git a/scripts/switch_package_to_release.js b/scripts/switch_package_to_release.js deleted file mode 100755 index 2ef9bb09cb2..00000000000 --- a/scripts/switch_package_to_release.js +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node - -const fsProm = require("fs/promises"); - -const PKGJSON = "package.json"; - -async function main() { - const pkgJson = JSON.parse(await fsProm.readFile(PKGJSON, "utf8")); - for (const field of ["main", "typings"]) { - if (pkgJson["matrix_lib_" + field] !== undefined) { - pkgJson[field] = pkgJson["matrix_lib_" + field]; - } - } - await fsProm.writeFile(PKGJSON, JSON.stringify(pkgJson, null, 2)); -} - -main(); diff --git a/scripts/switch_package_to_release.js b/scripts/switch_package_to_release.js new file mode 120000 index 00000000000..27f1619c9a2 --- /dev/null +++ b/scripts/switch_package_to_release.js @@ -0,0 +1 @@ +switch_package_to_release.cjs \ No newline at end of file diff --git a/spec/integ/crypto/crypto.spec.ts b/spec/integ/crypto/crypto.spec.ts index 50b5f4dea05..c1a665e2c06 100644 --- a/spec/integ/crypto/crypto.spec.ts +++ b/spec/integ/crypto/crypto.spec.ts @@ -19,7 +19,7 @@ import anotherjson from "another-json"; import fetchMock from "fetch-mock-jest"; import "fake-indexeddb/auto"; import { IDBFactory } from "fake-indexeddb"; -import { MockResponse, MockResponseFunction } from "fetch-mock"; +import FetchMock from "fetch-mock"; import Olm from "@matrix-org/olm"; import * as testUtils from "../../test-utils/test-utils"; @@ -157,7 +157,7 @@ async function expectSendRoomKey( return await new Promise((resolve) => { fetchMock.putOnce( new RegExp("/sendToDevice/m.room.encrypted/"), - (url: string, opts: RequestInit): MockResponse => { + (url: string, opts: RequestInit): FetchMock.MockResponse => { const content = JSON.parse(opts.body as string); resolve(onSendRoomKey(content)); return {}; @@ -291,7 +291,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, * @param response - the response to return from the request. Normally an {@link IClaimOTKsResult} * (or a function that returns one). */ - function expectAliceKeyClaim(response: MockResponse | MockResponseFunction) { + function expectAliceKeyClaim(response: FetchMock.MockResponse | FetchMock.MockResponseFunction) { const rootRegexp = escapeRegExp(new URL("/_matrix/client/", aliceClient.getHomeserverUrl()).toString()); fetchMock.postOnce(new RegExp(rootRegexp + "(r0|v3)/keys/claim"), response); } @@ -630,6 +630,27 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, expect(ev.decryptionFailureReason).toEqual(DecryptionFailureCode.HISTORICAL_MESSAGE_USER_NOT_JOINED); }); + newBackendOnly( + "fails with NOT_JOINED if user is not member of room (MSC4115 unstable prefix)", + async () => { + fetchMock.get("path:/_matrix/client/v3/room_keys/version", { + status: 404, + body: { errcode: "M_NOT_FOUND", error: "No current backup version." }, + }); + expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); + await startClientAndAwaitFirstSync(); + + const ev = await sendEventAndAwaitDecryption({ + unsigned: { + [UNSIGNED_MEMBERSHIP_FIELD.altName!]: "leave", + }, + }); + expect(ev.decryptionFailureReason).toEqual( + DecryptionFailureCode.HISTORICAL_MESSAGE_USER_NOT_JOINED, + ); + }, + ); + newBackendOnly( "fails with another error when the server reports user was a member of the room", async () => { @@ -654,6 +675,30 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, }, ); + newBackendOnly( + "fails with another error when the server reports user was a member of the room (MSC4115 unstable prefix)", + async () => { + // This tests that when the server reports that the user + // was invited at the time the event was sent, then we + // don't get a HISTORICAL_MESSAGE_USER_NOT_JOINED error, + // and instead get some other error, since the user should + // have gotten the key for the event. + fetchMock.get("path:/_matrix/client/v3/room_keys/version", { + status: 404, + body: { errcode: "M_NOT_FOUND", error: "No current backup version." }, + }); + expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); + await startClientAndAwaitFirstSync(); + + const ev = await sendEventAndAwaitDecryption({ + unsigned: { + [UNSIGNED_MEMBERSHIP_FIELD.altName!]: "invite", + }, + }); + expect(ev.decryptionFailureReason).toEqual(DecryptionFailureCode.HISTORICAL_MESSAGE_NO_KEY_BACKUP); + }, + ); + newBackendOnly( "fails with another error when the server reports user was a member of the room", async () => { @@ -676,6 +721,29 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, expect(ev.decryptionFailureReason).toEqual(DecryptionFailureCode.HISTORICAL_MESSAGE_NO_KEY_BACKUP); }, ); + + newBackendOnly( + "fails with another error when the server reports user was a member of the room (MSC4115 unstable prefix)", + async () => { + // This tests that when the server reports the user's + // membership, and reports that the user was joined, then we + // don't get a HISTORICAL_MESSAGE_USER_NOT_JOINED error, and + // instead get some other error. + fetchMock.get("path:/_matrix/client/v3/room_keys/version", { + status: 404, + body: { errcode: "M_NOT_FOUND", error: "No current backup version." }, + }); + expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); + await startClientAndAwaitFirstSync(); + + const ev = await sendEventAndAwaitDecryption({ + unsigned: { + [UNSIGNED_MEMBERSHIP_FIELD.altName!]: "join", + }, + }); + expect(ev.decryptionFailureReason).toEqual(DecryptionFailureCode.HISTORICAL_MESSAGE_NO_KEY_BACKUP); + }, + ); }); it("Decryption fails with Unable to decrypt for other errors", async () => { @@ -1351,7 +1419,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, fetchMock.putOnce( { url: new RegExp("/send/"), name: "send-event" }, - (url: string, opts: RequestInit): MockResponse => { + (url: string, opts: RequestInit): FetchMock.MockResponse => { const content = JSON.parse(opts.body as string); logger.log("/send:", content); // make sure that a new session is used @@ -1416,7 +1484,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, // mark the device as known, and resend. aliceClient.setDeviceKnown(aliceClient.getUserId()!, "DEVICE_ID"); - expectAliceKeyClaim((url: string, opts: RequestInit): MockResponse => { + expectAliceKeyClaim((url: string, opts: RequestInit): FetchMock.MockResponse => { const content = JSON.parse(opts.body as string); expect(content.one_time_keys[aliceClient.getUserId()!].DEVICE_ID).toEqual("signed_curve25519"); return getTestKeysClaimResponse(aliceClient.getUserId()!); @@ -2112,11 +2180,11 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, const inboundGroupSessionPromise = expectSendRoomKey("@bob:xyz", testOlmAccount); // ... and finally, send the room key. We block the response until `sendRoomMessageDefer` completes. - const sendRoomMessageDefer = defer(); + const sendRoomMessageDefer = defer(); const reqProm = new Promise((resolve) => { fetchMock.putOnce( new RegExp("/send/m.room.encrypted/"), - async (url: string, opts: RequestInit): Promise => { + async (url: string, opts: RequestInit): Promise => { resolve(JSON.parse(opts.body as string)); return await sendRoomMessageDefer.promise; }, @@ -2265,8 +2333,84 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, }); describe("m.room_key.withheld handling", () => { - // TODO: there are a bunch more tests for this sort of thing in spec/unit/crypto/algorithms/megolm.spec.ts. - // They should be converted to integ tests and moved. + describe.each([ + ["m.blacklisted", "The sender has blocked you.", DecryptionFailureCode.MEGOLM_KEY_WITHHELD], + [ + "m.unverified", + "The sender has disabled encrypting to unverified devices.", + DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE, + ], + ])( + "Decryption fails with withheld error if a withheld notice with code '%s' is received", + (withheldCode, expectedMessage, expectedErrorCode) => { + it.each(["before", "after"])("%s the event", async (when) => { + expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); + await startClientAndAwaitFirstSync(); + + // A promise which resolves, with the MatrixEvent which wraps the event, once the decryption fails. + let awaitDecryption = emitPromise(aliceClient, MatrixEventEvent.Decrypted); + + // Send Alice an encrypted room event which looks like it was encrypted with a megolm session + async function sendEncryptedEvent() { + const event = { + ...testData.ENCRYPTED_EVENT, + origin_server_ts: Date.now(), + }; + const syncResponse = { + next_batch: 1, + rooms: { join: { [ROOM_ID]: { timeline: { events: [event] } } } }, + }; + + syncResponder.sendOrQueueSyncResponse(syncResponse); + await syncPromise(aliceClient); + } + + // Send Alice a withheld notice + async function sendWithheldMessage() { + const withheldMessage = { + type: "m.room_key.withheld", + sender: "@bob:example.com", + content: { + algorithm: "m.megolm.v1.aes-sha2", + room_id: ROOM_ID, + sender_key: testData.ENCRYPTED_EVENT.content!.sender_key, + session_id: testData.ENCRYPTED_EVENT.content!.session_id, + code: withheldCode, + reason: "zzz", + }, + }; + + syncResponder.sendOrQueueSyncResponse({ + next_batch: 1, + to_device: { events: [withheldMessage] }, + }); + await syncPromise(aliceClient); + } + + if (when === "before") { + await sendWithheldMessage(); + await sendEncryptedEvent(); + } else { + await sendEncryptedEvent(); + // Make sure that the first attempt to decrypt has happened before the withheld arrives + await awaitDecryption; + awaitDecryption = emitPromise(aliceClient, MatrixEventEvent.Decrypted); + await sendWithheldMessage(); + } + + const ev = await awaitDecryption; + expect(ev.getContent()).toEqual({ + body: `** Unable to decrypt: DecryptionError: ${expectedMessage} **`, + msgtype: "m.bad.encrypted", + }); + + expect(ev.decryptionFailureReason).toEqual(expectedErrorCode); + + // `isEncryptedDisabledForUnverifiedDevices` should be true for `m.unverified` and false for other errors. + expect(ev.isEncryptedDisabledForUnverifiedDevices).toEqual(withheldCode === "m.unverified"); + }); + }, + ); oldBackendOnly("does not block decryption on an 'm.unavailable' report", async function () { // there may be a key downloads for alice diff --git a/spec/integ/crypto/megolm-backup.spec.ts b/spec/integ/crypto/megolm-backup.spec.ts index eee0eafebc2..bc36f940ffc 100644 --- a/spec/integ/crypto/megolm-backup.spec.ts +++ b/spec/integ/crypto/megolm-backup.spec.ts @@ -796,7 +796,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe const result = await aliceCrypto.checkKeyBackupAndEnable(); expect(result).toBeTruthy(); - jest.runAllTimers(); + jest.advanceTimersByTime(10 * 60 * 1000); await failurePromise; // Fix the endpoint to do successful uploads @@ -829,7 +829,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe }); // run the timers, which will make the backup loop redo the request - await jest.runAllTimersAsync(); + await jest.advanceTimersByTimeAsync(10 * 60 * 1000); await successPromise; await allKeysUploadedPromise; }); diff --git a/spec/integ/crypto/rust-crypto.spec.ts b/spec/integ/crypto/rust-crypto.spec.ts index a1b7a7545ed..5aee7e83582 100644 --- a/spec/integ/crypto/rust-crypto.spec.ts +++ b/spec/integ/crypto/rust-crypto.spec.ts @@ -66,26 +66,6 @@ describe("MatrixClient.initRustCrypto", () => { expect(databaseNames).toEqual(expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto"])); }); - it("should create the meta db if given a pickleKey", async () => { - const matrixClient = createClient({ - baseUrl: "http://test.server", - userId: "@alice:localhost", - deviceId: "aliceDevice", - pickleKey: "testKey", - }); - - // No databases. - expect(await indexedDB.databases()).toHaveLength(0); - - await matrixClient.initRustCrypto(); - - // should have two indexed dbs now - const databaseNames = (await indexedDB.databases()).map((db) => db.name); - expect(databaseNames).toEqual( - expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto", "matrix-js-sdk::matrix-sdk-crypto-meta"]), - ); - }); - it("should create the meta db if given a storageKey", async () => { const matrixClient = createClient({ baseUrl: "http://test.server", @@ -470,10 +450,9 @@ describe("MatrixClient.clearStores", () => { baseUrl: "http://test.server", userId: "@alice:localhost", deviceId: "aliceDevice", - pickleKey: "testKey", }); - await matrixClient.initRustCrypto(); + await matrixClient.initRustCrypto({ storagePassword: "testKey" }); expect(await indexedDB.databases()).toHaveLength(2); await matrixClient.stopClient(); diff --git a/spec/integ/crypto/verification.spec.ts b/spec/integ/crypto/verification.spec.ts index ae9ebcd5961..d288adfa0bc 100644 --- a/spec/integ/crypto/verification.spec.ts +++ b/spec/integ/crypto/verification.spec.ts @@ -17,7 +17,7 @@ limitations under the License. import "fake-indexeddb/auto"; import anotherjson from "another-json"; -import { MockResponse } from "fetch-mock"; +import FetchMock from "fetch-mock"; import fetchMock from "fetch-mock-jest"; import { IDBFactory } from "fake-indexeddb"; import { createHash } from "crypto"; @@ -1511,7 +1511,7 @@ function expectSendToDeviceMessage(msgtype: string): Promise<{ messages: any }> return new Promise((resolve) => { fetchMock.putOnce( new RegExp(`/_matrix/client/(r0|v3)/sendToDevice/${escapeRegExp(msgtype)}`), - (url: string, opts: RequestInit): MockResponse => { + (url: string, opts: RequestInit): FetchMock.MockResponse => { resolve(JSON.parse(opts.body as string)); return {}; }, @@ -1535,7 +1535,7 @@ function mockSecretRequestAndGetPromises(): Map> { fetchMock.put( new RegExp(`/_matrix/client/(r0|v3)/sendToDevice/m.secret.request`), - (url: string, opts: RequestInit): MockResponse => { + (url: string, opts: RequestInit): FetchMock.MockResponse => { const messages = JSON.parse(opts.body as string).messages[TEST_USER_ID]; // rust crypto broadcasts to all devices, old crypto to a specific device, take the first one const content = Object.values(messages)[0] as any; diff --git a/spec/integ/matrix-client-methods.spec.ts b/spec/integ/matrix-client-methods.spec.ts index 06986652d48..72793711f62 100644 --- a/spec/integ/matrix-client-methods.spec.ts +++ b/spec/integ/matrix-client-methods.spec.ts @@ -257,7 +257,7 @@ describe("MatrixClient", function () { .when("POST", "/knock/" + encodeURIComponent(roomId)) .check((request) => { expect(request.data).toEqual({ reason: opts.reason }); - expect(request.queryParams).toEqual({ server_name: opts.viaServers }); + expect(request.queryParams).toEqual({ server_name: opts.viaServers, via: opts.viaServers }); }) .respond(200, { room_id: roomId }); @@ -1293,18 +1293,109 @@ describe("MatrixClient", function () { }); describe("getCapabilities", () => { - it("should cache by default", async () => { + it("should return cached capabilities if present", async () => { + const capsObject = { + "m.change_password": false, + }; + + httpBackend!.when("GET", "/versions").respond(200, {}); + httpBackend!.when("GET", "/pushrules").respond(200, {}); + httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" }); httpBackend.when("GET", "/capabilities").respond(200, { - capabilities: { - "m.change_password": false, - }, + capabilities: capsObject, + }); + + client.startClient(); + await httpBackend!.flushAllExpected(); + + expect(await client.getCapabilities()).toEqual(capsObject); + }); + + it("should fetch capabilities if cache not present", async () => { + const capsObject = { + "m.change_password": false, + }; + + httpBackend.when("GET", "/capabilities").respond(200, { + capabilities: capsObject, + }); + + const capsPromise = client.getCapabilities(); + await httpBackend!.flushAllExpected(); + + expect(await capsPromise).toEqual(capsObject); + }); + }); + + describe("getCachedCapabilities", () => { + it("should return cached capabilities or undefined", async () => { + const capsObject = { + "m.change_password": false, + }; + + httpBackend!.when("GET", "/versions").respond(200, {}); + httpBackend!.when("GET", "/pushrules").respond(200, {}); + httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" }); + httpBackend.when("GET", "/capabilities").respond(200, { + capabilities: capsObject, + }); + + expect(client.getCachedCapabilities()).toBeUndefined(); + + client.startClient(); + + await httpBackend!.flushAllExpected(); + + expect(client.getCachedCapabilities()).toEqual(capsObject); + }); + }); + + describe("fetchCapabilities", () => { + const capsObject = { + "m.change_password": false, + }; + + beforeEach(() => { + httpBackend.when("GET", "/capabilities").respond(200, { + capabilities: capsObject, }); - const prom = httpBackend.flushAllExpected(); - const capabilities1 = await client.getCapabilities(); - const capabilities2 = await client.getCapabilities(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it("should always fetch capabilities and then cache", async () => { + const prom = client.fetchCapabilities(); + await httpBackend.flushAllExpected(); + const caps = await prom; + + expect(caps).toEqual(capsObject); + }); + + it("should write-through the cache", async () => { + httpBackend!.when("GET", "/versions").respond(200, {}); + httpBackend!.when("GET", "/pushrules").respond(200, {}); + httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" }); + + client.startClient(); + await httpBackend!.flushAllExpected(); + + expect(client.getCachedCapabilities()).toEqual(capsObject); + + const newCapsObject = { + "m.change_password": true, + }; + + httpBackend.when("GET", "/capabilities").respond(200, { + capabilities: newCapsObject, + }); + + const prom = client.fetchCapabilities(); + await httpBackend.flushAllExpected(); await prom; - expect(capabilities1).toStrictEqual(capabilities2); + expect(client.getCachedCapabilities()).toEqual(newCapsObject); }); }); diff --git a/spec/integ/matrix-client-syncing-errors.spec.ts b/spec/integ/matrix-client-syncing-errors.spec.ts index ab11a33adfc..4133ffb9aaa 100644 --- a/spec/integ/matrix-client-syncing-errors.spec.ts +++ b/spec/integ/matrix-client-syncing-errors.spec.ts @@ -105,13 +105,13 @@ describe("MatrixClient syncing errors", () => { await client!.startClient(); expect(await syncEvents[0].promise).toBe(SyncState.Error); - jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync + jest.advanceTimersByTime(60 * 1000); // this will skip forward to trigger the keepAlive/sync expect(await syncEvents[1].promise).toBe(SyncState.Error); - jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync + jest.advanceTimersByTime(60 * 1000); // this will skip forward to trigger the keepAlive/sync expect(await syncEvents[2].promise).toBe(SyncState.Prepared); - jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync + jest.advanceTimersByTime(60 * 1000); // this will skip forward to trigger the keepAlive/sync expect(await syncEvents[3].promise).toBe(SyncState.Syncing); - jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync + jest.advanceTimersByTime(60 * 1000); // this will skip forward to trigger the keepAlive/sync expect(await syncEvents[4].promise).toBe(SyncState.Syncing); }); @@ -119,6 +119,7 @@ describe("MatrixClient syncing errors", () => { jest.useFakeTimers(); fetchMock.config.overwriteRoutes = false; fetchMock + .get("end:capabilities", {}) .getOnce("end:versions", {}) // first version check without credentials needs to succeed .get("end:versions", unknownTokenErrorData) // further version checks fails with 401 .get("end:pushrules/", 401) // fails with 401 without an error. This does happen in practice e.g. with Synapse diff --git a/spec/integ/matrix-client-syncing.spec.ts b/spec/integ/matrix-client-syncing.spec.ts index 3e97c648b0d..e2d7fe3f263 100644 --- a/spec/integ/matrix-client-syncing.spec.ts +++ b/spec/integ/matrix-client-syncing.spec.ts @@ -2281,67 +2281,70 @@ describe("MatrixClient syncing", () => { httpBackend!.expectedRequests = []; }); - it("should return a room based on the room initialSync API", async () => { - httpBackend!.when("GET", `/rooms/${encodeURIComponent(roomOne)}/initialSync`).respond(200, { - room_id: roomOne, - membership: KnownMembership.Leave, - messages: { - start: "start", - end: "end", - chunk: [ + it.each([undefined, 100])( + "should return a room based on the room initialSync API with limit %s", + async (limit) => { + httpBackend!.when("GET", `/rooms/${encodeURIComponent(roomOne)}/initialSync`).respond(200, { + room_id: roomOne, + membership: KnownMembership.Leave, + messages: { + start: "start", + end: "end", + chunk: [ + { + content: { body: "Message 1" }, + type: "m.room.message", + event_id: "$eventId1", + sender: userA, + origin_server_ts: 12313525, + room_id: roomOne, + }, + { + content: { body: "Message 2" }, + type: "m.room.message", + event_id: "$eventId2", + sender: userB, + origin_server_ts: 12315625, + room_id: roomOne, + }, + ], + }, + state: [ { - content: { body: "Message 1" }, - type: "m.room.message", - event_id: "$eventId1", + content: { name: "Room Name" }, + type: "m.room.name", + event_id: "$eventId", sender: userA, - origin_server_ts: 12313525, + origin_server_ts: 12314525, + state_key: "", room_id: roomOne, }, + ], + presence: [ { - content: { body: "Message 2" }, - type: "m.room.message", - event_id: "$eventId2", - sender: userB, - origin_server_ts: 12315625, - room_id: roomOne, + content: {}, + type: "m.presence", + sender: userA, }, ], - }, - state: [ - { - content: { name: "Room Name" }, - type: "m.room.name", - event_id: "$eventId", - sender: userA, - origin_server_ts: 12314525, - state_key: "", - room_id: roomOne, - }, - ], - presence: [ - { - content: {}, - type: "m.presence", - sender: userA, - }, - ], - }); - httpBackend!.when("GET", "/events").respond(200, { chunk: [] }); - - const prom = client!.peekInRoom(roomOne); - await httpBackend!.flushAllExpected(); - const room = await prom; - - expect(room.roomId).toBe(roomOne); - expect(room.getMyMembership()).toBe(KnownMembership.Leave); - expect(room.name).toBe("Room Name"); - expect(room.currentState.getStateEvents("m.room.name", "")?.getId()).toBe("$eventId"); - expect(room.timeline[0].getContent().body).toBe("Message 1"); - expect(room.timeline[1].getContent().body).toBe("Message 2"); - client?.stopPeeking(); - httpBackend!.when("GET", "/events").respond(200, { chunk: [] }); - await httpBackend!.flushAllExpected(); - }); + }); + httpBackend!.when("GET", "/events").respond(200, { chunk: [] }); + + const prom = client!.peekInRoom(roomOne, limit); + await httpBackend!.flushAllExpected(); + const room = await prom; + + expect(room.roomId).toBe(roomOne); + expect(room.getMyMembership()).toBe(KnownMembership.Leave); + expect(room.name).toBe("Room Name"); + expect(room.currentState.getStateEvents("m.room.name", "")?.getId()).toBe("$eventId"); + expect(room.timeline[0].getContent().body).toBe("Message 1"); + expect(room.timeline[1].getContent().body).toBe("Message 2"); + client?.stopPeeking(); + httpBackend!.when("GET", "/events").respond(200, { chunk: [] }); + await httpBackend!.flushAllExpected(); + }, + ); }); describe("user account data", () => { diff --git a/spec/integ/rendezvous/MSC4108SignInWithQR.spec.ts b/spec/integ/rendezvous/MSC4108SignInWithQR.spec.ts new file mode 100644 index 00000000000..e64ba412a6d --- /dev/null +++ b/spec/integ/rendezvous/MSC4108SignInWithQR.spec.ts @@ -0,0 +1,358 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { QrCodeData, QrCodeMode } from "@matrix-org/matrix-sdk-crypto-wasm"; +import { mocked } from "jest-mock"; +import fetchMock from "fetch-mock-jest"; + +import { + MSC4108FailureReason, + MSC4108RendezvousSession, + MSC4108SecureChannel, + MSC4108SignInWithQR, + PayloadType, + RendezvousError, +} from "../../../src/rendezvous"; +import { defer } from "../../../src/utils"; +import { + ClientPrefix, + DEVICE_CODE_SCOPE, + IHttpOpts, + IMyDevice, + MatrixClient, + MatrixError, + MatrixHttpApi, +} from "../../../src"; +import { mockOpenIdConfiguration } from "../../test-utils/oidc"; + +function makeMockClient(opts: { userId: string; deviceId: string; msc4108Enabled: boolean }): MatrixClient { + const baseUrl = "https://example.com"; + const crypto = { + exportSecretsForQrLogin: jest.fn(), + }; + const client = { + doesServerSupportUnstableFeature(feature: string) { + return Promise.resolve(opts.msc4108Enabled && feature === "org.matrix.msc4108"); + }, + getUserId() { + return opts.userId; + }, + getDeviceId() { + return opts.deviceId; + }, + baseUrl, + getDomain: () => "example.com", + getDevice: jest.fn(), + getCrypto: jest.fn(() => crypto), + getAuthIssuer: jest.fn().mockResolvedValue({ issuer: "https://issuer/" }), + } as unknown as MatrixClient; + client.http = new MatrixHttpApi(client, { + baseUrl: client.baseUrl, + prefix: ClientPrefix.Unstable, + onlyData: true, + }); + return client; +} + +describe("MSC4108SignInWithQR", () => { + beforeEach(() => { + fetchMock.get( + "https://issuer/.well-known/openid-configuration", + mockOpenIdConfiguration("https://issuer/", [DEVICE_CODE_SCOPE]), + ); + fetchMock.get("https://issuer/jwks", { + status: 200, + headers: { + "Content-Type": "application/json", + }, + keys: [], + }); + }); + + afterEach(() => { + fetchMock.reset(); + }); + + const url = "https://fallbackserver/rz/123"; + const deviceId = "DEADB33F"; + const verificationUri = "https://example.com/verify"; + const verificationUriComplete = "https://example.com/verify/complete"; + + it("should generate qr code data as expected", async () => { + const session = new MSC4108RendezvousSession({ + url, + }); + const channel = new MSC4108SecureChannel(session); + const login = new MSC4108SignInWithQR(channel, false); + + await login.generateCode(); + const code = login.code; + expect(code).toHaveLength(71); + const text = new TextDecoder().decode(code); + expect(text.startsWith("MATRIX")).toBeTruthy(); + expect(text.endsWith(url)).toBeTruthy(); + + // Assert that the code is stable + await login.generateCode(); + expect(login.code).toEqual(code); + }); + + describe("should be able to connect as a reciprocating device", () => { + let client: MatrixClient; + let ourLogin: MSC4108SignInWithQR; + let opponentLogin: MSC4108SignInWithQR; + + beforeEach(async () => { + let ourData = defer(); + let opponentData = defer(); + + const ourMockSession = { + send: jest.fn(async (newData) => { + ourData.resolve(newData); + }), + receive: jest.fn(() => { + const prom = opponentData.promise; + prom.then(() => { + opponentData = defer(); + }); + return prom; + }), + url, + cancelled: false, + cancel: () => { + // @ts-ignore + ourMockSession.cancelled = true; + ourData.resolve(""); + }, + } as unknown as MSC4108RendezvousSession; + const opponentMockSession = { + send: jest.fn(async (newData) => { + opponentData.resolve(newData); + }), + receive: jest.fn(() => { + const prom = ourData.promise; + prom.then(() => { + ourData = defer(); + }); + return prom; + }), + url, + } as unknown as MSC4108RendezvousSession; + + client = makeMockClient({ userId: "@alice:example.com", deviceId: "alice", msc4108Enabled: true }); + + const ourChannel = new MSC4108SecureChannel(ourMockSession); + const qrCodeData = QrCodeData.fromBytes( + await ourChannel.generateCode(QrCodeMode.Reciprocate, client.getDomain()!), + ); + const opponentChannel = new MSC4108SecureChannel(opponentMockSession, qrCodeData.publicKey); + + ourLogin = new MSC4108SignInWithQR(ourChannel, true, client); + opponentLogin = new MSC4108SignInWithQR(opponentChannel, false); + }); + + it("should be able to connect with opponent and share server name & check code", async () => { + await Promise.all([ + expect(ourLogin.negotiateProtocols()).resolves.toEqual({}), + expect(opponentLogin.negotiateProtocols()).resolves.toEqual({ serverName: client.getDomain() }), + ]); + + expect(ourLogin.checkCode).toBe(opponentLogin.checkCode); + }); + + it("should be able to connect with opponent and share verificationUri", async () => { + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + mocked(client.getDevice).mockRejectedValue(new MatrixError({ errcode: "M_NOT_FOUND" }, 404)); + + await Promise.all([ + expect(ourLogin.deviceAuthorizationGrant()).resolves.toEqual({ + verificationUri: verificationUriComplete, + }), + // We don't have the new device side of this flow implemented at this time so mock it + // @ts-ignore + opponentLogin.send({ + type: PayloadType.Protocol, + protocol: "device_authorization_grant", + device_authorization_grant: { + verification_uri: verificationUri, + verification_uri_complete: verificationUriComplete, + }, + device_id: deviceId, + }), + ]); + }); + + it("should abort if device already exists", async () => { + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + mocked(client.getDevice).mockResolvedValue({} as IMyDevice); + + await Promise.all([ + expect(ourLogin.deviceAuthorizationGrant()).rejects.toThrow("Specified device ID already exists"), + // We don't have the new device side of this flow implemented at this time so mock it + // @ts-ignore + opponentLogin.send({ + type: PayloadType.Protocol, + protocol: "device_authorization_grant", + device_authorization_grant: { + verification_uri: verificationUri, + }, + device_id: deviceId, + }), + ]); + }); + + it("should abort on unsupported protocol", async () => { + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + await Promise.all([ + expect(ourLogin.deviceAuthorizationGrant()).rejects.toThrow( + "Received a request for an unsupported protocol", + ), + // We don't have the new device side of this flow implemented at this time so mock it + // @ts-ignore + opponentLogin.send({ + type: PayloadType.Protocol, + protocol: "device_authorization_grant_v2", + device_authorization_grant: { + verification_uri: verificationUri, + }, + device_id: deviceId, + }), + ]); + }); + + it("should be able to connect with opponent and share secrets", async () => { + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + // We don't have the new device side of this flow implemented at this time so mock it + // @ts-ignore + ourLogin.expectingNewDeviceId = "DEADB33F"; + + const ourProm = ourLogin.shareSecrets(); + + // Consume the ProtocolAccepted message which would normally be handled by step 4 which we do not have here + // @ts-ignore + await opponentLogin.receive(); + + mocked(client.getDevice).mockResolvedValue({} as IMyDevice); + + const secrets = { + cross_signing: { master_key: "mk", user_signing_key: "usk", self_signing_key: "ssk" }, + }; + client.getCrypto()!.exportSecretsBundle = jest.fn().mockResolvedValue(secrets); + + const payload = { + secrets: expect.objectContaining(secrets), + }; + await Promise.all([ + expect(ourProm).resolves.toEqual(payload), + expect(opponentLogin.shareSecrets()).resolves.toEqual(payload), + ]); + }); + + it("should abort if device doesn't come up by timeout", async () => { + jest.spyOn(global, "setTimeout").mockImplementation((fn) => { + (fn)(); + // TODO: mock timers properly + return -1 as any; + }); + jest.spyOn(Date, "now").mockImplementation(() => { + return 12345678 + mocked(setTimeout).mock.calls.length * 1000; + }); + + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + // We don't have the new device side of this flow implemented at this time so mock it + // @ts-ignore + ourLogin.expectingNewDeviceId = "DEADB33F"; + + // @ts-ignore + await opponentLogin.send({ + type: PayloadType.Success, + }); + mocked(client.getDevice).mockRejectedValue(new MatrixError({ errcode: "M_NOT_FOUND" }, 404)); + + const ourProm = ourLogin.shareSecrets(); + await expect(ourProm).rejects.toThrow("New device not found"); + }); + + it("should abort on unexpected errors", async () => { + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + // We don't have the new device side of this flow implemented at this time so mock it + // @ts-ignore + ourLogin.expectingNewDeviceId = "DEADB33F"; + + // @ts-ignore + await opponentLogin.send({ + type: PayloadType.Success, + }); + mocked(client.getDevice).mockRejectedValue( + new MatrixError({ errcode: "M_UNKNOWN", error: "The message" }, 500), + ); + + await expect(ourLogin.shareSecrets()).rejects.toThrow("The message"); + }); + + it("should abort on declined login", async () => { + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + await ourLogin.declineLoginOnExistingDevice(); + await expect(opponentLogin.shareSecrets()).rejects.toThrow( + new RendezvousError("Failed", MSC4108FailureReason.UserCancelled), + ); + }); + + it("should not send secrets if user cancels", async () => { + jest.spyOn(global, "setTimeout").mockImplementation((fn) => { + (fn)(); + // TODO: mock timers properly + return -1 as any; + }); + + await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]); + + // We don't have the new device side of this flow implemented at this time so mock it + // @ts-ignore + ourLogin.expectingNewDeviceId = "DEADB33F"; + + const ourProm = ourLogin.shareSecrets(); + const opponentProm = opponentLogin.shareSecrets(); + + // Consume the ProtocolAccepted message which would normally be handled by step 4 which we do not have here + // @ts-ignore + await opponentLogin.receive(); + + const deferred = defer(); + mocked(client.getDevice).mockReturnValue(deferred.promise); + + ourLogin.cancel(MSC4108FailureReason.UserCancelled).catch(() => {}); + deferred.resolve({} as IMyDevice); + + const secrets = { + cross_signing: { master_key: "mk", user_signing_key: "usk", self_signing_key: "ssk" }, + }; + client.getCrypto()!.exportSecretsBundle = jest.fn().mockResolvedValue(secrets); + + await Promise.all([ + expect(ourProm).rejects.toThrow("User cancelled"), + expect(opponentProm).rejects.toThrow("Unexpected message received"), + ]); + }); + }); +}); diff --git a/spec/setupTests.ts b/spec/setupTests.ts index 20c03b8ef06..2c16f663262 100644 --- a/spec/setupTests.ts +++ b/spec/setupTests.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import DOMException from "domexception"; - -global.DOMException = DOMException as typeof global.DOMException; - jest.mock("../src/http-api/utils", () => ({ ...jest.requireActual("../src/http-api/utils"), // We mock timeoutSignal otherwise it causes tests to leave timers running diff --git a/spec/slowReporter.js b/spec/slowReporter.cjs similarity index 100% rename from spec/slowReporter.js rename to spec/slowReporter.cjs diff --git a/spec/test-utils/AccountDataAccumulator.ts b/spec/test-utils/AccountDataAccumulator.ts index dca35bc2cc8..f24b7f53b35 100644 --- a/spec/test-utils/AccountDataAccumulator.ts +++ b/spec/test-utils/AccountDataAccumulator.ts @@ -15,7 +15,6 @@ limitations under the License. */ import fetchMock from "fetch-mock-jest"; -import { MockOptionsMethodPut } from "fetch-mock"; import { ISyncResponder } from "./SyncResponder"; @@ -40,7 +39,10 @@ export class AccountDataAccumulator { * @param opts - options to pass to fetchMock * @returns a Promise which will resolve (with the content of the account data) once it is set. */ - public interceptSetAccountData(accountDataType: string, opts?: MockOptionsMethodPut): Promise { + public interceptSetAccountData( + accountDataType: string, + opts?: Parameters<(typeof fetchMock)["put"]>[2], + ): Promise { return new Promise((resolve) => { // Called when the cross signing key is uploaded fetchMock.put( diff --git a/spec/test-utils/SyncResponder.ts b/spec/test-utils/SyncResponder.ts index 31fae7147a8..3caba9dfa00 100644 --- a/spec/test-utils/SyncResponder.ts +++ b/spec/test-utils/SyncResponder.ts @@ -17,7 +17,7 @@ limitations under the License. import debugFunc from "debug"; import { Debugger } from "debug"; import fetchMock from "fetch-mock-jest"; -import { MockResponse } from "fetch-mock"; +import FetchMock from "fetch-mock"; /** Interface implemented by classes that intercept `/sync` requests from test clients * @@ -80,7 +80,7 @@ export class SyncResponder implements ISyncResponder { ); } - private async onSyncRequest(): Promise { + private async onSyncRequest(): Promise { switch (this.state) { case SyncResponderState.IDLE: { this.debug("Got /sync request: waiting for response to be ready"); diff --git a/spec/test-utils/client.ts b/spec/test-utils/client.ts index 8123d0d65e6..62e11dffa13 100644 --- a/spec/test-utils/client.ts +++ b/spec/test-utils/client.ts @@ -88,6 +88,6 @@ export const mockClientMethodsEvents = () => ({ export const mockClientMethodsServer = (): Partial, unknown>> => ({ getIdentityServerUrl: jest.fn(), getHomeserverUrl: jest.fn(), - getCapabilities: jest.fn().mockReturnValue({}), + getCachedCapabilities: jest.fn().mockReturnValue({}), doesServerSupportUnstableFeature: jest.fn().mockResolvedValue(false), }); diff --git a/spec/test-utils/oidc.ts b/spec/test-utils/oidc.ts index 4f9a01c2ee2..8f2965c9a2a 100644 --- a/spec/test-utils/oidc.ts +++ b/spec/test-utils/oidc.ts @@ -38,7 +38,10 @@ export const makeDelegatedAuthConfig = (issuer = "https://auth.org/"): OidcClien * @param issuer used as the base for all other urls * @returns ValidatedIssuerMetadata */ -export const mockOpenIdConfiguration = (issuer = "https://auth.org/"): ValidatedIssuerMetadata => ({ +export const mockOpenIdConfiguration = ( + issuer = "https://auth.org/", + additionalGrantTypes: string[] = [], +): ValidatedIssuerMetadata => ({ issuer, revocation_endpoint: issuer + "revoke", token_endpoint: issuer + "token", @@ -47,6 +50,6 @@ export const mockOpenIdConfiguration = (issuer = "https://auth.org/"): Validated device_authorization_endpoint: issuer + "device", jwks_uri: issuer + "jwks", response_types_supported: ["code"], - grant_types_supported: ["authorization_code", "refresh_token"], + grant_types_supported: ["authorization_code", "refresh_token", ...additionalGrantTypes], code_challenge_methods_supported: ["S256"], }); diff --git a/spec/unit/base64.spec.ts b/spec/unit/base64.spec.ts index 4646fbd84a5..3ef495134a1 100644 --- a/spec/unit/base64.spec.ts +++ b/spec/unit/base64.spec.ts @@ -50,17 +50,18 @@ describe.each(["browser", "node"])("Base64 encoding (%s)", (env) => { }); it("Should encode unpadded URL-safe base64", () => { - const toEncode = "?????"; + // Chosen to have padding and multiple instances of / and + in the base64 + const toEncode = "???????⊕⊗⊗"; const data = new TextEncoder().encode(toEncode); const encoded = encodeUnpaddedBase64Url(data); - expect(encoded).toEqual("Pz8_Pz8"); + expect(encoded).toEqual("Pz8_Pz8_P-KKleKKl-KKlw"); }); it("Should decode URL-safe base64", () => { - const decoded = new TextDecoder().decode(decodeBase64("Pz8_Pz8=")); + const decoded = new TextDecoder().decode(decodeBase64("Pz8_Pz8_P-KKleKKl-KKlw==")); - expect(decoded).toStrictEqual("?????"); + expect(decoded).toStrictEqual("???????⊕⊗⊗"); }); it("Encode unpadded should not have padding", () => { diff --git a/spec/unit/content-repo.spec.ts b/spec/unit/content-repo.spec.ts index e0f0b5e0c76..23f504c1e43 100644 --- a/spec/unit/content-repo.spec.ts +++ b/spec/unit/content-repo.spec.ts @@ -80,24 +80,22 @@ describe("ContentRepo", function () { it("should return an authenticated URL when requested", function () { const mxcUri = "mxc://server.name/resourceid"; expect(getHttpUriForMxc(baseUrl, mxcUri, undefined, undefined, undefined, undefined, true, true)).toEqual( - baseUrl + - "/_matrix/client/unstable/org.matrix.msc3916/media/download/server.name/resourceid?allow_redirect=true", + baseUrl + "/_matrix/client/v1/media/download/server.name/resourceid?allow_redirect=true", ); expect(getHttpUriForMxc(baseUrl, mxcUri, 64, 64, "scale", undefined, true, true)).toEqual( baseUrl + - "/_matrix/client/unstable/org.matrix.msc3916/media/thumbnail/server.name/resourceid?width=64&height=64&method=scale&allow_redirect=true", + "/_matrix/client/v1/media/thumbnail/server.name/resourceid?width=64&height=64&method=scale&allow_redirect=true", ); }); it("should force-enable allow_redirects when useAuthentication is set true", function () { const mxcUri = "mxc://server.name/resourceid"; expect(getHttpUriForMxc(baseUrl, mxcUri, undefined, undefined, undefined, undefined, false, true)).toEqual( - baseUrl + - "/_matrix/client/unstable/org.matrix.msc3916/media/download/server.name/resourceid?allow_redirect=true", + baseUrl + "/_matrix/client/v1/media/download/server.name/resourceid?allow_redirect=true", ); expect(getHttpUriForMxc(baseUrl, mxcUri, 64, 64, "scale", undefined, false, true)).toEqual( baseUrl + - "/_matrix/client/unstable/org.matrix.msc3916/media/thumbnail/server.name/resourceid?width=64&height=64&method=scale&allow_redirect=true", + "/_matrix/client/v1/media/thumbnail/server.name/resourceid?width=64&height=64&method=scale&allow_redirect=true", ); }); }); diff --git a/spec/unit/digest.spec.ts b/spec/unit/digest.spec.ts new file mode 100644 index 00000000000..e129cf85070 --- /dev/null +++ b/spec/unit/digest.spec.ts @@ -0,0 +1,40 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { encodeUnpaddedBase64Url } from "../../src"; +import { sha256 } from "../../src/digest"; + +describe("sha256", () => { + it("should hash a string", async () => { + const hash = await sha256("test"); + expect(encodeUnpaddedBase64Url(hash)).toBe("n4bQgYhMfWWaL-qgxVrQFaO_TxsrC4Is0V1sFbDwCgg"); + }); + + it("should hash a string with emoji", async () => { + const hash = await sha256("test 🍱"); + expect(encodeUnpaddedBase64Url(hash)).toBe("X2aDNrrwfq3nCTOl90R9qg9ynxhHnSzsMqtrdYX-SGw"); + }); + + it("throws if webcrypto is not available", async () => { + const oldCrypto = global.crypto; + try { + global.crypto = {} as any; + await expect(sha256("test")).rejects.toThrow(); + } finally { + global.crypto = oldCrypto; + } + }); +}); diff --git a/spec/unit/embedded.spec.ts b/spec/unit/embedded.spec.ts index d9ac5a62f0b..d3b3e12359d 100644 --- a/spec/unit/embedded.spec.ts +++ b/spec/unit/embedded.spec.ts @@ -32,7 +32,7 @@ import { IOpenIDCredentials, } from "matrix-widget-api"; -import { createRoomWidgetClient, MsgType } from "../../src/matrix"; +import { createRoomWidgetClient, MsgType, UpdateDelayedEventAction } from "../../src/matrix"; import { MatrixClient, ClientEvent, ITurnServer as IClientTurnServer } from "../../src/client"; import { SyncState } from "../../src/sync"; import { ICapabilities } from "../../src/embedded"; @@ -59,8 +59,26 @@ class MockWidgetApi extends EventEmitter { public requestCapabilityToReceiveState = jest.fn(); public requestCapabilityToSendToDevice = jest.fn(); public requestCapabilityToReceiveToDevice = jest.fn(); - public sendRoomEvent = jest.fn(() => ({ event_id: `$${Math.random()}` })); - public sendStateEvent = jest.fn(); + public sendRoomEvent = jest.fn( + (eventType: string, content: unknown, roomId?: string, delay?: number, parentDelayId?: string) => + delay === undefined && parentDelayId === undefined + ? { event_id: `$${Math.random()}` } + : { delay_id: `id-${Math.random()}` }, + ); + public sendStateEvent = jest.fn( + ( + eventType: string, + stateKey: string, + content: unknown, + roomId?: string, + delay?: number, + parentDelayId?: string, + ) => + delay === undefined && parentDelayId === undefined + ? { event_id: `$${Math.random()}` } + : { delay_id: `id-${Math.random()}` }, + ); + public updateDelayedEvent = jest.fn(); public sendToDevice = jest.fn(); public requestOpenIDConnectToken = jest.fn(() => { return testOIDCToken; @@ -125,6 +143,17 @@ describe("RoomWidgetClient", () => { ); }); + it("send handles wrong field in response", async () => { + await makeClient({ sendEvent: ["org.matrix.rageshake_request"] }); + widgetApi.sendRoomEvent.mockResolvedValueOnce({ + room_id: "!1:example.org", + delay_id: `id-${Math.random}`, + }); + await expect( + client.sendEvent("!1:example.org", "org.matrix.rageshake_request", { request_id: 123 }), + ).rejects.toThrow(); + }); + it("receives", async () => { const event = new MatrixEvent({ type: "org.matrix.rageshake_request", @@ -160,6 +189,199 @@ describe("RoomWidgetClient", () => { }); }); + describe("delayed events", () => { + describe("when supported", () => { + const doesServerSupportUnstableFeatureMock = jest.fn((feature) => + Promise.resolve(feature === "org.matrix.msc4140"), + ); + + beforeAll(() => { + MatrixClient.prototype.doesServerSupportUnstableFeature = doesServerSupportUnstableFeatureMock; + }); + + afterAll(() => { + doesServerSupportUnstableFeatureMock.mockReset(); + }); + + it("sends delayed message events", async () => { + await makeClient({ sendDelayedEvents: true, sendEvent: ["org.matrix.rageshake_request"] }); + expect(widgetApi.requestCapability).toHaveBeenCalledWith(MatrixCapabilities.MSC4157SendDelayedEvent); + await client._unstable_sendDelayedEvent( + "!1:example.org", + { delay: 2000 }, + null, + "org.matrix.rageshake_request", + { request_id: 123 }, + ); + expect(widgetApi.sendRoomEvent).toHaveBeenCalledWith( + "org.matrix.rageshake_request", + { request_id: 123 }, + "!1:example.org", + 2000, + undefined, + ); + }); + + it("sends child action delayed message events", async () => { + await makeClient({ sendDelayedEvents: true, sendEvent: ["org.matrix.rageshake_request"] }); + expect(widgetApi.requestCapability).toHaveBeenCalledWith(MatrixCapabilities.MSC4157SendDelayedEvent); + const parentDelayId = `id-${Math.random()}`; + await client._unstable_sendDelayedEvent( + "!1:example.org", + { parent_delay_id: parentDelayId }, + null, + "org.matrix.rageshake_request", + { request_id: 123 }, + ); + expect(widgetApi.sendRoomEvent).toHaveBeenCalledWith( + "org.matrix.rageshake_request", + { request_id: 123 }, + "!1:example.org", + undefined, + parentDelayId, + ); + }); + + it("sends delayed state events", async () => { + await makeClient({ + sendDelayedEvents: true, + sendState: [{ eventType: "org.example.foo", stateKey: "bar" }], + }); + expect(widgetApi.requestCapability).toHaveBeenCalledWith(MatrixCapabilities.MSC4157SendDelayedEvent); + await client._unstable_sendDelayedStateEvent( + "!1:example.org", + { delay: 2000 }, + "org.example.foo", + { hello: "world" }, + "bar", + ); + expect(widgetApi.sendStateEvent).toHaveBeenCalledWith( + "org.example.foo", + "bar", + { hello: "world" }, + "!1:example.org", + 2000, + undefined, + ); + }); + + it("sends child action delayed state events", async () => { + await makeClient({ + sendDelayedEvents: true, + sendState: [{ eventType: "org.example.foo", stateKey: "bar" }], + }); + expect(widgetApi.requestCapability).toHaveBeenCalledWith(MatrixCapabilities.MSC4157SendDelayedEvent); + const parentDelayId = `fg-${Math.random()}`; + await client._unstable_sendDelayedStateEvent( + "!1:example.org", + { parent_delay_id: parentDelayId }, + "org.example.foo", + { hello: "world" }, + "bar", + ); + expect(widgetApi.sendStateEvent).toHaveBeenCalledWith( + "org.example.foo", + "bar", + { hello: "world" }, + "!1:example.org", + undefined, + parentDelayId, + ); + }); + + it("send delayed message events handles wrong field in response", async () => { + await makeClient({ sendDelayedEvents: true, sendEvent: ["org.matrix.rageshake_request"] }); + widgetApi.sendRoomEvent.mockResolvedValueOnce({ + room_id: "!1:example.org", + event_id: `$${Math.random()}`, + }); + await expect( + client._unstable_sendDelayedEvent( + "!1:example.org", + { delay: 2000 }, + null, + "org.matrix.rageshake_request", + { request_id: 123 }, + ), + ).rejects.toThrow(); + }); + + it("send delayed state events handles wrong field in response", async () => { + await makeClient({ + sendDelayedEvents: true, + sendState: [{ eventType: "org.example.foo", stateKey: "bar" }], + }); + widgetApi.sendStateEvent.mockResolvedValueOnce({ + room_id: "!1:example.org", + event_id: `$${Math.random()}`, + }); + await expect( + client._unstable_sendDelayedStateEvent( + "!1:example.org", + { delay: 2000 }, + "org.example.foo", + { hello: "world" }, + "bar", + ), + ).rejects.toThrow(); + }); + + it("updates delayed events", async () => { + await makeClient({ updateDelayedEvents: true, sendEvent: ["org.matrix.rageshake_request"] }); + expect(widgetApi.requestCapability).toHaveBeenCalledWith(MatrixCapabilities.MSC4157UpdateDelayedEvent); + for (const action of [ + UpdateDelayedEventAction.Cancel, + UpdateDelayedEventAction.Restart, + UpdateDelayedEventAction.Send, + ]) { + await client._unstable_updateDelayedEvent("id", action); + expect(widgetApi.updateDelayedEvent).toHaveBeenCalledWith("id", action); + } + }); + }); + + describe("when unsupported", () => { + it("fails to send delayed message events", async () => { + await makeClient({ sendEvent: ["org.matrix.rageshake_request"] }); + await expect( + client._unstable_sendDelayedEvent( + "!1:example.org", + { delay: 2000 }, + null, + "org.matrix.rageshake_request", + { request_id: 123 }, + ), + ).rejects.toThrow("Server does not support"); + }); + + it("fails to send delayed state events", async () => { + await makeClient({ sendState: [{ eventType: "org.example.foo", stateKey: "bar" }] }); + await expect( + client._unstable_sendDelayedStateEvent( + "!1:example.org", + { delay: 2000 }, + "org.example.foo", + { hello: "world" }, + "bar", + ), + ).rejects.toThrow("Server does not support"); + }); + + it("fails to update delayed state events", async () => { + await makeClient({}); + for (const action of [ + UpdateDelayedEventAction.Cancel, + UpdateDelayedEventAction.Restart, + UpdateDelayedEventAction.Send, + ]) { + await expect(client._unstable_updateDelayedEvent("id", action)).rejects.toThrow( + "Server does not support", + ); + } + }); + }); + }); + describe("initialization", () => { it("requests permissions for specific message types", async () => { await makeClient({ sendMessage: [MsgType.Text], receiveMessage: [MsgType.Text] }); @@ -211,6 +433,17 @@ describe("RoomWidgetClient", () => { ); }); + it("send handles incorrect response", async () => { + await makeClient({ sendState: [{ eventType: "org.example.foo", stateKey: "bar" }] }); + widgetApi.sendStateEvent.mockResolvedValueOnce({ + room_id: "!1:example.org", + delay_id: `id-${Math.random}`, + }); + await expect( + client.sendStateEvent("!1:example.org", "org.example.foo", { hello: "world" }, "bar"), + ).rejects.toThrow(); + }); + it("receives", async () => { await makeClient({ receiveState: [{ eventType: "org.example.foo", stateKey: "bar" }] }); expect(widgetApi.requestCapabilityForRoomTimeline).toHaveBeenCalledWith("!1:example.org"); diff --git a/spec/unit/matrix-client.spec.ts b/spec/unit/matrix-client.spec.ts index fa9cd776902..04129ab0818 100644 --- a/spec/unit/matrix-client.spec.ts +++ b/spec/unit/matrix-client.spec.ts @@ -57,6 +57,7 @@ import { Room, RuleId, TweakName, + UpdateDelayedEventAction, } from "../../src"; import { supportsMatrixCall } from "../../src/webrtc/call"; import { makeBeaconEvent } from "../test-utils/beacon"; @@ -97,7 +98,7 @@ type HttpLookup = { method: string; path: string; prefix?: string; - data?: Record; + data?: Record | Record[]; error?: object; expectBody?: Record; expectQueryParams?: QueryDict; @@ -298,7 +299,9 @@ describe("MatrixClient", function () { ...(opts || {}), }); // FIXME: We shouldn't be yanking http like this. - client.http = (["authedRequest", "getContentUri", "request", "uploadContent"] as const).reduce((r, k) => { + client.http = ( + ["authedRequest", "getContentUri", "request", "uploadContent", "idServerRequest"] as const + ).reduce((r, k) => { r[k] = jest.fn(); return r; }, {} as MatrixHttpApi); @@ -704,6 +707,328 @@ describe("MatrixClient", function () { }); }); + describe("_unstable_sendDelayedEvent", () => { + const unstableMSC4140Prefix = `${ClientPrefix.Unstable}/org.matrix.msc4140`; + + const roomId = "!room:example.org"; + const body = "This is the body"; + const content = { body, msgtype: MsgType.Text } satisfies RoomMessageEventContent; + const timeoutDelayOpts = { delay: 2000 }; + const realTimeoutDelayOpts = { "org.matrix.msc4140.delay": 2000 }; + + beforeEach(() => { + unstableFeatures["org.matrix.msc4140"] = true; + }); + + it("throws when unsupported by server", async () => { + unstableFeatures["org.matrix.msc4140"] = false; + const errorMessage = "Server does not support"; + + await expect( + client._unstable_sendDelayedEvent( + roomId, + timeoutDelayOpts, + null, + EventType.RoomMessage, + { ...content }, + client.makeTxnId(), + ), + ).rejects.toThrow(errorMessage); + + await expect( + client._unstable_sendDelayedStateEvent(roomId, timeoutDelayOpts, EventType.RoomTopic, { + topic: "topic", + }), + ).rejects.toThrow(errorMessage); + + await expect(client._unstable_getDelayedEvents()).rejects.toThrow(errorMessage); + + await expect( + client._unstable_updateDelayedEvent("anyDelayId", UpdateDelayedEventAction.Send), + ).rejects.toThrow(errorMessage); + }); + + it("works with null threadId", async () => { + httpLookups = []; + + const timeoutDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${timeoutDelayTxnId}`, + expectQueryParams: realTimeoutDelayOpts, + data: { delay_id: "id1" }, + expectBody: content, + }); + + const { delay_id: timeoutDelayId } = await client._unstable_sendDelayedEvent( + roomId, + timeoutDelayOpts, + null, + EventType.RoomMessage, + { ...content }, + timeoutDelayTxnId, + ); + + const actionDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${actionDelayTxnId}`, + expectQueryParams: { "org.matrix.msc4140.parent_delay_id": timeoutDelayId }, + data: { delay_id: "id2" }, + expectBody: content, + }); + + await client._unstable_sendDelayedEvent( + roomId, + { parent_delay_id: timeoutDelayId }, + null, + EventType.RoomMessage, + { ...content }, + actionDelayTxnId, + ); + }); + + it("works with non-null threadId", async () => { + httpLookups = []; + const threadId = "$threadId:server"; + const expectBody = { + ...content, + "m.relates_to": { + event_id: threadId, + is_falling_back: true, + rel_type: "m.thread", + }, + }; + + const timeoutDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${timeoutDelayTxnId}`, + expectQueryParams: realTimeoutDelayOpts, + data: { delay_id: "id1" }, + expectBody, + }); + + const { delay_id: timeoutDelayId } = await client._unstable_sendDelayedEvent( + roomId, + timeoutDelayOpts, + threadId, + EventType.RoomMessage, + { ...content }, + timeoutDelayTxnId, + ); + + const actionDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${actionDelayTxnId}`, + expectQueryParams: { "org.matrix.msc4140.parent_delay_id": timeoutDelayId }, + data: { delay_id: "id2" }, + expectBody, + }); + + await client._unstable_sendDelayedEvent( + roomId, + { parent_delay_id: timeoutDelayId }, + threadId, + EventType.RoomMessage, + { ...content }, + actionDelayTxnId, + ); + }); + + it("should add thread relation if threadId is passed and the relation is missing", async () => { + httpLookups = []; + const threadId = "$threadId:server"; + const expectBody = { + ...content, + "m.relates_to": { + "m.in_reply_to": { + event_id: threadId, + }, + "event_id": threadId, + "is_falling_back": true, + "rel_type": "m.thread", + }, + }; + + const room = new Room(roomId, client, userId); + mocked(store.getRoom).mockReturnValue(room); + + const rootEvent = new MatrixEvent({ event_id: threadId }); + room.createThread(threadId, rootEvent, [rootEvent], false); + + const timeoutDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${timeoutDelayTxnId}`, + expectQueryParams: realTimeoutDelayOpts, + data: { delay_id: "id1" }, + expectBody, + }); + + const { delay_id: timeoutDelayId } = await client._unstable_sendDelayedEvent( + roomId, + timeoutDelayOpts, + threadId, + EventType.RoomMessage, + { ...content }, + timeoutDelayTxnId, + ); + + const actionDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${actionDelayTxnId}`, + expectQueryParams: { "org.matrix.msc4140.parent_delay_id": timeoutDelayId }, + data: { delay_id: "id2" }, + expectBody, + }); + + await client._unstable_sendDelayedEvent( + roomId, + { parent_delay_id: timeoutDelayId }, + threadId, + EventType.RoomMessage, + { ...content }, + actionDelayTxnId, + ); + }); + + it("should add thread relation if threadId is passed and the relation is missing with reply", async () => { + httpLookups = []; + const threadId = "$threadId:server"; + + const content = { + body, + "msgtype": MsgType.Text, + "m.relates_to": { + "m.in_reply_to": { + event_id: "$other:event", + }, + }, + } satisfies RoomMessageEventContent; + const expectBody = { + ...content, + "m.relates_to": { + "m.in_reply_to": { + event_id: "$other:event", + }, + "event_id": threadId, + "is_falling_back": false, + "rel_type": "m.thread", + }, + }; + + const room = new Room(roomId, client, userId); + mocked(store.getRoom).mockReturnValue(room); + + const rootEvent = new MatrixEvent({ event_id: threadId }); + room.createThread(threadId, rootEvent, [rootEvent], false); + + const timeoutDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${timeoutDelayTxnId}`, + expectQueryParams: realTimeoutDelayOpts, + data: { delay_id: "id1" }, + expectBody, + }); + + const { delay_id: timeoutDelayId } = await client._unstable_sendDelayedEvent( + roomId, + timeoutDelayOpts, + threadId, + EventType.RoomMessage, + { ...content }, + timeoutDelayTxnId, + ); + + const actionDelayTxnId = client.makeTxnId(); + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${actionDelayTxnId}`, + expectQueryParams: { "org.matrix.msc4140.parent_delay_id": timeoutDelayId }, + data: { delay_id: "id2" }, + expectBody, + }); + + await client._unstable_sendDelayedEvent( + roomId, + { parent_delay_id: timeoutDelayId }, + threadId, + EventType.RoomMessage, + { ...content }, + actionDelayTxnId, + ); + }); + + it("can send a delayed state event", async () => { + httpLookups = []; + const content = { topic: "The year 2000" }; + + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/state/m.room.topic/`, + expectQueryParams: realTimeoutDelayOpts, + data: { delay_id: "id1" }, + expectBody: content, + }); + + const { delay_id: timeoutDelayId } = await client._unstable_sendDelayedStateEvent( + roomId, + timeoutDelayOpts, + EventType.RoomTopic, + { ...content }, + ); + + httpLookups.push({ + method: "PUT", + path: `/rooms/${encodeURIComponent(roomId)}/state/m.room.topic/`, + expectQueryParams: { "org.matrix.msc4140.parent_delay_id": timeoutDelayId }, + data: { delay_id: "id2" }, + expectBody: content, + }); + + await client._unstable_sendDelayedStateEvent( + roomId, + { parent_delay_id: timeoutDelayId }, + EventType.RoomTopic, + { ...content }, + ); + }); + + it("can look up delayed events", async () => { + httpLookups = [ + { + method: "GET", + prefix: unstableMSC4140Prefix, + path: "/delayed_events", + data: [], + }, + ]; + + await client._unstable_getDelayedEvents(); + }); + + it("can update delayed events", async () => { + const delayId = "id"; + const action = UpdateDelayedEventAction.Restart; + httpLookups = [ + { + method: "POST", + prefix: unstableMSC4140Prefix, + path: `/delayed_events/${encodeURIComponent(delayId)}`, + data: { + action, + }, + }, + ]; + + await client._unstable_updateDelayedEvent(delayId, action); + }); + }); + it("should create (unstable) file trees", async () => { const userId = "@test:example.org"; const roomId = "!room:example.org"; @@ -963,7 +1288,7 @@ describe("MatrixClient", function () { const filter = new Filter(client.credentials.userId); const filterId = await client.getOrCreateFilter(filterName, filter); - expect(filterId).toEqual(FILTER_RESPONSE.data?.filter_id); + expect(filterId).toEqual(!Array.isArray(FILTER_RESPONSE.data) && FILTER_RESPONSE.data?.filter_id); }); }); @@ -3035,4 +3360,45 @@ describe("MatrixClient", function () { expect(httpLookups.length).toEqual(0); }); }); + + describe("identityHashedLookup", () => { + it("should return hashed lookup results", async () => { + const ID_ACCESS_TOKEN = "hello_id_server_please_let_me_make_a_request"; + + client.http.idServerRequest = jest.fn().mockImplementation((method, path, params) => { + if (method === "GET" && path === "/hash_details") { + return { algorithms: ["sha256"], lookup_pepper: "carrot" }; + } else if (method === "POST" && path === "/lookup") { + return { + mappings: { + "WHA-MgrrsZACDI9F8OaVagpiyiV2sjZylGHJteT4OMU": "@bob:homeserver.dummy", + }, + }; + } + + throw new Error("Test impl doesn't know about this request"); + }); + + const lookupResult = await client.identityHashedLookup([["bob@email.dummy", "email"]], ID_ACCESS_TOKEN); + + expect(client.http.idServerRequest).toHaveBeenCalledWith( + "GET", + "/hash_details", + undefined, + "/_matrix/identity/v2", + ID_ACCESS_TOKEN, + ); + + expect(client.http.idServerRequest).toHaveBeenCalledWith( + "POST", + "/lookup", + { pepper: "carrot", algorithm: "sha256", addresses: ["WHA-MgrrsZACDI9F8OaVagpiyiV2sjZylGHJteT4OMU"] }, + "/_matrix/identity/v2", + ID_ACCESS_TOKEN, + ); + + expect(lookupResult).toHaveLength(1); + expect(lookupResult[0]).toEqual({ address: "bob@email.dummy", mxid: "@bob:homeserver.dummy" }); + }); + }); }); diff --git a/spec/unit/matrixrtc/CallMembership.spec.ts b/spec/unit/matrixrtc/CallMembership.spec.ts index 3d259103cc5..c3281b96ac3 100644 --- a/spec/unit/matrixrtc/CallMembership.spec.ts +++ b/spec/unit/matrixrtc/CallMembership.spec.ts @@ -15,16 +15,7 @@ limitations under the License. */ import { MatrixEvent } from "../../../src"; -import { CallMembership, CallMembershipData } from "../../../src/matrixrtc/CallMembership"; - -const membershipTemplate: CallMembershipData = { - call_id: "", - scope: "m.room", - application: "m.call", - device_id: "AAAAAAA", - expires: 5000, - membershipID: "bloop", -}; +import { CallMembership, CallMembershipDataLegacy, SessionMembershipData } from "../../../src/matrixrtc/CallMembership"; function makeMockEvent(originTs = 0): MatrixEvent { return { @@ -34,107 +25,165 @@ function makeMockEvent(originTs = 0): MatrixEvent { } describe("CallMembership", () => { - it("rejects membership with no expiry and no expires_ts", () => { - expect(() => { - new CallMembership( - makeMockEvent(), - Object.assign({}, membershipTemplate, { expires: undefined, expires_ts: undefined }), + describe("CallMembershipDataLegacy", () => { + const membershipTemplate: CallMembershipDataLegacy = { + call_id: "", + scope: "m.room", + application: "m.call", + device_id: "AAAAAAA", + expires: 5000, + membershipID: "bloop", + foci_active: [{ type: "livekit" }], + }; + it("rejects membership with no expiry and no expires_ts", () => { + expect(() => { + new CallMembership( + makeMockEvent(), + Object.assign({}, membershipTemplate, { expires: undefined, expires_ts: undefined }), + ); + }).toThrow(); + }); + + it("rejects membership with no device_id", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { device_id: undefined })); + }).toThrow(); + }); + + it("rejects membership with no call_id", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { call_id: undefined })); + }).toThrow(); + }); + + it("allow membership with no scope", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { scope: undefined })); + }).not.toThrow(); + }); + it("rejects with malformatted expires_ts", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires_ts: "string" })); + }).toThrow(); + }); + it("rejects with malformatted expires", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires: "string" })); + }).toThrow(); + }); + + it("uses event timestamp if no created_ts", () => { + const membership = new CallMembership(makeMockEvent(12345), membershipTemplate); + expect(membership.createdTs()).toEqual(12345); + }); + + it("uses created_ts if present", () => { + const membership = new CallMembership( + makeMockEvent(12345), + Object.assign({}, membershipTemplate, { created_ts: 67890 }), ); - }).toThrow(); - }); + expect(membership.createdTs()).toEqual(67890); + }); - it("rejects membership with no device_id", () => { - expect(() => { - new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { device_id: undefined })); - }).toThrow(); - }); + it("computes absolute expiry time based on expires", () => { + const membership = new CallMembership(makeMockEvent(1000), membershipTemplate); + expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000); + }); - it("rejects membership with no call_id", () => { - expect(() => { - new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { call_id: undefined })); - }).toThrow(); - }); + it("computes absolute expiry time based on expires_ts", () => { + const membership = new CallMembership( + makeMockEvent(1000), + Object.assign({}, membershipTemplate, { expires_ts: 6000 }), + ); + expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000); + }); - it("rejects membership with no scope", () => { - expect(() => { - new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { scope: undefined })); - }).toThrow(); - }); - it("rejects with malformatted expires_ts", () => { - expect(() => { - new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires_ts: "string" })); - }).toThrow(); - }); - it("rejects with malformatted expires", () => { - expect(() => { - new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires: "string" })); - }).toThrow(); + it("returns preferred foci", () => { + const fakeEvent = makeMockEvent(); + const mockFocus = { type: "this_is_a_mock_focus" }; + const membership = new CallMembership( + fakeEvent, + Object.assign({}, membershipTemplate, { foci_active: [mockFocus] }), + ); + expect(membership.getPreferredFoci()).toEqual([mockFocus]); + }); }); - it("uses event timestamp if no created_ts", () => { - const membership = new CallMembership(makeMockEvent(12345), membershipTemplate); - expect(membership.createdTs()).toEqual(12345); - }); + describe("SessionMembershipData", () => { + const membershipTemplate: SessionMembershipData = { + call_id: "", + scope: "m.room", + application: "m.call", + device_id: "AAAAAAA", + focus_active: { type: "livekit" }, + foci_preferred: [{ type: "livekit" }], + }; + + it("rejects membership with no device_id", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { device_id: undefined })); + }).toThrow(); + }); - it("uses created_ts if present", () => { - const membership = new CallMembership( - makeMockEvent(12345), - Object.assign({}, membershipTemplate, { created_ts: 67890 }), - ); - expect(membership.createdTs()).toEqual(67890); - }); + it("rejects membership with no call_id", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { call_id: undefined })); + }).toThrow(); + }); - it("computes absolute expiry time based on expires", () => { - const membership = new CallMembership(makeMockEvent(1000), membershipTemplate); - expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000); - }); + it("allow membership with no scope", () => { + expect(() => { + new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { scope: undefined })); + }).not.toThrow(); + }); - it("computes absolute expiry time based on expires_ts", () => { - const membership = new CallMembership( - makeMockEvent(1000), - Object.assign({}, membershipTemplate, { expires: undefined, expires_ts: 6000 }), - ); - expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000); - }); + it("uses event timestamp if no created_ts", () => { + const membership = new CallMembership(makeMockEvent(12345), membershipTemplate); + expect(membership.createdTs()).toEqual(12345); + }); - it("considers memberships unexpired if local age low enough", () => { - const fakeEvent = makeMockEvent(1000); - fakeEvent.getLocalAge = jest.fn().mockReturnValue(3000); - const membership = new CallMembership(fakeEvent, membershipTemplate); - expect(membership.isExpired()).toEqual(false); - }); + it("uses created_ts if present", () => { + const membership = new CallMembership( + makeMockEvent(12345), + Object.assign({}, membershipTemplate, { created_ts: 67890 }), + ); + expect(membership.createdTs()).toEqual(67890); + }); - it("considers memberships expired when local age large", () => { - const fakeEvent = makeMockEvent(1000); - fakeEvent.localTimestamp = Date.now() - 6000; - const membership = new CallMembership(fakeEvent, membershipTemplate); - expect(membership.isExpired()).toEqual(true); - }); + it("considers memberships unexpired if local age low enough", () => { + const fakeEvent = makeMockEvent(1000); + fakeEvent.getLocalAge = jest.fn().mockReturnValue(3000); + const membership = new CallMembership(fakeEvent, membershipTemplate); + expect(membership.isExpired()).toEqual(false); + }); - it("returns active foci", () => { - const fakeEvent = makeMockEvent(); - const mockFocus = { type: "this_is_a_mock_focus" }; - const membership = new CallMembership( - fakeEvent, - Object.assign({}, membershipTemplate, { foci_active: [mockFocus] }), - ); - expect(membership.getActiveFoci()).toEqual([mockFocus]); + it("returns preferred foci", () => { + const fakeEvent = makeMockEvent(); + const mockFocus = { type: "this_is_a_mock_focus" }; + const membership = new CallMembership( + fakeEvent, + Object.assign({}, membershipTemplate, { foci_preferred: [mockFocus] }), + ); + expect(membership.getPreferredFoci()).toEqual([mockFocus]); + }); }); describe("expiry calculation", () => { let fakeEvent: MatrixEvent; let membership: CallMembership; + const membershipTemplate: CallMembershipDataLegacy = { + call_id: "", + scope: "m.room", + application: "m.call", + device_id: "AAAAAAA", + expires: 5000, + membershipID: "bloop", + foci_active: [{ type: "livekit" }], + }; beforeEach(() => { // server origin timestamp for this event is 1000 fakeEvent = makeMockEvent(1000); - // our clock would have been at 2000 at the creation time (our clock at event receive time - age) - // (ie. the local clock is 1 second ahead of the servers' clocks) - fakeEvent.localTimestamp = 2000; - - // for simplicity's sake, we say that the event's age is zero - fakeEvent.getLocalAge = jest.fn().mockReturnValue(0); - membership = new CallMembership(fakeEvent!, membershipTemplate); jest.useFakeTimers(); @@ -145,6 +194,13 @@ describe("CallMembership", () => { }); it("converts expiry time into local clock", () => { + // our clock would have been at 2000 at the creation time (our clock at event receive time - age) + // (ie. the local clock is 1 second ahead of the servers' clocks) + fakeEvent.localTimestamp = 2000; + + // for simplicity's sake, we say that the event's age is zero + fakeEvent.getLocalAge = jest.fn().mockReturnValue(0); + // for sanity's sake, make sure the server-relative expiry time is what we expect expect(membership.getAbsoluteExpiry()).toEqual(6000); // therefore the expiry time converted to our clock should be 1 second later @@ -153,7 +209,8 @@ describe("CallMembership", () => { it("calculates time until expiry", () => { jest.setSystemTime(2000); - expect(membership.getMsUntilExpiry()).toEqual(5000); + // should be using absolute expiry time + expect(membership.getMsUntilExpiry()).toEqual(4000); }); }); }); diff --git a/spec/unit/matrixrtc/LivekitFocus.spec.ts b/spec/unit/matrixrtc/LivekitFocus.spec.ts new file mode 100644 index 00000000000..728d6a68de6 --- /dev/null +++ b/spec/unit/matrixrtc/LivekitFocus.spec.ts @@ -0,0 +1,60 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { isLivekitFocus, isLivekitFocusActive, isLivekitFocusConfig } from "../../../src/matrixrtc/LivekitFocus"; + +describe("LivekitFocus", () => { + it("isLivekitFocus", () => { + expect( + isLivekitFocus({ + type: "livekit", + livekit_service_url: "http://test.com", + livekit_alias: "test", + }), + ).toBeTruthy(); + expect(isLivekitFocus({ type: "livekit" })).toBeFalsy(); + expect( + isLivekitFocus({ type: "not-livekit", livekit_service_url: "http://test.com", livekit_alias: "test" }), + ).toBeFalsy(); + expect( + isLivekitFocus({ type: "livekit", other_service_url: "http://test.com", livekit_alias: "test" }), + ).toBeFalsy(); + expect( + isLivekitFocus({ type: "livekit", livekit_service_url: "http://test.com", other_alias: "test" }), + ).toBeFalsy(); + }); + it("isLivekitFocusActive", () => { + expect( + isLivekitFocusActive({ + type: "livekit", + focus_selection: "oldest_membership", + }), + ).toBeTruthy(); + expect(isLivekitFocusActive({ type: "livekit" })).toBeFalsy(); + expect(isLivekitFocusActive({ type: "not-livekit", focus_selection: "oldest_membership" })).toBeFalsy(); + }); + it("isLivekitFocusConfig", () => { + expect( + isLivekitFocusConfig({ + type: "livekit", + livekit_service_url: "http://test.com", + }), + ).toBeTruthy(); + expect(isLivekitFocusConfig({ type: "livekit" })).toBeFalsy(); + expect(isLivekitFocusConfig({ type: "not-livekit", livekit_service_url: "http://test.com" })).toBeFalsy(); + expect(isLivekitFocusConfig({ type: "livekit", other_service_url: "oldest_membership" })).toBeFalsy(); + }); +}); diff --git a/spec/unit/matrixrtc/MatrixRTCSession.spec.ts b/spec/unit/matrixrtc/MatrixRTCSession.spec.ts index d061c60d0cb..4cc225f213f 100644 --- a/spec/unit/matrixrtc/MatrixRTCSession.spec.ts +++ b/spec/unit/matrixrtc/MatrixRTCSession.spec.ts @@ -14,9 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EventTimeline, EventType, MatrixClient, MatrixError, MatrixEvent, Room } from "../../../src"; +import { encodeBase64, EventTimeline, EventType, MatrixClient, MatrixError, MatrixEvent, Room } from "../../../src"; import { KnownMembership } from "../../../src/@types/membership"; -import { CallMembershipData } from "../../../src/matrixrtc/CallMembership"; +import { + CallMembershipData, + CallMembershipDataLegacy, + SessionMembershipData, +} from "../../../src/matrixrtc/CallMembership"; import { MatrixRTCSession, MatrixRTCSessionEvent } from "../../../src/matrixrtc/MatrixRTCSession"; import { EncryptionKeysEventContent } from "../../../src/matrixrtc/types"; import { randomString } from "../../../src/randomstring"; @@ -29,6 +33,7 @@ const membershipTemplate: CallMembershipData = { device_id: "AAAAAAA", expires: 60 * 60 * 1000, membershipID: "bloop", + foci_active: [{ type: "livekit", livekit_service_url: "https://lk.url" }], }; const mockFocus = { type: "mock" }; @@ -41,6 +46,9 @@ describe("MatrixRTCSession", () => { client = new MatrixClient({ baseUrl: "base_url" }); client.getUserId = jest.fn().mockReturnValue("@alice:example.org"); client.getDeviceId = jest.fn().mockReturnValue("AAAAAAA"); + client.doesServerSupportUnstableFeature = jest.fn((feature) => + Promise.resolve(feature === "org.matrix.msc4140"), + ); }); afterEach(() => { @@ -65,14 +73,17 @@ describe("MatrixRTCSession", () => { }); it("ignores expired memberships events", () => { + jest.useFakeTimers(); const expiredMembership = Object.assign({}, membershipTemplate); expiredMembership.expires = 1000; expiredMembership.device_id = "EXPIRED"; - const mockRoom = makeMockRoom([membershipTemplate, expiredMembership], 10000); + const mockRoom = makeMockRoom([membershipTemplate, expiredMembership]); + jest.advanceTimersByTime(2000); sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); expect(sess?.memberships.length).toEqual(1); expect(sess?.memberships[0].deviceId).toEqual("AAAAAAA"); + jest.useRealTimers(); }); it("ignores memberships events of members not in the room", () => { @@ -83,12 +94,15 @@ describe("MatrixRTCSession", () => { }); it("honours created_ts", () => { + jest.useFakeTimers(); + jest.setSystemTime(500); const expiredMembership = Object.assign({}, membershipTemplate); expiredMembership.created_ts = 500; expiredMembership.expires = 1000; const mockRoom = makeMockRoom([expiredMembership]); sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); expect(sess?.memberships[0].getAbsoluteExpiry()).toEqual(1500); + jest.useRealTimers(); }); it("returns empty session if no membership events are present", () => { @@ -98,22 +112,33 @@ describe("MatrixRTCSession", () => { }); it("safely ignores events with no memberships section", () => { + const roomId = randomString(8); + const event = { + getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix), + getContent: jest.fn().mockReturnValue({}), + getSender: jest.fn().mockReturnValue("@mock:user.example"), + getTs: jest.fn().mockReturnValue(1000), + getLocalAge: jest.fn().mockReturnValue(0), + }; const mockRoom = { ...makeMockRoom([]), - roomId: randomString(8), + roomId, getLiveTimeline: jest.fn().mockReturnValue({ getState: jest.fn().mockReturnValue({ on: jest.fn(), off: jest.fn(), - getStateEvents: (_type: string, _stateKey: string) => [ - { - getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix), - getContent: jest.fn().mockReturnValue({}), - getSender: jest.fn().mockReturnValue("@mock:user.example"), - getTs: jest.fn().mockReturnValue(1000), - getLocalAge: jest.fn().mockReturnValue(0), - }, - ], + getStateEvents: (_type: string, _stateKey: string) => [event], + events: new Map([ + [ + EventType.GroupCallMemberPrefix, + { + size: () => true, + has: (_stateKey: string) => true, + get: (_stateKey: string) => event, + values: () => [event], + }, + ], + ]), }), }), }; @@ -122,22 +147,33 @@ describe("MatrixRTCSession", () => { }); it("safely ignores events with junk memberships section", () => { + const roomId = randomString(8); + const event = { + getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix), + getContent: jest.fn().mockReturnValue({ memberships: ["i am a fish"] }), + getSender: jest.fn().mockReturnValue("@mock:user.example"), + getTs: jest.fn().mockReturnValue(1000), + getLocalAge: jest.fn().mockReturnValue(0), + }; const mockRoom = { ...makeMockRoom([]), - roomId: randomString(8), + roomId, getLiveTimeline: jest.fn().mockReturnValue({ getState: jest.fn().mockReturnValue({ on: jest.fn(), off: jest.fn(), - getStateEvents: (_type: string, _stateKey: string) => [ - { - getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix), - getContent: jest.fn().mockReturnValue({ memberships: "i am a fish" }), - getSender: jest.fn().mockReturnValue("@mock:user.example"), - getTs: jest.fn().mockReturnValue(1000), - getLocalAge: jest.fn().mockReturnValue(0), - }, - ], + getStateEvents: (_type: string, _stateKey: string) => [event], + events: new Map([ + [ + EventType.GroupCallMemberPrefix, + { + size: () => true, + has: (_stateKey: string) => true, + get: (_stateKey: string) => event, + values: () => [event], + }, + ], + ]), }), }), }; @@ -185,8 +221,97 @@ describe("MatrixRTCSession", () => { expect(sess.memberships).toHaveLength(0); }); + describe("updateCallMembershipEvent", () => { + const mockFocus = { type: "livekit", livekit_service_url: "https://test.org" }; + const joinSessionConfig = { useLegacyMemberEvents: false }; + + const legacyMembershipData: CallMembershipDataLegacy = { + call_id: "", + scope: "m.room", + application: "m.call", + device_id: "AAAAAAA_legacy", + expires: 60 * 60 * 1000, + membershipID: "bloop", + foci_active: [mockFocus], + }; + + const expiredLegacyMembershipData: CallMembershipDataLegacy = { + ...legacyMembershipData, + device_id: "AAAAAAA_legacy_expired", + expires: 0, + }; + + const sessionMembershipData: SessionMembershipData = { + call_id: "", + scope: "m.room", + application: "m.call", + device_id: "AAAAAAA_session", + focus_active: mockFocus, + foci_preferred: [mockFocus], + }; + + let sendStateEventMock: jest.Mock; + let sendDelayedStateMock: jest.Mock; + + let sentStateEvent: Promise; + let sentDelayedState: Promise; + + beforeEach(() => { + sentStateEvent = new Promise((resolve) => { + sendStateEventMock = jest.fn(resolve); + }); + sentDelayedState = new Promise((resolve) => { + sendDelayedStateMock = jest.fn(() => { + resolve(); + return { + delay_id: "id", + }; + }); + }); + client.sendStateEvent = sendStateEventMock; + client._unstable_sendDelayedStateEvent = sendDelayedStateMock; + }); + + async function testSession( + membershipData: CallMembershipData[] | SessionMembershipData, + shouldUseLegacy: boolean, + ): Promise { + sess = MatrixRTCSession.roomSessionForRoom(client, makeMockRoom(membershipData)); + + const makeNewLegacyMembershipsMock = jest.spyOn(sess as any, "makeNewLegacyMemberships"); + const makeNewMembershipMock = jest.spyOn(sess as any, "makeNewMembership"); + + sess.joinRoomSession([mockFocus], mockFocus, joinSessionConfig); + await Promise.race([sentStateEvent, new Promise((resolve) => setTimeout(resolve, 500))]); + + expect(makeNewLegacyMembershipsMock).toHaveBeenCalledTimes(shouldUseLegacy ? 1 : 0); + expect(makeNewMembershipMock).toHaveBeenCalledTimes(shouldUseLegacy ? 0 : 1); + + await Promise.race([sentDelayedState, new Promise((resolve) => setTimeout(resolve, 500))]); + expect(client._unstable_sendDelayedStateEvent).toHaveBeenCalledTimes(shouldUseLegacy ? 0 : 1); + } + + it("uses legacy events if there are any active legacy calls", async () => { + await testSession([expiredLegacyMembershipData, legacyMembershipData, sessionMembershipData], true); + }); + + it('uses legacy events if a non-legacy call is in a "memberships" array', async () => { + await testSession([sessionMembershipData], true); + }); + + it("uses non-legacy events if all legacy calls are expired", async () => { + await testSession([expiredLegacyMembershipData], false); + }); + + it("uses non-legacy events if there are only non-legacy calls", async () => { + await testSession(sessionMembershipData, false); + }); + }); + describe("getOldestMembership", () => { it("returns the oldest membership event", () => { + jest.useFakeTimers(); + jest.setSystemTime(4000); const mockRoom = makeMockRoom([ Object.assign({}, membershipTemplate, { device_id: "foo", created_ts: 3000 }), Object.assign({}, membershipTemplate, { device_id: "old", created_ts: 1000 }), @@ -195,18 +320,98 @@ describe("MatrixRTCSession", () => { sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); expect(sess.getOldestMembership()!.deviceId).toEqual("old"); + jest.useRealTimers(); + }); + }); + + describe("getsActiveFocus", () => { + const activeFociConfig = { type: "livekit", livekit_service_url: "https://active.url" }; + it("gets the correct active focus with oldest_membership", () => { + jest.useFakeTimers(); + jest.setSystemTime(3000); + const mockRoom = makeMockRoom([ + Object.assign({}, membershipTemplate, { + device_id: "foo", + created_ts: 500, + foci_active: [activeFociConfig], + }), + Object.assign({}, membershipTemplate, { device_id: "old", created_ts: 1000 }), + Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }), + ]); + + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + + sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], { + type: "livekit", + focus_selection: "oldest_membership", + }); + expect(sess.getActiveFocus()).toBe(activeFociConfig); + jest.useRealTimers(); + }); + it("does not provide focus if the selction method is unknown", () => { + const mockRoom = makeMockRoom([ + Object.assign({}, membershipTemplate, { + device_id: "foo", + created_ts: 500, + foci_active: [activeFociConfig], + }), + Object.assign({}, membershipTemplate, { device_id: "old", created_ts: 1000 }), + Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }), + ]); + + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + + sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], { + type: "livekit", + focus_selection: "unknown", + }); + expect(sess.getActiveFocus()).toBe(undefined); + }); + it("gets the correct active focus legacy", () => { + jest.useFakeTimers(); + jest.setSystemTime(3000); + const mockRoom = makeMockRoom([ + Object.assign({}, membershipTemplate, { + device_id: "foo", + created_ts: 500, + foci_active: [activeFociConfig], + }), + Object.assign({}, membershipTemplate, { device_id: "old", created_ts: 1000 }), + Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }), + ]); + + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + + sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }]); + expect(sess.getActiveFocus()).toBe(activeFociConfig); + jest.useRealTimers(); }); }); describe("joining", () => { let mockRoom: Room; let sendStateEventMock: jest.Mock; + let sendDelayedStateMock: jest.Mock; let sendEventMock: jest.Mock; + let sentStateEvent: Promise; + let sentDelayedState: Promise; + beforeEach(() => { - sendStateEventMock = jest.fn(); + sentStateEvent = new Promise((resolve) => { + sendStateEventMock = jest.fn(resolve); + }); + sentDelayedState = new Promise((resolve) => { + sendDelayedStateMock = jest.fn(() => { + resolve(); + return { + delay_id: "id", + }; + }); + }); sendEventMock = jest.fn(); client.sendStateEvent = sendStateEventMock; + client._unstable_sendDelayedStateEvent = sendDelayedStateMock; client.sendEvent = sendEventMock; mockRoom = makeMockRoom([]); @@ -223,13 +428,15 @@ describe("MatrixRTCSession", () => { }); it("shows joined once join is called", () => { - sess!.joinRoomSession([mockFocus]); + sess!.joinRoomSession([mockFocus], mockFocus); expect(sess!.isJoined()).toEqual(true); }); - it("sends a membership event when joining a call", () => { + it("sends a membership event when joining a call", async () => { + const realSetTimeout = setTimeout; jest.useFakeTimers(); - sess!.joinRoomSession([mockFocus]); + sess!.joinRoomSession([mockFocus], mockFocus); + await Promise.race([sentStateEvent, new Promise((resolve) => realSetTimeout(resolve, 500))]); expect(client.sendStateEvent).toHaveBeenCalledWith( mockRoom!.roomId, EventType.GroupCallMemberPrefix, @@ -242,22 +449,65 @@ describe("MatrixRTCSession", () => { device_id: "AAAAAAA", expires: 3600000, expires_ts: Date.now() + 3600000, - foci_active: [{ type: "mock" }], + foci_active: [mockFocus], + membershipID: expect.stringMatching(".*"), }, ], }, "@alice:example.org", ); + await Promise.race([sentDelayedState, new Promise((resolve) => realSetTimeout(resolve, 500))]); + expect(client._unstable_sendDelayedStateEvent).toHaveBeenCalledTimes(0); jest.useRealTimers(); }); + describe("non-legacy calls", () => { + const activeFocusConfig = { type: "livekit", livekit_service_url: "https://active.url" }; + const activeFocus = { type: "livekit", focus_selection: "oldest_membership" }; + + async function testJoin(useOwnedStateEvents: boolean): Promise { + const realSetTimeout = setTimeout; + if (useOwnedStateEvents) { + mockRoom.getVersion = jest.fn().mockReturnValue("org.matrix.msc3779.default"); + } + + jest.useFakeTimers(); + sess!.joinRoomSession([activeFocusConfig], activeFocus, { useLegacyMemberEvents: false }); + await Promise.race([sentStateEvent, new Promise((resolve) => realSetTimeout(resolve, 500))]); + expect(client.sendStateEvent).toHaveBeenCalledWith( + mockRoom!.roomId, + EventType.GroupCallMemberPrefix, + { + application: "m.call", + scope: "m.room", + call_id: "", + device_id: "AAAAAAA", + foci_preferred: [activeFocusConfig], + focus_active: activeFocus, + } satisfies SessionMembershipData, + `${!useOwnedStateEvents ? "_" : ""}@alice:example.org_AAAAAAA`, + ); + await Promise.race([sentDelayedState, new Promise((resolve) => realSetTimeout(resolve, 500))]); + expect(client._unstable_sendDelayedStateEvent).toHaveBeenCalledTimes(1); + jest.useRealTimers(); + } + + it("sends a membership event with session payload when joining a non-legacy call", async () => { + await testJoin(false); + }); + + it("does not prefix the state key with _ for rooms that support user-owned state events", async () => { + await testJoin(true); + }); + }); + it("does nothing if join called when already joined", () => { - sess!.joinRoomSession([mockFocus]); + sess!.joinRoomSession([mockFocus], mockFocus); expect(client.sendStateEvent).toHaveBeenCalledTimes(1); - sess!.joinRoomSession([mockFocus]); + sess!.joinRoomSession([mockFocus], mockFocus); expect(client.sendStateEvent).toHaveBeenCalledTimes(1); }); @@ -274,15 +524,25 @@ describe("MatrixRTCSession", () => { const sendStateEventMock = jest.fn().mockImplementation(resolveFn); client.sendStateEvent = sendStateEventMock; - sess!.joinRoomSession([mockFocus]); + sess!.joinRoomSession([mockFocus], mockFocus); const eventContent = await eventSentPromise; - // definitely should have renewed by 1 second before the expiry! - const timeElapsed = 60 * 60 * 1000 - 1000; - mockRoom.getLiveTimeline().getState(EventTimeline.FORWARDS)!.getStateEvents = jest - .fn() - .mockReturnValue(mockRTCEvent(eventContent.memberships, mockRoom.roomId, timeElapsed)); + jest.setSystemTime(1000); + const event = mockRTCEvent(eventContent.memberships, mockRoom.roomId); + const getState = mockRoom.getLiveTimeline().getState(EventTimeline.FORWARDS)!; + getState.getStateEvents = jest.fn().mockReturnValue(event); + getState.events = new Map([ + [ + event.getType(), + { + size: () => true, + has: (_stateKey: string) => true, + get: (_stateKey: string) => event, + values: () => [event], + } as unknown as Map, + ], + ]); const eventReSentPromise = new Promise>((r) => { resolveFn = (_roomId: string, _type: string, val: Record) => { @@ -292,6 +552,8 @@ describe("MatrixRTCSession", () => { sendStateEventMock.mockReset().mockImplementation(resolveFn); + // definitely should have renewed by 1 second before the expiry! + const timeElapsed = 60 * 60 * 1000 - 1000; jest.setSystemTime(Date.now() + timeElapsed); jest.advanceTimersByTime(timeElapsed); await eventReSentPromise; @@ -308,7 +570,7 @@ describe("MatrixRTCSession", () => { device_id: "AAAAAAA", expires: 3600000 * 2, expires_ts: 1000 + 3600000 * 2, - foci_active: [{ type: "mock" }], + foci_active: [mockFocus], created_ts: 1000, membershipID: expect.stringMatching(".*"), }, @@ -322,7 +584,7 @@ describe("MatrixRTCSession", () => { }); it("creates a key when joining", () => { - sess!.joinRoomSession([mockFocus], true); + sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); const keys = sess?.getKeysForParticipant("@alice:example.org", "AAAAAAA"); expect(keys).toHaveLength(1); @@ -336,7 +598,7 @@ describe("MatrixRTCSession", () => { sendEventMock.mockImplementation(resolve); }); - sess!.joinRoomSession([mockFocus], true); + sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); await eventSentPromise; @@ -352,6 +614,17 @@ describe("MatrixRTCSession", () => { }); }); + it("does not send key if join called when already joined", () => { + sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); + + expect(client.sendStateEvent).toHaveBeenCalledTimes(1); + expect(client.sendEvent).toHaveBeenCalledTimes(1); + + sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); + expect(client.sendStateEvent).toHaveBeenCalledTimes(1); + expect(client.sendEvent).toHaveBeenCalledTimes(1); + }); + it("retries key sends", async () => { jest.useFakeTimers(); let firstEventSent = false; @@ -372,7 +645,7 @@ describe("MatrixRTCSession", () => { }); }); - sess!.joinRoomSession([mockFocus], true); + sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); jest.advanceTimersByTime(10000); await eventSentPromise; @@ -394,7 +667,7 @@ describe("MatrixRTCSession", () => { throw e; }); - sess!.joinRoomSession([mockFocus], true); + sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); expect(client.cancelPendingEvent).toHaveBeenCalledWith(eventSentinel); }); @@ -409,7 +682,7 @@ describe("MatrixRTCSession", () => { sendEventMock.mockImplementation(resolve); }); - sess.joinRoomSession([mockFocus], true); + sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); await keysSentPromise1; sendEventMock.mockClear(); @@ -428,7 +701,7 @@ describe("MatrixRTCSession", () => { mockRoom.getLiveTimeline().getState = jest .fn() - .mockReturnValue(makeMockRoomState([membershipTemplate, member2], mockRoom.roomId, undefined)); + .mockReturnValue(makeMockRoomState([membershipTemplate, member2], mockRoom.roomId)); sess.onMembershipUpdate(); await keysSentPromise2; @@ -439,6 +712,214 @@ describe("MatrixRTCSession", () => { } }); + it("Does not re-send key if memberships stays same", async () => { + jest.useFakeTimers(); + try { + const keysSentPromise1 = new Promise((resolve) => { + sendEventMock.mockImplementation(resolve); + }); + + const member1 = membershipTemplate; + const member2 = Object.assign({}, membershipTemplate, { + device_id: "BBBBBBB", + }); + + const mockRoom = makeMockRoom([member1, member2]); + mockRoom.getLiveTimeline().getState = jest + .fn() + .mockReturnValue(makeMockRoomState([member1, member2], mockRoom.roomId)); + + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); + + await keysSentPromise1; + + // make sure an encryption key was sent + expect(sendEventMock).toHaveBeenCalledWith( + expect.stringMatching(".*"), + "io.element.call.encryption_keys", + { + call_id: "", + device_id: "AAAAAAA", + keys: [ + { + index: 0, + key: expect.stringMatching(".*"), + }, + ], + }, + ); + + sendEventMock.mockClear(); + + // these should be a no-op: + sess.onMembershipUpdate(); + expect(sendEventMock).toHaveBeenCalledTimes(0); + } finally { + jest.useRealTimers(); + } + }); + + it("Re-sends key if a member changes membership ID", async () => { + jest.useFakeTimers(); + try { + const keysSentPromise1 = new Promise((resolve) => { + sendEventMock.mockImplementation(resolve); + }); + + const member1 = membershipTemplate; + const member2 = { + ...membershipTemplate, + device_id: "BBBBBBB", + }; + + const mockRoom = makeMockRoom([member1, member2]); + mockRoom.getLiveTimeline().getState = jest + .fn() + .mockReturnValue(makeMockRoomState([member1, member2], mockRoom.roomId)); + + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); + + await keysSentPromise1; + + // make sure an encryption key was sent + expect(sendEventMock).toHaveBeenCalledWith( + expect.stringMatching(".*"), + "io.element.call.encryption_keys", + { + call_id: "", + device_id: "AAAAAAA", + keys: [ + { + index: 0, + key: expect.stringMatching(".*"), + }, + ], + }, + ); + + sendEventMock.mockClear(); + + // this should be a no-op: + sess.onMembershipUpdate(); + expect(sendEventMock).toHaveBeenCalledTimes(0); + + // advance time to avoid key throttling + jest.advanceTimersByTime(10000); + + // update membership ID + member2.membershipID = "newID"; + + const keysSentPromise2 = new Promise((resolve) => { + sendEventMock.mockImplementation(resolve); + }); + + // this should re-send the key + sess.onMembershipUpdate(); + + await keysSentPromise2; + + expect(sendEventMock).toHaveBeenCalledWith( + expect.stringMatching(".*"), + "io.element.call.encryption_keys", + { + call_id: "", + device_id: "AAAAAAA", + keys: [ + { + index: 0, + key: expect.stringMatching(".*"), + }, + ], + }, + ); + } finally { + jest.useRealTimers(); + } + }); + + it("Re-sends key if a member changes created_ts", async () => { + jest.useFakeTimers(); + jest.setSystemTime(1000); + try { + const keysSentPromise1 = new Promise((resolve) => { + sendEventMock.mockImplementation(resolve); + }); + + const member1 = { ...membershipTemplate, created_ts: 1000 }; + const member2 = { + ...membershipTemplate, + created_ts: 1000, + device_id: "BBBBBBB", + }; + + const mockRoom = makeMockRoom([member1, member2]); + mockRoom.getLiveTimeline().getState = jest + .fn() + .mockReturnValue(makeMockRoomState([member1, member2], mockRoom.roomId)); + + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); + + await keysSentPromise1; + + // make sure an encryption key was sent + expect(sendEventMock).toHaveBeenCalledWith( + expect.stringMatching(".*"), + "io.element.call.encryption_keys", + { + call_id: "", + device_id: "AAAAAAA", + keys: [ + { + index: 0, + key: expect.stringMatching(".*"), + }, + ], + }, + ); + + sendEventMock.mockClear(); + + // this should be a no-op: + sess.onMembershipUpdate(); + expect(sendEventMock).toHaveBeenCalledTimes(0); + + // advance time to avoid key throttling + jest.advanceTimersByTime(10000); + + // update created_ts + member2.created_ts = 5000; + + const keysSentPromise2 = new Promise((resolve) => { + sendEventMock.mockImplementation(resolve); + }); + + // this should re-send the key + sess.onMembershipUpdate(); + + await keysSentPromise2; + + expect(sendEventMock).toHaveBeenCalledWith( + expect.stringMatching(".*"), + "io.element.call.encryption_keys", + { + call_id: "", + device_id: "AAAAAAA", + keys: [ + { + index: 0, + key: expect.stringMatching(".*"), + }, + ], + }, + ); + } finally { + jest.useRealTimers(); + } + }); + it("Rotates key if a member leaves", async () => { jest.useFakeTimers(); try { @@ -462,7 +943,7 @@ describe("MatrixRTCSession", () => { sendEventMock.mockImplementation((_roomId, _evType, payload) => resolve(payload)); }); - sess.joinRoomSession([mockFocus], true); + sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); const firstKeysPayload = await keysSentPromise1; expect(firstKeysPayload.keys).toHaveLength(1); @@ -474,7 +955,7 @@ describe("MatrixRTCSession", () => { mockRoom.getLiveTimeline().getState = jest .fn() - .mockReturnValue(makeMockRoomState([membershipTemplate], mockRoom.roomId, undefined)); + .mockReturnValue(makeMockRoomState([membershipTemplate], mockRoom.roomId)); sess.onMembershipUpdate(); jest.advanceTimersByTime(10000); @@ -489,7 +970,7 @@ describe("MatrixRTCSession", () => { }); it("Doesn't re-send key immediately", async () => { - const realSetImmediate = setImmediate; + const realSetTimeout = setTimeout; jest.useFakeTimers(); try { const mockRoom = makeMockRoom([membershipTemplate]); @@ -499,7 +980,7 @@ describe("MatrixRTCSession", () => { sendEventMock.mockImplementation(resolve); }); - sess.joinRoomSession([mockFocus], true); + sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); await keysSentPromise1; sendEventMock.mockClear(); @@ -513,11 +994,11 @@ describe("MatrixRTCSession", () => { mockRoom.getLiveTimeline().getState = jest .fn() - .mockReturnValue(makeMockRoomState([membershipTemplate, member2], mockRoom.roomId, undefined)); + .mockReturnValue(makeMockRoomState([membershipTemplate, member2], mockRoom.roomId)); sess.onMembershipUpdate(); await new Promise((resolve) => { - realSetImmediate(resolve); + realSetTimeout(resolve); }); expect(sendEventMock).not.toHaveBeenCalled(); @@ -545,9 +1026,7 @@ describe("MatrixRTCSession", () => { const onMembershipsChanged = jest.fn(); sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged); - mockRoom.getLiveTimeline().getState = jest - .fn() - .mockReturnValue(makeMockRoomState([], mockRoom.roomId, undefined)); + mockRoom.getLiveTimeline().getState = jest.fn().mockReturnValue(makeMockRoomState([], mockRoom.roomId)); sess.onMembershipUpdate(); expect(onMembershipsChanged).toHaveBeenCalled(); @@ -557,7 +1036,7 @@ describe("MatrixRTCSession", () => { jest.useFakeTimers(); try { const membership = Object.assign({}, membershipTemplate); - const mockRoom = makeMockRoom([membership], 0); + const mockRoom = makeMockRoom([membership]); sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); const membershipObject = sess.memberships[0]; @@ -585,7 +1064,7 @@ describe("MatrixRTCSession", () => { expires: 1000, }), ]; - const mockRoomNoExpired = makeMockRoom(mockMemberships, 0); + const mockRoomNoExpired = makeMockRoom(mockMemberships); sess = MatrixRTCSession.roomSessionForRoom(client, mockRoomNoExpired); @@ -595,7 +1074,7 @@ describe("MatrixRTCSession", () => { jest.advanceTimersByTime(10000); - sess.joinRoomSession([mockFocus]); + sess.joinRoomSession([mockFocus], mockFocus); expect(client.sendStateEvent).toHaveBeenCalledWith( mockRoomNoExpired!.roomId, @@ -624,6 +1103,7 @@ describe("MatrixRTCSession", () => { it("fills in created_ts for other memberships on update", () => { client.sendStateEvent = jest.fn(); jest.useFakeTimers(); + jest.setSystemTime(1000); const mockRoom = makeMockRoom([ Object.assign({}, membershipTemplate, { device_id: "OTHERDEVICE", @@ -631,7 +1111,7 @@ describe("MatrixRTCSession", () => { ]); sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); - sess.joinRoomSession([mockFocus]); + sess.joinRoomSession([mockFocus], mockFocus); expect(client.sendStateEvent).toHaveBeenCalledWith( mockRoom!.roomId, @@ -645,6 +1125,7 @@ describe("MatrixRTCSession", () => { device_id: "OTHERDEVICE", expires: 3600000, created_ts: 1000, + foci_active: [{ type: "livekit", livekit_service_url: "https://lk.url" }], membershipID: expect.stringMatching(".*"), }, { @@ -680,6 +1161,7 @@ describe("MatrixRTCSession", () => { ], }), getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(Date.now()), } as unknown as MatrixEvent); const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; @@ -703,6 +1185,7 @@ describe("MatrixRTCSession", () => { ], }), getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(Date.now()), } as unknown as MatrixEvent); const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; @@ -714,6 +1197,130 @@ describe("MatrixRTCSession", () => { expect(bobKeys[4]).toEqual(Buffer.from("this is the key", "utf-8")); }); + it("collects keys by merging", () => { + const mockRoom = makeMockRoom([membershipTemplate]); + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + sess.onCallEncryption({ + getType: jest.fn().mockReturnValue("io.element.call.encryption_keys"), + getContent: jest.fn().mockReturnValue({ + device_id: "bobsphone", + call_id: "", + keys: [ + { + index: 0, + key: "dGhpcyBpcyB0aGUga2V5", + }, + ], + }), + getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(Date.now()), + } as unknown as MatrixEvent); + + let bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; + expect(bobKeys).toHaveLength(1); + expect(bobKeys[0]).toEqual(Buffer.from("this is the key", "utf-8")); + + sess.onCallEncryption({ + getType: jest.fn().mockReturnValue("io.element.call.encryption_keys"), + getContent: jest.fn().mockReturnValue({ + device_id: "bobsphone", + call_id: "", + keys: [ + { + index: 4, + key: "dGhpcyBpcyB0aGUga2V5", + }, + ], + }), + getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(Date.now()), + } as unknown as MatrixEvent); + + bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; + expect(bobKeys).toHaveLength(5); + expect(bobKeys[4]).toEqual(Buffer.from("this is the key", "utf-8")); + }); + + it("ignores older keys at same index", () => { + const mockRoom = makeMockRoom([membershipTemplate]); + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + sess.onCallEncryption({ + getType: jest.fn().mockReturnValue("io.element.call.encryption_keys"), + getContent: jest.fn().mockReturnValue({ + device_id: "bobsphone", + call_id: "", + keys: [ + { + index: 0, + key: encodeBase64(Buffer.from("newer key", "utf-8")), + }, + ], + }), + getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(2000), + } as unknown as MatrixEvent); + + sess.onCallEncryption({ + getType: jest.fn().mockReturnValue("io.element.call.encryption_keys"), + getContent: jest.fn().mockReturnValue({ + device_id: "bobsphone", + call_id: "", + keys: [ + { + index: 0, + key: encodeBase64(Buffer.from("older key", "utf-8")), + }, + ], + }), + getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(1000), // earlier timestamp than the newer key + } as unknown as MatrixEvent); + + const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; + expect(bobKeys).toHaveLength(1); + expect(bobKeys[0]).toEqual(Buffer.from("newer key", "utf-8")); + }); + + it("key timestamps are treated as monotonic", () => { + const mockRoom = makeMockRoom([membershipTemplate]); + sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); + sess.onCallEncryption({ + getType: jest.fn().mockReturnValue("io.element.call.encryption_keys"), + getContent: jest.fn().mockReturnValue({ + device_id: "bobsphone", + call_id: "", + keys: [ + { + index: 0, + key: encodeBase64(Buffer.from("first key", "utf-8")), + }, + ], + }), + getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(1000), + } as unknown as MatrixEvent); + + sess.onCallEncryption({ + getType: jest.fn().mockReturnValue("io.element.call.encryption_keys"), + getContent: jest.fn().mockReturnValue({ + device_id: "bobsphone", + call_id: "", + keys: [ + { + index: 0, + key: encodeBase64(Buffer.from("second key", "utf-8")), + }, + ], + }), + getSender: jest.fn().mockReturnValue("@bob:example.org"), + getTs: jest.fn().mockReturnValue(1000), // same timestamp as the first key + } as unknown as MatrixEvent); + + const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; + expect(bobKeys).toHaveLength(1); + expect(bobKeys[0]).toEqual(Buffer.from("second key", "utf-8")); + }); + it("ignores keys event for the local participant", () => { const mockRoom = makeMockRoom([membershipTemplate]); sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom); @@ -730,6 +1337,7 @@ describe("MatrixRTCSession", () => { ], }), getSender: jest.fn().mockReturnValue(client.getUserId()), + getTs: jest.fn().mockReturnValue(Date.now()), } as unknown as MatrixEvent); const myKeys = sess.getKeysForParticipant(client.getUserId()!, client.getDeviceId()!)!; diff --git a/spec/unit/matrixrtc/MatrixRTCSessionManager.spec.ts b/spec/unit/matrixrtc/MatrixRTCSessionManager.spec.ts index f5ffc13e05b..bbc9c9f7e6f 100644 --- a/spec/unit/matrixrtc/MatrixRTCSessionManager.spec.ts +++ b/spec/unit/matrixrtc/MatrixRTCSessionManager.spec.ts @@ -35,6 +35,7 @@ const membershipTemplate: CallMembershipData = { device_id: "AAAAAAA", expires: 60 * 60 * 1000, membershipID: "bloop", + foci_active: [{ type: "test" }], }; describe("MatrixRTCSessionManager", () => { @@ -101,6 +102,7 @@ describe("MatrixRTCSessionManager", () => { getContent: jest.fn().mockReturnValue({}), getSender: jest.fn().mockReturnValue("@mock:user.example"), getRoomId: jest.fn().mockReturnValue("!room:id"), + isDecryptionFailure: jest.fn().mockReturnValue(false), sender: { userId: "@mock:user.example", }, @@ -109,4 +111,93 @@ describe("MatrixRTCSessionManager", () => { await new Promise(process.nextTick); expect(onCallEncryptionMock).toHaveBeenCalled(); }); + + describe("event decryption", () => { + it("Retries decryption and processes success", async () => { + try { + jest.useFakeTimers(); + const room1 = makeMockRoom([membershipTemplate]); + jest.spyOn(client, "getRooms").mockReturnValue([room1]); + jest.spyOn(client, "getRoom").mockReturnValue(room1); + + client.emit(ClientEvent.Room, room1); + const onCallEncryptionMock = jest.fn(); + client.matrixRTC.getRoomSession(room1).onCallEncryption = onCallEncryptionMock; + let isDecryptionFailure = true; + client.decryptEventIfNeeded = jest + .fn() + .mockReturnValueOnce(Promise.resolve()) + .mockImplementation(() => { + isDecryptionFailure = false; + return Promise.resolve(); + }); + const timelineEvent = { + getType: jest.fn().mockReturnValue(EventType.CallEncryptionKeysPrefix), + getContent: jest.fn().mockReturnValue({}), + getSender: jest.fn().mockReturnValue("@mock:user.example"), + getRoomId: jest.fn().mockReturnValue("!room:id"), + isDecryptionFailure: jest.fn().mockImplementation(() => isDecryptionFailure), + getId: jest.fn().mockReturnValue("event_id"), + sender: { + userId: "@mock:user.example", + }, + } as unknown as MatrixEvent; + client.emit(RoomEvent.Timeline, timelineEvent, undefined, undefined, false, {} as IRoomTimelineData); + + expect(client.decryptEventIfNeeded).toHaveBeenCalledTimes(1); + expect(onCallEncryptionMock).toHaveBeenCalledTimes(0); + + // should retry after one second: + await jest.advanceTimersByTimeAsync(1500); + + expect(client.decryptEventIfNeeded).toHaveBeenCalledTimes(2); + expect(onCallEncryptionMock).toHaveBeenCalledTimes(1); + } finally { + jest.useRealTimers(); + } + }); + + it("Retries decryption and processes failure", async () => { + try { + jest.useFakeTimers(); + const room1 = makeMockRoom([membershipTemplate]); + jest.spyOn(client, "getRooms").mockReturnValue([room1]); + jest.spyOn(client, "getRoom").mockReturnValue(room1); + + client.emit(ClientEvent.Room, room1); + const onCallEncryptionMock = jest.fn(); + client.matrixRTC.getRoomSession(room1).onCallEncryption = onCallEncryptionMock; + client.decryptEventIfNeeded = jest.fn().mockReturnValue(Promise.resolve()); + const timelineEvent = { + getType: jest.fn().mockReturnValue(EventType.CallEncryptionKeysPrefix), + getContent: jest.fn().mockReturnValue({}), + getSender: jest.fn().mockReturnValue("@mock:user.example"), + getRoomId: jest.fn().mockReturnValue("!room:id"), + isDecryptionFailure: jest.fn().mockReturnValue(true), // always fail + getId: jest.fn().mockReturnValue("event_id"), + sender: { + userId: "@mock:user.example", + }, + } as unknown as MatrixEvent; + client.emit(RoomEvent.Timeline, timelineEvent, undefined, undefined, false, {} as IRoomTimelineData); + + expect(client.decryptEventIfNeeded).toHaveBeenCalledTimes(1); + expect(onCallEncryptionMock).toHaveBeenCalledTimes(0); + + // should retry after one second: + await jest.advanceTimersByTimeAsync(1500); + + expect(client.decryptEventIfNeeded).toHaveBeenCalledTimes(2); + expect(onCallEncryptionMock).toHaveBeenCalledTimes(0); + + // doesn't retry again: + await jest.advanceTimersByTimeAsync(1500); + + expect(client.decryptEventIfNeeded).toHaveBeenCalledTimes(2); + expect(onCallEncryptionMock).toHaveBeenCalledTimes(0); + } finally { + jest.useRealTimers(); + } + }); + }); }); diff --git a/spec/unit/matrixrtc/mocks.ts b/spec/unit/matrixrtc/mocks.ts index 84496e657da..57863dc2c38 100644 --- a/spec/unit/matrixrtc/mocks.ts +++ b/spec/unit/matrixrtc/mocks.ts @@ -15,24 +15,27 @@ limitations under the License. */ import { EventType, MatrixEvent, Room } from "../../../src"; -import { CallMembershipData } from "../../../src/matrixrtc/CallMembership"; +import { CallMembershipData, SessionMembershipData } from "../../../src/matrixrtc/CallMembership"; import { randomString } from "../../../src/randomstring"; -export function makeMockRoom(memberships: CallMembershipData[], localAge: number | null = null): Room { +type MembershipData = CallMembershipData[] | SessionMembershipData; + +export function makeMockRoom(membershipData: MembershipData): Room { const roomId = randomString(8); // Caching roomState here so it does not get recreated when calling `getLiveTimeline.getState()` - const roomState = makeMockRoomState(memberships, roomId, localAge); + const roomState = makeMockRoomState(membershipData, roomId); return { roomId: roomId, hasMembershipState: jest.fn().mockReturnValue(true), getLiveTimeline: jest.fn().mockReturnValue({ getState: jest.fn().mockReturnValue(roomState), }), + getVersion: jest.fn().mockReturnValue("default"), } as unknown as Room; } -export function makeMockRoomState(memberships: CallMembershipData[], roomId: string, localAge: number | null = null) { - const event = mockRTCEvent(memberships, roomId, localAge); +export function makeMockRoomState(membershipData: MembershipData, roomId: string) { + const event = mockRTCEvent(membershipData, roomId); return { on: jest.fn(), off: jest.fn(), @@ -40,21 +43,36 @@ export function makeMockRoomState(memberships: CallMembershipData[], roomId: str if (stateKey !== undefined) return event; return [event]; }, + events: new Map([ + [ + event.getType(), + { + size: () => true, + has: (_stateKey: string) => true, + get: (_stateKey: string) => event, + values: () => [event], + }, + ], + ]), }; } -export function mockRTCEvent(memberships: CallMembershipData[], roomId: string, localAge: number | null): MatrixEvent { +export function mockRTCEvent(membershipData: MembershipData, roomId: string): MatrixEvent { return { getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix), - getContent: jest.fn().mockReturnValue({ - memberships: memberships, - }), + getContent: jest.fn().mockReturnValue( + !Array.isArray(membershipData) + ? membershipData + : { + memberships: membershipData, + }, + ), getSender: jest.fn().mockReturnValue("@mock:user.example"), - getTs: jest.fn().mockReturnValue(1000), - localTimestamp: Date.now() - (localAge ?? 10), + getTs: jest.fn().mockReturnValue(Date.now()), getRoomId: jest.fn().mockReturnValue(roomId), sender: { userId: "@mock:user.example", }, + isDecryptionFailure: jest.fn().mockReturnValue(false), } as unknown as MatrixEvent; } diff --git a/spec/unit/models/event.spec.ts b/spec/unit/models/event.spec.ts index d308d01395f..56f31482786 100644 --- a/spec/unit/models/event.spec.ts +++ b/spec/unit/models/event.spec.ts @@ -412,7 +412,12 @@ describe("MatrixEvent", () => { const crypto = { decryptEvent: jest .fn() - .mockRejectedValue("DecryptionError: The sender has disabled encrypting to unverified devices."), + .mockRejectedValue( + new DecryptionError( + DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE, + "The sender has disabled encrypting to unverified devices.", + ), + ), } as unknown as Crypto; await encryptedEvent.attemptDecryption(crypto); diff --git a/spec/unit/oidc/authorize.spec.ts b/spec/unit/oidc/authorize.spec.ts index e9cf7589a37..e786b8fb56c 100644 --- a/spec/unit/oidc/authorize.spec.ts +++ b/spec/unit/oidc/authorize.spec.ts @@ -26,7 +26,6 @@ import { getRandomValues } from "node:crypto"; import { TextEncoder } from "node:util"; import { Method } from "../../../src"; -import * as crypto from "../../../src/crypto/crypto"; import { logger } from "../../../src/logger"; import { completeAuthorizationCodeGrant, @@ -39,11 +38,6 @@ import { makeDelegatedAuthConfig, mockOpenIdConfiguration } from "../../test-uti jest.mock("jwt-decode"); -const webCrypto = new Crypto(); - -// save for resetting mocks -const realSubtleCrypto = crypto.subtleCrypto; - describe("oidc authorization", () => { const delegatedAuthConfig = makeDelegatedAuthConfig(); const authorizationEndpoint = delegatedAuthConfig.authorizationEndpoint; @@ -62,7 +56,11 @@ describe("oidc authorization", () => { delegatedAuthConfig.metadata.issuer + ".well-known/openid-configuration", mockOpenIdConfiguration(), ); + global.TextEncoder = TextEncoder; + }); + beforeEach(() => { + const webCrypto = new Crypto(); Object.defineProperty(window, "crypto", { value: { getRandomValues, @@ -70,12 +68,6 @@ describe("oidc authorization", () => { subtle: webCrypto.subtle, }, }); - global.TextEncoder = TextEncoder; - }); - - afterEach(() => { - // @ts-ignore reset any ugly mocking we did - crypto.subtleCrypto = realSubtleCrypto; }); it("should generate authorization params", () => { @@ -97,11 +89,8 @@ describe("oidc authorization", () => { describe("generateAuthorizationUrl()", () => { it("should generate url with correct parameters", async () => { - // test the no crypto case here - // @ts-ignore mocking - crypto.subtleCrypto = undefined; - const authorizationParams = generateAuthorizationParams({ redirectUri: baseUrl }); + authorizationParams.codeVerifier = "test-code-verifier"; const authUrl = new URL( await generateAuthorizationUrl(authorizationEndpoint, clientId, authorizationParams), ); @@ -113,6 +102,18 @@ describe("oidc authorization", () => { expect(authUrl.searchParams.get("scope")).toEqual(authorizationParams.scope); expect(authUrl.searchParams.get("state")).toEqual(authorizationParams.state); expect(authUrl.searchParams.get("nonce")).toEqual(authorizationParams.nonce); + expect(authUrl.searchParams.get("code_challenge")).toEqual("0FLIKahrX7kqxncwhV5WD82lu_wi5GA8FsRSLubaOpU"); + }); + + it("should log a warning if crypto is not available", async () => { + // test the no crypto case here + // @ts-ignore mocking + globalThis.crypto.subtle = undefined; + + const authorizationParams = generateAuthorizationParams({ redirectUri: baseUrl }); + const authUrl = new URL( + await generateAuthorizationUrl(authorizationEndpoint, clientId, authorizationParams), + ); // crypto not available, plain text code_challenge is used expect(authUrl.searchParams.get("code_challenge")).toEqual(authorizationParams.codeVerifier); diff --git a/spec/unit/queueToDevice.spec.ts b/spec/unit/queueToDevice.spec.ts index f9b90304e02..362d410af1a 100644 --- a/spec/unit/queueToDevice.spec.ts +++ b/spec/unit/queueToDevice.spec.ts @@ -61,251 +61,293 @@ describe.each([[StoreType.Memory], [StoreType.IndexedDB]])("queueToDevice (%s st let httpBackend: MockHttpBackend; let client: MatrixClient; - beforeEach(async function () { - jest.runOnlyPendingTimers(); - jest.useRealTimers(); - httpBackend = new MockHttpBackend(); - - let store: IStore; - if (storeType === StoreType.IndexedDB) { - const idbStore = new IndexedDBStore({ indexedDB: fakeIndexedDB }); - await idbStore.startup(); - store = idbStore; - } else { - store = new MemoryStore(); - } - - client = new MatrixClient({ - baseUrl: "https://my.home.server", - accessToken: "my.access.token", - fetchFn: httpBackend.fetchFn as typeof global.fetch, - store, + /** + * We need to split the tests into regular ones (these) and ones that use fake timers, + * because the fake indexeddb uses timers too and appears make tests cause other tests + * to fail if we keep enabling/disabling fake timers within the same test suite. + */ + describe("non-timed tests", () => { + beforeEach(async function () { + httpBackend = new MockHttpBackend(); + + let store: IStore; + if (storeType === StoreType.IndexedDB) { + const idbStore = new IndexedDBStore({ indexedDB: fakeIndexedDB }); + await idbStore.startup(); + store = idbStore; + } else { + store = new MemoryStore(); + } + + client = new MatrixClient({ + baseUrl: "https://my.home.server", + accessToken: "my.access.token", + fetchFn: httpBackend.fetchFn as typeof global.fetch, + store, + }); }); - }); - - afterEach(function () { - jest.useRealTimers(); - client.stopClient(); - }); - it("sends a to-device message", async function () { - httpBackend - .when("PUT", "/sendToDevice/org.example.foo/") - .check((request) => { - expect(request.data).toEqual(EXPECTED_BODY); - }) - .respond(200, {}); - - await client.queueToDevice({ - eventType: "org.example.foo", - batch: [FAKE_MSG], + afterEach(function () { + client.stopClient(); }); - await httpBackend.flushAllExpected(); - // let the code handle the response to the request so we don't get - // log output after the test has finished (apparently stopping the - // client in aftereach is not sufficient.) - await flushPromises(); - }); - - it("retries on error", async function () { - jest.useFakeTimers(); - - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); - - httpBackend - .when("PUT", "/sendToDevice/org.example.foo/") - .check((request) => { - expect(request.data).toEqual(EXPECTED_BODY); - }) - .respond(200, {}); + it("sends a to-device message", async function () { + httpBackend + .when("PUT", "/sendToDevice/org.example.foo/") + .check((request) => { + expect(request.data).toEqual(EXPECTED_BODY); + }) + .respond(200, {}); + + await client.queueToDevice({ + eventType: "org.example.foo", + batch: [FAKE_MSG], + }); - await client.queueToDevice({ - eventType: "org.example.foo", - batch: [FAKE_MSG], + await httpBackend.flushAllExpected(); + // let the code handle the response to the request so we don't get + // log output after the test has finished (apparently stopping the + // client in aftereach is not sufficient.) + await flushPromises(); }); - await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); - expect(httpBackend.flushSync(undefined, 1)).toEqual(1); - await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); + it("retries on retryImmediately()", async function () { + httpBackend.when("GET", "/_matrix/client/versions").respond(200, { + versions: ["v1.1"], + }); - expect(httpBackend.flushSync(undefined, 1)).toEqual(1); + await Promise.all([client.startClient(), httpBackend.flush(undefined, 1, 20)]); - // flush, as per comment in first test - await flushPromises(); - }); + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); + + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); - it("stops retrying on 4xx errors", async function () { - jest.useFakeTimers(); + await client.queueToDevice({ + eventType: "org.example.foo", + batch: [FAKE_MSG], + }); + expect(await httpBackend.flush(undefined, 1, 1)).toEqual(1); + await flushPromises(); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(400); + client.retryImmediately(); - await client.queueToDevice({ - eventType: "org.example.foo", - batch: [FAKE_MSG], + // longer timeout here to try & avoid flakiness + expect(await httpBackend.flush(undefined, 1, 3000)).toEqual(1); }); - await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); - expect(httpBackend.flushSync(undefined, 1)).toEqual(1); - // Asserting that another request is never made is obviously - // a bit tricky - we just flush the queue what should hopefully - // be plenty of times and assert that nothing comes through. - let tries = 0; - await flushAndRunTimersUntil(() => ++tries === 10); + it("retries on when client is started", async function () { + httpBackend.when("GET", "/_matrix/client/versions").respond(200, { + versions: ["v1.1"], + }); - expect(httpBackend.requests.length).toEqual(0); - }); + await Promise.all([client.startClient(), httpBackend.flush("/_matrix/client/versions", 1, 20)]); - it("honours ratelimiting", async function () { - jest.useFakeTimers(); + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); - // pick something obscure enough it's unlikley to clash with a - // retry delay the algorithm uses anyway - const retryDelay = 279 * 1000; + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(429, { - errcode: "M_LIMIT_EXCEEDED", - retry_after_ms: retryDelay, - }); + await client.queueToDevice({ + eventType: "org.example.foo", + batch: [FAKE_MSG], + }); + expect(await httpBackend.flush(undefined, 1, 1)).toEqual(1); + await flushPromises(); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); + client.stopClient(); + await Promise.all([client.startClient(), httpBackend.flush("/_matrix/client/versions", 1, 20)]); - await client.queueToDevice({ - eventType: "org.example.foo", - batch: [FAKE_MSG], + expect(await httpBackend.flush(undefined, 1, 20)).toEqual(1); }); - await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); - expect(httpBackend.flushSync(undefined, 1)).toEqual(1); - await flushPromises(); - logger.info("Advancing clock to just before expected retry time..."); + it("retries when a message is retried", async function () { + httpBackend.when("GET", "/_matrix/client/versions").respond(200, { + versions: ["v1.1"], + }); - jest.advanceTimersByTime(retryDelay - 1000); - await flushPromises(); + await Promise.all([client.startClient(), httpBackend.flush(undefined, 1, 20)]); - expect(httpBackend.requests.length).toEqual(0); + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); - logger.info("Advancing clock past expected retry time..."); + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); - jest.advanceTimersByTime(2000); - await flushPromises(); + await client.queueToDevice({ + eventType: "org.example.foo", + batch: [FAKE_MSG], + }); - expect(httpBackend.flushSync(undefined, 1)).toEqual(1); - }); + expect(await httpBackend.flush(undefined, 1, 20)).toEqual(1); + await flushPromises(); + + const dummyEvent = new MatrixEvent({ + event_id: "!fake:example.org", + }); + const mockRoom = { + updatePendingEvent: jest.fn(), + hasEncryptionStateEvent: jest.fn().mockReturnValue(false), + } as unknown as Room; + client.resendEvent(dummyEvent, mockRoom); - it("retries on retryImmediately()", async function () { - httpBackend.when("GET", "/_matrix/client/versions").respond(200, { - versions: ["v1.1"], + expect(await httpBackend.flush(undefined, 1, 20)).toEqual(1); }); - await Promise.all([client.startClient(), httpBackend.flush(undefined, 1, 20)]); + it("splits many messages into multiple HTTP requests", async function () { + const batch: ToDeviceBatch = { + eventType: "org.example.foo", + batch: [], + }; + + for (let i = 0; i <= 20; ++i) { + batch.batch.push({ + userId: `@user${i}:example.org`, + deviceId: FAKE_DEVICE_ID, + payload: FAKE_PAYLOAD, + }); + } + + const expectedCounts = [20, 1]; + httpBackend + .when("PUT", "/sendToDevice/org.example.foo/") + .check((request) => { + expect( + removeElement(expectedCounts, (c) => c === Object.keys(request.data.messages).length), + ).toBeTruthy(); + }) + .respond(200, {}); + httpBackend + .when("PUT", "/sendToDevice/org.example.foo/") + .check((request) => { + expect(Object.keys(request.data.messages).length).toEqual(1); + }) + .respond(200, {}); + + await client.queueToDevice(batch); + await httpBackend.flushAllExpected(); + + // flush, as per comment in first test + await flushPromises(); + }); + }); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); + describe("async tests", () => { + beforeAll(() => { + jest.useFakeTimers(); + }); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); + afterAll(() => { + jest.useRealTimers(); + }); - await client.queueToDevice({ - eventType: "org.example.foo", - batch: [FAKE_MSG], + beforeEach(async function () { + httpBackend = new MockHttpBackend(); + + let store: IStore; + if (storeType === StoreType.IndexedDB) { + const idbStore = new IndexedDBStore({ indexedDB: fakeIndexedDB }); + let storeStarted = false; + idbStore.startup().then(() => { + storeStarted = true; + }); + await flushAndRunTimersUntil(() => storeStarted); + store = idbStore; + } else { + store = new MemoryStore(); + } + + client = new MatrixClient({ + baseUrl: "https://my.home.server", + accessToken: "my.access.token", + fetchFn: httpBackend.fetchFn as typeof global.fetch, + store, + }); }); - expect(await httpBackend.flush(undefined, 1, 1)).toEqual(1); - await flushPromises(); - client.retryImmediately(); + afterEach(function () { + client.stopClient(); + }); - // longer timeout here to try & avoid flakiness - expect(await httpBackend.flush(undefined, 1, 3000)).toEqual(1); - }); + it("retries on error", async function () { + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); - it("retries on when client is started", async function () { - httpBackend.when("GET", "/_matrix/client/versions").respond(200, { - versions: ["v1.1"], - }); + httpBackend + .when("PUT", "/sendToDevice/org.example.foo/") + .check((request) => { + expect(request.data).toEqual(EXPECTED_BODY); + }) + .respond(200, {}); - await Promise.all([client.startClient(), httpBackend.flush("/_matrix/client/versions", 1, 20)]); + client + .queueToDevice({ + eventType: "org.example.foo", + batch: [FAKE_MSG], + }) + .then(); + await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); + expect(httpBackend.flushSync(undefined, 1)).toEqual(1); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); + await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); + expect(httpBackend.flushSync(undefined, 1)).toEqual(1); - await client.queueToDevice({ - eventType: "org.example.foo", - batch: [FAKE_MSG], + // flush, as per comment in first test + await flushPromises(); }); - expect(await httpBackend.flush(undefined, 1, 1)).toEqual(1); - await flushPromises(); - client.stopClient(); - await Promise.all([client.startClient(), httpBackend.flush("/_matrix/client/versions", 1, 20)]); + it("stops retrying on 4xx errors", async function () { + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(400); + + client + .queueToDevice({ + eventType: "org.example.foo", + batch: [FAKE_MSG], + }) + .then(); + await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); + expect(httpBackend.flushSync(undefined, 1)).toEqual(1); + + // Asserting that another request is never made is obviously + // a bit tricky - we just flush the queue what should hopefully + // be plenty of times and assert that nothing comes through. + let tries = 0; + await flushAndRunTimersUntil(() => ++tries === 10); + + expect(httpBackend.requests.length).toEqual(0); + }); - expect(await httpBackend.flush(undefined, 1, 20)).toEqual(1); - }); + it("honours ratelimiting", async function () { + // pick something obscure enough it's unlikley to clash with a + // retry delay the algorithm uses anyway + const retryDelay = 279 * 1000; - it("retries when a message is retried", async function () { - httpBackend.when("GET", "/_matrix/client/versions").respond(200, { - versions: ["v1.1"], - }); + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(429, { + errcode: "M_LIMIT_EXCEEDED", + retry_after_ms: retryDelay, + }); - await Promise.all([client.startClient(), httpBackend.flush(undefined, 1, 20)]); + httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(500); + client + .queueToDevice({ + eventType: "org.example.foo", + batch: [FAKE_MSG], + }) + .then(); + await flushAndRunTimersUntil(() => httpBackend.requests.length > 0); + expect(httpBackend.flushSync(undefined, 1)).toEqual(1); + await flushPromises(); - httpBackend.when("PUT", "/sendToDevice/org.example.foo/").respond(200, {}); + logger.info("Advancing clock to just before expected retry time..."); - await client.queueToDevice({ - eventType: "org.example.foo", - batch: [FAKE_MSG], - }); + jest.advanceTimersByTime(retryDelay - 1000); + await flushPromises(); - expect(await httpBackend.flush(undefined, 1, 20)).toEqual(1); - await flushPromises(); + expect(httpBackend.requests.length).toEqual(0); - const dummyEvent = new MatrixEvent({ - event_id: "!fake:example.org", - }); - const mockRoom = { - updatePendingEvent: jest.fn(), - hasEncryptionStateEvent: jest.fn().mockReturnValue(false), - } as unknown as Room; - client.resendEvent(dummyEvent, mockRoom); + logger.info("Advancing clock past expected retry time..."); - expect(await httpBackend.flush(undefined, 1, 20)).toEqual(1); - }); + jest.advanceTimersByTime(2000); + await flushPromises(); - it("splits many messages into multiple HTTP requests", async function () { - const batch: ToDeviceBatch = { - eventType: "org.example.foo", - batch: [], - }; - - for (let i = 0; i <= 20; ++i) { - batch.batch.push({ - userId: `@user${i}:example.org`, - deviceId: FAKE_DEVICE_ID, - payload: FAKE_PAYLOAD, - }); - } - - const expectedCounts = [20, 1]; - httpBackend - .when("PUT", "/sendToDevice/org.example.foo/") - .check((request) => { - expect( - removeElement(expectedCounts, (c) => c === Object.keys(request.data.messages).length), - ).toBeTruthy(); - }) - .respond(200, {}); - httpBackend - .when("PUT", "/sendToDevice/org.example.foo/") - .check((request) => { - expect(Object.keys(request.data.messages).length).toEqual(1); - }) - .respond(200, {}); - - await client.queueToDevice(batch); - await httpBackend.flushAllExpected(); - - // flush, as per comment in first test - await flushPromises(); + expect(httpBackend.flushSync(undefined, 1)).toEqual(1); + }); }); }); diff --git a/spec/unit/rendezvous/MSC4108RendezvousSession.spec.ts b/spec/unit/rendezvous/MSC4108RendezvousSession.spec.ts new file mode 100644 index 00000000000..57afd3afced --- /dev/null +++ b/spec/unit/rendezvous/MSC4108RendezvousSession.spec.ts @@ -0,0 +1,341 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import fetchMock from "fetch-mock-jest"; + +import { ClientPrefix, IHttpOpts, MatrixClient, MatrixHttpApi } from "../../../src"; +import { ClientRendezvousFailureReason, MSC4108RendezvousSession } from "../../../src/rendezvous"; + +function makeMockClient(opts: { userId: string; deviceId: string; msc4108Enabled: boolean }): MatrixClient { + const client = { + doesServerSupportUnstableFeature(feature: string) { + return Promise.resolve(opts.msc4108Enabled && feature === "org.matrix.msc4108"); + }, + getUserId() { + return opts.userId; + }, + getDeviceId() { + return opts.deviceId; + }, + baseUrl: "https://example.com", + } as unknown as MatrixClient; + client.http = new MatrixHttpApi(client, { + baseUrl: client.baseUrl, + prefix: ClientPrefix.Unstable, + onlyData: true, + }); + return client; +} + +fetchMock.config.overwriteRoutes = true; + +describe("MSC4108RendezvousSession", () => { + beforeEach(() => { + fetchMock.reset(); + }); + + async function postAndCheckLocation(msc4108Enabled: boolean, fallbackRzServer: string, locationResponse: string) { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled }); + const transport = new MSC4108RendezvousSession({ client, fallbackRzServer }); + { + // initial POST + const expectedPostLocation = msc4108Enabled + ? `${client.baseUrl}/_matrix/client/unstable/org.matrix.msc4108/rendezvous` + : fallbackRzServer; + + fetchMock.postOnce(expectedPostLocation, { + status: 201, + body: { url: locationResponse }, + }); + await transport.send("data"); + } + + { + fetchMock.get(locationResponse, { + status: 200, + body: "data", + headers: { + "content-type": "text/plain", + "etag": "aaa", + }, + }); + await expect(transport.receive()).resolves.toEqual("data"); + } + } + + it("should use custom fetchFn if provided", async () => { + const sandbox = fetchMock.sandbox(); + const fetchFn = jest.fn().mockImplementation(sandbox); + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fetchFn, + fallbackRzServer: "https://fallbackserver/rz", + }); + sandbox.postOnce("https://fallbackserver/rz", { + status: 201, + body: { + url: "https://fallbackserver/rz/123", + }, + }); + await transport.send("data"); + await sandbox.flush(true); + expect(fetchFn).toHaveBeenCalledWith("https://fallbackserver/rz", expect.anything()); + }); + + it("should throw an error when no server available", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ client }); + await expect(transport.send("data")).rejects.toThrow("Invalid rendezvous URI"); + }); + + it("POST to fallback server", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + fetchMock.postOnce("https://fallbackserver/rz", { + status: 201, + body: { url: "https://fallbackserver/rz/123" }, + }); + await fetchMock.flush(true); + await expect(transport.send("data")).resolves.toStrictEqual(undefined); + }); + + it("POST with no location", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + fetchMock.postOnce("https://fallbackserver/rz", { + status: 201, + }); + await Promise.all([expect(transport.send("data")).rejects.toThrow(), fetchMock.flush(true)]); + }); + + it("POST with absolute path response", async function () { + await postAndCheckLocation(false, "https://fallbackserver/rz", "https://fallbackserver/123"); + }); + + it("POST to built-in MSC3886 implementation", async function () { + await postAndCheckLocation( + true, + "https://fallbackserver/rz", + "https://example.com/_matrix/client/unstable/org.matrix.msc4108/rendezvous/123", + ); + }); + + it("POST with relative path response including parent", async function () { + await postAndCheckLocation(false, "https://fallbackserver/rz/abc", "https://fallbackserver/rz/xyz/123"); + }); + + // fetch-mock doesn't handle redirects properly, so we can't test this + it.skip("POST to follow 307 to other server", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + fetchMock.postOnce("https://fallbackserver/rz", { + status: 307, + redirectUrl: "https://redirected.fallbackserver/rz", + redirected: true, + }); + fetchMock.postOnce("https://redirected.fallbackserver/rz", { + status: 201, + body: { url: "https://redirected.fallbackserver/rz/123" }, + headers: { etag: "aaa" }, + }); + await fetchMock.flush(true); + await expect(transport.send("data")).resolves.toStrictEqual(undefined); + }); + + it("POST and GET", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + { + // initial POST + fetchMock.postOnce("https://fallbackserver/rz", { + status: 201, + body: { url: "https://fallbackserver/rz/123" }, + }); + await expect(transport.send("foo=baa")).resolves.toStrictEqual(undefined); + await fetchMock.flush(true); + expect(fetchMock).toHaveFetched("https://fallbackserver/rz", { + method: "POST", + headers: { "content-type": "text/plain" }, + functionMatcher: (_, opts): boolean => { + return opts.body === "foo=baa"; + }, + }); + } + { + // first GET without etag + fetchMock.getOnce("https://fallbackserver/rz/123", { + status: 200, + body: "foo=baa", + headers: { "content-type": "text/plain", "etag": "aaa" }, + }); + await expect(transport.receive()).resolves.toEqual("foo=baa"); + await fetchMock.flush(true); + } + { + // subsequent GET which should have etag from previous request + fetchMock.getOnce("https://fallbackserver/rz/123", { + status: 200, + body: "foo=baa", + headers: { "content-type": "text/plain", "etag": "bbb" }, + }); + await expect(transport.receive()).resolves.toEqual("foo=baa"); + await fetchMock.flush(true); + expect(fetchMock).toHaveFetched("https://fallbackserver/rz/123", { + method: "GET", + headers: { "if-none-match": "aaa" }, + }); + } + }); + + it("POST and PUTs", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + { + // initial POST + fetchMock.postOnce("https://fallbackserver/rz", { + status: 201, + body: { url: "https://fallbackserver/rz/123" }, + headers: { etag: "aaa" }, + }); + await transport.send("foo=baa"); + await fetchMock.flush(true); + expect(fetchMock).toHaveFetched("https://fallbackserver/rz", { + method: "POST", + headers: { "content-type": "text/plain" }, + functionMatcher: (_, opts): boolean => { + return opts.body === "foo=baa"; + }, + }); + } + { + // subsequent PUT which should have etag from previous request + fetchMock.putOnce("https://fallbackserver/rz/123", { status: 202, headers: { etag: "bbb" } }); + await transport.send("c=d"); + await fetchMock.flush(true); + expect(fetchMock).toHaveFetched("https://fallbackserver/rz/123", { + method: "PUT", + headers: { "if-match": "aaa" }, + }); + } + }); + + it("POST and DELETE", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + { + // Create + fetchMock.postOnce("https://fallbackserver/rz", { + status: 201, + body: { url: "https://fallbackserver/rz/123" }, + }); + await expect(transport.send("foo=baa")).resolves.toStrictEqual(undefined); + await fetchMock.flush(true); + expect(fetchMock).toHaveFetched("https://fallbackserver/rz", { + method: "POST", + headers: { "content-type": "text/plain" }, + functionMatcher: (_, opts): boolean => { + return opts.body === "foo=baa"; + }, + }); + } + { + // Cancel + fetchMock.deleteOnce("https://fallbackserver/rz/123", { status: 204 }); + await transport.cancel(ClientRendezvousFailureReason.UserDeclined); + await fetchMock.flush(true); + } + }); + + it("send after cancelled", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + await transport.cancel(ClientRendezvousFailureReason.UserDeclined); + await expect(transport.send("data")).resolves.toBeUndefined(); + }); + + it("receive before ready", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + }); + await expect(transport.receive()).rejects.toThrow(); + }); + + it("404 failure callback", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const onFailure = jest.fn(); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + onFailure, + }); + + fetchMock.postOnce("https://fallbackserver/rz", { status: 404 }); + await Promise.all([expect(transport.send("foo=baa")).resolves.toBeUndefined(), fetchMock.flush(true)]); + expect(onFailure).toHaveBeenCalledWith(ClientRendezvousFailureReason.Unknown); + }); + + it("404 failure callback mapped to expired", async function () { + const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc4108Enabled: false }); + const onFailure = jest.fn(); + const transport = new MSC4108RendezvousSession({ + client, + fallbackRzServer: "https://fallbackserver/rz", + onFailure, + }); + + { + // initial POST + fetchMock.postOnce("https://fallbackserver/rz", { + status: 201, + body: { url: "https://fallbackserver/rz/123" }, + headers: { expires: "Thu, 01 Jan 1970 00:00:00 GMT" }, + }); + + await transport.send("foo=baa"); + await fetchMock.flush(true); + } + { + // GET with 404 to simulate expiry + fetchMock.getOnce("https://fallbackserver/rz/123", { status: 404, body: "foo=baa" }); + await Promise.all([expect(transport.receive()).resolves.toBeUndefined(), fetchMock.flush(true)]); + expect(onFailure).toHaveBeenCalledWith(ClientRendezvousFailureReason.Expired); + } + }); +}); diff --git a/spec/unit/rendezvous/channels/MSC4108SecureChannel.spec.ts b/spec/unit/rendezvous/channels/MSC4108SecureChannel.spec.ts new file mode 100644 index 00000000000..bc357d9ac90 --- /dev/null +++ b/spec/unit/rendezvous/channels/MSC4108SecureChannel.spec.ts @@ -0,0 +1,126 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { EstablishedEcies, QrCodeData, QrCodeMode, Ecies } from "@matrix-org/matrix-sdk-crypto-wasm"; +import { mocked } from "jest-mock"; + +import { MSC4108RendezvousSession, MSC4108SecureChannel, PayloadType } from "../../../../src/rendezvous"; + +describe("MSC4108SecureChannel", () => { + const baseUrl = "https://example.com"; + const url = "https://fallbackserver/rz/123"; + + it("should generate qr code data as expected", async () => { + const session = new MSC4108RendezvousSession({ + url, + }); + const channel = new MSC4108SecureChannel(session); + + const code = await channel.generateCode(QrCodeMode.Login); + expect(code).toHaveLength(71); + const text = new TextDecoder().decode(code); + expect(text.startsWith("MATRIX")).toBeTruthy(); + expect(text.endsWith(url)).toBeTruthy(); + }); + + it("should throw error if attempt to connect multiple times", async () => { + const mockSession = { + send: jest.fn(), + receive: jest.fn(), + url, + } as unknown as MSC4108RendezvousSession; + const channel = new MSC4108SecureChannel(mockSession); + + const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeMode.Reciprocate, baseUrl)); + const { initial_message: ciphertext } = new Ecies().establish_outbound_channel( + qrCodeData.publicKey, + "MATRIX_QR_CODE_LOGIN_INITIATE", + ); + mocked(mockSession.receive).mockResolvedValue(ciphertext); + await channel.connect(); + await expect(channel.connect()).rejects.toThrow("Channel already connected"); + }); + + it("should throw error on invalid initiate response", async () => { + const mockSession = { + send: jest.fn(), + receive: jest.fn(), + url, + } as unknown as MSC4108RendezvousSession; + const channel = new MSC4108SecureChannel(mockSession); + + mocked(mockSession.receive).mockResolvedValue(""); + await expect(channel.connect()).rejects.toThrow("No response from other device"); + + const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeMode.Reciprocate, baseUrl)); + const { initial_message: ciphertext } = new Ecies().establish_outbound_channel( + qrCodeData.publicKey, + "NOT_REAL_MATRIX_QR_CODE_LOGIN_INITIATE", + ); + + mocked(mockSession.receive).mockResolvedValue(ciphertext); + await expect(channel.connect()).rejects.toThrow("Invalid response from other device"); + }); + + describe("should be able to connect as a reciprocating device", () => { + let mockSession: MSC4108RendezvousSession; + let channel: MSC4108SecureChannel; + let opponentChannel: EstablishedEcies; + + beforeEach(async () => { + mockSession = { + send: jest.fn(), + receive: jest.fn(), + url, + } as unknown as MSC4108RendezvousSession; + channel = new MSC4108SecureChannel(mockSession); + + const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeMode.Reciprocate, baseUrl)); + const { channel: _opponentChannel, initial_message: ciphertext } = new Ecies().establish_outbound_channel( + qrCodeData.publicKey, + "MATRIX_QR_CODE_LOGIN_INITIATE", + ); + opponentChannel = _opponentChannel; + + mocked(mockSession.receive).mockResolvedValue(ciphertext); + await channel.connect(); + expect(opponentChannel.decrypt(mocked(mockSession.send).mock.calls[0][0])).toBe("MATRIX_QR_CODE_LOGIN_OK"); + mocked(mockSession.send).mockReset(); + }); + + it("should be able to securely send encrypted payloads", async () => { + const payload = { + type: PayloadType.Secrets, + protocols: ["a", "b", "c"], + homeserver: "https://example.org", + }; + await channel.secureSend(payload); + expect(mockSession.send).toHaveBeenCalled(); + expect(opponentChannel.decrypt(mocked(mockSession.send).mock.calls[0][0])).toBe(JSON.stringify(payload)); + }); + + it("should be able to securely receive encrypted payloads", async () => { + const payload = { + type: PayloadType.Secrets, + protocols: ["a", "b", "c"], + homeserver: "https://example.org", + }; + const ciphertext = opponentChannel.encrypt(JSON.stringify(payload)); + mocked(mockSession.receive).mockResolvedValue(ciphertext); + await expect(channel.secureReceive()).resolves.toEqual(payload); + }); + }); +}); diff --git a/spec/unit/rendezvous/ecdhv2.spec.ts b/spec/unit/rendezvous/ecdhv2.spec.ts index caadfbf6e9c..1fd3f7cac18 100644 --- a/spec/unit/rendezvous/ecdhv2.spec.ts +++ b/spec/unit/rendezvous/ecdhv2.spec.ts @@ -15,7 +15,7 @@ limitations under the License. */ import "../../olm-loader"; -import { RendezvousFailureReason, RendezvousIntent } from "../../../src/rendezvous"; +import { LegacyRendezvousFailureReason as RendezvousFailureReason, RendezvousIntent } from "../../../src/rendezvous"; import { MSC3903ECDHPayload, MSC3903ECDHv2RendezvousChannel } from "../../../src/rendezvous/channels"; import { decodeBase64 } from "../../../src/base64"; import { DummyTransport } from "./DummyTransport"; diff --git a/spec/unit/rendezvous/rendezvous.spec.ts b/spec/unit/rendezvous/rendezvous.spec.ts index c7a31b8a1ff..a208ffc590e 100644 --- a/spec/unit/rendezvous/rendezvous.spec.ts +++ b/spec/unit/rendezvous/rendezvous.spec.ts @@ -17,7 +17,12 @@ limitations under the License. import MockHttpBackend from "matrix-mock-request"; import "../../olm-loader"; -import { MSC3906Rendezvous, RendezvousCode, RendezvousFailureReason, RendezvousIntent } from "../../../src/rendezvous"; +import { + MSC3906Rendezvous, + RendezvousCode, + LegacyRendezvousFailureReason as RendezvousFailureReason, + RendezvousIntent, +} from "../../../src/rendezvous"; import { ECDHv2RendezvousCode as ECDHRendezvousCode, MSC3903ECDHPayload, @@ -111,7 +116,7 @@ function makeMockClient(opts: { }, }; }, - getCapabilities() { + getCachedCapabilities() { return opts.msc3882r0Only ? {} : { diff --git a/spec/unit/rendezvous/simpleHttpTransport.spec.ts b/spec/unit/rendezvous/simpleHttpTransport.spec.ts index 166a6350730..c736d4d115d 100644 --- a/spec/unit/rendezvous/simpleHttpTransport.spec.ts +++ b/spec/unit/rendezvous/simpleHttpTransport.spec.ts @@ -17,7 +17,7 @@ limitations under the License. import MockHttpBackend from "matrix-mock-request"; import type { MatrixClient } from "../../../src"; -import { RendezvousFailureReason } from "../../../src/rendezvous"; +import { LegacyRendezvousFailureReason as RendezvousFailureReason } from "../../../src/rendezvous"; import { MSC3886SimpleHttpRendezvousTransport } from "../../../src/rendezvous/transports"; function makeMockClient(opts: { userId: string; deviceId: string; msc3886Enabled: boolean }): MatrixClient { diff --git a/spec/unit/room-state.spec.ts b/spec/unit/room-state.spec.ts index 9e0c29f35e8..2c79440df71 100644 --- a/spec/unit/room-state.spec.ts +++ b/spec/unit/room-state.spec.ts @@ -1122,4 +1122,59 @@ describe("RoomState", function () { ).toBeFalsy(); }); }); + describe("skipWrongOrderRoomStateInserts", () => { + const idNow = "now"; + const idBefore = "before"; + const endState = new RoomState(roomId); + const startState = new RoomState(roomId, undefined, true); + + let onRoomStateEvent: (event: MatrixEvent, state: RoomState, lastStateEvent: MatrixEvent | null) => void; + const evNow = new MatrixEvent({ + type: "m.call.member", + room_id: roomId, + state_key: "@user:example.org", + content: {}, + }); + evNow.event.unsigned = { replaces_state: idBefore }; + evNow.event.event_id = idNow; + + const evBefore = new MatrixEvent({ + type: "m.call.member", + room_id: roomId, + state_key: "@user:example.org", + content: {}, + }); + + const updatedStateWithBefore = jest.fn(); + const updatedStateWithNow = jest.fn(); + + beforeEach(() => { + evBefore.event.event_id = idBefore; + onRoomStateEvent = (event, _state, _lastState) => { + if (event.event.event_id === idNow) { + updatedStateWithNow(); + } else if (event.event.event_id === idBefore) { + updatedStateWithBefore(); + } + }; + endState.on(RoomStateEvent.Events, onRoomStateEvent); + startState.on(RoomStateEvent.Events, onRoomStateEvent); + }); + afterEach(() => { + endState.off(RoomStateEvent.Events, onRoomStateEvent); + startState.off(RoomStateEvent.Events, onRoomStateEvent); + updatedStateWithNow.mockReset(); + updatedStateWithBefore.mockReset(); + }); + it("should skip inserting state to the end of the timeline if the current endState events replaces_state id is the same as the inserted events id", () => { + endState.setStateEvents([evNow, evBefore]); + expect(updatedStateWithBefore).not.toHaveBeenCalled(); + expect(updatedStateWithNow).toHaveBeenCalled(); + }); + it("should skip inserting state at the beginning of the timeline if the inserted events replaces_state is the event id of the current startState", () => { + startState.setStateEvents([evBefore, evNow]); + expect(updatedStateWithBefore).toHaveBeenCalled(); + expect(updatedStateWithNow).not.toHaveBeenCalled(); + }); + }); }); diff --git a/spec/unit/room.spec.ts b/spec/unit/room.spec.ts index eb90b8bdfa0..542bbcb2536 100644 --- a/spec/unit/room.spec.ts +++ b/spec/unit/room.spec.ts @@ -4034,4 +4034,47 @@ describe("Room", function () { expect(room.getLastThread()).toBe(thread2); }); }); + + describe("getRecommendedVersion", () => { + it("returns the server's recommended version from capabilities", async () => { + const client = new TestClient(userA).client; + client.getCapabilities = jest.fn().mockReturnValue({ + ["m.room_versions"]: { + default: "1", + available: ["1", "2"], + }, + }); + const room = new Room(roomId, client, userA); + expect(await room.getRecommendedVersion()).toEqual({ + version: "1", + needsUpgrade: false, + urgent: false, + }); + }); + + it("force-refreshes versions to make sure an upgrade is necessary", async () => { + const client = new TestClient(userA).client; + client.getCapabilities = jest.fn().mockReturnValue({ + ["m.room_versions"]: { + default: "5", + available: ["5"], + }, + }); + + client.fetchCapabilities = jest.fn().mockResolvedValue({ + ["m.room_versions"]: { + default: "1", + available: ["1"], + }, + }); + + const room = new Room(roomId, client, userA); + expect(await room.getRecommendedVersion()).toEqual({ + version: "1", + needsUpgrade: false, + urgent: false, + }); + expect(client.fetchCapabilities).toHaveBeenCalled(); + }); + }); }); diff --git a/spec/unit/rust-crypto/rust-crypto.spec.ts b/spec/unit/rust-crypto/rust-crypto.spec.ts index 57c1066d593..2b161c778f7 100644 --- a/spec/unit/rust-crypto/rust-crypto.spec.ts +++ b/spec/unit/rust-crypto/rust-crypto.spec.ts @@ -95,6 +95,7 @@ describe("initRustCrypto", () => { deleteSecretsFromInbox: jest.fn(), registerReceiveSecretCallback: jest.fn(), registerDevicesUpdatedCallback: jest.fn(), + registerRoomKeysWithheldCallback: jest.fn(), outgoingRequests: jest.fn(), isBackupEnabled: jest.fn().mockResolvedValue(false), verifyBackup: jest.fn().mockResolvedValue({ trusted: jest.fn().mockReturnValue(false) }), @@ -1515,6 +1516,44 @@ describe("RustCrypto", () => { expect(await rustCrypto.isDehydrationSupported()).toBe(true); }); }); + + describe("import & export secrets bundle", () => { + let rustCrypto: RustCrypto; + + beforeEach(async () => { + rustCrypto = await makeTestRustCrypto( + new MatrixHttpApi(new TypedEventEmitter(), { + baseUrl: "http://server/", + prefix: "", + onlyData: true, + }), + testData.TEST_USER_ID, + ); + }); + + it("should throw an error if there is nothing to export", async () => { + await expect(rustCrypto.exportSecretsBundle()).rejects.toThrow( + "The store doesn't contain any cross-signing keys", + ); + }); + + it("should correctly import & export a secrets bundle", async () => { + const bundle = { + cross_signing: { + master_key: "bMnVpkHI4S2wXRxy+IpaKM5PIAUUkl6DE+n0YLIW/qs", + user_signing_key: "8tlgLjUrrb/zGJo4YKGhDTIDCEjtJTAS/Sh2AGNLuIo", + self_signing_key: "pfDknmP5a0fVVRE54zhkUgJfzbNmvKcNfIWEW796bQs", + }, + backup: { + algorithm: "m.megolm_backup.v1.curve25519-aes-sha2", + key: "bYYv3aFLQ49jMNcOjuTtBY9EKDby2x1m3gfX81nIKRQ", + backup_version: "9", + }, + }; + await rustCrypto.importSecretsBundle(bundle); + await expect(rustCrypto.exportSecretsBundle()).resolves.toEqual(expect.objectContaining(bundle)); + }); + }); }); /** Build a MatrixHttpApi instance */ diff --git a/spec/unit/timeline-window.spec.ts b/spec/unit/timeline-window.spec.ts index ddb2a48d3b9..a428e905a2f 100644 --- a/spec/unit/timeline-window.spec.ts +++ b/spec/unit/timeline-window.spec.ts @@ -434,7 +434,7 @@ describe("TimelineWindow", function () { }); function idsOf(events: Array): Array { - return events.map((e) => (e ? e.getId() ?? "MISSING_ID" : "MISSING_EVENT")); + return events.map((e) => (e ? (e.getId() ?? "MISSING_ID") : "MISSING_EVENT")); } describe("removing events", () => { diff --git a/spec/unit/webrtc/groupCall.spec.ts b/spec/unit/webrtc/groupCall.spec.ts index ea04a1f3ed8..286f5d1011e 100644 --- a/spec/unit/webrtc/groupCall.spec.ts +++ b/spec/unit/webrtc/groupCall.spec.ts @@ -105,7 +105,7 @@ const mockGetStateEvents = (events: MatrixEvent[] = FAKE_STATE_EVENTS as MatrixEvent[]) => (type: EventType, userId?: string): MatrixEvent[] | MatrixEvent | null => { if (type === EventType.GroupCallMemberPrefix) { - return userId === undefined ? events : events.find((e) => e.getStateKey() === userId) ?? null; + return userId === undefined ? events : (events.find((e) => e.getStateKey() === userId) ?? null); } else { const fakeEvent = { getContent: () => ({}), getTs: () => 0 } as MatrixEvent; return userId === undefined ? [fakeEvent] : fakeEvent; diff --git a/src/@types/auth.ts b/src/@types/auth.ts index 649a851764e..27b220db39c 100644 --- a/src/@types/auth.ts +++ b/src/@types/auth.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { UnstableValue } from "../NamespacedValue"; -import { IClientWellKnown } from "../client"; +import { UnstableValue } from "../NamespacedValue.ts"; +import { IClientWellKnown } from "../client.ts"; // disable lint because these are wire responses /* eslint-disable camelcase */ diff --git a/src/@types/beacon.ts b/src/@types/beacon.ts index e6bfb8ff95a..2bcc6260ce5 100644 --- a/src/@types/beacon.ts +++ b/src/@types/beacon.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RelatesToRelationship, REFERENCE_RELATION } from "./extensible_events"; -import { UnstableValue } from "../NamespacedValue"; -import { MAssetEvent, MLocationEvent, MTimestampEvent } from "./location"; +import { RelatesToRelationship, REFERENCE_RELATION } from "./extensible_events.ts"; +import { UnstableValue } from "../NamespacedValue.ts"; +import { MAssetEvent, MLocationEvent, MTimestampEvent } from "./location.ts"; /** * Beacon info and beacon event types as described in MSC3672 diff --git a/src/@types/crypto.ts b/src/@types/crypto.ts index 010882966f4..54389e33603 100644 --- a/src/@types/crypto.ts +++ b/src/@types/crypto.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type { ISignatures } from "./signed"; +import type { ISignatures } from "./signed.ts"; export type OlmGroupSessionExtraData = { untrusted?: boolean; @@ -22,7 +22,7 @@ export type OlmGroupSessionExtraData = { }; // Backwards compatible re-export -export type { EventDecryptionResult as IEventDecryptionResult } from "../common-crypto/CryptoBackend"; +export type { EventDecryptionResult as IEventDecryptionResult } from "../common-crypto/CryptoBackend.ts"; interface Extensible { [key: string]: any; diff --git a/src/@types/event.ts b/src/@types/event.ts index 5d8a26c9b23..0d28b38fc32 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { UnstableValue } from "../NamespacedValue"; +import { NamespacedValue, UnstableValue } from "../NamespacedValue.ts"; import { PolicyRuleEventContent, RoomAvatarEventContent, @@ -34,16 +34,16 @@ import { RoomTopicEventContent, SpaceChildEventContent, SpaceParentEventContent, -} from "./state_events"; +} from "./state_events.ts"; import { ExperimentalGroupCallRoomMemberState, IGroupCallRoomMemberState, IGroupCallRoomState, -} from "../webrtc/groupCall"; -import { MSC3089EventContent } from "../models/MSC3089Branch"; -import { M_BEACON, M_BEACON_INFO, MBeaconEventContent, MBeaconInfoEventContent } from "./beacon"; -import { XOR } from "./common"; -import { ReactionEventContent, RoomMessageEventContent, StickerEventContent } from "./events"; +} from "../webrtc/groupCall.ts"; +import { MSC3089EventContent } from "../models/MSC3089Branch.ts"; +import { M_BEACON, M_BEACON_INFO, MBeaconEventContent, MBeaconInfoEventContent } from "./beacon.ts"; +import { XOR } from "./common.ts"; +import { ReactionEventContent, RoomMessageEventContent, StickerEventContent } from "./events.ts"; import { MCallAnswer, MCallBase, @@ -54,9 +54,10 @@ import { MCallSelectAnswer, SDPStreamMetadata, SDPStreamMetadataKey, -} from "../webrtc/callEventTypes"; -import { EncryptionKeysEventContent, ICallNotifyContent } from "../matrixrtc/types"; -import { M_POLL_END, M_POLL_START, PollEndEventContent, PollStartEventContent } from "./polls"; +} from "../webrtc/callEventTypes.ts"; +import { EncryptionKeysEventContent, ICallNotifyContent } from "../matrixrtc/types.ts"; +import { M_POLL_END, M_POLL_START, PollEndEventContent, PollStartEventContent } from "./polls.ts"; +import { SessionMembershipData } from "../matrixrtc/CallMembership.ts"; export enum EventType { // Room state events @@ -302,7 +303,7 @@ export const UNSIGNED_THREAD_ID_FIELD = new UnstableValue("thread_id", "org.matr * * @experimental */ -export const UNSIGNED_MEMBERSHIP_FIELD = new UnstableValue("membership", "io.element.msc4115.membership"); +export const UNSIGNED_MEMBERSHIP_FIELD = new NamespacedValue("membership", "io.element.msc4115.membership"); /** * Mapped type from event type to content type for all specified non-state room events. @@ -356,7 +357,10 @@ export interface StateEvents { // MSC3401 [EventType.GroupCallPrefix]: IGroupCallRoomState; - [EventType.GroupCallMemberPrefix]: XOR; + [EventType.GroupCallMemberPrefix]: XOR< + XOR, + XOR + >; // MSC3089 [UNSTABLE_MSC3089_BRANCH.name]: MSC3089EventContent; diff --git a/src/@types/events.ts b/src/@types/events.ts index 59c41d2018c..55af87252b0 100644 --- a/src/@types/events.ts +++ b/src/@types/events.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MsgType, RelationType } from "./event"; -import { FileInfo, ImageInfo, MediaEventContent } from "./media"; -import { XOR } from "./common"; +import { MsgType, RelationType } from "./event.ts"; +import { FileInfo, ImageInfo, MediaEventContent } from "./media.ts"; +import { XOR } from "./common.ts"; interface BaseTimelineEvent { "body": string; diff --git a/src/@types/extensible_events.ts b/src/@types/extensible_events.ts index 9b16e0e437e..27095c271a9 100644 --- a/src/@types/extensible_events.ts +++ b/src/@types/extensible_events.ts @@ -16,7 +16,7 @@ limitations under the License. import { EitherAnd, NamespacedValue, Optional, UnstableValue } from "matrix-events-sdk"; -import { isProvided } from "../extensible_events_v1/utilities"; +import { isProvided } from "../extensible_events_v1/utilities.ts"; // Types and utilities for MSC1767: Extensible events (version 1) in Matrix diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 71c0c87b815..d7e7c76ac2d 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -29,20 +29,11 @@ declare global { namespace NodeJS { interface Global { - localStorage: Storage; // marker variable used to detect both the browser & node entrypoints being used at once __js_sdk_entrypoint: unknown; } } - interface Window { - webkitAudioContext: typeof AudioContext; - } - - interface Crypto { - webkitSubtle?: Window["crypto"]["subtle"]; - } - interface MediaDevices { // This is experimental and types don't know about it yet // https://github.com/microsoft/TypeScript/issues/33232 @@ -76,40 +67,4 @@ declare global { // on webkit: we should check if we still need to do this webkitGetUserMedia: DummyInterfaceWeShouldntBeUsingThis; } - - export interface ISettledFulfilled { - status: "fulfilled"; - value: T; - } - export interface ISettledRejected { - status: "rejected"; - reason: any; - } - - interface PromiseConstructor { - allSettled(promises: Promise[]): Promise | ISettledRejected>>; - } - - interface RTCRtpTransceiver { - // This has been removed from TS - // (https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/1029), - // but we still need this for MatrixCall::getRidOfRTXCodecs() - setCodecPreferences(codecs: RTCRtpCodecCapability[]): void; - } - - interface RequestInit { - /** - * Specifies the priority of the fetch request relative to other requests of the same type. - * Must be one of the following strings: - * high: A high priority fetch request relative to other requests of the same type. - * low: A low priority fetch request relative to other requests of the same type. - * auto: Automatically determine the priority of the fetch request relative to other requests of the same type (default). - * - * @see https://html.spec.whatwg.org/multipage/urls-and-fetching.html#fetch-priority-attribute - * @see https://github.com/microsoft/TypeScript/issues/54472 - * @see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility - * Not yet supported in Safari or Firefox - */ - priority?: "high" | "low" | "auto"; - } } diff --git a/src/@types/location.ts b/src/@types/location.ts index d1a826fd8f1..dd7c49bf024 100644 --- a/src/@types/location.ts +++ b/src/@types/location.ts @@ -17,8 +17,8 @@ limitations under the License. // Types for MSC3488 - m.location: Extending events with location data import { EitherAnd } from "matrix-events-sdk"; -import { UnstableValue } from "../NamespacedValue"; -import { M_TEXT } from "./extensible_events"; +import { UnstableValue } from "../NamespacedValue.ts"; +import { M_TEXT } from "./extensible_events.ts"; export enum LocationAssetType { Self = "m.self", diff --git a/src/@types/matrix-sdk-crypto-wasm.d.ts b/src/@types/matrix-sdk-crypto-wasm.d.ts new file mode 100644 index 00000000000..c7504a3484d --- /dev/null +++ b/src/@types/matrix-sdk-crypto-wasm.d.ts @@ -0,0 +1,44 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import type * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; + +declare module "@matrix-org/matrix-sdk-crypto-wasm" { + interface OlmMachine { + importSecretsBundle(bundle: RustSdkCryptoJs.SecretsBundle): Promise; + exportSecretsBundle(): Promise; + } + + interface SecretsBundle { + // eslint-disable-next-line @typescript-eslint/naming-convention + to_json(): Promise<{ + cross_signing: { + master_key: string; + self_signing_key: string; + user_signing_key: string; + }; + backup?: { + algorithm: string; + key: string; + backup_version: string; + }; + }>; + } + + interface Device { + requestVerification(methods?: any[]): [RustSdkCryptoJs.VerificationRequest, RustSdkCryptoJs.ToDeviceRequest]; + } +} diff --git a/src/@types/media.ts b/src/@types/media.ts index 20e5ca6c66b..ef23668b05d 100644 --- a/src/@types/media.ts +++ b/src/@types/media.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MsgType } from "../@types/event"; +import { MsgType } from "../@types/event.ts"; /** * Information on encrypted media attachments. diff --git a/src/@types/polls.ts b/src/@types/polls.ts index 3b06f932a62..1a602dc0ca9 100644 --- a/src/@types/polls.ts +++ b/src/@types/polls.ts @@ -21,7 +21,7 @@ import { REFERENCE_RELATION, RelatesToRelationship, TSNamespace, -} from "./extensible_events"; +} from "./extensible_events.ts"; /** * Identifier for a disclosed poll. diff --git a/src/@types/registration.ts b/src/@types/registration.ts index 7bfb99f7d40..2799ba17805 100644 --- a/src/@types/registration.ts +++ b/src/@types/registration.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { AuthDict } from "../interactive-auth"; +import { AuthDict } from "../interactive-auth.ts"; /** * The request body of a call to `POST /_matrix/client/v3/register`. diff --git a/src/@types/requests.ts b/src/@types/requests.ts index d6b7ff75fa2..0baedff3ff4 100644 --- a/src/@types/requests.ts +++ b/src/@types/requests.ts @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IContent, IEvent } from "../models/event"; -import { Preset, Visibility } from "./partials"; -import { IEventWithRoomId, SearchKey } from "./search"; -import { IRoomEventFilter } from "../filter"; -import { Direction } from "../models/event-timeline"; -import { PushRuleAction } from "./PushRules"; -import { IRoomEvent } from "../sync-accumulator"; -import { EventType, RelationType, RoomType } from "./event"; +import { IContent, IEvent } from "../models/event.ts"; +import { Preset, Visibility } from "./partials.ts"; +import { IEventWithRoomId, SearchKey } from "./search.ts"; +import { IRoomEventFilter } from "../filter.ts"; +import { Direction } from "../models/event-timeline.ts"; +import { PushRuleAction } from "./PushRules.ts"; +import { IRoomEvent } from "../sync-accumulator.ts"; +import { EventType, RelationType, RoomType } from "./event.ts"; // allow camelcase as these are things that go onto the wire /* eslint-disable camelcase */ @@ -76,6 +76,56 @@ export interface ISendEventResponse { event_id: string; } +export type TimeoutDelay = { + delay: number; +}; + +export type ParentDelayId = { + parent_delay_id: string; +}; + +export type SendTimeoutDelayedEventRequestOpts = TimeoutDelay & Partial; +export type SendActionDelayedEventRequestOpts = ParentDelayId; + +export type SendDelayedEventRequestOpts = SendTimeoutDelayedEventRequestOpts | SendActionDelayedEventRequestOpts; + +export type SendDelayedEventResponse = { + delay_id: string; +}; + +export enum UpdateDelayedEventAction { + Cancel = "cancel", + Restart = "restart", + Send = "send", +} + +export type UpdateDelayedEventRequestOpts = SendDelayedEventResponse & { + action: UpdateDelayedEventAction; +}; + +type DelayedPartialTimelineEvent = { + room_id: string; + type: string; + content: IContent; +}; + +type DelayedPartialStateEvent = DelayedPartialTimelineEvent & { + state_key: string; + transaction_id: string; +}; + +type DelayedPartialEvent = DelayedPartialTimelineEvent | DelayedPartialStateEvent; + +export type DelayedEventInfo = { + delayed_events: DelayedPartialEvent & + SendDelayedEventResponse & + SendDelayedEventRequestOpts & + { + running_since: number; + }[]; + next_batch?: string; +}; + export interface IPresenceOpts { // One of "online", "offline" or "unavailable" presence: "online" | "offline" | "unavailable"; diff --git a/src/@types/search.ts b/src/@types/search.ts index 3a6d4fdd57f..4069d3e9826 100644 --- a/src/@types/search.ts +++ b/src/@types/search.ts @@ -16,9 +16,9 @@ limitations under the License. // Types relating to the /search API -import { IRoomEvent, IStateEvent } from "../sync-accumulator"; -import { IRoomEventFilter } from "../filter"; -import { SearchResult } from "../models/search-result"; +import { IRoomEvent, IStateEvent } from "../sync-accumulator.ts"; +import { IRoomEventFilter } from "../filter.ts"; +import { SearchResult } from "../models/search-result.ts"; /* eslint-disable camelcase */ export interface IEventWithRoomId extends IRoomEvent { @@ -54,9 +54,9 @@ enum GroupKey { } export interface IResultRoomEvents { - count: number; - highlights: string[]; - results: ISearchResult[]; + count?: number; + highlights?: string[]; + results?: ISearchResult[]; state?: { [roomId: string]: IStateEventWithRoomId[] }; groups?: { [groupKey in GroupKey]: { diff --git a/src/@types/spaces.ts b/src/@types/spaces.ts index 9edab274a16..249952e5c33 100644 --- a/src/@types/spaces.ts +++ b/src/@types/spaces.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IPublicRoomsChunkRoom } from "../client"; -import { RoomType } from "./event"; -import { IStrippedState } from "../sync-accumulator"; +import { IPublicRoomsChunkRoom } from "../client.ts"; +import { RoomType } from "./event.ts"; +import { IStrippedState } from "../sync-accumulator.ts"; // Types relating to Rooms of type `m.space` and related APIs diff --git a/src/@types/state_events.ts b/src/@types/state_events.ts index 415f2806a75..d570c5a1299 100644 --- a/src/@types/state_events.ts +++ b/src/@types/state_events.ts @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RoomType } from "./event"; -import { GuestAccess, HistoryVisibility, JoinRule, RestrictedAllowType } from "./partials"; -import { ImageInfo } from "./media"; -import { PolicyRecommendation } from "../models/invites-ignorer"; +import { RoomType } from "./event.ts"; +import { GuestAccess, HistoryVisibility, JoinRule, RestrictedAllowType } from "./partials.ts"; +import { ImageInfo } from "./media.ts"; +import { PolicyRecommendation } from "../models/invites-ignorer.ts"; export interface RoomCanonicalAliasEventContent { alias?: string; @@ -95,7 +95,9 @@ export interface RoomTopicEventContent { export interface RoomAvatarEventContent { url?: string; - info?: ImageInfo; + // The spec says that an encrypted file can be used for the thumbnail but this isn't true + // https://github.com/matrix-org/matrix-spec/issues/562 so omit those fields + info?: Omit; } export interface RoomPinnedEventsEventContent { diff --git a/src/@types/synapse.ts b/src/@types/synapse.ts index 1d4ce41ac61..8b309c2ae95 100644 --- a/src/@types/synapse.ts +++ b/src/@types/synapse.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IdServerUnbindResult } from "./partials"; +import { IdServerUnbindResult } from "./partials.ts"; // Types relating to Synapse Admin APIs diff --git a/src/@types/sync.ts b/src/@types/sync.ts index d9a2a6f564d..74e00f79286 100644 --- a/src/@types/sync.ts +++ b/src/@types/sync.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ServerControlledNamespacedValue } from "../NamespacedValue"; +import { ServerControlledNamespacedValue } from "../NamespacedValue.ts"; /** * https://github.com/matrix-org/matrix-doc/pull/3773 diff --git a/src/@types/topic.ts b/src/@types/topic.ts index 04d14640680..3d4a633326a 100644 --- a/src/@types/topic.ts +++ b/src/@types/topic.ts @@ -16,8 +16,8 @@ limitations under the License. import { EitherAnd } from "matrix-events-sdk"; -import { UnstableValue } from "../NamespacedValue"; -import { IMessageRendering } from "./extensible_events"; +import { UnstableValue } from "../NamespacedValue.ts"; +import { IMessageRendering } from "./extensible_events.ts"; /** * Extensible topic event type based on MSC3765 diff --git a/src/@types/uia.ts b/src/@types/uia.ts index bc10f2dd9cd..0103d45517a 100644 --- a/src/@types/uia.ts +++ b/src/@types/uia.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { AuthDict, IAuthData } from "../interactive-auth"; +import { AuthDict, IAuthData } from "../interactive-auth.ts"; /** * Helper type to represent HTTP request body for a UIA enabled endpoint diff --git a/src/ReEmitter.ts b/src/ReEmitter.ts index 5d41ac0e455..9a1bb17d48c 100644 --- a/src/ReEmitter.ts +++ b/src/ReEmitter.ts @@ -19,7 +19,7 @@ limitations under the License. // eslint-disable-next-line no-restricted-imports import { EventEmitter } from "events"; -import { ListenerMap, TypedEventEmitter } from "./models/typed-event-emitter"; +import { ListenerMap, TypedEventEmitter } from "./models/typed-event-emitter.ts"; export class ReEmitter { public constructor(private readonly target: EventEmitter) {} diff --git a/src/ToDeviceMessageQueue.ts b/src/ToDeviceMessageQueue.ts index 59eada4db22..391f678fa07 100644 --- a/src/ToDeviceMessageQueue.ts +++ b/src/ToDeviceMessageQueue.ts @@ -14,14 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ToDeviceMessageId } from "./@types/event"; -import { logger } from "./logger"; -import { MatrixClient, ClientEvent } from "./client"; -import { MatrixError } from "./http-api"; -import { IndexedToDeviceBatch, ToDeviceBatch, ToDeviceBatchWithTxnId, ToDevicePayload } from "./models/ToDeviceMessage"; -import { MatrixScheduler } from "./scheduler"; -import { SyncState } from "./sync"; -import { MapWithDefault } from "./utils"; +import { ToDeviceMessageId } from "./@types/event.ts"; +import { logger } from "./logger.ts"; +import { MatrixClient, ClientEvent } from "./client.ts"; +import { MatrixError } from "./http-api/index.ts"; +import { + IndexedToDeviceBatch, + ToDeviceBatch, + ToDeviceBatchWithTxnId, + ToDevicePayload, +} from "./models/ToDeviceMessage.ts"; +import { MatrixScheduler } from "./scheduler.ts"; +import { SyncState } from "./sync.ts"; +import { MapWithDefault } from "./utils.ts"; const MAX_BATCH_SIZE = 20; diff --git a/src/autodiscovery.ts b/src/autodiscovery.ts index 8f4f196682c..3733e533022 100644 --- a/src/autodiscovery.ts +++ b/src/autodiscovery.ts @@ -15,10 +15,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IClientWellKnown, IWellKnownConfig, IServerVersions } from "./client"; -import { logger } from "./logger"; -import { MatrixError, Method, timeoutSignal } from "./http-api"; -import { SUPPORTED_MATRIX_VERSIONS } from "./version-support"; +import { IClientWellKnown, IWellKnownConfig, IServerVersions } from "./client.ts"; +import { logger } from "./logger.ts"; +import { MatrixError, Method, timeoutSignal } from "./http-api/index.ts"; +import { SUPPORTED_MATRIX_VERSIONS } from "./version-support.ts"; // Dev note: Auto discovery is part of the spec. // See: https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery diff --git a/src/base64.ts b/src/base64.ts index 79bc5a49380..450468b0889 100644 --- a/src/base64.ts +++ b/src/base64.ts @@ -59,7 +59,7 @@ export function encodeUnpaddedBase64(uint8Array: ArrayBuffer | Uint8Array): stri * @returns The unpadded base64. */ export function encodeUnpaddedBase64Url(uint8Array: ArrayBuffer | Uint8Array): string { - return encodeUnpaddedBase64(uint8Array).replace("+", "-").replace("/", "_"); + return encodeUnpaddedBase64(uint8Array).replace(/\+/g, "-").replace(/\//g, "_"); } /** @@ -75,7 +75,7 @@ export function decodeBase64(base64: string): Uint8Array { const itFunc = function* (): Generator { const decoded = atob( // built-in atob doesn't support base64url: convert so we support either - base64.replace("-", "+").replace("_", "/"), + base64.replace(/-/g, "+").replace(/_/g, "/"), ); for (let i = 0; i < decoded.length; ++i) { yield decoded.charCodeAt(i); diff --git a/src/browser-index.ts b/src/browser-index.ts index a8d9e4ab0bb..6b77aed915a 100644 --- a/src/browser-index.ts +++ b/src/browser-index.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as matrixcs from "./matrix"; +import * as matrixcs from "./matrix.ts"; type BrowserMatrix = typeof matrixcs; declare global { @@ -40,5 +40,5 @@ if (indexedDB) { matrixcs.setCryptoStoreFactory(() => new matrixcs.IndexedDBCryptoStore(indexedDB!, "matrix-js-sdk:crypto")); } -export * from "./matrix"; +export * from "./matrix.ts"; globalThis.matrixcs = matrixcs; diff --git a/src/client.ts b/src/client.ts index 981b8e5d69a..4375830ff44 100644 --- a/src/client.ts +++ b/src/client.ts @@ -20,8 +20,8 @@ limitations under the License. import { Optional } from "matrix-events-sdk"; -import type { IDeviceKeys, IMegolmSessionData, IOneTimeKey } from "./@types/crypto"; -import { ISyncStateData, SetPresence, SyncApi, SyncApiOptions, SyncState } from "./sync"; +import type { IDeviceKeys, IMegolmSessionData, IOneTimeKey } from "./@types/crypto.ts"; +import { ISyncStateData, SetPresence, SyncApi, SyncApiOptions, SyncState } from "./sync.ts"; import { EventStatus, IContent, @@ -31,29 +31,29 @@ import { MatrixEventEvent, MatrixEventHandlerMap, PushDetails, -} from "./models/event"; -import { StubStore } from "./store/stub"; -import { CallEvent, CallEventHandlerMap, createNewMatrixCall, MatrixCall, supportsMatrixCall } from "./webrtc/call"; -import { Filter, IFilterDefinition, IRoomEventFilter } from "./filter"; -import { CallEventHandler, CallEventHandlerEvent, CallEventHandlerEventHandlerMap } from "./webrtc/callEventHandler"; +} from "./models/event.ts"; +import { StubStore } from "./store/stub.ts"; +import { CallEvent, CallEventHandlerMap, createNewMatrixCall, MatrixCall, supportsMatrixCall } from "./webrtc/call.ts"; +import { Filter, IFilterDefinition, IRoomEventFilter } from "./filter.ts"; +import { CallEventHandler, CallEventHandlerEvent, CallEventHandlerEventHandlerMap } from "./webrtc/callEventHandler.ts"; import { GroupCallEventHandler, GroupCallEventHandlerEvent, GroupCallEventHandlerEventHandlerMap, -} from "./webrtc/groupCallEventHandler"; -import * as utils from "./utils"; -import { noUnsafeEventProps, QueryDict, replaceParam, safeSet, sleep } from "./utils"; -import { Direction, EventTimeline } from "./models/event-timeline"; -import { IActionsObject, PushProcessor } from "./pushprocessor"; -import { AutoDiscovery, AutoDiscoveryAction } from "./autodiscovery"; -import * as olmlib from "./crypto/olmlib"; -import { decodeBase64, encodeBase64 } from "./base64"; -import { IExportedDevice as IExportedOlmDevice } from "./crypto/OlmDevice"; -import { IOlmDevice } from "./crypto/algorithms/megolm"; -import { TypedReEmitter } from "./ReEmitter"; -import { IRoomEncryption } from "./crypto/RoomList"; -import { logger, Logger } from "./logger"; -import { SERVICE_TYPES } from "./service-types"; +} from "./webrtc/groupCallEventHandler.ts"; +import * as utils from "./utils.ts"; +import { noUnsafeEventProps, QueryDict, replaceParam, safeSet, sleep } from "./utils.ts"; +import { Direction, EventTimeline } from "./models/event-timeline.ts"; +import { IActionsObject, PushProcessor } from "./pushprocessor.ts"; +import { AutoDiscovery, AutoDiscoveryAction } from "./autodiscovery.ts"; +import * as olmlib from "./crypto/olmlib.ts"; +import { decodeBase64, encodeBase64, encodeUnpaddedBase64Url } from "./base64.ts"; +import { IExportedDevice as IExportedOlmDevice } from "./crypto/OlmDevice.ts"; +import { IOlmDevice } from "./crypto/algorithms/megolm.ts"; +import { TypedReEmitter } from "./ReEmitter.ts"; +import { IRoomEncryption } from "./crypto/RoomList.ts"; +import { logger, Logger } from "./logger.ts"; +import { SERVICE_TYPES } from "./service-types.ts"; import { Body, ClientPrefix, @@ -73,7 +73,7 @@ import { Upload, UploadOpts, UploadResponse, -} from "./http-api"; +} from "./http-api/index.ts"; import { Crypto, CryptoEvent, @@ -83,14 +83,14 @@ import { ICryptoCallbacks, IRoomKeyRequestBody, isCryptoAvailable, -} from "./crypto"; -import { DeviceInfo } from "./crypto/deviceinfo"; -import { decodeRecoveryKey } from "./crypto/recoverykey"; -import { keyFromAuthData } from "./crypto/key_passphrase"; -import { User, UserEvent, UserEventHandlerMap } from "./models/user"; -import { getHttpUriForMxc } from "./content-repo"; -import { SearchResult } from "./models/search-result"; -import { DEHYDRATION_ALGORITHM, IDehydratedDevice, IDehydratedDeviceKeyInfo } from "./crypto/dehydration"; +} from "./crypto/index.ts"; +import { DeviceInfo } from "./crypto/deviceinfo.ts"; +import { decodeRecoveryKey } from "./crypto/recoverykey.ts"; +import { keyFromAuthData } from "./crypto/key_passphrase.ts"; +import { User, UserEvent, UserEventHandlerMap } from "./models/user.ts"; +import { getHttpUriForMxc } from "./content-repo.ts"; +import { SearchResult } from "./models/search-result.ts"; +import { DEHYDRATION_ALGORITHM, IDehydratedDevice, IDehydratedDeviceKeyInfo } from "./crypto/dehydration.ts"; import { IKeyBackupInfo, IKeyBackupPrepareOpts, @@ -98,22 +98,23 @@ import { IKeyBackupRestoreResult, IKeyBackupRoomSessions, IKeyBackupSession, -} from "./crypto/keybackup"; -import { IIdentityServerProvider } from "./@types/IIdentityServerProvider"; -import { MatrixScheduler } from "./scheduler"; -import { BeaconEvent, BeaconEventHandlerMap } from "./models/beacon"; -import { AuthDict } from "./interactive-auth"; -import { IMinimalEvent, IRoomEvent, IStateEvent } from "./sync-accumulator"; -import { CrossSigningKey, ICreateSecretStorageOpts, IEncryptedEventInfo, IRecoveryKey } from "./crypto/api"; -import { EventTimelineSet } from "./models/event-timeline-set"; -import { VerificationRequest } from "./crypto/verification/request/VerificationRequest"; -import { VerificationBase as Verification } from "./crypto/verification/Base"; -import * as ContentHelpers from "./content-helpers"; -import { CrossSigningInfo, DeviceTrustLevel, ICacheCallbacks, UserTrustLevel } from "./crypto/CrossSigning"; -import { NotificationCountType, Room, RoomEvent, RoomEventHandlerMap, RoomNameState } from "./models/room"; -import { RoomMemberEvent, RoomMemberEventHandlerMap } from "./models/room-member"; -import { IPowerLevelsContent, RoomStateEvent, RoomStateEventHandlerMap } from "./models/room-state"; +} from "./crypto/keybackup.ts"; +import { IIdentityServerProvider } from "./@types/IIdentityServerProvider.ts"; +import { MatrixScheduler } from "./scheduler.ts"; +import { BeaconEvent, BeaconEventHandlerMap } from "./models/beacon.ts"; +import { AuthDict } from "./interactive-auth.ts"; +import { IMinimalEvent, IRoomEvent, IStateEvent } from "./sync-accumulator.ts"; +import { CrossSigningKey, ICreateSecretStorageOpts, IEncryptedEventInfo, IRecoveryKey } from "./crypto/api.ts"; +import { EventTimelineSet } from "./models/event-timeline-set.ts"; +import { VerificationRequest } from "./crypto/verification/request/VerificationRequest.ts"; +import { VerificationBase as Verification } from "./crypto/verification/Base.ts"; +import * as ContentHelpers from "./content-helpers.ts"; +import { CrossSigningInfo, DeviceTrustLevel, ICacheCallbacks, UserTrustLevel } from "./crypto/CrossSigning.ts"; +import { NotificationCountType, Room, RoomEvent, RoomEventHandlerMap, RoomNameState } from "./models/room.ts"; +import { RoomMemberEvent, RoomMemberEventHandlerMap } from "./models/room-member.ts"; +import { IPowerLevelsContent, RoomStateEvent, RoomStateEventHandlerMap } from "./models/room-state.ts"; import { + DelayedEventInfo, IAddThreePidOnlyBody, IBindThreePidBody, IContextResponse, @@ -134,7 +135,10 @@ import { IStatusResponse, ITagsResponse, KnockRoomOpts, -} from "./@types/requests"; + SendDelayedEventRequestOpts, + SendDelayedEventResponse, + UpdateDelayedEventAction, +} from "./@types/requests.ts"; import { EventType, LOCAL_NOTIFICATION_SETTINGS_PREFIX, @@ -149,15 +153,22 @@ import { UNSTABLE_MSC3088_ENABLED, UNSTABLE_MSC3088_PURPOSE, UNSTABLE_MSC3089_TREE_SUBTYPE, -} from "./@types/event"; -import { GuestAccess, HistoryVisibility, IdServerUnbindResult, JoinRule, Preset, Visibility } from "./@types/partials"; -import { EventMapper, eventMapperFor, MapperOpts } from "./event-mapper"; -import { randomString } from "./randomstring"; -import { BackupManager, IKeyBackup, IKeyBackupCheck, IPreparedKeyBackupVersion, TrustInfo } from "./crypto/backup"; -import { DEFAULT_TREE_POWER_LEVELS_TEMPLATE, MSC3089TreeSpace } from "./models/MSC3089TreeSpace"; -import { ISignatures } from "./@types/signed"; -import { IStore } from "./store"; -import { ISecretRequest } from "./crypto/SecretStorage"; +} from "./@types/event.ts"; +import { + GuestAccess, + HistoryVisibility, + IdServerUnbindResult, + JoinRule, + Preset, + Visibility, +} from "./@types/partials.ts"; +import { EventMapper, eventMapperFor, MapperOpts } from "./event-mapper.ts"; +import { randomString } from "./randomstring.ts"; +import { BackupManager, IKeyBackup, IKeyBackupCheck, IPreparedKeyBackupVersion, TrustInfo } from "./crypto/backup.ts"; +import { DEFAULT_TREE_POWER_LEVELS_TEMPLATE, MSC3089TreeSpace } from "./models/MSC3089TreeSpace.ts"; +import { ISignatures } from "./@types/signed.ts"; +import { IStore } from "./store/index.ts"; +import { ISecretRequest } from "./crypto/SecretStorage.ts"; import { IEventWithRoomId, ISearchRequestBody, @@ -165,9 +176,9 @@ import { ISearchResults, IStateEventWithRoomId, SearchOrderBy, -} from "./@types/search"; -import { ISynapseAdminDeactivateResponse, ISynapseAdminWhoisResponse } from "./@types/synapse"; -import { IHierarchyRoom } from "./@types/spaces"; +} from "./@types/search.ts"; +import { ISynapseAdminDeactivateResponse, ISynapseAdminWhoisResponse } from "./@types/synapse.ts"; +import { IHierarchyRoom } from "./@types/spaces.ts"; import { IPusher, IPusherRequest, @@ -177,11 +188,11 @@ import { PushRuleActionName, PushRuleKind, RuleId, -} from "./@types/PushRules"; -import { IThreepid } from "./@types/threepids"; -import { CryptoStore, OutgoingRoomKeyRequest } from "./crypto/store/base"; -import { GroupCall, GroupCallIntent, GroupCallType, IGroupCallDataChannelOptions } from "./webrtc/groupCall"; -import { MediaHandler } from "./webrtc/mediaHandler"; +} from "./@types/PushRules.ts"; +import { IThreepid } from "./@types/threepids.ts"; +import { CryptoStore, OutgoingRoomKeyRequest } from "./crypto/store/base.ts"; +import { GroupCall, GroupCallIntent, GroupCallType, IGroupCallDataChannelOptions } from "./webrtc/groupCall.ts"; +import { MediaHandler } from "./webrtc/mediaHandler.ts"; import { ILoginFlowsResponse, IRefreshTokenResponse, @@ -189,11 +200,11 @@ import { LoginResponse, LoginTokenPostResponse, SSOAction, -} from "./@types/auth"; -import { TypedEventEmitter } from "./models/typed-event-emitter"; -import { MAIN_ROOM_TIMELINE, ReceiptType } from "./@types/read_receipts"; -import { MSC3575SlidingSyncRequest, MSC3575SlidingSyncResponse, SlidingSync } from "./sliding-sync"; -import { SlidingSyncSdk } from "./sliding-sync-sdk"; +} from "./@types/auth.ts"; +import { TypedEventEmitter } from "./models/typed-event-emitter.ts"; +import { MAIN_ROOM_TIMELINE, ReceiptType } from "./@types/read_receipts.ts"; +import { MSC3575SlidingSyncRequest, MSC3575SlidingSyncResponse, SlidingSync } from "./sliding-sync.ts"; +import { SlidingSyncSdk } from "./sliding-sync-sdk.ts"; import { determineFeatureSupport, FeatureSupport, @@ -201,31 +212,33 @@ import { THREAD_RELATION_TYPE, ThreadFilterType, threadFilterTypeToFilter, -} from "./models/thread"; -import { M_BEACON_INFO, MBeaconInfoEventContent } from "./@types/beacon"; -import { NamespacedValue, UnstableValue } from "./NamespacedValue"; -import { ToDeviceMessageQueue } from "./ToDeviceMessageQueue"; -import { ToDeviceBatch } from "./models/ToDeviceMessage"; -import { IgnoredInvites } from "./models/invites-ignorer"; -import { UIARequest, UIAResponse } from "./@types/uia"; -import { LocalNotificationSettings } from "./@types/local_notifications"; -import { buildFeatureSupportMap, Feature, ServerSupport } from "./feature"; -import { BackupDecryptor, CryptoBackend } from "./common-crypto/CryptoBackend"; -import { RUST_SDK_STORE_PREFIX } from "./rust-crypto/constants"; -import { BootstrapCrossSigningOpts, CrossSigningKeyInfo, CryptoApi, ImportRoomKeysOpts } from "./crypto-api"; -import { DeviceInfoMap } from "./crypto/DeviceList"; +} from "./models/thread.ts"; +import { M_BEACON_INFO, MBeaconInfoEventContent } from "./@types/beacon.ts"; +import { NamespacedValue, UnstableValue } from "./NamespacedValue.ts"; +import { ToDeviceMessageQueue } from "./ToDeviceMessageQueue.ts"; +import { ToDeviceBatch } from "./models/ToDeviceMessage.ts"; +import { IgnoredInvites } from "./models/invites-ignorer.ts"; +import { UIARequest, UIAResponse } from "./@types/uia.ts"; +import { LocalNotificationSettings } from "./@types/local_notifications.ts"; +import { buildFeatureSupportMap, Feature, ServerSupport } from "./feature.ts"; +import { BackupDecryptor, CryptoBackend } from "./common-crypto/CryptoBackend.ts"; +import { RUST_SDK_STORE_PREFIX } from "./rust-crypto/constants.ts"; +import { BootstrapCrossSigningOpts, CrossSigningKeyInfo, CryptoApi, ImportRoomKeysOpts } from "./crypto-api/index.ts"; +import { DeviceInfoMap } from "./crypto/DeviceList.ts"; import { AddSecretStorageKeyOpts, SecretStorageKeyDescription, ServerSideSecretStorage, ServerSideSecretStorageImpl, -} from "./secret-storage"; -import { RegisterRequest, RegisterResponse } from "./@types/registration"; -import { MatrixRTCSessionManager } from "./matrixrtc/MatrixRTCSessionManager"; -import { getRelationsThreadFilter } from "./thread-utils"; -import { KnownMembership, Membership } from "./@types/membership"; -import { RoomMessageEventContent, StickerEventContent } from "./@types/events"; -import { ImageInfo } from "./@types/media"; +} from "./secret-storage.ts"; +import { RegisterRequest, RegisterResponse } from "./@types/registration.ts"; +import { MatrixRTCSessionManager } from "./matrixrtc/MatrixRTCSessionManager.ts"; +import { getRelationsThreadFilter } from "./thread-utils.ts"; +import { KnownMembership, Membership } from "./@types/membership.ts"; +import { RoomMessageEventContent, StickerEventContent } from "./@types/events.ts"; +import { ImageInfo } from "./@types/media.ts"; +import { Capabilities, ServerCapabilities } from "./serverCapabilities.ts"; +import { sha256 } from "./digest.ts"; export type Store = IStore; @@ -233,7 +246,6 @@ export type ResetTimelineCallback = (roomId: string) => boolean; const SCROLLBACK_DELAY_MS = 3000; export const CRYPTO_ENABLED: boolean = isCryptoAvailable(); -const CAPABILITIES_CACHE_MS = 21600000; // 6 hours - an arbitrary value const TURN_CHECK_INTERVAL = 10 * 60 * 1000; // poll for turn credentials every 10 minutes export const UNSTABLE_MSC3852_LAST_SEEN_UA = new UnstableValue( @@ -324,10 +336,13 @@ export interface ICreateClientOpts { localTimeoutMs?: number; /** - * Set to true to use - * Authorization header instead of query param to send the access token to the server. + * Set to false to send the access token to the server via a query parameter rather + * than the Authorization HTTP header. + * + * Note that as of v1.11 of the Matrix spec, sending the access token via a query + * is deprecated. * - * Default false. + * Default true. */ useAuthorizationHeader?: boolean; @@ -518,26 +533,6 @@ export interface IStartClientOpts { export interface IStoredClientOpts extends IStartClientOpts {} -export enum RoomVersionStability { - Stable = "stable", - Unstable = "unstable", -} - -export interface IRoomVersionsCapability { - default: string; - available: Record; -} - -export interface ICapability { - enabled: boolean; -} - -export interface IChangePasswordCapability extends ICapability {} - -export interface IThreadsCapability extends ICapability {} - -export interface IGetLoginTokenCapability extends ICapability {} - export const GET_LOGIN_TOKEN_CAPABILITY = new NamespacedValue( "m.get_login_token", "org.matrix.msc3882.get_login_token", @@ -547,18 +542,7 @@ export const UNSTABLE_MSC2666_SHARED_ROOMS = "uk.half-shot.msc2666"; export const UNSTABLE_MSC2666_MUTUAL_ROOMS = "uk.half-shot.msc2666.mutual_rooms"; export const UNSTABLE_MSC2666_QUERY_MUTUAL_ROOMS = "uk.half-shot.msc2666.query_mutual_rooms"; -/** - * A representation of the capabilities advertised by a homeserver as defined by - * [Capabilities negotiation](https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv3capabilities). - */ -export interface Capabilities { - [key: string]: any; - "m.change_password"?: IChangePasswordCapability; - "m.room_versions"?: IRoomVersionsCapability; - "io.element.thread"?: IThreadsCapability; - "m.get_login_token"?: IGetLoginTokenCapability; - "org.matrix.msc3882.get_login_token"?: IGetLoginTokenCapability; -} +export const UNSTABLE_MSC4140_DELAYED_EVENTS = "org.matrix.msc4140"; enum CrossSigningKeyType { MasterKey = "master_key", @@ -1108,7 +1092,7 @@ export type ClientEventHandlerMap = { * }); * ``` */ - [ClientEvent.Sync]: (state: SyncState, lastState: SyncState | null, data?: ISyncStateData) => void; + [ClientEvent.Sync]: (state: SyncState, prevState: SyncState | null, data?: ISyncStateData) => void; /** * Fires whenever the SDK receives a new event. *

@@ -1293,10 +1277,6 @@ export class MatrixClient extends TypedEventEmitter; - public cachedCapabilities?: { - capabilities: Capabilities; - expiration: number; - }; protected clientWellKnown?: IClientWellKnown; protected clientWellKnownPromise?: Promise; protected turnServers: ITurnServer[] = []; @@ -1325,6 +1305,8 @@ export class MatrixClient extends TypedEventEmitter { - const now = new Date().getTime(); - - if (this.cachedCapabilities && !fresh) { - if (now < this.cachedCapabilities.expiration) { - this.logger.debug("Returning cached capabilities"); - return Promise.resolve(this.cachedCapabilities.capabilities); - } - } - - type Response = { - capabilities?: Capabilities; - }; - return this.http - .authedRequest(Method.Get, "/capabilities") - .catch((e: Error): Response => { - // We swallow errors because we need a default object anyhow - this.logger.error(e); - return {}; - }) - .then((r = {}) => { - const capabilities = r["capabilities"] || {}; - - // If the capabilities missed the cache, cache it for a shorter amount - // of time to try and refresh them later. - const cacheMs = Object.keys(capabilities).length ? CAPABILITIES_CACHE_MS : 60000 + Math.random() * 5000; + public async getCapabilities(): Promise { + const caps = this.serverCapabilitiesService.getCachedCapabilities(); + if (caps) return caps; + return this.serverCapabilitiesService.fetchCapabilities(); + } - this.cachedCapabilities = { - capabilities, - expiration: now + cacheMs, - }; + /** + * Gets the cached capabilities of the homeserver. If none have been fetched yet, + * return undefined. + * + * @returns The capabilities of the homeserver + */ + public getCachedCapabilities(): Capabilities | undefined { + return this.serverCapabilitiesService.getCachedCapabilities(); + } - this.logger.debug("Caching capabilities: ", capabilities); - return capabilities; - }); + /** + * Fetches the latest capabilities from the homeserver, ignoring any cached + * versions. The newly returned version is cached. + * + * @returns A promise which resolves to the capabilities of the homeserver + */ + public fetchCapabilities(): Promise { + return this.serverCapabilitiesService.fetchCapabilities(); } /** @@ -2274,9 +2249,7 @@ export class MatrixClient extends TypedEventEmitter(Method.Post, url); } - const queryString: Record = {}; + let queryParams: QueryDict = {}; if (opts.viaServers) { - queryString["server_name"] = opts.viaServers; + queryParams.server_name = opts.viaServers; + queryParams.via = opts.viaServers; + if (this.canSupport.get(Feature.MigrateServerNameToVia) === ServerSupport.Unstable) { + queryParams = replaceParam("via", "org.matrix.msc4156.via", queryParams); + } } const data: IJoinRequestBody = {}; @@ -4331,7 +4308,7 @@ export class MatrixClient extends TypedEventEmitter(Method.Post, path, queryString, data); + const res = await this.http.authedRequest<{ room_id: string }>(Method.Post, path, queryParams, data); const roomId = res.room_id; // In case we were originally given an alias, check the room cache again @@ -4364,9 +4341,13 @@ export class MatrixClient extends TypedEventEmitter = {}; + let queryParams: QueryDict = {}; if (opts.viaServers) { queryParams.server_name = opts.viaServers; + queryParams.via = opts.viaServers; + if (this.canSupport.get(Feature.MigrateServerNameToVia) === ServerSupport.Unstable) { + queryParams = replaceParam("via", "org.matrix.msc4156.via", queryParams); + } } const body: Record = {}; @@ -4606,12 +4587,19 @@ export class MatrixClient extends TypedEventEmitter { @@ -4629,8 +4617,6 @@ export class MatrixClient extends TypedEventEmitter, txnId?: string, - ): Promise { + ): Promise; + /** + * Sends a delayed event (MSC4140). + * @param eventObject - An object with the partial structure of an event, to which event_id, user_id, room_id and origin_server_ts will be added. + * @param delayOpts - Properties of the delay for this event. + * @param txnId - Optional. + * @returns Promise which resolves: to an empty object `{}` + * @returns Rejects: with an error response. + */ + private sendCompleteEvent( + roomId: string, + threadId: string | null, + eventObject: Partial, + delayOpts: SendDelayedEventRequestOpts, + txnId?: string, + ): Promise; + private sendCompleteEvent( + roomId: string, + threadId: string | null, + eventObject: Partial, + delayOptsOrTxnId?: SendDelayedEventRequestOpts | string, + txnIdOrVoid?: string, + ): Promise { + let delayOpts: SendDelayedEventRequestOpts | undefined; + let txnId: string | undefined; + if (typeof delayOptsOrTxnId === "string") { + txnId = delayOptsOrTxnId; + } else { + delayOpts = delayOptsOrTxnId; + txnId = txnIdOrVoid; + } + if (!txnId) { txnId = this.makeTxnId(); } @@ -4667,9 +4684,11 @@ export class MatrixClient extends TypedEventEmitter { + protected async encryptAndSendEvent(room: Room | null, event: MatrixEvent): Promise; + /** + * Simply sends a delayed event without encrypting it. + * TODO: Allow encrypted delayed events, and encrypt them properly + * @param delayOpts - Properties of the delay for this event. + * @returns returns a promise which resolves with the result of the delayed send request + */ + protected async encryptAndSendEvent( + room: Room | null, + event: MatrixEvent, + delayOpts: SendDelayedEventRequestOpts, + ): Promise; + protected async encryptAndSendEvent( + room: Room | null, + event: MatrixEvent, + delayOpts?: SendDelayedEventRequestOpts, + ): Promise { + if (delayOpts) { + return this.sendEventHttpRequest(event, delayOpts); + } + try { let cancelled: boolean; this.eventsBeingEncrypted.add(event.getId()!); @@ -4857,7 +4903,15 @@ export class MatrixClient extends TypedEventEmitter { + private sendEventHttpRequest(event: MatrixEvent): Promise; + private sendEventHttpRequest( + event: MatrixEvent, + delayOpts: SendDelayedEventRequestOpts, + ): Promise; + private sendEventHttpRequest( + event: MatrixEvent, + delayOpts?: SendDelayedEventRequestOpts, + ): Promise { let txnId = event.getTxnId(); if (!txnId) { txnId = this.makeTxnId(); @@ -4889,12 +4943,20 @@ export class MatrixClient extends TypedEventEmitter(Method.Put, path, undefined, event.getWireContent()) - .then((res) => { + const content = event.getWireContent(); + if (!delayOpts) { + return this.http.authedRequest(Method.Put, path, undefined, content).then((res) => { this.logger.debug(`Event sent to ${event.getRoomId()} with event id ${res.event_id}`); return res; }); + } else { + return this.http.authedRequest( + Method.Put, + path, + getUnstableDelayQueryOpts(delayOpts), + content, + ); + } } /** @@ -5224,6 +5286,101 @@ export class MatrixClient extends TypedEventEmitter( + roomId: string, + delayOpts: SendDelayedEventRequestOpts, + threadId: string | null, + eventType: K, + content: TimelineEvents[K], + txnId?: string, + ): Promise { + if (!(await this.doesServerSupportUnstableFeature(UNSTABLE_MSC4140_DELAYED_EVENTS))) { + throw Error("Server does not support the delayed events API"); + } + + this.addThreadRelationIfNeeded(content, threadId, roomId); + return this.sendCompleteEvent(roomId, threadId, { type: eventType, content }, delayOpts, txnId); + } + + /** + * Send a delayed state event. + * + * Note: This endpoint is unstable, and can throw an `Error`. + * Check progress on [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140) for more details. + */ + // eslint-disable-next-line + public async _unstable_sendDelayedStateEvent( + roomId: string, + delayOpts: SendDelayedEventRequestOpts, + eventType: K, + content: StateEvents[K], + stateKey = "", + opts: IRequestOpts = {}, + ): Promise { + if (!(await this.doesServerSupportUnstableFeature(UNSTABLE_MSC4140_DELAYED_EVENTS))) { + throw Error("Server does not support the delayed events API"); + } + + const pathParams = { + $roomId: roomId, + $eventType: eventType, + $stateKey: stateKey, + }; + let path = utils.encodeUri("/rooms/$roomId/state/$eventType", pathParams); + if (stateKey !== undefined) { + path = utils.encodeUri(path + "/$stateKey", pathParams); + } + return this.http.authedRequest(Method.Put, path, getUnstableDelayQueryOpts(delayOpts), content as Body, opts); + } + + /** + * Get all pending delayed events for the calling user. + * + * Note: This endpoint is unstable, and can throw an `Error`. + * Check progress on [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140) for more details. + */ + // eslint-disable-next-line + public async _unstable_getDelayedEvents(fromToken?: string): Promise { + if (!(await this.doesServerSupportUnstableFeature(UNSTABLE_MSC4140_DELAYED_EVENTS))) { + throw Error("Server does not support the delayed events API"); + } + + const queryDict = fromToken ? { from: fromToken } : undefined; + return await this.http.authedRequest(Method.Get, "/delayed_events", queryDict, undefined, { + prefix: `${ClientPrefix.Unstable}/${UNSTABLE_MSC4140_DELAYED_EVENTS}`, + }); + } + + /** + * Manage a delayed event associated with the given delay_id. + * + * Note: This endpoint is unstable, and can throw an `Error`. + * Check progress on [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140) for more details. + */ + // eslint-disable-next-line + public async _unstable_updateDelayedEvent(delayId: string, action: UpdateDelayedEventAction): Promise<{}> { + if (!(await this.doesServerSupportUnstableFeature(UNSTABLE_MSC4140_DELAYED_EVENTS))) { + throw Error("Server does not support the delayed events API"); + } + + const path = utils.encodeUri("/delayed_events/$delayId", { + $delayId: delayId, + }); + const data = { + action, + }; + return await this.http.authedRequest(Method.Post, path, undefined, data, { + prefix: `${ClientPrefix.Unstable}/${UNSTABLE_MSC4140_DELAYED_EVENTS}`, + }); + } + /** * Send a receipt. * @param event - The event being acknowledged @@ -5437,10 +5594,15 @@ export class MatrixClient extends TypedEventEmitter([room.roomId]); // Work backwards from newer to older rooms let predecessorRoomId = room.findPredecessor(msc3946ProcessDynamicPredecessor)?.roomId; while (predecessorRoomId !== null) { + if (predecessorRoomId) { + if (seenRoomIDs.has(predecessorRoomId)) break; + seenRoomIDs.add(predecessorRoomId); + } const predecessorRoom = this.getRoom(predecessorRoomId); if (predecessorRoom === null) { break; @@ -6639,13 +6801,14 @@ export class MatrixClient extends TypedEventEmitter { + public peekInRoom(roomId: string, limit: number = 20): Promise { this.peekSync?.stopPeeking(); this.peekSync = new SyncApi(this, this.clientOpts, this.buildSyncApiOptions()); - return this.peekSync.peek(roomId); + return this.peekSync.peek(roomId, limit); } /** @@ -7109,7 +7272,7 @@ export class MatrixClient extends TypedEventEmitter { + protected async fetchClientWellKnown(): Promise { // `getRawClientConfig` does not throw or reject on network errors, instead // it absorbs errors and returns `{}`. this.clientWellKnownPromise = AutoDiscovery.getRawClientConfig(this.getDomain() ?? undefined); @@ -9335,20 +9498,19 @@ export class MatrixClient extends TypedEventEmitter { - const addr = p[0].toLowerCase(); // lowercase to get consistent hashes - const med = p[1].toLowerCase(); - const hashed = olmutil - .sha256(`${addr} ${med} ${params["pepper"]}`) - .replace(/\+/g, "-") - .replace(/\//g, "_"); // URL-safe base64 - // Map the hash to a known (case-sensitive) address. We use the case - // sensitive version because the caller might be expecting that. - localMapping[hashed] = p[0]; - return hashed; - }); + params["addresses"] = await Promise.all( + addressPairs.map(async (p) => { + const addr = p[0].toLowerCase(); // lowercase to get consistent hashes + const med = p[1].toLowerCase(); + const hashBuffer = await sha256(`${addr} ${med} ${params["pepper"]}`); + const hashed = encodeUnpaddedBase64Url(hashBuffer); + + // Map the hash to a known (case-sensitive) address. We use the case + // sensitive version because the caller might be expecting that. + localMapping[hashed] = p[0]; + return hashed; + }), + ); params["algorithm"] = "sha256"; } else if (hashes["algorithms"].includes("none")) { params["addresses"] = addressPairs.map((p) => { @@ -9925,6 +10087,12 @@ export class MatrixClient extends TypedEventEmitter [`${UNSTABLE_MSC4140_DELAYED_EVENTS}.${k}`, v]), + ); +} + /** * recalculates an accurate notifications count on event decryption. * Servers do not have enough knowledge about encrypted events to calculate an diff --git a/src/common-crypto/CryptoBackend.ts b/src/common-crypto/CryptoBackend.ts index 7a36dc560e9..bbd6e5ec682 100644 --- a/src/common-crypto/CryptoBackend.ts +++ b/src/common-crypto/CryptoBackend.ts @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type { IDeviceLists, IToDeviceEvent } from "../sync-accumulator"; -import { IClearEvent, MatrixEvent } from "../models/event"; -import { Room } from "../models/room"; -import { CryptoApi, DecryptionFailureCode, ImportRoomKeysOpts } from "../crypto-api"; -import { CrossSigningInfo, UserTrustLevel } from "../crypto/CrossSigning"; -import { IEncryptedEventInfo } from "../crypto/api"; -import { KeyBackupInfo, KeyBackupSession } from "../crypto-api/keybackup"; -import { IMegolmSessionData } from "../@types/crypto"; +import type { IDeviceLists, IToDeviceEvent } from "../sync-accumulator.ts"; +import { IClearEvent, MatrixEvent } from "../models/event.ts"; +import { Room } from "../models/room.ts"; +import { CryptoApi, DecryptionFailureCode, ImportRoomKeysOpts } from "../crypto-api/index.ts"; +import { CrossSigningInfo, UserTrustLevel } from "../crypto/CrossSigning.ts"; +import { IEncryptedEventInfo } from "../crypto/api.ts"; +import { KeyBackupInfo, KeyBackupSession } from "../crypto-api/keybackup.ts"; +import { IMegolmSessionData } from "../@types/crypto.ts"; /** * Common interface for the crypto implementations diff --git a/src/content-helpers.ts b/src/content-helpers.ts index 3f611e36901..ce8b373d93e 100644 --- a/src/content-helpers.ts +++ b/src/content-helpers.ts @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MBeaconEventContent, MBeaconInfoContent, MBeaconInfoEventContent } from "./@types/beacon"; -import { MsgType } from "./@types/event"; -import { M_TEXT, REFERENCE_RELATION } from "./@types/extensible_events"; -import { isProvided } from "./extensible_events_v1/utilities"; +import { MBeaconEventContent, MBeaconInfoContent, MBeaconInfoEventContent } from "./@types/beacon.ts"; +import { MsgType } from "./@types/event.ts"; +import { M_TEXT, REFERENCE_RELATION } from "./@types/extensible_events.ts"; +import { isProvided } from "./extensible_events_v1/utilities.ts"; import { M_ASSET, LocationAssetType, @@ -28,9 +28,9 @@ import { MLocationContent, MAssetContent, LegacyLocationEventContent, -} from "./@types/location"; -import { MRoomTopicEventContent, MTopicContent, M_TOPIC } from "./@types/topic"; -import { RoomMessageEventContent } from "./@types/events"; +} from "./@types/location.ts"; +import { MRoomTopicEventContent, MTopicContent, M_TOPIC } from "./@types/topic.ts"; +import { RoomMessageEventContent } from "./@types/events.ts"; /** * Generates the content for a HTML Message event diff --git a/src/content-repo.ts b/src/content-repo.ts index eaa119f97cd..b6174b6d8d9 100644 --- a/src/content-repo.ts +++ b/src/content-repo.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { encodeParams } from "./utils"; +import { encodeParams } from "./utils.ts"; /** * Get the HTTP URL for an MXC URI. @@ -62,7 +62,7 @@ export function getHttpUriForMxc( if (useAuthentication) { allowRedirects = true; // per docs (MSC3916 always expects redirects) - // Dev note: MSC3916 (as of writing) removes `allow_redirect` entirely, but + // Dev note: MSC3916 removes `allow_redirect` entirely, but // for explicitness we set it here. This makes it slightly more obvious to // callers, hopefully. } @@ -70,8 +70,7 @@ export function getHttpUriForMxc( let serverAndMediaId = mxc.slice(6); // strips mxc:// let prefix: string; if (useAuthentication) { - // TODO: Use stable once available (requires FCP on MSC3916). - prefix = "/_matrix/client/unstable/org.matrix.msc3916/media/download/"; + prefix = "/_matrix/client/v1/media/download/"; } else { prefix = "/_matrix/media/v3/download/"; } @@ -90,8 +89,7 @@ export function getHttpUriForMxc( // these are thumbnailing params so they probably want the // thumbnailing API... if (useAuthentication) { - // TODO: Use stable once available (requires FCP on MSC3916). - prefix = "/_matrix/client/unstable/org.matrix.msc3916/media/thumbnail/"; + prefix = "/_matrix/client/v1/media/thumbnail/"; } else { prefix = "/_matrix/media/v3/thumbnail/"; } diff --git a/src/crypto-api.ts b/src/crypto-api/index.ts similarity index 94% rename from src/crypto-api.ts rename to src/crypto-api/index.ts index 7dfdfbfcf08..6b9db3811dc 100644 --- a/src/crypto-api.ts +++ b/src/crypto-api/index.ts @@ -14,15 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type { IMegolmSessionData } from "./@types/crypto"; -import { Room } from "./models/room"; -import { DeviceMap } from "./models/device"; -import { UIAuthCallback } from "./interactive-auth"; -import { PassphraseInfo, SecretStorageCallbacks, SecretStorageKeyDescription } from "./secret-storage"; -import { VerificationRequest } from "./crypto-api/verification"; -import { BackupTrustInfo, KeyBackupCheck, KeyBackupInfo } from "./crypto-api/keybackup"; -import { ISignatures } from "./@types/signed"; -import { MatrixEvent } from "./models/event"; +import type { SecretsBundle } from "@matrix-org/matrix-sdk-crypto-wasm"; +import type { IMegolmSessionData } from "../@types/crypto.ts"; +import { Room } from "../models/room.ts"; +import { DeviceMap } from "../models/device.ts"; +import { UIAuthCallback } from "../interactive-auth.ts"; +import { PassphraseInfo, SecretStorageCallbacks, SecretStorageKeyDescription } from "../secret-storage.ts"; +import { VerificationRequest } from "./verification.ts"; +import { BackupTrustInfo, KeyBackupCheck, KeyBackupInfo } from "./keybackup.ts"; +import { ISignatures } from "../@types/signed.ts"; +import { MatrixEvent } from "../models/event.ts"; /** * Public interface to the cryptography parts of the js-sdk @@ -532,6 +533,23 @@ export interface CryptoApi { * to false. */ startDehydration(createNewKey?: boolean): Promise; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Import/export of secret keys + // + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Export secrets bundle for transmitting to another device as part of OIDC QR login + */ + exportSecretsBundle?(): Promise>>; + + /** + * Import secrets bundle transmitted from another device. + * @param secrets - The secrets bundle received from the other device + */ + importSecretsBundle?(secrets: Awaited>): Promise; } /** A reason code for a failure to decrypt an event. */ @@ -539,6 +557,12 @@ export enum DecryptionFailureCode { /** Message was encrypted with a Megolm session whose keys have not been shared with us. */ MEGOLM_UNKNOWN_INBOUND_SESSION_ID = "MEGOLM_UNKNOWN_INBOUND_SESSION_ID", + /** A special case of {@link MEGOLM_UNKNOWN_INBOUND_SESSION_ID}: the sender has told us it is withholding the key. */ + MEGOLM_KEY_WITHHELD = "MEGOLM_KEY_WITHHELD", + + /** A special case of {@link MEGOLM_KEY_WITHHELD}: the sender has told us it is withholding the key, because the current device is unverified. */ + MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE = "MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE", + /** Message was encrypted with a Megolm session which has been shared with us, but in a later ratchet state. */ OLM_UNKNOWN_MESSAGE_INDEX = "OLM_UNKNOWN_MESSAGE_INDEX", @@ -785,6 +809,8 @@ export interface CryptoCallbacks extends SecretStorageCallbacks { * @param key - private key to store */ cacheSecretStorageKey?: (keyId: string, keyInfo: SecretStorageKeyDescription, key: Uint8Array) => void; + + /** @deprecated: unused with the Rust crypto stack. */ onSecretRequested?: ( userId: string, deviceId: string, @@ -792,10 +818,13 @@ export interface CryptoCallbacks extends SecretStorageCallbacks { secretName: string, deviceTrust: DeviceVerificationStatus, ) => Promise; + + /** @deprecated: unused with the Rust crypto stack. */ getDehydrationKey?: ( keyInfo: SecretStorageKeyDescription, checkFunc: (key: Uint8Array) => void, ) => Promise; + getBackupKey?: () => Promise; } @@ -830,9 +859,14 @@ export interface CreateSecretStorageOpts { setupNewSecretStorage?: boolean; /** - * Function called to get the user's - * current key backup passphrase. Should return a promise that resolves with a Uint8Array + * Function called to get the user's current key backup passphrase. + * + * Should return a promise that resolves with a Uint8Array * containing the key, or rejects if the key cannot be obtained. + * + * Only used when the client has existing key backup, but no secret storage. + * + * @deprecated Not used by the Rust crypto stack. */ getKeyBackupPassphrase?: () => Promise; } @@ -931,5 +965,5 @@ export interface OwnDeviceKeys { curve25519: string; } -export * from "./crypto-api/verification"; -export * from "./crypto-api/keybackup"; +export * from "./verification.ts"; +export * from "./keybackup.ts"; diff --git a/src/crypto-api/keybackup.ts b/src/crypto-api/keybackup.ts index 71c47d6834f..3209de6c320 100644 --- a/src/crypto-api/keybackup.ts +++ b/src/crypto-api/keybackup.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ISigned } from "../@types/signed"; -import { IEncryptedPayload } from "../crypto/aes"; +import { ISigned } from "../@types/signed.ts"; +import { IEncryptedPayload } from "../crypto/aes.ts"; export interface Curve25519AuthData { public_key: string; diff --git a/src/crypto-api/verification.ts b/src/crypto-api/verification.ts index dd42dc35c9b..daa7bdbceed 100644 --- a/src/crypto-api/verification.ts +++ b/src/crypto-api/verification.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixEvent } from "../models/event"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; +import { MatrixEvent } from "../models/event.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; /** * An incoming, or outgoing, request to verify a user or a device via cross-signing. diff --git a/src/crypto/CrossSigning.ts b/src/crypto/CrossSigning.ts index 95d20da052e..a4caf1c53a1 100644 --- a/src/crypto/CrossSigning.ts +++ b/src/crypto/CrossSigning.ts @@ -19,19 +19,23 @@ limitations under the License. */ import type { PkSigning } from "@matrix-org/olm"; -import { IObject, pkSign, pkVerify } from "./olmlib"; -import { logger } from "../logger"; -import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store"; -import { decryptAES, encryptAES } from "./aes"; -import { DeviceInfo } from "./deviceinfo"; -import { ISignedKey, MatrixClient } from "../client"; -import { OlmDevice } from "./OlmDevice"; -import { ICryptoCallbacks } from "."; -import { ISignatures } from "../@types/signed"; -import { CryptoStore, SecretStorePrivateKeys } from "./store/base"; -import { ServerSideSecretStorage, SecretStorageKeyDescription } from "../secret-storage"; -import { CrossSigningKeyInfo, DeviceVerificationStatus, UserVerificationStatus as UserTrustLevel } from "../crypto-api"; -import { decodeBase64, encodeBase64 } from "../base64"; +import { IObject, pkSign, pkVerify } from "./olmlib.ts"; +import { logger } from "../logger.ts"; +import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store.ts"; +import { decryptAES, encryptAES } from "./aes.ts"; +import { DeviceInfo } from "./deviceinfo.ts"; +import { ISignedKey, MatrixClient } from "../client.ts"; +import { OlmDevice } from "./OlmDevice.ts"; +import { ICryptoCallbacks } from "./index.ts"; +import { ISignatures } from "../@types/signed.ts"; +import { CryptoStore, SecretStorePrivateKeys } from "./store/base.ts"; +import { ServerSideSecretStorage, SecretStorageKeyDescription } from "../secret-storage.ts"; +import { + CrossSigningKeyInfo, + DeviceVerificationStatus, + UserVerificationStatus as UserTrustLevel, +} from "../crypto-api/index.ts"; +import { decodeBase64, encodeBase64 } from "../base64.ts"; // backwards-compatibility re-exports export { UserTrustLevel }; diff --git a/src/crypto/DeviceList.ts b/src/crypto/DeviceList.ts index 8ad3831893a..320ea6a2653 100644 --- a/src/crypto/DeviceList.ts +++ b/src/crypto/DeviceList.ts @@ -18,17 +18,17 @@ limitations under the License. * Manages the list of other users' devices */ -import { logger } from "../logger"; -import { DeviceInfo, IDevice } from "./deviceinfo"; -import { CrossSigningInfo, ICrossSigningInfo } from "./CrossSigning"; -import * as olmlib from "./olmlib"; -import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store"; -import { chunkPromises, defer, IDeferred, sleep } from "../utils"; -import { DeviceKeys, IDownloadKeyResult, Keys, MatrixClient, SigningKeys } from "../client"; -import { OlmDevice } from "./OlmDevice"; -import { CryptoStore } from "./store/base"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { CryptoEvent, CryptoEventHandlerMap } from "./index"; +import { logger } from "../logger.ts"; +import { DeviceInfo, IDevice } from "./deviceinfo.ts"; +import { CrossSigningInfo, ICrossSigningInfo } from "./CrossSigning.ts"; +import * as olmlib from "./olmlib.ts"; +import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store.ts"; +import { chunkPromises, defer, IDeferred, sleep } from "../utils.ts"; +import { DeviceKeys, IDownloadKeyResult, Keys, MatrixClient, SigningKeys } from "../client.ts"; +import { OlmDevice } from "./OlmDevice.ts"; +import { CryptoStore } from "./store/base.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { CryptoEvent, CryptoEventHandlerMap } from "./index.ts"; /* State transition diagram for DeviceList.deviceTrackingStatus * diff --git a/src/crypto/EncryptionSetup.ts b/src/crypto/EncryptionSetup.ts index b7015b5a0ba..dab5d560693 100644 --- a/src/crypto/EncryptionSetup.ts +++ b/src/crypto/EncryptionSetup.ts @@ -14,17 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../logger"; -import { MatrixEvent } from "../models/event"; -import { createCryptoStoreCacheCallbacks, ICacheCallbacks } from "./CrossSigning"; -import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store"; -import { Method, ClientPrefix } from "../http-api"; -import { Crypto, ICryptoCallbacks } from "./index"; -import { ClientEvent, ClientEventHandlerMap, CrossSigningKeys, ISignedKey, KeySignatures } from "../client"; -import { IKeyBackupInfo } from "./keybackup"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { AccountDataClient, SecretStorageKeyDescription } from "../secret-storage"; -import { BootstrapCrossSigningOpts, CrossSigningKeyInfo } from "../crypto-api"; +import { logger } from "../logger.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { createCryptoStoreCacheCallbacks, ICacheCallbacks } from "./CrossSigning.ts"; +import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store.ts"; +import { Method, ClientPrefix } from "../http-api/index.ts"; +import { Crypto, ICryptoCallbacks } from "./index.ts"; +import { ClientEvent, ClientEventHandlerMap, CrossSigningKeys, ISignedKey, KeySignatures } from "../client.ts"; +import { IKeyBackupInfo } from "./keybackup.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { AccountDataClient, SecretStorageKeyDescription } from "../secret-storage.ts"; +import { BootstrapCrossSigningOpts, CrossSigningKeyInfo } from "../crypto-api/index.ts"; interface ICrossSigningKeys { authUpload: BootstrapCrossSigningOpts["authUploadDeviceSigningKeys"]; diff --git a/src/crypto/OlmDevice.ts b/src/crypto/OlmDevice.ts index 6e645b72b97..1006bf0de47 100644 --- a/src/crypto/OlmDevice.ts +++ b/src/crypto/OlmDevice.ts @@ -16,14 +16,14 @@ limitations under the License. import { Account, InboundGroupSession, OutboundGroupSession, Session, Utility } from "@matrix-org/olm"; -import { logger, Logger } from "../logger"; -import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store"; -import { CryptoStore, IProblem, ISessionInfo, IWithheld } from "./store/base"; -import { IOlmDevice, IOutboundGroupSessionKey } from "./algorithms/megolm"; -import { IMegolmSessionData, OlmGroupSessionExtraData } from "../@types/crypto"; -import { IMessage } from "./algorithms/olm"; -import { DecryptionFailureCode } from "../crypto-api"; -import { DecryptionError } from "../common-crypto/CryptoBackend"; +import { logger, Logger } from "../logger.ts"; +import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store.ts"; +import { CryptoStore, IProblem, ISessionInfo, IWithheld } from "./store/base.ts"; +import { IOlmDevice, IOutboundGroupSessionKey } from "./algorithms/megolm.ts"; +import { IMegolmSessionData, OlmGroupSessionExtraData } from "../@types/crypto.ts"; +import { IMessage } from "./algorithms/olm.ts"; +import { DecryptionFailureCode } from "../crypto-api/index.ts"; +import { DecryptionError } from "../common-crypto/CryptoBackend.ts"; // The maximum size of an event is 65K, and we base64 the content, so this is a // reasonable approximation to the biggest plaintext we can encrypt. @@ -1221,13 +1221,13 @@ export class OlmDevice { this.getInboundGroupSession(roomId, senderKey, sessionId, txn, (session, sessionData, withheld) => { if (session === null || sessionData === null) { if (withheld) { - error = new DecryptionError( - DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID, - calculateWithheldMessage(withheld), - { - session: senderKey + "|" + sessionId, - }, - ); + const failureCode = + withheld.code === "m.unverified" + ? DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE + : DecryptionFailureCode.MEGOLM_KEY_WITHHELD; + error = new DecryptionError(failureCode, calculateWithheldMessage(withheld), { + session: senderKey + "|" + sessionId, + }); } result = null; return; @@ -1237,13 +1237,13 @@ export class OlmDevice { res = session.decrypt(body); } catch (e) { if ((e)?.message === "OLM.UNKNOWN_MESSAGE_INDEX" && withheld) { - error = new DecryptionError( - DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID, - calculateWithheldMessage(withheld), - { - session: senderKey + "|" + sessionId, - }, - ); + const failureCode = + withheld.code === "m.unverified" + ? DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE + : DecryptionFailureCode.MEGOLM_KEY_WITHHELD; + error = new DecryptionError(failureCode, calculateWithheldMessage(withheld), { + session: senderKey + "|" + sessionId, + }); } else { error = e; } diff --git a/src/crypto/OutgoingRoomKeyRequestManager.ts b/src/crypto/OutgoingRoomKeyRequestManager.ts index 4628b3e8dd9..4f3cf2534ae 100644 --- a/src/crypto/OutgoingRoomKeyRequestManager.ts +++ b/src/crypto/OutgoingRoomKeyRequestManager.ts @@ -16,12 +16,12 @@ limitations under the License. import { v4 as uuidv4 } from "uuid"; -import { logger } from "../logger"; -import { MatrixClient } from "../client"; -import { IRoomKeyRequestBody, IRoomKeyRequestRecipient } from "./index"; -import { CryptoStore, OutgoingRoomKeyRequest } from "./store/base"; -import { EventType, ToDeviceMessageId } from "../@types/event"; -import { MapWithDefault } from "../utils"; +import { logger } from "../logger.ts"; +import { MatrixClient } from "../client.ts"; +import { IRoomKeyRequestBody, IRoomKeyRequestRecipient } from "./index.ts"; +import { CryptoStore, OutgoingRoomKeyRequest } from "./store/base.ts"; +import { EventType, ToDeviceMessageId } from "../@types/event.ts"; +import { MapWithDefault } from "../utils.ts"; /** * Internal module. Management of outgoing room key requests. diff --git a/src/crypto/RoomList.ts b/src/crypto/RoomList.ts index b100bd30218..75573d64022 100644 --- a/src/crypto/RoomList.ts +++ b/src/crypto/RoomList.ts @@ -18,8 +18,8 @@ limitations under the License. * Manages the list of encrypted rooms */ -import { CryptoStore } from "./store/base"; -import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store"; +import { CryptoStore } from "./store/base.ts"; +import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store.ts"; /* eslint-disable camelcase */ export interface IRoomEncryption { diff --git a/src/crypto/SecretSharing.ts b/src/crypto/SecretSharing.ts index 5083a8c243b..11def73715e 100644 --- a/src/crypto/SecretSharing.ts +++ b/src/crypto/SecretSharing.ts @@ -15,13 +15,13 @@ limitations under the License. */ import { v4 as uuidv4 } from "uuid"; -import { MatrixClient } from "../client"; -import { ICryptoCallbacks, IEncryptedContent } from "./index"; -import { defer, IDeferred } from "../utils"; -import { ToDeviceMessageId } from "../@types/event"; -import { logger } from "../logger"; -import { MatrixEvent } from "../models/event"; -import * as olmlib from "./olmlib"; +import { MatrixClient } from "../client.ts"; +import { ICryptoCallbacks, IEncryptedContent } from "./index.ts"; +import { defer, IDeferred } from "../utils.ts"; +import { ToDeviceMessageId } from "../@types/event.ts"; +import { logger } from "../logger.ts"; +import { MatrixEvent } from "../models/event.ts"; +import * as olmlib from "./olmlib.ts"; export interface ISecretRequest { requestId: string; diff --git a/src/crypto/SecretStorage.ts b/src/crypto/SecretStorage.ts index 452d1fde99f..6bd653dd0c0 100644 --- a/src/crypto/SecretStorage.ts +++ b/src/crypto/SecretStorage.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ICryptoCallbacks } from "."; -import { MatrixEvent } from "../models/event"; -import { MatrixClient } from "../client"; +import { ICryptoCallbacks } from "./index.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { MatrixClient } from "../client.ts"; import { SecretStorageKeyDescription, SecretStorageKeyTuple, @@ -25,8 +25,8 @@ import { AccountDataClient, ServerSideSecretStorage, ServerSideSecretStorageImpl, -} from "../secret-storage"; -import { ISecretRequest, SecretSharing } from "./SecretSharing"; +} from "../secret-storage.ts"; +import { ISecretRequest, SecretSharing } from "./SecretSharing.ts"; /* re-exports for backwards compatibility */ export type { @@ -34,9 +34,9 @@ export type { SecretStorageKeyTuple, SecretStorageKeyObject, SECRET_STORAGE_ALGORITHM_V1_AES, -} from "../secret-storage"; +} from "../secret-storage.ts"; -export type { ISecretRequest } from "./SecretSharing"; +export type { ISecretRequest } from "./SecretSharing.ts"; /** * Implements Secure Secret Storage and Sharing (MSC1946) diff --git a/src/crypto/aes.ts b/src/crypto/aes.ts index 389e2ff6ac3..6c6779d0611 100644 --- a/src/crypto/aes.ts +++ b/src/crypto/aes.ts @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { decodeBase64, encodeBase64 } from "../base64"; -import { subtleCrypto, crypto, TextEncoder } from "./crypto"; +import { decodeBase64, encodeBase64 } from "../base64.ts"; // salt for HKDF, with 8 bytes of zeros const zeroSalt = new Uint8Array(8); @@ -49,7 +48,7 @@ export async function encryptAES( iv = decodeBase64(ivStr); } else { iv = new Uint8Array(16); - crypto.getRandomValues(iv); + globalThis.crypto.getRandomValues(iv); // clear bit 63 of the IV to stop us hitting the 64-bit counter boundary // (which would mean we wouldn't be able to decrypt on Android). The loss @@ -60,7 +59,7 @@ export async function encryptAES( const [aesKey, hmacKey] = await deriveKeys(key, name); const encodedData = new TextEncoder().encode(data); - const ciphertext = await subtleCrypto.encrypt( + const ciphertext = await globalThis.crypto.subtle.encrypt( { name: "AES-CTR", counter: iv, @@ -70,7 +69,7 @@ export async function encryptAES( encodedData, ); - const hmac = await subtleCrypto.sign({ name: "HMAC" }, hmacKey, ciphertext); + const hmac = await globalThis.crypto.subtle.sign({ name: "HMAC" }, hmacKey, ciphertext); return { iv: encodeBase64(iv), @@ -91,11 +90,11 @@ export async function decryptAES(data: IEncryptedPayload, key: Uint8Array, name: const ciphertext = decodeBase64(data.ciphertext); - if (!(await subtleCrypto.verify({ name: "HMAC" }, hmacKey, decodeBase64(data.mac), ciphertext))) { + if (!(await globalThis.crypto.subtle.verify({ name: "HMAC" }, hmacKey, decodeBase64(data.mac), ciphertext))) { throw new Error(`Error decrypting secret ${name}: bad MAC`); } - const plaintext = await subtleCrypto.decrypt( + const plaintext = await globalThis.crypto.subtle.decrypt( { name: "AES-CTR", counter: decodeBase64(data.iv), @@ -109,8 +108,8 @@ export async function decryptAES(data: IEncryptedPayload, key: Uint8Array, name: } async function deriveKeys(key: Uint8Array, name: string): Promise<[CryptoKey, CryptoKey]> { - const hkdfkey = await subtleCrypto.importKey("raw", key, { name: "HKDF" }, false, ["deriveBits"]); - const keybits = await subtleCrypto.deriveBits( + const hkdfkey = await globalThis.crypto.subtle.importKey("raw", key, { name: "HKDF" }, false, ["deriveBits"]); + const keybits = await globalThis.crypto.subtle.deriveBits( { name: "HKDF", salt: zeroSalt, @@ -126,9 +125,12 @@ async function deriveKeys(key: Uint8Array, name: string): Promise<[CryptoKey, Cr const aesKey = keybits.slice(0, 32); const hmacKey = keybits.slice(32); - const aesProm = subtleCrypto.importKey("raw", aesKey, { name: "AES-CTR" }, false, ["encrypt", "decrypt"]); + const aesProm = globalThis.crypto.subtle.importKey("raw", aesKey, { name: "AES-CTR" }, false, [ + "encrypt", + "decrypt", + ]); - const hmacProm = subtleCrypto.importKey( + const hmacProm = globalThis.crypto.subtle.importKey( "raw", hmacKey, { diff --git a/src/crypto/algorithms/base.ts b/src/crypto/algorithms/base.ts index 37dae34bd77..9b038426147 100644 --- a/src/crypto/algorithms/base.ts +++ b/src/crypto/algorithms/base.ts @@ -18,15 +18,15 @@ limitations under the License. * Internal module. Defines the base classes of the encryption implementations */ -import type { IMegolmSessionData } from "../../@types/crypto"; -import { MatrixClient } from "../../client"; -import { Room } from "../../models/room"; -import { OlmDevice } from "../OlmDevice"; -import { IContent, MatrixEvent, RoomMember } from "../../matrix"; -import { Crypto, IEncryptedContent, IEventDecryptionResult, IncomingRoomKeyRequest } from ".."; -import { DeviceInfo } from "../deviceinfo"; -import { IRoomEncryption } from "../RoomList"; -import { DeviceInfoMap } from "../DeviceList"; +import type { IMegolmSessionData } from "../../@types/crypto.ts"; +import { MatrixClient } from "../../client.ts"; +import { Room } from "../../models/room.ts"; +import { OlmDevice } from "../OlmDevice.ts"; +import { IContent, MatrixEvent, RoomMember } from "../../matrix.ts"; +import { Crypto, IEncryptedContent, IEventDecryptionResult, IncomingRoomKeyRequest } from "../index.ts"; +import { DeviceInfo } from "../deviceinfo.ts"; +import { IRoomEncryption } from "../RoomList.ts"; +import { DeviceInfoMap } from "../DeviceList.ts"; /** * Map of registered encryption algorithm classes. A map from string to {@link EncryptionAlgorithm} class @@ -66,7 +66,6 @@ export abstract class EncryptionAlgorithm { protected readonly crypto: Crypto; protected readonly olmDevice: OlmDevice; protected readonly baseApis: MatrixClient; - protected readonly roomId?: string; /** * @param params - parameters @@ -77,7 +76,6 @@ export abstract class EncryptionAlgorithm { this.crypto = params.crypto; this.olmDevice = params.olmDevice; this.baseApis = params.baseApis; - this.roomId = params.roomId; } /** @@ -127,14 +125,12 @@ export abstract class DecryptionAlgorithm { protected readonly crypto: Crypto; protected readonly olmDevice: OlmDevice; protected readonly baseApis: MatrixClient; - protected readonly roomId?: string; public constructor(params: DecryptionClassParams) { this.userId = params.userId; this.crypto = params.crypto; this.olmDevice = params.olmDevice; this.baseApis = params.baseApis; - this.roomId = params.roomId; } /** @@ -237,4 +233,4 @@ export function registerAlgorithm

( } /* Re-export for backwards compatibility. Deprecated: this is an internal class. */ -export { DecryptionError } from "../../common-crypto/CryptoBackend"; +export { DecryptionError } from "../../common-crypto/CryptoBackend.ts"; diff --git a/src/crypto/algorithms/index.ts b/src/crypto/algorithms/index.ts index b3c5b0ede84..947c6e0ea2b 100644 --- a/src/crypto/algorithms/index.ts +++ b/src/crypto/algorithms/index.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import "./olm"; -import "./megolm"; +import "./olm.ts"; +import "./megolm.ts"; -export * from "./base"; +export * from "./base.ts"; diff --git a/src/crypto/algorithms/megolm.ts b/src/crypto/algorithms/megolm.ts index 5fa4a1b757e..9fde8e5bc9c 100644 --- a/src/crypto/algorithms/megolm.ts +++ b/src/crypto/algorithms/megolm.ts @@ -20,9 +20,9 @@ limitations under the License. import { v4 as uuidv4 } from "uuid"; -import type { IEventDecryptionResult, IMegolmSessionData } from "../../@types/crypto"; -import { logger, Logger } from "../../logger"; -import * as olmlib from "../olmlib"; +import type { IEventDecryptionResult, IMegolmSessionData } from "../../@types/crypto.ts"; +import { logger, Logger } from "../../logger.ts"; +import * as olmlib from "../olmlib.ts"; import { DecryptionAlgorithm, DecryptionClassParams, @@ -30,22 +30,22 @@ import { IParams, registerAlgorithm, UnknownDeviceError, -} from "./base"; -import { IDecryptedGroupMessage, WITHHELD_MESSAGES } from "../OlmDevice"; -import { Room } from "../../models/room"; -import { DeviceInfo } from "../deviceinfo"; -import { IOlmSessionResult } from "../olmlib"; -import { DeviceInfoMap } from "../DeviceList"; -import { IContent, MatrixEvent } from "../../models/event"; -import { EventType, MsgType, ToDeviceMessageId } from "../../@types/event"; -import { IMegolmEncryptedContent, IncomingRoomKeyRequest, IEncryptedContent } from "../index"; -import { RoomKeyRequestState } from "../OutgoingRoomKeyRequestManager"; -import { OlmGroupSessionExtraData } from "../../@types/crypto"; -import { MatrixError } from "../../http-api"; -import { immediate, MapWithDefault } from "../../utils"; -import { KnownMembership } from "../../@types/membership"; -import { DecryptionFailureCode } from "../../crypto-api"; -import { DecryptionError } from "../../common-crypto/CryptoBackend"; +} from "./base.ts"; +import { IDecryptedGroupMessage, WITHHELD_MESSAGES } from "../OlmDevice.ts"; +import { Room } from "../../models/room.ts"; +import { DeviceInfo } from "../deviceinfo.ts"; +import { IOlmSessionResult } from "../olmlib.ts"; +import { DeviceInfoMap } from "../DeviceList.ts"; +import { IContent, MatrixEvent } from "../../models/event.ts"; +import { EventType, MsgType, ToDeviceMessageId } from "../../@types/event.ts"; +import { IMegolmEncryptedContent, IncomingRoomKeyRequest, IEncryptedContent } from "../index.ts"; +import { RoomKeyRequestState } from "../OutgoingRoomKeyRequestManager.ts"; +import { OlmGroupSessionExtraData } from "../../@types/crypto.ts"; +import { MatrixError } from "../../http-api/index.ts"; +import { immediate, MapWithDefault } from "../../utils.ts"; +import { KnownMembership } from "../../@types/membership.ts"; +import { DecryptionFailureCode } from "../../crypto-api/index.ts"; +import { DecryptionError } from "../../common-crypto/CryptoBackend.ts"; // determine whether the key can be shared with invitees export function isRoomSharedHistory(room: Room): boolean { diff --git a/src/crypto/algorithms/olm.ts b/src/crypto/algorithms/olm.ts index 3bcff5872b0..eb93a06a171 100644 --- a/src/crypto/algorithms/olm.ts +++ b/src/crypto/algorithms/olm.ts @@ -18,17 +18,17 @@ limitations under the License. * Defines m.olm encryption/decryption */ -import type { IEventDecryptionResult } from "../../@types/crypto"; -import { logger } from "../../logger"; -import * as olmlib from "../olmlib"; -import { DeviceInfo } from "../deviceinfo"; -import { DecryptionAlgorithm, EncryptionAlgorithm, registerAlgorithm } from "./base"; -import { Room } from "../../models/room"; -import { IContent, MatrixEvent } from "../../models/event"; -import { IEncryptedContent, IOlmEncryptedContent } from "../index"; -import { IInboundSession } from "../OlmDevice"; -import { DecryptionFailureCode } from "../../crypto-api"; -import { DecryptionError } from "../../common-crypto/CryptoBackend"; +import type { IEventDecryptionResult } from "../../@types/crypto.ts"; +import { logger } from "../../logger.ts"; +import * as olmlib from "../olmlib.ts"; +import { DeviceInfo } from "../deviceinfo.ts"; +import { DecryptionAlgorithm, EncryptionAlgorithm, registerAlgorithm } from "./base.ts"; +import { Room } from "../../models/room.ts"; +import { IContent, MatrixEvent } from "../../models/event.ts"; +import { IEncryptedContent, IOlmEncryptedContent } from "../index.ts"; +import { IInboundSession } from "../OlmDevice.ts"; +import { DecryptionFailureCode } from "../../crypto-api/index.ts"; +import { DecryptionError } from "../../common-crypto/CryptoBackend.ts"; const DeviceVerification = DeviceInfo.DeviceVerification; diff --git a/src/crypto/api.ts b/src/crypto/api.ts index a0e11a415be..0b520277772 100644 --- a/src/crypto/api.ts +++ b/src/crypto/api.ts @@ -14,26 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { DeviceInfo } from "./deviceinfo"; +import { DeviceInfo } from "./deviceinfo.ts"; /* re-exports for backwards compatibility. */ // CrossSigningKey is used as a value in `client.ts`, we can't export it as a type -export { CrossSigningKey } from "../crypto-api"; +export { CrossSigningKey } from "../crypto-api/index.ts"; export type { GeneratedSecretStorageKey as IRecoveryKey, CreateSecretStorageOpts as ICreateSecretStorageOpts, -} from "../crypto-api"; +} from "../crypto-api/index.ts"; export type { ImportRoomKeyProgressData as IImportOpts, ImportRoomKeysOpts as IImportRoomKeysOpts, -} from "../crypto-api"; +} from "../crypto-api/index.ts"; export type { AddSecretStorageKeyOpts as IAddSecretStorageKeyOpts, PassphraseInfo as IPassphraseInfo, SecretStorageKeyDescription as ISecretStorageKeyInfo, -} from "../secret-storage"; +} from "../secret-storage.ts"; // TODO: Merge this with crypto.js once converted diff --git a/src/crypto/backup.ts b/src/crypto/backup.ts index d51fa641c26..3ac6a3ddc0b 100644 --- a/src/crypto/backup.ts +++ b/src/crypto/backup.ts @@ -18,30 +18,29 @@ limitations under the License. * Classes for dealing with key backup. */ -import type { IMegolmSessionData } from "../@types/crypto"; -import { MatrixClient } from "../client"; -import { logger } from "../logger"; -import { MEGOLM_ALGORITHM, verifySignature } from "./olmlib"; -import { DeviceInfo } from "./deviceinfo"; -import { DeviceTrustLevel } from "./CrossSigning"; -import { keyFromPassphrase } from "./key_passphrase"; -import { encodeUri, safeSet, sleep } from "../utils"; -import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store"; -import { encodeRecoveryKey } from "./recoverykey"; -import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./aes"; +import type { IMegolmSessionData } from "../@types/crypto.ts"; +import { MatrixClient } from "../client.ts"; +import { logger } from "../logger.ts"; +import { MEGOLM_ALGORITHM, verifySignature } from "./olmlib.ts"; +import { DeviceInfo } from "./deviceinfo.ts"; +import { DeviceTrustLevel } from "./CrossSigning.ts"; +import { keyFromPassphrase } from "./key_passphrase.ts"; +import { encodeUri, safeSet, sleep } from "../utils.ts"; +import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store.ts"; +import { encodeRecoveryKey } from "./recoverykey.ts"; +import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./aes.ts"; import { Curve25519SessionData, IAes256AuthData, ICurve25519AuthData, IKeyBackupInfo, IKeyBackupSession, -} from "./keybackup"; -import { UnstableValue } from "../NamespacedValue"; -import { CryptoEvent } from "./index"; -import { crypto } from "./crypto"; -import { ClientPrefix, HTTPError, MatrixError, Method } from "../http-api"; -import { BackupTrustInfo } from "../crypto-api/keybackup"; -import { BackupDecryptor } from "../common-crypto/CryptoBackend"; +} from "./keybackup.ts"; +import { UnstableValue } from "../NamespacedValue.ts"; +import { CryptoEvent } from "./index.ts"; +import { ClientPrefix, HTTPError, MatrixError, Method } from "../http-api/index.ts"; +import { BackupTrustInfo } from "../crypto-api/keybackup.ts"; +import { BackupDecryptor } from "../common-crypto/CryptoBackend.ts"; const KEY_BACKUP_KEYS_PER_REQUEST = 200; const KEY_BACKUP_CHECK_RATE_LIMIT = 5000; // ms @@ -764,7 +763,7 @@ export class Curve25519 implements BackupAlgorithm { function randomBytes(size: number): Uint8Array { const buf = new Uint8Array(size); - crypto.getRandomValues(buf); + globalThis.crypto.getRandomValues(buf); return buf; } diff --git a/src/crypto/crypto.ts b/src/crypto/crypto.ts index 170dabb0937..4aea59de52b 100644 --- a/src/crypto/crypto.ts +++ b/src/crypto/crypto.ts @@ -14,37 +14,5 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../logger"; - -export let crypto = globalThis.crypto; -export let subtleCrypto = crypto?.subtle ?? crypto?.webkitSubtle; // TODO: Stop using webkitSubtle fallback -export let TextEncoder = globalThis.TextEncoder; - -/* eslint-disable @typescript-eslint/no-var-requires */ -if (!crypto) { - try { - crypto = require("crypto").webcrypto; - } catch (e) { - logger.error("Failed to load webcrypto", e); - } -} -if (!subtleCrypto) { - subtleCrypto = crypto?.subtle; -} -if (!TextEncoder) { - try { - TextEncoder = require("util").TextEncoder; - } catch (e) { - logger.error("Failed to load TextEncoder util", e); - } -} -/* eslint-enable @typescript-eslint/no-var-requires */ - -export function setCrypto(_crypto: Crypto): void { - crypto = _crypto; - subtleCrypto = _crypto.subtle ?? _crypto.webkitSubtle; -} - -export function setTextEncoder(_TextEncoder: typeof TextEncoder): void { - TextEncoder = _TextEncoder; -} +/** @deprecated this is a no-op and should no longer be called. */ +export function setCrypto(_crypto: Crypto): void {} diff --git a/src/crypto/dehydration.ts b/src/crypto/dehydration.ts index a24e65e4537..01dafa83c71 100644 --- a/src/crypto/dehydration.ts +++ b/src/crypto/dehydration.ts @@ -16,14 +16,14 @@ limitations under the License. import anotherjson from "another-json"; -import type { IDeviceKeys, IOneTimeKey } from "../@types/crypto"; -import { decodeBase64, encodeBase64 } from "../base64"; -import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store"; -import { decryptAES, encryptAES } from "./aes"; -import { logger } from "../logger"; -import { Crypto } from "./index"; -import { Method } from "../http-api"; -import { SecretStorageKeyDescription } from "../secret-storage"; +import type { IDeviceKeys, IOneTimeKey } from "../@types/crypto.ts"; +import { decodeBase64, encodeBase64 } from "../base64.ts"; +import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store.ts"; +import { decryptAES, encryptAES } from "./aes.ts"; +import { logger } from "../logger.ts"; +import { Crypto } from "./index.ts"; +import { Method } from "../http-api/index.ts"; +import { SecretStorageKeyDescription } from "../secret-storage.ts"; export interface IDehydratedDevice { device_id: string; // eslint-disable-line camelcase diff --git a/src/crypto/device-converter.ts b/src/crypto/device-converter.ts index cf32ef6141e..a2591150cfc 100644 --- a/src/crypto/device-converter.ts +++ b/src/crypto/device-converter.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Device } from "../models/device"; -import { DeviceInfo } from "./deviceinfo"; +import { Device } from "../models/device.ts"; +import { DeviceInfo } from "./deviceinfo.ts"; /** * Convert a {@link DeviceInfo} to a {@link Device}. diff --git a/src/crypto/deviceinfo.ts b/src/crypto/deviceinfo.ts index 8b41c3c6784..7641af31692 100644 --- a/src/crypto/deviceinfo.ts +++ b/src/crypto/deviceinfo.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ISignatures } from "../@types/signed"; -import { DeviceVerification } from "../models/device"; +import { ISignatures } from "../@types/signed.ts"; +import { DeviceVerification } from "../models/device.ts"; export interface IDevice { keys: Record; diff --git a/src/crypto/index.ts b/src/crypto/index.ts index 4379c2e1272..420160c0de4 100644 --- a/src/crypto/index.ts +++ b/src/crypto/index.ts @@ -20,55 +20,60 @@ limitations under the License. import anotherjson from "another-json"; import { v4 as uuidv4 } from "uuid"; -import type { IDeviceKeys, IEventDecryptionResult, IMegolmSessionData, IOneTimeKey } from "../@types/crypto"; +import type { IDeviceKeys, IEventDecryptionResult, IMegolmSessionData, IOneTimeKey } from "../@types/crypto.ts"; import type { PkDecryption, PkSigning } from "@matrix-org/olm"; -import { EventType, ToDeviceMessageId } from "../@types/event"; -import { TypedReEmitter } from "../ReEmitter"; -import { logger } from "../logger"; -import { IExportedDevice, OlmDevice } from "./OlmDevice"; -import { IOlmDevice } from "./algorithms/megolm"; -import * as olmlib from "./olmlib"; -import { DeviceInfoMap, DeviceList } from "./DeviceList"; -import { DeviceInfo, IDevice } from "./deviceinfo"; -import type { DecryptionAlgorithm, EncryptionAlgorithm } from "./algorithms"; -import * as algorithms from "./algorithms"; -import { createCryptoStoreCacheCallbacks, CrossSigningInfo, DeviceTrustLevel, UserTrustLevel } from "./CrossSigning"; -import { EncryptionSetupBuilder } from "./EncryptionSetup"; -import { SecretStorage as LegacySecretStorage } from "./SecretStorage"; -import { CrossSigningKey, ICreateSecretStorageOpts, IEncryptedEventInfo, IRecoveryKey } from "./api"; -import { OutgoingRoomKeyRequestManager } from "./OutgoingRoomKeyRequestManager"; -import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store"; -import { VerificationBase } from "./verification/Base"; -import { ReciprocateQRCode, SCAN_QR_CODE_METHOD, SHOW_QR_CODE_METHOD } from "./verification/QRCode"; -import { SAS as SASVerification } from "./verification/SAS"; -import { keyFromPassphrase } from "./key_passphrase"; -import { decodeRecoveryKey, encodeRecoveryKey } from "./recoverykey"; -import { VerificationRequest } from "./verification/request/VerificationRequest"; -import { InRoomChannel, InRoomRequests } from "./verification/request/InRoomChannel"; -import { Request, ToDeviceChannel, ToDeviceRequests } from "./verification/request/ToDeviceChannel"; -import { IllegalMethod } from "./verification/IllegalMethod"; -import { KeySignatureUploadError } from "../errors"; -import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./aes"; -import { DehydrationManager } from "./dehydration"; -import { BackupManager, LibOlmBackupDecryptor, backupTrustInfoFromLegacyTrustInfo } from "./backup"; -import { IStore } from "../store"; -import { Room, RoomEvent } from "../models/room"; -import { RoomMember, RoomMemberEvent } from "../models/room-member"; -import { EventStatus, IContent, IEvent, MatrixEvent, MatrixEventEvent } from "../models/event"; -import { ToDeviceBatch } from "../models/ToDeviceMessage"; -import { ClientEvent, IKeysUploadResponse, ISignedKey, IUploadKeySignaturesResponse, MatrixClient } from "../client"; -import { IRoomEncryption, RoomList } from "./RoomList"; -import { IKeyBackupInfo } from "./keybackup"; -import { ISyncStateData } from "../sync"; -import { CryptoStore } from "./store/base"; -import { IVerificationChannel } from "./verification/request/Channel"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { IDeviceLists, ISyncResponse, IToDeviceEvent } from "../sync-accumulator"; -import { ISignatures } from "../@types/signed"; -import { IMessage } from "./algorithms/olm"; -import { BackupDecryptor, CryptoBackend, DecryptionError, OnSyncCompletedData } from "../common-crypto/CryptoBackend"; -import { RoomState, RoomStateEvent } from "../models/room-state"; -import { MapWithDefault, recursiveMapToObject } from "../utils"; +import { EventType, ToDeviceMessageId } from "../@types/event.ts"; +import { TypedReEmitter } from "../ReEmitter.ts"; +import { logger } from "../logger.ts"; +import { IExportedDevice, OlmDevice } from "./OlmDevice.ts"; +import { IOlmDevice } from "./algorithms/megolm.ts"; +import * as olmlib from "./olmlib.ts"; +import { DeviceInfoMap, DeviceList } from "./DeviceList.ts"; +import { DeviceInfo, IDevice } from "./deviceinfo.ts"; +import type { DecryptionAlgorithm, EncryptionAlgorithm } from "./algorithms/index.ts"; +import * as algorithms from "./algorithms/index.ts"; +import { createCryptoStoreCacheCallbacks, CrossSigningInfo, DeviceTrustLevel, UserTrustLevel } from "./CrossSigning.ts"; +import { EncryptionSetupBuilder } from "./EncryptionSetup.ts"; +import { SecretStorage as LegacySecretStorage } from "./SecretStorage.ts"; +import { CrossSigningKey, ICreateSecretStorageOpts, IEncryptedEventInfo, IRecoveryKey } from "./api.ts"; +import { OutgoingRoomKeyRequestManager } from "./OutgoingRoomKeyRequestManager.ts"; +import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store.ts"; +import { VerificationBase } from "./verification/Base.ts"; +import { ReciprocateQRCode, SCAN_QR_CODE_METHOD, SHOW_QR_CODE_METHOD } from "./verification/QRCode.ts"; +import { SAS as SASVerification } from "./verification/SAS.ts"; +import { keyFromPassphrase } from "./key_passphrase.ts"; +import { decodeRecoveryKey, encodeRecoveryKey } from "./recoverykey.ts"; +import { VerificationRequest } from "./verification/request/VerificationRequest.ts"; +import { InRoomChannel, InRoomRequests } from "./verification/request/InRoomChannel.ts"; +import { Request, ToDeviceChannel, ToDeviceRequests } from "./verification/request/ToDeviceChannel.ts"; +import { IllegalMethod } from "./verification/IllegalMethod.ts"; +import { KeySignatureUploadError } from "../errors.ts"; +import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./aes.ts"; +import { DehydrationManager } from "./dehydration.ts"; +import { BackupManager, LibOlmBackupDecryptor, backupTrustInfoFromLegacyTrustInfo } from "./backup.ts"; +import { IStore } from "../store/index.ts"; +import { Room, RoomEvent } from "../models/room.ts"; +import { RoomMember, RoomMemberEvent } from "../models/room-member.ts"; +import { EventStatus, IContent, IEvent, MatrixEvent, MatrixEventEvent } from "../models/event.ts"; +import { ToDeviceBatch } from "../models/ToDeviceMessage.ts"; +import { ClientEvent, IKeysUploadResponse, ISignedKey, IUploadKeySignaturesResponse, MatrixClient } from "../client.ts"; +import { IRoomEncryption, RoomList } from "./RoomList.ts"; +import { IKeyBackupInfo } from "./keybackup.ts"; +import { ISyncStateData } from "../sync.ts"; +import { CryptoStore } from "./store/base.ts"; +import { IVerificationChannel } from "./verification/request/Channel.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { IDeviceLists, ISyncResponse, IToDeviceEvent } from "../sync-accumulator.ts"; +import { ISignatures } from "../@types/signed.ts"; +import { IMessage } from "./algorithms/olm.ts"; +import { + BackupDecryptor, + CryptoBackend, + DecryptionError, + OnSyncCompletedData, +} from "../common-crypto/CryptoBackend.ts"; +import { RoomState, RoomStateEvent } from "../models/room-state.ts"; +import { MapWithDefault, recursiveMapToObject } from "../utils.ts"; import { AccountDataClient, AddSecretStorageKeyOpts, @@ -77,8 +82,8 @@ import { SecretStorageKeyObject, SecretStorageKeyTuple, ServerSideSecretStorageImpl, -} from "../secret-storage"; -import { ISecretRequest } from "./SecretSharing"; +} from "../secret-storage.ts"; +import { ISecretRequest } from "./SecretSharing.ts"; import { BackupTrustInfo, BootstrapCrossSigningOpts, @@ -94,18 +99,18 @@ import { KeyBackupInfo, OwnDeviceKeys, VerificationRequest as CryptoApiVerificationRequest, -} from "../crypto-api"; -import { Device, DeviceMap } from "../models/device"; -import { deviceInfoToDevice } from "./device-converter"; -import { ClientPrefix, MatrixError, Method } from "../http-api"; -import { decodeBase64, encodeBase64 } from "../base64"; -import { KnownMembership } from "../@types/membership"; +} from "../crypto-api/index.ts"; +import { Device, DeviceMap } from "../models/device.ts"; +import { deviceInfoToDevice } from "./device-converter.ts"; +import { ClientPrefix, MatrixError, Method } from "../http-api/index.ts"; +import { decodeBase64, encodeBase64 } from "../base64.ts"; +import { KnownMembership } from "../@types/membership.ts"; /* re-exports for backwards compatibility */ export type { BootstrapCrossSigningOpts as IBootstrapCrossSigningOpts, CryptoCallbacks as ICryptoCallbacks, -} from "../crypto-api"; +} from "../crypto-api/index.ts"; const DeviceVerification = DeviceInfo.DeviceVerification; @@ -276,7 +281,7 @@ export type CryptoEventHandlerMap = { * @param deviceId - the id of the verified device * @param deviceInfo - updated device information */ - [CryptoEvent.DeviceVerificationChanged]: (userId: string, deviceId: string, device: DeviceInfo) => void; + [CryptoEvent.DeviceVerificationChanged]: (userId: string, deviceId: string, deviceInfo: DeviceInfo) => void; /** * Fires when the trust status of a user changes * If userId is the userId of the logged-in user, this indicated a change @@ -292,7 +297,7 @@ export type CryptoEventHandlerMap = { /** * Fires when we receive a room key request * - * @param req - request details + * @param request - request details */ [CryptoEvent.RoomKeyRequest]: (request: IncomingRoomKeyRequest) => void; /** @@ -4374,4 +4379,4 @@ class IncomingRoomKeyRequestCancellation { } // a number of types are re-exported for backwards compatibility, in case any applications are referencing it. -export type { IEventDecryptionResult, IMegolmSessionData } from "../@types/crypto"; +export type { IEventDecryptionResult, IMegolmSessionData } from "../@types/crypto.ts"; diff --git a/src/crypto/key_passphrase.ts b/src/crypto/key_passphrase.ts index f6fe7b6b7d7..85b9c48fbcd 100644 --- a/src/crypto/key_passphrase.ts +++ b/src/crypto/key_passphrase.ts @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { randomString } from "../randomstring"; -import { subtleCrypto, TextEncoder } from "./crypto"; +import { randomString } from "../randomstring.ts"; const DEFAULT_ITERATIONS = 500000; @@ -36,10 +35,6 @@ interface IKey { } export function keyFromAuthData(authData: IAuthData, password: string): Promise { - if (!global.Olm) { - throw new Error("Olm is not available"); - } - if (!authData.private_key_salt || !authData.private_key_iterations) { throw new Error("Salt and/or iterations not found: " + "this backup cannot be restored with a passphrase"); } @@ -53,10 +48,6 @@ export function keyFromAuthData(authData: IAuthData, password: string): Promise< } export async function keyFromPassphrase(password: string): Promise { - if (!global.Olm) { - throw new Error("Olm is not available"); - } - const salt = randomString(32); const key = await deriveKey(password, salt, DEFAULT_ITERATIONS, DEFAULT_BITSIZE); @@ -70,15 +61,19 @@ export async function deriveKey( iterations: number, numBits = DEFAULT_BITSIZE, ): Promise { - if (!subtleCrypto || !TextEncoder) { + if (!globalThis.crypto.subtle || !TextEncoder) { throw new Error("Password-based backup is not available on this platform"); } - const key = await subtleCrypto.importKey("raw", new TextEncoder().encode(password), { name: "PBKDF2" }, false, [ - "deriveBits", - ]); + const key = await globalThis.crypto.subtle.importKey( + "raw", + new TextEncoder().encode(password), + { name: "PBKDF2" }, + false, + ["deriveBits"], + ); - const keybits = await subtleCrypto.deriveBits( + const keybits = await globalThis.crypto.subtle.deriveBits( { name: "PBKDF2", salt: new TextEncoder().encode(salt), diff --git a/src/crypto/keybackup.ts b/src/crypto/keybackup.ts index 8ef04176cb2..4399a38601f 100644 --- a/src/crypto/keybackup.ts +++ b/src/crypto/keybackup.ts @@ -15,7 +15,7 @@ limitations under the License. */ // Export for backward compatibility -import { ImportRoomKeyProgressData } from "../crypto-api"; +import { ImportRoomKeyProgressData } from "../crypto-api/index.ts"; export type { Curve25519AuthData as ICurve25519AuthData, @@ -24,7 +24,7 @@ export type { Curve25519SessionData, KeyBackupSession as IKeyBackupSession, KeyBackupRoomSessions as IKeyBackupRoomSessions, -} from "../crypto-api/keybackup"; +} from "../crypto-api/keybackup.ts"; /* eslint-enable camelcase */ diff --git a/src/crypto/olmlib.ts b/src/crypto/olmlib.ts index 7396ef47988..9eceaf48bc7 100644 --- a/src/crypto/olmlib.ts +++ b/src/crypto/olmlib.ts @@ -21,16 +21,16 @@ limitations under the License. import anotherjson from "another-json"; import type { PkSigning } from "@matrix-org/olm"; -import type { IOneTimeKey } from "../@types/crypto"; -import { OlmDevice } from "./OlmDevice"; -import { DeviceInfo } from "./deviceinfo"; -import { Logger, logger } from "../logger"; -import { IClaimOTKsResult, MatrixClient } from "../client"; -import { ISignatures } from "../@types/signed"; -import { MatrixEvent } from "../models/event"; -import { EventType } from "../@types/event"; -import { IMessage } from "./algorithms/olm"; -import { MapWithDefault } from "../utils"; +import type { IOneTimeKey } from "../@types/crypto.ts"; +import { OlmDevice } from "./OlmDevice.ts"; +import { DeviceInfo } from "./deviceinfo.ts"; +import { Logger, logger } from "../logger.ts"; +import { IClaimOTKsResult, MatrixClient } from "../client.ts"; +import { ISignatures } from "../@types/signed.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { EventType } from "../@types/event.ts"; +import { IMessage } from "./algorithms/olm.ts"; +import { MapWithDefault } from "../utils.ts"; enum Algorithm { Olm = "m.olm.v1.curve25519-aes-sha2", diff --git a/src/crypto/recoverykey.ts b/src/crypto/recoverykey.ts index 8c6a7e33ed7..3d7c12d4acf 100644 --- a/src/crypto/recoverykey.ts +++ b/src/crypto/recoverykey.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as bs58 from "bs58"; +import bs58 from "bs58"; // picked arbitrarily but to try & avoid clashing with any bitcoin ones // (which are also base58 encoded, but bitcoin's involve a lot more hashing) diff --git a/src/crypto/store/base.ts b/src/crypto/store/base.ts index 871804b7379..daf11b5b0b3 100644 --- a/src/crypto/store/base.ts +++ b/src/crypto/store/base.ts @@ -14,19 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IRoomKeyRequestBody, IRoomKeyRequestRecipient } from "../index"; -import { RoomKeyRequestState } from "../OutgoingRoomKeyRequestManager"; -import { IOlmDevice } from "../algorithms/megolm"; -import { TrackingStatus } from "../DeviceList"; -import { IRoomEncryption } from "../RoomList"; -import { IDevice } from "../deviceinfo"; -import { ICrossSigningInfo } from "../CrossSigning"; -import { Logger } from "../../logger"; -import { InboundGroupSessionData } from "../OlmDevice"; -import { MatrixEvent } from "../../models/event"; -import { DehydrationManager } from "../dehydration"; -import { IEncryptedPayload } from "../aes"; -import { CrossSigningKeyInfo } from "../../crypto-api"; +import { IRoomKeyRequestBody, IRoomKeyRequestRecipient } from "../index.ts"; +import { RoomKeyRequestState } from "../OutgoingRoomKeyRequestManager.ts"; +import { IOlmDevice } from "../algorithms/megolm.ts"; +import { TrackingStatus } from "../DeviceList.ts"; +import { IRoomEncryption } from "../RoomList.ts"; +import { IDevice } from "../deviceinfo.ts"; +import { ICrossSigningInfo } from "../CrossSigning.ts"; +import { Logger } from "../../logger.ts"; +import { InboundGroupSessionData } from "../OlmDevice.ts"; +import { MatrixEvent } from "../../models/event.ts"; +import { DehydrationManager } from "../dehydration.ts"; +import { IEncryptedPayload } from "../aes.ts"; +import { CrossSigningKeyInfo } from "../../crypto-api/index.ts"; /** * Internal module. Definitions for storage for the crypto module diff --git a/src/crypto/store/indexeddb-crypto-store-backend.ts b/src/crypto/store/indexeddb-crypto-store-backend.ts index 08d4c0f6e98..1ef3dd120e2 100644 --- a/src/crypto/store/indexeddb-crypto-store-backend.ts +++ b/src/crypto/store/indexeddb-crypto-store-backend.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Logger, logger } from "../../logger"; -import { deepCompare } from "../../utils"; +import { Logger, logger } from "../../logger.ts"; +import { deepCompare } from "../../utils.ts"; import { CryptoStore, IDeviceData, @@ -31,13 +31,13 @@ import { SecretStorePrivateKeys, SESSION_BATCH_SIZE, ACCOUNT_OBJECT_KEY_MIGRATION_STATE, -} from "./base"; -import { IRoomKeyRequestBody, IRoomKeyRequestRecipient } from "../index"; -import { IOlmDevice } from "../algorithms/megolm"; -import { IRoomEncryption } from "../RoomList"; -import { InboundGroupSessionData } from "../OlmDevice"; -import { IndexedDBCryptoStore } from "./indexeddb-crypto-store"; -import { CrossSigningKeyInfo } from "../../crypto-api"; +} from "./base.ts"; +import { IRoomKeyRequestBody, IRoomKeyRequestRecipient } from "../index.ts"; +import { IOlmDevice } from "../algorithms/megolm.ts"; +import { IRoomEncryption } from "../RoomList.ts"; +import { InboundGroupSessionData } from "../OlmDevice.ts"; +import { IndexedDBCryptoStore } from "./indexeddb-crypto-store.ts"; +import { CrossSigningKeyInfo } from "../../crypto-api/index.ts"; const PROFILE_TRANSACTIONS = false; diff --git a/src/crypto/store/indexeddb-crypto-store.ts b/src/crypto/store/indexeddb-crypto-store.ts index 8fe488e08d0..29d32b5e34c 100644 --- a/src/crypto/store/indexeddb-crypto-store.ts +++ b/src/crypto/store/indexeddb-crypto-store.ts @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger, Logger } from "../../logger"; -import { LocalStorageCryptoStore } from "./localStorage-crypto-store"; -import { MemoryCryptoStore } from "./memory-crypto-store"; -import * as IndexedDBCryptoStoreBackend from "./indexeddb-crypto-store-backend"; -import { InvalidCryptoStoreError, InvalidCryptoStoreState } from "../../errors"; -import * as IndexedDBHelpers from "../../indexeddb-helpers"; +import { logger, Logger } from "../../logger.ts"; +import { LocalStorageCryptoStore } from "./localStorage-crypto-store.ts"; +import { MemoryCryptoStore } from "./memory-crypto-store.ts"; +import * as IndexedDBCryptoStoreBackend from "./indexeddb-crypto-store-backend.ts"; +import { InvalidCryptoStoreError, InvalidCryptoStoreState } from "../../errors.ts"; +import * as IndexedDBHelpers from "../../indexeddb-helpers.ts"; import { CryptoStore, IDeviceData, @@ -34,12 +34,12 @@ import { ParkedSharedHistory, SecretStorePrivateKeys, ACCOUNT_OBJECT_KEY_MIGRATION_STATE, -} from "./base"; -import { IRoomKeyRequestBody } from "../index"; -import { IOlmDevice } from "../algorithms/megolm"; -import { IRoomEncryption } from "../RoomList"; -import { InboundGroupSessionData } from "../OlmDevice"; -import { CrossSigningKeyInfo } from "../../crypto-api"; +} from "./base.ts"; +import { IRoomKeyRequestBody } from "../index.ts"; +import { IOlmDevice } from "../algorithms/megolm.ts"; +import { IRoomEncryption } from "../RoomList.ts"; +import { InboundGroupSessionData } from "../OlmDevice.ts"; +import { CrossSigningKeyInfo } from "../../crypto-api/index.ts"; /* * Internal module. indexeddb storage for e2e. diff --git a/src/crypto/store/localStorage-crypto-store.ts b/src/crypto/store/localStorage-crypto-store.ts index 41821ec62a5..d24e648d634 100644 --- a/src/crypto/store/localStorage-crypto-store.ts +++ b/src/crypto/store/localStorage-crypto-store.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../../logger"; -import { MemoryCryptoStore } from "./memory-crypto-store"; +import { logger } from "../../logger.ts"; +import { MemoryCryptoStore } from "./memory-crypto-store.ts"; import { CryptoStore, IDeviceData, @@ -28,12 +28,12 @@ import { Mode, SecretStorePrivateKeys, SESSION_BATCH_SIZE, -} from "./base"; -import { IOlmDevice } from "../algorithms/megolm"; -import { IRoomEncryption } from "../RoomList"; -import { InboundGroupSessionData } from "../OlmDevice"; -import { safeSet } from "../../utils"; -import { CrossSigningKeyInfo } from "../../crypto-api"; +} from "./base.ts"; +import { IOlmDevice } from "../algorithms/megolm.ts"; +import { IRoomEncryption } from "../RoomList.ts"; +import { InboundGroupSessionData } from "../OlmDevice.ts"; +import { safeSet } from "../../utils.ts"; +import { CrossSigningKeyInfo } from "../../crypto-api/index.ts"; /** * Internal module. Partial localStorage backed storage for e2e. diff --git a/src/crypto/store/memory-crypto-store.ts b/src/crypto/store/memory-crypto-store.ts index 4fd8a57f85e..65fca29d7b7 100644 --- a/src/crypto/store/memory-crypto-store.ts +++ b/src/crypto/store/memory-crypto-store.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../../logger"; -import { deepCompare, promiseTry, safeSet } from "../../utils"; +import { logger } from "../../logger.ts"; +import { deepCompare, promiseTry, safeSet } from "../../utils.ts"; import { CryptoStore, IDeviceData, @@ -30,12 +30,12 @@ import { ParkedSharedHistory, SecretStorePrivateKeys, SESSION_BATCH_SIZE, -} from "./base"; -import { IRoomKeyRequestBody } from "../index"; -import { IOlmDevice } from "../algorithms/megolm"; -import { IRoomEncryption } from "../RoomList"; -import { InboundGroupSessionData } from "../OlmDevice"; -import { CrossSigningKeyInfo } from "../../crypto-api"; +} from "./base.ts"; +import { IRoomKeyRequestBody } from "../index.ts"; +import { IOlmDevice } from "../algorithms/megolm.ts"; +import { IRoomEncryption } from "../RoomList.ts"; +import { InboundGroupSessionData } from "../OlmDevice.ts"; +import { CrossSigningKeyInfo } from "../../crypto-api/index.ts"; function encodeSessionKey(senderCurve25519Key: string, sessionId: string): string { return encodeURIComponent(senderCurve25519Key) + "/" + encodeURIComponent(sessionId); diff --git a/src/crypto/verification/Base.ts b/src/crypto/verification/Base.ts index 308ea4401d7..179c868b64b 100644 --- a/src/crypto/verification/Base.ts +++ b/src/crypto/verification/Base.ts @@ -19,23 +19,23 @@ limitations under the License. * Base class for verification methods. */ -import { MatrixEvent } from "../../models/event"; -import { EventType } from "../../@types/event"; -import { logger } from "../../logger"; -import { DeviceInfo } from "../deviceinfo"; -import { newTimeoutError } from "./Error"; -import { KeysDuringVerification, requestKeysDuringVerification } from "../CrossSigning"; -import { IVerificationChannel } from "./request/Channel"; -import { MatrixClient } from "../../client"; -import { VerificationRequest } from "./request/VerificationRequest"; -import { TypedEventEmitter } from "../../models/typed-event-emitter"; +import { MatrixEvent } from "../../models/event.ts"; +import { EventType } from "../../@types/event.ts"; +import { logger } from "../../logger.ts"; +import { DeviceInfo } from "../deviceinfo.ts"; +import { newTimeoutError } from "./Error.ts"; +import { KeysDuringVerification, requestKeysDuringVerification } from "../CrossSigning.ts"; +import { IVerificationChannel } from "./request/Channel.ts"; +import { MatrixClient } from "../../client.ts"; +import { VerificationRequest } from "./request/VerificationRequest.ts"; +import { TypedEventEmitter } from "../../models/typed-event-emitter.ts"; import { ShowQrCodeCallbacks, ShowSasCallbacks, Verifier, VerifierEvent, VerifierEventHandlerMap, -} from "../../crypto-api/verification"; +} from "../../crypto-api/verification.ts"; const timeoutException = new Error("Verification timed out"); diff --git a/src/crypto/verification/Error.ts b/src/crypto/verification/Error.ts index da73ebb847e..4f609db3a8e 100644 --- a/src/crypto/verification/Error.ts +++ b/src/crypto/verification/Error.ts @@ -18,8 +18,8 @@ limitations under the License. * Error messages. */ -import { MatrixEvent } from "../../models/event"; -import { EventType } from "../../@types/event"; +import { MatrixEvent } from "../../models/event.ts"; +import { EventType } from "../../@types/event.ts"; export function newVerificationError(code: string, reason: string, extraData?: Record): MatrixEvent { const content = Object.assign({}, { code, reason }, extraData); diff --git a/src/crypto/verification/IllegalMethod.ts b/src/crypto/verification/IllegalMethod.ts index c437e0cd2a9..c556be71785 100644 --- a/src/crypto/verification/IllegalMethod.ts +++ b/src/crypto/verification/IllegalMethod.ts @@ -19,11 +19,11 @@ limitations under the License. * do verification with this method). */ -import { VerificationBase as Base, VerificationEvent, VerificationEventHandlerMap } from "./Base"; -import { IVerificationChannel } from "./request/Channel"; -import { MatrixClient } from "../../client"; -import { MatrixEvent } from "../../models/event"; -import { VerificationRequest } from "./request/VerificationRequest"; +import { VerificationBase as Base, VerificationEvent, VerificationEventHandlerMap } from "./Base.ts"; +import { IVerificationChannel } from "./request/Channel.ts"; +import { MatrixClient } from "../../client.ts"; +import { MatrixEvent } from "../../models/event.ts"; +import { VerificationRequest } from "./request/VerificationRequest.ts"; export class IllegalMethod extends Base { public static factory( diff --git a/src/crypto/verification/QRCode.ts b/src/crypto/verification/QRCode.ts index 7ccd4986d53..4caaf42b672 100644 --- a/src/crypto/verification/QRCode.ts +++ b/src/crypto/verification/QRCode.ts @@ -18,17 +18,16 @@ limitations under the License. * QR code key verification. */ -import { crypto } from "../crypto"; -import { VerificationBase as Base } from "./Base"; -import { newKeyMismatchError, newUserCancelledError } from "./Error"; -import { decodeBase64, encodeUnpaddedBase64 } from "../../base64"; -import { logger } from "../../logger"; -import { VerificationRequest } from "./request/VerificationRequest"; -import { MatrixClient } from "../../client"; -import { IVerificationChannel } from "./request/Channel"; -import { MatrixEvent } from "../../models/event"; -import { ShowQrCodeCallbacks, VerifierEvent } from "../../crypto-api/verification"; -import { VerificationMethod } from "../../types"; +import { VerificationBase as Base } from "./Base.ts"; +import { newKeyMismatchError, newUserCancelledError } from "./Error.ts"; +import { decodeBase64, encodeUnpaddedBase64 } from "../../base64.ts"; +import { logger } from "../../logger.ts"; +import { VerificationRequest } from "./request/VerificationRequest.ts"; +import { MatrixClient } from "../../client.ts"; +import { IVerificationChannel } from "./request/Channel.ts"; +import { MatrixEvent } from "../../models/event.ts"; +import { ShowQrCodeCallbacks, VerifierEvent } from "../../crypto-api/verification.ts"; +import { VerificationMethod } from "../../types.ts"; export const SHOW_QR_CODE_METHOD = VerificationMethod.ShowQrCode; export const SCAN_QR_CODE_METHOD = VerificationMethod.ScanQrCode; @@ -202,7 +201,7 @@ export class QRCodeData { private static generateSharedSecret(): string { const secretBytes = new Uint8Array(11); - crypto.getRandomValues(secretBytes); + globalThis.crypto.getRandomValues(secretBytes); return encodeUnpaddedBase64(secretBytes); } diff --git a/src/crypto/verification/SAS.ts b/src/crypto/verification/SAS.ts index f161278bc43..31e96753728 100644 --- a/src/crypto/verification/SAS.ts +++ b/src/crypto/verification/SAS.ts @@ -21,27 +21,27 @@ limitations under the License. import anotherjson from "another-json"; import { Utility, SAS as OlmSAS } from "@matrix-org/olm"; -import { VerificationBase as Base, SwitchStartEventError } from "./Base"; +import { VerificationBase as Base, SwitchStartEventError } from "./Base.ts"; import { errorFactory, newInvalidMessageError, newKeyMismatchError, newUnknownMethodError, newUserCancelledError, -} from "./Error"; -import { logger } from "../../logger"; -import { IContent, MatrixEvent } from "../../models/event"; -import { generateDecimalSas } from "./SASDecimal"; -import { EventType } from "../../@types/event"; -import { EmojiMapping, GeneratedSas, ShowSasCallbacks, VerifierEvent } from "../../crypto-api/verification"; -import { VerificationMethod } from "../../types"; +} from "./Error.ts"; +import { logger } from "../../logger.ts"; +import { IContent, MatrixEvent } from "../../models/event.ts"; +import { generateDecimalSas } from "./SASDecimal.ts"; +import { EventType } from "../../@types/event.ts"; +import { EmojiMapping, GeneratedSas, ShowSasCallbacks, VerifierEvent } from "../../crypto-api/verification.ts"; +import { VerificationMethod } from "../../types.ts"; // backwards-compatibility exports export type { ShowSasCallbacks as ISasEvent, GeneratedSas as IGeneratedSas, EmojiMapping, -} from "../../crypto-api/verification"; +} from "../../crypto-api/verification.ts"; const START_TYPE = EventType.KeyVerificationStart; diff --git a/src/crypto/verification/request/Channel.ts b/src/crypto/verification/request/Channel.ts index 48415f977e1..cb45c7b76c7 100644 --- a/src/crypto/verification/request/Channel.ts +++ b/src/crypto/verification/request/Channel.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixEvent } from "../../../models/event"; -import { VerificationRequest } from "./VerificationRequest"; +import { MatrixEvent } from "../../../models/event.ts"; +import { VerificationRequest } from "./VerificationRequest.ts"; export interface IVerificationChannel { request?: VerificationRequest; diff --git a/src/crypto/verification/request/InRoomChannel.ts b/src/crypto/verification/request/InRoomChannel.ts index 59df11d7884..05dcce872d6 100644 --- a/src/crypto/verification/request/InRoomChannel.ts +++ b/src/crypto/verification/request/InRoomChannel.ts @@ -15,13 +15,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { VerificationRequest, REQUEST_TYPE, READY_TYPE, START_TYPE } from "./VerificationRequest"; -import { logger } from "../../../logger"; -import { IVerificationChannel } from "./Channel"; -import { EventType, TimelineEvents } from "../../../@types/event"; -import { MatrixClient } from "../../../client"; -import { MatrixEvent } from "../../../models/event"; -import { IRequestsMap } from "../.."; +import { VerificationRequest, REQUEST_TYPE, READY_TYPE, START_TYPE } from "./VerificationRequest.ts"; +import { logger } from "../../../logger.ts"; +import { IVerificationChannel } from "./Channel.ts"; +import { EventType, TimelineEvents } from "../../../@types/event.ts"; +import { MatrixClient } from "../../../client.ts"; +import { MatrixEvent } from "../../../models/event.ts"; +import { IRequestsMap } from "../../index.ts"; const MESSAGE_TYPE = EventType.RoomMessage; const M_REFERENCE = "m.reference"; diff --git a/src/crypto/verification/request/ToDeviceChannel.ts b/src/crypto/verification/request/ToDeviceChannel.ts index d51b85ac75f..34bf6f51ab5 100644 --- a/src/crypto/verification/request/ToDeviceChannel.ts +++ b/src/crypto/verification/request/ToDeviceChannel.ts @@ -15,8 +15,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { randomString } from "../../../randomstring"; -import { logger } from "../../../logger"; +import { randomString } from "../../../randomstring.ts"; +import { logger } from "../../../logger.ts"; import { CANCEL_TYPE, PHASE_STARTED, @@ -25,12 +25,12 @@ import { READY_TYPE, START_TYPE, VerificationRequest, -} from "./VerificationRequest"; -import { errorFromEvent, newUnexpectedMessageError } from "../Error"; -import { MatrixEvent } from "../../../models/event"; -import { IVerificationChannel } from "./Channel"; -import { MatrixClient } from "../../../client"; -import { IRequestsMap } from "../.."; +} from "./VerificationRequest.ts"; +import { errorFromEvent, newUnexpectedMessageError } from "../Error.ts"; +import { MatrixEvent } from "../../../models/event.ts"; +import { IVerificationChannel } from "./Channel.ts"; +import { MatrixClient } from "../../../client.ts"; +import { IRequestsMap } from "../../index.ts"; export type Request = VerificationRequest; diff --git a/src/crypto/verification/request/VerificationRequest.ts b/src/crypto/verification/request/VerificationRequest.ts index 5c544f131e2..8a3aca9a287 100644 --- a/src/crypto/verification/request/VerificationRequest.ts +++ b/src/crypto/verification/request/VerificationRequest.ts @@ -14,16 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../../../logger"; -import { errorFactory, errorFromEvent, newUnexpectedMessageError, newUnknownMethodError } from "../Error"; -import { QRCodeData, SCAN_QR_CODE_METHOD } from "../QRCode"; -import { IVerificationChannel } from "./Channel"; -import { MatrixClient } from "../../../client"; -import { MatrixEvent } from "../../../models/event"; -import { EventType } from "../../../@types/event"; -import { VerificationBase } from "../Base"; -import { VerificationMethod } from "../../index"; -import { TypedEventEmitter } from "../../../models/typed-event-emitter"; +import { logger } from "../../../logger.ts"; +import { errorFactory, errorFromEvent, newUnexpectedMessageError, newUnknownMethodError } from "../Error.ts"; +import { QRCodeData, SCAN_QR_CODE_METHOD } from "../QRCode.ts"; +import { IVerificationChannel } from "./Channel.ts"; +import { MatrixClient } from "../../../client.ts"; +import { MatrixEvent } from "../../../models/event.ts"; +import { EventType } from "../../../@types/event.ts"; +import { VerificationBase } from "../Base.ts"; +import { VerificationMethod } from "../../index.ts"; +import { TypedEventEmitter } from "../../../models/typed-event-emitter.ts"; import { canAcceptVerificationRequest, VerificationPhase as Phase, @@ -31,10 +31,10 @@ import { VerificationRequestEvent, VerificationRequestEventHandlerMap, Verifier, -} from "../../../crypto-api/verification"; +} from "../../../crypto-api/verification.ts"; // backwards-compatibility exports -export { VerificationPhase as Phase, VerificationRequestEvent } from "../../../crypto-api/verification"; +export { VerificationPhase as Phase, VerificationRequestEvent } from "../../../crypto-api/verification.ts"; // How long after the event's timestamp that the request times out const TIMEOUT_FROM_EVENT_TS = 10 * 60 * 1000; // 10 minutes diff --git a/src/digest.ts b/src/digest.ts new file mode 100644 index 00000000000..85b5be9643b --- /dev/null +++ b/src/digest.ts @@ -0,0 +1,34 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * Computes a SHA-256 hash of a string (after utf-8 encoding) and returns it as an ArrayBuffer. + * + * @param plaintext The string to hash + * @returns An ArrayBuffer containing the SHA-256 hash of the input string + * @throws If the subtle crypto API is not available, for example if the code is running + * in a web page with an insecure context (eg. served over plain HTTP). + */ +export async function sha256(plaintext: string): Promise { + if (!globalThis.crypto.subtle) { + throw new Error("Crypto.subtle is not available: insecure context?"); + } + const utf8 = new TextEncoder().encode(plaintext); + + const digest = await globalThis.crypto.subtle.digest("SHA-256", utf8); + + return digest; +} diff --git a/src/embedded.ts b/src/embedded.ts index 8730c22ee3f..1974ea9f98e 100644 --- a/src/embedded.ts +++ b/src/embedded.ts @@ -25,10 +25,15 @@ import { ISendEventFromWidgetResponseData, } from "matrix-widget-api"; -import { MatrixEvent, IEvent, IContent, EventStatus } from "./models/event"; -import { ISendEventResponse } from "./@types/requests"; -import { EventType } from "./@types/event"; -import { logger } from "./logger"; +import { MatrixEvent, IEvent, IContent, EventStatus } from "./models/event.ts"; +import { + ISendEventResponse, + SendDelayedEventRequestOpts, + SendDelayedEventResponse, + UpdateDelayedEventAction, +} from "./@types/requests.ts"; +import { EventType, StateEvents } from "./@types/event.ts"; +import { logger } from "./logger.ts"; import { MatrixClient, ClientEvent, @@ -36,15 +41,16 @@ import { IStartClientOpts, SendToDeviceContentMap, IOpenIDToken, -} from "./client"; -import { SyncApi, SyncState } from "./sync"; -import { SlidingSyncSdk } from "./sliding-sync-sdk"; -import { User } from "./models/user"; -import { Room } from "./models/room"; -import { ToDeviceBatch, ToDevicePayload } from "./models/ToDeviceMessage"; -import { DeviceInfo } from "./crypto/deviceinfo"; -import { IOlmDevice } from "./crypto/algorithms/megolm"; -import { MapWithDefault, recursiveMapToObject } from "./utils"; + UNSTABLE_MSC4140_DELAYED_EVENTS, +} from "./client.ts"; +import { SyncApi, SyncState } from "./sync.ts"; +import { SlidingSyncSdk } from "./sliding-sync-sdk.ts"; +import { User } from "./models/user.ts"; +import { Room } from "./models/room.ts"; +import { ToDeviceBatch, ToDevicePayload } from "./models/ToDeviceMessage.ts"; +import { DeviceInfo } from "./crypto/deviceinfo.ts"; +import { IOlmDevice } from "./crypto/algorithms/megolm.ts"; +import { MapWithDefault, recursiveMapToObject } from "./utils.ts"; interface IStateEventRequest { eventType: string; @@ -95,6 +101,20 @@ export interface ICapabilities { * @defaultValue false */ turnServers?: boolean; + + /** + * Whether this client needs to be able to send delayed events. + * @experimental Part of MSC4140 & MSC4157 + * @defaultValue false + */ + sendDelayedEvents?: boolean; + + /** + * Whether this client needs to be able to update delayed events. + * @experimental Part of MSC4140 & MSC4157 + * @defaultValue false + */ + updateDelayedEvents?: boolean; } /** @@ -162,6 +182,18 @@ export class RoomWidgetClient extends MatrixClient { ); capabilities.sendToDevice?.forEach((eventType) => widgetApi.requestCapabilityToSendToDevice(eventType)); capabilities.receiveToDevice?.forEach((eventType) => widgetApi.requestCapabilityToReceiveToDevice(eventType)); + if ( + capabilities.sendDelayedEvents && + (capabilities.sendEvent?.length || + capabilities.sendMessage === true || + (Array.isArray(capabilities.sendMessage) && capabilities.sendMessage.length) || + capabilities.sendState?.length) + ) { + widgetApi.requestCapability(MatrixCapabilities.MSC4157SendDelayedEvent); + } + if (capabilities.updateDelayedEvents) { + widgetApi.requestCapability(MatrixCapabilities.MSC4157UpdateDelayedEvent); + } if (capabilities.turnServers) { widgetApi.requestCapability(MatrixCapabilities.MSC3846TurnServers); } @@ -218,6 +250,14 @@ export class RoomWidgetClient extends MatrixClient { }); }) ?? [], ); + + if (opts.clientWellKnownPollPeriod !== undefined) { + this.clientWellKnownIntervalID = setInterval(() => { + this.fetchClientWellKnown(); + }, 1000 * opts.clientWellKnownPollPeriod); + this.fetchClientWellKnown(); + } + this.setSyncState(SyncState.Syncing); logger.info("Finished backfilling events"); @@ -240,7 +280,29 @@ export class RoomWidgetClient extends MatrixClient { throw new Error(`Unknown room: ${roomIdOrAlias}`); } - protected async encryptAndSendEvent(room: Room, event: MatrixEvent): Promise { + protected async encryptAndSendEvent(room: Room, event: MatrixEvent): Promise; + protected async encryptAndSendEvent( + room: Room, + event: MatrixEvent, + delayOpts: SendDelayedEventRequestOpts, + ): Promise; + protected async encryptAndSendEvent( + room: Room, + event: MatrixEvent, + delayOpts?: SendDelayedEventRequestOpts, + ): Promise { + if (delayOpts) { + // TODO: updatePendingEvent for delayed events? + const response = await this.widgetApi.sendRoomEvent( + event.getType(), + event.getContent(), + room.roomId, + "delay" in delayOpts ? delayOpts.delay : undefined, + "parent_delay_id" in delayOpts ? delayOpts.parent_delay_id : undefined, + ); + return this.validateSendDelayedEventResponse(response); + } + let response: ISendEventFromWidgetResponseData; try { response = await this.widgetApi.sendRoomEvent(event.getType(), event.getContent(), room.roomId); @@ -249,8 +311,9 @@ export class RoomWidgetClient extends MatrixClient { throw e; } + // This also checks for an event id on the response room.updatePendingEvent(event, EventStatus.SENT, response.event_id); - return { event_id: response.event_id }; + return { event_id: response.event_id! }; } public async sendStateEvent( @@ -259,7 +322,56 @@ export class RoomWidgetClient extends MatrixClient { content: any, stateKey = "", ): Promise { - return await this.widgetApi.sendStateEvent(eventType, stateKey, content, roomId); + const response = await this.widgetApi.sendStateEvent(eventType, stateKey, content, roomId); + if (response.event_id === undefined) { + throw new Error("'event_id' absent from response to an event request"); + } + return { event_id: response.event_id }; + } + + /** + * @experimental This currently relies on an unstable MSC (MSC4140). + */ + // eslint-disable-next-line + public async _unstable_sendDelayedStateEvent( + roomId: string, + delayOpts: SendDelayedEventRequestOpts, + eventType: K, + content: StateEvents[K], + stateKey = "", + ): Promise { + if (!(await this.doesServerSupportUnstableFeature(UNSTABLE_MSC4140_DELAYED_EVENTS))) { + throw Error("Server does not support the delayed events API"); + } + + const response = await this.widgetApi.sendStateEvent( + eventType, + stateKey, + content, + roomId, + "delay" in delayOpts ? delayOpts.delay : undefined, + "parent_delay_id" in delayOpts ? delayOpts.parent_delay_id : undefined, + ); + return this.validateSendDelayedEventResponse(response); + } + + private validateSendDelayedEventResponse(response: ISendEventFromWidgetResponseData): SendDelayedEventResponse { + if (response.delay_id === undefined) { + throw new Error("'delay_id' absent from response to a delayed event request"); + } + return { delay_id: response.delay_id }; + } + + /** + * @experimental This currently relies on an unstable MSC (MSC4140). + */ + // eslint-disable-next-line + public async _unstable_updateDelayedEvent(delayId: string, action: UpdateDelayedEventAction): Promise<{}> { + if (!(await this.doesServerSupportUnstableFeature(UNSTABLE_MSC4140_DELAYED_EVENTS))) { + throw Error("Server does not support the delayed events API"); + } + + return await this.widgetApi.updateDelayedEvent(delayId, action); } public async sendToDevice(eventType: string, contentMap: SendToDeviceContentMap): Promise<{}> { diff --git a/src/event-mapper.ts b/src/event-mapper.ts index 828d87e9510..7dbf6a3c167 100644 --- a/src/event-mapper.ts +++ b/src/event-mapper.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixClient } from "./client"; -import { IEvent, MatrixEvent, MatrixEventEvent } from "./models/event"; -import { RelationType } from "./@types/event"; +import { MatrixClient } from "./client.ts"; +import { IEvent, MatrixEvent, MatrixEventEvent } from "./models/event.ts"; +import { RelationType } from "./@types/event.ts"; export type EventMapper = (obj: Partial) => MatrixEvent; diff --git a/src/extensible_events_v1/ExtensibleEvent.ts b/src/extensible_events_v1/ExtensibleEvent.ts index 049659251b6..3bfa0632ee8 100644 --- a/src/extensible_events_v1/ExtensibleEvent.ts +++ b/src/extensible_events_v1/ExtensibleEvent.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ExtensibleEventType, IPartialEvent } from "../@types/extensible_events"; +import { ExtensibleEventType, IPartialEvent } from "../@types/extensible_events.ts"; /** * Represents an Extensible Event in Matrix. diff --git a/src/extensible_events_v1/MessageEvent.ts b/src/extensible_events_v1/MessageEvent.ts index 3d049f45809..17457f04972 100644 --- a/src/extensible_events_v1/MessageEvent.ts +++ b/src/extensible_events_v1/MessageEvent.ts @@ -16,7 +16,7 @@ limitations under the License. import { Optional } from "matrix-events-sdk"; -import { ExtensibleEvent } from "./ExtensibleEvent"; +import { ExtensibleEvent } from "./ExtensibleEvent.ts"; import { ExtensibleEventType, IMessageRendering, @@ -26,9 +26,9 @@ import { M_MESSAGE, ExtensibleAnyMessageEventContent, M_TEXT, -} from "../@types/extensible_events"; -import { isOptionalAString, isProvided } from "./utilities"; -import { InvalidEventError } from "./InvalidEventError"; +} from "../@types/extensible_events.ts"; +import { isOptionalAString, isProvided } from "./utilities.ts"; +import { InvalidEventError } from "./InvalidEventError.ts"; /** * Represents a message event. Message events are the simplest form of event with diff --git a/src/extensible_events_v1/PollEndEvent.ts b/src/extensible_events_v1/PollEndEvent.ts index 243f1906acf..87cd49569ad 100644 --- a/src/extensible_events_v1/PollEndEvent.ts +++ b/src/extensible_events_v1/PollEndEvent.ts @@ -20,11 +20,11 @@ import { isEventTypeSame, M_TEXT, REFERENCE_RELATION, -} from "../@types/extensible_events"; -import { M_POLL_END, PollEndEventContent } from "../@types/polls"; -import { ExtensibleEvent } from "./ExtensibleEvent"; -import { InvalidEventError } from "./InvalidEventError"; -import { MessageEvent } from "./MessageEvent"; +} from "../@types/extensible_events.ts"; +import { M_POLL_END, PollEndEventContent } from "../@types/polls.ts"; +import { ExtensibleEvent } from "./ExtensibleEvent.ts"; +import { InvalidEventError } from "./InvalidEventError.ts"; +import { MessageEvent } from "./MessageEvent.ts"; /** * Represents a poll end/closure event. diff --git a/src/extensible_events_v1/PollResponseEvent.ts b/src/extensible_events_v1/PollResponseEvent.ts index a61fc2e7cb6..9e7659ba731 100644 --- a/src/extensible_events_v1/PollResponseEvent.ts +++ b/src/extensible_events_v1/PollResponseEvent.ts @@ -14,11 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ExtensibleEvent } from "./ExtensibleEvent"; -import { M_POLL_RESPONSE, PollResponseEventContent, PollResponseSubtype } from "../@types/polls"; -import { ExtensibleEventType, IPartialEvent, isEventTypeSame, REFERENCE_RELATION } from "../@types/extensible_events"; -import { InvalidEventError } from "./InvalidEventError"; -import { PollStartEvent } from "./PollStartEvent"; +import { ExtensibleEvent } from "./ExtensibleEvent.ts"; +import { M_POLL_RESPONSE, PollResponseEventContent, PollResponseSubtype } from "../@types/polls.ts"; +import { + ExtensibleEventType, + IPartialEvent, + isEventTypeSame, + REFERENCE_RELATION, +} from "../@types/extensible_events.ts"; +import { InvalidEventError } from "./InvalidEventError.ts"; +import { PollStartEvent } from "./PollStartEvent.ts"; /** * Represents a poll response event. diff --git a/src/extensible_events_v1/PollStartEvent.ts b/src/extensible_events_v1/PollStartEvent.ts index 8584bf9e1fc..98b15e2ada9 100644 --- a/src/extensible_events_v1/PollStartEvent.ts +++ b/src/extensible_events_v1/PollStartEvent.ts @@ -16,8 +16,8 @@ limitations under the License. import { NamespacedValue } from "matrix-events-sdk"; -import { MessageEvent } from "./MessageEvent"; -import { ExtensibleEventType, IPartialEvent, isEventTypeSame, M_TEXT } from "../@types/extensible_events"; +import { MessageEvent } from "./MessageEvent.ts"; +import { ExtensibleEventType, IPartialEvent, isEventTypeSame, M_TEXT } from "../@types/extensible_events.ts"; import { KnownPollKind, M_POLL_KIND_DISCLOSED, @@ -26,9 +26,9 @@ import { PollStartEventContent, PollStartSubtype, PollAnswer, -} from "../@types/polls"; -import { InvalidEventError } from "./InvalidEventError"; -import { ExtensibleEvent } from "./ExtensibleEvent"; +} from "../@types/polls.ts"; +import { InvalidEventError } from "./InvalidEventError.ts"; +import { ExtensibleEvent } from "./ExtensibleEvent.ts"; /** * Represents a poll answer. Note that this is represented as a subtype and is diff --git a/src/feature.ts b/src/feature.ts index 01cadd8e87c..47c914353bb 100644 --- a/src/feature.ts +++ b/src/feature.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IServerVersions } from "./client"; +import { IServerVersions } from "./client.ts"; export enum ServerSupport { Stable, @@ -33,6 +33,7 @@ export enum Feature { AccountDataDeletion = "AccountDataDeletion", RelationsRecursion = "RelationsRecursion", IntentionalMentions = "IntentionalMentions", + MigrateServerNameToVia = "MigrateServerNameToVia", } type FeatureSupportCondition = { @@ -65,6 +66,9 @@ const featureSupportResolver: Record = { unstablePrefixes: ["org.matrix.msc3952_intentional_mentions"], matrixVersion: "v1.7", }, + [Feature.MigrateServerNameToVia]: { + unstablePrefixes: ["org.matrix.msc4156"], + }, }; export async function buildFeatureSupportMap(versions: IServerVersions): Promise> { diff --git a/src/filter-component.ts b/src/filter-component.ts index 0954e634f6e..41f2903cb73 100644 --- a/src/filter-component.ts +++ b/src/filter-component.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RelationType } from "./@types/event"; -import { MatrixEvent } from "./models/event"; -import { FILTER_RELATED_BY_REL_TYPES, FILTER_RELATED_BY_SENDERS, THREAD_RELATION_TYPE } from "./models/thread"; +import { RelationType } from "./@types/event.ts"; +import { MatrixEvent } from "./models/event.ts"; +import { FILTER_RELATED_BY_REL_TYPES, FILTER_RELATED_BY_SENDERS, THREAD_RELATION_TYPE } from "./models/thread.ts"; /** * Checks if a value matches a given field value, which may be a * terminated diff --git a/src/filter.ts b/src/filter.ts index aea2fb4910d..d5ad00509d4 100644 --- a/src/filter.ts +++ b/src/filter.ts @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EventType, RelationType } from "./@types/event"; -import { UNREAD_THREAD_NOTIFICATIONS } from "./@types/sync"; -import { FilterComponent, IFilterComponent } from "./filter-component"; -import { MatrixEvent } from "./models/event"; +import { EventType, RelationType } from "./@types/event.ts"; +import { UNREAD_THREAD_NOTIFICATIONS } from "./@types/sync.ts"; +import { FilterComponent, IFilterComponent } from "./filter-component.ts"; +import { MatrixEvent } from "./models/event.ts"; /** */ diff --git a/src/http-api/errors.ts b/src/http-api/errors.ts index c5aba882bfb..86cfdc908c0 100644 --- a/src/http-api/errors.ts +++ b/src/http-api/errors.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IUsageLimit } from "../@types/partials"; -import { MatrixEvent } from "../models/event"; +import { IUsageLimit } from "../@types/partials.ts"; +import { MatrixEvent } from "../models/event.ts"; interface IErrorJson extends Partial { [key: string]: any; // extensible diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts index 274f39f0d41..3c98c10aa58 100644 --- a/src/http-api/fetch.ts +++ b/src/http-api/fetch.ts @@ -18,13 +18,13 @@ limitations under the License. * This is an internal module. See {@link MatrixHttpApi} for the public class. */ -import { checkObjectHasKeys, encodeParams } from "../utils"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { Method } from "./method"; -import { ConnectionError, MatrixError } from "./errors"; -import { HttpApiEvent, HttpApiEventHandlerMap, IHttpOpts, IRequestOpts, Body } from "./interface"; -import { anySignal, parseErrorResponse, timeoutSignal } from "./utils"; -import { QueryDict } from "../utils"; +import { checkObjectHasKeys, encodeParams } from "../utils.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { Method } from "./method.ts"; +import { ConnectionError, MatrixError } from "./errors.ts"; +import { HttpApiEvent, HttpApiEventHandlerMap, IHttpOpts, IRequestOpts, Body } from "./interface.ts"; +import { anySignal, parseErrorResponse, timeoutSignal } from "./utils.ts"; +import { QueryDict } from "../utils.ts"; interface TypedResponse extends Response { json(): Promise; diff --git a/src/http-api/index.ts b/src/http-api/index.ts index cd63f8d289c..abc7391da16 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -14,20 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { FetchHttpApi } from "./fetch"; -import { FileType, IContentUri, IHttpOpts, Upload, UploadOpts, UploadResponse } from "./interface"; -import { MediaPrefix } from "./prefix"; -import { defer, QueryDict, removeElement } from "../utils"; -import * as callbacks from "../realtime-callbacks"; -import { Method } from "./method"; -import { ConnectionError } from "./errors"; -import { parseErrorResponse } from "./utils"; - -export * from "./interface"; -export * from "./prefix"; -export * from "./errors"; -export * from "./method"; -export * from "./utils"; +import { FetchHttpApi } from "./fetch.ts"; +import { FileType, IContentUri, IHttpOpts, Upload, UploadOpts, UploadResponse } from "./interface.ts"; +import { MediaPrefix } from "./prefix.ts"; +import { defer, QueryDict, removeElement } from "../utils.ts"; +import * as callbacks from "../realtime-callbacks.ts"; +import { Method } from "./method.ts"; +import { ConnectionError } from "./errors.ts"; +import { parseErrorResponse } from "./utils.ts"; + +export * from "./interface.ts"; +export * from "./prefix.ts"; +export * from "./errors.ts"; +export * from "./method.ts"; +export * from "./utils.ts"; export class MatrixHttpApi extends FetchHttpApi { private uploads: Upload[] = []; diff --git a/src/http-api/interface.ts b/src/http-api/interface.ts index ee4456d7cc5..c06b850f311 100644 --- a/src/http-api/interface.ts +++ b/src/http-api/interface.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixError } from "./errors"; -import { Logger } from "../logger"; +import { MatrixError } from "./errors.ts"; +import { Logger } from "../logger.ts"; export type Body = Record | BodyInit; diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index 0b3c3554ffa..861d47ea1b0 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -16,9 +16,9 @@ limitations under the License. import { parse as parseContentType, ParsedMediaType } from "content-type"; -import { logger } from "../logger"; -import { sleep } from "../utils"; -import { ConnectionError, HTTPError, MatrixError } from "./errors"; +import { logger } from "../logger.ts"; +import { sleep } from "../utils.ts"; +import { ConnectionError, HTTPError, MatrixError } from "./errors.ts"; // Ponyfill for https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout export function timeoutSignal(ms: number): AbortSignal { diff --git a/src/index.ts b/src/index.ts index c9a5dcf65c0..65e798c870f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as matrixcs from "./matrix"; +import * as matrixcs from "./matrix.ts"; if (global.__js_sdk_entrypoint) { throw new Error("Multiple matrix-js-sdk entrypoints detected!"); } global.__js_sdk_entrypoint = true; -export * from "./matrix"; +export * from "./matrix.ts"; export default matrixcs; diff --git a/src/indexeddb-worker.ts b/src/indexeddb-worker.ts index 68dcf0f8006..15fc1bb8bd2 100644 --- a/src/indexeddb-worker.ts +++ b/src/indexeddb-worker.ts @@ -21,4 +21,4 @@ limitations under the License. */ /** The {@link IndexedDBStoreWorker} class. */ -export { IndexedDBStoreWorker } from "./store/indexeddb-store-worker"; +export { IndexedDBStoreWorker } from "./store/indexeddb-store-worker.ts"; diff --git a/src/interactive-auth.ts b/src/interactive-auth.ts index 8ecfc64a0d2..60c31d017f3 100644 --- a/src/interactive-auth.ts +++ b/src/interactive-auth.ts @@ -16,12 +16,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "./logger"; -import { MatrixClient } from "./client"; -import { defer, IDeferred } from "./utils"; -import { MatrixError } from "./http-api"; -import { UIAResponse } from "./@types/uia"; -import { UserIdentifier } from "./@types/auth"; +import { logger } from "./logger.ts"; +import { MatrixClient } from "./client.ts"; +import { defer, IDeferred } from "./utils.ts"; +import { MatrixError } from "./http-api/index.ts"; +import { UIAResponse } from "./@types/uia.ts"; +import { UserIdentifier } from "./@types/auth.ts"; const EMAIL_STAGE_TYPE = "m.login.email.identity"; const MSISDN_STAGE_TYPE = "m.login.msisdn"; diff --git a/src/matrix.ts b/src/matrix.ts index 793a894e0d0..cac7c91fd21 100644 --- a/src/matrix.ts +++ b/src/matrix.ts @@ -16,73 +16,74 @@ limitations under the License. import { WidgetApi } from "matrix-widget-api"; -import { MemoryCryptoStore } from "./crypto/store/memory-crypto-store"; -import { MemoryStore } from "./store/memory"; -import { MatrixScheduler } from "./scheduler"; -import { MatrixClient, ICreateClientOpts } from "./client"; -import { RoomWidgetClient, ICapabilities } from "./embedded"; -import { CryptoStore } from "./crypto/store/base"; +import { MemoryCryptoStore } from "./crypto/store/memory-crypto-store.ts"; +import { MemoryStore } from "./store/memory.ts"; +import { MatrixScheduler } from "./scheduler.ts"; +import { MatrixClient, ICreateClientOpts } from "./client.ts"; +import { RoomWidgetClient, ICapabilities } from "./embedded.ts"; +import { CryptoStore } from "./crypto/store/base.ts"; -export * from "./client"; -export * from "./embedded"; -export * from "./http-api"; -export * from "./autodiscovery"; -export * from "./sync-accumulator"; -export * from "./errors"; -export * from "./base64"; -export * from "./models/beacon"; -export * from "./models/event"; -export * from "./models/room"; -export * from "./models/event-timeline"; -export * from "./models/event-timeline-set"; -export * from "./models/poll"; -export * from "./models/room-member"; -export * from "./models/room-state"; -export * from "./models/thread"; -export * from "./models/typed-event-emitter"; -export * from "./models/user"; -export * from "./models/device"; -export * from "./models/search-result"; -export * from "./oidc"; -export * from "./scheduler"; -export * from "./filter"; -export * from "./timeline-window"; -export * from "./interactive-auth"; -export * from "./service-types"; -export * from "./store/memory"; -export * from "./store/indexeddb"; -export * from "./crypto/store/memory-crypto-store"; -export * from "./crypto/store/localStorage-crypto-store"; -export * from "./crypto/store/indexeddb-crypto-store"; -export type { OutgoingRoomKeyRequest } from "./crypto/store/base"; -export * from "./content-repo"; -export * from "./@types/common"; -export * from "./@types/uia"; -export * from "./@types/event"; -export * from "./@types/PushRules"; -export * from "./@types/partials"; -export * from "./@types/requests"; -export * from "./@types/search"; -export * from "./@types/beacon"; -export * from "./@types/topic"; -export * from "./@types/location"; -export * from "./@types/threepids"; -export * from "./@types/auth"; -export * from "./@types/polls"; -export * from "./@types/local_notifications"; -export * from "./@types/registration"; -export * from "./@types/read_receipts"; -export * from "./@types/crypto"; -export * from "./@types/extensible_events"; -export * from "./@types/IIdentityServerProvider"; -export * from "./models/room-summary"; -export * from "./models/event-status"; -export type { RoomSummary } from "./client"; -export * as ContentHelpers from "./content-helpers"; -export * as SecretStorage from "./secret-storage"; -export type { ICryptoCallbacks } from "./crypto"; // used to be located here -export { createNewMatrixCall, CallEvent } from "./webrtc/call"; -export type { MatrixCall } from "./webrtc/call"; +export * from "./client.ts"; +export * from "./serverCapabilities.ts"; +export * from "./embedded.ts"; +export * from "./http-api/index.ts"; +export * from "./autodiscovery.ts"; +export * from "./sync-accumulator.ts"; +export * from "./errors.ts"; +export * from "./base64.ts"; +export * from "./models/beacon.ts"; +export * from "./models/event.ts"; +export * from "./models/room.ts"; +export * from "./models/event-timeline.ts"; +export * from "./models/event-timeline-set.ts"; +export * from "./models/poll.ts"; +export * from "./models/room-member.ts"; +export * from "./models/room-state.ts"; +export * from "./models/thread.ts"; +export * from "./models/typed-event-emitter.ts"; +export * from "./models/user.ts"; +export * from "./models/device.ts"; +export * from "./models/search-result.ts"; +export * from "./oidc/index.ts"; +export * from "./scheduler.ts"; +export * from "./filter.ts"; +export * from "./timeline-window.ts"; +export * from "./interactive-auth.ts"; +export * from "./service-types.ts"; +export * from "./store/memory.ts"; +export * from "./store/indexeddb.ts"; +export * from "./crypto/store/memory-crypto-store.ts"; +export * from "./crypto/store/localStorage-crypto-store.ts"; +export * from "./crypto/store/indexeddb-crypto-store.ts"; +export type { OutgoingRoomKeyRequest } from "./crypto/store/base.ts"; +export * from "./content-repo.ts"; +export * from "./@types/common.ts"; +export * from "./@types/uia.ts"; +export * from "./@types/event.ts"; +export * from "./@types/PushRules.ts"; +export * from "./@types/partials.ts"; +export * from "./@types/requests.ts"; +export * from "./@types/search.ts"; +export * from "./@types/beacon.ts"; +export * from "./@types/topic.ts"; +export * from "./@types/location.ts"; +export * from "./@types/threepids.ts"; +export * from "./@types/auth.ts"; +export * from "./@types/polls.ts"; +export * from "./@types/local_notifications.ts"; +export * from "./@types/registration.ts"; +export * from "./@types/read_receipts.ts"; +export * from "./@types/crypto.ts"; +export * from "./@types/extensible_events.ts"; +export * from "./@types/IIdentityServerProvider.ts"; +export * from "./models/room-summary.ts"; +export * from "./models/event-status.ts"; +export type { RoomSummary } from "./client.ts"; +export * as ContentHelpers from "./content-helpers.ts"; +export * as SecretStorage from "./secret-storage.ts"; +export type { ICryptoCallbacks } from "./crypto/index.ts"; // used to be located here +export { createNewMatrixCall, CallEvent } from "./webrtc/call.ts"; +export type { MatrixCall } from "./webrtc/call.ts"; export { GroupCall, GroupCallEvent, @@ -90,21 +91,21 @@ export { GroupCallState, GroupCallType, GroupCallStatsReportEvent, -} from "./webrtc/groupCall"; -export { CryptoEvent } from "./crypto"; -export { SyncState, SetPresence } from "./sync"; -export type { ISyncStateData as SyncStateData } from "./sync"; -export { SlidingSyncEvent } from "./sliding-sync"; -export { MediaHandlerEvent } from "./webrtc/mediaHandler"; -export { CallFeedEvent } from "./webrtc/callFeed"; -export { StatsReport } from "./webrtc/stats/statsReport"; -export { Relations, RelationsEvent } from "./models/relations"; -export { TypedEventEmitter } from "./models/typed-event-emitter"; -export { LocalStorageErrors } from "./store/local-storage-events-emitter"; -export { IdentityProviderBrand, SSOAction } from "./@types/auth"; -export type { ISSOFlow as SSOFlow, LoginFlow } from "./@types/auth"; -export type { IHierarchyRelation as HierarchyRelation, IHierarchyRoom as HierarchyRoom } from "./@types/spaces"; -export { LocationAssetType } from "./@types/location"; +} from "./webrtc/groupCall.ts"; +export { CryptoEvent } from "./crypto/index.ts"; +export { SyncState, SetPresence } from "./sync.ts"; +export type { ISyncStateData as SyncStateData } from "./sync.ts"; +export { SlidingSyncEvent } from "./sliding-sync.ts"; +export { MediaHandlerEvent } from "./webrtc/mediaHandler.ts"; +export { CallFeedEvent } from "./webrtc/callFeed.ts"; +export { StatsReport } from "./webrtc/stats/statsReport.ts"; +export { Relations, RelationsEvent } from "./models/relations.ts"; +export { TypedEventEmitter } from "./models/typed-event-emitter.ts"; +export { LocalStorageErrors } from "./store/local-storage-events-emitter.ts"; +export { IdentityProviderBrand, SSOAction } from "./@types/auth.ts"; +export type { ISSOFlow as SSOFlow, LoginFlow } from "./@types/auth.ts"; +export type { IHierarchyRelation as HierarchyRelation, IHierarchyRoom as HierarchyRoom } from "./@types/spaces.ts"; +export { LocationAssetType } from "./@types/location.ts"; /** * Types supporting cryptography. @@ -112,7 +113,7 @@ export { LocationAssetType } from "./@types/location"; * The most important is {@link Crypto.CryptoApi}, an instance of which can be retrieved via * {@link MatrixClient.getCrypto}. */ -export * as Crypto from "./crypto-api"; +export * as Crypto from "./crypto-api/index.ts"; let cryptoStoreFactory = (): CryptoStore => new MemoryCryptoStore(); diff --git a/src/matrixrtc/CallMembership.ts b/src/matrixrtc/CallMembership.ts index 171751f1d1f..495ce1c4947 100644 --- a/src/matrixrtc/CallMembership.ts +++ b/src/matrixrtc/CallMembership.ts @@ -14,52 +14,114 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixEvent } from "../matrix"; -import { deepCompare } from "../utils"; -import { Focus } from "./focus"; +import { EitherAnd } from "matrix-events-sdk/lib/types"; -type CallScope = "m.room" | "m.user"; +import { MatrixEvent } from "../matrix.ts"; +import { deepCompare } from "../utils.ts"; +import { Focus } from "./focus.ts"; +import { isLivekitFocusActive } from "./LivekitFocus.ts"; +type CallScope = "m.room" | "m.user"; // Represents an entry in the memberships section of an m.call.member event as it is on the wire -export interface CallMembershipData { - application?: string; + +// There are two different data interfaces. One for the Legacy types and one compliant with MSC4143 + +// MSC4143 (MatrixRTC) session membership data + +export type SessionMembershipData = { + application: string; + call_id: string; + device_id: string; + + focus_active: Focus; + foci_preferred: Focus[]; + created_ts?: number; + + // Application specific data + scope?: CallScope; +}; + +export const isSessionMembershipData = (data: CallMembershipData): data is SessionMembershipData => + "focus_active" in data; + +const checkSessionsMembershipData = (data: any, errors: string[]): data is SessionMembershipData => { + const prefix = "Malformed session membership event: "; + if (typeof data.device_id !== "string") errors.push(prefix + "device_id must be string"); + if (typeof data.call_id !== "string") errors.push(prefix + "call_id must be string"); + if (typeof data.application !== "string") errors.push(prefix + "application must be a string"); + if (typeof data.focus_active?.type !== "string") errors.push(prefix + "focus_active.type must be a string"); + if (!Array.isArray(data.foci_preferred)) errors.push(prefix + "foci_preferred must be an array"); + // optional parameters + if (data.created_ts && typeof data.created_ts !== "number") errors.push(prefix + "created_ts must be number"); + + // application specific data (we first need to check if they exist) + if (data.scope && typeof data.scope !== "string") errors.push(prefix + "scope must be string"); + return errors.length === 0; +}; + +// Legacy session membership data + +export type CallMembershipDataLegacy = { + application: string; call_id: string; scope: CallScope; device_id: string; + membershipID: string; created_ts?: number; - expires?: number; - expires_ts?: number; foci_active?: Focus[]; - membershipID: string; -} +} & EitherAnd<{ expires: number }, { expires_ts: number }>; + +export const isLegacyCallMembershipData = (data: CallMembershipData): data is CallMembershipDataLegacy => + "membershipID" in data; + +const checkCallMembershipDataLegacy = (data: any, errors: string[]): data is CallMembershipDataLegacy => { + const prefix = "Malformed legacy rtc membership event: "; + if (!("expires" in data || "expires_ts" in data)) { + errors.push(prefix + "expires_ts or expires must be present"); + } + if ("expires" in data) { + if (typeof data.expires !== "number") { + errors.push(prefix + "expires must be numeric"); + } + } + if ("expires_ts" in data) { + if (typeof data.expires_ts !== "number") { + errors.push(prefix + "expires_ts must be numeric"); + } + } + + if (typeof data.device_id !== "string") errors.push(prefix + "device_id must be string"); + if (typeof data.call_id !== "string") errors.push(prefix + "call_id must be string"); + if (typeof data.application !== "string") errors.push(prefix + "application must be a string"); + if (typeof data.membershipID !== "string") errors.push(prefix + "membershipID must be a string"); + // optional elements + if (data.created_ts && typeof data.created_ts !== "number") errors.push(prefix + "created_ts must be number"); + // application specific data (we first need to check if they exist) + if (data.scope && typeof data.scope !== "string") errors.push(prefix + "scope must be string"); + return errors.length === 0; +}; + +export type CallMembershipData = CallMembershipDataLegacy | SessionMembershipData; export class CallMembership { public static equal(a: CallMembership, b: CallMembership): boolean { - return deepCompare(a.data, b.data); + return deepCompare(a.membershipData, b.membershipData); } + private membershipData: CallMembershipData; public constructor( private parentEvent: MatrixEvent, - private data: CallMembershipData, + data: any, ) { - if (!(data.expires || data.expires_ts)) { - throw new Error("Malformed membership: expires_ts or expires must be present"); - } - if (data.expires) { - if (typeof data.expires !== "number") { - throw new Error("Malformed membership: expires must be numeric"); - } - } - if (data.expires_ts) { - if (typeof data.expires_ts !== "number") { - throw new Error("Malformed membership: expires_ts must be numeric"); - } + const sessionErrors: string[] = []; + const legacyErrors: string[] = []; + if (!checkSessionsMembershipData(data, sessionErrors) && !checkCallMembershipDataLegacy(data, legacyErrors)) { + throw Error( + `unknown CallMembership data. Does not match legacy call.member (${legacyErrors.join(" & ")}) events nor MSC4143 (${sessionErrors.join(" & ")})`, + ); + } else { + this.membershipData = data; } - - if (typeof data.device_id !== "string") throw new Error("Malformed membership event: device_id must be string"); - if (typeof data.call_id !== "string") throw new Error("Malformed membership event: call_id must be string"); - if (typeof data.scope !== "string") throw new Error("Malformed membership event: scope must be string"); - if (!parentEvent.getSender()) throw new Error("Invalid parent event: sender is null"); } public get sender(): string | undefined { @@ -67,62 +129,115 @@ export class CallMembership { } public get callId(): string { - return this.data.call_id; + return this.membershipData.call_id; } public get deviceId(): string { - return this.data.device_id; + return this.membershipData.device_id; } public get application(): string | undefined { - return this.data.application; + return this.membershipData.application; } - public get scope(): CallScope { - return this.data.scope; + public get scope(): CallScope | undefined { + return this.membershipData.scope; } public get membershipID(): string { - return this.data.membershipID; + if (isLegacyCallMembershipData(this.membershipData)) return this.membershipData.membershipID; + // the createdTs behaves equivalent to the membershipID. + // we only need the field for the legacy member envents where we needed to update them + // synapse ignores sending state events if they have the same content. + else return this.createdTs().toString(); } public createdTs(): number { - return this.data.created_ts ?? this.parentEvent.getTs(); + return this.membershipData.created_ts ?? this.parentEvent.getTs(); } - public getAbsoluteExpiry(): number { - if (this.data.expires) { - return this.createdTs() + this.data.expires; + /** + * Gets the absolute expiry time of the membership if applicable to this membership type. + * @returns The absolute expiry time of the membership as a unix timestamp in milliseconds or undefined if not applicable + */ + public getAbsoluteExpiry(): number | undefined { + // if the membership is not a legacy membership, we assume it is MSC4143 + if (!isLegacyCallMembershipData(this.membershipData)) return undefined; + + if ("expires" in this.membershipData) { + // we know createdTs exists since we already do the isLegacyCallMembershipData check + return this.createdTs() + this.membershipData.expires; } else { // We know it exists because we checked for this in the constructor. - return this.data.expires_ts!; + return this.membershipData.expires_ts; } } - // gets the expiry time of the event, converted into the device's local time - public getLocalExpiry(): number { - if (this.data.expires) { + /** + * Gets the expiry time of the event, converted into the device's local time. + * @deprecated This function has been observed returning bad data and is no longer used by MatrixRTC. + * @returns The local expiry time of the membership as a unix timestamp in milliseconds or undefined if not applicable + */ + public getLocalExpiry(): number | undefined { + // if the membership is not a legacy membership, we assume it is MSC4143 + if (!isLegacyCallMembershipData(this.membershipData)) return undefined; + + if ("expires" in this.membershipData) { + // we know createdTs exists since we already do the isLegacyCallMembershipData check const relativeCreationTime = this.parentEvent.getTs() - this.createdTs(); const localCreationTs = this.parentEvent.localTimestamp - relativeCreationTime; - return localCreationTs + this.data.expires; + return localCreationTs + this.membershipData.expires; } else { // With expires_ts we cannot convert to local time. // TODO: Check the server timestamp and compute a diff to local time. - return this.data.expires_ts!; + return this.membershipData.expires_ts; } } - public getMsUntilExpiry(): number { - return this.getLocalExpiry() - Date.now(); + /** + * @returns The number of milliseconds until the membership expires or undefined if applicable + */ + public getMsUntilExpiry(): number | undefined { + if (isLegacyCallMembershipData(this.membershipData)) { + // Assume that local clock is sufficiently in sync with other clocks in the distributed system. + // We used to try and adjust for the local clock being skewed, but there are cases where this is not accurate. + // The current implementation allows for the local clock to be -infinity to +MatrixRTCSession.MEMBERSHIP_EXPIRY_TIME/2 + return this.getAbsoluteExpiry()! - Date.now(); + } + + // Assumed to be MSC4143 + return undefined; } + /** + * @returns true if the membership has expired, otherwise false + */ public isExpired(): boolean { - return this.getMsUntilExpiry() <= 0; + if (isLegacyCallMembershipData(this.membershipData)) return this.getMsUntilExpiry()! <= 0; + + // MSC4143 events expire by being updated. So if the event exists, its not expired. + return false; + } + + public getPreferredFoci(): Focus[] { + // To support both, the new and the old MatrixRTC memberships have two cases based + // on the availablitiy of `foci_preferred` + if (isLegacyCallMembershipData(this.membershipData)) return this.membershipData.foci_active ?? []; + + // MSC4143 style membership + return this.membershipData.foci_preferred; } - public getActiveFoci(): Focus[] { - return this.data.foci_active ?? []; + public getFocusSelection(): string | undefined { + if (isLegacyCallMembershipData(this.membershipData)) { + return "oldest_membership"; + } else { + const focusActive = this.membershipData.focus_active; + if (isLivekitFocusActive(focusActive)) { + return focusActive.focus_selection; + } + } } } diff --git a/src/matrixrtc/LivekitFocus.ts b/src/matrixrtc/LivekitFocus.ts new file mode 100644 index 00000000000..254c715410e --- /dev/null +++ b/src/matrixrtc/LivekitFocus.ts @@ -0,0 +1,39 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Focus } from "./focus.ts"; + +export interface LivekitFocusConfig extends Focus { + type: "livekit"; + livekit_service_url: string; +} + +export const isLivekitFocusConfig = (object: any): object is LivekitFocusConfig => + object.type === "livekit" && "livekit_service_url" in object; + +export interface LivekitFocus extends LivekitFocusConfig { + livekit_alias: string; +} + +export const isLivekitFocus = (object: any): object is LivekitFocus => + isLivekitFocusConfig(object) && "livekit_alias" in object; + +export interface LivekitFocusActive extends Focus { + type: "livekit"; + focus_selection: "oldest_membership"; +} +export const isLivekitFocusActive = (object: any): object is LivekitFocusActive => + object.type === "livekit" && "focus_selection" in object; diff --git a/src/matrixrtc/MatrixRTCSession.ts b/src/matrixrtc/MatrixRTCSession.ts index 7421723ecb4..ebd69400a90 100644 --- a/src/matrixrtc/MatrixRTCSession.ts +++ b/src/matrixrtc/MatrixRTCSession.ts @@ -14,21 +14,32 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../logger"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { EventTimeline } from "../models/event-timeline"; -import { Room } from "../models/room"; -import { MatrixClient } from "../client"; -import { EventType } from "../@types/event"; -import { CallMembership, CallMembershipData } from "./CallMembership"; -import { RoomStateEvent } from "../models/room-state"; -import { Focus } from "./focus"; -import { randomString, secureRandomBase64Url } from "../randomstring"; -import { EncryptionKeysEventContent } from "./types"; -import { decodeBase64, encodeUnpaddedBase64 } from "../base64"; -import { KnownMembership } from "../@types/membership"; -import { MatrixError } from "../http-api/errors"; -import { MatrixEvent } from "../models/event"; +import { logger as rootLogger } from "../logger.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { EventTimeline } from "../models/event-timeline.ts"; +import { Room } from "../models/room.ts"; +import { MatrixClient } from "../client.ts"; +import { EventType } from "../@types/event.ts"; +import { UpdateDelayedEventAction } from "../@types/requests.ts"; +import { + CallMembership, + CallMembershipData, + CallMembershipDataLegacy, + SessionMembershipData, + isLegacyCallMembershipData, +} from "./CallMembership.ts"; +import { RoomStateEvent } from "../models/room-state.ts"; +import { Focus } from "./focus.ts"; +import { randomString, secureRandomBase64Url } from "../randomstring.ts"; +import { EncryptionKeysEventContent } from "./types.ts"; +import { decodeBase64, encodeUnpaddedBase64 } from "../base64.ts"; +import { KnownMembership } from "../@types/membership.ts"; +import { MatrixError } from "../http-api/errors.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { isLivekitFocusActive } from "./LivekitFocus.ts"; +import { ExperimentalGroupCallRoomMemberState } from "../webrtc/groupCall.ts"; + +const logger = rootLogger.getChild("MatrixRTCSession"); const MEMBERSHIP_EXPIRY_TIME = 60 * 60 * 1000; const MEMBER_EVENT_CHECK_PERIOD = 2 * 60 * 1000; // How often we check to see if we need to re-send our member event @@ -47,9 +58,9 @@ const USE_KEY_DELAY = 5000; const getParticipantId = (userId: string, deviceId: string): string => `${userId}:${deviceId}`; const getParticipantIdFromMembership = (m: CallMembership): string => getParticipantId(m.sender!, m.deviceId); -function keysEqual(a: Uint8Array, b: Uint8Array): boolean { +function keysEqual(a: Uint8Array | undefined, b: Uint8Array | undefined): boolean { if (a === b) return true; - return a && b && a.length === b.length && a.every((x, i) => x === b[i]); + return !!a && !!b && a.length === b.length && a.every((x, i) => x === b[i]); } export enum MatrixRTCSessionEvent { @@ -57,7 +68,7 @@ export enum MatrixRTCSessionEvent { MembershipsChanged = "memberships_changed", // We joined or left the session: our own local idea of whether we are joined, // separate from MembershipsChanged, ie. independent of whether our member event - // has succesfully gone through. + // has successfully gone through. JoinStateChanged = "join_state_changed", // The key used to encrypt media has changed EncryptionKeyChanged = "encryption_key_changed", @@ -75,7 +86,20 @@ export type MatrixRTCSessionEventHandlerMap = { participantId: string, ) => void; }; - +export interface JoinSessionConfig { + /** If true, generate and share a media key for this participant, + * and emit MatrixRTCSessionEvent.EncryptionKeyChanged when + * media keys for other participants become available. + */ + manageMediaKeys?: boolean; + /** Lets you configure how the events for the session are formatted. + * - legacy: use one event with a membership array. + * - MSC4143: use one event per membership (with only one membership per event) + * More details can be found in MSC4143 and by checking the types: + * `CallMembershipDataLegacy` and `SessionMembershipData` + */ + useLegacyMemberEvents?: boolean; +} /** * A MatrixRTCSession manages the membership & properties of a MatrixRTC session. * This class doesn't deal with media at all, just membership & properties of a session. @@ -102,16 +126,24 @@ export class MatrixRTCSession extends TypedEventEmitter; private setNewKeyTimeouts = new Set>(); - private activeFoci: Focus[] | undefined; + // This is a Focus with the specified fields for an ActiveFocus (e.g. LivekitFocusActive for type="livekit") + private ownFocusActive?: Focus; + // This is a Foci array that contains the Focus objects this user is aware of and proposes to use. + private ownFociPreferred?: Focus[]; private updateCallMembershipRunning = false; private needCallMembershipUpdate = false; private manageMediaKeys = false; - // userId:deviceId => array of keys - private encryptionKeys = new Map>(); + private useLegacyMemberEvents = true; + // userId:deviceId => array of (key, timestamp) + private encryptionKeys = new Map>(); private lastEncryptionKeyUpdateRequest?: number; + // We use this to store the last membership fingerprints we saw, so we can proactively re-send encryption keys + // if it looks like a membership has been updated. + private lastMembershipFingerprints: Set | undefined; + /** * The callId (sessionId) of the call. * @@ -134,21 +166,34 @@ export class MatrixRTCSession extends TypedEventEmitter 1 && "focus_active" in content) { + // We have a MSC4143 event membership event + membershipContents.push(content); + } else if (eventKeysCount === 1 && "memberships" in content) { + // we have a legacy (one event for all devices) event + if (!Array.isArray(content["memberships"])) { + logger.warn(`Malformed member event from ${memberEvent.getSender()}: memberships is not an array`); + continue; + } + membershipContents = content["memberships"]; } - for (const membershipData of eventMemberships) { + if (membershipContents.length === 0) continue; + + for (const membershipData of membershipContents) { try { const membership = new CallMembership(memberEvent, membershipData); if (membership.callId !== "" || membership.scope !== "m.room") { - // for now, just ignore anything that isn't the a room scope call + // for now, just ignore anything that isn't a room scope call logger.info(`Ignoring user-scoped call`); continue; } @@ -202,6 +247,7 @@ export class MatrixRTCSession extends TypedEventEmitter | undefined { - return this.encryptionKeys.get(getParticipantId(userId, deviceId)); + return this.encryptionKeys.get(getParticipantId(userId, deviceId))?.map((entry) => entry.key); } /** @@ -324,7 +396,10 @@ export class MatrixRTCSession extends TypedEventEmitter]> { - return this.encryptionKeys.entries(); + // the returned array doesn't contain the timestamps + return Array.from(this.encryptionKeys.entries()) + .map(([participantId, keys]): [string, Uint8Array[]] => [participantId, keys.map((k) => k.key)]) + .values(); } private getNewEncryptionKeyIndex(): number { @@ -339,13 +414,15 @@ export class MatrixRTCSession extends TypedEventEmitter timestamp) { + logger.info( + `Ignoring new key at index ${encryptionKeyIndex} for ${participantId} as it is older than existing known key`, + ); + return; + } + + if (keysEqual(existingKeyAtIndex.key, keyBin)) { + existingKeyAtIndex.timestamp = timestamp; + return; + } + } - if (keysEqual(encryptionKeys[encryptionKeyIndex], keyBin)) return; + participantKeys[encryptionKeyIndex] = { + key: keyBin, + timestamp, + }; - encryptionKeys[encryptionKeyIndex] = keyBin; - this.encryptionKeys.set(participantId, encryptionKeys); - if (delayBeforeuse) { + if (delayBeforeUse) { const useKeyTimeout = setTimeout(() => { this.setNewKeyTimeouts.delete(useKeyTimeout); logger.info(`Delayed-emitting key changed event for ${participantId} idx ${encryptionKeyIndex}`); @@ -379,7 +477,7 @@ export class MatrixRTCSession extends TypedEventEmitter { const userId = event.getSender(); const content = event.getContent(); @@ -563,11 +677,19 @@ export class MatrixRTCSession extends TypedEventEmitter + m.sender === this.client.getUserId() && m.deviceId === this.client.getDeviceId(); + + /** + * Examines the latest call memberships and handles any encryption key sending or rotation that is needed. + * + * This function should be called when the room members or call memberships might have changed. + */ public onMembershipUpdate = (): void => { const oldMemberships = this.memberships; this.memberships = MatrixRTCSession.callMembershipsForRoom(this.room); @@ -583,19 +705,22 @@ export class MatrixRTCSession extends TypedEventEmitter - m.sender === this.client.getUserId() && m.deviceId === this.client.getDeviceId(); - if (this.manageMediaKeys && this.isJoined() && this.makeNewKeyTimeout === undefined) { - const oldMebershipIds = new Set( - oldMemberships.filter((m) => !isMyMembership(m)).map(getParticipantIdFromMembership), + const oldMembershipIds = new Set( + oldMemberships.filter((m) => !this.isMyMembership(m)).map(getParticipantIdFromMembership), ); - const newMebershipIds = new Set( - this.memberships.filter((m) => !isMyMembership(m)).map(getParticipantIdFromMembership), + const newMembershipIds = new Set( + this.memberships.filter((m) => !this.isMyMembership(m)).map(getParticipantIdFromMembership), ); - const anyLeft = Array.from(oldMebershipIds).some((x) => !newMebershipIds.has(x)); - const anyJoined = Array.from(newMebershipIds).some((x) => !oldMebershipIds.has(x)); + // We can use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/symmetricDifference + // for this once available + const anyLeft = Array.from(oldMembershipIds).some((x) => !newMembershipIds.has(x)); + const anyJoined = Array.from(newMembershipIds).some((x) => !oldMembershipIds.has(x)); + + const oldFingerprints = this.lastMembershipFingerprints; + // always store the fingerprints of these latest memberships + this.storeLastMembershipFingerprints(); if (anyLeft) { logger.debug(`Member(s) have left: queueing sender key rotation`); @@ -603,40 +728,72 @@ export class MatrixRTCSession extends TypedEventEmitter !newFingerprints.has(x)) || + Array.from(newFingerprints).some((x) => !oldFingerprints.has(x)); + if (candidateUpdates) { + logger.debug(`Member(s) have updated/reconnected: re-sending keys`); + this.requestKeyEventSend(); + } } } this.setExpiryTimer(); }; + private storeLastMembershipFingerprints(): void { + this.lastMembershipFingerprints = new Set( + this.memberships + .filter((m) => !this.isMyMembership(m)) + .map((m) => `${getParticipantIdFromMembership(m)}:${m.membershipID}:${m.createdTs()}`), + ); + } + /** * Constructs our own membership * @param prevMembership - The previous value of our call membership, if any */ - private makeMyMembership(prevMembership?: CallMembership): CallMembershipData { + private makeMyMembershipLegacy(deviceId: string, prevMembership?: CallMembership): CallMembershipDataLegacy { if (this.relativeExpiry === undefined) { throw new Error("Tried to create our own membership event when we're not joined!"); } if (this.membershipId === undefined) { throw new Error("Tried to create our own membership event when we have no membership ID!"); } - - const m: CallMembershipData = { + const createdTs = prevMembership?.createdTs(); + return { call_id: "", scope: "m.room", application: "m.call", - device_id: this.client.getDeviceId()!, + device_id: deviceId, expires: this.relativeExpiry, - foci_active: this.activeFoci, + // TODO: Date.now() should be the origin_server_ts (now). + expires_ts: this.relativeExpiry + (createdTs ?? Date.now()), + // we use the fociPreferred since this is the list of foci. + // it is named wrong in the Legacy events. + foci_active: this.ownFociPreferred, membershipID: this.membershipId, + ...(createdTs ? { created_ts: createdTs } : {}), + }; + } + /** + * Constructs our own membership + */ + private makeMyMembership(deviceId: string): SessionMembershipData { + return { + call_id: "", + scope: "m.room", + application: "m.call", + device_id: deviceId, + focus_active: { type: "livekit", focus_selection: "oldest_membership" }, + foci_preferred: this.ownFociPreferred ?? [], }; - - if (prevMembership) m.created_ts = prevMembership.createdTs(); - if (m.created_ts) m.expires_ts = m.created_ts + (m.expires ?? 0); - // TODO: Date.now() should be the origin_server_ts (now). - else m.expires_ts = Date.now() + (m.expires ?? 0); - - return m; } /** @@ -646,36 +803,41 @@ export class MatrixRTCSession extends TypedEventEmitter { let membershipObj; try { @@ -704,10 +866,10 @@ export class MatrixRTCSession extends TypedEventEmitter => { @@ -741,57 +903,128 @@ export class MatrixRTCSession extends TypedEventEmitter>() ?? {}; - const memberships: CallMembershipData[] = Array.isArray(content["memberships"]) ? content["memberships"] : []; - - const myPrevMembershipData = memberships.find((m) => m.device_id === localDeviceId); - let myPrevMembership; - try { - if (myCallMemberEvent && myPrevMembershipData && myPrevMembershipData.membershipID === this.membershipId) { - myPrevMembership = new CallMembership(myCallMemberEvent, myPrevMembershipData); + const callMemberEvents = roomState.events.get(EventType.GroupCallMemberPrefix); + const legacy = this.stateEventsContainOngoingLegacySession(callMemberEvents); + let newContent: {} | ExperimentalGroupCallRoomMemberState | SessionMembershipData = {}; + if (legacy) { + const myCallMemberEvent = callMemberEvents?.get(localUserId); + const content = myCallMemberEvent?.getContent() ?? {}; + let myPrevMembership: CallMembership | undefined; + // We know its CallMembershipDataLegacy + const memberships: CallMembershipDataLegacy[] = Array.isArray(content["memberships"]) + ? content["memberships"] + : []; + const myPrevMembershipData = memberships.find((m) => m.device_id === localDeviceId); + try { + if ( + myCallMemberEvent && + myPrevMembershipData && + isLegacyCallMembershipData(myPrevMembershipData) && + myPrevMembershipData.membershipID === this.membershipId + ) { + myPrevMembership = new CallMembership(myCallMemberEvent, myPrevMembershipData); + } + } catch (e) { + // This would indicate a bug or something weird if our own call membership + // wasn't valid + logger.warn("Our previous call membership was invalid - this shouldn't happen.", e); } - } catch (e) { - // This would indicate a bug or something weird if our own call membership - // wasn't valid - logger.warn("Our previous call membership was invalid - this shouldn't happen.", e); - } - - if (myPrevMembership) { - logger.debug(`${myPrevMembership.getMsUntilExpiry()} until our membership expires`); - } - - if (!this.membershipEventNeedsUpdate(myPrevMembershipData, myPrevMembership)) { - // nothing to do - reschedule the check again - this.memberEventTimeout = setTimeout(this.triggerCallMembershipEventUpdate, MEMBER_EVENT_CHECK_PERIOD); - return; + if (myPrevMembership) { + logger.debug(`${myPrevMembership.getMsUntilExpiry()} until our membership expires`); + } + if (!this.membershipEventNeedsUpdate(myPrevMembershipData, myPrevMembership)) { + // nothing to do - reschedule the check again + this.memberEventTimeout = setTimeout(this.triggerCallMembershipEventUpdate, MEMBER_EVENT_CHECK_PERIOD); + return; + } + newContent = this.makeNewLegacyMemberships(memberships, localDeviceId, myCallMemberEvent, myPrevMembership); + } else { + newContent = this.makeNewMembership(localDeviceId); } - const newContent = { - memberships: this.makeNewMemberships(memberships, myCallMemberEvent, myPrevMembership), - }; - + const stateKey = legacy ? localUserId : this.makeMembershipStateKey(localUserId, localDeviceId); try { - await this.client.sendStateEvent( - this.room.roomId, - EventType.GroupCallMemberPrefix, - newContent, - localUserId, - ); + await this.client.sendStateEvent(this.room.roomId, EventType.GroupCallMemberPrefix, newContent, stateKey); logger.info(`Sent updated call member event.`); // check periodically to see if we need to refresh our member event if (this.isJoined()) { - this.memberEventTimeout = setTimeout(this.triggerCallMembershipEventUpdate, MEMBER_EVENT_CHECK_PERIOD); + if (legacy) { + this.memberEventTimeout = setTimeout( + this.triggerCallMembershipEventUpdate, + MEMBER_EVENT_CHECK_PERIOD, + ); + } else { + try { + // TODO: If delayed event times out, re-join! + const res = await this.client._unstable_sendDelayedStateEvent( + this.room.roomId, + { + delay: 8000, + }, + EventType.GroupCallMemberPrefix, + {}, // leave event + stateKey, + ); + this.scheduleDelayDisconnection(res.delay_id); + } catch (e) { + logger.error("Failed to send delayed event:", e); + } + } } } catch (e) { const resendDelay = CALL_MEMBER_EVENT_RETRY_DELAY_MIN + Math.random() * 2000; - logger.warn(`Failed to send call member event: retrying in ${resendDelay}`); + logger.warn(`Failed to send call member event (retrying in ${resendDelay}): ${e}`); await new Promise((resolve) => setTimeout(resolve, resendDelay)); await this.triggerCallMembershipEventUpdate(); } } + private scheduleDelayDisconnection(delayId: string): void { + this.memberEventTimeout = setTimeout(() => this.delayDisconnection(delayId), 5000); + } + + private async delayDisconnection(delayId: string): Promise { + try { + await this.client._unstable_updateDelayedEvent(delayId, UpdateDelayedEventAction.Restart); + this.scheduleDelayDisconnection(delayId); + } catch (e) { + logger.error("Failed to delay our disconnection event", e); + } + } + + private stateEventsContainOngoingLegacySession(callMemberEvents: Map | undefined): boolean { + if (!callMemberEvents?.size) { + return this.useLegacyMemberEvents; + } + + let containsAnyOngoingSession = false; + let containsUnknownOngoingSession = false; + for (const callMemberEvent of callMemberEvents.values()) { + const content = callMemberEvent.getContent(); + if (Array.isArray(content["memberships"])) { + for (const membership of content.memberships) { + if (!new CallMembership(callMemberEvent, membership).isExpired()) { + return true; + } + } + } else if (Object.keys(content).length > 0) { + containsAnyOngoingSession ||= true; + containsUnknownOngoingSession ||= !("focus_active" in content); + } + } + return containsAnyOngoingSession && !containsUnknownOngoingSession ? false : this.useLegacyMemberEvents; + } + + private makeMembershipStateKey(localUserId: string, localDeviceId: string): string { + const stateKey = `${localUserId}_${localDeviceId}`; + if (/^org\.matrix\.msc(3757|3779)\b/.exec(this.room.getVersion())) { + return stateKey; + } else { + return `_${stateKey}`; + } + } + private onRotateKeyTimeout = (): void => { if (!this.manageMediaKeys) return; diff --git a/src/matrixrtc/MatrixRTCSessionManager.ts b/src/matrixrtc/MatrixRTCSessionManager.ts index 188f7b3e176..e64d19f7a6e 100644 --- a/src/matrixrtc/MatrixRTCSessionManager.ts +++ b/src/matrixrtc/MatrixRTCSessionManager.ts @@ -14,14 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../logger"; -import { MatrixClient, ClientEvent } from "../client"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { Room, RoomEvent } from "../models/room"; -import { RoomState, RoomStateEvent } from "../models/room-state"; -import { MatrixEvent } from "../models/event"; -import { MatrixRTCSession } from "./MatrixRTCSession"; -import { EventType } from "../@types/event"; +import { logger as rootLogger } from "../logger.ts"; +import { MatrixClient, ClientEvent } from "../client.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { Room, RoomEvent } from "../models/room.ts"; +import { RoomState, RoomStateEvent } from "../models/room-state.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { MatrixRTCSession } from "./MatrixRTCSession.ts"; +import { EventType } from "../@types/event.ts"; + +const logger = rootLogger.getChild("MatrixRTCSessionManager"); export enum MatrixRTCSessionManagerEvents { // A member has joined the MatrixRTC session, creating an active session in a room where there wasn't previously @@ -73,9 +75,9 @@ export class MatrixRTCSessionManager extends TypedEventEmitter { + private async consumeCallEncryptionEvent(event: MatrixEvent, isRetry = false): Promise { await this.client.decryptEventIfNeeded(event); + if (event.isDecryptionFailure()) { + if (!isRetry) { + logger.warn( + `Decryption failed for event ${event.getId()}: ${event.decryptionFailureReason} will retry once only`, + ); + // retry after 1 second. After this we give up. + setTimeout(() => this.consumeCallEncryptionEvent(event, true), 1000); + } else { + logger.warn(`Decryption failed for event ${event.getId()}: ${event.decryptionFailureReason}`); + } + return; + } else if (isRetry) { + logger.info(`Decryption succeeded for event ${event.getId()} after retry`); + } + if (event.getType() !== EventType.CallEncryptionKeysPrefix) return Promise.resolve(); const room = this.client.getRoom(event.getRoomId()); diff --git a/src/matrixrtc/focus.ts b/src/matrixrtc/focus.ts index 6892bbf15c0..cf9836dd450 100644 --- a/src/matrixrtc/focus.ts +++ b/src/matrixrtc/focus.ts @@ -21,4 +21,5 @@ limitations under the License. */ export interface Focus { type: string; + [key: string]: unknown; } diff --git a/src/matrixrtc/index.ts b/src/matrixrtc/index.ts new file mode 100644 index 00000000000..0474f635300 --- /dev/null +++ b/src/matrixrtc/index.ts @@ -0,0 +1,22 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export * from "./CallMembership.ts"; +export * from "./focus.ts"; +export * from "./LivekitFocus.ts"; +export * from "./MatrixRTCSession.ts"; +export * from "./MatrixRTCSessionManager.ts"; +export * from "./types.ts"; diff --git a/src/matrixrtc/types.ts b/src/matrixrtc/types.ts index de4c7ac47dc..479e3436699 100644 --- a/src/matrixrtc/types.ts +++ b/src/matrixrtc/types.ts @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { IMentions } from "../matrix"; +import { IMentions } from "../matrix.ts"; export interface EncryptionKeyEntry { index: number; key: string; diff --git a/src/models/MSC3089Branch.ts b/src/models/MSC3089Branch.ts index ebae391e33e..503a6e4af5b 100644 --- a/src/models/MSC3089Branch.ts +++ b/src/models/MSC3089Branch.ts @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixClient } from "../client"; -import { RelationType, UNSTABLE_MSC3089_BRANCH } from "../@types/event"; -import { IContent, MatrixEvent } from "./event"; -import { MSC3089TreeSpace } from "./MSC3089TreeSpace"; -import { EventTimeline } from "./event-timeline"; -import { FileType } from "../http-api"; -import type { ISendEventResponse } from "../@types/requests"; -import { EncryptedFile } from "../@types/media"; +import { MatrixClient } from "../client.ts"; +import { RelationType, UNSTABLE_MSC3089_BRANCH } from "../@types/event.ts"; +import { IContent, MatrixEvent } from "./event.ts"; +import { MSC3089TreeSpace } from "./MSC3089TreeSpace.ts"; +import { EventTimeline } from "./event-timeline.ts"; +import { FileType } from "../http-api/index.ts"; +import type { ISendEventResponse } from "../@types/requests.ts"; +import { EncryptedFile } from "../@types/media.ts"; export interface MSC3089EventContent { active?: boolean; diff --git a/src/models/MSC3089TreeSpace.ts b/src/models/MSC3089TreeSpace.ts index 6dc1b6fbb63..8bcc933d7c2 100644 --- a/src/models/MSC3089TreeSpace.ts +++ b/src/models/MSC3089TreeSpace.ts @@ -16,11 +16,11 @@ limitations under the License. import promiseRetry from "p-retry"; -import { MatrixClient } from "../client"; -import { EventType, MsgType, UNSTABLE_MSC3089_BRANCH, UNSTABLE_MSC3089_LEAF } from "../@types/event"; -import { Room } from "./room"; -import { logger } from "../logger"; -import { IContent, MatrixEvent } from "./event"; +import { MatrixClient } from "../client.ts"; +import { EventType, MsgType, UNSTABLE_MSC3089_BRANCH, UNSTABLE_MSC3089_LEAF } from "../@types/event.ts"; +import { Room } from "./room.ts"; +import { logger } from "../logger.ts"; +import { IContent, MatrixEvent } from "./event.ts"; import { averageBetweenStrings, DEFAULT_ALPHABET, @@ -28,14 +28,14 @@ import { nextString, prevString, simpleRetryOperation, -} from "../utils"; -import { MSC3089Branch } from "./MSC3089Branch"; -import { isRoomSharedHistory } from "../crypto/algorithms/megolm"; -import { ISendEventResponse } from "../@types/requests"; -import { FileType } from "../http-api"; -import { KnownMembership } from "../@types/membership"; -import { RoomPowerLevelsEventContent, SpaceChildEventContent } from "../@types/state_events"; -import type { EncryptedFile, FileContent } from "../@types/media"; +} from "../utils.ts"; +import { MSC3089Branch } from "./MSC3089Branch.ts"; +import { isRoomSharedHistory } from "../crypto/algorithms/megolm.ts"; +import { ISendEventResponse } from "../@types/requests.ts"; +import { FileType } from "../http-api/index.ts"; +import { KnownMembership } from "../@types/membership.ts"; +import { RoomPowerLevelsEventContent, SpaceChildEventContent } from "../@types/state_events.ts"; +import type { EncryptedFile, FileContent } from "../@types/media.ts"; /** * The recommended defaults for a tree space's power levels. Note that this diff --git a/src/models/beacon.ts b/src/models/beacon.ts index 3801831a1ce..95115780e55 100644 --- a/src/models/beacon.ts +++ b/src/models/beacon.ts @@ -14,11 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MBeaconEventContent } from "../@types/beacon"; -import { BeaconInfoState, BeaconLocationState, parseBeaconContent, parseBeaconInfoContent } from "../content-helpers"; -import { MatrixEvent } from "./event"; -import { sortEventsByLatestContentTimestamp } from "../utils"; -import { TypedEventEmitter } from "./typed-event-emitter"; +import { MBeaconEventContent } from "../@types/beacon.ts"; +import { + BeaconInfoState, + BeaconLocationState, + parseBeaconContent, + parseBeaconInfoContent, +} from "../content-helpers.ts"; +import { MatrixEvent } from "./event.ts"; +import { sortEventsByLatestContentTimestamp } from "../utils.ts"; +import { TypedEventEmitter } from "./typed-event-emitter.ts"; export enum BeaconEvent { New = "Beacon.new", diff --git a/src/models/compare-event-ordering.ts b/src/models/compare-event-ordering.ts index 6be23ec0345..31d50812812 100644 --- a/src/models/compare-event-ordering.ts +++ b/src/models/compare-event-ordering.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixEvent } from "./event"; -import { Room } from "./room"; -import { inMainTimelineForReceipt, threadIdForReceipt } from "../client"; +import { MatrixEvent } from "./event.ts"; +import { Room } from "./room.ts"; +import { inMainTimelineForReceipt, threadIdForReceipt } from "../client.ts"; /** * Determine the order of two events in a room. diff --git a/src/models/event-context.ts b/src/models/event-context.ts index 0401cd53007..c99b2db379e 100644 --- a/src/models/event-context.ts +++ b/src/models/event-context.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixEvent } from "./event"; -import { Direction } from "./event-timeline"; +import { MatrixEvent } from "./event.ts"; +import { Direction } from "./event-timeline.ts"; export class EventContext { private timeline: MatrixEvent[]; diff --git a/src/models/event-timeline-set.ts b/src/models/event-timeline-set.ts index e64d118fdd5..da8e6383373 100644 --- a/src/models/event-timeline-set.ts +++ b/src/models/event-timeline-set.ts @@ -14,16 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EventTimeline, IAddEventOptions } from "./event-timeline"; -import { MatrixEvent } from "./event"; -import { logger } from "../logger"; -import { Room, RoomEvent } from "./room"; -import { Filter } from "../filter"; -import { RoomState } from "./room-state"; -import { TypedEventEmitter } from "./typed-event-emitter"; -import { RelationsContainer } from "./relations-container"; -import { MatrixClient } from "../client"; -import { Thread, ThreadFilterType } from "./thread"; +import { EventTimeline, IAddEventOptions } from "./event-timeline.ts"; +import { MatrixEvent } from "./event.ts"; +import { logger } from "../logger.ts"; +import { Room, RoomEvent } from "./room.ts"; +import { Filter } from "../filter.ts"; +import { RoomState } from "./room-state.ts"; +import { TypedEventEmitter } from "./typed-event-emitter.ts"; +import { RelationsContainer } from "./relations-container.ts"; +import { MatrixClient } from "../client.ts"; +import { Thread, ThreadFilterType } from "./thread.ts"; const DEBUG = true; @@ -118,7 +118,7 @@ export type EventTimelineSetHandlerMap = { */ [RoomEvent.TimelineReset]: ( room: Room | undefined, - eventTimelineSet: EventTimelineSet, + timelineSet: EventTimelineSet, resetAllTimelines: boolean, ) => void; }; diff --git a/src/models/event-timeline.ts b/src/models/event-timeline.ts index 912dcaf2130..3489fdaee7b 100644 --- a/src/models/event-timeline.ts +++ b/src/models/event-timeline.ts @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IMarkerFoundOptions, RoomState } from "./room-state"; -import { EventTimelineSet } from "./event-timeline-set"; -import { MatrixEvent } from "./event"; -import { Filter } from "../filter"; -import { EventType } from "../@types/event"; +import { IMarkerFoundOptions, RoomState } from "./room-state.ts"; +import { EventTimelineSet } from "./event-timeline-set.ts"; +import { MatrixEvent } from "./event.ts"; +import { Filter } from "../filter.ts"; +import { EventType } from "../@types/event.ts"; export interface IInitialiseStateOptions extends Pick { // This is a separate interface without any extra stuff currently added on @@ -127,7 +127,7 @@ export class EventTimeline { public constructor(private readonly eventTimelineSet: EventTimelineSet) { this.roomId = eventTimelineSet.room?.roomId ?? null; if (this.roomId) { - this.startState = new RoomState(this.roomId); + this.startState = new RoomState(this.roomId, undefined, true); this.endState = new RoomState(this.roomId); } @@ -267,7 +267,7 @@ export class EventTimeline { /** * Get a pagination token * - * @param direction - EventTimeline.BACKWARDS to get the pagination + * @param direction - EventTimeline.BACKWARDS to get the pagination * token for going backwards in time; EventTimeline.FORWARDS to get the * pagination token for going forwards in time. * diff --git a/src/models/event.ts b/src/models/event.ts index 7b9365aad50..8c132144381 100644 --- a/src/models/event.ts +++ b/src/models/event.ts @@ -21,9 +21,9 @@ limitations under the License. import { ExtensibleEvent, ExtensibleEvents, Optional } from "matrix-events-sdk"; -import type { IEventDecryptionResult } from "../@types/crypto"; -import { logger } from "../logger"; -import { VerificationRequest } from "../crypto/verification/request/VerificationRequest"; +import type { IEventDecryptionResult } from "../@types/crypto.ts"; +import { logger } from "../logger.ts"; +import { VerificationRequest } from "../crypto/verification/request/VerificationRequest.ts"; import { EVENT_VISIBILITY_CHANGE_TYPE, EventType, @@ -32,25 +32,24 @@ import { ToDeviceMessageId, UNSIGNED_THREAD_ID_FIELD, UNSIGNED_MEMBERSHIP_FIELD, -} from "../@types/event"; -import { Crypto } from "../crypto"; -import { deepSortedObjectEntries, internaliseString } from "../utils"; -import { RoomMember } from "./room-member"; -import { Thread, THREAD_RELATION_TYPE, ThreadEvent, ThreadEventHandlerMap } from "./thread"; -import { IActionsObject } from "../pushprocessor"; -import { TypedReEmitter } from "../ReEmitter"; -import { MatrixError } from "../http-api"; -import { TypedEventEmitter } from "./typed-event-emitter"; -import { EventStatus } from "./event-status"; -import { CryptoBackend, DecryptionError } from "../common-crypto/CryptoBackend"; -import { WITHHELD_MESSAGES } from "../crypto/OlmDevice"; -import { IAnnotatedPushRule } from "../@types/PushRules"; -import { Room } from "./room"; -import { EventTimeline } from "./event-timeline"; -import { Membership } from "../@types/membership"; -import { DecryptionFailureCode } from "../crypto-api"; - -export { EventStatus } from "./event-status"; +} from "../@types/event.ts"; +import { Crypto } from "../crypto/index.ts"; +import { deepSortedObjectEntries, internaliseString } from "../utils.ts"; +import { RoomMember } from "./room-member.ts"; +import { Thread, THREAD_RELATION_TYPE, ThreadEvent, ThreadEventHandlerMap } from "./thread.ts"; +import { IActionsObject } from "../pushprocessor.ts"; +import { TypedReEmitter } from "../ReEmitter.ts"; +import { MatrixError } from "../http-api/index.ts"; +import { TypedEventEmitter } from "./typed-event-emitter.ts"; +import { EventStatus } from "./event-status.ts"; +import { CryptoBackend, DecryptionError } from "../common-crypto/CryptoBackend.ts"; +import { IAnnotatedPushRule } from "../@types/PushRules.ts"; +import { Room } from "./room.ts"; +import { EventTimeline } from "./event-timeline.ts"; +import { Membership } from "../@types/membership.ts"; +import { DecryptionFailureCode } from "../crypto-api/index.ts"; + +export { EventStatus } from "./event-status.ts"; /* eslint-disable camelcase */ export interface IContent { @@ -77,7 +76,6 @@ export interface IUnsigned { "invite_room_state"?: StrippedState[]; "m.relations"?: Record; // No common pattern for aggregated relations [UNSIGNED_THREAD_ID_FIELD.name]?: string; - [UNSIGNED_MEMBERSHIP_FIELD.name]?: Membership | string; } export interface IThreadBundledRelationship { @@ -313,12 +311,6 @@ export class MatrixEvent extends TypedEventEmitter { const unsigned = this.getUnsigned(); - if (typeof unsigned[UNSIGNED_MEMBERSHIP_FIELD.name] === "string") { - return unsigned[UNSIGNED_MEMBERSHIP_FIELD.name]; - } else { - return undefined; - } + return UNSIGNED_MEMBERSHIP_FIELD.findIn(unsigned); } /** @@ -792,12 +780,14 @@ export class MatrixEvent extends TypedEventEmitter void; + [RoomStateEvent.Events]: (event: MatrixEvent, state: RoomState, prevEvent: MatrixEvent | null) => void; /** * Fires whenever a member in the members dictionary is updated in any way. * @param event - The matrix event which caused this event to fire. @@ -194,10 +194,22 @@ export class RoomState extends TypedEventEmitter * As the timeline might get reset while they are loading, this state needs to be inherited * and shared when the room state is cloned for the new timeline. * This should only be passed from clone. + * @param isStartTimelineState - Optional. This state is marked as a start state. + * This is used to skip state insertions that are + * in the wrong order. The order is determined by the `replaces_state` id. + * + * Example: + * A current state events `replaces_state` value is `1`. + * Trying to insert a state event with `event_id` `1` in its place would fail if isStartTimelineState = false. + * + * A current state events `event_id` is `2`. + * Trying to insert a state event where its `replaces_state` value is `2` would fail if isStartTimelineState = true. */ + public constructor( public readonly roomId: string, private oobMemberFlags = { status: OobStatus.NotStarted }, + public readonly isStartTimelineState = false, ) { super(); this.updateModifiedTime(); @@ -408,7 +420,7 @@ export class RoomState extends TypedEventEmitter * Fires {@link RoomStateEvent.Events} * Fires {@link RoomStateEvent.Marker} */ - public setStateEvents(stateEvents: MatrixEvent[], markerFoundOptions?: IMarkerFoundOptions): void { + public setStateEvents(stateEvents: MatrixEvent[], options?: IMarkerFoundOptions): void { this.updateModifiedTime(); // update the core event dict @@ -420,6 +432,22 @@ export class RoomState extends TypedEventEmitter } const lastStateEvent = this.getStateEventMatching(event); + + // Safety measure to not update the room (and emit the update) with older state. + // The sync loop really should not send old events but it does very regularly. + // Logging on return in those two conditions results in a large amount of logging. (on startup and when running element) + const lastReplaceId = lastStateEvent?.event.unsigned?.replaces_state; + const lastId = lastStateEvent?.event.event_id; + const newReplaceId = event.event.unsigned?.replaces_state; + const newId = event.event.event_id; + if (this.isStartTimelineState) { + // Add an event to the start of the timeline. Its replace id should not be the same as the one of the current/last start state event. + if (newReplaceId && lastId && newReplaceId === lastId) return; + } else { + // Add an event to the end of the timeline. It should not be the same as the one replaced by the current/last end state event. + if (lastReplaceId && newId && lastReplaceId === newId) return; + } + this.setStateEvent(event); if (event.getType() === EventType.RoomMember) { this.updateDisplayNameCache(event.getStateKey()!, event.getContent().displayname ?? ""); @@ -476,7 +504,7 @@ export class RoomState extends TypedEventEmitter // assume all our sentinels are now out-of-date this.sentinels = {}; } else if (UNSTABLE_MSC2716_MARKER.matches(event.getType())) { - this.emit(RoomStateEvent.Marker, event, markerFoundOptions); + this.emit(RoomStateEvent.Marker, event, options); } }); diff --git a/src/models/room.ts b/src/models/room.ts index d8b90a60856..b013e76afaa 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -21,17 +21,17 @@ import { DuplicateStrategy, IAddLiveEventOptions, EventTimelineSetHandlerMap, -} from "./event-timeline-set"; -import { Direction, EventTimeline } from "./event-timeline"; -import { getHttpUriForMxc } from "../content-repo"; -import { compare, removeElement } from "../utils"; -import { normalize, noUnsafeEventProps } from "../utils"; -import { IEvent, IThreadBundledRelationship, MatrixEvent, MatrixEventEvent, MatrixEventHandlerMap } from "./event"; -import { EventStatus } from "./event-status"; -import { RoomMember } from "./room-member"; -import { IRoomSummary, RoomSummary } from "./room-summary"; -import { logger } from "../logger"; -import { TypedReEmitter } from "../ReEmitter"; +} from "./event-timeline-set.ts"; +import { Direction, EventTimeline } from "./event-timeline.ts"; +import { getHttpUriForMxc } from "../content-repo.ts"; +import { removeElement } from "../utils.ts"; +import { normalize, noUnsafeEventProps } from "../utils.ts"; +import { IEvent, IThreadBundledRelationship, MatrixEvent, MatrixEventEvent, MatrixEventHandlerMap } from "./event.ts"; +import { EventStatus } from "./event-status.ts"; +import { RoomMember } from "./room-member.ts"; +import { IRoomSummary, RoomSummary } from "./room-summary.ts"; +import { logger } from "../logger.ts"; +import { TypedReEmitter } from "../ReEmitter.ts"; import { EventType, RoomCreateTypeField, @@ -40,12 +40,12 @@ import { EVENT_VISIBILITY_CHANGE_TYPE, RelationType, UNSIGNED_THREAD_ID_FIELD, -} from "../@types/event"; -import { IRoomVersionsCapability, MatrixClient, PendingEventOrdering, RoomVersionStability } from "../client"; -import { GuestAccess, HistoryVisibility, JoinRule, ResizeMethod } from "../@types/partials"; -import { Filter, IFilterDefinition } from "../filter"; -import { RoomState, RoomStateEvent, RoomStateEventHandlerMap } from "./room-state"; -import { BeaconEvent, BeaconEventHandlerMap } from "./beacon"; +} from "../@types/event.ts"; +import { MatrixClient, PendingEventOrdering } from "../client.ts"; +import { GuestAccess, HistoryVisibility, JoinRule, ResizeMethod } from "../@types/partials.ts"; +import { Filter, IFilterDefinition } from "../filter.ts"; +import { RoomState, RoomStateEvent, RoomStateEventHandlerMap } from "./room-state.ts"; +import { BeaconEvent, BeaconEventHandlerMap } from "./beacon.ts"; import { Thread, ThreadEvent, @@ -54,22 +54,23 @@ import { THREAD_RELATION_TYPE, FILTER_RELATED_BY_SENDERS, ThreadFilterType, -} from "./thread"; +} from "./thread.ts"; import { CachedReceiptStructure, MAIN_ROOM_TIMELINE, Receipt, ReceiptContent, ReceiptType, -} from "../@types/read_receipts"; -import { IStateEventWithRoomId } from "../@types/search"; -import { RelationsContainer } from "./relations-container"; -import { ReadReceipt, synthesizeReceipt } from "./read-receipt"; -import { isPollEvent, Poll, PollEvent } from "./poll"; -import { RoomReceipts } from "./room-receipts"; -import { compareEventOrdering } from "./compare-event-ordering"; -import * as utils from "../utils"; -import { KnownMembership, Membership } from "../@types/membership"; +} from "../@types/read_receipts.ts"; +import { IStateEventWithRoomId } from "../@types/search.ts"; +import { RelationsContainer } from "./relations-container.ts"; +import { ReadReceipt, synthesizeReceipt } from "./read-receipt.ts"; +import { isPollEvent, Poll, PollEvent } from "./poll.ts"; +import { RoomReceipts } from "./room-receipts.ts"; +import { compareEventOrdering } from "./compare-event-ordering.ts"; +import * as utils from "../utils.ts"; +import { KnownMembership, Membership } from "../@types/membership.ts"; +import { Capabilities, IRoomVersionsCapability, RoomVersionStability } from "../serverCapabilities.ts"; // These constants are used as sane defaults when the homeserver doesn't support // the m.room_versions capability. In practice, KNOWN_SAFE_ROOM_VERSION should be @@ -208,7 +209,7 @@ export type RoomEventHandlerMap = { * }); * ``` */ - [RoomEvent.AccountData]: (event: MatrixEvent, room: Room, lastEvent?: MatrixEvent) => void; + [RoomEvent.AccountData]: (event: MatrixEvent, room: Room, prevEvent?: MatrixEvent) => void; /** * Fires whenever a receipt is received for a room * @param event - The receipt event @@ -397,7 +398,8 @@ export class Room extends ReadReceipt { * Use getLiveTimeline().getState(EventTimeline.FORWARDS) instead. */ public currentState!: RoomState; - public readonly relations = new RelationsContainer(this.client, this); + + public readonly relations; /** * A collection of events known by the client @@ -459,6 +461,7 @@ export class Room extends ReadReceipt { private readonly opts: IOpts = {}, ) { super(); + // In some cases, we add listeners for every displayed Matrix event, so it's // common to have quite a few more than the default limit. this.setMaxListeners(100); @@ -469,6 +472,8 @@ export class Room extends ReadReceipt { this.name = roomId; this.normalizedName = roomId; + this.relations = new RelationsContainer(this.client, this); + // Listen to our own receipt event as a more modular way of processing our own // receipts. No need to remove the listener: it's on ourself anyway. this.on(RoomEvent.Receipt, this.onReceipt); @@ -611,7 +616,10 @@ export class Room extends ReadReceipt { * Resolves to the version the room should be upgraded to. */ public async getRecommendedVersion(): Promise { - const capabilities = await this.client.getCapabilities(); + let capabilities: Capabilities = {}; + try { + capabilities = await this.client.getCapabilities(); + } catch (e) {} let versionCap = capabilities["m.room_versions"]; if (!versionCap) { versionCap = { @@ -636,8 +644,12 @@ export class Room extends ReadReceipt { "to be supporting a newer room version we don't know about.", ); - const caps = await this.client.getCapabilities(true); - versionCap = caps["m.room_versions"]; + try { + capabilities = await this.client.fetchCapabilities(); + } catch (e) { + logger.warn("Failed to refresh room version capabilities", e); + } + versionCap = capabilities["m.room_versions"]; if (!versionCap) { logger.warn("No room version capability - assuming upgrade required."); return result; @@ -3439,7 +3451,8 @@ export class Room extends ReadReceipt { return true; }); // make sure members have stable order - otherMembers.sort((a, b) => compare(a.userId, b.userId)); + const collator = new Intl.Collator(); + otherMembers.sort((a, b) => collator.compare(a.userId, b.userId)); // only 5 first members, immitate summaryHeroes otherMembers = otherMembers.slice(0, 5); otherNames = otherMembers.map((m) => m.name); diff --git a/src/models/search-result.ts b/src/models/search-result.ts index 525b525fc2c..4677371a5c0 100644 --- a/src/models/search-result.ts +++ b/src/models/search-result.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EventContext } from "./event-context"; -import { EventMapper } from "../event-mapper"; -import { IResultContext, ISearchResult } from "../@types/search"; +import { EventContext } from "./event-context.ts"; +import { EventMapper } from "../event-mapper.ts"; +import { IResultContext, ISearchResult } from "../@types/search.ts"; export class SearchResult { /** diff --git a/src/models/thread.ts b/src/models/thread.ts index 6db967d4e89..905c4db3c1f 100644 --- a/src/models/thread.ts +++ b/src/models/thread.ts @@ -16,19 +16,19 @@ limitations under the License. import { Optional } from "matrix-events-sdk"; -import { MatrixClient, PendingEventOrdering } from "../client"; -import { TypedReEmitter } from "../ReEmitter"; -import { RelationType } from "../@types/event"; -import { IThreadBundledRelationship, MatrixEvent, MatrixEventEvent } from "./event"; -import { Direction, EventTimeline } from "./event-timeline"; -import { EventTimelineSet, EventTimelineSetHandlerMap } from "./event-timeline-set"; -import { NotificationCountType, Room, RoomEvent } from "./room"; -import { RoomState } from "./room-state"; -import { ServerControlledNamespacedValue } from "../NamespacedValue"; -import { logger } from "../logger"; -import { ReadReceipt } from "./read-receipt"; -import { CachedReceiptStructure, Receipt, ReceiptType } from "../@types/read_receipts"; -import { Feature, ServerSupport } from "../feature"; +import { MatrixClient, PendingEventOrdering } from "../client.ts"; +import { TypedReEmitter } from "../ReEmitter.ts"; +import { RelationType } from "../@types/event.ts"; +import { IThreadBundledRelationship, MatrixEvent, MatrixEventEvent } from "./event.ts"; +import { Direction, EventTimeline } from "./event-timeline.ts"; +import { EventTimelineSet, EventTimelineSetHandlerMap } from "./event-timeline-set.ts"; +import { NotificationCountType, Room, RoomEvent } from "./room.ts"; +import { RoomState } from "./room-state.ts"; +import { ServerControlledNamespacedValue } from "../NamespacedValue.ts"; +import { logger } from "../logger.ts"; +import { ReadReceipt } from "./read-receipt.ts"; +import { CachedReceiptStructure, Receipt, ReceiptType } from "../@types/read_receipts.ts"; +import { Feature, ServerSupport } from "../feature.ts"; export enum ThreadEvent { New = "Thread.new", diff --git a/src/models/user.ts b/src/models/user.ts index 32614bedc59..90005c2cf4a 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixClient } from "../matrix"; -import { MatrixEvent } from "./event"; -import { TypedEventEmitter } from "./typed-event-emitter"; +import { MatrixClient } from "../matrix.ts"; +import { MatrixEvent } from "./event.ts"; +import { TypedEventEmitter } from "./typed-event-emitter.ts"; export enum UserEvent { DisplayName = "User.displayName", diff --git a/src/oidc/authorize.ts b/src/oidc/authorize.ts index 35b93dc48e2..7e3692dfb94 100644 --- a/src/oidc/authorize.ts +++ b/src/oidc/authorize.ts @@ -16,18 +16,19 @@ limitations under the License. import { IdTokenClaims, Log, OidcClient, SigninResponse, SigninState, WebStorageStateStore } from "oidc-client-ts"; -import { subtleCrypto, TextEncoder } from "../crypto/crypto"; -import { logger } from "../logger"; -import { randomString } from "../randomstring"; -import { OidcError } from "./error"; +import { logger } from "../logger.ts"; +import { randomString } from "../randomstring.ts"; +import { OidcError } from "./error.ts"; import { - validateIdToken, - ValidatedIssuerMetadata, - validateStoredUserState, - UserState, BearerTokenResponse, + UserState, validateBearerTokenResponse, -} from "./validate"; + ValidatedIssuerMetadata, + validateIdToken, + validateStoredUserState, +} from "./validate.ts"; +import { sha256 } from "../digest.ts"; +import { encodeUnpaddedBase64Url } from "../base64.ts"; // reexport for backwards compatibility export type { BearerTokenResponse }; @@ -57,19 +58,14 @@ export const generateScope = (deviceId?: string): string => { // https://www.rfc-editor.org/rfc/rfc7636 const generateCodeChallenge = async (codeVerifier: string): Promise => { - if (!subtleCrypto) { + if (!globalThis.crypto.subtle) { // @TODO(kerrya) should this be allowed? configurable? logger.warn("A secure context is required to generate code challenge. Using plain text code challenge"); return codeVerifier; } - const utf8 = new TextEncoder().encode(codeVerifier); - - const digest = await subtleCrypto.digest("SHA-256", utf8); - return btoa(String.fromCharCode(...new Uint8Array(digest))) - .replace(/=/g, "") - .replace(/\+/g, "-") - .replace(/\//g, "_"); + const hashBuffer = await sha256(codeVerifier); + return encodeUnpaddedBase64Url(hashBuffer); }; /** diff --git a/src/oidc/discovery.ts b/src/oidc/discovery.ts index 7199c8715d4..656bb30a5c8 100644 --- a/src/oidc/discovery.ts +++ b/src/oidc/discovery.ts @@ -16,9 +16,9 @@ limitations under the License. import { MetadataService, OidcClientSettingsStore } from "oidc-client-ts"; -import { isValidatedIssuerMetadata, validateOIDCIssuerWellKnown } from "./validate"; -import { Method, timeoutSignal } from "../http-api"; -import { OidcClientConfig } from "./index"; +import { isValidatedIssuerMetadata, validateOIDCIssuerWellKnown } from "./validate.ts"; +import { Method, timeoutSignal } from "../http-api/index.ts"; +import { OidcClientConfig } from "./index.ts"; /** * @experimental diff --git a/src/oidc/index.ts b/src/oidc/index.ts index 7fc31836f83..519b311a617 100644 --- a/src/oidc/index.ts +++ b/src/oidc/index.ts @@ -15,14 +15,14 @@ limitations under the License. */ import type { SigningKey } from "oidc-client-ts"; -import { ValidatedIssuerConfig, ValidatedIssuerMetadata } from "./validate"; +import { ValidatedIssuerConfig, ValidatedIssuerMetadata } from "./validate.ts"; -export * from "./authorize"; -export * from "./discovery"; -export * from "./error"; -export * from "./register"; -export * from "./tokenRefresher"; -export * from "./validate"; +export * from "./authorize.ts"; +export * from "./discovery.ts"; +export * from "./error.ts"; +export * from "./register.ts"; +export * from "./tokenRefresher.ts"; +export * from "./validate.ts"; /** * Validated config for native OIDC authentication, as returned by {@link discoverAndValidateOIDCIssuerWellKnown}. diff --git a/src/oidc/register.ts b/src/oidc/register.ts index 0c5f0556557..25c3673d3a1 100644 --- a/src/oidc/register.ts +++ b/src/oidc/register.ts @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { OidcClientConfig } from "."; -import { OidcError } from "./error"; -import { Method } from "../http-api"; -import { logger } from "../logger"; -import { NonEmptyArray } from "../@types/common"; +import { OidcClientConfig } from "./index.ts"; +import { OidcError } from "./error.ts"; +import { Method } from "../http-api/index.ts"; +import { logger } from "../logger.ts"; +import { NonEmptyArray } from "../@types/common.ts"; /** * Client metadata passed to registration endpoint @@ -49,6 +49,8 @@ interface OidcRegistrationRequestBody { application_type: "web" | "native"; } +export const DEVICE_CODE_SCOPE = "urn:ietf:params:oauth:grant-type:device_code"; + /** * Attempts dynamic registration against the configured registration endpoint * @param delegatedAuthConfig - Auth config from {@link discoverAndValidateOIDCIssuerWellKnown} diff --git a/src/oidc/tokenRefresher.ts b/src/oidc/tokenRefresher.ts index 84b773531b9..b75de5c2ce3 100644 --- a/src/oidc/tokenRefresher.ts +++ b/src/oidc/tokenRefresher.ts @@ -16,10 +16,10 @@ limitations under the License. import { IdTokenClaims, OidcClient, WebStorageStateStore } from "oidc-client-ts"; -import { AccessTokens } from "../http-api"; -import { generateScope } from "./authorize"; -import { discoverAndValidateOIDCIssuerWellKnown } from "./discovery"; -import { logger } from "../logger"; +import { AccessTokens } from "../http-api/index.ts"; +import { generateScope } from "./authorize.ts"; +import { discoverAndValidateOIDCIssuerWellKnown } from "./discovery.ts"; +import { logger } from "../logger.ts"; /** * @experimental diff --git a/src/oidc/validate.ts b/src/oidc/validate.ts index de50b570b66..72eb7e96e64 100644 --- a/src/oidc/validate.ts +++ b/src/oidc/validate.ts @@ -17,8 +17,8 @@ limitations under the License. import { jwtDecode } from "jwt-decode"; import { IdTokenClaims, OidcMetadata, SigninResponse } from "oidc-client-ts"; -import { logger } from "../logger"; -import { OidcError } from "./error"; +import { logger } from "../logger.ts"; +import { OidcError } from "./error.ts"; export type ValidatedIssuerConfig = { authorizationEndpoint: string; diff --git a/src/pushprocessor.ts b/src/pushprocessor.ts index 734a72751c3..be40c2d1e83 100644 --- a/src/pushprocessor.ts +++ b/src/pushprocessor.ts @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { deepCompare, escapeRegExp, globToRegexp, isNullOrUndefined } from "./utils"; -import { logger } from "./logger"; -import { MatrixClient } from "./client"; -import { MatrixEvent } from "./models/event"; +import { deepCompare, escapeRegExp, globToRegexp, isNullOrUndefined } from "./utils.ts"; +import { logger } from "./logger.ts"; +import { MatrixClient } from "./client.ts"; +import { MatrixEvent } from "./models/event.ts"; import { ConditionKind, IAnnotatedPushRule, @@ -38,8 +38,8 @@ import { PushRuleSet, RuleId, TweakName, -} from "./@types/PushRules"; -import { EventType } from "./@types/event"; +} from "./@types/PushRules.ts"; +import { EventType } from "./@types/event.ts"; const RULEKINDS_IN_ORDER = [ PushRuleKind.Override, diff --git a/src/randomstring.ts b/src/randomstring.ts index 36a6e748284..d0cc9e675d2 100644 --- a/src/randomstring.ts +++ b/src/randomstring.ts @@ -15,8 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { encodeUnpaddedBase64Url } from "./base64"; -import { crypto } from "./crypto/crypto"; +import { encodeUnpaddedBase64Url } from "./base64.ts"; const LOWERCASE = "abcdefghijklmnopqrstuvwxyz"; const UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -24,7 +23,7 @@ const DIGITS = "0123456789"; export function secureRandomBase64Url(len: number): string { const key = new Uint8Array(len); - crypto.getRandomValues(key); + globalThis.crypto.getRandomValues(key); return encodeUnpaddedBase64Url(key); } diff --git a/src/realtime-callbacks.ts b/src/realtime-callbacks.ts index 1b03a579a28..b59d145344a 100644 --- a/src/realtime-callbacks.ts +++ b/src/realtime-callbacks.ts @@ -24,7 +24,7 @@ limitations under the License. * it will instead fire as soon as possible after resume. */ -import { logger } from "./logger"; +import { logger } from "./logger.ts"; // we schedule a callback at least this often, to check if we've missed out on // some wall-clock time due to being suspended. diff --git a/src/receipt-accumulator.ts b/src/receipt-accumulator.ts index ded358ad9a1..707b2ff2714 100644 --- a/src/receipt-accumulator.ts +++ b/src/receipt-accumulator.ts @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IMinimalEvent } from "./sync-accumulator"; -import { EventType } from "./@types/event"; -import { isSupportedReceiptType, MapWithDefault, recursiveMapToObject } from "./utils"; -import { IContent } from "./models/event"; -import { ReceiptContent, ReceiptType } from "./@types/read_receipts"; +import { IMinimalEvent } from "./sync-accumulator.ts"; +import { EventType } from "./@types/event.ts"; +import { isSupportedReceiptType, MapWithDefault, recursiveMapToObject } from "./utils.ts"; +import { IContent } from "./models/event.ts"; +import { ReceiptContent, ReceiptType } from "./@types/read_receipts.ts"; interface AccumulatedReceipt { data: IMinimalEvent; diff --git a/src/rendezvous/MSC3906Rendezvous.ts b/src/rendezvous/MSC3906Rendezvous.ts index e558c224abe..a84a41d687a 100644 --- a/src/rendezvous/MSC3906Rendezvous.ts +++ b/src/rendezvous/MSC3906Rendezvous.ts @@ -16,13 +16,18 @@ limitations under the License. import { UnstableValue } from "matrix-events-sdk"; -import { RendezvousChannel, RendezvousFailureListener, RendezvousFailureReason, RendezvousIntent } from "."; -import { IGetLoginTokenCapability, MatrixClient, GET_LOGIN_TOKEN_CAPABILITY } from "../client"; -import { buildFeatureSupportMap, Feature, ServerSupport } from "../feature"; -import { logger } from "../logger"; -import { sleep } from "../utils"; -import { CrossSigningKey } from "../crypto-api"; -import { Device } from "../matrix"; +import { + RendezvousChannel, + RendezvousFailureListener, + LegacyRendezvousFailureReason as RendezvousFailureReason, + RendezvousIntent, +} from "./index.ts"; +import { MatrixClient, GET_LOGIN_TOKEN_CAPABILITY } from "../client.ts"; +import { buildFeatureSupportMap, Feature, ServerSupport } from "../feature.ts"; +import { logger } from "../logger.ts"; +import { sleep } from "../utils.ts"; +import { CrossSigningKey } from "../crypto-api/index.ts"; +import { Capabilities, Device, IGetLoginTokenCapability } from "../matrix.ts"; enum PayloadType { Start = "m.login.start", @@ -59,6 +64,9 @@ const LOGIN_TOKEN_PROTOCOL = new UnstableValue("login_token", "org.matrix.msc390 * Implements MSC3906 to allow a user to sign in on a new device using QR code. * This implementation only supports generating a QR code on a device that is already signed in. * Note that this is UNSTABLE and may have breaking changes without notice. + * MSC3886/MSC3903/MSC3906 are now closed and so this functionality will be removed in future. + * However, we want to keep this implementation around for some time. + * TODO: define an end-of-life date for this implementation. */ export class MSC3906Rendezvous { private newDeviceId?: string; @@ -101,7 +109,10 @@ export class MSC3906Rendezvous { logger.info(`Connected to secure channel with checksum: ${checksum} our intent is ${this.ourIntent}`); // in stable and unstable r1 the availability is exposed as a capability - const capabilities = await this.client.getCapabilities(); + let capabilities: Capabilities = {}; + try { + capabilities = await this.client.getCapabilities(); + } catch (e) {} // in r0 of MSC3882 the availability is exposed as a feature flag const features = await buildFeatureSupportMap(await this.client.getVersions()); const capability = GET_LOGIN_TOKEN_CAPABILITY.findIn(capabilities); diff --git a/src/rendezvous/MSC4108SignInWithQR.ts b/src/rendezvous/MSC4108SignInWithQR.ts new file mode 100644 index 00000000000..a22b3149e5a --- /dev/null +++ b/src/rendezvous/MSC4108SignInWithQR.ts @@ -0,0 +1,444 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { QrCodeMode } from "@matrix-org/matrix-sdk-crypto-wasm"; + +import { + ClientRendezvousFailureReason, + MSC4108FailureReason, + RendezvousError, + RendezvousFailureListener, +} from "./index.ts"; +import { MatrixClient } from "../client.ts"; +import { logger } from "../logger.ts"; +import { MSC4108SecureChannel } from "./channels/MSC4108SecureChannel.ts"; +import { MatrixError } from "../http-api/index.ts"; +import { sleep } from "../utils.ts"; +import { DEVICE_CODE_SCOPE, discoverAndValidateOIDCIssuerWellKnown, OidcClientConfig } from "../oidc/index.ts"; +import { CryptoApi } from "../crypto-api/index.ts"; + +/** + * Enum representing the payload types transmissible over [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108) + * secure channels. + * @experimental Note that this is UNSTABLE and may have breaking changes without notice. + */ +export enum PayloadType { + Protocols = "m.login.protocols", + Protocol = "m.login.protocol", + Failure = "m.login.failure", + Success = "m.login.success", + Secrets = "m.login.secrets", + ProtocolAccepted = "m.login.protocol_accepted", + Declined = "m.login.declined", +} + +/** + * Type representing the base payload format for [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108) + * messages sent over the secure channel. + * @experimental Note that this is UNSTABLE and may have breaking changes without notice. + */ +export interface MSC4108Payload { + type: PayloadType; +} + +interface ProtocolsPayload extends MSC4108Payload { + type: PayloadType.Protocols; + protocols: string[]; + homeserver: string; +} + +interface ProtocolPayload extends MSC4108Payload { + type: PayloadType.Protocol; + protocol: Exclude; + device_id: string; +} + +interface DeviceAuthorizationGrantProtocolPayload extends ProtocolPayload { + protocol: "device_authorization_grant"; + device_authorization_grant: { + verification_uri: string; + verification_uri_complete?: string; + }; +} + +function isDeviceAuthorizationGrantProtocolPayload( + payload: ProtocolPayload, +): payload is DeviceAuthorizationGrantProtocolPayload { + return payload.protocol === "device_authorization_grant"; +} + +interface FailurePayload extends MSC4108Payload { + type: PayloadType.Failure; + reason: MSC4108FailureReason; + homeserver?: string; +} + +interface DeclinedPayload extends MSC4108Payload { + type: PayloadType.Declined; +} + +interface SuccessPayload extends MSC4108Payload { + type: PayloadType.Success; +} + +interface AcceptedPayload extends MSC4108Payload { + type: PayloadType.ProtocolAccepted; +} + +interface SecretsPayload extends MSC4108Payload, Awaited>> { + type: PayloadType.Secrets; +} + +/** + * Prototype of the unstable [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108) + * sign in with QR + OIDC flow. + * @experimental Note that this is UNSTABLE and may have breaking changes without notice. + */ +export class MSC4108SignInWithQR { + private readonly ourIntent: QrCodeMode; + private _code?: Uint8Array; + private expectingNewDeviceId?: string; + + /** + * Returns the check code for the secure channel or undefined if not generated yet. + */ + public get checkCode(): string | undefined { + return this.channel?.getCheckCode(); + } + + /** + * @param channel - The secure channel used for communication + * @param client - The Matrix client in used on the device already logged in + * @param didScanCode - Whether this side of the channel scanned the QR code from the other party + * @param onFailure - Callback for when the rendezvous fails + */ + public constructor( + private readonly channel: MSC4108SecureChannel, + private readonly didScanCode: boolean, + private readonly client?: MatrixClient, + public onFailure?: RendezvousFailureListener, + ) { + this.ourIntent = client ? QrCodeMode.Reciprocate : QrCodeMode.Login; + } + + /** + * Returns the code representing the rendezvous suitable for rendering in a QR code or undefined if not generated yet. + */ + public get code(): Uint8Array | undefined { + return this._code; + } + + /** + * Generate the code including doing partial set up of the channel where required. + */ + public async generateCode(): Promise { + if (this._code) { + return; + } + + if (this.ourIntent === QrCodeMode.Reciprocate && this.client) { + this._code = await this.channel.generateCode(this.ourIntent, this.client.getDomain()!); + } else if (this.ourIntent === QrCodeMode.Login) { + this._code = await this.channel.generateCode(this.ourIntent); + } + } + + /** + * Returns true if the device is the already logged in device reciprocating a new login on the other side of the channel. + */ + public get isExistingDevice(): boolean { + return this.ourIntent === QrCodeMode.Reciprocate; + } + + /** + * Returns true if the device is the new device logging in being reciprocated by the device on the other side of the channel. + */ + public get isNewDevice(): boolean { + return !this.isExistingDevice; + } + + /** + * The first step in the OIDC QR login process. + * To be called after the QR code has been rendered or scanned. + * The scanning device has to discover the homeserver details, if they scanned the code then they already have it. + * If the new device is the one rendering the QR code then it has to wait be sent the homeserver details via the rendezvous channel. + */ + public async negotiateProtocols(): Promise<{ serverName?: string }> { + logger.info(`negotiateProtocols(isNewDevice=${this.isNewDevice} didScanCode=${this.didScanCode})`); + await this.channel.connect(); + + if (this.didScanCode) { + // Secure Channel step 6 completed, we trust the channel + + if (this.isNewDevice) { + // MSC4108-Flow: ExistingScanned - take homeserver from QR code which should already be set + } else { + // MSC4108-Flow: NewScanned -send protocols message + let oidcClientConfig: OidcClientConfig | undefined; + try { + const { issuer } = await this.client!.getAuthIssuer(); + oidcClientConfig = await discoverAndValidateOIDCIssuerWellKnown(issuer); + } catch (e) { + logger.error("Failed to discover OIDC metadata", e); + } + + if (oidcClientConfig?.metadata.grant_types_supported.includes(DEVICE_CODE_SCOPE)) { + await this.send({ + type: PayloadType.Protocols, + protocols: ["device_authorization_grant"], + homeserver: this.client!.getDomain()!, + }); + } else { + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.UnsupportedProtocol, + }); + throw new RendezvousError( + "Device code grant unsupported", + MSC4108FailureReason.UnsupportedProtocol, + ); + } + } + } else if (this.isNewDevice) { + // MSC4108-Flow: ExistingScanned - wait for protocols message + logger.info("Waiting for protocols message"); + const payload = await this.receive(); + + if (payload?.type === PayloadType.Failure) { + throw new RendezvousError("Failed", payload.reason); + } + + if (payload?.type !== PayloadType.Protocols) { + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.UnexpectedMessageReceived, + }); + throw new RendezvousError( + "Unexpected message received", + MSC4108FailureReason.UnexpectedMessageReceived, + ); + } + + return { serverName: payload.homeserver }; + } else { + // MSC4108-Flow: NewScanned - nothing to do + } + return {}; + } + + /** + * The second & third step in the OIDC QR login process. + * To be called after `negotiateProtocols` for the existing device. + * To be called after OIDC negotiation for the new device. (Currently unsupported) + */ + public async deviceAuthorizationGrant(): Promise<{ + verificationUri?: string; + userCode?: string; + }> { + if (this.isNewDevice) { + throw new Error("New device flows around OIDC are not yet implemented"); + } else { + // The user needs to do step 7 for the out-of-band confirmation + // but, first we receive the protocol chosen by the other device so that + // the confirmation_uri is ready to go + logger.info("Waiting for protocol message"); + const payload = await this.receive(); + + if (payload?.type === PayloadType.Failure) { + throw new RendezvousError("Failed", payload.reason); + } + + if (payload?.type !== PayloadType.Protocol) { + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.UnexpectedMessageReceived, + }); + throw new RendezvousError( + "Unexpected message received", + MSC4108FailureReason.UnexpectedMessageReceived, + ); + } + + if (isDeviceAuthorizationGrantProtocolPayload(payload)) { + const { device_authorization_grant: dag, device_id: expectingNewDeviceId } = payload; + const { verification_uri: verificationUri, verification_uri_complete: verificationUriComplete } = dag; + + let deviceAlreadyExists = true; + try { + await this.client?.getDevice(expectingNewDeviceId); + } catch (err: MatrixError | unknown) { + if (err instanceof MatrixError && err.httpStatus === 404) { + deviceAlreadyExists = false; + } + } + + if (deviceAlreadyExists) { + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.DeviceAlreadyExists, + }); + throw new RendezvousError( + "Specified device ID already exists", + MSC4108FailureReason.DeviceAlreadyExists, + ); + } + + this.expectingNewDeviceId = expectingNewDeviceId; + + return { verificationUri: verificationUriComplete ?? verificationUri }; + } + + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.UnsupportedProtocol, + }); + throw new RendezvousError( + "Received a request for an unsupported protocol", + MSC4108FailureReason.UnsupportedProtocol, + ); + } + } + + /** + * The fifth (and final) step in the OIDC QR login process. + * To be called after the new device has completed authentication. + */ + public async shareSecrets(): Promise<{ secrets?: Omit }> { + if (this.isNewDevice) { + await this.send({ + type: PayloadType.Success, + }); + // then wait for secrets + logger.info("Waiting for secrets message"); + const payload = await this.receive(); + if (payload?.type === PayloadType.Failure) { + throw new RendezvousError("Failed", payload.reason); + } + + if (payload?.type !== PayloadType.Secrets) { + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.UnexpectedMessageReceived, + }); + throw new RendezvousError( + "Unexpected message received", + MSC4108FailureReason.UnexpectedMessageReceived, + ); + } + return { secrets: payload }; + // then done? + } else { + if (!this.expectingNewDeviceId) { + throw new Error("No new device ID expected"); + } + await this.send({ + type: PayloadType.ProtocolAccepted, + }); + + logger.info("Waiting for outcome message"); + const payload = await this.receive(); + + if (payload?.type === PayloadType.Failure) { + throw new RendezvousError("Failed", payload.reason); + } + + if (payload?.type === PayloadType.Declined) { + throw new RendezvousError("User declined", ClientRendezvousFailureReason.UserDeclined); + } + + if (payload?.type !== PayloadType.Success) { + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.UnexpectedMessageReceived, + }); + throw new RendezvousError("Unexpected message", MSC4108FailureReason.UnexpectedMessageReceived); + } + + const timeout = Date.now() + 10000; // wait up to 10 seconds + do { + // is the device visible via the Homeserver? + try { + const device = await this.client?.getDevice(this.expectingNewDeviceId); + + if (device) { + // if so, return the secrets + const secretsBundle = await this.client!.getCrypto()!.exportSecretsBundle!(); + if (this.channel.cancelled) { + throw new RendezvousError("User cancelled", MSC4108FailureReason.UserCancelled); + } + // send secrets + await this.send({ + type: PayloadType.Secrets, + ...secretsBundle, + }); + return { secrets: secretsBundle }; + // let the other side close the rendezvous session + } + } catch (err: MatrixError | unknown) { + if (err instanceof MatrixError && err.httpStatus === 404) { + // not found, so keep waiting until timeout + } else { + throw err; + } + } + await sleep(1000); + } while (Date.now() < timeout); + + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.DeviceNotFound, + }); + throw new RendezvousError("New device not found", MSC4108FailureReason.DeviceNotFound); + } + } + + private async receive(): Promise { + return (await this.channel.secureReceive()) as T | undefined; + } + + private async send(payload: T): Promise { + await this.channel.secureSend(payload); + } + + /** + * Decline the login on the existing device. + */ + public async declineLoginOnExistingDevice(): Promise { + if (!this.isExistingDevice) { + throw new Error("Can only decline login on existing device"); + } + await this.send({ + type: PayloadType.Failure, + reason: MSC4108FailureReason.UserCancelled, + }); + } + + /** + * Cancels the rendezvous session. + * @param reason the reason for the cancellation + */ + public async cancel(reason: MSC4108FailureReason | ClientRendezvousFailureReason): Promise { + this.onFailure?.(reason); + await this.channel.cancel(reason); + } + + /** + * Closes the rendezvous session. + */ + public async close(): Promise { + await this.channel.close(); + } +} diff --git a/src/rendezvous/RendezvousChannel.ts b/src/rendezvous/RendezvousChannel.ts index 549ebc83f51..ced8523bdb4 100644 --- a/src/rendezvous/RendezvousChannel.ts +++ b/src/rendezvous/RendezvousChannel.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RendezvousCode, RendezvousIntent, RendezvousFailureReason } from "."; +import { RendezvousCode, RendezvousIntent, RendezvousFailureReason } from "./index.ts"; export interface RendezvousChannel { /** diff --git a/src/rendezvous/RendezvousCode.ts b/src/rendezvous/RendezvousCode.ts index 86608aa1c44..e5b89aae67c 100644 --- a/src/rendezvous/RendezvousCode.ts +++ b/src/rendezvous/RendezvousCode.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RendezvousTransportDetails, RendezvousIntent } from "."; +import { RendezvousTransportDetails, RendezvousIntent } from "./index.ts"; export interface RendezvousCode { intent: RendezvousIntent; diff --git a/src/rendezvous/RendezvousError.ts b/src/rendezvous/RendezvousError.ts index b3026d43b87..502538fff61 100644 --- a/src/rendezvous/RendezvousError.ts +++ b/src/rendezvous/RendezvousError.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RendezvousFailureReason } from "."; +import { RendezvousFailureReason } from "./index.ts"; export class RendezvousError extends Error { public constructor( diff --git a/src/rendezvous/RendezvousFailureReason.ts b/src/rendezvous/RendezvousFailureReason.ts index b19a91cec0b..7a0116ca0e1 100644 --- a/src/rendezvous/RendezvousFailureReason.ts +++ b/src/rendezvous/RendezvousFailureReason.ts @@ -16,16 +16,47 @@ limitations under the License. export type RendezvousFailureListener = (reason: RendezvousFailureReason) => void; -export enum RendezvousFailureReason { +export type RendezvousFailureReason = + | LegacyRendezvousFailureReason + | MSC4108FailureReason + | ClientRendezvousFailureReason; + +export enum LegacyRendezvousFailureReason { UserDeclined = "user_declined", - OtherDeviceNotSignedIn = "other_device_not_signed_in", - OtherDeviceAlreadySignedIn = "other_device_already_signed_in", Unknown = "unknown", Expired = "expired", UserCancelled = "user_cancelled", - InvalidCode = "invalid_code", UnsupportedAlgorithm = "unsupported_algorithm", - DataMismatch = "data_mismatch", - UnsupportedTransport = "unsupported_transport", + UnsupportedProtocol = "unsupported_protocol", + HomeserverLacksSupport = "homeserver_lacks_support", +} + +export enum MSC4108FailureReason { + AuthorizationExpired = "authorization_expired", + DeviceAlreadyExists = "device_already_exists", + DeviceNotFound = "device_not_found", + UnexpectedMessageReceived = "unexpected_message_received", + UnsupportedProtocol = "unsupported_protocol", + UserCancelled = "user_cancelled", +} + +export enum ClientRendezvousFailureReason { + /** The sign in request has expired */ + Expired = "expired", + /** The homeserver is lacking support for the required features */ HomeserverLacksSupport = "homeserver_lacks_support", + /** The secure channel verification failed meaning that it might be compromised */ + InsecureChannelDetected = "insecure_channel_detected", + /** An invalid/incompatible QR code was scanned */ + InvalidCode = "invalid_code", + /** The other device is not signed in */ + OtherDeviceNotSignedIn = "other_device_not_signed_in", + /** The other device is already signed in */ + OtherDeviceAlreadySignedIn = "other_device_already_signed_in", + /** Other */ + Unknown = "unknown", + /** The user declined the sign in request */ + UserDeclined = "user_declined", + /** The rendezvous request is missing an ETag header */ + ETagMissing = "etag_missing", } diff --git a/src/rendezvous/RendezvousTransport.ts b/src/rendezvous/RendezvousTransport.ts index 08905be65e8..a86db5fc076 100644 --- a/src/rendezvous/RendezvousTransport.ts +++ b/src/rendezvous/RendezvousTransport.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RendezvousFailureListener, RendezvousFailureReason } from "."; +import { RendezvousFailureListener, RendezvousFailureReason } from "./index.ts"; export interface RendezvousTransportDetails { type: string; diff --git a/src/rendezvous/channels/MSC3903ECDHv2RendezvousChannel.ts b/src/rendezvous/channels/MSC3903ECDHv2RendezvousChannel.ts index 872c6ea2c78..47b8e3fd8dc 100644 --- a/src/rendezvous/channels/MSC3903ECDHv2RendezvousChannel.ts +++ b/src/rendezvous/channels/MSC3903ECDHv2RendezvousChannel.ts @@ -17,18 +17,17 @@ limitations under the License. import { SAS } from "@matrix-org/olm"; import { - RendezvousError, + LegacyRendezvousFailureReason as RendezvousFailureReason, + RendezvousChannel, RendezvousCode, + RendezvousError, RendezvousIntent, - RendezvousChannel, - RendezvousTransportDetails, RendezvousTransport, - RendezvousFailureReason, -} from ".."; -import { encodeUnpaddedBase64, decodeBase64 } from "../../base64"; -import { crypto, subtleCrypto, TextEncoder } from "../../crypto/crypto"; -import { generateDecimalSas } from "../../crypto/verification/SASDecimal"; -import { UnstableValue } from "../../NamespacedValue"; + RendezvousTransportDetails, +} from "../index.ts"; +import { decodeBase64, encodeUnpaddedBase64 } from "../../base64.ts"; +import { generateDecimalSas } from "../../crypto/verification/SASDecimal.ts"; +import { UnstableValue } from "../../NamespacedValue.ts"; const ECDH_V2 = new UnstableValue( "m.rendezvous.v2.curve25519-aes-sha256", @@ -56,11 +55,11 @@ export interface EncryptedPayload { } async function importKey(key: Uint8Array): Promise { - if (!subtleCrypto) { + if (!globalThis.crypto.subtle) { throw new Error("Web Crypto is not available"); } - const imported = subtleCrypto.importKey("raw", key, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]); + const imported = globalThis.crypto.subtle.importKey("raw", key, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]); return imported; } @@ -69,6 +68,9 @@ async function importKey(key: Uint8Array): Promise { * Implementation of the unstable [MSC3903](https://github.com/matrix-org/matrix-spec-proposals/pull/3903) * X25519/ECDH key agreement based secure rendezvous channel. * Note that this is UNSTABLE and may have breaking changes without notice. + * MSC3886/MSC3903/MSC3906 are now closed and so this functionality will be removed in future. + * However, we want to keep this implementation around for some time. + * TODO: define an end-of-life date for this implementation. */ export class MSC3903ECDHv2RendezvousChannel implements RendezvousChannel { private olmSAS?: SAS; @@ -161,16 +163,16 @@ export class MSC3903ECDHv2RendezvousChannel implements RendezvousChannel { } private async encrypt(data: T): Promise { - if (!subtleCrypto) { + if (!globalThis.crypto.subtle) { throw new Error("Web Crypto is not available"); } const iv = new Uint8Array(32); - crypto.getRandomValues(iv); + globalThis.crypto.getRandomValues(iv); const encodedData = new TextEncoder().encode(JSON.stringify(data)); - const ciphertext = await subtleCrypto.encrypt( + const ciphertext = await globalThis.crypto.subtle.encrypt( { name: "AES-GCM", iv, @@ -205,11 +207,11 @@ export class MSC3903ECDHv2RendezvousChannel implements RendezvousChannel { const ciphertextBytes = decodeBase64(ciphertext); - if (!subtleCrypto) { + if (!globalThis.crypto.subtle) { throw new Error("Web Crypto is not available"); } - const plaintext = await subtleCrypto.decrypt( + const plaintext = await globalThis.crypto.subtle.decrypt( { name: "AES-GCM", iv: decodeBase64(iv), diff --git a/src/rendezvous/channels/MSC4108SecureChannel.ts b/src/rendezvous/channels/MSC4108SecureChannel.ts new file mode 100644 index 00000000000..8165000e768 --- /dev/null +++ b/src/rendezvous/channels/MSC4108SecureChannel.ts @@ -0,0 +1,270 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { + Curve25519PublicKey, + Ecies, + EstablishedEcies, + QrCodeData, + QrCodeMode, +} from "@matrix-org/matrix-sdk-crypto-wasm"; + +import { + ClientRendezvousFailureReason, + MSC4108FailureReason, + MSC4108Payload, + RendezvousError, + RendezvousFailureListener, +} from "../index.ts"; +import { MSC4108RendezvousSession } from "../transports/MSC4108RendezvousSession.ts"; +import { logger } from "../../logger.ts"; + +/** + * Prototype of the unstable [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108) + * secure rendezvous session protocol. + * @experimental Note that this is UNSTABLE and may have breaking changes without notice. + * Imports @matrix-org/matrix-sdk-crypto-wasm so should be async-imported to avoid bundling the WASM into the main bundle. + */ +export class MSC4108SecureChannel { + private readonly secureChannel: Ecies; + private establishedChannel?: EstablishedEcies; + private connected = false; + + public constructor( + private rendezvousSession: MSC4108RendezvousSession, + private theirPublicKey?: Curve25519PublicKey, + public onFailure?: RendezvousFailureListener, + ) { + this.secureChannel = new Ecies(); + } + + /** + * Generate a QR code for the current session. + * @param mode the mode to generate the QR code in, either `Login` or `Reciprocate`. + * @param serverName the name of the homeserver to connect to, as defined by server discovery in the spec, required for `Reciprocate` mode. + */ + public async generateCode(mode: QrCodeMode.Login): Promise; + public async generateCode(mode: QrCodeMode.Reciprocate, serverName: string): Promise; + public async generateCode(mode: QrCodeMode, serverName?: string): Promise { + const { url } = this.rendezvousSession; + + if (!url) { + throw new Error("No rendezvous session URL"); + } + + return new QrCodeData( + this.secureChannel.public_key(), + url, + mode === QrCodeMode.Reciprocate ? serverName : undefined, + ).toBytes(); + } + + /** + * Returns the check code for the secure channel or undefined if not generated yet. + */ + public getCheckCode(): string | undefined { + const x = this.establishedChannel?.check_code(); + + if (!x) { + return undefined; + } + return Array.from(x.as_bytes()) + .map((b) => `${b % 10}`) + .join(""); + } + + /** + * Connects and establishes a secure channel with the other device. + */ + public async connect(): Promise { + if (this.connected) { + throw new Error("Channel already connected"); + } + + if (this.theirPublicKey) { + // We are the scanning device + const result = this.secureChannel.establish_outbound_channel( + this.theirPublicKey, + "MATRIX_QR_CODE_LOGIN_INITIATE", + ); + this.establishedChannel = result.channel; + + /* + Secure Channel step 4. Device S sends the initial message + + Nonce := 0 + SH := ECDH(Ss, Gp) + EncKey := HKDF_SHA256(SH, "MATRIX_QR_CODE_LOGIN|" || Gp || "|" || Sp, 0, 32) + TaggedCiphertext := ChaCha20Poly1305_Encrypt(EncKey, Nonce, "MATRIX_QR_CODE_LOGIN_INITIATE") + Nonce := Nonce + 2 + LoginInitiateMessage := UnpaddedBase64(TaggedCiphertext) || "|" || UnpaddedBase64(Sp) + */ + { + logger.info("Sending LoginInitiateMessage"); + await this.rendezvousSession.send(result.initial_message); + } + + /* + Secure Channel step 6. Verification by Device S + + Nonce_G := 1 + (TaggedCiphertext, Sp) := Unpack(Message) + Plaintext := ChaCha20Poly1305_Decrypt(EncKey, Nonce_G, TaggedCiphertext) + Nonce_G := Nonce_G + 2 + + unless Plaintext == "MATRIX_QR_CODE_LOGIN_OK": + FAIL + */ + { + logger.info("Waiting for LoginOkMessage"); + const ciphertext = await this.rendezvousSession.receive(); + + if (!ciphertext) { + throw new RendezvousError( + "No response from other device", + MSC4108FailureReason.UnexpectedMessageReceived, + ); + } + const candidateLoginOkMessage = await this.decrypt(ciphertext); + + if (candidateLoginOkMessage !== "MATRIX_QR_CODE_LOGIN_OK") { + throw new RendezvousError( + "Invalid response from other device", + ClientRendezvousFailureReason.InsecureChannelDetected, + ); + } + + // Step 6 is now complete. We trust the channel + } + } else { + /* + Secure Channel step 5. Device G confirms + + Nonce_S := 0 + (TaggedCiphertext, Sp) := Unpack(LoginInitiateMessage) + SH := ECDH(Gs, Sp) + EncKey := HKDF_SHA256(SH, "MATRIX_QR_CODE_LOGIN|" || Gp || "|" || Sp, 0, 32) + Plaintext := ChaCha20Poly1305_Decrypt(EncKey, Nonce_S, TaggedCiphertext) + Nonce_S := Nonce_S + 2 + */ + // wait for the other side to send us their public key + logger.info("Waiting for LoginInitiateMessage"); + const loginInitiateMessage = await this.rendezvousSession.receive(); + if (!loginInitiateMessage) { + throw new Error("No response from other device"); + } + + const { channel, message: candidateLoginInitiateMessage } = + this.secureChannel.establish_inbound_channel(loginInitiateMessage); + this.establishedChannel = channel; + + if (candidateLoginInitiateMessage !== "MATRIX_QR_CODE_LOGIN_INITIATE") { + throw new RendezvousError( + "Invalid response from other device", + ClientRendezvousFailureReason.InsecureChannelDetected, + ); + } + logger.info("LoginInitiateMessage received"); + + logger.info("Sending LoginOkMessage"); + const loginOkMessage = await this.encrypt("MATRIX_QR_CODE_LOGIN_OK"); + await this.rendezvousSession.send(loginOkMessage); + + // Step 5 is complete. We don't yet trust the channel + + // next step will be for the user to confirm the check code on the other device + } + + this.connected = true; + } + + private async decrypt(ciphertext: string): Promise { + if (!this.establishedChannel) { + throw new Error("Channel closed"); + } + + return this.establishedChannel.decrypt(ciphertext); + } + + private async encrypt(plaintext: string): Promise { + if (!this.establishedChannel) { + throw new Error("Channel closed"); + } + + return this.establishedChannel.encrypt(plaintext); + } + + /** + * Sends a payload securely to the other device. + * @param payload the payload to encrypt and send + */ + public async secureSend(payload: T): Promise { + if (!this.connected) { + throw new Error("Channel closed"); + } + + const stringifiedPayload = JSON.stringify(payload); + logger.debug(`=> {"type": ${JSON.stringify(payload.type)}, ...}`); + + await this.rendezvousSession.send(await this.encrypt(stringifiedPayload)); + } + + /** + * Receives an encrypted payload from the other device and decrypts it. + */ + public async secureReceive(): Promise | undefined> { + if (!this.establishedChannel) { + throw new Error("Channel closed"); + } + + const ciphertext = await this.rendezvousSession.receive(); + if (!ciphertext) { + return undefined; + } + const plaintext = await this.decrypt(ciphertext); + const json = JSON.parse(plaintext); + + logger.debug(`<= {"type": ${JSON.stringify(json.type)}, ...}`); + return json as Partial | undefined; + } + + /** + * Closes the secure channel. + */ + public async close(): Promise { + await this.rendezvousSession.close(); + } + + /** + * Cancels the secure channel. + * @param reason the reason for the cancellation + */ + public async cancel(reason: MSC4108FailureReason | ClientRendezvousFailureReason): Promise { + try { + await this.rendezvousSession.cancel(reason); + this.onFailure?.(reason); + } finally { + await this.close(); + } + } + + /** + * Returns whether the rendezvous session has been cancelled. + */ + public get cancelled(): boolean { + return this.rendezvousSession.cancelled; + } +} diff --git a/src/rendezvous/channels/index.ts b/src/rendezvous/channels/index.ts index f157bbeaef1..c525e278485 100644 --- a/src/rendezvous/channels/index.ts +++ b/src/rendezvous/channels/index.ts @@ -14,4 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -export * from "./MSC3903ECDHv2RendezvousChannel"; +/** + * @deprecated in favour of MSC4108-based implementation + */ +export * from "./MSC3903ECDHv2RendezvousChannel.ts"; +export * from "./MSC4108SecureChannel.ts"; diff --git a/src/rendezvous/index.ts b/src/rendezvous/index.ts index 379b13351b8..5b8d83f51e8 100644 --- a/src/rendezvous/index.ts +++ b/src/rendezvous/index.ts @@ -14,10 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -export * from "./MSC3906Rendezvous"; -export * from "./RendezvousChannel"; -export * from "./RendezvousCode"; -export * from "./RendezvousError"; -export * from "./RendezvousFailureReason"; -export * from "./RendezvousIntent"; -export * from "./RendezvousTransport"; +/** + * @deprecated in favour of MSC4108-based implementation + */ +export * from "./MSC3906Rendezvous.ts"; +export * from "./MSC4108SignInWithQR.ts"; +export * from "./RendezvousChannel.ts"; +export * from "./RendezvousCode.ts"; +export * from "./RendezvousError.ts"; +export * from "./RendezvousFailureReason.ts"; +export * from "./RendezvousIntent.ts"; +export * from "./RendezvousTransport.ts"; +export * from "./transports/index.ts"; +export * from "./channels/index.ts"; diff --git a/src/rendezvous/transports/MSC3886SimpleHttpRendezvousTransport.ts b/src/rendezvous/transports/MSC3886SimpleHttpRendezvousTransport.ts index 430ee92d1c7..b8521eda420 100644 --- a/src/rendezvous/transports/MSC3886SimpleHttpRendezvousTransport.ts +++ b/src/rendezvous/transports/MSC3886SimpleHttpRendezvousTransport.ts @@ -16,16 +16,16 @@ limitations under the License. import { UnstableValue } from "matrix-events-sdk"; -import { logger } from "../../logger"; -import { sleep } from "../../utils"; +import { logger } from "../../logger.ts"; +import { sleep } from "../../utils.ts"; import { RendezvousFailureListener, - RendezvousFailureReason, + LegacyRendezvousFailureReason as RendezvousFailureReason, RendezvousTransport, RendezvousTransportDetails, -} from ".."; -import { MatrixClient } from "../../matrix"; -import { ClientPrefix } from "../../http-api"; +} from "../index.ts"; +import { MatrixClient } from "../../matrix.ts"; +import { ClientPrefix } from "../../http-api/index.ts"; const TYPE = new UnstableValue("http.v1", "org.matrix.msc3886.http.v1"); @@ -37,6 +37,9 @@ export interface MSC3886SimpleHttpRendezvousTransportDetails extends RendezvousT * Implementation of the unstable [MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886) * simple HTTP rendezvous protocol. * Note that this is UNSTABLE and may have breaking changes without notice. + * MSC3886/MSC3903/MSC3906 are now closed and so this functionality will be removed in future. + * However, we want to keep this implementation around for some time. + * TODO: define an end-of-life date for this implementation. */ export class MSC3886SimpleHttpRendezvousTransport implements RendezvousTransport { private uri?: string; diff --git a/src/rendezvous/transports/MSC4108RendezvousSession.ts b/src/rendezvous/transports/MSC4108RendezvousSession.ts new file mode 100644 index 00000000000..98091471fae --- /dev/null +++ b/src/rendezvous/transports/MSC4108RendezvousSession.ts @@ -0,0 +1,270 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { logger } from "../../logger.ts"; +import { sleep } from "../../utils.ts"; +import { ClientRendezvousFailureReason, MSC4108FailureReason, RendezvousFailureListener } from "../index.ts"; +import { MatrixClient, Method } from "../../matrix.ts"; +import { ClientPrefix } from "../../http-api/index.ts"; + +/** + * Prototype of the unstable [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108) + * insecure rendezvous session protocol. + * @experimental Note that this is UNSTABLE and may have breaking changes without notice. + */ +export class MSC4108RendezvousSession { + public url?: string; + private readonly client?: MatrixClient; + private readonly fallbackRzServer?: string; + private readonly fetchFn?: typeof global.fetch; + private readonly onFailure?: RendezvousFailureListener; + private etag?: string; + private expiresAt?: Date; + private expiresTimer?: ReturnType; + private _cancelled = false; + private _ready = false; + + public constructor({ + onFailure, + url, + fetchFn, + }: { + fetchFn?: typeof global.fetch; + onFailure?: RendezvousFailureListener; + url: string; + }); + public constructor({ + onFailure, + client, + fallbackRzServer, + fetchFn, + }: { + fetchFn?: typeof global.fetch; + onFailure?: RendezvousFailureListener; + client?: MatrixClient; + fallbackRzServer?: string; + }); + public constructor({ + fetchFn, + onFailure, + url, + client, + fallbackRzServer, + }: { + fetchFn?: typeof global.fetch; + onFailure?: RendezvousFailureListener; + url?: string; + client?: MatrixClient; + fallbackRzServer?: string; + }) { + this.fetchFn = fetchFn; + this.onFailure = onFailure; + this.client = client; + this.fallbackRzServer = fallbackRzServer; + this.url = url; + } + + /** + * Returns whether the channel is ready to be used. + */ + public get ready(): boolean { + return this._ready; + } + + /** + * Returns whether the channel has been cancelled. + */ + public get cancelled(): boolean { + return this._cancelled; + } + + private fetch(resource: URL | string, options?: RequestInit): ReturnType { + if (this.fetchFn) { + return this.fetchFn(resource, options); + } + return global.fetch(resource, options); + } + + private async getPostEndpoint(): Promise { + if (this.client) { + try { + if (await this.client.doesServerSupportUnstableFeature("org.matrix.msc4108")) { + return this.client.http + .getUrl("/org.matrix.msc4108/rendezvous", undefined, ClientPrefix.Unstable) + .toString(); + } + } catch (err) { + logger.warn("Failed to get unstable features", err); + } + } + + return this.fallbackRzServer; + } + + /** + * Sends data via the rendezvous channel. + * @param data the payload to send + */ + public async send(data: string): Promise { + if (this._cancelled) { + return; + } + const method = this.url ? Method.Put : Method.Post; + const uri = this.url ?? (await this.getPostEndpoint()); + + if (!uri) { + throw new Error("Invalid rendezvous URI"); + } + + const headers: Record = { "content-type": "text/plain" }; + + // if we didn't create the rendezvous channel, we need to fetch the first etag if needed + if (!this.etag && this.url) { + await this.receive(); + } + + if (this.etag) { + headers["if-match"] = this.etag; + } + + logger.info(`=> ${method} ${uri} with ${data} if-match: ${this.etag}`); + + const res = await this.fetch(uri, { method, headers, body: data, redirect: "follow" }); + if (res.status === 404) { + return this.cancel(ClientRendezvousFailureReason.Unknown); + } + this.etag = res.headers.get("etag") ?? undefined; + + logger.info(`Received etag: ${this.etag}`); + + if (method === Method.Post) { + const expires = res.headers.get("expires"); + if (expires) { + if (this.expiresTimer) { + clearTimeout(this.expiresTimer); + this.expiresTimer = undefined; + } + this.expiresAt = new Date(expires); + this.expiresTimer = setTimeout(() => { + this.expiresTimer = undefined; + this.cancel(ClientRendezvousFailureReason.Expired); + }, this.expiresAt.getTime() - Date.now()); + } + // MSC4108: we expect a JSON response with a rendezvous URL + const json = await res.json(); + if (typeof json.url !== "string") { + throw new Error("No rendezvous URL given"); + } + this.url = json.url; + this._ready = true; + } + } + + /** + * Receives data from the rendezvous channel. + * @return the returned promise won't resolve until new data is acquired or the channel is closed either by the server or the other party. + */ + public async receive(): Promise { + if (!this.url) { + throw new Error("Rendezvous not set up"); + } + // eslint-disable-next-line no-constant-condition + while (true) { + if (this._cancelled) { + return undefined; + } + + const headers: Record = {}; + if (this.etag) { + headers["if-none-match"] = this.etag; + } + + logger.info(`=> GET ${this.url} if-none-match: ${this.etag}`); + const poll = await this.fetch(this.url, { method: Method.Get, headers }); + + if (poll.status === 404) { + await this.cancel(ClientRendezvousFailureReason.Unknown); + return undefined; + } + + // rely on server expiring the channel rather than checking ourselves + + const etag = poll.headers.get("etag") ?? undefined; + if (poll.headers.get("content-type") !== "text/plain") { + this.etag = etag; + } else if (poll.status === 200) { + if (!etag) { + // Some browsers & extensions block the ETag header for anti-tracking purposes + // We try and detect this so the client can give the user a somewhat helpful message + await this.cancel(ClientRendezvousFailureReason.ETagMissing); + return undefined; + } + + this.etag = etag; + const text = await poll.text(); + logger.info(`Received: ${text} with etag ${this.etag}`); + return text; + } + await sleep(1000); + } + } + + /** + * Cancels the rendezvous channel. + * If the reason is user_declined or user_cancelled then the channel will also be closed. + * @param reason the reason to cancel with + */ + public async cancel(reason: MSC4108FailureReason | ClientRendezvousFailureReason): Promise { + if (this._cancelled) return; + if (this.expiresTimer) { + clearTimeout(this.expiresTimer); + this.expiresTimer = undefined; + } + + if ( + reason === ClientRendezvousFailureReason.Unknown && + this.expiresAt && + this.expiresAt.getTime() < Date.now() + ) { + reason = ClientRendezvousFailureReason.Expired; + } + + this._cancelled = true; + this._ready = false; + this.onFailure?.(reason); + + if (reason === ClientRendezvousFailureReason.UserDeclined || reason === MSC4108FailureReason.UserCancelled) { + await this.close(); + } + } + + /** + * Closes the rendezvous channel. + */ + public async close(): Promise { + if (this.expiresTimer) { + clearTimeout(this.expiresTimer); + this.expiresTimer = undefined; + } + + if (!this.url) return; + try { + await this.fetch(this.url, { method: Method.Delete }); + } catch (e) { + logger.warn(e); + } + } +} diff --git a/src/rendezvous/transports/index.ts b/src/rendezvous/transports/index.ts index 6d8d64245e4..88fe91ba1d9 100644 --- a/src/rendezvous/transports/index.ts +++ b/src/rendezvous/transports/index.ts @@ -14,4 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -export * from "./MSC3886SimpleHttpRendezvousTransport"; +/** + * @deprecated in favour of MSC4108-based implementation + */ +export * from "./MSC3886SimpleHttpRendezvousTransport.ts"; +export * from "./MSC4108RendezvousSession.ts"; diff --git a/src/room-hierarchy.ts b/src/room-hierarchy.ts index 5c0b61d743f..58e952545af 100644 --- a/src/room-hierarchy.ts +++ b/src/room-hierarchy.ts @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Room } from "./models/room"; -import { IHierarchyRoom, IHierarchyRelation } from "./@types/spaces"; -import { MatrixClient } from "./client"; -import { EventType } from "./@types/event"; -import { MatrixError } from "./http-api"; +import { Room } from "./models/room.ts"; +import { IHierarchyRoom, IHierarchyRelation } from "./@types/spaces.ts"; +import { MatrixClient } from "./client.ts"; +import { EventType } from "./@types/event.ts"; +import { MatrixError } from "./http-api/index.ts"; export class RoomHierarchy { // Map from room id to list of servers which are listed as a via somewhere in the loaded hierarchy diff --git a/src/rust-crypto/CrossSigningIdentity.ts b/src/rust-crypto/CrossSigningIdentity.ts index 7a994a8d049..76f7189db9b 100644 --- a/src/rust-crypto/CrossSigningIdentity.ts +++ b/src/rust-crypto/CrossSigningIdentity.ts @@ -17,11 +17,11 @@ limitations under the License. import { OlmMachine, CrossSigningStatus, CrossSigningBootstrapRequests } from "@matrix-org/matrix-sdk-crypto-wasm"; import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; -import { BootstrapCrossSigningOpts } from "../crypto-api"; -import { logger } from "../logger"; -import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor"; -import { UIAuthCallback } from "../interactive-auth"; -import { ServerSideSecretStorage } from "../secret-storage"; +import { BootstrapCrossSigningOpts } from "../crypto-api/index.ts"; +import { logger } from "../logger.ts"; +import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts"; +import { UIAuthCallback } from "../interactive-auth.ts"; +import { ServerSideSecretStorage } from "../secret-storage.ts"; /** Manages the cross-signing keys for our own user. * diff --git a/src/rust-crypto/DehydratedDeviceManager.ts b/src/rust-crypto/DehydratedDeviceManager.ts index 56f6052b724..ca6be006f1b 100644 --- a/src/rust-crypto/DehydratedDeviceManager.ts +++ b/src/rust-crypto/DehydratedDeviceManager.ts @@ -16,14 +16,13 @@ limitations under the License. import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; -import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor"; -import { encodeUri } from "../utils"; -import { IHttpOpts, MatrixError, MatrixHttpApi, Method } from "../http-api"; -import { IToDeviceEvent } from "../sync-accumulator"; -import { ServerSideSecretStorage } from "../secret-storage"; -import { crypto } from "../crypto/crypto"; -import { decodeBase64, encodeUnpaddedBase64 } from "../base64"; -import { Logger } from "../logger"; +import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts"; +import { encodeUri } from "../utils.ts"; +import { IHttpOpts, MatrixError, MatrixHttpApi, Method } from "../http-api/index.ts"; +import { IToDeviceEvent } from "../sync-accumulator.ts"; +import { ServerSideSecretStorage } from "../secret-storage.ts"; +import { decodeBase64, encodeUnpaddedBase64 } from "../base64.ts"; +import { Logger } from "../logger.ts"; /** * The response body of `GET /_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device`. @@ -155,7 +154,7 @@ export class DehydratedDeviceManager { */ public async resetKey(): Promise { const key = new Uint8Array(32); - crypto.getRandomValues(key); + globalThis.crypto.getRandomValues(key); await this.secretStorage.store(SECRET_STORAGE_NAME, encodeUnpaddedBase64(key)); this.key = key; } diff --git a/src/rust-crypto/KeyClaimManager.ts b/src/rust-crypto/KeyClaimManager.ts index aaeed4d1435..3023de8c2f8 100644 --- a/src/rust-crypto/KeyClaimManager.ts +++ b/src/rust-crypto/KeyClaimManager.ts @@ -16,8 +16,8 @@ limitations under the License. import { OlmMachine, UserId } from "@matrix-org/matrix-sdk-crypto-wasm"; -import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor"; -import { LogSpan } from "../logger"; +import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts"; +import { LogSpan } from "../logger.ts"; /** * KeyClaimManager: linearises calls to OlmMachine.getMissingSessions to avoid races diff --git a/src/rust-crypto/OutgoingRequestProcessor.ts b/src/rust-crypto/OutgoingRequestProcessor.ts index d3ae4d9c4a3..ec8e38fcf53 100644 --- a/src/rust-crypto/OutgoingRequestProcessor.ts +++ b/src/rust-crypto/OutgoingRequestProcessor.ts @@ -27,13 +27,13 @@ import { UploadSigningKeysRequest, } from "@matrix-org/matrix-sdk-crypto-wasm"; -import { logger } from "../logger"; -import { calculateRetryBackoff, IHttpOpts, MatrixHttpApi, Method } from "../http-api"; -import { logDuration, QueryDict, sleep } from "../utils"; -import { AuthDict, UIAuthCallback } from "../interactive-auth"; -import { UIAResponse } from "../@types/uia"; -import { ToDeviceMessageId } from "../@types/event"; -import { UnstablePrefix as DehydrationUnstablePrefix } from "./DehydratedDeviceManager"; +import { logger } from "../logger.ts"; +import { calculateRetryBackoff, IHttpOpts, MatrixHttpApi, Method } from "../http-api/index.ts"; +import { logDuration, QueryDict, sleep } from "../utils.ts"; +import { AuthDict, UIAuthCallback } from "../interactive-auth.ts"; +import { UIAResponse } from "../@types/uia.ts"; +import { ToDeviceMessageId } from "../@types/event.ts"; +import { UnstablePrefix as DehydrationUnstablePrefix } from "./DehydratedDeviceManager.ts"; /** * Common interface for all the request types returned by `OlmMachine.outgoingRequests`. diff --git a/src/rust-crypto/OutgoingRequestsManager.ts b/src/rust-crypto/OutgoingRequestsManager.ts index 81b3001c83a..72823d88b60 100644 --- a/src/rust-crypto/OutgoingRequestsManager.ts +++ b/src/rust-crypto/OutgoingRequestsManager.ts @@ -16,9 +16,9 @@ limitations under the License. import { OlmMachine } from "@matrix-org/matrix-sdk-crypto-wasm"; -import { OutgoingRequest, OutgoingRequestProcessor } from "./OutgoingRequestProcessor"; -import { Logger } from "../logger"; -import { defer, IDeferred, logDuration } from "../utils"; +import { OutgoingRequest, OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts"; +import { Logger } from "../logger.ts"; +import { defer, IDeferred, logDuration } from "../utils.ts"; /** * OutgoingRequestsManager: responsible for processing outgoing requests from the OlmMachine. diff --git a/src/rust-crypto/PerSessionKeyBackupDownloader.ts b/src/rust-crypto/PerSessionKeyBackupDownloader.ts index ad5a649c51f..e463cbaa7d9 100644 --- a/src/rust-crypto/PerSessionKeyBackupDownloader.ts +++ b/src/rust-crypto/PerSessionKeyBackupDownloader.ts @@ -17,13 +17,13 @@ limitations under the License. import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; import { OlmMachine } from "@matrix-org/matrix-sdk-crypto-wasm"; -import { Curve25519AuthData, KeyBackupInfo, KeyBackupSession } from "../crypto-api/keybackup"; -import { Logger } from "../logger"; -import { ClientPrefix, IHttpOpts, MatrixError, MatrixHttpApi, Method } from "../http-api"; -import { RustBackupManager } from "./backup"; -import { CryptoEvent } from "../matrix"; -import { encodeUri, sleep } from "../utils"; -import { BackupDecryptor } from "../common-crypto/CryptoBackend"; +import { Curve25519AuthData, KeyBackupInfo, KeyBackupSession } from "../crypto-api/keybackup.ts"; +import { Logger } from "../logger.ts"; +import { ClientPrefix, IHttpOpts, MatrixError, MatrixHttpApi, Method } from "../http-api/index.ts"; +import { RustBackupManager } from "./backup.ts"; +import { CryptoEvent } from "../matrix.ts"; +import { encodeUri, sleep } from "../utils.ts"; +import { BackupDecryptor } from "../common-crypto/CryptoBackend.ts"; // The minimum time to wait between two retries in case of errors. To avoid hammering the server. const KEY_BACKUP_BACKOFF = 5000; // ms diff --git a/src/rust-crypto/RoomEncryptor.ts b/src/rust-crypto/RoomEncryptor.ts index 7447ae61a74..3b6a6c80cc0 100644 --- a/src/rust-crypto/RoomEncryptor.ts +++ b/src/rust-crypto/RoomEncryptor.ts @@ -14,27 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. */ +import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; import { + CollectStrategy, EncryptionAlgorithm, EncryptionSettings, + HistoryVisibility as RustHistoryVisibility, OlmMachine, RoomId, - UserId, - HistoryVisibility as RustHistoryVisibility, ToDeviceRequest, + UserId, } from "@matrix-org/matrix-sdk-crypto-wasm"; -import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; -import { EventType } from "../@types/event"; -import { IContent, MatrixEvent } from "../models/event"; -import { Room } from "../models/room"; -import { Logger, logger, LogSpan } from "../logger"; -import { KeyClaimManager } from "./KeyClaimManager"; -import { RoomMember } from "../models/room-member"; -import { HistoryVisibility } from "../@types/partials"; -import { OutgoingRequestsManager } from "./OutgoingRequestsManager"; -import { logDuration } from "../utils"; -import { KnownMembership } from "../@types/membership"; +import { EventType } from "../@types/event.ts"; +import { IContent, MatrixEvent } from "../models/event.ts"; +import { Room } from "../models/room.ts"; +import { Logger, logger, LogSpan } from "../logger.ts"; +import { KeyClaimManager } from "./KeyClaimManager.ts"; +import { RoomMember } from "../models/room-member.ts"; +import { HistoryVisibility } from "../@types/partials.ts"; +import { OutgoingRequestsManager } from "./OutgoingRequestsManager.ts"; +import { logDuration } from "../utils.ts"; +import { KnownMembership } from "../@types/membership.ts"; /** * RoomEncryptor: responsible for encrypting messages to a given room @@ -105,10 +106,8 @@ export class RoomEncryptor { (member.membership == KnownMembership.Invite && this.room.shouldEncryptForInvitedMembers()) ) { // make sure we are tracking the deviceList for this user - logDuration(this.prefixedLogger, "updateTrackedUsers", async () => { - this.olmMachine.updateTrackedUsers([new UserId(member.userId)]).catch((e) => { - this.prefixedLogger.error("Unable to update tracked users", e); - }); + this.olmMachine.updateTrackedUsers([new UserId(member.userId)]).catch((e) => { + this.prefixedLogger.error("Unable to update tracked users", e); }); } @@ -144,7 +143,7 @@ export class RoomEncryptor { * @param globalBlacklistUnverifiedDevices - When `true`, it will not send encrypted messages to unverified devices */ public encryptEvent(event: MatrixEvent | null, globalBlacklistUnverifiedDevices: boolean): Promise { - const logger = new LogSpan(this.prefixedLogger, event ? event.getTxnId() ?? "" : "prepareForEncryption"); + const logger = new LogSpan(this.prefixedLogger, event ? (event.getTxnId() ?? "") : "prepareForEncryption"); // Ensure order of encryption to avoid message ordering issues, as the scheduler only ensures // events order after they have been encrypted. const prom = this.currentEncryptionPromise @@ -254,8 +253,11 @@ export class RoomEncryptor { // When this.room.getBlacklistUnverifiedDevices() === null, the global settings should be used // See Room#getBlacklistUnverifiedDevices - rustEncryptionSettings.onlyAllowTrustedDevices = - this.room.getBlacklistUnverifiedDevices() ?? globalBlacklistUnverifiedDevices; + if (this.room.getBlacklistUnverifiedDevices() ?? globalBlacklistUnverifiedDevices) { + rustEncryptionSettings.sharingStrategy = CollectStrategy.DeviceBasedStrategyOnlyTrustedDevices; + } else { + rustEncryptionSettings.sharingStrategy = CollectStrategy.DeviceBasedStrategyAllDevices; + } await logDuration(this.prefixedLogger, "shareRoomKey", async () => { const shareMessages: ToDeviceRequest[] = await this.olmMachine.shareRoomKey( diff --git a/src/rust-crypto/backup.ts b/src/rust-crypto/backup.ts index 8eb84887448..c4407da21f8 100644 --- a/src/rust-crypto/backup.ts +++ b/src/rust-crypto/backup.ts @@ -24,19 +24,19 @@ import { KeyBackupInfo, KeyBackupSession, Curve25519SessionData, -} from "../crypto-api/keybackup"; -import { logger } from "../logger"; -import { ClientPrefix, IHttpOpts, MatrixError, MatrixHttpApi, Method } from "../http-api"; -import { CryptoEvent, IMegolmSessionData } from "../crypto"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { encodeUri, logDuration } from "../utils"; -import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor"; -import { sleep } from "../utils"; -import { BackupDecryptor } from "../common-crypto/CryptoBackend"; -import { IEncryptedPayload } from "../crypto/aes"; -import { ImportRoomKeyProgressData, ImportRoomKeysOpts } from "../crypto-api"; -import { IKeyBackupInfo } from "../crypto/keybackup"; -import { IKeyBackup } from "../crypto/backup"; +} from "../crypto-api/keybackup.ts"; +import { logger } from "../logger.ts"; +import { ClientPrefix, IHttpOpts, MatrixError, MatrixHttpApi, Method } from "../http-api/index.ts"; +import { CryptoEvent, IMegolmSessionData } from "../crypto/index.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { encodeUri, logDuration } from "../utils.ts"; +import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts"; +import { sleep } from "../utils.ts"; +import { BackupDecryptor } from "../common-crypto/CryptoBackend.ts"; +import { IEncryptedPayload } from "../crypto/aes.ts"; +import { ImportRoomKeyProgressData, ImportRoomKeysOpts } from "../crypto-api/index.ts"; +import { IKeyBackupInfo } from "../crypto/keybackup.ts"; +import { IKeyBackup } from "../crypto/backup.ts"; /** Authentification of the backup info, depends on algorithm */ type AuthData = KeyBackupInfo["auth_data"]; diff --git a/src/rust-crypto/device-converter.ts b/src/rust-crypto/device-converter.ts index 587640cb0e9..80e8bd373c1 100644 --- a/src/rust-crypto/device-converter.ts +++ b/src/rust-crypto/device-converter.ts @@ -16,8 +16,8 @@ limitations under the License. import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; -import { Device, DeviceVerification } from "../models/device"; -import { DeviceKeys } from "../client"; +import { Device, DeviceVerification } from "../models/device.ts"; +import { DeviceKeys } from "../client.ts"; /** * Convert a {@link RustSdkCryptoJs.Device} to a {@link Device} diff --git a/src/rust-crypto/index.ts b/src/rust-crypto/index.ts index dc9a42af743..61f15a192a1 100644 --- a/src/rust-crypto/index.ts +++ b/src/rust-crypto/index.ts @@ -17,17 +17,17 @@ limitations under the License. import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; import { StoreHandle } from "@matrix-org/matrix-sdk-crypto-wasm"; -import { RustCrypto } from "./rust-crypto"; -import { IHttpOpts, MatrixHttpApi } from "../http-api"; -import { ServerSideSecretStorage } from "../secret-storage"; -import { ICryptoCallbacks } from "../crypto"; -import { Logger } from "../logger"; -import { CryptoStore, MigrationState } from "../crypto/store/base"; +import { RustCrypto } from "./rust-crypto.ts"; +import { IHttpOpts, MatrixHttpApi } from "../http-api/index.ts"; +import { ServerSideSecretStorage } from "../secret-storage.ts"; +import { ICryptoCallbacks } from "../crypto/index.ts"; +import { Logger } from "../logger.ts"; +import { CryptoStore, MigrationState } from "../crypto/store/base.ts"; import { migrateFromLegacyCrypto, migrateLegacyLocalTrustIfNeeded, migrateRoomSettingsFromLegacyCrypto, -} from "./libolm_migration"; +} from "./libolm_migration.ts"; /** * Create a new `RustCrypto` implementation @@ -174,6 +174,9 @@ async function initOlmMachine( await olmMachine.registerRoomKeyUpdatedCallback((sessions: RustSdkCryptoJs.RoomKeyInfo[]) => rustCrypto.onRoomKeysUpdated(sessions), ); + await olmMachine.registerRoomKeysWithheldCallback((withheld: RustSdkCryptoJs.RoomKeyWithheldInfo[]) => + rustCrypto.onRoomKeysWithheld(withheld), + ); await olmMachine.registerUserIdentityUpdatedCallback((userId: RustSdkCryptoJs.UserId) => rustCrypto.onUserIdentityUpdated(userId), ); diff --git a/src/rust-crypto/libolm_migration.ts b/src/rust-crypto/libolm_migration.ts index ec01847262c..50d92a626e1 100644 --- a/src/rust-crypto/libolm_migration.ts +++ b/src/rust-crypto/libolm_migration.ts @@ -16,18 +16,18 @@ limitations under the License. import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; -import { Logger } from "../logger"; -import { CryptoStore, MigrationState, SecretStorePrivateKeys } from "../crypto/store/base"; -import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store"; -import { decryptAES, IEncryptedPayload } from "../crypto/aes"; -import { IHttpOpts, MatrixHttpApi } from "../http-api"; -import { requestKeyBackupVersion } from "./backup"; -import { IRoomEncryption } from "../crypto/RoomList"; -import { CrossSigningKeyInfo, Curve25519AuthData } from "../crypto-api"; -import { RustCrypto } from "./rust-crypto"; -import { KeyBackupInfo } from "../crypto-api/keybackup"; -import { sleep } from "../utils"; -import { encodeBase64 } from "../base64"; +import { Logger } from "../logger.ts"; +import { CryptoStore, MigrationState, SecretStorePrivateKeys } from "../crypto/store/base.ts"; +import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store.ts"; +import { decryptAES, IEncryptedPayload } from "../crypto/aes.ts"; +import { IHttpOpts, MatrixHttpApi } from "../http-api/index.ts"; +import { requestKeyBackupVersion } from "./backup.ts"; +import { IRoomEncryption } from "../crypto/RoomList.ts"; +import { CrossSigningKeyInfo, Curve25519AuthData } from "../crypto-api/index.ts"; +import { RustCrypto } from "./rust-crypto.ts"; +import { KeyBackupInfo } from "../crypto-api/keybackup.ts"; +import { sleep } from "../utils.ts"; +import { encodeBase64 } from "../base64.ts"; /** * Determine if any data needs migrating from the legacy store, and do so. diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index 8cbfba4b0c5..2a4ba09c5eb 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -17,20 +17,25 @@ limitations under the License. import anotherjson from "another-json"; import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm"; -import type { IEventDecryptionResult, IMegolmSessionData } from "../@types/crypto"; -import { KnownMembership } from "../@types/membership"; -import type { IDeviceLists, IToDeviceEvent } from "../sync-accumulator"; -import type { IEncryptedEventInfo } from "../crypto/api"; -import { IContent, MatrixEvent, MatrixEventEvent } from "../models/event"; -import { Room } from "../models/room"; -import { RoomMember } from "../models/room-member"; -import { BackupDecryptor, CryptoBackend, DecryptionError, OnSyncCompletedData } from "../common-crypto/CryptoBackend"; -import { logger, Logger } from "../logger"; -import { IHttpOpts, MatrixHttpApi, Method } from "../http-api"; -import { RoomEncryptor } from "./RoomEncryptor"; -import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor"; -import { KeyClaimManager } from "./KeyClaimManager"; -import { logDuration, MapWithDefault } from "../utils"; +import type { IEventDecryptionResult, IMegolmSessionData } from "../@types/crypto.ts"; +import { KnownMembership } from "../@types/membership.ts"; +import type { IDeviceLists, IToDeviceEvent } from "../sync-accumulator.ts"; +import type { IEncryptedEventInfo } from "../crypto/api.ts"; +import { MatrixEvent, MatrixEventEvent } from "../models/event.ts"; +import { Room } from "../models/room.ts"; +import { RoomMember } from "../models/room-member.ts"; +import { + BackupDecryptor, + CryptoBackend, + DecryptionError, + OnSyncCompletedData, +} from "../common-crypto/CryptoBackend.ts"; +import { logger, Logger } from "../logger.ts"; +import { IHttpOpts, MatrixHttpApi, Method } from "../http-api/index.ts"; +import { RoomEncryptor } from "./RoomEncryptor.ts"; +import { OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts"; +import { KeyClaimManager } from "./KeyClaimManager.ts"; +import { logDuration, MapWithDefault } from "../utils.ts"; import { BackupTrustInfo, BootstrapCrossSigningOpts, @@ -38,6 +43,7 @@ import { CrossSigningKey, CrossSigningKeyInfo, CrossSigningStatus, + CryptoApi, CryptoCallbacks, Curve25519AuthData, DecryptionFailureCode, @@ -52,30 +58,29 @@ import { OwnDeviceKeys, UserVerificationStatus, VerificationRequest, -} from "../crypto-api"; -import { deviceKeysToDeviceMap, rustDeviceToJsDevice } from "./device-converter"; -import { IDownloadKeyResult, IQueryKeysRequest } from "../client"; -import { Device, DeviceMap } from "../models/device"; -import { SECRET_STORAGE_ALGORITHM_V1_AES, ServerSideSecretStorage } from "../secret-storage"; -import { CrossSigningIdentity } from "./CrossSigningIdentity"; -import { secretStorageCanAccessSecrets, secretStorageContainsCrossSigningKeys } from "./secret-storage"; -import { keyFromPassphrase } from "../crypto/key_passphrase"; -import { encodeRecoveryKey } from "../crypto/recoverykey"; -import { crypto } from "../crypto/crypto"; -import { isVerificationEvent, RustVerificationRequest, verificationMethodIdentifierToMethod } from "./verification"; -import { EventType, MsgType } from "../@types/event"; -import { CryptoEvent } from "../crypto"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { RustBackupCryptoEventMap, RustBackupCryptoEvents, RustBackupManager } from "./backup"; -import { TypedReEmitter } from "../ReEmitter"; -import { randomString } from "../randomstring"; -import { ClientStoppedError } from "../errors"; -import { ISignatures } from "../@types/signed"; -import { encodeBase64 } from "../base64"; -import { OutgoingRequestsManager } from "./OutgoingRequestsManager"; -import { PerSessionKeyBackupDownloader } from "./PerSessionKeyBackupDownloader"; -import { DehydratedDeviceManager } from "./DehydratedDeviceManager"; -import { VerificationMethod } from "../types"; +} from "../crypto-api/index.ts"; +import { deviceKeysToDeviceMap, rustDeviceToJsDevice } from "./device-converter.ts"; +import { IDownloadKeyResult, IQueryKeysRequest } from "../client.ts"; +import { Device, DeviceMap } from "../models/device.ts"; +import { SECRET_STORAGE_ALGORITHM_V1_AES, ServerSideSecretStorage } from "../secret-storage.ts"; +import { CrossSigningIdentity } from "./CrossSigningIdentity.ts"; +import { secretStorageCanAccessSecrets, secretStorageContainsCrossSigningKeys } from "./secret-storage.ts"; +import { keyFromPassphrase } from "../crypto/key_passphrase.ts"; +import { encodeRecoveryKey } from "../crypto/recoverykey.ts"; +import { isVerificationEvent, RustVerificationRequest, verificationMethodIdentifierToMethod } from "./verification.ts"; +import { EventType, MsgType } from "../@types/event.ts"; +import { CryptoEvent } from "../crypto/index.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { RustBackupCryptoEventMap, RustBackupCryptoEvents, RustBackupManager } from "./backup.ts"; +import { TypedReEmitter } from "../ReEmitter.ts"; +import { randomString } from "../randomstring.ts"; +import { ClientStoppedError } from "../errors.ts"; +import { ISignatures } from "../@types/signed.ts"; +import { encodeBase64 } from "../base64.ts"; +import { OutgoingRequestsManager } from "./OutgoingRequestsManager.ts"; +import { PerSessionKeyBackupDownloader } from "./PerSessionKeyBackupDownloader.ts"; +import { DehydratedDeviceManager } from "./DehydratedDeviceManager.ts"; +import { VerificationMethod } from "../types.ts"; const ALL_VERIFICATION_METHODS = [ VerificationMethod.Sas, @@ -308,6 +313,40 @@ export class RustCrypto extends TypedEventEmitter): Promise { + if (backupInfo.algorithm != "m.megolm_backup.v1.curve25519-aes-sha2") { + throw new Error(`getBackupDecryptor Unsupported algorithm ${backupInfo.algorithm}`); + } + + const authData = backupInfo.auth_data; + + if (!(privKey instanceof Uint8Array)) { + throw new Error(`getBackupDecryptor expects Uint8Array`); + } + + const backupDecryptionKey = RustSdkCryptoJs.BackupDecryptionKey.fromBase64(encodeBase64(privKey)); + + if (authData.public_key != backupDecryptionKey.megolmV1PublicKey.publicKeyBase64) { + throw new Error(`getBackupDecryptor key mismatch error`); + } + + return this.backupManager.createBackupDecryptor(backupDecryptionKey); + } + + /** + * Implementation of {@link CryptoBackend#importBackedUpRoomKeys}. + */ + public async importBackedUpRoomKeys( + keys: IMegolmSessionData[], + backupVersion: string, + opts?: ImportRoomKeysOpts, + ): Promise { + return await this.backupManager.importBackedUpRoomKeys(keys, backupVersion, opts); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // CryptoApi implementation @@ -856,7 +895,7 @@ export class RustCrypto extends TypedEventEmitter(obj: T): Promise { @@ -1192,54 +1232,40 @@ export class RustCrypto extends TypedEventEmitter): Promise { - if (backupInfo.algorithm != "m.megolm_backup.v1.curve25519-aes-sha2") { - throw new Error(`getBackupDecryptor Unsupported algorithm ${backupInfo.algorithm}`); - } - - const authData = backupInfo.auth_data; - - if (!(privKey instanceof Uint8Array)) { - throw new Error(`getBackupDecryptor expects Uint8Array`); - } - - const backupDecryptionKey = RustSdkCryptoJs.BackupDecryptionKey.fromBase64(encodeBase64(privKey)); - - if (authData.public_key != backupDecryptionKey.megolmV1PublicKey.publicKeyBase64) { - throw new Error(`getBackupDecryptor key mismatch error`); - } - - return this.backupManager.createBackupDecryptor(backupDecryptionKey); + public async isDehydrationSupported(): Promise { + return await this.dehydratedDeviceManager.isSupported(); } /** - * Implementation of {@link CryptoBackend#importBackedUpRoomKeys}. + * Implementation of {@link CryptoApi#startDehydration}. */ - public async importBackedUpRoomKeys( - keys: IMegolmSessionData[], - backupVersion: string, - opts?: ImportRoomKeysOpts, - ): Promise { - return await this.backupManager.importBackedUpRoomKeys(keys, backupVersion, opts); + public async startDehydration(createNewKey?: boolean): Promise { + if (!(await this.isCrossSigningReady()) || !(await this.isSecretStorageReady())) { + throw new Error("Device dehydration requires cross-signing and secret storage to be set up"); + } + return await this.dehydratedDeviceManager.start(createNewKey); } /** - * Implementation of {@link CryptoBackend#isDehydrationSupported}. + * Implementation of {@link CryptoApi#importSecretsBundle}. */ - public async isDehydrationSupported(): Promise { - return await this.dehydratedDeviceManager.isSupported(); + public async importSecretsBundle( + secrets: Parameters>[0], + ): Promise { + const secretsBundle = RustSdkCryptoJs.SecretsBundle.from_json(secrets); + await this.getOlmMachineOrThrow().importSecretsBundle(secretsBundle); // this method frees the SecretsBundle } /** - * Implementation of {@link CryptoBackend#startDehydration}. + * Implementation of {@link CryptoApi#exportSecretsBundle}. */ - public async startDehydration(createNewKey?: boolean): Promise { - if (!(await this.isCrossSigningReady()) || !(await this.isSecretStorageReady())) { - throw new Error("Device dehydration requires cross-signing and secret storage to be set up"); - } - return await this.dehydratedDeviceManager.start(createNewKey); + public async exportSecretsBundle(): ReturnType> { + const secretsBundle = await this.getOlmMachineOrThrow().exportSecretsBundle(); + const secrets = secretsBundle.to_json(); + secretsBundle.free(); + return secrets; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1293,7 +1319,11 @@ export class RustCrypto extends TypedEventEmitter { + for (const session of withheld) { + this.logger.debug(`Got withheld message for session ${session.sessionId} in ${session.roomId.toString()}`); + const pendingList = this.eventDecryptor.getEventsPendingRoomKey( + session.roomId.toString(), + session.sessionId, + ); + if (pendingList.length === 0) return; + + // The easiest way to update the status of the event is to have another go at decrypting it. + this.logger.debug( + "Retrying decryption on events:", + pendingList.map((e) => `${e.getId()}`), + ); + + for (const ev of pendingList) { + ev.attemptDecryption(this, { isRetry: true }).catch((_e) => { + // It's somewhat expected that we still can't decrypt here. + }); + } + } + } + /** * Callback for `OlmMachine.registerUserIdentityUpdatedCallback` * @@ -1575,7 +1637,7 @@ export class RustCrypto extends TypedEventEmitter => { // Process only verification event if (isVerificationEvent(event)) { - await this.onKeyVerificationRequest(evt); + await this.onKeyVerificationEvent(evt); } }; @@ -1602,11 +1664,11 @@ export class RustCrypto extends TypedEventEmitter { + private async onKeyVerificationEvent(event: MatrixEvent): Promise { const roomId = event.getRoomId(); if (!roomId) { @@ -1633,27 +1695,7 @@ export class RustCrypto extends TypedEventEmitter>>( () => new MapWithDefault>(() => new Set()), @@ -1781,6 +1823,17 @@ class EventDecryptor { } } + // If we got a withheld code, expose that. + if (err.maybe_withheld) { + // Unfortunately the Rust SDK API doesn't let us distinguish between different withheld cases, other than + // by string-matching. + const failureCode = + err.maybe_withheld === "The sender has disabled encrypting to unverified devices." + ? DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE + : DecryptionFailureCode.MEGOLM_KEY_WITHHELD; + throw new DecryptionError(failureCode, err.maybe_withheld, errorDetails); + } + switch (err.code) { case RustSdkCryptoJs.DecryptionErrorCode.MissingRoomKey: throw new DecryptionError( @@ -1826,30 +1879,27 @@ class EventDecryptor { * Look for events which are waiting for a given megolm session * * Returns a list of events which were encrypted by `session` and could not be decrypted - * - * @param session - */ - public getEventsPendingRoomKey(session: RustSdkCryptoJs.RoomKeyInfo): MatrixEvent[] { - const senderPendingEvents = this.eventsPendingKey.get(session.senderKey.toBase64()); - if (!senderPendingEvents) return []; + public getEventsPendingRoomKey(roomId: string, sessionId: string): MatrixEvent[] { + const roomPendingEvents = this.eventsPendingKey.get(roomId); + if (!roomPendingEvents) return []; - const sessionPendingEvents = senderPendingEvents.get(session.sessionId); + const sessionPendingEvents = roomPendingEvents.get(sessionId); if (!sessionPendingEvents) return []; - const roomId = session.roomId.toString(); - return [...sessionPendingEvents].filter((ev) => ev.getRoomId() === roomId); + return [...sessionPendingEvents]; } /** * Add an event to the list of those awaiting their session keys. */ private addEventToPendingList(event: MatrixEvent): void { - const content = event.getWireContent(); - const senderKey = content.sender_key; - const sessionId = content.session_id; + const roomId = event.getRoomId(); + // We shouldn't have events without a room id here. + if (!roomId) return; - const senderPendingEvents = this.eventsPendingKey.getOrCreate(senderKey); - const sessionPendingEvents = senderPendingEvents.getOrCreate(sessionId); + const roomPendingEvents = this.eventsPendingKey.getOrCreate(roomId); + const sessionPendingEvents = roomPendingEvents.getOrCreate(event.getWireContent().session_id); sessionPendingEvents.add(event); } @@ -1857,23 +1907,22 @@ class EventDecryptor { * Remove an event from the list of those awaiting their session keys. */ private removeEventFromPendingList(event: MatrixEvent): void { - const content = event.getWireContent(); - const senderKey = content.sender_key; - const sessionId = content.session_id; + const roomId = event.getRoomId(); + if (!roomId) return; - const senderPendingEvents = this.eventsPendingKey.get(senderKey); - if (!senderPendingEvents) return; + const roomPendingEvents = this.eventsPendingKey.getOrCreate(roomId); + if (!roomPendingEvents) return; - const sessionPendingEvents = senderPendingEvents.get(sessionId); + const sessionPendingEvents = roomPendingEvents.get(event.getWireContent().session_id); if (!sessionPendingEvents) return; sessionPendingEvents.delete(event); // also clean up the higher-level maps if they are now empty if (sessionPendingEvents.size === 0) { - senderPendingEvents.delete(sessionId); - if (senderPendingEvents.size === 0) { - this.eventsPendingKey.delete(senderKey); + roomPendingEvents.delete(event.getWireContent().session_id); + if (roomPendingEvents.size === 0) { + this.eventsPendingKey.delete(roomId); } } } diff --git a/src/rust-crypto/secret-storage.ts b/src/rust-crypto/secret-storage.ts index e35a63f3b29..951eae762df 100644 --- a/src/rust-crypto/secret-storage.ts +++ b/src/rust-crypto/secret-storage.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ServerSideSecretStorage } from "../secret-storage"; +import { ServerSideSecretStorage } from "../secret-storage.ts"; /** * Check that the private cross signing keys (master, self signing, user signing) are stored in the secret storage and encrypted with the default secret storage key. diff --git a/src/rust-crypto/verification.ts b/src/rust-crypto/verification.ts index d25e6b26d16..284bcc61e64 100644 --- a/src/rust-crypto/verification.ts +++ b/src/rust-crypto/verification.ts @@ -28,14 +28,14 @@ import { Verifier, VerifierEvent, VerifierEventHandlerMap, -} from "../crypto-api/verification"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { OutgoingRequest, OutgoingRequestProcessor } from "./OutgoingRequestProcessor"; -import { TypedReEmitter } from "../ReEmitter"; -import { MatrixEvent } from "../models/event"; -import { EventType, MsgType } from "../@types/event"; -import { defer, IDeferred } from "../utils"; -import { VerificationMethod } from "../types"; +} from "../crypto-api/verification.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { OutgoingRequest, OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts"; +import { TypedReEmitter } from "../ReEmitter.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { EventType, MsgType } from "../@types/event.ts"; +import { defer, IDeferred } from "../utils.ts"; +import { VerificationMethod } from "../types.ts"; /** * An incoming, or outgoing, request to verify a user or a device via cross-signing. @@ -72,30 +72,40 @@ export class RustVerificationRequest private readonly supportedVerificationMethods: string[], ) { super(); - this.reEmitter = new TypedReEmitter(this); - const onChange = async (): Promise => { - const verification: RustSdkCryptoJs.Qr | RustSdkCryptoJs.Sas | undefined = this.inner.getVerification(); - - // Set the _verifier object (wrapping the rust `Verification` as a js-sdk Verifier) if: - // - we now have a `Verification` where we lacked one before - // - we have transitioned from QR to SAS - // - we are verifying with SAS, but we need to replace our verifier with a new one because both parties - // tried to start verification at the same time, and we lost the tie breaking - if (verification instanceof RustSdkCryptoJs.Sas) { - if (this._verifier === undefined || this._verifier instanceof RustQrCodeVerifier) { - this.setVerifier(new RustSASVerifier(verification, this, outgoingRequestProcessor)); - } else if (this._verifier instanceof RustSASVerifier) { - this._verifier.replaceInner(verification); - } - } else if (verification instanceof RustSdkCryptoJs.Qr && this._verifier === undefined) { - this.setVerifier(new RustQrCodeVerifier(verification, outgoingRequestProcessor)); + // Obviously, the Rust object maintains a reference to the callback function. If the callback function maintains + // a reference to the Rust object, then we have a reference cycle which means that `RustVerificationRequest` + // will never be garbage-collected, and hence the underlying rust object will never be freed. + // + // To avoid this reference cycle, use a weak reference in the callback function. If the `RustVerificationRequest` + // gets garbage-collected, then there is nothing to update! + const weakThis = new WeakRef(this); + inner.registerChangesCallback(async () => weakThis.deref()?.onChange()); + } + + /** + * Hook which is called when the underlying rust class notifies us that there has been a change. + */ + private onChange(): void { + const verification: RustSdkCryptoJs.Qr | RustSdkCryptoJs.Sas | undefined = this.inner.getVerification(); + + // Set the _verifier object (wrapping the rust `Verification` as a js-sdk Verifier) if: + // - we now have a `Verification` where we lacked one before + // - we have transitioned from QR to SAS + // - we are verifying with SAS, but we need to replace our verifier with a new one because both parties + // tried to start verification at the same time, and we lost the tie breaking + if (verification instanceof RustSdkCryptoJs.Sas) { + if (this._verifier === undefined || this._verifier instanceof RustQrCodeVerifier) { + this.setVerifier(new RustSASVerifier(verification, this, this.outgoingRequestProcessor)); + } else if (this._verifier instanceof RustSASVerifier) { + this._verifier.replaceInner(verification); } + } else if (verification instanceof RustSdkCryptoJs.Qr && this._verifier === undefined) { + this.setVerifier(new RustQrCodeVerifier(verification, this.outgoingRequestProcessor)); + } - this.emit(VerificationRequestEvent.Change); - }; - inner.registerChangesCallback(onChange); + this.emit(VerificationRequestEvent.Change); } private setVerifier(verifier: RustSASVerifier | RustQrCodeVerifier): void { @@ -473,9 +483,12 @@ abstract class BaseRustVerifer { - this.onChange(); - }); + + // As with RustVerificationRequest, we need to avoid a reference cycle. + // See the comments in RustVerificationRequest. + const weakThis = new WeakRef(this); + inner.registerChangesCallback(async () => weakThis.deref()?.onChange()); + // stop the runtime complaining if nobody catches a failure this.completionDeferred.promise.catch(() => null); } @@ -752,9 +765,12 @@ export class RustSASVerifier extends BaseRustVerifer implem public replaceInner(inner: RustSdkCryptoJs.Sas): void { if (this.inner != inner) { this.inner = inner; - inner.registerChangesCallback(async () => { - this.onChange(); - }); + + // As with RustVerificationRequest, we need to avoid a reference cycle. + // See the comments in RustVerificationRequest. + const weakThis = new WeakRef(this); + inner.registerChangesCallback(async () => weakThis.deref()?.onChange()); + // replaceInner will only get called if we started the verification at the same time as the other side, and we lost // the tie breaker. So we need to re-accept their verification. this.sendAccept(); diff --git a/src/scheduler.ts b/src/scheduler.ts index 6dfd212c72c..e854a67697a 100644 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -18,12 +18,12 @@ limitations under the License. * This is an internal module which manages queuing, scheduling and retrying * of requests. */ -import { logger } from "./logger"; -import { MatrixEvent } from "./models/event"; -import { EventType } from "./@types/event"; -import { defer, IDeferred, removeElement } from "./utils"; -import { calculateRetryBackoff, MatrixError } from "./http-api"; -import { ISendEventResponse } from "./@types/requests"; +import { logger } from "./logger.ts"; +import { MatrixEvent } from "./models/event.ts"; +import { EventType } from "./@types/event.ts"; +import { defer, IDeferred, removeElement } from "./utils.ts"; +import { calculateRetryBackoff, MatrixError } from "./http-api/index.ts"; +import { ISendEventResponse } from "./@types/requests.ts"; const DEBUG = false; // set true to enable console logging. diff --git a/src/secret-storage.ts b/src/secret-storage.ts index 71ef30856f9..82dd4272e8a 100644 --- a/src/secret-storage.ts +++ b/src/secret-storage.ts @@ -20,12 +20,12 @@ limitations under the License. * @see https://spec.matrix.org/v1.6/client-server-api/#storage */ -import { TypedEventEmitter } from "./models/typed-event-emitter"; -import { ClientEvent, ClientEventHandlerMap } from "./client"; -import { MatrixEvent } from "./models/event"; -import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./crypto/aes"; -import { randomString } from "./randomstring"; -import { logger } from "./logger"; +import { TypedEventEmitter } from "./models/typed-event-emitter.ts"; +import { ClientEvent, ClientEventHandlerMap } from "./client.ts"; +import { MatrixEvent } from "./models/event.ts"; +import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./crypto/aes.ts"; +import { randomString } from "./randomstring.ts"; +import { logger } from "./logger.ts"; export const SECRET_STORAGE_ALGORITHM_V1_AES = "m.secret_storage.v1.aes-hmac-sha2"; diff --git a/src/serverCapabilities.ts b/src/serverCapabilities.ts new file mode 100644 index 00000000000..c23c9c72e92 --- /dev/null +++ b/src/serverCapabilities.ts @@ -0,0 +1,136 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { IHttpOpts, MatrixHttpApi, Method } from "./http-api/index.ts"; +import { logger } from "./logger.ts"; + +// How often we update the server capabilities. +// 6 hours - an arbitrary value, but they should change very infrequently. +const CAPABILITIES_CACHE_MS = 6 * 60 * 60 * 1000; + +// How long we want before retrying if we couldn't fetch +const CAPABILITIES_RETRY_MS = 30 * 1000; + +export interface ICapability { + enabled: boolean; +} + +export interface IChangePasswordCapability extends ICapability {} + +export interface IThreadsCapability extends ICapability {} + +export interface IGetLoginTokenCapability extends ICapability {} + +export interface ISetDisplayNameCapability extends ICapability {} + +export interface ISetAvatarUrlCapability extends ICapability {} + +export enum RoomVersionStability { + Stable = "stable", + Unstable = "unstable", +} + +export interface IRoomVersionsCapability { + default: string; + available: Record; +} + +/** + * A representation of the capabilities advertised by a homeserver as defined by + * [Capabilities negotiation](https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv3capabilities). + */ +export interface Capabilities { + [key: string]: any; + "m.change_password"?: IChangePasswordCapability; + "m.room_versions"?: IRoomVersionsCapability; + "io.element.thread"?: IThreadsCapability; + "m.get_login_token"?: IGetLoginTokenCapability; + "org.matrix.msc3882.get_login_token"?: IGetLoginTokenCapability; + "m.set_displayname"?: ISetDisplayNameCapability; + "m.set_avatar_url"?: ISetAvatarUrlCapability; +} + +type CapabilitiesResponse = { + capabilities: Capabilities; +}; + +/** + * Manages storing and periodically refreshing the server capabilities. + */ +export class ServerCapabilities { + private capabilities?: Capabilities; + private retryTimeout?: ReturnType; + private refreshTimeout?: ReturnType; + + public constructor(private readonly http: MatrixHttpApi) {} + + /** + * Starts periodically fetching the server capabilities. + */ + public start(): void { + this.poll().then(); + } + + /** + * Stops the service + */ + public stop(): void { + this.clearTimeouts(); + } + + /** + * Returns the cached capabilities, or undefined if none are cached. + * @returns the current capabilities, if any. + */ + public getCachedCapabilities(): Capabilities | undefined { + return this.capabilities; + } + + /** + * Fetches the latest server capabilities from the homeserver and returns them, or rejects + * on failure. + */ + public fetchCapabilities = async (): Promise => { + const resp = await this.http.authedRequest(Method.Get, "/capabilities"); + this.capabilities = resp["capabilities"]; + return this.capabilities; + }; + + private poll = async (): Promise => { + try { + await this.fetchCapabilities(); + this.clearTimeouts(); + this.refreshTimeout = setTimeout(this.poll, CAPABILITIES_CACHE_MS); + logger.debug("Fetched new server capabilities"); + } catch (e) { + this.clearTimeouts(); + const howLong = Math.floor(CAPABILITIES_RETRY_MS + Math.random() * 5000); + this.retryTimeout = setTimeout(this.poll, howLong); + logger.warn(`Failed to refresh capabilities: retrying in ${howLong}ms`, e); + } + }; + + private clearTimeouts(): void { + if (this.refreshTimeout) { + clearInterval(this.refreshTimeout); + this.refreshTimeout = undefined; + } + if (this.retryTimeout) { + clearTimeout(this.retryTimeout); + this.retryTimeout = undefined; + } + } +} diff --git a/src/sliding-sync-sdk.ts b/src/sliding-sync-sdk.ts index 4a99cc4e72b..4c07984732f 100644 --- a/src/sliding-sync-sdk.ts +++ b/src/sliding-sync-sdk.ts @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type { SyncCryptoCallbacks } from "./common-crypto/CryptoBackend"; -import { NotificationCountType, Room, RoomEvent } from "./models/room"; -import { logger } from "./logger"; -import { promiseMapSeries } from "./utils"; -import { EventTimeline } from "./models/event-timeline"; -import { ClientEvent, IStoredClientOpts, MatrixClient } from "./client"; +import type { SyncCryptoCallbacks } from "./common-crypto/CryptoBackend.ts"; +import { NotificationCountType, Room, RoomEvent } from "./models/room.ts"; +import { logger } from "./logger.ts"; +import { promiseMapSeries } from "./utils.ts"; +import { EventTimeline } from "./models/event-timeline.ts"; +import { ClientEvent, IStoredClientOpts, MatrixClient } from "./client.ts"; import { ISyncStateData, SyncState, @@ -28,11 +28,11 @@ import { defaultClientOpts, defaultSyncApiOpts, SetPresence, -} from "./sync"; -import { MatrixEvent } from "./models/event"; -import { Crypto } from "./crypto"; -import { IMinimalEvent, IRoomEvent, IStateEvent, IStrippedState, ISyncResponse } from "./sync-accumulator"; -import { MatrixError } from "./http-api"; +} from "./sync.ts"; +import { MatrixEvent } from "./models/event.ts"; +import { Crypto } from "./crypto/index.ts"; +import { IMinimalEvent, IRoomEvent, IStateEvent, IStrippedState, ISyncResponse } from "./sync-accumulator.ts"; +import { MatrixError } from "./http-api/index.ts"; import { Extension, ExtensionState, @@ -41,12 +41,12 @@ import { SlidingSync, SlidingSyncEvent, SlidingSyncState, -} from "./sliding-sync"; -import { EventType } from "./@types/event"; -import { IPushRules } from "./@types/PushRules"; -import { RoomStateEvent } from "./models/room-state"; -import { RoomMemberEvent } from "./models/room-member"; -import { KnownMembership } from "./@types/membership"; +} from "./sliding-sync.ts"; +import { EventType } from "./@types/event.ts"; +import { IPushRules } from "./@types/PushRules.ts"; +import { RoomStateEvent } from "./models/room-state.ts"; +import { RoomMemberEvent } from "./models/room-member.ts"; +import { KnownMembership } from "./@types/membership.ts"; // Number of consecutive failed syncs that will lead to a syncState of ERROR as opposed // to RECONNECTING. This is needed to inform the client of server issues when the diff --git a/src/sliding-sync.ts b/src/sliding-sync.ts index 12da3d70404..487c447a262 100644 --- a/src/sliding-sync.ts +++ b/src/sliding-sync.ts @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "./logger"; -import { MatrixClient } from "./client"; -import { IRoomEvent, IStateEvent } from "./sync-accumulator"; -import { TypedEventEmitter } from "./models/typed-event-emitter"; -import { sleep, IDeferred, defer } from "./utils"; -import { HTTPError } from "./http-api"; +import { logger } from "./logger.ts"; +import { MatrixClient } from "./client.ts"; +import { IRoomEvent, IStateEvent } from "./sync-accumulator.ts"; +import { TypedEventEmitter } from "./models/typed-event-emitter.ts"; +import { sleep, IDeferred, defer } from "./utils.ts"; +import { HTTPError } from "./http-api/index.ts"; // /sync requests allow you to set a timeout= but the request may continue // beyond that and wedge forever, so we need to track how long we are willing diff --git a/src/store/index.ts b/src/store/index.ts index fbb66b006ec..64870753317 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -14,17 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EventType } from "../@types/event"; -import { Room } from "../models/room"; -import { User } from "../models/user"; -import { IEvent, MatrixEvent } from "../models/event"; -import { Filter } from "../filter"; -import { RoomSummary } from "../models/room-summary"; -import { IMinimalEvent, IRooms, ISyncResponse } from "../sync-accumulator"; -import { IStartClientOpts } from "../client"; -import { IStateEventWithRoomId } from "../@types/search"; -import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage"; -import { EventEmitterEvents } from "../models/typed-event-emitter"; +import { EventType } from "../@types/event.ts"; +import { Room } from "../models/room.ts"; +import { User } from "../models/user.ts"; +import { IEvent, MatrixEvent } from "../models/event.ts"; +import { Filter } from "../filter.ts"; +import { RoomSummary } from "../models/room-summary.ts"; +import { IMinimalEvent, IRooms, ISyncResponse } from "../sync-accumulator.ts"; +import { IStartClientOpts } from "../client.ts"; +import { IStateEventWithRoomId } from "../@types/search.ts"; +import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage.ts"; +import { EventEmitterEvents } from "../models/typed-event-emitter.ts"; export interface ISavedSync { nextBatch: string; diff --git a/src/store/indexeddb-backend.ts b/src/store/indexeddb-backend.ts index c93afb9e705..e5e1dff5bae 100644 --- a/src/store/indexeddb-backend.ts +++ b/src/store/indexeddb-backend.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ISavedSync } from "./index"; -import { IEvent, IStateEventWithRoomId, IStoredClientOpts, ISyncResponse } from "../matrix"; -import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage"; +import { ISavedSync } from "./index.ts"; +import { IEvent, IStateEventWithRoomId, IStoredClientOpts, ISyncResponse } from "../matrix.ts"; +import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage.ts"; export interface IIndexedDBBackend { connect(onClose?: () => void): Promise; diff --git a/src/store/indexeddb-local-backend.ts b/src/store/indexeddb-local-backend.ts index f9e51e4ff18..03673803864 100644 --- a/src/store/indexeddb-local-backend.ts +++ b/src/store/indexeddb-local-backend.ts @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IMinimalEvent, ISyncData, ISyncResponse, SyncAccumulator } from "../sync-accumulator"; -import { deepCopy, promiseTry } from "../utils"; -import { exists as idbExists } from "../indexeddb-helpers"; -import { logger } from "../logger"; -import { IStateEventWithRoomId, IStoredClientOpts } from "../matrix"; -import { ISavedSync } from "./index"; -import { IIndexedDBBackend, UserTuple } from "./indexeddb-backend"; -import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage"; +import { IMinimalEvent, ISyncData, ISyncResponse, SyncAccumulator } from "../sync-accumulator.ts"; +import { deepCopy, promiseTry } from "../utils.ts"; +import { exists as idbExists } from "../indexeddb-helpers.ts"; +import { logger } from "../logger.ts"; +import { IStateEventWithRoomId, IStoredClientOpts } from "../matrix.ts"; +import { ISavedSync } from "./index.ts"; +import { IIndexedDBBackend, UserTuple } from "./indexeddb-backend.ts"; +import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage.ts"; type DbMigration = (db: IDBDatabase) => void; const DB_MIGRATIONS: DbMigration[] = [ diff --git a/src/store/indexeddb-remote-backend.ts b/src/store/indexeddb-remote-backend.ts index e3285afecf3..1bb9e19c8a1 100644 --- a/src/store/indexeddb-remote-backend.ts +++ b/src/store/indexeddb-remote-backend.ts @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { logger } from "../logger"; -import { defer, IDeferred } from "../utils"; -import { ISavedSync } from "./index"; -import { IStoredClientOpts } from "../client"; -import { IStateEventWithRoomId, ISyncResponse } from "../matrix"; -import { IIndexedDBBackend, UserTuple } from "./indexeddb-backend"; -import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage"; +import { logger } from "../logger.ts"; +import { defer, IDeferred } from "../utils.ts"; +import { ISavedSync } from "./index.ts"; +import { IStoredClientOpts } from "../client.ts"; +import { IStateEventWithRoomId, ISyncResponse } from "../matrix.ts"; +import { IIndexedDBBackend, UserTuple } from "./indexeddb-backend.ts"; +import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage.ts"; export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { private worker?: Worker; diff --git a/src/store/indexeddb-store-worker.ts b/src/store/indexeddb-store-worker.ts index 52a7fa6bf32..36c6ee67607 100644 --- a/src/store/indexeddb-store-worker.ts +++ b/src/store/indexeddb-store-worker.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { LocalIndexedDBStoreBackend } from "./indexeddb-local-backend"; -import { logger } from "../logger"; +import { LocalIndexedDBStoreBackend } from "./indexeddb-local-backend.ts"; +import { logger } from "../logger.ts"; interface ICmd { command: string; diff --git a/src/store/indexeddb.ts b/src/store/indexeddb.ts index 33132a17bde..67d219e2bb3 100644 --- a/src/store/indexeddb.ts +++ b/src/store/indexeddb.ts @@ -16,18 +16,18 @@ limitations under the License. /* eslint-disable @babel/no-invalid-this */ -import { MemoryStore, IOpts as IBaseOpts } from "./memory"; -import { LocalIndexedDBStoreBackend } from "./indexeddb-local-backend"; -import { RemoteIndexedDBStoreBackend } from "./indexeddb-remote-backend"; -import { IEvent, MatrixEvent } from "../models/event"; -import { logger } from "../logger"; -import { ISavedSync } from "./index"; -import { IIndexedDBBackend } from "./indexeddb-backend"; -import { ISyncResponse } from "../sync-accumulator"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { IStateEventWithRoomId } from "../@types/search"; -import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage"; -import { IStoredClientOpts } from "../client"; +import { MemoryStore, IOpts as IBaseOpts } from "./memory.ts"; +import { LocalIndexedDBStoreBackend } from "./indexeddb-local-backend.ts"; +import { RemoteIndexedDBStoreBackend } from "./indexeddb-remote-backend.ts"; +import { IEvent, MatrixEvent } from "../models/event.ts"; +import { logger } from "../logger.ts"; +import { ISavedSync } from "./index.ts"; +import { IIndexedDBBackend } from "./indexeddb-backend.ts"; +import { ISyncResponse } from "../sync-accumulator.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { IStateEventWithRoomId } from "../@types/search.ts"; +import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage.ts"; +import { IStoredClientOpts } from "../client.ts"; /** * This is an internal module. See {@link IndexedDBStore} for the public class. diff --git a/src/store/local-storage-events-emitter.ts b/src/store/local-storage-events-emitter.ts index adb70cb541d..03900a70eda 100644 --- a/src/store/local-storage-events-emitter.ts +++ b/src/store/local-storage-events-emitter.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { TypedEventEmitter } from "../models/typed-event-emitter"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; export enum LocalStorageErrors { Global = "Global", diff --git a/src/store/memory.ts b/src/store/memory.ts index 7251be1c6b5..3021c23ebdb 100644 --- a/src/store/memory.ts +++ b/src/store/memory.ts @@ -18,21 +18,21 @@ limitations under the License. * This is an internal module. See {@link MemoryStore} for the public class. */ -import { EventType } from "../@types/event"; -import { Room } from "../models/room"; -import { User } from "../models/user"; -import { IEvent, MatrixEvent } from "../models/event"; -import { RoomState, RoomStateEvent } from "../models/room-state"; -import { RoomMember } from "../models/room-member"; -import { Filter } from "../filter"; -import { ISavedSync, IStore, UserCreator } from "./index"; -import { RoomSummary } from "../models/room-summary"; -import { ISyncResponse } from "../sync-accumulator"; -import { IStateEventWithRoomId } from "../@types/search"; -import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage"; -import { IStoredClientOpts } from "../client"; -import { MapWithDefault } from "../utils"; -import { KnownMembership } from "../@types/membership"; +import { EventType } from "../@types/event.ts"; +import { Room } from "../models/room.ts"; +import { User } from "../models/user.ts"; +import { IEvent, MatrixEvent } from "../models/event.ts"; +import { RoomState, RoomStateEvent } from "../models/room-state.ts"; +import { RoomMember } from "../models/room-member.ts"; +import { Filter } from "../filter.ts"; +import { ISavedSync, IStore, UserCreator } from "./index.ts"; +import { RoomSummary } from "../models/room-summary.ts"; +import { ISyncResponse } from "../sync-accumulator.ts"; +import { IStateEventWithRoomId } from "../@types/search.ts"; +import { IndexedToDeviceBatch, ToDeviceBatchWithTxnId } from "../models/ToDeviceMessage.ts"; +import { IStoredClientOpts } from "../client.ts"; +import { MapWithDefault } from "../utils.ts"; +import { KnownMembership } from "../@types/membership.ts"; function isValidFilterId(filterId?: string | number | null): boolean { const isValidStr = diff --git a/src/store/stub.ts b/src/store/stub.ts index c320d78b153..72b0acff098 100644 --- a/src/store/stub.ts +++ b/src/store/stub.ts @@ -18,17 +18,17 @@ limitations under the License. * This is an internal module. */ -import { EventType } from "../@types/event"; -import { Room } from "../models/room"; -import { User } from "../models/user"; -import { IEvent, MatrixEvent } from "../models/event"; -import { Filter } from "../filter"; -import { ISavedSync, IStore, UserCreator } from "./index"; -import { RoomSummary } from "../models/room-summary"; -import { ISyncResponse } from "../sync-accumulator"; -import { IStateEventWithRoomId } from "../@types/search"; -import { IndexedToDeviceBatch, ToDeviceBatch } from "../models/ToDeviceMessage"; -import { IStoredClientOpts } from "../client"; +import { EventType } from "../@types/event.ts"; +import { Room } from "../models/room.ts"; +import { User } from "../models/user.ts"; +import { IEvent, MatrixEvent } from "../models/event.ts"; +import { Filter } from "../filter.ts"; +import { ISavedSync, IStore, UserCreator } from "./index.ts"; +import { RoomSummary } from "../models/room-summary.ts"; +import { ISyncResponse } from "../sync-accumulator.ts"; +import { IStateEventWithRoomId } from "../@types/search.ts"; +import { IndexedToDeviceBatch, ToDeviceBatch } from "../models/ToDeviceMessage.ts"; +import { IStoredClientOpts } from "../client.ts"; /** * Construct a stub store. This does no-ops on most store methods. diff --git a/src/sync-accumulator.ts b/src/sync-accumulator.ts index eec811577b8..d66a497f822 100644 --- a/src/sync-accumulator.ts +++ b/src/sync-accumulator.ts @@ -18,13 +18,13 @@ limitations under the License. * This is an internal module. See {@link SyncAccumulator} for the public class. */ -import { logger } from "./logger"; -import { deepCopy } from "./utils"; -import { IContent, IUnsigned } from "./models/event"; -import { IRoomSummary } from "./models/room-summary"; -import { EventType } from "./@types/event"; -import { UNREAD_THREAD_NOTIFICATIONS } from "./@types/sync"; -import { ReceiptAccumulator } from "./receipt-accumulator"; +import { logger } from "./logger.ts"; +import { deepCopy } from "./utils.ts"; +import { IContent, IUnsigned } from "./models/event.ts"; +import { IRoomSummary } from "./models/room-summary.ts"; +import { EventType } from "./@types/event.ts"; +import { UNREAD_THREAD_NOTIFICATIONS } from "./@types/sync.ts"; +import { ReceiptAccumulator } from "./receipt-accumulator.ts"; interface IOpts { /** @@ -504,7 +504,7 @@ export class SyncAccumulator { currentData._timeline.push({ event: transformedEvent, - token: index === 0 ? data.timeline.prev_batch ?? null : null, + token: index === 0 ? (data.timeline.prev_batch ?? null) : null, }); }); diff --git a/src/sync.ts b/src/sync.ts index 82dae75af0a..47be1ebc89a 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -25,14 +25,14 @@ limitations under the License. import { Optional } from "matrix-events-sdk"; -import type { SyncCryptoCallbacks } from "./common-crypto/CryptoBackend"; -import { User } from "./models/user"; -import { NotificationCountType, Room, RoomEvent } from "./models/room"; -import { deepCopy, defer, IDeferred, noUnsafeEventProps, promiseMapSeries, unsafeProp } from "./utils"; -import { Filter } from "./filter"; -import { EventTimeline } from "./models/event-timeline"; -import { logger } from "./logger"; -import { ClientEvent, IStoredClientOpts, MatrixClient, PendingEventOrdering, ResetTimelineCallback } from "./client"; +import type { SyncCryptoCallbacks } from "./common-crypto/CryptoBackend.ts"; +import { User } from "./models/user.ts"; +import { NotificationCountType, Room, RoomEvent } from "./models/room.ts"; +import { deepCopy, defer, IDeferred, noUnsafeEventProps, promiseMapSeries, unsafeProp } from "./utils.ts"; +import { Filter } from "./filter.ts"; +import { EventTimeline } from "./models/event-timeline.ts"; +import { logger } from "./logger.ts"; +import { ClientEvent, IStoredClientOpts, MatrixClient, PendingEventOrdering, ResetTimelineCallback } from "./client.ts"; import { IEphemeral, IInvitedRoom, @@ -47,20 +47,20 @@ import { ISyncResponse, ITimeline, IToDeviceEvent, -} from "./sync-accumulator"; -import { MatrixEvent } from "./models/event"; -import { MatrixError, Method } from "./http-api"; -import { ISavedSync } from "./store"; -import { EventType } from "./@types/event"; -import { IPushRules } from "./@types/PushRules"; -import { RoomStateEvent, IMarkerFoundOptions } from "./models/room-state"; -import { RoomMemberEvent } from "./models/room-member"; -import { BeaconEvent } from "./models/beacon"; -import { IEventsResponse } from "./@types/requests"; -import { UNREAD_THREAD_NOTIFICATIONS } from "./@types/sync"; -import { Feature, ServerSupport } from "./feature"; -import { Crypto } from "./crypto"; -import { KnownMembership } from "./@types/membership"; +} from "./sync-accumulator.ts"; +import { MatrixEvent } from "./models/event.ts"; +import { MatrixError, Method } from "./http-api/index.ts"; +import { ISavedSync } from "./store/index.ts"; +import { EventType } from "./@types/event.ts"; +import { IPushRules } from "./@types/PushRules.ts"; +import { RoomStateEvent, IMarkerFoundOptions } from "./models/room-state.ts"; +import { RoomMemberEvent } from "./models/room-member.ts"; +import { BeaconEvent } from "./models/beacon.ts"; +import { IEventsResponse } from "./@types/requests.ts"; +import { UNREAD_THREAD_NOTIFICATIONS } from "./@types/sync.ts"; +import { Feature, ServerSupport } from "./feature.ts"; +import { Crypto } from "./crypto/index.ts"; +import { KnownMembership } from "./@types/membership.ts"; const DEBUG = true; @@ -401,17 +401,18 @@ export class SyncApi { * Peek into a room. This will result in the room in question being synced so it * is accessible via getRooms(). Live updates for the room will be provided. * @param roomId - The room ID to peek into. + * @param limit - The number of timeline events to initially retrieve. * @returns A promise which resolves once the room has been added to the * store. */ - public peek(roomId: string): Promise { + public peek(roomId: string, limit: number = 20): Promise { if (this._peekRoom?.roomId === roomId) { return Promise.resolve(this._peekRoom); } const client = this.client; this._peekRoom = this.createRoom(roomId); - return this.client.roomInitialSync(roomId, 20).then((response) => { + return this.client.roomInitialSync(roomId, limit).then((response) => { if (this._peekRoom?.roomId !== roomId) { throw new Error("Peeking aborted"); } @@ -1402,7 +1403,9 @@ export class SyncApi { if (limited) { room.resetLiveTimeline( joinObj.timeline.prev_batch, - this.syncOpts.canResetEntireTimeline!(room.roomId) ? null : syncEventData.oldSyncToken ?? null, + this.syncOpts.canResetEntireTimeline!(room.roomId) + ? null + : (syncEventData.oldSyncToken ?? null), ); // We have to assume any gap in any timeline is diff --git a/src/testing.ts b/src/testing.ts index cce36494884..ba609ad0984 100644 --- a/src/testing.ts +++ b/src/testing.ts @@ -22,12 +22,12 @@ limitations under the License. * @packageDocumentation */ -import { IContent, IEvent, IUnsigned, MatrixEvent } from "./models/event"; -import { RoomMember } from "./models/room-member"; -import { EventType } from "./@types/event"; -import { DecryptionError } from "./crypto/algorithms"; -import { DecryptionFailureCode } from "./crypto-api"; -import { EventDecryptionResult } from "./common-crypto/CryptoBackend"; +import { IContent, IEvent, IUnsigned, MatrixEvent } from "./models/event.ts"; +import { RoomMember } from "./models/room-member.ts"; +import { EventType } from "./@types/event.ts"; +import { DecryptionError } from "./crypto/algorithms/index.ts"; +import { DecryptionFailureCode } from "./crypto-api/index.ts"; +import { EventDecryptionResult } from "./common-crypto/CryptoBackend.ts"; /** * Create a {@link MatrixEvent}. diff --git a/src/thread-utils.ts b/src/thread-utils.ts index 51412592f32..3362c006052 100644 --- a/src/thread-utils.ts +++ b/src/thread-utils.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { THREAD_RELATION_TYPE } from "./models/thread"; -import { IEvent } from "./models/event"; +import { THREAD_RELATION_TYPE } from "./models/thread.ts"; +import { IEvent } from "./models/event.ts"; /** * Returns a filter function for the /relations endpoint to filter out relations directly diff --git a/src/timeline-window.ts b/src/timeline-window.ts index 793b68e7dd3..7e961beef03 100644 --- a/src/timeline-window.ts +++ b/src/timeline-window.ts @@ -16,12 +16,12 @@ limitations under the License. import { Optional } from "matrix-events-sdk"; -import { Direction, EventTimeline } from "./models/event-timeline"; -import { logger } from "./logger"; -import { MatrixClient } from "./client"; -import { EventTimelineSet } from "./models/event-timeline-set"; -import { MatrixEvent } from "./models/event"; -import { Room, RoomEvent } from "./models/room"; +import { Direction, EventTimeline } from "./models/event-timeline.ts"; +import { logger } from "./logger.ts"; +import { MatrixClient } from "./client.ts"; +import { EventTimelineSet } from "./models/event-timeline-set.ts"; +import { MatrixEvent } from "./models/event.ts"; +import { Room, RoomEvent } from "./models/room.ts"; /** * @internal diff --git a/src/types.ts b/src/types.ts index c1469b17062..24f1620427c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,11 +21,11 @@ limitations under the License. * Remember to only export *public* types from this file. */ -export type * from "./@types/media"; -export * from "./@types/membership"; -export type * from "./@types/event"; -export type * from "./@types/events"; -export type * from "./@types/state_events"; +export type * from "./@types/media.ts"; +export * from "./@types/membership.ts"; +export type * from "./@types/event.ts"; +export type * from "./@types/events.ts"; +export type * from "./@types/state_events.ts"; /** The different methods for device and user verification */ export enum VerificationMethod { diff --git a/src/utils.ts b/src/utils.ts index f3ad18d5735..ce7c5016b14 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -22,10 +22,10 @@ import unhomoglyph from "unhomoglyph"; import promiseRetry from "p-retry"; import { Optional } from "matrix-events-sdk"; -import { IEvent, MatrixEvent } from "./models/event"; -import { M_TIMESTAMP } from "./@types/location"; -import { ReceiptType } from "./@types/read_receipts"; -import { BaseLogger } from "./logger"; +import { IEvent, MatrixEvent } from "./models/event.ts"; +import { M_TIMESTAMP } from "./@types/location.ts"; +import { ReceiptType } from "./@types/read_receipts.ts"; +import { BaseLogger } from "./logger.ts"; const interns = new Map(); @@ -407,9 +407,12 @@ export async function logDuration(logger: BaseLogger, name: string, block: () /** * Promise/async version of {@link setImmediate}. + * + * Implementation is based on `setTimeout` for wider compatibility. + * @deprecated Use {@link sleep} instead. */ export function immediate(): Promise { - return new Promise(setImmediate); + return new Promise((resolve) => setTimeout(resolve)); } export function isNullOrUndefined(val: any): boolean { @@ -646,16 +649,6 @@ export function lexicographicCompare(a: string, b: string): number { } } -const collator = new Intl.Collator(); -/** - * Performant language-sensitive string comparison - * @param a - the first string to compare - * @param b - the second string to compare - */ -export function compare(a: string, b: string): number { - return collator.compare(a, b); -} - /** * This function is similar to Object.assign() but it assigns recursively and * allows you to ignore nullish values from the source diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index 45d35f60c9f..6a8a15e0612 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -24,12 +24,12 @@ limitations under the License. import { v4 as uuidv4 } from "uuid"; import { parse as parseSdp, write as writeSdp } from "sdp-transform"; -import { logger } from "../logger"; -import { checkObjectHasKeys, isNullOrUndefined, recursivelyAssign } from "../utils"; -import { MatrixEvent } from "../models/event"; -import { EventType, TimelineEvents, ToDeviceMessageId } from "../@types/event"; -import { RoomMember } from "../models/room-member"; -import { randomString } from "../randomstring"; +import { logger } from "../logger.ts"; +import { checkObjectHasKeys, isNullOrUndefined, recursivelyAssign } from "../utils.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { EventType, TimelineEvents, ToDeviceMessageId } from "../@types/event.ts"; +import { RoomMember } from "../models/room-member.ts"; +import { randomString } from "../randomstring.ts"; import { MCallReplacesEvent, MCallAnswer, @@ -44,15 +44,15 @@ import { MCallCandidates, MCallBase, MCallHangupReject, -} from "./callEventTypes"; -import { CallFeed } from "./callFeed"; -import { MatrixClient } from "../client"; -import { EventEmitterEvents, TypedEventEmitter } from "../models/typed-event-emitter"; -import { DeviceInfo } from "../crypto/deviceinfo"; -import { GroupCallUnknownDeviceError } from "./groupCall"; -import { IScreensharingOpts } from "./mediaHandler"; -import { MatrixError } from "../http-api"; -import { GroupCallStats } from "./stats/groupCallStats"; +} from "./callEventTypes.ts"; +import { CallFeed } from "./callFeed.ts"; +import { MatrixClient } from "../client.ts"; +import { EventEmitterEvents, TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { DeviceInfo } from "../crypto/deviceinfo.ts"; +import { GroupCallUnknownDeviceError } from "./groupCall.ts"; +import { IScreensharingOpts } from "./mediaHandler.ts"; +import { MatrixError } from "../http-api/index.ts"; +import { GroupCallStats } from "./stats/groupCallStats.ts"; interface CallOpts { // The room ID for this call. @@ -2381,22 +2381,40 @@ export class MatrixCall extends TypedEventEmitter => { diff --git a/src/webrtc/callEventHandler.ts b/src/webrtc/callEventHandler.ts index 4ee183a7f38..c9cde3bd363 100644 --- a/src/webrtc/callEventHandler.ts +++ b/src/webrtc/callEventHandler.ts @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixEvent } from "../models/event"; -import { logger } from "../logger"; -import { CallDirection, CallError, CallErrorCode, CallState, createNewMatrixCall, MatrixCall } from "./call"; -import { EventType } from "../@types/event"; -import { ClientEvent, MatrixClient } from "../client"; -import { MCallAnswer, MCallHangupReject } from "./callEventTypes"; -import { GroupCall, GroupCallErrorCode, GroupCallEvent, GroupCallUnknownDeviceError } from "./groupCall"; -import { RoomEvent } from "../models/room"; +import { MatrixEvent } from "../models/event.ts"; +import { logger } from "../logger.ts"; +import { CallDirection, CallError, CallErrorCode, CallState, createNewMatrixCall, MatrixCall } from "./call.ts"; +import { EventType } from "../@types/event.ts"; +import { ClientEvent, MatrixClient } from "../client.ts"; +import { MCallAnswer, MCallHangupReject } from "./callEventTypes.ts"; +import { GroupCall, GroupCallErrorCode, GroupCallEvent, GroupCallUnknownDeviceError } from "./groupCall.ts"; +import { RoomEvent } from "../models/room.ts"; // Don't ring unless we'd be ringing for at least 3 seconds: the user needs some // time to press the 'accept' button diff --git a/src/webrtc/callEventTypes.ts b/src/webrtc/callEventTypes.ts index 0be2b2d4d8a..c54e3ead8e0 100644 --- a/src/webrtc/callEventTypes.ts +++ b/src/webrtc/callEventTypes.ts @@ -1,7 +1,7 @@ // allow non-camelcase as these are events type that go onto the wire /* eslint-disable camelcase */ -import { CallErrorCode } from "./call"; +import { CallErrorCode } from "./call.ts"; // TODO: Change to "sdp_stream_metadata" when MSC3077 is merged export const SDPStreamMetadataKey = "org.matrix.msc3077.sdp_stream_metadata"; diff --git a/src/webrtc/callFeed.ts b/src/webrtc/callFeed.ts index a9cf7a7a973..9ae3c344162 100644 --- a/src/webrtc/callFeed.ts +++ b/src/webrtc/callFeed.ts @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { SDPStreamMetadataPurpose } from "./callEventTypes"; -import { acquireContext, releaseContext } from "./audioContext"; -import { MatrixClient } from "../client"; -import { RoomMember } from "../models/room-member"; -import { logger } from "../logger"; -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { CallEvent, CallState, MatrixCall } from "./call"; +import { SDPStreamMetadataPurpose } from "./callEventTypes.ts"; +import { acquireContext, releaseContext } from "./audioContext.ts"; +import { MatrixClient } from "../client.ts"; +import { RoomMember } from "../models/room-member.ts"; +import { logger } from "../logger.ts"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { CallEvent, CallState, MatrixCall } from "./call.ts"; const POLLING_INTERVAL = 200; // ms export const SPEAKING_THRESHOLD = -60; // dB diff --git a/src/webrtc/groupCall.ts b/src/webrtc/groupCall.ts index a33f676b1b7..5fd6985cc1d 100644 --- a/src/webrtc/groupCall.ts +++ b/src/webrtc/groupCall.ts @@ -1,6 +1,6 @@ -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { CallFeed, SPEAKING_THRESHOLD } from "./callFeed"; -import { MatrixClient, IMyDevice } from "../client"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { CallFeed, SPEAKING_THRESHOLD } from "./callFeed.ts"; +import { MatrixClient, IMyDevice } from "../client.ts"; import { CallErrorCode, CallEvent, @@ -11,31 +11,31 @@ import { setTracksEnabled, createNewMatrixCall, CallError, -} from "./call"; -import { RoomMember } from "../models/room-member"; -import { Room } from "../models/room"; -import { RoomStateEvent } from "../models/room-state"; -import { logger } from "../logger"; -import { ReEmitter } from "../ReEmitter"; -import { SDPStreamMetadataPurpose } from "./callEventTypes"; -import { MatrixEvent } from "../models/event"; -import { EventType } from "../@types/event"; -import { CallEventHandlerEvent } from "./callEventHandler"; -import { GroupCallEventHandlerEvent } from "./groupCallEventHandler"; -import { IScreensharingOpts } from "./mediaHandler"; -import { mapsEqual } from "../utils"; -import { GroupCallStats } from "./stats/groupCallStats"; +} from "./call.ts"; +import { RoomMember } from "../models/room-member.ts"; +import { Room } from "../models/room.ts"; +import { RoomStateEvent } from "../models/room-state.ts"; +import { logger } from "../logger.ts"; +import { ReEmitter } from "../ReEmitter.ts"; +import { SDPStreamMetadataPurpose } from "./callEventTypes.ts"; +import { MatrixEvent } from "../models/event.ts"; +import { EventType } from "../@types/event.ts"; +import { CallEventHandlerEvent } from "./callEventHandler.ts"; +import { GroupCallEventHandlerEvent } from "./groupCallEventHandler.ts"; +import { IScreensharingOpts } from "./mediaHandler.ts"; +import { mapsEqual } from "../utils.ts"; +import { GroupCallStats } from "./stats/groupCallStats.ts"; import { ByteSentStatsReport, CallFeedReport, ConnectionStatsReport, StatsReport, SummaryStatsReport, -} from "./stats/statsReport"; -import { SummaryStatsReportGatherer } from "./stats/summaryStatsReportGatherer"; -import { CallFeedStatsReporter } from "./stats/callFeedStatsReporter"; -import { KnownMembership } from "../@types/membership"; -import { CallMembershipData } from "../matrixrtc/CallMembership"; +} from "./stats/statsReport.ts"; +import { SummaryStatsReportGatherer } from "./stats/summaryStatsReportGatherer.ts"; +import { CallFeedStatsReporter } from "./stats/callFeedStatsReporter.ts"; +import { KnownMembership } from "../@types/membership.ts"; +import { CallMembershipData } from "../matrixrtc/CallMembership.ts"; export enum GroupCallIntent { Ring = "m.ring", @@ -91,7 +91,7 @@ export type GroupCallEventHandlerMap = { * `MatrixCall.ERR_NO_USER_MEDIA`. `ERR_LOCAL_OFFER_FAILED` is emitted when the local client * fails to create an offer. `ERR_NO_USER_MEDIA` is emitted when the user has denied access * to their audio/video hardware. - * @param err - The error raised by MatrixCall. + * @param error - The error raised by MatrixCall. * @example * ``` * matrixCall.on("error", function(err){ diff --git a/src/webrtc/groupCallEventHandler.ts b/src/webrtc/groupCallEventHandler.ts index 2db54f66b49..d0ce6af057c 100644 --- a/src/webrtc/groupCallEventHandler.ts +++ b/src/webrtc/groupCallEventHandler.ts @@ -14,15 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixEvent } from "../models/event"; -import { MatrixClient, ClientEvent } from "../client"; -import { GroupCall, GroupCallIntent, GroupCallType, IGroupCallDataChannelOptions } from "./groupCall"; -import { Room } from "../models/room"; -import { RoomState, RoomStateEvent } from "../models/room-state"; -import { RoomMember } from "../models/room-member"; -import { logger } from "../logger"; -import { EventType } from "../@types/event"; -import { SyncState } from "../sync"; +import { MatrixEvent } from "../models/event.ts"; +import { MatrixClient, ClientEvent } from "../client.ts"; +import { GroupCall, GroupCallIntent, GroupCallType, IGroupCallDataChannelOptions } from "./groupCall.ts"; +import { Room } from "../models/room.ts"; +import { RoomState, RoomStateEvent } from "../models/room-state.ts"; +import { RoomMember } from "../models/room-member.ts"; +import { logger } from "../logger.ts"; +import { EventType } from "../@types/event.ts"; +import { SyncState } from "../sync.ts"; export enum GroupCallEventHandlerEvent { Incoming = "GroupCall.incoming", diff --git a/src/webrtc/mediaHandler.ts b/src/webrtc/mediaHandler.ts index b17cc2852cc..7efa786d251 100644 --- a/src/webrtc/mediaHandler.ts +++ b/src/webrtc/mediaHandler.ts @@ -17,10 +17,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { TypedEventEmitter } from "../models/typed-event-emitter"; -import { GroupCallType, GroupCallState } from "../webrtc/groupCall"; -import { logger } from "../logger"; -import { MatrixClient } from "../client"; +import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; +import { GroupCallType, GroupCallState } from "../webrtc/groupCall.ts"; +import { logger } from "../logger.ts"; +import { MatrixClient } from "../client.ts"; export enum MediaHandlerEvent { LocalStreamsChanged = "local_streams_changed", diff --git a/src/webrtc/stats/callFeedStatsReporter.ts b/src/webrtc/stats/callFeedStatsReporter.ts index 2b2c092d73d..d219f717277 100644 --- a/src/webrtc/stats/callFeedStatsReporter.ts +++ b/src/webrtc/stats/callFeedStatsReporter.ts @@ -13,8 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { CallFeedReport, CallFeedStats, TrackStats, TransceiverStats } from "./statsReport"; -import { CallFeed } from "../callFeed"; +import { CallFeedReport, CallFeedStats, TrackStats, TransceiverStats } from "./statsReport.ts"; +import { CallFeed } from "../callFeed.ts"; export class CallFeedStatsReporter { public static buildCallFeedReport(callId: string, opponentMemberId: string, pc: RTCPeerConnection): CallFeedReport { diff --git a/src/webrtc/stats/callStatsReportGatherer.ts b/src/webrtc/stats/callStatsReportGatherer.ts index cc52156f0d7..202d654e0c5 100644 --- a/src/webrtc/stats/callStatsReportGatherer.ts +++ b/src/webrtc/stats/callStatsReportGatherer.ts @@ -14,20 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ConnectionStats } from "./connectionStats"; -import { StatsReportEmitter } from "./statsReportEmitter"; -import { ByteSend, ByteSentStatsReport, TrackID } from "./statsReport"; -import { ConnectionStatsBuilder } from "./connectionStatsBuilder"; -import { TransportStatsBuilder } from "./transportStatsBuilder"; -import { MediaSsrcHandler } from "./media/mediaSsrcHandler"; -import { MediaTrackHandler } from "./media/mediaTrackHandler"; -import { MediaTrackStatsHandler } from "./media/mediaTrackStatsHandler"; -import { TrackStatsBuilder } from "./trackStatsBuilder"; -import { ConnectionStatsReportBuilder } from "./connectionStatsReportBuilder"; -import { ValueFormatter } from "./valueFormatter"; -import { CallStatsReportSummary } from "./callStatsReportSummary"; -import { logger } from "../../logger"; -import { CallFeedStatsReporter } from "./callFeedStatsReporter"; +import { ConnectionStats } from "./connectionStats.ts"; +import { StatsReportEmitter } from "./statsReportEmitter.ts"; +import { ByteSend, ByteSentStatsReport, TrackID } from "./statsReport.ts"; +import { ConnectionStatsBuilder } from "./connectionStatsBuilder.ts"; +import { TransportStatsBuilder } from "./transportStatsBuilder.ts"; +import { MediaSsrcHandler } from "./media/mediaSsrcHandler.ts"; +import { MediaTrackHandler } from "./media/mediaTrackHandler.ts"; +import { MediaTrackStatsHandler } from "./media/mediaTrackStatsHandler.ts"; +import { TrackStatsBuilder } from "./trackStatsBuilder.ts"; +import { ConnectionStatsReportBuilder } from "./connectionStatsReportBuilder.ts"; +import { ValueFormatter } from "./valueFormatter.ts"; +import { CallStatsReportSummary } from "./callStatsReportSummary.ts"; +import { logger } from "../../logger.ts"; +import { CallFeedStatsReporter } from "./callFeedStatsReporter.ts"; export class CallStatsReportGatherer { private isActive = true; diff --git a/src/webrtc/stats/connectionStats.ts b/src/webrtc/stats/connectionStats.ts index ef1c36797ea..2a998c0931d 100644 --- a/src/webrtc/stats/connectionStats.ts +++ b/src/webrtc/stats/connectionStats.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { TransportStats } from "./transportStats"; -import { Bitrate } from "./media/mediaTrackStats"; +import { TransportStats } from "./transportStats.ts"; +import { Bitrate } from "./media/mediaTrackStats.ts"; export interface ConnectionStatsBandwidth { /** diff --git a/src/webrtc/stats/connectionStatsBuilder.ts b/src/webrtc/stats/connectionStatsBuilder.ts index f954fed49f7..154a648d36f 100644 --- a/src/webrtc/stats/connectionStatsBuilder.ts +++ b/src/webrtc/stats/connectionStatsBuilder.ts @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { Bitrate } from "./media/mediaTrackStats"; +import { Bitrate } from "./media/mediaTrackStats.ts"; export class ConnectionStatsBuilder { public static buildBandwidthReport(now: RTCIceCandidatePairStats): Bitrate { diff --git a/src/webrtc/stats/connectionStatsReportBuilder.ts b/src/webrtc/stats/connectionStatsReportBuilder.ts index 5ed99d59bae..0be778f1ca5 100644 --- a/src/webrtc/stats/connectionStatsReportBuilder.ts +++ b/src/webrtc/stats/connectionStatsReportBuilder.ts @@ -13,8 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { AudioConcealment, CodecMap, ConnectionStatsReport, FramerateMap, ResolutionMap, TrackID } from "./statsReport"; -import { MediaTrackStats, Resolution } from "./media/mediaTrackStats"; +import { + AudioConcealment, + CodecMap, + ConnectionStatsReport, + FramerateMap, + ResolutionMap, + TrackID, +} from "./statsReport.ts"; +import { MediaTrackStats, Resolution } from "./media/mediaTrackStats.ts"; export class ConnectionStatsReportBuilder { public static build(stats: Map): ConnectionStatsReport { diff --git a/src/webrtc/stats/groupCallStats.ts b/src/webrtc/stats/groupCallStats.ts index 1c976a9dd91..ac9283e1cc1 100644 --- a/src/webrtc/stats/groupCallStats.ts +++ b/src/webrtc/stats/groupCallStats.ts @@ -13,11 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { CallStatsReportGatherer } from "./callStatsReportGatherer"; -import { StatsReportEmitter } from "./statsReportEmitter"; -import { CallStatsReportSummary } from "./callStatsReportSummary"; -import { SummaryStatsReportGatherer } from "./summaryStatsReportGatherer"; -import { logger } from "../../logger"; +import { CallStatsReportGatherer } from "./callStatsReportGatherer.ts"; +import { StatsReportEmitter } from "./statsReportEmitter.ts"; +import { CallStatsReportSummary } from "./callStatsReportSummary.ts"; +import { SummaryStatsReportGatherer } from "./summaryStatsReportGatherer.ts"; +import { logger } from "../../logger.ts"; export class GroupCallStats { private timer: undefined | ReturnType; diff --git a/src/webrtc/stats/media/mediaTrackStats.ts b/src/webrtc/stats/media/mediaTrackStats.ts index 7835ceb8a65..e03fae9b3ac 100644 --- a/src/webrtc/stats/media/mediaTrackStats.ts +++ b/src/webrtc/stats/media/mediaTrackStats.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { AudioConcealment } from "../statsReport"; -import { TrackId } from "./mediaTrackHandler"; +import { AudioConcealment } from "../statsReport.ts"; +import { TrackId } from "./mediaTrackHandler.ts"; export interface PacketLoss { packetsTotal: number; diff --git a/src/webrtc/stats/media/mediaTrackStatsHandler.ts b/src/webrtc/stats/media/mediaTrackStatsHandler.ts index 4841c90f152..d3bd0ec4911 100644 --- a/src/webrtc/stats/media/mediaTrackStatsHandler.ts +++ b/src/webrtc/stats/media/mediaTrackStatsHandler.ts @@ -13,10 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { TrackID } from "../statsReport"; -import { MediaTrackStats } from "./mediaTrackStats"; -import { MediaTrackHandler, TrackId } from "./mediaTrackHandler"; -import { MediaSsrcHandler } from "./mediaSsrcHandler"; +import { TrackID } from "../statsReport.ts"; +import { MediaTrackStats } from "./mediaTrackStats.ts"; +import { MediaTrackHandler, TrackId } from "./mediaTrackHandler.ts"; +import { MediaSsrcHandler } from "./mediaSsrcHandler.ts"; export class MediaTrackStatsHandler { private readonly track2stats = new Map(); diff --git a/src/webrtc/stats/statsReport.ts b/src/webrtc/stats/statsReport.ts index 9f24267e1fe..2fe13c7e6d6 100644 --- a/src/webrtc/stats/statsReport.ts +++ b/src/webrtc/stats/statsReport.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ConnectionStatsBandwidth, ConnectionStatsBitrate, PacketLoss } from "./connectionStats"; -import { TransportStats } from "./transportStats"; -import { Resolution } from "./media/mediaTrackStats"; +import { ConnectionStatsBandwidth, ConnectionStatsBitrate, PacketLoss } from "./connectionStats.ts"; +import { TransportStats } from "./transportStats.ts"; +import { Resolution } from "./media/mediaTrackStats.ts"; export enum StatsReport { CONNECTION_STATS = "StatsReport.connection_stats", diff --git a/src/webrtc/stats/statsReportEmitter.ts b/src/webrtc/stats/statsReportEmitter.ts index 1b8834326af..aef92a830fb 100644 --- a/src/webrtc/stats/statsReportEmitter.ts +++ b/src/webrtc/stats/statsReportEmitter.ts @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { TypedEventEmitter } from "../../models/typed-event-emitter"; +import { TypedEventEmitter } from "../../models/typed-event-emitter.ts"; import { ByteSentStatsReport, CallFeedReport, ConnectionStatsReport, StatsReport, SummaryStatsReport, -} from "./statsReport"; +} from "./statsReport.ts"; export type StatsReportHandlerMap = { [StatsReport.BYTE_SENT_STATS]: (report: ByteSentStatsReport) => void; diff --git a/src/webrtc/stats/summaryStatsReportGatherer.ts b/src/webrtc/stats/summaryStatsReportGatherer.ts index b0227670d98..09e381d48da 100644 --- a/src/webrtc/stats/summaryStatsReportGatherer.ts +++ b/src/webrtc/stats/summaryStatsReportGatherer.ts @@ -10,11 +10,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { StatsReportEmitter } from "./statsReportEmitter"; -import { CallStatsReportSummary } from "./callStatsReportSummary"; -import { SummaryStatsReport } from "./statsReport"; -import { ParticipantState } from "../groupCall"; -import { RoomMember } from "../../matrix"; +import { StatsReportEmitter } from "./statsReportEmitter.ts"; +import { CallStatsReportSummary } from "./callStatsReportSummary.ts"; +import { SummaryStatsReport } from "./statsReport.ts"; +import { ParticipantState } from "../groupCall.ts"; +import { RoomMember } from "../../matrix.ts"; interface CallStatsReportSummaryCounter { receivedAudio: number; diff --git a/src/webrtc/stats/trackStatsBuilder.ts b/src/webrtc/stats/trackStatsBuilder.ts index c670fddbb47..f6ef729872d 100644 --- a/src/webrtc/stats/trackStatsBuilder.ts +++ b/src/webrtc/stats/trackStatsBuilder.ts @@ -1,6 +1,6 @@ -import { MediaTrackStats } from "./media/mediaTrackStats"; -import { ValueFormatter } from "./valueFormatter"; -import { TrackSummary } from "./callStatsReportSummary"; +import { MediaTrackStats } from "./media/mediaTrackStats.ts"; +import { ValueFormatter } from "./valueFormatter.ts"; +import { TrackSummary } from "./callStatsReportSummary.ts"; export class TrackStatsBuilder { public static buildFramerateResolution(trackStats: MediaTrackStats, now: any): void { diff --git a/src/webrtc/stats/transportStatsBuilder.ts b/src/webrtc/stats/transportStatsBuilder.ts index 12ed7b0cbe4..c81ca4b5ab2 100644 --- a/src/webrtc/stats/transportStatsBuilder.ts +++ b/src/webrtc/stats/transportStatsBuilder.ts @@ -1,4 +1,4 @@ -import { TransportStats } from "./transportStats"; +import { TransportStats } from "./transportStats.ts"; export class TransportStatsBuilder { public static buildReport( diff --git a/tsconfig.json b/tsconfig.json index c1c9d48b8e9..9339d6dfd31 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2016", + "target": "es2022", "experimentalDecorators": true, "esModuleInterop": true, "module": "commonjs", @@ -8,7 +8,8 @@ "noUnusedLocals": true, "noEmit": true, "declaration": true, - "strict": true + "strict": true, + "allowImportingTsExtensions": true }, "include": ["./src/**/*.ts", "./spec/**/*.ts"] } diff --git a/yarn.lock b/yarn.lock index cf6d64c5b80..49efed4ad35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - "@action-validator/cli@^0.6.0": version "0.6.0" resolved "https://registry.yarnpkg.com/@action-validator/cli/-/cli-0.6.0.tgz#02a29e322d3794903896183281eed2b55c685851" @@ -28,12 +23,12 @@ "@jridgewell/trace-mapping" "^0.3.24" "@babel/cli@^7.12.10": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.24.5.tgz#9eba21699f289c32e63a28aedf82f888dc134b30" - integrity sha512-2qg1mYtJRsOOWF6IUwLP5jI42P8Cc0hQ5TmnjLrik/4DKouO8dFJN80HEz81VmVeUs97yuuf3vQ/9j7Elrcjlg== + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.24.8.tgz#79eaa55a69c77cafbea3e87537fd1df5a5a2edf8" + integrity sha512-isdp+G6DpRyKc+3Gqxy2rjzgF7Zj9K0mzLNnxz+E/fgeag8qT3vVulX4gY9dGO1q0y+0lUv6V3a+uhUzMzrwXg== dependencies: "@jridgewell/trace-mapping" "^0.3.25" - commander "^4.0.1" + commander "^6.2.0" convert-source-map "^2.0.0" fs-readdir-recursive "^1.1.0" glob "^7.2.0" @@ -43,205 +38,121 @@ "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" chokidar "^3.4.0" -"@babel/code-frame@^7.0.0": - version "7.22.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" - integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== - dependencies: - "@babel/highlight" "^7.22.13" - chalk "^2.4.2" - -"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== dependencies: - "@babel/highlight" "^7.24.2" + "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.20.5": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" - integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.2.tgz#e41928bd33475305c586f6acbbb7e3ade7a6f7f5" + integrity sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ== -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" - integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== - -"@babel/compat-data@^7.22.9": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== - -"@babel/core@^7.0.0", "@babel/core@^7.12.10": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.5.tgz#15ab5b98e101972d171aeef92ac70d8d6718f06a" - integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== +"@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.24.5" - "@babel/helpers" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/core@^7.11.6", "@babel/core@^7.12.3": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.17.tgz#2f9b0b395985967203514b24ee50f9fd0639c866" - integrity sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" - "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.22.17" - "@babel/helpers" "^7.22.15" - "@babel/parser" "^7.22.16" - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.17" - "@babel/types" "^7.22.17" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - "@babel/eslint-parser@^7.12.10": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.24.5.tgz#3b0f7d383a540329a30a6a9937cfc89461d26217" - integrity sha512-gsUcqS/fPlgAw1kOtpss7uhY6E9SFFANQ6EFX5GTvzUwaV0+sGaZWk6xq22MOdeT9wfxyokW3ceCUvOiRtZciQ== + version "7.25.1" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.25.1.tgz#469cee4bd18a88ff3edbdfbd227bd20e82aa9b82" + integrity sha512-Y956ghgTT4j7rKesabkh5WeqgSFZVFwaPR0IWFm7KFHFmmJ4afbG49SmfW4S+GyRPx0Dy5jxEWA5t0rpxfElWg== dependencies: "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" semver "^6.3.1" "@babel/eslint-plugin@^7.12.10": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.24.5.tgz#6581b9005ab76308e4aef6b50aa1788099393211" - integrity sha512-5n3K9Zv13VOa9SG2ZiX0WV7A0ddApRn6vsV8zBojCsxnCbYKLjCDvzDfVxS7C4STmjQDOXU1uk/ppxxDTC860w== + version "7.25.1" + resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.25.1.tgz#fc7fff590ab566c9d643fdecf346b69064157ef9" + integrity sha512-jF04YOsrCbEeQk4s+FwsuRddwBiAHooMDG9/nrV83HiYQwEuQppbXTeXyydxCoH5oEWmVBI51wHuZrcIXMkPfw== dependencies: eslint-rule-composer "^0.3.0" -"@babel/generator@^7.22.15", "@babel/generator@^7.7.2": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" - integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== - dependencies: - "@babel/types" "^7.22.15" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/generator@^7.23.0": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.3.tgz#86e6e83d95903fbe7613f448613b8b319f330a8e" - integrity sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg== +"@babel/generator@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e" + integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw== dependencies: - "@babel/types" "^7.23.3" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" + "@babel/types" "^7.25.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/generator@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3" - integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== +"@babel/generator@^7.7.2": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" + integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== dependencies: - "@babel/types" "^7.24.5" + "@babel/types" "^7.24.7" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" - integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz#5426b109cf3ad47b91120f8328d8ab1be8b0b956" - integrity sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw== +"@babel/helper-annotate-as-pure@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz#5373c7bc8366b12a033b4be1ac13a206c6656aab" + integrity sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.24.7" -"@babel/helper-compilation-targets@^7.20.7": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024" - integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz#37d66feb012024f2422b762b9b2a7cfe27c7fba3" + integrity sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA== dependencies: - "@babel/compat-data" "^7.22.9" - "@babel/helper-validator-option" "^7.22.5" - browserslist "^4.21.9" - lru-cache "^5.1.1" - semver "^6.3.1" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.24.7", "@babel/helper-compilation-targets@^7.24.8", "@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.18.6": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz#dd2612d59eac45588021ac3d6fa976d08f4e95a3" - integrity sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" - "@babel/helper-member-expression-to-functions" "^7.22.5" - "@babel/helper-optimise-call-expression" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" +"@babel/helper-create-class-features-plugin@^7.24.7": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz#a109bf9c3d58dfed83aaf42e85633c89f43a6253" + integrity sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/helper-replace-supers" "^7.25.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/traverse" "^7.25.0" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.24.1", "@babel/helper-create-class-features-plugin@^7.24.4", "@babel/helper-create-class-features-plugin@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz#7d19da92c7e0cd8d11c09af2ce1b8e7512a6e723" - integrity sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-member-expression-to-functions" "^7.24.5" - "@babel/helper-optimise-call-expression" "^7.22.5" - "@babel/helper-replace-supers" "^7.24.1" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.24.5" - semver "^6.3.1" - -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1" - integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w== +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz#24c75974ed74183797ffd5f134169316cd1808d9" + integrity sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g== dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-annotate-as-pure" "^7.24.7" regexpu-core "^5.3.1" semver "^6.3.1" @@ -256,305 +167,170 @@ lodash.debounce "^4.0.8" resolve "^1.14.2" -"@babel/helper-environment-visitor@^7.22.20", "@babel/helper-environment-visitor@^7.22.5": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.22.5", "@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-member-expression-to-functions@^7.22.15": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz#9263e88cc5e41d39ec18c9a3e0eced59a3e7d366" - integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== - dependencies: - "@babel/types" "^7.23.0" - -"@babel/helper-member-expression-to-functions@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz#b95a144896f6d491ca7863576f820f3628818621" - integrity sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-member-expression-to-functions@^7.23.0", "@babel/helper-member-expression-to-functions@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz#5981e131d5c7003c7d1fa1ad49e86c9b097ec475" - integrity sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA== - dependencies: - "@babel/types" "^7.24.5" - -"@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.24.1", "@babel/helper-module-imports@^7.24.3": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== - dependencies: - "@babel/types" "^7.24.0" - -"@babel/helper-module-transforms@^7.22.17": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz#7edf129097a51ccc12443adbc6320e90eab76693" - integrity sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.15" - -"@babel/helper-module-transforms@^7.23.3", "@babel/helper-module-transforms@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz#ea6c5e33f7b262a0ae762fd5986355c45f54a545" - integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.24.3" - "@babel/helper-simple-access" "^7.24.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/helper-validator-identifier" "^7.24.5" - -"@babel/helper-optimise-call-expression@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" - integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.24.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz#a924607dd254a65695e5bd209b98b902b3b2f11a" - integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== - -"@babel/helper-plugin-utils@^7.20.2": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" - integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== - -"@babel/helper-remap-async-to-generator@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz#7b68e1cb4fa964d2996fd063723fb48eca8498e0" - integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-wrap-function" "^7.22.20" - -"@babel/helper-replace-supers@^7.22.9": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" - integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-member-expression-to-functions" "^7.22.15" - "@babel/helper-optimise-call-expression" "^7.22.5" - -"@babel/helper-replace-supers@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz#7085bd19d4a0b7ed8f405c1ed73ccb70f323abc1" - integrity sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-member-expression-to-functions" "^7.23.0" - "@babel/helper-optimise-call-expression" "^7.22.5" - -"@babel/helper-simple-access@^7.22.5", "@babel/helper-simple-access@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz#50da5b72f58c16b07fbd992810be6049478e85ba" - integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== - dependencies: - "@babel/types" "^7.24.5" - -"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" - integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6", "@babel/helper-split-export-declaration@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz#b9a67f06a46b0b339323617c8c6213b9055a78b6" - integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== - dependencies: - "@babel/types" "^7.24.5" - -"@babel/helper-string-parser@^7.22.5": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - -"@babel/helper-string-parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" - integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== - -"@babel/helper-validator-identifier@^7.22.15", "@babel/helper-validator-identifier@^7.22.19": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" - integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== - -"@babel/helper-validator-option@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" - integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== - -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helper-wrap-function@^7.22.20": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.24.5.tgz#335f934c0962e2c1ed1fb9d79e06a56115067c09" - integrity sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw== - dependencies: - "@babel/helper-function-name" "^7.23.0" - "@babel/template" "^7.24.0" - "@babel/types" "^7.24.5" - -"@babel/helpers@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" - integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/helpers@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.5.tgz#fedeb87eeafa62b621160402181ad8585a22a40a" - integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== - dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" - -"@babel/highlight@^7.22.13": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/highlight@^7.23.4": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.1.tgz#21f3f5391c793b3f0d6dbb40f898c48cc6ad4215" - integrity sha512-EPmDPxidWe/Ex+HTFINpvXdPHRmgSF3T8hGvzondYjmgzTQ/0EbLpSxyt+w3zzlYSk9cNBQNF9k0dT5Z2NiBjw== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" +"@babel/helper-member-expression-to-functions@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz#6155e079c913357d24a4c20480db7c712a5c3fb6" + integrity sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA== + dependencies: + "@babel/traverse" "^7.24.8" + "@babel/types" "^7.24.8" + +"@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-module-transforms@^7.24.7", "@babel/helper-module-transforms@^7.24.8", "@babel/helper-module-transforms@^7.25.0", "@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== + dependencies: + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" + +"@babel/helper-optimise-call-expression@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz#8b0a0456c92f6b323d27cfd00d1d664e76692a0f" + integrity sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== + +"@babel/helper-remap-async-to-generator@^7.24.7", "@babel/helper-remap-async-to-generator@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz#d2f0fbba059a42d68e5e378feaf181ef6055365e" + integrity sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-wrap-function" "^7.25.0" + "@babel/traverse" "^7.25.0" + +"@babel/helper-replace-supers@^7.24.7", "@babel/helper-replace-supers@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz#ff44deac1c9f619523fe2ca1fd650773792000a9" + integrity sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/traverse" "^7.25.0" + +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz#5f8fa83b69ed5c27adc56044f8be2b3ea96669d9" + integrity sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-string-parser@^7.24.7", "@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + +"@babel/helper-validator-identifier@^7.24.5", "@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-option@^7.24.7", "@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== + +"@babel/helper-wrap-function@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz#dab12f0f593d6ca48c0062c28bcfb14ebe812f81" + integrity sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ== + dependencies: + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.0" + "@babel/types" "^7.25.0" + +"@babel/helpers@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.0.tgz#e69beb7841cb93a6505531ede34f34e6a073650a" + integrity sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw== + dependencies: + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.0" + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/highlight@^7.24.2": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.5.tgz#bc0613f98e1dd0720e99b2a9ee3760194a704b6e" - integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== - dependencies: - "@babel/helper-validator-identifier" "^7.24.5" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.16": - version "7.22.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" - integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" + integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== -"@babel/parser@^7.22.15": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b" - integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== - -"@babel/parser@^7.23.0": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.3.tgz#0ce0be31a4ca4f1884b5786057cadcb6c3be58f9" - integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw== - -"@babel/parser@^7.24.0", "@babel/parser@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" - integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== - -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.5.tgz#4c3685eb9cd790bcad2843900fe0250c91ccf895" - integrity sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw== +"@babel/parser@^7.24.7", "@babel/parser@^7.25.0", "@babel/parser@^7.25.3": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065" + integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.24.5" + "@babel/types" "^7.25.2" -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz#b645d9ba8c2bc5b7af50f0fe949f9edbeb07c8cf" - integrity sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg== +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.3": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz#dca427b45a6c0f5c095a1c639dfe2476a3daba7f" + integrity sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/traverse" "^7.25.3" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz#da8261f2697f0f41b0855b91d3a20a1fbfd271d3" - integrity sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ== +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz#cd0c583e01369ef51676bdb3d7b603e17d2b3f73" + integrity sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/plugin-transform-optional-chaining" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz#1181d9685984c91d657b8ddf14f0487a6bab2988" - integrity sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/plugin-proposal-class-properties@^7.12.1": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz#749bde80356b295390954643de7635e0dffabe73" + integrity sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-proposal-numeric-separator@^7.12.7": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" - integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz#e4eabdd5109acc399b38d7999b2ef66fc2022f89" + integrity sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/plugin-transform-optional-chaining" "^7.24.7" -"@babel/plugin-proposal-object-rest-spread@^7.12.1": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz#3a82a70e7cb7294ad2559465ebcb871dfbf078fb" + integrity sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw== dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/traverse" "^7.25.0" "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": version "7.21.0-placeholder-for-preset-env.2" @@ -603,19 +379,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-import-assertions@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz#db3aad724153a00eaac115a3fb898de544e34971" - integrity sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ== +"@babel/plugin-syntax-import-assertions@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz#2a0b406b5871a20a841240586b1300ce2088a778" + integrity sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-syntax-import-attributes@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz#c66b966c63b714c4eec508fcf5763b1f2d381093" - integrity sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA== +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz#b4f9ea95a79e6912480c4b626739f86a076624ca" + integrity sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" @@ -631,19 +407,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" - integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/plugin-syntax-jsx@^7.7.2": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" - integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== +"@babel/plugin-syntax-jsx@^7.24.7", "@babel/plugin-syntax-jsx@^7.7.2": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" + integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -701,19 +470,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" - integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/plugin-syntax-typescript@^7.7.2": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" - integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== +"@babel/plugin-syntax-typescript@^7.24.7", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c" + integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" @@ -723,443 +485,452 @@ "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-arrow-functions@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz#2bf263617060c9cc45bcdbf492b8cc805082bf27" - integrity sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw== +"@babel/plugin-transform-arrow-functions@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz#4f6886c11e423bd69f3ce51dbf42424a5f275514" + integrity sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-async-generator-functions@^7.24.3": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz#8fa7ae481b100768cc9842c8617808c5352b8b89" - integrity sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg== +"@babel/plugin-transform-async-generator-functions@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz#b785cf35d73437f6276b1e30439a57a50747bddf" + integrity sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-remap-async-to-generator" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-remap-async-to-generator" "^7.25.0" "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/traverse" "^7.25.0" -"@babel/plugin-transform-async-to-generator@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz#0e220703b89f2216800ce7b1c53cb0cf521c37f4" - integrity sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw== +"@babel/plugin-transform-async-to-generator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz#72a3af6c451d575842a7e9b5a02863414355bdcc" + integrity sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA== dependencies: - "@babel/helper-module-imports" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-remap-async-to-generator" "^7.22.20" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-remap-async-to-generator" "^7.24.7" -"@babel/plugin-transform-block-scoped-functions@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz#1c94799e20fcd5c4d4589523bbc57b7692979380" - integrity sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg== +"@babel/plugin-transform-block-scoped-functions@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz#a4251d98ea0c0f399dafe1a35801eaba455bbf1f" + integrity sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-block-scoping@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.5.tgz#89574191397f85661d6f748d4b89ee4d9ee69a2a" - integrity sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw== +"@babel/plugin-transform-block-scoping@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz#23a6ed92e6b006d26b1869b1c91d1b917c2ea2ac" + integrity sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-class-properties@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz#bcbf1aef6ba6085cfddec9fc8d58871cf011fc29" - integrity sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g== +"@babel/plugin-transform-class-properties@^7.12.1", "@babel/plugin-transform-class-properties@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz#256879467b57b0b68c7ddfc5b76584f398cd6834" + integrity sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-class-static-block@^7.24.4": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz#1a4653c0cf8ac46441ec406dece6e9bc590356a4" - integrity sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg== +"@babel/plugin-transform-class-static-block@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz#c82027ebb7010bc33c116d4b5044fbbf8c05484d" + integrity sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.4" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-transform-classes@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.5.tgz#05e04a09df49a46348299a0e24bfd7e901129339" - integrity sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-plugin-utils" "^7.24.5" - "@babel/helper-replace-supers" "^7.24.1" - "@babel/helper-split-export-declaration" "^7.24.5" +"@babel/plugin-transform-classes@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz#63122366527d88e0ef61b612554fe3f8c793991e" + integrity sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-compilation-targets" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-replace-supers" "^7.25.0" + "@babel/traverse" "^7.25.0" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz#bc7e787f8e021eccfb677af5f13c29a9934ed8a7" - integrity sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw== +"@babel/plugin-transform-computed-properties@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz#4cab3214e80bc71fae3853238d13d097b004c707" + integrity sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/template" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/template" "^7.24.7" -"@babel/plugin-transform-destructuring@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.5.tgz#80843ee6a520f7362686d1a97a7b53544ede453c" - integrity sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg== +"@babel/plugin-transform-destructuring@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz#c828e814dbe42a2718a838c2a2e16a408e055550" + integrity sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-dotall-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz#d56913d2f12795cc9930801b84c6f8c47513ac13" - integrity sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw== +"@babel/plugin-transform-dotall-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz#5f8bf8a680f2116a7207e16288a5f974ad47a7a0" + integrity sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-duplicate-keys@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz#5347a797fe82b8d09749d10e9f5b83665adbca88" - integrity sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA== +"@babel/plugin-transform-duplicate-keys@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz#dd20102897c9a2324e5adfffb67ff3610359a8ee" + integrity sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-dynamic-import@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz#2a5a49959201970dd09a5fca856cb651e44439dd" - integrity sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA== +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz#809af7e3339466b49c034c683964ee8afb3e2604" + integrity sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.25.0" + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/plugin-transform-dynamic-import@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz#4d8b95e3bae2b037673091aa09cd33fecd6419f4" + integrity sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz#6650ebeb5bd5c012d5f5f90a26613a08162e8ba4" - integrity sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw== +"@babel/plugin-transform-exponentiation-operator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz#b629ee22645f412024297d5245bce425c31f9b0d" + integrity sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-export-namespace-from@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz#f033541fc036e3efb2dcb58eedafd4f6b8078acd" - integrity sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ== +"@babel/plugin-transform-export-namespace-from@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz#176d52d8d8ed516aeae7013ee9556d540c53f197" + integrity sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-transform-for-of@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz#67448446b67ab6c091360ce3717e7d3a59e202fd" - integrity sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg== +"@babel/plugin-transform-for-of@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz#f25b33f72df1d8be76399e1b8f3f9d366eb5bc70" + integrity sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" -"@babel/plugin-transform-function-name@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz#8cba6f7730626cc4dfe4ca2fa516215a0592b361" - integrity sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA== +"@babel/plugin-transform-function-name@^7.25.1": + version "7.25.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz#b85e773097526c1a4fc4ba27322748643f26fc37" + integrity sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA== dependencies: - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-compilation-targets" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/traverse" "^7.25.1" -"@babel/plugin-transform-json-strings@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz#08e6369b62ab3e8a7b61089151b161180c8299f7" - integrity sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ== +"@babel/plugin-transform-json-strings@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz#f3e9c37c0a373fee86e36880d45b3664cedaf73a" + integrity sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-transform-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz#0a1982297af83e6b3c94972686067df588c5c096" - integrity sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g== +"@babel/plugin-transform-literals@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz#deb1ad14fc5490b9a65ed830e025bca849d8b5f3" + integrity sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-logical-assignment-operators@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz#719d8aded1aa94b8fb34e3a785ae8518e24cfa40" - integrity sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w== +"@babel/plugin-transform-logical-assignment-operators@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz#a58fb6eda16c9dc8f9ff1c7b1ba6deb7f4694cb0" + integrity sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-transform-member-expression-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz#896d23601c92f437af8b01371ad34beb75df4489" - integrity sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg== +"@babel/plugin-transform-member-expression-literals@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz#3b4454fb0e302e18ba4945ba3246acb1248315df" + integrity sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-modules-amd@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz#b6d829ed15258536977e9c7cc6437814871ffa39" - integrity sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ== +"@babel/plugin-transform-modules-amd@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz#65090ed493c4a834976a3ca1cde776e6ccff32d7" + integrity sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg== dependencies: - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-modules-commonjs@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz#e71ba1d0d69e049a22bf90b3867e263823d3f1b9" - integrity sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw== +"@babel/plugin-transform-modules-commonjs@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz#9fd5f7fdadee9085886b183f1ad13d1ab260f4ab" + integrity sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ== dependencies: - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" -"@babel/plugin-transform-modules-systemjs@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz#2b9625a3d4e445babac9788daec39094e6b11e3e" - integrity sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA== +"@babel/plugin-transform-modules-commonjs@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz#ab6421e564b717cb475d6fff70ae7f103536ea3c" + integrity sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA== dependencies: - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-module-transforms" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-simple-access" "^7.24.7" -"@babel/plugin-transform-modules-umd@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz#69220c66653a19cf2c0872b9c762b9a48b8bebef" - integrity sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg== +"@babel/plugin-transform-modules-systemjs@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz#8f46cdc5f9e5af74f3bd019485a6cbe59685ea33" + integrity sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw== dependencies: - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-module-transforms" "^7.25.0" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.0" -"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" - integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== +"@babel/plugin-transform-modules-umd@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz#edd9f43ec549099620df7df24e7ba13b5c76efc8" + integrity sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.5" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-new-target@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz#29c59988fa3d0157de1c871a28cd83096363cc34" - integrity sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug== +"@babel/plugin-transform-named-capturing-groups-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz#9042e9b856bc6b3688c0c2e4060e9e10b1460923" + integrity sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-nullish-coalescing-operator@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz#0cd494bb97cb07d428bd651632cb9d4140513988" - integrity sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw== +"@babel/plugin-transform-new-target@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz#31ff54c4e0555cc549d5816e4ab39241dfb6ab00" + integrity sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz#1de4534c590af9596f53d67f52a92f12db984120" + integrity sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-transform-numeric-separator@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz#5bc019ce5b3435c1cadf37215e55e433d674d4e8" - integrity sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw== +"@babel/plugin-transform-numeric-separator@^7.12.7", "@babel/plugin-transform-numeric-separator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz#bea62b538c80605d8a0fac9b40f48e97efa7de63" + integrity sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-transform-object-rest-spread@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.5.tgz#f91bbcb092ff957c54b4091c86bda8372f0b10ef" - integrity sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA== +"@babel/plugin-transform-object-rest-spread@^7.12.1", "@babel/plugin-transform-object-rest-spread@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz#d13a2b93435aeb8a197e115221cab266ba6e55d6" + integrity sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q== dependencies: - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-compilation-targets" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.24.5" + "@babel/plugin-transform-parameters" "^7.24.7" -"@babel/plugin-transform-object-super@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz#e71d6ab13483cca89ed95a474f542bbfc20a0520" - integrity sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ== +"@babel/plugin-transform-object-super@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz#66eeaff7830bba945dd8989b632a40c04ed625be" + integrity sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-replace-supers" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-replace-supers" "^7.24.7" -"@babel/plugin-transform-optional-catch-binding@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz#92a3d0efe847ba722f1a4508669b23134669e2da" - integrity sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA== +"@babel/plugin-transform-optional-catch-binding@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz#00eabd883d0dd6a60c1c557548785919b6e717b4" + integrity sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.24.1", "@babel/plugin-transform-optional-chaining@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.5.tgz#a6334bebd7f9dd3df37447880d0bd64b778e600f" - integrity sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg== +"@babel/plugin-transform-optional-chaining@^7.24.7", "@babel/plugin-transform-optional-chaining@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz#bb02a67b60ff0406085c13d104c99a835cdf365d" + integrity sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw== dependencies: - "@babel/helper-plugin-utils" "^7.24.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-transform-parameters@^7.20.7": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" - integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-parameters@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.5.tgz#5c3b23f3a6b8fed090f9b98f2926896d3153cc62" - integrity sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA== +"@babel/plugin-transform-parameters@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz#5881f0ae21018400e320fc7eb817e529d1254b68" + integrity sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA== dependencies: - "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-private-methods@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz#a0faa1ae87eff077e1e47a5ec81c3aef383dc15a" - integrity sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw== +"@babel/plugin-transform-private-methods@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz#e6318746b2ae70a59d023d5cc1344a2ba7a75f5e" + integrity sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-private-property-in-object@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.5.tgz#f5d1fcad36e30c960134cb479f1ca98a5b06eda5" - integrity sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ== +"@babel/plugin-transform-private-property-in-object@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz#4eec6bc701288c1fab5f72e6a4bbc9d67faca061" + integrity sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA== dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.24.5" - "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-transform-property-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz#d6a9aeab96f03749f4eebeb0b6ea8e90ec958825" - integrity sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA== +"@babel/plugin-transform-property-literals@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz#f0d2ed8380dfbed949c42d4d790266525d63bbdc" + integrity sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-regenerator@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz#625b7545bae52363bdc1fbbdc7252b5046409c8c" - integrity sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw== +"@babel/plugin-transform-regenerator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz#021562de4534d8b4b1851759fd7af4e05d2c47f8" + integrity sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" regenerator-transform "^0.15.2" -"@babel/plugin-transform-reserved-words@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz#8de729f5ecbaaf5cf83b67de13bad38a21be57c1" - integrity sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg== +"@babel/plugin-transform-reserved-words@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz#80037fe4fbf031fc1125022178ff3938bb3743a4" + integrity sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-transform-runtime@^7.12.10": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.3.tgz#dc58ad4a31810a890550365cc922e1ff5acb5d7f" - integrity sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.7.tgz#00a5bfaf8c43cf5c8703a8a6e82b59d9c58f38ca" + integrity sha512-YqXjrk4C+a1kZjewqt+Mmu2UuV1s07y8kqcUf4qYLnoqemhR4gRQikhdAhSVJioMjVTu6Mo6pAbaypEA3jY6fw== dependencies: - "@babel/helper-module-imports" "^7.24.3" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" babel-plugin-polyfill-corejs2 "^0.4.10" babel-plugin-polyfill-corejs3 "^0.10.1" babel-plugin-polyfill-regenerator "^0.6.1" semver "^6.3.1" -"@babel/plugin-transform-shorthand-properties@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz#ba9a09144cf55d35ec6b93a32253becad8ee5b55" - integrity sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA== +"@babel/plugin-transform-shorthand-properties@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz#85448c6b996e122fa9e289746140aaa99da64e73" + integrity sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-spread@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz#a1acf9152cbf690e4da0ba10790b3ac7d2b2b391" - integrity sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g== +"@babel/plugin-transform-spread@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz#e8a38c0fde7882e0fb8f160378f74bd885cc7bb3" + integrity sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" -"@babel/plugin-transform-sticky-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz#f03e672912c6e203ed8d6e0271d9c2113dc031b9" - integrity sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw== +"@babel/plugin-transform-sticky-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz#96ae80d7a7e5251f657b5cf18f1ea6bf926f5feb" + integrity sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-template-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz#15e2166873a30d8617e3e2ccadb86643d327aab7" - integrity sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g== +"@babel/plugin-transform-template-literals@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz#a05debb4a9072ae8f985bcf77f3f215434c8f8c8" + integrity sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-typeof-symbol@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.5.tgz#703cace5ef74155fb5eecab63cbfc39bdd25fe12" - integrity sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg== +"@babel/plugin-transform-typeof-symbol@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz#383dab37fb073f5bfe6e60c654caac309f92ba1c" + integrity sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw== dependencies: - "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-typescript@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.1.tgz#5c05e28bb76c7dfe7d6c5bed9951324fd2d3ab07" - integrity sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w== +"@babel/plugin-transform-typescript@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.7.tgz#b006b3e0094bf0813d505e0c5485679eeaf4a881" + integrity sha512-iLD3UNkgx2n/HrjBesVbYX6j0yqn/sJktvbtKKgcaLIQ4bTTQ8obAypc1VpyHPD2y4Phh9zHOaAt8e/L14wCpw== dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-typescript" "^7.24.1" + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-typescript" "^7.24.7" -"@babel/plugin-transform-unicode-escapes@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz#fb3fa16676549ac7c7449db9b342614985c2a3a4" - integrity sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw== +"@babel/plugin-transform-unicode-escapes@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz#2023a82ced1fb4971630a2e079764502c4148e0e" + integrity sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-unicode-property-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz#56704fd4d99da81e5e9f0c0c93cabd91dbc4889e" - integrity sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng== +"@babel/plugin-transform-unicode-property-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz#9073a4cd13b86ea71c3264659590ac086605bbcd" + integrity sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-unicode-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz#57c3c191d68f998ac46b708380c1ce4d13536385" - integrity sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g== +"@babel/plugin-transform-unicode-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz#dfc3d4a51127108099b19817c0963be6a2adf19f" + integrity sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-unicode-sets-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz#c1ea175b02afcffc9cf57a9c4658326625165b7f" - integrity sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA== +"@babel/plugin-transform-unicode-sets-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz#d40705d67523803a576e29c63cef6e516b858ed9" + integrity sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/preset-env@^7.12.11": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.5.tgz#6a9ac90bd5a5a9dae502af60dfc58c190551bbcd" - integrity sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ== - dependencies: - "@babel/compat-data" "^7.24.4" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-plugin-utils" "^7.24.5" - "@babel/helper-validator-option" "^7.23.5" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.24.5" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.24.1" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.1" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.24.1" + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.3.tgz#0bf4769d84ac51d1073ab4a86f00f30a3a83c67c" + integrity sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g== + dependencies: + "@babel/compat-data" "^7.25.2" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-validator-option" "^7.24.8" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.3" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.0" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.0" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.0" "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.24.1" - "@babel/plugin-syntax-import-attributes" "^7.24.1" + "@babel/plugin-syntax-import-assertions" "^7.24.7" + "@babel/plugin-syntax-import-attributes" "^7.24.7" "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" @@ -1171,59 +942,60 @@ "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" - "@babel/plugin-transform-arrow-functions" "^7.24.1" - "@babel/plugin-transform-async-generator-functions" "^7.24.3" - "@babel/plugin-transform-async-to-generator" "^7.24.1" - "@babel/plugin-transform-block-scoped-functions" "^7.24.1" - "@babel/plugin-transform-block-scoping" "^7.24.5" - "@babel/plugin-transform-class-properties" "^7.24.1" - "@babel/plugin-transform-class-static-block" "^7.24.4" - "@babel/plugin-transform-classes" "^7.24.5" - "@babel/plugin-transform-computed-properties" "^7.24.1" - "@babel/plugin-transform-destructuring" "^7.24.5" - "@babel/plugin-transform-dotall-regex" "^7.24.1" - "@babel/plugin-transform-duplicate-keys" "^7.24.1" - "@babel/plugin-transform-dynamic-import" "^7.24.1" - "@babel/plugin-transform-exponentiation-operator" "^7.24.1" - "@babel/plugin-transform-export-namespace-from" "^7.24.1" - "@babel/plugin-transform-for-of" "^7.24.1" - "@babel/plugin-transform-function-name" "^7.24.1" - "@babel/plugin-transform-json-strings" "^7.24.1" - "@babel/plugin-transform-literals" "^7.24.1" - "@babel/plugin-transform-logical-assignment-operators" "^7.24.1" - "@babel/plugin-transform-member-expression-literals" "^7.24.1" - "@babel/plugin-transform-modules-amd" "^7.24.1" - "@babel/plugin-transform-modules-commonjs" "^7.24.1" - "@babel/plugin-transform-modules-systemjs" "^7.24.1" - "@babel/plugin-transform-modules-umd" "^7.24.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" - "@babel/plugin-transform-new-target" "^7.24.1" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.1" - "@babel/plugin-transform-numeric-separator" "^7.24.1" - "@babel/plugin-transform-object-rest-spread" "^7.24.5" - "@babel/plugin-transform-object-super" "^7.24.1" - "@babel/plugin-transform-optional-catch-binding" "^7.24.1" - "@babel/plugin-transform-optional-chaining" "^7.24.5" - "@babel/plugin-transform-parameters" "^7.24.5" - "@babel/plugin-transform-private-methods" "^7.24.1" - "@babel/plugin-transform-private-property-in-object" "^7.24.5" - "@babel/plugin-transform-property-literals" "^7.24.1" - "@babel/plugin-transform-regenerator" "^7.24.1" - "@babel/plugin-transform-reserved-words" "^7.24.1" - "@babel/plugin-transform-shorthand-properties" "^7.24.1" - "@babel/plugin-transform-spread" "^7.24.1" - "@babel/plugin-transform-sticky-regex" "^7.24.1" - "@babel/plugin-transform-template-literals" "^7.24.1" - "@babel/plugin-transform-typeof-symbol" "^7.24.5" - "@babel/plugin-transform-unicode-escapes" "^7.24.1" - "@babel/plugin-transform-unicode-property-regex" "^7.24.1" - "@babel/plugin-transform-unicode-regex" "^7.24.1" - "@babel/plugin-transform-unicode-sets-regex" "^7.24.1" + "@babel/plugin-transform-arrow-functions" "^7.24.7" + "@babel/plugin-transform-async-generator-functions" "^7.25.0" + "@babel/plugin-transform-async-to-generator" "^7.24.7" + "@babel/plugin-transform-block-scoped-functions" "^7.24.7" + "@babel/plugin-transform-block-scoping" "^7.25.0" + "@babel/plugin-transform-class-properties" "^7.24.7" + "@babel/plugin-transform-class-static-block" "^7.24.7" + "@babel/plugin-transform-classes" "^7.25.0" + "@babel/plugin-transform-computed-properties" "^7.24.7" + "@babel/plugin-transform-destructuring" "^7.24.8" + "@babel/plugin-transform-dotall-regex" "^7.24.7" + "@babel/plugin-transform-duplicate-keys" "^7.24.7" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.0" + "@babel/plugin-transform-dynamic-import" "^7.24.7" + "@babel/plugin-transform-exponentiation-operator" "^7.24.7" + "@babel/plugin-transform-export-namespace-from" "^7.24.7" + "@babel/plugin-transform-for-of" "^7.24.7" + "@babel/plugin-transform-function-name" "^7.25.1" + "@babel/plugin-transform-json-strings" "^7.24.7" + "@babel/plugin-transform-literals" "^7.25.2" + "@babel/plugin-transform-logical-assignment-operators" "^7.24.7" + "@babel/plugin-transform-member-expression-literals" "^7.24.7" + "@babel/plugin-transform-modules-amd" "^7.24.7" + "@babel/plugin-transform-modules-commonjs" "^7.24.8" + "@babel/plugin-transform-modules-systemjs" "^7.25.0" + "@babel/plugin-transform-modules-umd" "^7.24.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.24.7" + "@babel/plugin-transform-new-target" "^7.24.7" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.7" + "@babel/plugin-transform-numeric-separator" "^7.24.7" + "@babel/plugin-transform-object-rest-spread" "^7.24.7" + "@babel/plugin-transform-object-super" "^7.24.7" + "@babel/plugin-transform-optional-catch-binding" "^7.24.7" + "@babel/plugin-transform-optional-chaining" "^7.24.8" + "@babel/plugin-transform-parameters" "^7.24.7" + "@babel/plugin-transform-private-methods" "^7.24.7" + "@babel/plugin-transform-private-property-in-object" "^7.24.7" + "@babel/plugin-transform-property-literals" "^7.24.7" + "@babel/plugin-transform-regenerator" "^7.24.7" + "@babel/plugin-transform-reserved-words" "^7.24.7" + "@babel/plugin-transform-shorthand-properties" "^7.24.7" + "@babel/plugin-transform-spread" "^7.24.7" + "@babel/plugin-transform-sticky-regex" "^7.24.7" + "@babel/plugin-transform-template-literals" "^7.24.7" + "@babel/plugin-transform-typeof-symbol" "^7.24.8" + "@babel/plugin-transform-unicode-escapes" "^7.24.7" + "@babel/plugin-transform-unicode-property-regex" "^7.24.7" + "@babel/plugin-transform-unicode-regex" "^7.24.7" + "@babel/plugin-transform-unicode-sets-regex" "^7.24.7" "@babel/preset-modules" "0.1.6-no-external-plugins" babel-plugin-polyfill-corejs2 "^0.4.10" babel-plugin-polyfill-corejs3 "^0.10.4" babel-plugin-polyfill-regenerator "^0.6.1" - core-js-compat "^3.31.0" + core-js-compat "^3.37.1" semver "^6.3.1" "@babel/preset-modules@0.1.6-no-external-plugins": @@ -1236,15 +1008,15 @@ esutils "^2.0.2" "@babel/preset-typescript@^7.12.7": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz#89bdf13a3149a17b3b2a2c9c62547f06db8845ec" - integrity sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz#66cd86ea8f8c014855671d5ea9a737139cbbfef1" + integrity sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-validator-option" "^7.23.5" - "@babel/plugin-syntax-jsx" "^7.24.1" - "@babel/plugin-transform-modules-commonjs" "^7.24.1" - "@babel/plugin-transform-typescript" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + "@babel/plugin-syntax-jsx" "^7.24.7" + "@babel/plugin-transform-modules-commonjs" "^7.24.7" + "@babel/plugin-transform-typescript" "^7.24.7" "@babel/regjsgen@^0.8.0": version "0.8.0" @@ -1252,96 +1024,59 @@ integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== "@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" - integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" + integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.22.15", "@babel/template@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== +"@babel/template@^7.24.7", "@babel/template@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.25.0" + "@babel/types" "^7.25.0" "@babel/template@^7.3.3": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17": - version "7.23.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" - integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.0" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.0" - "@babel/types" "^7.23.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.5.tgz#972aa0bc45f16983bf64aa1f877b2dd0eea7e6f8" - integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== - dependencies: - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/types" "^7.24.5" + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" + integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.3.tgz#f1b901951c83eda2f3e29450ce92743783373490" + integrity sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/parser" "^7.25.3" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.2" debug "^4.3.1" globals "^11.1.0" "@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.3.3": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.17.tgz#f753352c4610ffddf9c8bc6823f9ff03e2303eee" - integrity sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.15" - to-fast-properties "^2.0.0" - -"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.4.4": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" - integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== - dependencies: - "@babel/helper-string-parser" "^7.24.1" - "@babel/helper-validator-identifier" "^7.24.5" - to-fast-properties "^2.0.0" - -"@babel/types@^7.22.17": - version "7.22.19" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" - integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" + integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.19" + "@babel/helper-string-parser" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" -"@babel/types@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.3.tgz#d5ea892c07f2ec371ac704420f4dcdb07b5f9598" - integrity sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw== +"@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.4.4": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125" + integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q== dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -1365,42 +1100,14 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@ericcornelissen/bash-parser@0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@ericcornelissen/bash-parser/-/bash-parser-0.5.2.tgz#5eb3bc52020d97fbaebc63b5168ca0aa0b2e8418" - integrity sha512-4pIMTa1nEFfMXitv7oaNEWOdM+zpOZavesa5GaiWTgda6Zk32CFGxjUp/iIaN0PwgUW1yTq/fztSjbpE8SLGZQ== - dependencies: - array-last "^1.1.1" - babylon "^6.9.1" - compose-function "^3.0.3" - deep-freeze "0.0.1" - filter-iterator "0.0.1" - filter-obj "^1.1.0" - has-own-property "^0.1.0" - identity-function "^1.0.0" - is-iterable "^1.1.0" - iterable-lookahead "^1.0.0" - lodash.curry "^4.1.1" - magic-string "^0.16.0" - map-obj "^2.0.0" - object-pairs "^0.1.0" - object-values "^1.0.0" - reverse-arguments "^1.0.0" - shell-quote-word "^1.0.1" - to-pascal-case "^1.0.0" - unescape-js "^1.0.5" - -"@es-joy/jsdoccomment@~0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.43.0.tgz#35c295cadd0a939d1a3a6cd1548f66ec76d38870" - integrity sha512-Q1CnsQrytI3TlCB1IVWXWeqUIPGVEKGaE7IbVdt13Nq/3i0JESAkQQERrfiQkmlpijl+++qyqPgaS31Bvc1jRQ== - dependencies: - "@types/eslint" "^8.56.5" - "@types/estree" "^1.0.5" - "@typescript-eslint/types" "^7.2.0" +"@es-joy/jsdoccomment@~0.48.0": + version "0.48.0" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz#5d9dc1a295cf5d1ed224dffafb4800d5c7206c27" + integrity sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw== + dependencies: comment-parser "1.4.1" - esquery "^1.5.0" - jsdoc-type-pratt-parser "~4.0.0" + esquery "^1.6.0" + jsdoc-type-pratt-parser "~4.1.0" "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" @@ -1409,15 +1116,10 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.10.0": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== - -"@eslint-community/regexpp@^4.6.1": - version "4.6.2" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" - integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" + integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== "@eslint/eslintrc@^2.1.4": version "2.1.4" @@ -1434,21 +1136,6 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/eslintrc@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.0.2.tgz#36180f8e85bf34d2fe3ccc2261e8e204a411ab4e" - integrity sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^10.0.1" - globals "^14.0.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - "@eslint/js@8.57.0": version "8.57.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" @@ -1469,9 +1156,9 @@ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@isaacs/cliui@^8.0.2": version "8.0.2" @@ -1496,7 +1183,7 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2": +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== @@ -1719,7 +1406,7 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": +"@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -1728,12 +1415,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== @@ -1744,9 +1426,9 @@ integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -1756,15 +1438,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -1772,30 +1446,30 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@matrix-org/matrix-sdk-crypto-wasm@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-5.0.0.tgz#f45a7bccaad218c05bcf9e7c8ca783c9d9a07af4" - integrity sha512-37ASjCKSTU5ycGfkP+LUXG4Ok6OAf6vE+1qU6uwWhe6FwadCS3vVWzJYd/3d9BQFwsx4GhFTIAXrW4iLG85rmQ== +"@matrix-org/matrix-sdk-crypto-wasm@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-7.0.0.tgz#8d6abdb9ded8656cc9e2a7909913a34bf3fc9b3a" + integrity sha512-MOencXiW/gI5MuTtCNsuojjwT5DXCrjMqv9xOslJC9h2tPdLFFFMGr58dY5Lis4DRd9MRWcgrGowUIHOqieWTA== "@matrix-org/olm@3.2.15": version "3.2.15" resolved "https://registry.yarnpkg.com/@matrix-org/olm/-/olm-3.2.15.tgz#55f3c1b70a21bbee3f9195cecd6846b1083451ec" integrity sha512-S7lOrndAK9/8qOtaTq/WhttJC/o4GAzdfK0MUPpo8ApzsJEC0QjtwrkC3KBXdFP1cD1MXi/mlKR7aaoVMKgs6Q== -"@microsoft/tsdoc-config@0.16.2": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf" - integrity sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw== +"@microsoft/tsdoc-config@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.17.0.tgz#82605152b3c1d3f5cd4a11697bc298437484d55d" + integrity sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg== dependencies: - "@microsoft/tsdoc" "0.14.2" - ajv "~6.12.6" + "@microsoft/tsdoc" "0.15.0" + ajv "~8.12.0" jju "~1.4.0" - resolve "~1.19.0" + resolve "~1.22.2" -"@microsoft/tsdoc@0.14.2": - version "0.14.2" - resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb" - integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug== +"@microsoft/tsdoc@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz#f29a55df17cb6e87cfbabce33ff6a14a9f85076d" + integrity sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA== "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" @@ -1817,33 +1491,12 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.scandir@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-3.0.0.tgz#91c0a33e1aeaedcd4bab2bf31be5d1962a55d2a7" - integrity sha512-ktI9+PxfHYtKjF3cLTUAh2N+b8MijCRPNwKJNqTVdL0gB0QxLU2rIRaZ1t71oEa3YBDE6bukH1sR0+CDnpp/Mg== - dependencies: - "@nodelib/fs.stat" "3.0.0" - run-parallel "^1.2.0" - "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.stat@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-3.0.0.tgz#ef6c829f2b05f42595d88854ebd777d4335ff0a9" - integrity sha512-2tQOI38s19P9i7X/Drt0v8iMA+KMsgdhB/dyPER+e+2Y8L1Z7QvnuRdW/uLuf5YRFUYmnj4bMA6qCuZHFI1GDQ== - -"@nodelib/fs.walk@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-2.0.0.tgz#10499ac2210f6399770b465ba728adafc7d44bb1" - integrity sha512-54voNDBobGdMl3BUXSu7UaDh1P85PGHWlJ5e0XhPugo1JulOyCtp2I+5ri4wplGDJ8QGwPEQW7/x3yTLU7yF1A== - dependencies: - "@nodelib/fs.scandir" "3.0.0" - fastq "^1.15.0" - -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@1.2.8", "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -1868,21 +1521,33 @@ tslib "^2.0.0" "@peculiar/webcrypto@^1.4.5": - version "1.4.6" - resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.6.tgz#607af294c4f205efeeb172aa32cb20024fe4aecf" - integrity sha512-YBcMfqNSwn3SujUJvAaySy5tlYbYm6tVt9SKoXu8BaTdKGROiJDgPR3TXpZdAKUfklzm3lRapJEAltiMQtBgZg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz#9e57174c02c1291051c553600347e12b81469e10" + integrity sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg== dependencies: "@peculiar/asn1-schema" "^2.3.8" "@peculiar/json-schema" "^1.1.12" pvtsutils "^1.3.5" tslib "^2.6.2" - webcrypto-core "^1.7.9" + webcrypto-core "^1.8.0" "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + +"@shikijs/core@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@shikijs/core/-/core-1.14.1.tgz#008f1c4a20ff83fd1672d9e31d76b687862f7511" + integrity sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw== + dependencies: + "@types/hast" "^3.0.4" + "@sinclair/typebox@^0.24.1": version "0.24.51" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" @@ -1894,9 +1559,9 @@ integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== "@sinonjs/commons@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" - integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" @@ -1922,9 +1587,9 @@ integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== "@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -1942,9 +1607,9 @@ integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/babel__core@^7.1.14": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" - integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" @@ -1953,24 +1618,24 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.1.tgz#dd6f1d2411ae677dcb2db008c962598be31d6acf" - integrity sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" @@ -1994,48 +1659,35 @@ dependencies: "@types/ms" "*" -"@types/domexception@^4.0.0": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/domexception/-/domexception-4.0.3.tgz#b2ed09e3d3a83c264f5eb7e2a803d319ac441d1f" - integrity sha512-lYPlkldpQqYTgqj5tJgKg5UEa6/vOsaiCc54q6pJ1LPNphJ5UjE4yFjZx/bsvsijzS6Z9OkJYvFiAZZEvYy+Gw== - dependencies: - "@types/webidl-conversions" "*" - -"@types/eslint@^8.56.5": - version "8.56.10" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.10.tgz#eb2370a73bf04a901eeba8f22595c7ee0f7eb58d" - integrity sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== - "@types/events@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.3.tgz#a8ef894305af28d1fc6d2dfdfc98e899591ea529" + integrity sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g== + +"@types/glob-to-regexp@^0.4.4": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz#409e71290253203185b1ea8a3d6ea406a4bdc902" + integrity sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg== "@types/graceful-fs@^4.1.3": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" - integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": +"@types/hast@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" + integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== + dependencies: + "@types/unist" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== -"@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - "@types/istanbul-lib-report@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" @@ -2067,11 +1719,6 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.15": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -2083,23 +1730,23 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*": - version "20.11.16" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.16.tgz#4411f79411514eb8e2926f036c86c9f0e4ec6708" - integrity sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ== + version "20.14.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a" + integrity sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ== dependencies: undici-types "~5.26.4" "@types/node@18": - version "18.19.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.33.tgz#98cd286a1b8a5e11aa06623210240bcc28e95c48" - integrity sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A== + version "18.19.45" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.45.tgz#a9ebfe4c316a356be7ca11f753ecb2feda6d6bdf" + integrity sha512-VZxPKNNhjKmaC1SUYowuXSRSMGyQGmQjvvA1xE4QZ0xce2kLtEhPDS+kqpCPBZYgqblCLQ2DAjSzmgCM5auvhA== dependencies: undici-types "~5.26.4" "@types/normalize-package-data@^2.4.0": - version "2.4.3" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz#291c243e4b94dbfbc0c0ee26b7666f1d5c030e2c" - integrity sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg== + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" + integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== "@types/retry@0.12.0": version "0.12.0" @@ -2111,11 +1758,6 @@ resolved "https://registry.yarnpkg.com/@types/sdp-transform/-/sdp-transform-2.4.9.tgz#26ef39f487a6909b0512f580b80920a366b27f52" integrity sha512-bVr+/OoZZy7wrHlNcEAAa6PAgKA4BoXPYVN2EijMC5WnGgQ4ZEuixmKnVs2roiAvr7RhIFVH17QD27cojgIZCg== -"@types/semver@^7.5.8": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== - "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -2126,15 +1768,15 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== -"@types/uuid@9": - version "9.0.8" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" - integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== +"@types/unist@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" + integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== -"@types/webidl-conversions@*": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz#1306dbfa53768bcbcfc95a1c8cde367975581859" - integrity sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA== +"@types/uuid@10": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-10.0.0.tgz#e9c07fe50da0f53dc24970cca94d619ff03f6f6d" + integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== "@types/yargs-parser@*": version "21.0.3" @@ -2149,76 +1791,74 @@ "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^7.0.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz#c78e309fe967cb4de05b85cdc876fb95f8e01b6f" - integrity sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg== + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3" + integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.8.0" - "@typescript-eslint/type-utils" "7.8.0" - "@typescript-eslint/utils" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" - debug "^4.3.4" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/type-utils" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" - semver "^7.6.0" ts-api-utils "^1.3.0" "@typescript-eslint/parser@^7.0.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.8.0.tgz#1e1db30c8ab832caffee5f37e677dbcb9357ddc8" - integrity sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ== - dependencies: - "@typescript-eslint/scope-manager" "7.8.0" - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/typescript-estree" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.18.0.tgz#83928d0f1b7f4afa974098c64b5ce6f9051f96a0" + integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== + dependencies: + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz#bb19096d11ec6b87fb6640d921df19b813e02047" - integrity sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g== +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== dependencies: - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" -"@typescript-eslint/scope-manager@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz#1dd3e63a4411db356a9d040e75864851b5f2619b" - integrity sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ== +"@typescript-eslint/scope-manager@8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz#4a4bd7e7df5522acc8795c3b6f21e8c41b951138" + integrity sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw== dependencies: - "@typescript-eslint/types" "7.9.0" - "@typescript-eslint/visitor-keys" "7.9.0" + "@typescript-eslint/types" "8.2.0" + "@typescript-eslint/visitor-keys" "8.2.0" -"@typescript-eslint/type-utils@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz#9de166f182a6e4d1c5da76e94880e91831e3e26f" - integrity sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A== +"@typescript-eslint/type-utils@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b" + integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== dependencies: - "@typescript-eslint/typescript-estree" "7.8.0" - "@typescript-eslint/utils" "7.8.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils" "7.18.0" debug "^4.3.4" ts-api-utils "^1.3.0" -"@typescript-eslint/types@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.8.0.tgz#1fd2577b3ad883b769546e2d1ef379f929a7091d" - integrity sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw== +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== -"@typescript-eslint/types@7.9.0", "@typescript-eslint/types@^7.2.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.9.0.tgz#b58e485e4bfba055659c7e683ad4f5f0821ae2ec" - integrity sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w== +"@typescript-eslint/types@8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.2.0.tgz#dfe9895a2812f7c6bf7af863054c22a67060420c" + integrity sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ== -"@typescript-eslint/typescript-estree@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz#b028a9226860b66e623c1ee55cc2464b95d2987c" - integrity sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg== +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== dependencies: - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -2226,13 +1866,13 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/typescript-estree@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz#3395e27656060dc313a6b406c3a298b729685e07" - integrity sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg== +"@typescript-eslint/typescript-estree@8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz#fbdb93a1c7ac7f1f96ae2de4fc97cd64c60ae894" + integrity sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA== dependencies: - "@typescript-eslint/types" "7.9.0" - "@typescript-eslint/visitor-keys" "7.9.0" + "@typescript-eslint/types" "8.2.0" + "@typescript-eslint/visitor-keys" "8.2.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -2240,43 +1880,40 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.8.0.tgz#57a79f9c0c0740ead2f622e444cfaeeb9fd047cd" - integrity sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ== +"@typescript-eslint/utils@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.15" - "@types/semver" "^7.5.8" - "@typescript-eslint/scope-manager" "7.8.0" - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/typescript-estree" "7.8.0" - semver "^7.6.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" -"@typescript-eslint/utils@^6.0.0 || ^7.0.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.9.0.tgz#1b96a34eefdca1c820cb1bbc2751d848b4540899" - integrity sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA== +"@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.2.0.tgz#02d442285925f28d520587185f295f932702e733" + integrity sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "7.9.0" - "@typescript-eslint/types" "7.9.0" - "@typescript-eslint/typescript-estree" "7.9.0" + "@typescript-eslint/scope-manager" "8.2.0" + "@typescript-eslint/types" "8.2.0" + "@typescript-eslint/typescript-estree" "8.2.0" -"@typescript-eslint/visitor-keys@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz#7285aab991da8bee411a42edbd5db760d22fdd91" - integrity sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA== +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== dependencies: - "@typescript-eslint/types" "7.8.0" + "@typescript-eslint/types" "7.18.0" eslint-visitor-keys "^3.4.3" -"@typescript-eslint/visitor-keys@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz#82162656e339c3def02895f5c8546f6888d9b9ea" - integrity sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ== +"@typescript-eslint/visitor-keys@8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz#f6abb3b6508898a117175ddc11f9b9869cc96834" + integrity sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q== dependencies: - "@typescript-eslint/types" "7.9.0" + "@typescript-eslint/types" "8.2.0" eslint-visitor-keys "^3.4.3" "@ungap/structured-clone@^1.2.0": @@ -2302,30 +1939,17 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^8.0.2: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn-walk@^8.1.1: - version "8.3.1" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.1.tgz#2f10f5b69329d90ae18c58bf1fa8fccd8b959a43" - integrity sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw== - -acorn@^8.1.0, acorn@^8.8.1, acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - -acorn@^8.11.3: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn-walk@^8.0.2, acorn-walk@^8.1.1: + version "8.3.3" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" + integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== + dependencies: + acorn "^8.11.0" -acorn@^8.4.1: - version "8.11.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" - integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== +acorn@^8.1.0, acorn@^8.11.0, acorn@^8.12.0, acorn@^8.4.1, acorn@^8.8.1, acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== agent-base@6: version "6.0.2" @@ -2342,7 +1966,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.12.4, ajv@~6.12.6: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2352,6 +1976,16 @@ ajv@^6.12.4, ajv@~6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@~8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + another-json@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/another-json/-/another-json-0.2.0.tgz#b5f4019c973b6dd5c6506a2d93469cb6d32aeedc" @@ -2364,12 +1998,12 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" -ansi-escapes@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-6.2.0.tgz#8a13ce75286f417f1963487d86ba9f90dccf9947" - integrity sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw== +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== dependencies: - type-fest "^3.0.0" + environment "^1.0.0" ansi-regex@^5.0.1: version "5.0.1" @@ -2381,11 +2015,6 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-sequence-parser@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz#e0aa1cdcbc8f8bb0b5bca625aac41f5f056973cf" - integrity sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -2440,52 +2069,42 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -arity-n@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745" - integrity sha512-fExL2kFDC1Q2DUOx3whE/9KoN66IzkY4b4zUHUBFM1ojEYjZZYDcUW3bek/ufGionX9giIKDC5redH2IlGqcQQ== - -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" + call-bind "^1.0.5" + is-array-buffer "^3.0.4" array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" -array-last@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336" - integrity sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg== - dependencies: - is-number "^4.0.0" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== array.prototype.findlastindex@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" - integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" array.prototype.flat@^1.3.2: version "1.3.2" @@ -2507,17 +2126,18 @@ array.prototype.flatmap@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -arraybuffer.prototype.slice@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" - integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" asn1js@^3.0.1, asn1js@^3.0.5: @@ -2534,10 +2154,12 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" babel-jest@^29.0.0, babel-jest@^29.7.0: version "29.7.0" @@ -2582,7 +2204,7 @@ babel-plugin-polyfill-corejs2@^0.4.10: "@babel/helper-define-polyfill-provider" "^0.6.2" semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.10.1, babel-plugin-polyfill-corejs3@^0.10.4: +babel-plugin-polyfill-corejs3@^0.10.1: version "0.10.4" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz#789ac82405ad664c20476d0233b485281deb9c77" integrity sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg== @@ -2590,6 +2212,14 @@ babel-plugin-polyfill-corejs3@^0.10.1, babel-plugin-polyfill-corejs3@^0.10.4: "@babel/helper-define-polyfill-provider" "^0.6.1" core-js-compat "^3.36.1" +babel-plugin-polyfill-corejs3@^0.10.4: + version "0.10.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" + integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.2" + core-js-compat "^3.38.0" + babel-plugin-polyfill-regenerator@^0.6.1: version "0.6.2" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" @@ -2623,27 +2253,22 @@ babel-preset-jest@^29.6.3: babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" -babylon@^6.9.1: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base-x@^3.0.6: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + version "3.0.10" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.10.tgz#62de58653f8762b5d6f8d9fe30fa75f7b2585a75" + integrity sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ== dependencies: safe-buffer "^5.0.1" -base-x@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" - integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== +base-x@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.0.tgz#6d835ceae379130e1a4cb846a70ac4746f28ea9b" + integrity sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ== binary-extensions@^2.0.0: version "2.3.0" @@ -2665,39 +2290,29 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -browserslist@^4.21.9: - version "4.22.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" - integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - caniuse-lite "^1.0.30001565" - electron-to-chromium "^1.4.601" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + fill-range "^7.1.1" -browserslist@^4.22.2, browserslist@^4.23.0: - version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.23.0, browserslist@^4.23.1, browserslist@^4.23.3: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" -bs58@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279" - integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== +bs58@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-6.0.0.tgz#a2cda0130558535dd281a2f8697df79caaf425d8" + integrity sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw== dependencies: - base-x "^4.0.0" + base-x "^5.0.0" bser@2.1.1: version "2.1.1" @@ -2716,14 +2331,16 @@ builtin-modules@^3.3.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" - integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" function-bind "^1.1.2" - get-intrinsic "^1.2.1" - set-function-length "^1.1.1" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" callsites@^3.0.0: version "3.1.0" @@ -2740,26 +2357,16 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001565: - version "1.0.30001583" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001583.tgz#abb2970cc370801dc7e27bf290509dc132cfa390" - integrity sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q== - -caniuse-lite@^1.0.30001587: - version "1.0.30001614" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz#f894b4209376a0bf923d67d9c361d96b1dfebe39" - integrity sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog== +caniuse-lite@^1.0.30001646: + version "1.0.30001651" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" + integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== chalk@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== -chalk@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2777,6 +2384,11 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -2808,9 +2420,9 @@ ci-info@^4.0.0: integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== cjs-module-lexer@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" - integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + version "1.3.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== clean-regexp@^1.0.0: version "1.0.0" @@ -2824,12 +2436,12 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-cursor@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" - integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== dependencies: - restore-cursor "^4.0.0" + restore-cursor "^5.0.0" cli-truncate@^4.0.0: version "4.0.0" @@ -2899,28 +2511,26 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" - integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== - -commander@^4.0.1, commander@^4.1.1: +commander@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== +commander@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + +commander@~12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + comment-parser@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg== -compose-function@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" - integrity sha512-xzhzTJ5eC+gmIzvZq+C3kCJHsp9os6tJkrigDRZclyGtOKINbZtE8n1Tzmeh32jW+BUDPbvZpibwvJHBLGMVwg== - dependencies: - arity-n "^1.0.4" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -2931,22 +2541,17 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -core-js-compat@^3.31.0, core-js-compat@^3.36.1: - version "3.37.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.0.tgz#d9570e544163779bb4dff1031c7972f44918dc73" - integrity sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA== +core-js-compat@^3.36.1, core-js-compat@^3.37.1, core-js-compat@^3.38.0: + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.1.tgz#2bc7a298746ca5a7bcb9c164bcb120f2ebc09a09" + integrity sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw== dependencies: - browserslist "^4.23.0" + browserslist "^4.23.3" core-js-compat@^3.37.0: version "3.37.1" @@ -2956,9 +2561,9 @@ core-js-compat@^3.37.0: browserslist "^4.23.0" core-js@^3.0.0: - version "3.32.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.0.tgz#7643d353d899747ab1f8b03d2803b0312a0fb3b6" - integrity sha512-rd4rYZNlF3WuoYuRIDEmbR/ga9CeuWX9U05umAvgrrZoHY4Z++cp/xwPQMvUpBB4Ag6J8KfD80G0zwCyaSxDww== + version "3.37.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.1.tgz#d21751ddb756518ac5a00e4d66499df981a62db9" + integrity sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw== create-jest@^29.7.0: version "29.7.0" @@ -3013,10 +2618,37 @@ data-urls@^3.0.2: whatwg-mimetype "^3.0.0" whatwg-url "^11.0.0" -debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@~4.3.6: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== dependencies: ms "2.1.2" @@ -3033,14 +2665,9 @@ decimal.js@^10.4.2: integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== - -deep-freeze@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" - integrity sha512-Z+z8HiAvsGwmjqlphnHW5oz6yWlOwu6EQfFTjmeTWlDeda3FS2yv3jhq35TX/ewmsnqB+RX2IdsIOyjJCQN5tg== + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-is@^0.1.3: version "0.1.4" @@ -3059,16 +2686,16 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-data-property@^1.0.1, define-data-property@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" - integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: - get-intrinsic "^1.2.1" + es-define-property "^1.0.0" + es-errors "^1.3.0" gopd "^1.0.1" - has-property-descriptors "^1.0.0" -define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: +define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -3082,6 +2709,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -3144,15 +2776,10 @@ easy-table@1.2.0: optionalDependencies: wcwidth "^1.0.1" -electron-to-chromium@^1.4.601: - version "1.4.655" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.655.tgz#112410db0d7f9c2b4ed8baa3b1b548522a6f89d4" - integrity sha512-2yszojF7vIZ68adIOvzV4bku8OZad9w5H9xF3ZAMZjPuOjBarlflUkjN6DggdV+L71WZuKUfKUhov/34+G5QHg== - -electron-to-chromium@^1.4.668: - version "1.4.751" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz#b5b19742a435c589de02f60c16618150498bbd59" - integrity sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw== +electron-to-chromium@^1.5.4: + version "1.5.13" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6" + integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q== emittery@^0.13.1: version "0.13.1" @@ -3175,9 +2802,17 @@ emoji-regex@^9.2.2: integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== enhanced-resolve@^5.12.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + version "5.17.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz#d037603789dd9555b89aaec7eb78845c49089bc5" + integrity sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enhanced-resolve@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -3187,6 +2822,11 @@ entities@^4.4.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3194,61 +2834,92 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== - dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" - is-typed-array "^1.1.12" + is-typed-array "^1.1.13" is-weakref "^1.0.2" object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" + which-typed-array "^1.1.15" -es-set-tostringtag@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.5.3: + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" -es-shim-unscopables@^1.0.0: +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== @@ -3264,7 +2935,7 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -escalade@^3.1.1: +escalade@^3.1.1, escalade@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== @@ -3328,9 +2999,9 @@ eslint-import-resolver-typescript@^3.5.1: is-glob "^4.0.3" eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + version "2.8.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" + integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== dependencies: debug "^3.2.7" @@ -3358,52 +3029,54 @@ eslint-plugin-import@^2.26.0: tsconfig-paths "^3.15.0" eslint-plugin-jest@^28.0.0: - version "28.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.5.0.tgz#b497b795de37f671eaccd38bd83030186ff5dc8d" - integrity sha512-6np6DGdmNq/eBbA7HOUNV8fkfL86PYwBfwyb8n23FXgJNTR8+ot3smRHjza9LGsBBZRypK3qyF79vMjohIL8eQ== + version "28.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz#54f597b5a3295ad04ec946baa245ad02b9b2bca0" + integrity sha512-Tubj1hooFxCl52G4qQu0edzV/+EZzPUeN8p2NnW5uu4fbDs+Yo7+qDVDc4/oG3FbCqEBmu/OC3LSsyiU22oghw== dependencies: - "@typescript-eslint/utils" "^6.0.0 || ^7.0.0" + "@typescript-eslint/utils" "^6.0.0 || ^7.0.0 || ^8.0.0" -eslint-plugin-jsdoc@^48.0.0: - version "48.2.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.4.tgz#0b6972faa9e5de89a08f1b0bcdc30e70a9cad736" - integrity sha512-3ebvVgCJFy06gpmuS2ynz13uh9iFSzZ1C1dDkgcSAqVVg82zlORKMk2fvjq708pAO6bwfs5YLttknFEbaoDiGw== +eslint-plugin-jsdoc@^50.0.0: + version "50.2.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.2.2.tgz#151e63c8bc245ea8b2357d4229392a5b993827b0" + integrity sha512-i0ZMWA199DG7sjxlzXn5AeYZxpRfMJjDPUl7lL9eJJX8TPRoIaxJU4ys/joP5faM5AXE1eqW/dslCj3uj4Nqpg== dependencies: - "@es-joy/jsdoccomment" "~0.43.0" + "@es-joy/jsdoccomment" "~0.48.0" are-docs-informative "^0.0.2" comment-parser "1.4.1" - debug "^4.3.4" + debug "^4.3.6" escape-string-regexp "^4.0.0" - esquery "^1.5.0" - is-builtin-module "^3.2.1" - semver "^7.6.0" + espree "^10.1.0" + esquery "^1.6.0" + parse-imports "^2.1.1" + semver "^7.6.3" spdx-expression-parse "^4.0.0" + synckit "^0.9.1" eslint-plugin-matrix-org@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-1.2.1.tgz#76d1505daa93fb99ba4156008b9b32f57682c9b1" integrity sha512-A3cDjhG7RHwfCS8o3bOip8hSCsxtmgk2ahvqE5v/Ic2kPEZxixY6w8zLj7hFGsrRmPSEpLWqkVLt8uvQBapiQA== -eslint-plugin-tsdoc@^0.2.17: - version "0.2.17" - resolved "https://registry.yarnpkg.com/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz#27789495bbd8778abbf92db1707fec2ed3dfe281" - integrity sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA== +eslint-plugin-tsdoc@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.3.0.tgz#e4498070355cac2b9f38ea497ba83016bb7eda62" + integrity sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A== dependencies: - "@microsoft/tsdoc" "0.14.2" - "@microsoft/tsdoc-config" "0.16.2" + "@microsoft/tsdoc" "0.15.0" + "@microsoft/tsdoc-config" "0.17.0" -eslint-plugin-unicorn@^53.0.0: - version "53.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz#df3a5c9ecabeb759e6fd867b2d84198466ac8c4d" - integrity sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw== +eslint-plugin-unicorn@^55.0.0: + version "55.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz#e2aeb397914799895702480970e7d148df5bcc7b" + integrity sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA== dependencies: "@babel/helper-validator-identifier" "^7.24.5" "@eslint-community/eslint-utils" "^4.4.0" - "@eslint/eslintrc" "^3.0.2" ci-info "^4.0.0" clean-regexp "^1.0.0" core-js-compat "^3.37.0" esquery "^1.5.0" + globals "^15.7.0" indent-string "^4.0.0" is-builtin-module "^3.2.1" jsesc "^3.0.2" @@ -3494,12 +3167,12 @@ eslint@8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -espree@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-10.0.1.tgz#600e60404157412751ba4a6f3a2ee1a42433139f" - integrity sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww== +espree@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56" + integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA== dependencies: - acorn "^8.11.3" + acorn "^8.12.0" acorn-jsx "^5.3.2" eslint-visitor-keys "^4.0.0" @@ -3517,10 +3190,10 @@ esprima@^4.0.0, esprima@^4.0.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2, esquery@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esquery@^1.4.2, esquery@^1.5.0, esquery@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -3556,21 +3229,6 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -execa@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" - integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^8.0.1" - human-signals "^5.0.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^4.1.0" - strip-final-newline "^3.0.0" - execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -3586,6 +3244,21 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execa@~8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -3623,7 +3296,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@3.3.2, fast-glob@^3.2.9: +fast-glob@^3.2.9, fast-glob@^3.3.1, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -3634,17 +3307,6 @@ fast-glob@3.3.2, fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -3655,7 +3317,7 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fastq@^1.15.0, fastq@^1.6.0: +fastq@^1.6.0: version "1.17.1" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== @@ -3676,7 +3338,18 @@ fetch-mock-jest@^1.5.1: dependencies: fetch-mock "^9.11.0" -fetch-mock@9.11.0, fetch-mock@^9.11.0: +fetch-mock@11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-11.1.1.tgz#33440be6d184f52f1d8bc48a15b9e631589fd5e2" + integrity sha512-2lZ42bnMar9MBfNR0nza5wM4ZDwLxb+ZbNR4sEvpqOOBzZ+V6cZVVhLBHj8+AAEInF4vp2/tbRM8WlGX5mPhiA== + dependencies: + "@types/glob-to-regexp" "^0.4.4" + dequal "^2.0.3" + glob-to-regexp "^0.4.1" + is-subset "^0.1.1" + regexparam "^3.0.0" + +fetch-mock@^9.11.0: version "9.11.0" resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-9.11.0.tgz#371c6fb7d45584d2ae4a18ee6824e7ad4b637a3f" integrity sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q== @@ -3692,13 +3365,6 @@ fetch-mock@9.11.0, fetch-mock@^9.11.0: querystring "^0.2.0" whatwg-url "^6.5.0" -file-entry-cache@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" - integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== - dependencies: - flat-cache "^4.0.0" - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -3706,23 +3372,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -filter-iterator@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/filter-iterator/-/filter-iterator-0.0.1.tgz#0a2ecf07d6c06f96bdeb6846f8e88b57b8da1f37" - integrity sha512-v4lhL7Qa8XpbW3LN46CEnmhGk3eHZwxfNl5at20aEkreesht4YKb/Ba3BUIbnPhAC/r3dmu7ABaGk6MAvh2alA== - -filter-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" - integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== - find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -3740,25 +3396,13 @@ find-up@^5.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flat-cache@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" - integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" - keyv "^4.5.4" - -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + keyv "^4.5.3" + rimraf "^3.0.2" flatted@^3.2.9: version "3.3.1" @@ -3773,9 +3417,9 @@ for-each@^0.3.3: is-callable "^1.1.3" foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + version "3.2.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" + integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -3839,11 +3483,12 @@ get-east-asian-width@^1.0.0: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e" integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" - integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: + es-errors "^1.3.0" function-bind "^1.1.2" has-proto "^1.0.1" has-symbols "^1.0.3" @@ -3864,18 +3509,19 @@ get-stream@^8.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" get-tsconfig@^4.5.0: - version "4.7.2" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" - integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + version "4.7.5" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.5.tgz#5e012498579e9a6947511ed0cd403272c7acbbaf" + integrity sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw== dependencies: resolve-pkg-maps "^1.0.0" @@ -3893,21 +3539,22 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob-to-regexp@^0.4.0: +glob-to-regexp@^0.4.0, glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^10.3.7: - version "10.3.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.15.tgz#e72bc61bc3038c90605f5dd48543dc67aaf3b50d" - integrity sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw== +glob@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e" + integrity sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.6" - minimatch "^9.0.1" - minipass "^7.0.4" - path-scurry "^1.11.0" + jackspeak "^4.0.1" + minimatch "^10.0.0" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: version "7.2.3" @@ -3927,23 +3574,24 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" -globals@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" - integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== +globals@^15.7.0: + version "15.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.9.0.tgz#e9de01771091ffbc37db5714dab484f9f69ff399" + integrity sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA== globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - define-properties "^1.1.3" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^11.1.0: version "11.1.0" @@ -3989,41 +3637,31 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-own-property@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-own-property/-/has-own-property-0.1.0.tgz#992b0f5bb3a25416f8d4d0cde53f497b9d7b1ea5" - integrity sha512-14qdBKoonU99XDhWcFKZTShK+QV47qU97u8zzoVo9cL5TZ3BmBHXogItSt9qJjR0KUMFRhcCW8uGIGl8nkl7Aw== - -has-property-descriptors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" - integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - get-intrinsic "^1.2.2" + es-define-property "^1.0.0" -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - has-symbols "^1.0.2" - -has@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" - integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== + has-symbols "^1.0.3" -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -4075,9 +3713,9 @@ human-signals@^5.0.0: integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== husky@^9.0.0: - version "9.0.11" - resolved "https://registry.yarnpkg.com/husky/-/husky-9.0.11.tgz#fc91df4c756050de41b3e478b2158b87c1e79af9" - integrity sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw== + version "9.1.5" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.5.tgz#2b6edede53ee1adbbd3a3da490628a23f5243b83" + integrity sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag== iconv-lite@0.6.3: version "0.6.3" @@ -4086,15 +3724,10 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -identity-function@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/identity-function/-/identity-function-1.0.0.tgz#bea1159f0985239be3ca348edf40ce2f0dd2c21d" - integrity sha512-kNrgUK0qI+9qLTBidsH85HjDLpZfrrS0ElquKKe/fJFdB3D7VeKdXXEvOPDUHSHOzdZKCAAaQIWWyp0l2yq6pw== - ignore@^5.1.8, ignore@^5.2.0, ignore@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== import-fresh@^3.2.1: version "3.3.0" @@ -4135,23 +3768,22 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" - integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: - get-intrinsic "^1.2.2" + es-errors "^1.3.0" hasown "^2.0.0" side-channel "^1.0.4" -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" + get-intrinsic "^1.2.1" is-arrayish@^0.2.1: version "0.2.1" @@ -4192,19 +3824,26 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.1.0, is-core-module@^2.11.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== +is-core-module@^2.11.0, is-core-module@^2.13.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" + integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== dependencies: - has "^1.0.3" + hasown "^2.0.2" -is-core-module@^2.13.0, is-core-module@^2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== +is-core-module@^2.13.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" is-date-object@^1.0.1: version "1.0.5" @@ -4247,15 +3886,10 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-iterable@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-iterable/-/is-iterable-1.1.1.tgz#71f9aa6f113e1d968ebe1d41cff4c8fb23a817bc" - integrity sha512-EdOZCr0NsGE00Pot+x1ZFx9MJK3C6wy91geZpXwvwexDLJvA4nzYyZf7r+EIwSeVsOLDdBz7ATg9NqKTzuNYuQ== - -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: version "1.0.7" @@ -4264,11 +3898,6 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -4292,12 +3921,12 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" @@ -4328,12 +3957,12 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - which-typed-array "^1.1.11" + which-typed-array "^1.1.14" is-weakref@^1.0.2: version "1.0.2" @@ -4353,9 +3982,9 @@ isexe@^2.0.0: integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-instrument@^5.0.4: version "5.2.1" @@ -4369,13 +3998,13 @@ istanbul-lib-instrument@^5.0.4: semver "^6.3.0" istanbul-lib-instrument@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz#7a8af094cbfff1d5bb280f62ce043695ae8dd5b8" - integrity sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw== + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" istanbul-lib-coverage "^3.2.0" semver "^7.5.4" @@ -4398,22 +4027,17 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.6" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" - integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterable-lookahead@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/iterable-lookahead/-/iterable-lookahead-1.0.0.tgz#896dfcb78680bdb50036e97edb034c8b68a9737f" - integrity sha512-hJnEP2Xk4+44DDwJqUQGdXal5VbyeWLaPyDl2AQc242Zr7iqz4DgpQOrEzglWVMGHMDCkguLHEKxd1+rOsmgSQ== - -jackspeak@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" - integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== +jackspeak@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.1.tgz#9fca4ce961af6083e259c376e9e3541431f5287b" + integrity sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -4848,10 +4472,10 @@ jest@^29.0.0: import-local "^3.0.2" jest-cli "^29.7.0" -jiti@1.21.0: - version "1.21.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" - integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== +jiti@^1.21.6: + version "1.21.6" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" + integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== jju@~1.4.0: version "1.4.0" @@ -4863,13 +4487,6 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" @@ -4878,10 +4495,17 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -jsdoc-type-pratt-parser@~4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" - integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdoc-type-pratt-parser@~4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113" + integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg== jsdom@^20.0.0: version "20.0.3" @@ -4945,6 +4569,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -4962,17 +4591,12 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" - integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== - jwt-decode@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-4.0.0.tgz#2270352425fd413785b2faf11f6e755c5151bd4b" integrity sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA== -keyv@^4.5.4: +keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== @@ -4985,24 +4609,22 @@ kleur@^3.0.3: integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== knip@^5.0.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/knip/-/knip-5.16.0.tgz#aa6c4de4f38f1735a984fca6f868826f254f3464" - integrity sha512-kdHfTRZuOqsMnvYYNT+pwefyBUNUYTqgyeGM8k4hfw++GZ3TMRGSPZoSl8IxQTy56AkxEDWyj1/P/mYv1vu/Gw== + version "5.27.2" + resolved "https://registry.yarnpkg.com/knip/-/knip-5.27.2.tgz#8a5a569a5baac0ab2e06dbd5454f07608ccb1952" + integrity sha512-Mya1XEDq1oygibQf0uocQd02Fil8RtvNVhcFAcxypjcc6zakT7wsJtS0xvuwEitilfI0tiFC9PghmJQ3DMKuTg== dependencies: - "@ericcornelissen/bash-parser" "0.5.2" - "@nodelib/fs.walk" "2.0.0" + "@nodelib/fs.walk" "1.2.8" "@snyk/github-codeowners" "1.1.0" easy-table "1.2.0" - fast-glob "3.3.2" - file-entry-cache "8.0.0" - jiti "1.21.0" - js-yaml "4.1.0" - minimist "1.2.8" - picocolors "1.0.0" + enhanced-resolve "^5.17.1" + fast-glob "^3.3.2" + jiti "^1.21.6" + js-yaml "^4.1.0" + minimist "^1.2.8" + picocolors "^1.0.0" picomatch "^4.0.1" - pretty-ms "9.0.0" - resolve "1.22.8" - smol-toml "1.1.4" + pretty-ms "^9.0.0" + smol-toml "^1.1.4" strip-json-comments "5.0.1" summary "2.1.0" zod "^3.22.4" @@ -5021,42 +4643,49 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lilconfig@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc" - integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g== +lilconfig@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" + integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== + dependencies: + uc.micro "^2.0.0" + lint-staged@^15.0.2: - version "15.2.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.2.tgz#ad7cbb5b3ab70e043fa05bff82a09ed286bc4c5f" - integrity sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw== - dependencies: - chalk "5.3.0" - commander "11.1.0" - debug "4.3.4" - execa "8.0.1" - lilconfig "3.0.0" - listr2 "8.0.1" - micromatch "4.0.5" - pidtree "0.6.0" - string-argv "0.3.2" - yaml "2.3.4" - -listr2@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.0.1.tgz#4d3f50ae6cec3c62bdf0e94f5c2c9edebd4b9c34" - integrity sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA== + version "15.2.9" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.9.tgz#bf70d40b6b192df6ad756fb89822211615e0f4da" + integrity sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ== + dependencies: + chalk "~5.3.0" + commander "~12.1.0" + debug "~4.3.6" + execa "~8.0.1" + lilconfig "~3.1.2" + listr2 "~8.2.4" + micromatch "~4.0.7" + pidtree "~0.6.0" + string-argv "~0.3.2" + yaml "~2.5.0" + +listr2@~8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.4.tgz#486b51cbdb41889108cb7e2c90eeb44519f5a77f" + integrity sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g== dependencies: cli-truncate "^4.0.0" colorette "^2.0.20" eventemitter3 "^5.0.1" - log-update "^6.0.0" - rfdc "^1.3.0" + log-update "^6.1.0" + rfdc "^1.4.1" wrap-ansi "^9.0.0" locate-path@^5.0.0: @@ -5073,11 +4702,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash.curry@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" - integrity sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA== - lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -5098,14 +4722,14 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== -log-update@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.0.0.tgz#0ddeb7ac6ad658c944c1de902993fce7c33f5e59" - integrity sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw== +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== dependencies: - ansi-escapes "^6.2.0" - cli-cursor "^4.0.0" - slice-ansi "^7.0.0" + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" strip-ansi "^7.1.0" wrap-ansi "^9.0.0" @@ -5114,10 +4738,10 @@ loglevel@^1.7.1: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.1.tgz#d63976ac9bcd03c7c873116d41c2a85bafff1be7" integrity sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg== -lru-cache@^10.2.0: - version "10.2.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" - integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== +lru-cache@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.0.tgz#15d93a196f189034d7166caf9fe55e7384c98a21" + integrity sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA== lru-cache@^5.1.1: version "5.1.1" @@ -5126,25 +4750,11 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - lunr@^2.3.9: version "2.3.9" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== -magic-string@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.16.0.tgz#970ebb0da7193301285fb1aa650f39bdd81eb45a" - integrity sha512-c4BEos3y6G2qO0B9X7K0FVLOPT9uGrjYwYRLFmDqyl5YMboUviyecnXWp94fJTSMwPw2/sf+CEYt5AGpmklkkQ== - dependencies: - vlq "^0.2.1" - make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -5172,15 +4782,17 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha512-TzQSV2DiMYgoF5RycneKVUzIa9bQsj/B3tTgsE3dOGqlzHnGIDaC7XBE7grnA+8kZPnfqSGFe95VHc2oc0VFUQ== - -marked@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" - integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== +markdown-it@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.0" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" matrix-events-sdk@0.0.1: version "0.0.1" @@ -5194,14 +4806,19 @@ matrix-mock-request@^2.5.0: dependencies: expect "^28.1.0" -matrix-widget-api@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.6.0.tgz#f0075411edffc6de339580ade7e6e6e6edb01af4" - integrity sha512-VXIJyAZ/WnBmT4C7ePqevgMYGneKMCP/0JuCOqntSsaNlCRHJvwvTxmqUU+ufOpzIF5gYNyIrAjbgrEbK3iqJQ== +matrix-widget-api@^1.8.2: + version "1.9.0" + resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.9.0.tgz#884136b405bd3c56e4ea285095c9e01ec52b6b1f" + integrity sha512-au8mqralNDqrEvaVAkU37bXOb8I9SCe+ACdPk11QWw58FKstVq31q2wRz+qWA6J+42KJ6s1DggWbG/S3fEs3jw== dependencies: "@types/events" "^3.0.0" events "^3.2.0" +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -5212,12 +4829,12 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@4.0.5, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.4, micromatch@~4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -5242,11 +4859,23 @@ mimic-fn@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== + min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +minimatch@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -5254,22 +4883,22 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.1, minimatch@^9.0.3, minimatch@^9.0.4: - version "9.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" - integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== +minimatch@^9.0.4, minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" -minimist@1.2.8, minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4: - version "7.1.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.1.tgz#f7f85aff59aa22f110b20e27692465cf3bf89481" - integrity sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA== +minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== mkdirp@1.0.4: version "1.0.4" @@ -5303,10 +4932,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== normalize-package-data@^2.5.0: version "2.5.0" @@ -5331,38 +4960,28 @@ npm-run-path@^4.0.1: path-key "^3.0.0" npm-run-path@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" - integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: path-key "^4.0.0" nwsapi@^2.2.2: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + version "2.2.10" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.10.tgz#0b77a68e21a0b483db70b11fad055906e867cda8" + integrity sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ== -object-inspect@^1.13.1, object-inspect@^1.9.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-pairs@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-pairs/-/object-pairs-0.1.0.tgz#8276eed81d60b8549d69c5f73a682ab9da4ff32f" - integrity sha512-3ECr6K831I4xX/Mduxr9UC+HPOz/d6WKKYj9p4cmC8Lg8p7g8gitzsxNX5IWlSIgFWN/a4JgrJaoAMKn20oKwA== - -object-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/object-values/-/object-values-1.0.0.tgz#72af839630119e5b98c3b02bb8c27e3237158105" - integrity sha512-+8hwcz/JnQ9EpLIXzN0Rs7DLsBpJNT/xYehtB/jU93tHYr5BFEO8E+JGQNOSqE7opVzz5cGksKFHt7uUJVLSjQ== - -object.assign@^4.1.4: +object.assign@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== @@ -5373,32 +4992,32 @@ object.assign@^4.1.4: object-keys "^1.1.1" object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" object.groupby@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" - integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" oidc-client-ts@^3.0.1: version "3.0.1" @@ -5414,7 +5033,7 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -5428,17 +5047,24 @@ onetime@^6.0.0: dependencies: mimic-fn "^4.0.0" +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== + dependencies: + mimic-function "^5.0.0" + optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" + word-wrap "^1.2.5" p-limit@^2.2.0: version "2.3.0" @@ -5488,6 +5114,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -5495,6 +5126,14 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-imports@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/parse-imports/-/parse-imports-2.1.1.tgz#ce52141df24990065d72a446a364bffd595577f4" + integrity sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA== + dependencies: + es-module-lexer "^1.5.3" + slashes "^3.0.12" + parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -5537,18 +5176,18 @@ path-key@^4.0.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.11.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + lru-cache "^11.0.0" + minipass "^7.1.2" path-to-regexp@^2.2.1: version "2.4.0" @@ -5560,10 +5199,10 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -picocolors@1.0.0, picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -5575,7 +5214,7 @@ picomatch@^4.0.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -pidtree@0.6.0: +pidtree@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== @@ -5602,15 +5241,20 @@ pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" - integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== +prettier@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== pretty-format@^28.1.3: version "28.1.3" @@ -5631,10 +5275,10 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -pretty-ms@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-9.0.0.tgz#53c57f81171c53be7ce3fd20bdd4265422bc5929" - integrity sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng== +pretty-ms@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-9.1.0.tgz#0ad44de6086454f48a168e5abb3c26f8db1b3253" + integrity sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw== dependencies: parse-ms "^4.0.0" @@ -5651,15 +5295,20 @@ psl@^1.1.33: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + punycode@^2.1.0, punycode@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: - version "6.0.3" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.3.tgz#3c9e6b53c09e52ac3cedffc85ab7c1c7094b38cb" - integrity sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w== + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== pvtsutils@^1.3.2, pvtsutils@^1.3.5: version "1.3.5" @@ -5689,9 +5338,9 @@ queue-microtask@^1.2.2: integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== read-pkg-up@^7.0.1: version "7.0.1" @@ -5748,14 +5397,20 @@ regexp-tree@^0.1.27: resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== -regexp.prototype.flags@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" - integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - set-function-name "^2.0.0" + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" + +regexparam@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-3.0.0.tgz#1673e09d41cb7fd41eaafd4040a6aa90daa0a21a" + integrity sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q== regexpu-core@^5.3.1: version "5.3.2" @@ -5788,6 +5443,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -5820,7 +5480,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@1.22.8, resolve@^1.14.2, resolve@^1.22.4: +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.4, resolve@~1.22.2: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -5829,30 +5489,13 @@ resolve@1.22.8, resolve@^1.14.2, resolve@^1.22.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.10.0, resolve@^1.20.0: - version "1.22.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" - integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@~1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" - integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== dependencies: - is-core-module "^2.1.0" - path-parse "^1.0.6" - -restore-cursor@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" - integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" + onetime "^7.0.0" + signal-exit "^4.1.0" retry@^0.13.1: version "0.13.1" @@ -5864,15 +5507,10 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -reverse-arguments@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/reverse-arguments/-/reverse-arguments-1.0.0.tgz#c28095a3a921ac715d61834ddece9027992667cd" - integrity sha512-/x8uIPdTafBqakK0TmPNJzgkLP+3H+yxpUJhCQHsLBg1rYEVNR2D8BRYNWQhVBjyOd7oo1dZRVzIkwMY2oqfYQ== - -rfdc@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" - integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== rimraf@^3.0.2: version "3.0.2" @@ -5881,27 +5519,28 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -rimraf@^5.0.0: - version "5.0.7" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.7.tgz#27bddf202e7d89cb2e0381656380d1734a854a74" - integrity sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg== +rimraf@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-6.0.1.tgz#ffb8ad8844dd60332ab15f52bc104bc3ed71ea4e" + integrity sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A== dependencies: - glob "^10.3.7" + glob "^11.0.0" + package-json-from-dist "^1.0.0" -run-parallel@^1.1.9, run-parallel@^1.2.0: +run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" -safe-array-concat@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" - integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" has-symbols "^1.0.3" isarray "^2.0.5" @@ -5910,13 +5549,13 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.1.tgz#207369b445fd007e534864635b28b2ae7b105783" - integrity sha512-Y5NejJTTliTyY4H7sipGqY+RX5P87i3F7c4Rcepy72nq+mNLhIsD0W4c7kEmduMDQCSqtPsXPlSTsFhh2LQv+g== +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" + call-bind "^1.0.6" + es-errors "^1.3.0" is-regex "^1.1.4" "safer-buffer@>= 2.1.2 < 3.0.0": @@ -5946,43 +5585,37 @@ semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.3: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -semver@^7.5.4: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" - -semver@^7.6.0, semver@^7.6.1: +semver@^7.5.3, semver@^7.5.4, semver@^7.6.1: version "7.6.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== -set-function-length@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" - integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== +semver@^7.6.0, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - define-data-property "^1.1.1" - get-intrinsic "^1.2.1" + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" gopd "^1.0.1" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" -set-function-name@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== +set-function-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: - define-data-property "^1.0.1" + define-data-property "^1.1.4" + es-errors "^1.3.0" functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" shebang-command@^2.0.0: version "2.0.0" @@ -5996,31 +5629,25 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote-word@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/shell-quote-word/-/shell-quote-word-1.0.1.tgz#e2bdfd22d599fd68886491677e38f560f9d469c9" - integrity sha512-lT297f1WLAdq0A4O+AknIFRP6kkiI3s8C913eJ0XqBxJbZPGWUNkRQk2u8zk4bEAjUJ5i+fSLwB6z1HzeT+DEg== - -shiki@^0.14.7: - version "0.14.7" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.7.tgz#c3c9e1853e9737845f1d2ef81b31bcfb07056d4e" - integrity sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg== +shiki@^1.9.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-1.14.1.tgz#617e62dfbe3a083e46111e22086044fbd7644786" + integrity sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA== dependencies: - ansi-sequence-parser "^1.1.0" - jsonc-parser "^3.2.0" - vscode-oniguruma "^1.7.0" - vscode-textmate "^8.0.0" + "@shikijs/core" "1.14.1" + "@types/hast" "^3.0.4" side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -6045,6 +5672,11 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slashes@^3.0.12: + version "3.0.12" + resolved "https://registry.yarnpkg.com/slashes/-/slashes-3.0.12.tgz#3d664c877ad542dc1509eaf2c50f38d483a6435a" + integrity sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA== + slice-ansi@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" @@ -6053,7 +5685,7 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" -slice-ansi@^7.0.0: +slice-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9" integrity sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg== @@ -6061,10 +5693,10 @@ slice-ansi@^7.0.0: ansi-styles "^6.2.1" is-fullwidth-code-point "^5.0.0" -smol-toml@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/smol-toml/-/smol-toml-1.1.4.tgz#08c23b105f56f17e57b0a77c7edcb10b75a62c5c" - integrity sha512-Y0OT8HezWsTNeEOSVxDnKOW/AyNXHQ4BwJNbAXlLTF5wWsBvrcHhIkE5Rf8kQMLmgf7nDX3PVOlgC6/Aiggu3Q== +smol-toml@^1.1.4: + version "1.3.0" + resolved "https://registry.yarnpkg.com/smol-toml/-/smol-toml-1.3.0.tgz#5200e251fffadbb72570c84e9776d2a3eca48143" + integrity sha512-tWpi2TsODPScmi48b/OQZGi2lgUmBCHy6SZrhi/FdnnHiU1GwebbCfuQuxsC3nHaLwtYeJGPrDZDIeodDOc4pA== source-map-support@0.5.13: version "0.5.13" @@ -6109,9 +5741,9 @@ spdx-expression-parse@^4.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.17" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" - integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== + version "3.0.20" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz#e44ed19ed318dd1e5888f93325cee800f0f51b89" + integrity sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw== sprintf-js@~1.0.2: version "1.0.3" @@ -6125,7 +5757,7 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -string-argv@0.3.2: +string-argv@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== @@ -6166,45 +5798,41 @@ string-width@^5.0.1, string-width@^5.1.2: strip-ansi "^7.0.1" string-width@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.1.0.tgz#d994252935224729ea3719c49f7206dc9c46550a" - integrity sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw== + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== dependencies: emoji-regex "^10.3.0" get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" -string.fromcodepoint@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz#8d978333c0bc92538f50f383e4888f3e5619d653" - integrity sha512-n69H31OnxSGSZyZbgBlvYIXlrMhJQ0dQAX1js1QDhpaUH6zmU3QYlj07bCwCNlPOu3oRXIubGPl2gDGnHsiCqg== - -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" @@ -6300,6 +5928,14 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +synckit@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.1.tgz#febbfbb6649979450131f64735aa3f6c14575c88" + integrity sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -6329,18 +5965,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== -to-no-case@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" - integrity sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg== - -to-pascal-case@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-pascal-case/-/to-pascal-case-1.0.0.tgz#0bbdc8df448886ba01535e543327048d0aa1ce78" - integrity sha512-QGMWHqM6xPrcQW57S23c5/3BbYb0Tbe9p+ur98ckRnGDwD4wbbtDiYI38CfmMKNB5Iv0REjs5SNDntTwvDxzZA== - dependencies: - to-space-case "^1.0.0" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -6348,17 +5972,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-space-case@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" - integrity sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA== - dependencies: - to-no-case "^1.0.0" - tough-cookie@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" punycode "^2.1.1" @@ -6419,9 +6036,9 @@ tsconfig-paths@^3.15.0: strip-bom "^3.0.0" tslib@^2.0.0, tslib@^2.4.0, tslib@^2.6.1, tslib@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -6455,79 +6072,85 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^3.0.0: - version "3.13.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.13.1.tgz#bb744c1f0678bea7543a2d1ec24e83e68e8c8706" - integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== - -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typedoc-plugin-coverage@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/typedoc-plugin-coverage/-/typedoc-plugin-coverage-3.1.1.tgz#dda6f4d12a870ffd231b24d53be859e2e44d9c31" - integrity sha512-PAMYQ4fX7wJo6Y8mMzrISDNRurl5+xSNWEojrt6Yxofb/m7vWrgiP3bid2KXloMlPcSfCoBiJA6F2g3rmu8XTQ== + version "3.3.0" + resolved "https://registry.yarnpkg.com/typedoc-plugin-coverage/-/typedoc-plugin-coverage-3.3.0.tgz#2b00830f32129e7433708f6893729d6770b96276" + integrity sha512-wpywQ95tqGSD6IbYUPMXSKiwnSWboSKdx2y9X6SJQKzQvBqZoz5iiUyDJFixtW8v7+xmrqXFR/B6Wy37FNhVqA== typedoc-plugin-mdn-links@^3.0.3: - version "3.1.25" - resolved "https://registry.yarnpkg.com/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-3.1.25.tgz#db877e030216d90f52933b2e5cd5e0506df4af18" - integrity sha512-Tox8kt/yUt+vUiSjz22D+yJyKH7z1f9/CtWbrJdOkfGpmt4SOssEmCPYgxmKPTTCt+SMHL8w5S5tWSc+gj3GYA== + version "3.2.9" + resolved "https://registry.yarnpkg.com/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-3.2.9.tgz#2ee846685e1e3d9e5f76445216e479566c9a3198" + integrity sha512-+bjuG/rPyeRBGA/ILk8u2j7KksohicCsUd+qcTQitOaS9GLvN69zcQlCJU1KqcPHpt3fTqJnVmyhMRe5F+ig7w== -typedoc-plugin-missing-exports@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.2.0.tgz#e39a04bab5b0d7f7b28507d64c07a4c40b788648" - integrity sha512-2+XR1IcyQ5UwXZVJe9NE6HrLmNufT9i5OwoIuuj79VxuA3eYq+Y6itS9rnNV1D7UeQnUSH8kISYD73gHE5zw+w== +typedoc-plugin-missing-exports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-3.0.0.tgz#47ab7cf9b91967f50550b7f07549ed1b743f3726" + integrity sha512-R7D8fYrK34mBFZSlF1EqJxfqiUSlQSmyrCiQgTQD52nNm6+kUtqwiaqaNkuJ2rA2wBgWFecUA8JzHT7x2r7ePg== -typedoc@^0.25.10: - version "0.25.13" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.13.tgz#9a98819e3b2d155a6d78589b46fa4c03768f0922" - integrity sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ== +typedoc@^0.26.0: + version "0.26.6" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.26.6.tgz#9cb3d6f0ed5070f86af169c3f88ca2c9b7031f59" + integrity sha512-SfEU3SH3wHNaxhFPjaZE2kNl/NFtLNW5c1oHsg7mti7GjmUj1Roq6osBQeMd+F4kL0BoRBBr8gQAuqBlfFu8LA== dependencies: lunr "^2.3.9" - marked "^4.3.0" - minimatch "^9.0.3" - shiki "^0.14.7" + markdown-it "^14.1.0" + minimatch "^9.0.5" + shiki "^1.9.1" + yaml "^2.4.5" typescript@^5.3.3: - version "5.4.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" - integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== unbox-primitive@^1.0.2: version "1.0.2" @@ -6544,13 +6167,6 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -unescape-js@^1.0.5: - version "1.1.4" - resolved "https://registry.yarnpkg.com/unescape-js/-/unescape-js-1.1.4.tgz#4bc6389c499cb055a98364a0b3094e1c3d5da395" - integrity sha512-42SD8NOQEhdYntEiUQdYq/1V/YHwr1HLwlHuTJB5InVVdOSbgI6xu8jK5q65yIzuFCfczzyDF/7hbGzVbyCw0g== - dependencies: - string.fromcodepoint "^0.2.1" - unhomoglyph@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/unhomoglyph/-/unhomoglyph-1.0.6.tgz#ea41f926d0fcf598e3b8bb2980c2ddac66b081d3" @@ -6584,13 +6200,13 @@ universalify@^0.2.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.1.2" + picocolors "^1.0.1" uri-js@^4.2.2: version "4.4.1" @@ -6607,29 +6223,29 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +uuid@10: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + uuid@8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@9: - version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== v8-to-istanbul@^9.0.1: - version "9.1.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" - integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" + convert-source-map "^2.0.0" validate-npm-package-license@^3.0.1: version "3.0.4" @@ -6639,21 +6255,6 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -vlq@^0.2.1: - version "0.2.3" - resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" - integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow== - -vscode-oniguruma@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" - integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== - -vscode-textmate@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" - integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== - w3c-xmlserializer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" @@ -6675,10 +6276,10 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -webcrypto-core@^1.7.9: - version "1.7.9" - resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.9.tgz#a585f0032dbc88d202cff4f266cbef02ba48bd7a" - integrity sha512-FE+a4PPkOmBbgNDIyRmcHhgXn+2ClRl3JzJdDu/P4+B8y81LqKe6RAsI9b3lAOHe1T1BMkSjsRHTYRikImZnVA== +webcrypto-core@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.8.0.tgz#aaea17f3dd9c77c304e3c494eb27ca07cc72ca37" + integrity sha512-kR1UQNH8MD42CYuLzvibfakG5Ew5seG85dMMoAM/1LqvckxaF6pUiidLuraIu4V+YCIFabYecUZAW0TuxAoaqw== dependencies: "@peculiar/asn1-schema" "^2.3.8" "@peculiar/json-schema" "^1.1.12" @@ -6749,16 +6350,16 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.11, which-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" - integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== +which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.0" + has-tostringtag "^1.0.2" which@^2.0.1: version "2.0.2" @@ -6767,6 +6368,11 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -6817,9 +6423,9 @@ write-file-atomic@^4.0.2: signal-exit "^3.0.7" ws@^8.11.0: - version "8.14.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.1.tgz#4b9586b4f70f9e6534c7bb1d3dc0baa8b8cf01e0" - integrity sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A== + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== xml-name-validator@^4.0.0: version "4.0.0" @@ -6846,15 +6452,10 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" - integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== +yaml@^2.4.5, yaml@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" + integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== yargs-parser@^21.1.1: version "21.1.1" @@ -6885,9 +6486,9 @@ yocto-queue@^0.1.0: integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zod-validation-error@^3.0.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.3.0.tgz#2cfe81b62d044e0453d1aa3ae7c32a2f36dde9af" - integrity sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw== + version "3.3.1" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.3.1.tgz#86adc781129d1a7fed3c3e567e8dbe7c4a15eaa4" + integrity sha512-uFzCZz7FQis256dqw4AhPQgD6f3pzNca/Zh62RNELavlumQB3nDIUFbF5JQfFLcMbO1s02Q7Xg/gpcOBlEnYZA== zod@^3.22.4: version "3.23.8"