diff --git a/.github/workflows/build-pull-request.yml b/.github/workflows/build-pull-request.yml index 67ae5f1e..ae1097be 100644 --- a/.github/workflows/build-pull-request.yml +++ b/.github/workflows/build-pull-request.yml @@ -25,7 +25,7 @@ jobs: NODE_OPTIONS: '--max_old_space_size=4096' run: npm run build - name: Upload artifact - uses: actions/upload-artifact@v4.3.4 + uses: actions/upload-artifact@v4.3.6 with: name: preview path: dist @@ -33,7 +33,7 @@ jobs: - name: Save pr number run: echo ${PR_NUMBER} > ./pr.txt - name: Upload pr number - uses: actions/upload-artifact@v4.3.4 + uses: actions/upload-artifact@v4.3.6 with: name: pr path: ./pr.txt diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 2ad3d145..65513427 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -12,7 +12,7 @@ jobs: - name: 'CLA Assistant' if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' # Beta Release - uses: cla-assistant/github-action@v2.4.0 + uses: cla-assistant/github-action@v2.5.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # the below token should have repo scope and must be manually added by you in the repository's secret diff --git a/.github/workflows/docker-pr.yml b/.github/workflows/docker-pr.yml index 7b1e2abd..7c67c27a 100644 --- a/.github/workflows/docker-pr.yml +++ b/.github/workflows/docker-pr.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4.1.7 - name: Build Docker image - uses: docker/build-push-action@v6.5.0 + uses: docker/build-push-action@v6.7.0 with: context: . push: false diff --git a/.github/workflows/prod-deploy.yml b/.github/workflows/prod-deploy.yml index a0a70d13..f8f13a7e 100644 --- a/.github/workflows/prod-deploy.yml +++ b/.github/workflows/prod-deploy.yml @@ -70,7 +70,7 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.5.0 + uses: docker/setup-buildx-action@v3.6.1 - name: Login to Docker Hub uses: docker/login-action@v3.3.0 with: @@ -90,7 +90,7 @@ jobs: ${{ secrets.DOCKER_USERNAME }}/cinny ghcr.io/${{ github.repository }} - name: Build and push Docker image - uses: docker/build-push-action@v6.5.0 + uses: docker/build-push-action@v6.7.0 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/.npmrc b/.npmrc index 8833acba..e28ce002 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,2 @@ legacy-peer-deps=true -save-exact=true -@matrix-org:registry=https://gitlab.matrix.org/api/v4/projects/27/packages/npm/ \ No newline at end of file +save-exact=true \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..f1ef5d46 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +cinnyapp@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/README.md b/README.md index 5b54f7ae..5cee6fa2 100644 --- a/README.md +++ b/README.md @@ -19,22 +19,24 @@ A Matrix client focusing primarily on simple, elegant and secure interface. The ## Getting started -Web app is available at https://app.cinny.in and gets updated on each new release. The `dev` branch is continuously deployed at https://dev.cinny.in but keep in mind that it could have things broken. +* Web app is available at https://app.cinny.in and gets updated on each new release. The `dev` branch is continuously deployed at https://dev.cinny.in but keep in mind that it could have things broken. -You can also download our desktop app from [cinny-desktop repository](https://github.com/cinnyapp/cinny-desktop). +* You can also download our desktop app from [cinny-desktop repository](https://github.com/cinnyapp/cinny-desktop). -To host Cinny on your own, download tarball of the app from [GitHub release](https://github.com/cinnyapp/cinny/releases/latest). +* To host Cinny on your own, download tarball of the app from [GitHub release](https://github.com/cinnyapp/cinny/releases/latest). You can serve the application with a webserver of your choice by simply copying `dist/` directory to the webroot. -To set default Homeserver on login and register page, place a customized [`config.json`](config.json) in webroot of your choice. +To set default Homeserver on login, register and Explore Community page, place a customized [`config.json`](config.json) in webroot of your choice. +You will also need to setup redirects to serve the assests. An example setting of redirects for netlify is done in [`netlify.toml`](netlify.toml). You can also set `hashRouter.enabled = true` in [`config.json`](config.json) if you have trouble setting redirects. +To deploy on subdirectory, you need to rebuild the app youself after updating the `base` path in [`build.config.ts`](build.config.ts). For example, if you want to deploy on `https://cinny.in/app`, then change `base: '/app'`. -Alternatively you can just pull the [DockerHub image](https://hub.docker.com/r/ajbura/cinny) by: -``` -docker pull ajbura/cinny -``` -or [ghcr image](https://github.com/cinnyapp/cinny/pkgs/container/cinny) by: -``` -docker pull ghcr.io/cinnyapp/cinny:latest -``` +* Alternatively you can just pull the [DockerHub image](https://hub.docker.com/r/ajbura/cinny) by: + ``` + docker pull ajbura/cinny + ``` + or [ghcr image](https://github.com/cinnyapp/cinny/pkgs/container/cinny) by: + ``` + docker pull ghcr.io/cinnyapp/cinny:latest + ```
PGP Public Key to verify tarball diff --git a/contrib/nginx/cinny.domain.tld.conf b/contrib/nginx/cinny.domain.tld.conf index 360302c0..0ba70f7e 100644 --- a/contrib/nginx/cinny.domain.tld.conf +++ b/contrib/nginx/cinny.domain.tld.conf @@ -24,6 +24,7 @@ server { rewrite ^/manifest.json$ /manifest.json break; rewrite ^.*/olm.wasm$ /olm.wasm break; + rewrite ^/sw.js$ /sw.js break; rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break; rewrite ^/public/(.*)$ /public/$1 break; diff --git a/docker-nginx.conf b/docker-nginx.conf index 6994b8c8..fca10746 100644 --- a/docker-nginx.conf +++ b/docker-nginx.conf @@ -1,16 +1,20 @@ server { - location / { - root /usr/share/nginx/html; + listen 80; + listen [::]:80; - rewrite ^/config.json$ /config.json break; + location / { + root /usr/share/nginx/html; + + rewrite ^/config.json$ /config.json break; rewrite ^/manifest.json$ /manifest.json break; rewrite ^.*/olm.wasm$ /olm.wasm break; + rewrite ^/sw.js$ /sw.js break; rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break; rewrite ^/public/(.*)$ /public/$1 break; rewrite ^/assets/(.*)$ /assets/$1 break; rewrite ^(.+)$ /index.html break; - } -} \ No newline at end of file + } +} diff --git a/netlify.toml b/netlify.toml index d79aa91c..1b192bec 100644 --- a/netlify.toml +++ b/netlify.toml @@ -7,7 +7,12 @@ from = "/manifest.json" to = "/manifest.json" status = 200 - + +[[redirects]] + from = "/sw.js" + to = "/sw.js" + status = 200 + [[redirects]] from = "*/olm.wasm" to = "/olm.wasm" diff --git a/package-lock.json b/package-lock.json index 8b00ff07..1dcff435 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "cinny", - "version": "4.0.3", + "version": "4.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cinny", - "version": "4.0.3", + "version": "4.1.0", "license": "AGPL-3.0-only", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "1.1.6", "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "1.3.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.0.3", "@fontsource/inter": "4.5.14", - "@matrix-org/olm": "3.2.14", + "@matrix-org/olm": "3.2.15", "@tanstack/react-query": "5.24.1", "@tanstack/react-query-devtools": "5.24.1", "@tanstack/react-virtual": "3.2.0", @@ -37,12 +37,15 @@ "formik": "2.4.6", "html-dom-parser": "4.0.0", "html-react-parser": "4.2.0", + "i18next": "23.12.2", + "i18next-browser-languagedetector": "8.0.0", + "i18next-http-backend": "2.5.2", "immer": "9.0.16", "is-hotkey": "0.2.0", "jotai": "2.6.0", "linkify-react": "4.1.3", "linkifyjs": "4.1.3", - "matrix-js-sdk": "29.1.0", + "matrix-js-sdk": "34.4.0", "millify": "6.1.0", "pdfjs-dist": "4.2.67", "prismjs": "1.29.0", @@ -54,6 +57,7 @@ "react-dom": "18.2.0", "react-error-boundary": "4.0.13", "react-google-recaptcha": "2.1.0", + "react-i18next": "15.0.0", "react-modal": "3.16.1", "react-range": "1.8.14", "react-router-dom": "6.20.0", @@ -75,6 +79,7 @@ "@types/react-dom": "18.2.17", "@types/react-google-recaptcha": "2.1.8", "@types/sanitize-html": "2.9.0", + "@types/serviceworker": "0.0.95", "@types/ua-parser-js": "0.7.36", "@typescript-eslint/eslint-plugin": "5.46.1", "@typescript-eslint/parser": "5.46.1", @@ -91,6 +96,7 @@ "sass": "1.56.2", "typescript": "4.9.4", "vite": "5.0.13", + "vite-plugin-pwa": "0.20.5", "vite-plugin-static-copy": "1.0.4", "vite-plugin-top-level-await": "1.4.1" }, @@ -110,6 +116,24 @@ "node": ">=6.0.0" } }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, "node_modules/@atlaskit/pragmatic-drag-and-drop": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@atlaskit/pragmatic-drag-and-drop/-/pragmatic-drag-and-drop-1.1.6.tgz", @@ -139,40 +163,43 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", - "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", - "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", - "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.3", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", + "@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", @@ -188,13 +215,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", - "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -202,26 +230,55 @@ } }, "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "license": "MIT", + "dependencies": { + "@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" }, @@ -233,6 +290,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -240,60 +298,23 @@ "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@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.20" + "@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.4", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -302,90 +323,249 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", - "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.4", - "@babel/types": "^7.23.4" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", - "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.6" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -393,6 +573,339 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.20.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", @@ -407,6 +920,676 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.23.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", @@ -437,12 +1620,314 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", - "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dev": true, + "license": "MIT", "dependencies": { - "regenerator-runtime": "^0.13.11" + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.4", + "@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.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", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@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.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@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.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@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.25.4", + "@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.25.4", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/runtime": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -467,38 +1952,32 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "dev": true }, - "node_modules/@babel/runtime/node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", - "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.23.4", - "@babel/generator": "^7.23.4", - "@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.4", - "@babel/types": "^7.23.4", - "debug": "^4.1.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -506,12 +1985,13 @@ } }, "node_modules/@babel/types": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", - "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@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" }, "engines": { @@ -1077,9 +2557,36 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, "engines": { "node": ">=6.0.0" } @@ -1090,12 +2597,13 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@juggle/resize-observer": { @@ -1139,17 +2647,19 @@ } }, "node_modules/@matrix-org/matrix-sdk-crypto-wasm": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-2.2.0.tgz", - "integrity": "sha512-txmvaTiZpVV0/kWCRcE7tZvRESCEc1ynLJDVh9OUsFlaXfl13c7qdD3E6IJEJ8YiPMIn+PHogdfBZsO84reaMg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-7.0.0.tgz", + "integrity": "sha512-MOencXiW/gI5MuTtCNsuojjwT5DXCrjMqv9xOslJC9h2tPdLFFFMGr58dY5Lis4DRd9MRWcgrGowUIHOqieWTA==", + "license": "Apache-2.0", "engines": { "node": ">= 10" } }, "node_modules/@matrix-org/olm": { - "version": "3.2.14", - "resolved": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz", - "integrity": "sha1-rNlsAKiB0PRi4fl6Vsc3QsjbyYQ=" + "version": "3.2.15", + "resolved": "https://registry.npmjs.org/@matrix-org/olm/-/olm-3.2.15.tgz", + "integrity": "sha512-S7lOrndAK9/8qOtaTq/WhttJC/o4GAzdfK0MUPpo8ApzsJEC0QjtwrkC3KBXdFP1cD1MXi/mlKR7aaoVMKgs6Q==", + "license": "Apache-2.0" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -2608,6 +4118,55 @@ "node": ">=14.0.0" } }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-babel/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-babel/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/plugin-inject": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.3.tgz", @@ -2636,6 +4195,114 @@ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve/node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-replace/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-virtual": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", @@ -2867,6 +4534,29 @@ "win32" ] }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, "node_modules/@swc/core": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.5.tgz", @@ -3227,9 +4917,10 @@ "dev": true }, "node_modules/@types/events": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.2.tgz", - "integrity": "sha512-v4Mr60wJuF069iZZCdY5DKhfj0l6eXNJtbSM/oMDNdRLoBEUsktmKnswkz0X3OAic5W8Qy/YU6owKE4A66Y46A==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz", + "integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==", + "license": "MIT" }, "node_modules/@types/file-saver": { "version": "2.0.5", @@ -3313,6 +5004,13 @@ "@types/react": "*" } }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -3338,6 +5036,20 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/serviceworker": { + "version": "0.0.95", + "resolved": "https://registry.npmjs.org/@types/serviceworker/-/serviceworker-0.0.95.tgz", + "integrity": "sha512-Zw7kLIehLvaXf/9RnxAUiYyHmYC5pfvIJD3b1uSPkZGzp+OVmXgmPzVW5fbhYHKcqkeGzsv89uGm+JmMCAPa8Q==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ua-parser-js": { "version": "0.7.36", "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz", @@ -3766,10 +5478,11 @@ "optional": true }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3836,6 +5549,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -4041,6 +5755,23 @@ "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/autosize": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/autosize/-/autosize-4.0.4.tgz", @@ -4084,6 +5815,48 @@ "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", "dev": true }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4091,9 +5864,10 @@ "devOptional": true }, "node_modules/base-x": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", - "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -4162,9 +5936,9 @@ "integrity": "sha512-L7siI766UCH6+arP9yT5wpA5AFxnmGbKiGSsxEVACl1tE0pvDJeQvMmbY2UmJiuffrr0ZJ2+U6Om46wQBqh1Lw==" }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "funding": [ { "type": "opencollective", @@ -4179,11 +5953,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "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" }, "bin": { "browserslist": "cli.js" @@ -4193,11 +5968,12 @@ } }, "node_modules/bs58": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", - "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", "dependencies": { - "base-x": "^4.0.0" + "base-x": "^5.0.0" } }, "node_modules/buffer": { @@ -4224,6 +6000,26 @@ "ieee754": "^1.2.1" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -4253,9 +6049,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001565", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", - "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "version": "1.0.30001658", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001658.tgz", + "integrity": "sha512-N2YVqWbJELVdrnsW5p+apoQyYt51aBMSsBZki1XZEfeBCexcM/sf4xiAHcXQBkuOwJBXtWF7aW1sYX6tKebPHw==", "funding": [ { "type": "opencollective", @@ -4269,7 +6065,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/canvas": { "version": "2.11.2", @@ -4290,6 +6087,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4377,6 +6175,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -4384,7 +6183,8 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" }, "node_modules/color-support": { "version": "1.1.3", @@ -4395,6 +6195,23 @@ "color-support": "bin.js" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/compute-scroll-into-view": { "version": "1.0.20", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", @@ -4436,6 +6253,20 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-pure": { "version": "3.26.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.1.tgz", @@ -4469,10 +6300,15 @@ "node": ">= 8" } }, - "node_modules/crypto-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, "node_modules/css-what": { "version": "5.1.0", @@ -4572,11 +6408,12 @@ "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -4754,10 +6591,27 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron-to-chromium": { - "version": "1.4.596", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.596.tgz", - "integrity": "sha512-zW3zbZ40Icb2BCWjm47nxwcFGYlIgdXkAx85XDO7cyky9J4QQfq8t0W19/TLZqq3JPQXtlv8BPIGmfa9Jb4scg==" + "version": "1.5.16", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.16.tgz", + "integrity": "sha512-2gQpi2WYobXmz2q23FrOBYTLcI1O/P4heW3eqX+ldmPVDQELRqhiebV380EhlGG12NtnX1qbK/FHpN0ba+7bLA==", + "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -4967,9 +6821,10 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4978,6 +6833,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -5481,6 +7337,13 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5505,6 +7368,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { "node": ">=0.8.x" } @@ -5560,6 +7424,13 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true, + "license": "MIT" + }, "node_modules/fastq": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", @@ -5614,6 +7485,21 @@ "node": "*" } }, + "node_modules/fdir": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz", + "integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5631,6 +7517,39 @@ "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5761,6 +7680,22 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -5896,6 +7831,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true, + "license": "ISC" + }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", @@ -5949,6 +7891,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } @@ -6038,6 +7981,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -6146,6 +8090,15 @@ "entities": "^4.5.0" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-react-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-4.2.0.tgz", @@ -6191,6 +8144,83 @@ "node": ">= 6" } }, + "node_modules/i18next": { + "version": "23.12.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.12.2.tgz", + "integrity": "sha512-XIeh5V+bi8SJSWGL3jqbTEBW5oD6rbP5L+E7dVQh1MNTxxYef0x15rhJVcRb7oiuq4jLtgy2SD8eFlf6P2cmqg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", + "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.2.tgz", + "integrity": "sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw==", + "license": "MIT", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, + "node_modules/i18next-http-backend/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/i18next-http-backend/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -6367,6 +8397,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -6455,6 +8501,13 @@ "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==" }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -6491,6 +8544,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -6524,6 +8587,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", @@ -6539,6 +8612,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -6608,6 +8694,101 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/javascript-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", @@ -6664,6 +8845,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -6671,6 +8853,13 @@ "node": ">=4" } }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -6694,6 +8883,29 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -6708,9 +8920,13 @@ } }, "node_modules/jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/language-subtag-registry": { "version": "0.3.22", @@ -6741,6 +8957,16 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -6811,12 +9037,26 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, + "license": "MIT" + }, "node_modules/loglevel": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", @@ -6885,33 +9125,49 @@ "integrity": "sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==" }, "node_modules/matrix-js-sdk": { - "version": "29.1.0", - "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-29.1.0.tgz", - "integrity": "sha512-nF+ACFioDltGCf2KFfXK7QoJ70Ytnzm4Jse2UI+BDXeR9WCjtKefXJtboN2rmU4MFmLCTHcnBTmu6yig67YUqw==", + "version": "34.4.0", + "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-34.4.0.tgz", + "integrity": "sha512-bI5xJZS3/qhjPQqQL5HhOQ1iBvnHxiqhS2zgzk9SarEuXiH08wbVl9gAAuDqOYE3miNGs4WQQJ19MoaUEOnNwg==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.12.5", - "@matrix-org/matrix-sdk-crypto-wasm": "^2.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": "^3.1.2", + "jwt-decode": "^4.0.0", "loglevel": "^1.7.1", "matrix-events-sdk": "0.0.1", - "matrix-widget-api": "^1.6.0", - "oidc-client-ts": "^2.2.4", + "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" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" + } + }, + "node_modules/matrix-js-sdk/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/matrix-widget-api": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/matrix-widget-api/-/matrix-widget-api-1.6.0.tgz", - "integrity": "sha512-VXIJyAZ/WnBmT4C7ePqevgMYGneKMCP/0JuCOqntSsaNlCRHJvwvTxmqUU+ufOpzIF5gYNyIrAjbgrEbK3iqJQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/matrix-widget-api/-/matrix-widget-api-1.9.0.tgz", + "integrity": "sha512-au8mqralNDqrEvaVAkU37bXOb8I9SCe+ACdPk11QWw58FKstVq31q2wRz+qWA6J+42KJ6s1DggWbG/S3fEs3jw==", + "license": "Apache-2.0", "dependencies": { "@types/events": "^3.0.0", "events": "^3.2.0" @@ -7038,9 +9294,10 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/nan": { "version": "2.17.0", @@ -7097,9 +9354,10 @@ } }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "license": "MIT" }, "node_modules/nopt": { "version": "5.0.0", @@ -7258,15 +9516,15 @@ } }, "node_modules/oidc-client-ts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-2.4.0.tgz", - "integrity": "sha512-WijhkTrlXK2VvgGoakWJiBdfIsVGz6CFzgjNNqZU1hPKV2kyeEaJgLs7RwuiSp2WhLfWBQuLvr2SxVlZnk3N1w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.0.1.tgz", + "integrity": "sha512-xX8unZNtmtw3sOz4FPSqDhkLFnxCDsdo2qhFEH2opgWnF/iXMFoYdBQzkwCxAZVgt3FT3DnuBY3k80EZHT0RYg==", + "license": "Apache-2.0", "dependencies": { - "crypto-js": "^4.2.0", - "jwt-decode": "^3.1.2" + "jwt-decode": "^4.0.0" }, "engines": { - "node": ">=12.13.0" + "node": ">=18" } }, "node_modules/once": { @@ -7420,9 +9678,10 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -7524,6 +9783,19 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/pretty-bytes": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prismjs": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", @@ -7584,6 +9856,16 @@ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -7717,6 +9999,28 @@ "react": ">=16.4.1" } }, + "node_modules/react-i18next": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.0.tgz", + "integrity": "sha512-2O3IgF4zivg57Q6p6i+ChDgJ371IDcEWbuWC6gvoh5NbkDMs0Q+O7RPr4v61+Se32E0V+LmtwePAeqWZW0bi6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.8", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -7824,6 +10128,42 @@ "node": ">=8.10.0" } }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -7854,6 +10194,46 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7862,6 +10242,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-like": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", @@ -8003,6 +10393,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "devOptional": true, "funding": [ { "type": "github", @@ -8016,8 +10407,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "optional": true + ] }, "node_modules/safe-regex-test": { "version": "1.0.3", @@ -8117,6 +10507,16 @@ "semver": "bin/semver.js" } }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -8288,6 +10688,26 @@ "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.1.8.tgz", "integrity": "sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==" }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -8296,6 +10716,64 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/source-map/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/source-map/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "license": "MIT" + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -8391,6 +10869,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -8411,6 +10904,16 @@ "node": ">=4" } }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8443,6 +10946,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -8484,6 +10988,67 @@ "node": ">=10" } }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -8500,6 +11065,33 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "node_modules/tinyglobby": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.5.tgz", + "integrity": "sha512-Dlqgt6h0QkoHttG53/WGADNh9QhcjCAIZMTERAVhdpmIBEejSuLI9ZmGKWzB7tweBjlk30+s/ofi4SLmBeTYhw==", + "dev": true, + "license": "ISC", + "dependencies": { + "fdir": "^6.2.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tippy.js": { "version": "6.3.7", "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", @@ -8726,10 +11318,88 @@ "resolved": "https://registry.npmjs.org/unhomoglyph/-/unhomoglyph-1.0.6.tgz", "integrity": "sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==" }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "funding": [ { "type": "opencollective", @@ -8744,9 +11414,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -8774,6 +11445,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -8837,6 +11509,37 @@ } } }, + "node_modules/vite-plugin-pwa": { + "version": "0.20.5", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.20.5.tgz", + "integrity": "sha512-aweuI/6G6n4C5Inn0vwHumElU/UEpNuO+9iZzwPZGTCH87TeZ6YFMrEY6ZUBQdIHHlhTsbMDryFARcSuOdsz9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.0", + "workbox-build": "^7.1.0", + "workbox-window": "^7.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^0.2.6", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0", + "workbox-build": "^7.1.0", + "workbox-window": "^7.1.0" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, "node_modules/vite-plugin-static-copy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.4.tgz", @@ -8869,27 +11572,6 @@ "node": ">=14.14" } }, - "node_modules/vite-plugin-static-copy/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/vite-plugin-static-copy/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/vite-plugin-top-level-await": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.4.1.tgz", @@ -9294,6 +11976,15 @@ "@esbuild/win32-x64": "0.19.12" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", @@ -9384,6 +12075,266 @@ "node": ">=0.10.0" } }, + "node_modules/workbox-background-sync": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.1.0.tgz", + "integrity": "sha512-rMbgrzueVWDFcEq1610YyDW71z0oAXLfdRHRQcKw4SGihkfOK0JUEvqWHFwA6rJ+6TClnMIn7KQI5PNN1XQXwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.1.0.tgz", + "integrity": "sha512-O36hIfhjej/c5ar95pO67k1GQw0/bw5tKP7CERNgK+JdxBANQhDmIuOXZTNvwb2IHBx9hj2kxvcDyRIh5nzOgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-build": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.1.1.tgz", + "integrity": "sha512-WdkVdC70VMpf5NBCtNbiwdSZeKVuhTEd5PV3mAwpTQCGAB5XbOny1P9egEgNdetv4srAMmMKjvBk4RD58LpooA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^2.4.1", + "@rollup/plugin-terser": "^0.4.3", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "7.1.0", + "workbox-broadcast-update": "7.1.0", + "workbox-cacheable-response": "7.1.0", + "workbox-core": "7.1.0", + "workbox-expiration": "7.1.0", + "workbox-google-analytics": "7.1.0", + "workbox-navigation-preload": "7.1.0", + "workbox-precaching": "7.1.0", + "workbox-range-requests": "7.1.0", + "workbox-recipes": "7.1.0", + "workbox-routing": "7.1.0", + "workbox-strategies": "7.1.0", + "workbox-streams": "7.1.0", + "workbox-sw": "7.1.0", + "workbox-window": "7.1.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/workbox-build/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/workbox-build/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-build/node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-build/node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.1.0.tgz", + "integrity": "sha512-iwsLBll8Hvua3xCuBB9h92+/e0wdsmSVgR2ZlvcfjepZWwhd3osumQB3x9o7flj+FehtWM2VHbZn8UJeBXXo6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.1.0.tgz", + "integrity": "sha512-5KB4KOY8rtL31nEF7BfvU7FMzKT4B5TkbYa2tzkS+Peqj0gayMT9SytSFtNzlrvMaWgv6y/yvP9C0IbpFjV30Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-expiration": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.1.0.tgz", + "integrity": "sha512-m5DcMY+A63rJlPTbbBNtpJ20i3enkyOtSgYfv/l8h+D6YbbNiA0zKEkCUaMsdDlxggla1oOfRkyqTvl5Ni5KQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-google-analytics": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.1.0.tgz", + "integrity": "sha512-FvE53kBQHfVTcZyczeBVRexhh7JTkyQ8HAvbVY6mXd2n2A7Oyz/9fIwnY406ZcDhvE4NFfKGjW56N4gBiqkrew==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-background-sync": "7.1.0", + "workbox-core": "7.1.0", + "workbox-routing": "7.1.0", + "workbox-strategies": "7.1.0" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.1.0.tgz", + "integrity": "sha512-4wyAbo0vNI/X0uWNJhCMKxnPanNyhybsReMGN9QUpaePLTiDpKxPqFxl4oUmBNddPwIXug01eTSLVIFXimRG/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-precaching": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.1.0.tgz", + "integrity": "sha512-LyxzQts+UEpgtmfnolo0hHdNjoB7EoRWcF7EDslt+lQGd0lW4iTvvSe3v5JiIckQSB5KTW5xiCqjFviRKPj1zA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0", + "workbox-routing": "7.1.0", + "workbox-strategies": "7.1.0" + } + }, + "node_modules/workbox-range-requests": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.1.0.tgz", + "integrity": "sha512-m7+O4EHolNs5yb/79CrnwPR/g/PRzMFYEdo01LqwixVnc/sbzNSvKz0d04OE3aMRel1CwAAZQheRsqGDwATgPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-recipes": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.1.0.tgz", + "integrity": "sha512-NRrk4ycFN9BHXJB6WrKiRX3W3w75YNrNrzSX9cEZgFB5ubeGoO8s/SDmOYVrFYp9HMw6sh1Pm3eAY/1gVS8YLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-cacheable-response": "7.1.0", + "workbox-core": "7.1.0", + "workbox-expiration": "7.1.0", + "workbox-precaching": "7.1.0", + "workbox-routing": "7.1.0", + "workbox-strategies": "7.1.0" + } + }, + "node_modules/workbox-routing": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.1.0.tgz", + "integrity": "sha512-oOYk+kLriUY2QyHkIilxUlVcFqwduLJB7oRZIENbqPGeBP/3TWHYNNdmGNhz1dvKuw7aqvJ7CQxn27/jprlTdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-strategies": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.1.0.tgz", + "integrity": "sha512-/UracPiGhUNehGjRm/tLUQ+9PtWmCbRufWtV0tNrALuf+HZ4F7cmObSEK+E4/Bx1p8Syx2tM+pkIrvtyetdlew==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0" + } + }, + "node_modules/workbox-streams": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.1.0.tgz", + "integrity": "sha512-WyHAVxRXBMfysM8ORwiZnI98wvGWTVAq/lOyBjf00pXFvG0mNaVz4Ji+u+fKa/mf1i2SnTfikoYKto4ihHeS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.1.0", + "workbox-routing": "7.1.0" + } + }, + "node_modules/workbox-sw": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.1.0.tgz", + "integrity": "sha512-Hml/9+/njUXBglv3dtZ9WBKHI235AQJyLBV1G7EFmh4/mUdSQuXui80RtjDeVRrXnm/6QWgRUEHG3/YBVbxtsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-window": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.1.0.tgz", + "integrity": "sha512-ZHeROyqR+AS5UPzholQRDttLFqGMwP0Np8MKWAdyxsDETxq3qOAyXvqessc3GniohG6e0mAqSQyKOHmT8zPF7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "7.1.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -9495,4 +12446,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index ec8b81f4..7cb18f1c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cinny", - "version": "4.0.3", + "version": "4.1.0", "description": "Yet another matrix client", "main": "index.js", "type": "module", @@ -24,7 +24,7 @@ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "1.3.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.0.3", "@fontsource/inter": "4.5.14", - "@matrix-org/olm": "3.2.14", + "@matrix-org/olm": "3.2.15", "@tanstack/react-query": "5.24.1", "@tanstack/react-query-devtools": "5.24.1", "@tanstack/react-virtual": "3.2.0", @@ -49,12 +49,15 @@ "formik": "2.4.6", "html-dom-parser": "4.0.0", "html-react-parser": "4.2.0", + "i18next": "23.12.2", + "i18next-browser-languagedetector": "8.0.0", + "i18next-http-backend": "2.5.2", "immer": "9.0.16", "is-hotkey": "0.2.0", "jotai": "2.6.0", "linkify-react": "4.1.3", "linkifyjs": "4.1.3", - "matrix-js-sdk": "29.1.0", + "matrix-js-sdk": "34.4.0", "millify": "6.1.0", "pdfjs-dist": "4.2.67", "prismjs": "1.29.0", @@ -66,6 +69,7 @@ "react-dom": "18.2.0", "react-error-boundary": "4.0.13", "react-google-recaptcha": "2.1.0", + "react-i18next": "15.0.0", "react-modal": "3.16.1", "react-range": "1.8.14", "react-router-dom": "6.20.0", @@ -87,6 +91,7 @@ "@types/react-dom": "18.2.17", "@types/react-google-recaptcha": "2.1.8", "@types/sanitize-html": "2.9.0", + "@types/serviceworker": "0.0.95", "@types/ua-parser-js": "0.7.36", "@typescript-eslint/eslint-plugin": "5.46.1", "@typescript-eslint/parser": "5.46.1", @@ -103,6 +108,7 @@ "sass": "1.56.2", "typescript": "4.9.4", "vite": "5.0.13", + "vite-plugin-pwa": "0.20.5", "vite-plugin-static-copy": "1.0.4", "vite-plugin-top-level-await": "1.4.1" } diff --git a/public/locales/de.json b/public/locales/de.json new file mode 100644 index 00000000..43a37160 --- /dev/null +++ b/public/locales/de.json @@ -0,0 +1,7 @@ +{ + "Organisms": { + "RoomCommon": { + "changed_room_name": " hat den Raum Name geändert" + } + } +} diff --git a/public/locales/en.json b/public/locales/en.json new file mode 100644 index 00000000..7a2534b8 --- /dev/null +++ b/public/locales/en.json @@ -0,0 +1,7 @@ +{ + "Organisms": { + "RoomCommon": { + "changed_room_name": " changed room name" + } + } +} diff --git a/src/app/components/BackRouteHandler.tsx b/src/app/components/BackRouteHandler.tsx new file mode 100644 index 00000000..fa3d7592 --- /dev/null +++ b/src/app/components/BackRouteHandler.tsx @@ -0,0 +1,86 @@ +import { ReactNode, useCallback } from 'react'; +import { matchPath, useLocation, useNavigate } from 'react-router-dom'; +import { + getDirectPath, + getExplorePath, + getHomePath, + getInboxPath, + getSpacePath, +} from '../pages/pathUtils'; +import { DIRECT_PATH, EXPLORE_PATH, HOME_PATH, INBOX_PATH, SPACE_PATH } from '../pages/paths'; + +type BackRouteHandlerProps = { + children: (onBack: () => void) => ReactNode; +}; +export function BackRouteHandler({ children }: BackRouteHandlerProps) { + const navigate = useNavigate(); + const location = useLocation(); + + const goBack = useCallback(() => { + if ( + matchPath( + { + path: HOME_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getHomePath()); + return; + } + if ( + matchPath( + { + path: DIRECT_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getDirectPath()); + return; + } + const spaceMatch = matchPath( + { + path: SPACE_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ); + if (spaceMatch?.params.spaceIdOrAlias) { + navigate(getSpacePath(spaceMatch.params.spaceIdOrAlias)); + return; + } + if ( + matchPath( + { + path: EXPLORE_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getExplorePath()); + return; + } + if ( + matchPath( + { + path: INBOX_PATH, + caseSensitive: true, + end: false, + }, + location.pathname + ) + ) { + navigate(getInboxPath()); + } + }, [navigate, location]); + + return children(goBack); +} diff --git a/src/app/components/RenderMessageContent.tsx b/src/app/components/RenderMessageContent.tsx index 60e03313..1ce37e5c 100644 --- a/src/app/components/RenderMessageContent.tsx +++ b/src/app/components/RenderMessageContent.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { MsgType } from 'matrix-js-sdk'; import { HTMLReactParserOptions } from 'html-react-parser'; +import { Opts } from 'linkifyjs'; import { AudioContent, DownloadFile, @@ -27,6 +28,7 @@ import { Image, MediaControl, Video } from './media'; import { ImageViewer } from './image-viewer'; import { PdfViewer } from './Pdf-viewer'; import { TextViewer } from './text-viewer'; +import { testMatrixTo } from '../plugins/matrix-to'; type RenderMessageContentProps = { displayName: string; @@ -38,6 +40,7 @@ type RenderMessageContentProps = { urlPreview?: boolean; highlightRegex?: RegExp; htmlReactParserOptions: HTMLReactParserOptions; + linkifyOpts: Opts; outlineAttachment?: boolean; }; export function RenderMessageContent({ @@ -50,8 +53,21 @@ export function RenderMessageContent({ urlPreview, highlightRegex, htmlReactParserOptions, + linkifyOpts, outlineAttachment, }: RenderMessageContentProps) { + const renderUrlsPreview = (urls: string[]) => { + const filteredUrls = urls.filter((url) => !testMatrixTo(url)); + if (filteredUrls.length === 0) return undefined; + return ( + + {filteredUrls.map((url) => ( + + ))} + + ); + }; + const renderFile = () => ( )} - renderUrlsPreview={ - urlPreview - ? (urls) => ( - - {urls.map((url) => ( - - ))} - - ) - : undefined - } + renderUrlsPreview={urlPreview ? renderUrlsPreview : undefined} /> ); } @@ -123,19 +130,10 @@ export function RenderMessageContent({ {...props} highlightRegex={highlightRegex} htmlReactParserOptions={htmlReactParserOptions} + linkifyOpts={linkifyOpts} /> )} - renderUrlsPreview={ - urlPreview - ? (urls) => ( - - {urls.map((url) => ( - - ))} - - ) - : undefined - } + renderUrlsPreview={urlPreview ? renderUrlsPreview : undefined} /> ); } @@ -150,19 +148,10 @@ export function RenderMessageContent({ {...props} highlightRegex={highlightRegex} htmlReactParserOptions={htmlReactParserOptions} + linkifyOpts={linkifyOpts} /> )} - renderUrlsPreview={ - urlPreview - ? (urls) => ( - - {urls.map((url) => ( - - ))} - - ) - : undefined - } + renderUrlsPreview={urlPreview ? renderUrlsPreview : undefined} /> ); } diff --git a/src/app/components/editor/Elements.tsx b/src/app/components/editor/Elements.tsx index c4767ab9..aee50ac8 100644 --- a/src/app/components/editor/Elements.tsx +++ b/src/app/components/editor/Elements.tsx @@ -13,6 +13,8 @@ import { CommandElement, EmoticonElement, LinkElement, MentionElement } from './ import { useMatrixClient } from '../../hooks/useMatrixClient'; import { getBeginCommand } from './utils'; import { BlockType } from './types'; +import { mxcUrlToHttp } from '../../utils/matrix'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; // Put this at the start and end of an inline component to work around this Chromium bug: // https://bugs.chromium.org/p/chromium/issues/detail?id=1249405 @@ -76,6 +78,8 @@ function RenderEmoticonElement({ children, }: { element: EmoticonElement } & RenderElementProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const selected = useSelected(); const focused = useFocused(); @@ -90,7 +94,7 @@ function RenderEmoticonElement({ {element.key.startsWith('mxc://') ? ( {element.shortcode} ) : ( diff --git a/src/app/components/editor/autocomplete/EmoticonAutocomplete.tsx b/src/app/components/editor/autocomplete/EmoticonAutocomplete.tsx index bc98667e..b77ae746 100644 --- a/src/app/components/editor/autocomplete/EmoticonAutocomplete.tsx +++ b/src/app/components/editor/autocomplete/EmoticonAutocomplete.tsx @@ -18,6 +18,8 @@ import { useRelevantImagePacks } from '../../../hooks/useImagePacks'; import { IEmoji, emojis } from '../../../plugins/emoji'; import { ExtendedPackImage, PackUsage } from '../../../plugins/custom-emoji'; import { useKeyDown } from '../../../hooks/useKeyDown'; +import { mxcUrlToHttp } from '../../../utils/matrix'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; type EmoticonCompleteHandler = (key: string, shortcode: string) => void; @@ -48,6 +50,8 @@ export function EmoticonAutocomplete({ requestClose, }: EmoticonAutocompleteProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const imagePacks = useRelevantImagePacks(mx, PackUsage.Emoticon, imagePackRooms); const recentEmoji = useRecentEmoji(mx, 20); @@ -103,7 +107,7 @@ export function EmoticonAutocomplete({ diff --git a/src/app/components/editor/autocomplete/RoomMentionAutocomplete.tsx b/src/app/components/editor/autocomplete/RoomMentionAutocomplete.tsx index 439d98ca..049be94a 100644 --- a/src/app/components/editor/autocomplete/RoomMentionAutocomplete.tsx +++ b/src/app/components/editor/autocomplete/RoomMentionAutocomplete.tsx @@ -17,6 +17,7 @@ import { mDirectAtom } from '../../../state/mDirectList'; import { allRoomsAtom } from '../../../state/room-list/roomList'; import { factoryRoomIdByActivity } from '../../../utils/sort'; import { RoomAvatar, RoomIcon } from '../../room-avatar'; +import { getViaServers } from '../../../plugins/via-servers'; type MentionAutoCompleteHandler = (roomAliasOrId: string, name: string) => void; @@ -104,10 +105,14 @@ export function RoomMentionAutocomplete({ }, [query.text, search, resetSearch]); const handleAutocomplete: MentionAutoCompleteHandler = (roomAliasOrId, name) => { + const mentionRoom = mx.getRoom(roomAliasOrId); + const viaServers = mentionRoom ? getViaServers(mentionRoom) : undefined; const mentionEl = createMentionElement( roomAliasOrId, name.startsWith('#') ? name : `#${name}`, - roomId === roomAliasOrId || mx.getRoom(roomId)?.getCanonicalAlias() === roomAliasOrId + roomId === roomAliasOrId || mx.getRoom(roomId)?.getCanonicalAlias() === roomAliasOrId, + undefined, + viaServers ); replaceWithElement(editor, query.range, mentionEl); moveCursor(editor, true); diff --git a/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx b/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx index 642ce50a..05d303a2 100644 --- a/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx +++ b/src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx @@ -18,6 +18,7 @@ import { useKeyDown } from '../../../hooks/useKeyDown'; import { getMxIdLocalPart, getMxIdServer, validMxId } from '../../../utils/matrix'; import { getMemberDisplayName, getMemberSearchStr } from '../../../utils/room'; import { UserAvatar } from '../../user-avatar'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; type MentionAutoCompleteHandler = (userId: string, name: string) => void; @@ -84,6 +85,8 @@ export function UserMentionAutocomplete({ requestClose, }: UserMentionAutocompleteProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const roomId: string = room.roomId!; const roomAliasOrId = room.getCanonicalAlias() || roomId; const members = useRoomMembers(mx, roomId); @@ -143,7 +146,8 @@ export function UserMentionAutocomplete({ /> ) : ( autoCompleteMembers.map((roomMember) => { - const avatarUrl = roomMember.getAvatarUrl(mx.baseUrl, 32, 32, 'crop', undefined, false); + const avatarMxcUrl = roomMember.getMxcAvatarUrl(); + const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(avatarMxcUrl, 32, 32, 'crop', undefined, false, useAuthentication) : undefined; return ( = { b: MarkType.Bold, @@ -68,11 +74,33 @@ const elementToInlineNode = (node: Element): MentionElement | EmoticonElement | return createEmoticonElement(src, alt || 'Unknown Emoji'); } if (node.name === 'a') { - const { href } = node.attribs; + const href = tryDecodeURIComponent(node.attribs.href); if (typeof href !== 'string') return undefined; - const [mxId] = parseMatrixToUrl(href); - if (mxId) { - return createMentionElement(mxId, parseNodeText(node) || mxId, false); + if (testMatrixTo(href)) { + const userMention = parseMatrixToUser(href); + if (userMention) { + return createMentionElement(userMention, parseNodeText(node) || userMention, false); + } + const roomMention = parseMatrixToRoom(href); + if (roomMention) { + return createMentionElement( + roomMention.roomIdOrAlias, + parseNodeText(node) || roomMention.roomIdOrAlias, + false, + undefined, + roomMention.viaServers + ); + } + const eventMention = parseMatrixToRoomEvent(href); + if (eventMention) { + return createMentionElement( + eventMention.roomIdOrAlias, + parseNodeText(node) || eventMention.roomIdOrAlias, + false, + eventMention.eventId, + eventMention.viaServers + ); + } } } return undefined; diff --git a/src/app/components/editor/output.ts b/src/app/components/editor/output.ts index 53ee6ddf..d6136d99 100644 --- a/src/app/components/editor/output.ts +++ b/src/app/components/editor/output.ts @@ -51,10 +51,19 @@ const elementToCustomHtml = (node: CustomElement, children: string): string => { case BlockType.UnorderedList: return `
    ${children}
`; - case BlockType.Mention: - return `${sanitizeText( - node.name - )}`; + case BlockType.Mention: { + let fragment = node.id; + + if (node.eventId) { + fragment += `/${node.eventId}`; + } + if (node.viaServers && node.viaServers.length > 0) { + fragment += `?${node.viaServers.map((server) => `via=${server}`).join('&')}`; + } + + const matrixTo = `https://matrix.to/#/${fragment}`; + return `${sanitizeText(node.name)}`; + } case BlockType.Emoticon: return node.key.startsWith('mxc://') ? `${sanitizeText(
@@ -62,7 +71,7 @@ const elementToCustomHtml = (node: CustomElement, children: string): string => {
           )}` : sanitizeText(node.key); case BlockType.Link: - return `${node.children}`; + return `${node.children}`; case BlockType.Command: return `/${sanitizeText(node.command)}`; default: diff --git a/src/app/components/editor/slate.d.ts b/src/app/components/editor/slate.d.ts index 1b08ae88..da1460e5 100644 --- a/src/app/components/editor/slate.d.ts +++ b/src/app/components/editor/slate.d.ts @@ -29,6 +29,8 @@ export type LinkElement = { export type MentionElement = { type: BlockType.Mention; id: string; + eventId?: string; + viaServers?: string[]; highlight: boolean; name: string; children: Text[]; diff --git a/src/app/components/editor/utils.ts b/src/app/components/editor/utils.ts index 3f4f9547..90c549c8 100644 --- a/src/app/components/editor/utils.ts +++ b/src/app/components/editor/utils.ts @@ -158,10 +158,14 @@ export const resetEditorHistory = (editor: Editor) => { export const createMentionElement = ( id: string, name: string, - highlight: boolean + highlight: boolean, + eventId?: string, + viaServers?: string[] ): MentionElement => ({ type: BlockType.Mention, id, + eventId, + viaServers, highlight, name, children: [{ text: '' }], diff --git a/src/app/components/emoji-board/EmojiBoard.tsx b/src/app/components/emoji-board/EmojiBoard.tsx index 53172efd..46015acd 100644 --- a/src/app/components/emoji-board/EmojiBoard.tsx +++ b/src/app/components/emoji-board/EmojiBoard.tsx @@ -42,13 +42,14 @@ import { useRelevantImagePacks } from '../../hooks/useImagePacks'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { useRecentEmoji } from '../../hooks/useRecentEmoji'; import { ExtendedPackImage, ImagePack, PackUsage } from '../../plugins/custom-emoji'; -import { isUserId } from '../../utils/matrix'; +import { isUserId, mxcUrlToHttp } from '../../utils/matrix'; import { editableActiveElement, isIntersectingScrollView, targetFromEvent } from '../../utils/dom'; import { useAsyncSearch, UseAsyncSearchOptions } from '../../hooks/useAsyncSearch'; import { useDebounce } from '../../hooks/useDebounce'; import { useThrottle } from '../../hooks/useThrottle'; import { addRecentEmoji } from '../../plugins/recent-emoji'; import { mobileOrTablet } from '../../utils/user-agent'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; const RECENT_GROUP_ID = 'recent_group'; const SEARCH_GROUP_ID = 'search_group'; @@ -354,11 +355,13 @@ function ImagePackSidebarStack({ packs, usage, onItemClick, + useAuthentication, }: { mx: MatrixClient; packs: ImagePack[]; usage: PackUsage; onItemClick: (id: string) => void; + useAuthentication?: boolean; }) { const activeGroupId = useAtomValue(activeGroupIdAtom); return ( @@ -381,7 +384,7 @@ function ImagePackSidebarStack({ height: toRem(24), objectFit: 'contain', }} - src={mx.mxcUrlToHttp(pack.getPackAvatarUrl(usage) ?? '') || pack.avatarUrl} + src={mxcUrlToHttp(mx, pack.getPackAvatarUrl(usage) ?? '', useAuthentication) || pack.avatarUrl} alt={label || 'Unknown Pack'} /> @@ -453,68 +456,70 @@ export function SearchEmojiGroup({ label, id, emojis: searchResult, + useAuthentication, }: { mx: MatrixClient; tab: EmojiBoardTab; label: string; id: string; emojis: Array; + useAuthentication?: boolean; }) { return ( {tab === EmojiBoardTab.Emoji ? searchResult.map((emoji) => - 'unicode' in emoji ? ( - - {emoji.unicode} - - ) : ( - - {emoji.body - - ) + 'unicode' in emoji ? ( + + {emoji.unicode} + + ) : ( + + {emoji.body + ) + ) : searchResult.map((emoji) => - 'unicode' in emoji ? null : ( - - {emoji.body - - ) - )} + 'unicode' in emoji ? null : ( + + {emoji.body + + ) + )} ); } export const CustomEmojiGroups = memo( - ({ mx, groups }: { mx: MatrixClient; groups: ImagePack[] }) => ( + ({ mx, groups, useAuthentication }: { mx: MatrixClient; groups: ImagePack[]; useAuthentication?: boolean }) => ( <> {groups.map((pack) => ( @@ -530,7 +535,7 @@ export const CustomEmojiGroups = memo( loading="lazy" className={css.CustomEmojiImg} alt={image.body || image.shortcode} - src={mx.mxcUrlToHttp(image.url) ?? image.url} + src={mxcUrlToHttp(mx, image.url, useAuthentication) ?? image.url} /> ))} @@ -540,7 +545,7 @@ export const CustomEmojiGroups = memo( ) ); -export const StickerGroups = memo(({ mx, groups }: { mx: MatrixClient; groups: ImagePack[] }) => ( +export const StickerGroups = memo(({ mx, groups, useAuthentication }: { mx: MatrixClient; groups: ImagePack[]; useAuthentication?: boolean }) => ( <> {groups.length === 0 && ( ))} @@ -645,6 +650,8 @@ export function EmojiBoard({ const setActiveGroupId = useSetAtom(activeGroupIdAtom); const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const emojiGroupLabels = useEmojiGroupLabels(); const emojiGroupIcons = useEmojiGroupIcons(); const imagePacks = useRelevantImagePacks(mx, usage, imagePackRooms); @@ -729,14 +736,14 @@ export function EmojiBoard({ } else if (emojiInfo.type === EmojiType.CustomEmoji && emojiPreviewRef.current) { const img = document.createElement('img'); img.className = css.CustomEmojiImg; - img.setAttribute('src', mx.mxcUrlToHttp(emojiInfo.data) || emojiInfo.data); + img.setAttribute('src', mxcUrlToHttp(mx, emojiInfo.data, useAuthentication) || emojiInfo.data); img.setAttribute('alt', emojiInfo.shortcode); emojiPreviewRef.current.textContent = ''; emojiPreviewRef.current.appendChild(img); } emojiPreviewTextRef.current.textContent = `:${emojiInfo.shortcode}:`; }, - [mx] + [mx, useAuthentication] ); const throttleEmojiHover = useThrottle(handleEmojiPreview, { @@ -829,6 +836,7 @@ export function EmojiBoard({ usage={usage} packs={imagePacks} onItemClick={handleScrollToGroup} + useAuthentication={useAuthentication} /> )} {emojiTab && ( @@ -890,13 +898,14 @@ export function EmojiBoard({ id={SEARCH_GROUP_ID} label={result.items.length ? 'Search Results' : 'No Results found'} emojis={result.items} + useAuthentication={useAuthentication} /> )} {emojiTab && recentEmojis.length > 0 && ( )} - {emojiTab && } - {stickerTab && } + {emojiTab && } + {stickerTab && } {emojiTab && } diff --git a/src/app/components/event-readers/EventReaders.tsx b/src/app/components/event-readers/EventReaders.tsx index 08e24a52..a6163b8b 100644 --- a/src/app/components/event-readers/EventReaders.tsx +++ b/src/app/components/event-readers/EventReaders.tsx @@ -21,6 +21,7 @@ import * as css from './EventReaders.css'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { openProfileViewer } from '../../../client/action/navigation'; import { UserAvatar } from '../user-avatar'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; export type EventReadersProps = { room: Room; @@ -30,6 +31,8 @@ export type EventReadersProps = { export const EventReaders = as<'div', EventReadersProps>( ({ className, room, eventId, requestClose, ...props }, ref) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const latestEventReaders = useRoomEventReaders(room, eventId); const getName = (userId: string) => @@ -55,9 +58,10 @@ export const EventReaders = as<'div', EventReadersProps>( {latestEventReaders.map((readerId) => { const name = getName(readerId); - const avatarUrl = room + const avatarMxcUrl = room .getMember(readerId) - ?.getAvatarUrl(mx.baseUrl, 100, 100, 'crop', undefined, false); + ?.getMxcAvatarUrl(); + const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp(avatarMxcUrl, 100, 100, 'crop', undefined, false, useAuthentication) : undefined; return ( (({ className, mx, count, reaction, ...props }, ref) => ( +>(({ className, mx, count, reaction, useAuthentication, ...props }, ref) => ( ) : ( diff --git a/src/app/components/message/RenderBody.tsx b/src/app/components/message/RenderBody.tsx index b5b517e1..6db9ee48 100644 --- a/src/app/components/message/RenderBody.tsx +++ b/src/app/components/message/RenderBody.tsx @@ -1,13 +1,10 @@ import React from 'react'; import parse, { HTMLReactParserOptions } from 'html-react-parser'; import Linkify from 'linkify-react'; +import { Opts } from 'linkifyjs'; import { MessageEmptyContent } from './content'; import { sanitizeCustomHtml } from '../../utils/sanitize'; -import { - LINKIFY_OPTS, - highlightText, - scaleSystemEmoji, -} from '../../plugins/react-custom-html-parser'; +import { highlightText, scaleSystemEmoji } from '../../plugins/react-custom-html-parser'; type RenderBodyProps = { body: string; @@ -15,12 +12,14 @@ type RenderBodyProps = { highlightRegex?: RegExp; htmlReactParserOptions: HTMLReactParserOptions; + linkifyOpts: Opts; }; export function RenderBody({ body, customBody, highlightRegex, htmlReactParserOptions, + linkifyOpts, }: RenderBodyProps) { if (body === '') ; if (customBody) { @@ -28,7 +27,7 @@ export function RenderBody({ return parse(sanitizeCustomHtml(customBody), htmlReactParserOptions); } return ( - + {highlightRegex ? highlightText(highlightRegex, scaleSystemEmoji(body)) : scaleSystemEmoji(body)} diff --git a/src/app/components/message/Reply.css.ts b/src/app/components/message/Reply.css.ts index 014a2840..06799391 100644 --- a/src/app/components/message/Reply.css.ts +++ b/src/app/components/message/Reply.css.ts @@ -5,6 +5,25 @@ export const ReplyBend = style({ flexShrink: 0, }); +export const ThreadIndicator = style({ + opacity: config.opacity.P300, + gap: toRem(2), + + selectors: { + 'button&': { + cursor: 'pointer', + }, + ':hover&': { + opacity: config.opacity.P500, + }, + }, +}); + +export const ThreadIndicatorIcon = style({ + width: toRem(14), + height: toRem(14), +}); + export const Reply = style({ marginBottom: toRem(1), minWidth: 0, diff --git a/src/app/components/message/Reply.tsx b/src/app/components/message/Reply.tsx index 85383cdb..82a9d919 100644 --- a/src/app/components/message/Reply.tsx +++ b/src/app/components/message/Reply.tsx @@ -1,7 +1,7 @@ import { Box, Icon, Icons, Text, as, color, toRem } from 'folds'; import { EventTimelineSet, MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk'; import { CryptoBackend } from 'matrix-js-sdk/lib/common-crypto/CryptoBackend'; -import React, { ReactNode, useEffect, useMemo, useState } from 'react'; +import React, { MouseEventHandler, ReactNode, useEffect, useMemo, useState } from 'react'; import to from 'await-to-js'; import classNames from 'classnames'; import colorMXID from '../../../util/colorMXID'; @@ -22,6 +22,7 @@ export const ReplyLayout = as<'div', ReplyLayoutProps>( ( ) ); +export const ThreadIndicator = as<'div'>(({ ...props }, ref) => ( + + + Threaded reply + +)); + type ReplyProps = { mx: MatrixClient; room: Room; - timelineSet?: EventTimelineSet; - eventId: string; + timelineSet?: EventTimelineSet | undefined; + replyEventId: string; + threadRootId?: string | undefined; + onClick?: MouseEventHandler | undefined; }; -export const Reply = as<'div', ReplyProps>(({ mx, room, timelineSet, eventId, ...props }, ref) => { +export const Reply = as<'div', ReplyProps>((_, ref) => { + const { mx, room, timelineSet, replyEventId, threadRootId, onClick, ...props } = _; const [replyEvent, setReplyEvent] = useState( - timelineSet?.findEventById(eventId) + timelineSet?.findEventById(replyEventId) ); const placeholderWidth = useMemo(() => randomNumberBetween(40, 400), []); @@ -62,7 +73,7 @@ export const Reply = as<'div', ReplyProps>(({ mx, room, timelineSet, eventId, .. useEffect(() => { let disposed = false; const loadEvent = async () => { - const [err, evt] = await to(mx.fetchRoomEvent(room.roomId, eventId)); + const [err, evt] = await to(mx.fetchRoomEvent(room.roomId, replyEventId)); const mEvent = new MatrixEvent(evt); if (disposed) return; if (err) { @@ -78,37 +89,43 @@ export const Reply = as<'div', ReplyProps>(({ mx, room, timelineSet, eventId, .. return () => { disposed = true; }; - }, [replyEvent, mx, room, eventId]); + }, [replyEvent, mx, room, replyEventId]); const badEncryption = replyEvent?.getContent().msgtype === 'm.bad.encrypted'; const bodyJSX = body ? scaleSystemEmoji(trimReplyFromBody(body)) : fallbackBody; return ( - - {getMemberDisplayName(room, sender) ?? getMxIdLocalPart(sender)} - - ) - } - {...props} - ref={ref} - > - {replyEvent !== undefined ? ( - - {badEncryption ? : bodyJSX} - - ) : ( - + + {threadRootId && ( + )} - + + {getMemberDisplayName(room, sender) ?? getMxIdLocalPart(sender)} + + ) + } + data-event-id={replyEventId} + onClick={onClick} + > + {replyEvent !== undefined ? ( + + {badEncryption ? : bodyJSX} + + ) : ( + + )} + + ); }); diff --git a/src/app/components/message/content/AudioContent.tsx b/src/app/components/message/content/AudioContent.tsx index 34777cc4..38fa9515 100644 --- a/src/app/components/message/content/AudioContent.tsx +++ b/src/app/components/message/content/AudioContent.tsx @@ -17,6 +17,8 @@ import { } from '../../../hooks/media'; import { useThrottle } from '../../../hooks/useThrottle'; import { secondsToMinutesAndSeconds } from '../../../utils/common'; +import { mxcUrlToHttp } from '../../../utils/matrix'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; const PLAY_TIME_THROTTLE_OPS = { wait: 500, @@ -44,11 +46,13 @@ export function AudioContent({ renderMediaControl, }: AudioContentProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [srcState, loadSrc] = useAsyncCallback( useCallback( - () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo), - [mx, url, mimeType, encInfo] + () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo), + [mx, url, useAuthentication, mimeType, encInfo] ) ); diff --git a/src/app/components/message/content/FileContent.tsx b/src/app/components/message/content/FileContent.tsx index f09c1e07..379d1456 100644 --- a/src/app/components/message/content/FileContent.tsx +++ b/src/app/components/message/content/FileContent.tsx @@ -30,6 +30,8 @@ import { } from '../../../utils/mimeTypes'; import * as css from './style.css'; import { stopPropagation } from '../../../utils/keyboard'; +import { mxcUrlToHttp } from '../../../utils/matrix'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; const renderErrorButton = (retry: () => void, text: string) => ( getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo), - [mx, url, mimeType, encInfo] + () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo), + [mx, url, useAuthentication, mimeType, encInfo] ); const [textState, loadText] = useAsyncCallback( @@ -166,14 +170,16 @@ export type ReadPdfFileProps = { }; export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer }: ReadPdfFileProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [pdfViewer, setPdfViewer] = useState(false); const [pdfState, loadPdf] = useAsyncCallback( useCallback(async () => { - const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo); + const httpUrl = await getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo); setPdfViewer(true); return httpUrl; - }, [mx, url, mimeType, encInfo]) + }, [mx, url, useAuthentication, mimeType, encInfo]) ); return ( @@ -240,13 +246,15 @@ export type DownloadFileProps = { }; export function DownloadFile({ body, mimeType, url, info, encInfo }: DownloadFileProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [downloadState, download] = useAsyncCallback( useCallback(async () => { - const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo); + const httpUrl = await getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo); FileSaver.saveAs(httpUrl, body); return httpUrl; - }, [mx, url, mimeType, encInfo, body]) + }, [mx, url, useAuthentication, mimeType, encInfo, body]) ); return downloadState.status === AsyncStatus.Error ? ( diff --git a/src/app/components/message/content/ImageContent.tsx b/src/app/components/message/content/ImageContent.tsx index 90c46354..798c60c5 100644 --- a/src/app/components/message/content/ImageContent.tsx +++ b/src/app/components/message/content/ImageContent.tsx @@ -27,6 +27,8 @@ import * as css from './style.css'; import { bytesToSize } from '../../../utils/common'; import { FALLBACK_MIMETYPE } from '../../../utils/mimeTypes'; import { stopPropagation } from '../../../utils/keyboard'; +import { mxcUrlToHttp } from '../../../utils/matrix'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; type RenderViewerProps = { src: string; @@ -69,6 +71,8 @@ export const ImageContent = as<'div', ImageContentProps>( ref ) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const blurHash = info?.[MATRIX_BLUR_HASH_PROPERTY_NAME]; const [load, setLoad] = useState(false); @@ -77,8 +81,8 @@ export const ImageContent = as<'div', ImageContentProps>( const [srcState, loadSrc] = useAsyncCallback( useCallback( - () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType || FALLBACK_MIMETYPE, encInfo), - [mx, url, mimeType, encInfo] + () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType || FALLBACK_MIMETYPE, encInfo), + [mx, url, useAuthentication, mimeType, encInfo] ) ); diff --git a/src/app/components/message/content/ThumbnailContent.tsx b/src/app/components/message/content/ThumbnailContent.tsx index 9d940f3a..4324376d 100644 --- a/src/app/components/message/content/ThumbnailContent.tsx +++ b/src/app/components/message/content/ThumbnailContent.tsx @@ -3,6 +3,8 @@ import { IThumbnailContent } from '../../../../types/matrix/common'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { getFileSrcUrl } from './util'; +import { mxcUrlToHttp } from '../../../utils/matrix'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; export type ThumbnailContentProps = { info: IThumbnailContent; @@ -10,6 +12,8 @@ export type ThumbnailContentProps = { }; export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [thumbSrcState, loadThumbSrc] = useAsyncCallback( useCallback(() => { @@ -19,11 +23,11 @@ export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) { throw new Error('Failed to load thumbnail'); } return getFileSrcUrl( - mx.mxcUrlToHttp(thumbMxcUrl) ?? '', + mxcUrlToHttp(mx, thumbMxcUrl, useAuthentication) ?? '', thumbInfo.mimetype, info.thumbnail_file ); - }, [mx, info]) + }, [mx, info, useAuthentication]) ); useEffect(() => { diff --git a/src/app/components/message/content/VideoContent.tsx b/src/app/components/message/content/VideoContent.tsx index b08512a4..e83e4595 100644 --- a/src/app/components/message/content/VideoContent.tsx +++ b/src/app/components/message/content/VideoContent.tsx @@ -25,6 +25,8 @@ import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { getFileSrcUrl } from './util'; import { bytesToSize } from '../../../../util/common'; import { millisecondsToMinutesAndSeconds } from '../../../utils/common'; +import { mxcUrlToHttp } from '../../../utils/matrix'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; type RenderVideoProps = { title: string; @@ -61,6 +63,8 @@ export const VideoContent = as<'div', VideoContentProps>( ref ) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const blurHash = info.thumbnail_info?.[MATRIX_BLUR_HASH_PROPERTY_NAME]; const [load, setLoad] = useState(false); @@ -68,8 +72,8 @@ export const VideoContent = as<'div', VideoContentProps>( const [srcState, loadSrc] = useAsyncCallback( useCallback( - () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo), - [mx, url, mimeType, encInfo] + () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo), + [mx, url, useAuthentication, mimeType, encInfo] ) ); diff --git a/src/app/components/page/Page.tsx b/src/app/components/page/Page.tsx index 4ccb1ec0..a8b9ea04 100644 --- a/src/app/components/page/Page.tsx +++ b/src/app/components/page/Page.tsx @@ -87,15 +87,17 @@ export const Page = as<'div'>(({ className, ...props }, ref) => ( /> )); -export const PageHeader = as<'div'>(({ className, ...props }, ref) => ( -
-)); +export const PageHeader = as<'div', css.PageHeaderVariants>( + ({ className, balance, ...props }, ref) => ( +
+ ) +); export const PageContent = as<'div'>(({ className, ...props }, ref) => (
diff --git a/src/app/components/page/style.css.ts b/src/app/components/page/style.css.ts index 4807a227..23f2da49 100644 --- a/src/app/components/page/style.css.ts +++ b/src/app/components/page/style.css.ts @@ -1,4 +1,5 @@ import { style } from '@vanilla-extract/css'; +import { recipe, RecipeVariants } from '@vanilla-extract/recipes'; import { DefaultReset, color, config, toRem } from 'folds'; export const PageNav = style({ @@ -33,11 +34,21 @@ export const PageNavContent = style({ paddingBottom: config.space.S700, }); -export const PageHeader = style({ - paddingLeft: config.space.S400, - paddingRight: config.space.S200, - borderBottomWidth: config.borderWidth.B300, +export const PageHeader = recipe({ + base: { + paddingLeft: config.space.S400, + paddingRight: config.space.S200, + borderBottomWidth: config.borderWidth.B300, + }, + variants: { + balance: { + true: { + paddingLeft: config.space.S200, + }, + }, + }, }); +export type PageHeaderVariants = RecipeVariants; export const PageContent = style([ DefaultReset, diff --git a/src/app/components/room-card/RoomCard.tsx b/src/app/components/room-card/RoomCard.tsx index 79dd87db..1ca7813f 100644 --- a/src/app/components/room-card/RoomCard.tsx +++ b/src/app/components/room-card/RoomCard.tsx @@ -21,7 +21,7 @@ import classNames from 'classnames'; import FocusTrap from 'focus-trap-react'; import * as css from './style.css'; import { RoomAvatar } from '../room-avatar'; -import { getMxIdLocalPart } from '../../utils/matrix'; +import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix'; import { nameInitials } from '../../utils/common'; import { millify } from '../../plugins/millify'; import { useMatrixClient } from '../../hooks/useMatrixClient'; @@ -32,6 +32,7 @@ import { useJoinedRoomId } from '../../hooks/useJoinedRoomId'; import { useElementSizeObserver } from '../../hooks/useElementSizeObserver'; import { getRoomAvatarUrl, getStateEvent } from '../../utils/room'; import { useStateEventCallback } from '../../hooks/useStateEventCallback'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; type GridColumnCount = '1' | '2' | '3'; const getGridColumnCount = (gridWidth: number): GridColumnCount => { @@ -138,6 +139,7 @@ type RoomCardProps = { topic?: string; memberCount?: number; roomType?: string; + viaServers?: string[]; onView?: (roomId: string) => void; renderTopicViewer: (name: string, topic: string, requestClose: () => void) => ReactNode; }; @@ -152,6 +154,7 @@ export const RoomCard = as<'div', RoomCardProps>( topic, memberCount, roomType, + viaServers, onView, renderTopicViewer, ...props @@ -159,6 +162,8 @@ export const RoomCard = as<'div', RoomCardProps>( ref ) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const joinedRoomId = useJoinedRoomId(allRooms, roomIdOrAlias); const joinedRoom = mx.getRoom(joinedRoomId); const [topicEvent, setTopicEvent] = useState(() => @@ -169,8 +174,8 @@ export const RoomCard = as<'div', RoomCardProps>( const fallbackTopic = roomIdOrAlias; const avatar = joinedRoom - ? getRoomAvatarUrl(mx, joinedRoom, 96) - : avatarUrl && mx.mxcUrlToHttp(avatarUrl, 96, 96, 'crop'); + ? getRoomAvatarUrl(mx, joinedRoom, 96, useAuthentication) + : avatarUrl && mxcUrlToHttp(mx, avatarUrl, useAuthentication, 96, 96, 'crop'); const roomName = joinedRoom?.name || name || fallbackName; const roomTopic = @@ -194,7 +199,7 @@ export const RoomCard = as<'div', RoomCardProps>( ); const [joinState, join] = useAsyncCallback( - useCallback(() => mx.joinRoom(roomIdOrAlias), [mx, roomIdOrAlias]) + useCallback(() => mx.joinRoom(roomIdOrAlias, { viaServers }), [mx, roomIdOrAlias, viaServers]) ); const joining = joinState.status === AsyncStatus.Loading || joinState.status === AsyncStatus.Success; diff --git a/src/app/components/room-intro/RoomIntro.tsx b/src/app/components/room-intro/RoomIntro.tsx index 0fed123d..28be5daf 100644 --- a/src/app/components/room-intro/RoomIntro.tsx +++ b/src/app/components/room-intro/RoomIntro.tsx @@ -6,7 +6,7 @@ import { openInviteUser } from '../../../client/action/navigation'; import { IRoomCreateContent, Membership, StateEvent } from '../../../types/matrix/room'; import { getMemberDisplayName, getStateEvent } from '../../utils/room'; import { useMatrixClient } from '../../hooks/useMatrixClient'; -import { getMxIdLocalPart } from '../../utils/matrix'; +import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import { timeDayMonthYear, timeHourMinute } from '../../utils/time'; import { useRoomNavigate } from '../../hooks/useRoomNavigate'; @@ -14,6 +14,7 @@ import { RoomAvatar } from '../room-avatar'; import { nameInitials } from '../../utils/common'; import { useRoomAvatar, useRoomName, useRoomTopic } from '../../hooks/useRoomMeta'; import { mDirectAtom } from '../../state/mDirectList'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; export type RoomIntroProps = { room: Room; @@ -21,6 +22,8 @@ export type RoomIntroProps = { export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const { navigateRoom } = useRoomNavigate(); const mDirects = useAtomValue(mDirectAtom); @@ -28,7 +31,7 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) => const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId)); const name = useRoomName(room); const topic = useRoomTopic(room); - const avatarHttpUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc) : undefined; + const avatarHttpUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication) : undefined; const createContent = createEvent?.getContent(); const ts = createEvent?.getTs(); diff --git a/src/app/components/url-preview/UrlPreviewCard.tsx b/src/app/components/url-preview/UrlPreviewCard.tsx index fc9229fa..c33b9850 100644 --- a/src/app/components/url-preview/UrlPreviewCard.tsx +++ b/src/app/components/url-preview/UrlPreviewCard.tsx @@ -9,12 +9,17 @@ import { useIntersectionObserver, } from '../../hooks/useIntersectionObserver'; import * as css from './UrlPreviewCard.css'; +import { tryDecodeURIComponent } from '../../utils/dom'; +import { mxcUrlToHttp } from '../../utils/matrix'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; const linkStyles = { color: color.Success.Main }; export const UrlPreviewCard = as<'div', { url: string; ts: number }>( ({ url, ts, ...props }, ref) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [previewStatus, loadPreview] = useAsyncCallback( useCallback(() => mx.getUrlPreview(url, ts), [url, ts, mx]) ); @@ -26,7 +31,7 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number }>( if (previewStatus.status === AsyncStatus.Error) return null; const renderContent = (prev: IPreviewUrlResponse) => { - const imgUrl = mx.mxcUrlToHttp(prev['og:image'] || '', 256, 256, 'scale', false); + const imgUrl = mxcUrlToHttp(mx, prev['og:image'] || '', useAuthentication, 256, 256, 'scale', false); return ( <> @@ -43,7 +48,7 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number }>( priority="300" > {typeof prev['og:site_name'] === 'string' && `${prev['og:site_name']} | `} - {decodeURIComponent(url)} + {tryDecodeURIComponent(url)} {prev['og:title']} diff --git a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx index 2b9c3e50..028cd560 100644 --- a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx +++ b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Scroll, Text, toRem } from 'folds'; +import { Box, Icon, IconButton, Icons, Scroll, Text, toRem } from 'folds'; import { useAtomValue } from 'jotai'; import { RoomCard } from '../../components/room-card'; import { RoomTopicViewer } from '../../components/room-topic-viewer'; @@ -8,28 +8,48 @@ import { RoomSummaryLoader } from '../../components/RoomSummaryLoader'; import { useRoomNavigate } from '../../hooks/useRoomNavigate'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { allRoomsAtom } from '../../state/room-list/roomList'; +import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../components/BackRouteHandler'; -type JoinBeforeNavigateProps = { roomIdOrAlias: string }; -export function JoinBeforeNavigate({ roomIdOrAlias }: JoinBeforeNavigateProps) { +type JoinBeforeNavigateProps = { roomIdOrAlias: string; eventId?: string; viaServers?: string[] }; +export function JoinBeforeNavigate({ + roomIdOrAlias, + eventId, + viaServers, +}: JoinBeforeNavigateProps) { const mx = useMatrixClient(); const allRooms = useAtomValue(allRoomsAtom); const { navigateRoom, navigateSpace } = useRoomNavigate(); + const screenSize = useScreenSizeContext(); const handleView = (roomId: string) => { if (mx.getRoom(roomId)?.isSpaceRoom()) { navigateSpace(roomId); return; } - navigateRoom(roomId); + navigateRoom(roomId, eventId); }; return ( - - - - {roomIdOrAlias} - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + + {roomIdOrAlias} + + @@ -46,6 +66,7 @@ export function JoinBeforeNavigate({ roomIdOrAlias }: JoinBeforeNavigateProps) { topic={summary?.topic} memberCount={summary?.num_joined_members} roomType={summary?.room_type} + viaServers={viaServers} renderTopicViewer={(name, topic, requestClose) => ( )} diff --git a/src/app/features/lobby/LobbyHeader.tsx b/src/app/features/lobby/LobbyHeader.tsx index e01d3ad5..ed5373b3 100644 --- a/src/app/features/lobby/LobbyHeader.tsx +++ b/src/app/features/lobby/LobbyHeader.tsx @@ -31,6 +31,10 @@ import { IPowerLevels, usePowerLevelsAPI } from '../../hooks/usePowerLevels'; import { UseStateProvider } from '../../components/UseStateProvider'; import { LeaveSpacePrompt } from '../../components/leave-space-prompt'; import { stopPropagation } from '../../utils/keyboard'; +import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../components/BackRouteHandler'; +import { mxcUrlToHttp } from '../../utils/matrix'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; type LobbyMenuProps = { roomId: string; @@ -120,55 +124,88 @@ type LobbyHeaderProps = { }; export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const space = useSpace(); const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer'); const [menuAnchor, setMenuAnchor] = useState(); + const screenSize = useScreenSizeContext(); const name = useRoomName(space); const avatarMxc = useRoomAvatar(space); - const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined; + const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined : undefined; const handleOpenMenu: MouseEventHandler = (evt) => { setMenuAnchor(evt.currentTarget.getBoundingClientRect()); }; return ( - + - - - {showProfile && ( - <> - - {nameInitials(name)}} - /> - - - {name} - - + {screenSize === ScreenSize.Mobile ? ( + <> + + + {(onBack) => ( + + + + )} + + + + {showProfile && ( + + {name} + + )} + + + ) : ( + <> + + + {showProfile && ( + <> + + {nameInitials(name)}} + /> + + + {name} + + + )} + + + )} + + {screenSize !== ScreenSize.Mobile && ( + + Members + + } + > + {(triggerRef) => ( + setPeopleDrawer((drawer) => !drawer)}> + + + )} + )} - - - - Members - - } - > - {(triggerRef) => ( - setPeopleDrawer((drawer) => !drawer)}> - - - )} - ( ref ) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const { roomId, content } = item; const room = getRoom(roomId); const targetRef = useRef(null); @@ -364,7 +368,7 @@ export const RoomItemCard = as<'div', RoomItemCardProps>( name={localSummary.name} topic={localSummary.topic} avatarUrl={ - dm ? getDirectRoomAvatarUrl(mx, room, 96) : getRoomAvatarUrl(mx, room, 96) + dm ? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication) : getRoomAvatarUrl(mx, room, 96, useAuthentication) } memberCount={localSummary.memberCount} suggested={content.suggested} @@ -418,8 +422,8 @@ export const RoomItemCard = as<'div', RoomItemCardProps>( topic={summaryState.data.topic} avatarUrl={ summaryState.data?.avatar_url - ? mx.mxcUrlToHttp(summaryState.data.avatar_url, 96, 96, 'crop') ?? - undefined + ? mxcUrlToHttp(mx, summaryState.data.avatar_url, useAuthentication, 96, 96, 'crop') ?? + undefined : undefined } memberCount={summaryState.data.num_joined_members} diff --git a/src/app/features/lobby/SpaceItem.tsx b/src/app/features/lobby/SpaceItem.tsx index 04f7e2cc..3e3c3214 100644 --- a/src/app/features/lobby/SpaceItem.tsx +++ b/src/app/features/lobby/SpaceItem.tsx @@ -35,6 +35,8 @@ import { ErrorCode } from '../../cs-errorcode'; import { useDraggableItem } from './DnD'; import { openCreateRoom, openSpaceAddExisting } from '../../../client/action/navigation'; import { stopPropagation } from '../../utils/keyboard'; +import { mxcUrlToHttp } from '../../utils/matrix'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; function SpaceProfileLoading() { return ( @@ -408,6 +410,8 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>( ref ) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const { roomId, content } = item; const space = getRoom(roomId); const targetRef = useRef(null); @@ -432,7 +436,7 @@ export const SpaceItemCard = as<'div', SpaceItemCardProps>( ( name={summaryState.data.name || summaryState.data.canonical_alias || roomId} avatarUrl={ summaryState.data?.avatar_url - ? mx.mxcUrlToHttp(summaryState.data.avatar_url, 96, 96, 'crop') ?? - undefined + ? mxcUrlToHttp(mx, summaryState.data.avatar_url, useAuthentication, 96, 96, 'crop') ?? + undefined : undefined } suggested={content.suggested} diff --git a/src/app/features/message-search/SearchResultGroup.tsx b/src/app/features/message-search/SearchResultGroup.tsx index 6f84f621..a3a67eda 100644 --- a/src/app/features/message-search/SearchResultGroup.tsx +++ b/src/app/features/message-search/SearchResultGroup.tsx @@ -3,13 +3,17 @@ import React, { MouseEventHandler, useMemo } from 'react'; import { IEventWithRoomId, JoinRule, RelationType, Room } from 'matrix-js-sdk'; import { HTMLReactParserOptions } from 'html-react-parser'; import { Avatar, Box, Chip, Header, Icon, Icons, Text, config } from 'folds'; +import { Opts as LinkifyOpts } from 'linkifyjs'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { + factoryRenderLinkifyWithMention, getReactCustomHtmlParser, + LINKIFY_OPTS, makeHighlightRegex, + makeMentionCustomProps, + renderMatrixMention, } from '../../plugins/react-custom-html-parser'; -import { getMxIdLocalPart, isRoomId, isUserId } from '../../utils/matrix'; -import { openJoinAlias, openProfileViewer } from '../../../client/action/navigation'; +import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix'; import { useMatrixEventRenderer } from '../../hooks/useMatrixEventRenderer'; import { GetContentCallback, MessageEvent, StateEvent } from '../../../types/matrix/room'; import { @@ -31,8 +35,10 @@ import { getMemberAvatarMxc, getMemberDisplayName, getRoomAvatarUrl } from '../. import colorMXID from '../../../util/colorMXID'; import { ResultItem } from './useMessageSearch'; import { SequenceCard } from '../../components/sequence-card'; -import { useRoomNavigate } from '../../hooks/useRoomNavigate'; import { UserAvatar } from '../../components/user-avatar'; +import { useMentionClickHandler } from '../../hooks/useMentionClickHandler'; +import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; type SearchResultGroupProps = { room: Room; @@ -51,38 +57,32 @@ export function SearchResultGroup({ onOpen, }: SearchResultGroupProps) { const mx = useMatrixClient(); - const { navigateRoom, navigateSpace } = useRoomNavigate(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const highlightRegex = useMemo(() => makeHighlightRegex(highlights), [highlights]); + const mentionClickHandler = useMentionClickHandler(room.roomId); + const spoilerClickHandler = useSpoilerClickHandler(); + + const linkifyOpts = useMemo( + () => ({ + ...LINKIFY_OPTS, + render: factoryRenderLinkifyWithMention((href) => + renderMatrixMention(mx, room.roomId, href, makeMentionCustomProps(mentionClickHandler)) + ), + }), + [mx, room, mentionClickHandler] + ); const htmlReactParserOptions = useMemo( () => - getReactCustomHtmlParser(mx, room, { + getReactCustomHtmlParser(mx, room.roomId, { + linkifyOpts, highlightRegex, - handleSpoilerClick: (evt) => { - const target = evt.currentTarget; - if (target.getAttribute('aria-pressed') === 'true') { - evt.stopPropagation(); - target.setAttribute('aria-pressed', 'false'); - target.style.cursor = 'initial'; - } - }, - handleMentionClick: (evt) => { - const target = evt.currentTarget; - const mentionId = target.getAttribute('data-mention-id'); - if (typeof mentionId !== 'string') return; - if (isUserId(mentionId)) { - openProfileViewer(mentionId, room.roomId); - return; - } - if (isRoomId(mentionId) && mx.getRoom(mentionId)) { - if (mx.getRoom(mentionId)?.isSpaceRoom()) navigateSpace(mentionId); - else navigateRoom(mentionId); - return; - } - openJoinAlias(mentionId); - }, + useAuthentication, + handleSpoilerClick: spoilerClickHandler, + handleMentionClick: mentionClickHandler, }), - [mx, room, highlightRegex, navigateRoom, navigateSpace] + [mx, room, linkifyOpts, highlightRegex, mentionClickHandler, spoilerClickHandler, useAuthentication] ); const renderMatrixEvent = useMatrixEventRenderer<[IEventWithRoomId, string, GetContentCallback]>( @@ -101,6 +101,7 @@ export function SearchResultGroup({ mediaAutoLoad={mediaAutoLoad} urlPreview={urlPreview} htmlReactParserOptions={htmlReactParserOptions} + linkifyOpts={linkifyOpts} highlightRegex={highlightRegex} outlineAttachment /> @@ -151,7 +152,7 @@ export function SearchResultGroup({ } ); - const handleOpenClick: MouseEventHandler = (evt) => { + const handleOpenClick: MouseEventHandler = (evt) => { const eventId = evt.currentTarget.getAttribute('data-event-id'); if (!eventId) return; onOpen(room.roomId, eventId); @@ -164,7 +165,7 @@ export function SearchResultGroup({ ( @@ -186,15 +187,16 @@ export function SearchResultGroup({ event.sender; const senderAvatarMxc = getMemberAvatarMxc(room, event.sender); + const relation = event.content['m.relates_to']; const mainEventId = - event.content['m.relates_to']?.rel_type === RelationType.Replace - ? event.content['m.relates_to'].event_id - : event.event_id; + relation?.rel_type === RelationType.Replace ? relation.event_id : event.event_id; const getContent = (() => event.content['m.new_content'] ?? event.content) as GetContentCallback; - const replyEventId = event.content['m.relates_to']?.['m.in_reply_to']?.event_id; + const replyEventId = relation?.['m.in_reply_to']?.event_id; + const threadRootId = + relation?.rel_type === RelationType.Thread ? relation.event_id : undefined; return ( {replyEventId && ( )} diff --git a/src/app/features/room-nav/RoomNavItem.tsx b/src/app/features/room-nav/RoomNavItem.tsx index 281c5b77..c525ab2a 100644 --- a/src/app/features/room-nav/RoomNavItem.tsx +++ b/src/app/features/room-nav/RoomNavItem.tsx @@ -28,25 +28,25 @@ import { useRoomUnread } from '../../state/hooks/unread'; import { roomToUnreadAtom } from '../../state/room/roomToUnread'; import { usePowerLevels, usePowerLevelsAPI } from '../../hooks/usePowerLevels'; import { copyToClipboard } from '../../utils/dom'; -import { getOriginBaseUrl, withOriginBaseUrl } from '../../pages/pathUtils'; import { markAsRead } from '../../../client/action/notifications'; import { openInviteUser, toggleRoomSettings } from '../../../client/action/navigation'; import { UseStateProvider } from '../../components/UseStateProvider'; import { LeaveRoomPrompt } from '../../components/leave-room-prompt'; -import { useClientConfig } from '../../hooks/useClientConfig'; import { useRoomTypingMember } from '../../hooks/useRoomTypingMembers'; import { TypingIndicator } from '../../components/typing-indicator'; import { stopPropagation } from '../../utils/keyboard'; +import { getMatrixToRoom } from '../../plugins/matrix-to'; +import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix'; +import { getViaServers } from '../../plugins/via-servers'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; type RoomNavItemMenuProps = { room: Room; - linkPath: string; requestClose: () => void; }; const RoomNavItemMenu = forwardRef( - ({ room, linkPath, requestClose }, ref) => { + ({ room, requestClose }, ref) => { const mx = useMatrixClient(); - const { hashRouter } = useClientConfig(); const unread = useRoomUnread(room.roomId, roomToUnreadAtom); const powerLevels = usePowerLevels(room); const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); @@ -63,7 +63,9 @@ const RoomNavItemMenu = forwardRef( }; const handleCopyLink = () => { - copyToClipboard(withOriginBaseUrl(getOriginBaseUrl(hashRouter), linkPath)); + const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, room.roomId); + const viaServers = isRoomAlias(roomIdOrAlias) ? undefined : getViaServers(room); + copyToClipboard(getMatrixToRoom(roomIdOrAlias, viaServers)); requestClose(); }; @@ -174,6 +176,8 @@ export function RoomNavItem({ linkPath, }: RoomNavItemProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [hover, setHover] = useState(false); const { hoverProps } = useHover({ onHoverChange: setHover }); const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover }); @@ -216,7 +220,7 @@ export function RoomNavItem({ ( @@ -273,11 +277,7 @@ export function RoomNavItem({ escapeDeactivates: stopPropagation, }} > - setMenuAnchor(undefined)} - /> + setMenuAnchor(undefined)} /> } > diff --git a/src/app/features/room/MembersDrawer.tsx b/src/app/features/room/MembersDrawer.tsx index 15d07412..1b538ffc 100644 --- a/src/app/features/room/MembersDrawer.tsx +++ b/src/app/features/room/MembersDrawer.tsx @@ -55,6 +55,7 @@ import { ScrollTopContainer } from '../../components/scroll-top-container'; import { UserAvatar } from '../../components/user-avatar'; import { useRoomTypingMember } from '../../hooks/useRoomTypingMembers'; import { stopPropagation } from '../../utils/keyboard'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; export const MembershipFilters = { filterJoined: (m: RoomMember) => m.membership === Membership.Join, @@ -171,6 +172,8 @@ type MembersDrawerProps = { }; export function MembersDrawer({ room, members }: MembersDrawerProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const scrollRef = useRef(null); const searchInputRef = useRef(null); const scrollTopAnchorRef = useRef(null); @@ -426,9 +429,8 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) { }} after={} > - {`${result.items.length || 'No'} ${ - result.items.length === 1 ? 'Result' : 'Results' - }`} + {`${result.items.length || 'No'} ${result.items.length === 1 ? 'Result' : 'Results' + }`} ) } @@ -483,14 +485,16 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) { const member = tagOrMember; const name = getName(member); - const avatarUrl = member.getAvatarUrl( - mx.baseUrl, + const avatarMxcUrl = member.getMxcAvatarUrl(); + const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp( + avatarMxcUrl, 100, 100, 'crop', undefined, - false - ); + false, + useAuthentication + ) : undefined; return ( ( ({ editor, fileDropContainerRef, roomId, room }, ref) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline'); const [isMarkdown] = useSetting(settingsAtom, 'isMarkdown'); const commands = useCommands(mx, room); @@ -186,9 +189,8 @@ export const RoomInput = forwardRef( Transforms.insertFragment(editor, msgDraft); }, [editor, msgDraft]); - useEffect(() => { - if (!mobileOrTablet()) ReactEditor.focus(editor); - return () => { + useEffect( + () => () => { if (!isEmptyEditor(editor)) { const parsedDraft = JSON.parse(JSON.stringify(editor.children)); setMsgDraft(parsedDraft); @@ -197,8 +199,9 @@ export const RoomInput = forwardRef( } resetEditor(editor); resetEditorHistory(editor); - }; - }, [roomId, editor, setMsgDraft]); + }, + [roomId, editor, setMsgDraft] + ); const handleRemoveUpload = useCallback( (upload: TUploadContent | TUploadContent[]) => { @@ -310,6 +313,11 @@ export const RoomInput = forwardRef( event_id: replyDraft.eventId, }, }; + if (replyDraft.relation?.rel_type === RelationType.Thread) { + content['m.relates_to'].event_id = replyDraft.relation.event_id; + content['m.relates_to'].rel_type = RelationType.Thread; + content['m.relates_to'].is_falling_back = false; + } } mx.sendMessage(roomId, content); resetEditor(editor); @@ -361,7 +369,7 @@ export const RoomInput = forwardRef( }; const handleStickerSelect = async (mxc: string, shortcode: string, label: string) => { - const stickerUrl = mx.mxcUrlToHttp(mxc); + const stickerUrl = mxcUrlToHttp(mx, mxc, useAuthentication); if (!stickerUrl) return; const info = await getImageInfo( @@ -489,22 +497,25 @@ export const RoomInput = forwardRef( > - + {replyDraft.relation?.rel_type === RelationType.Thread && } + + + {getMemberDisplayName(room, replyDraft.userId) ?? + getMxIdLocalPart(replyDraft.userId) ?? + replyDraft.userId} + + + } + > - - {getMemberDisplayName(room, replyDraft.userId) ?? - getMxIdLocalPart(replyDraft.userId) ?? - replyDraft.userId} - + {trimReplyFromBody(replyDraft.body)} - } - > - - {trimReplyFromBody(replyDraft.body)} - - + +
) diff --git a/src/app/features/room/RoomTimeline.tsx b/src/app/features/room/RoomTimeline.tsx index 170fdfaa..9127c2ec 100644 --- a/src/app/features/room/RoomTimeline.tsx +++ b/src/app/features/room/RoomTimeline.tsx @@ -16,6 +16,7 @@ import { EventTimeline, EventTimelineSet, EventTimelineSetHandlerMap, + IContent, IEncryptedFile, MatrixClient, MatrixEvent, @@ -45,13 +46,13 @@ import { toRem, } from 'folds'; import { isKeyHotkey } from 'is-hotkey'; +import { Opts as LinkifyOpts } from 'linkifyjs'; +import { useTranslation } from 'react-i18next'; import { decryptFile, eventWithShortcode, factoryEventSentBy, getMxIdLocalPart, - isRoomId, - isUserId, } from '../../utils/matrix'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { useVirtualPaginator, ItemRange } from '../../hooks/useVirtualPaginator'; @@ -70,7 +71,13 @@ import { ImageContent, EventContent, } from '../../components/message'; -import { getReactCustomHtmlParser } from '../../plugins/react-custom-html-parser'; +import { + factoryRenderLinkifyWithMention, + getReactCustomHtmlParser, + LINKIFY_OPTS, + makeMentionCustomProps, + renderMatrixMention, +} from '../../plugins/react-custom-html-parser'; import { canEditEvent, decryptAllTimelineEvent, @@ -85,7 +92,7 @@ import { } from '../../utils/room'; import { useSetting } from '../../state/hooks/settings'; import { settingsAtom } from '../../state/settings'; -import { openJoinAlias, openProfileViewer } from '../../../client/action/navigation'; +import { openProfileViewer } from '../../../client/action/navigation'; import { useMatrixEventRenderer } from '../../hooks/useMatrixEventRenderer'; import { Reactions, Message, Event, EncryptedContent } from './message'; import { useMemberEventParser } from '../../hooks/useMemberEventParser'; @@ -109,10 +116,13 @@ import { useDocumentFocusChange } from '../../hooks/useDocumentFocusChange'; import { RenderMessageContent } from '../../components/RenderMessageContent'; import { Image } from '../../components/media'; import { ImageViewer } from '../../components/image-viewer'; -import { useRoomNavigate } from '../../hooks/useRoomNavigate'; import { roomToParentsAtom } from '../../state/room/roomToParents'; import { useRoomUnread } from '../../state/hooks/unread'; import { roomToUnreadAtom } from '../../state/room/roomToUnread'; +import { useMentionClickHandler } from '../../hooks/useMentionClickHandler'; +import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler'; +import { useRoomNavigate } from '../../hooks/useRoomNavigate'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; const TimelineFloat = as<'div', css.TimelineFloatVariants>( ({ position, className, ...props }, ref) => ( @@ -301,9 +311,9 @@ const useTimelinePagination = ( range: offsetRange > 0 ? { - start: currentTimeline.range.start + offsetRange, - end: currentTimeline.range.end + offsetRange, - } + start: currentTimeline.range.start + offsetRange, + end: currentTimeline.range.end + offsetRange, + } : { ...currentTimeline.range }, })); }; @@ -323,7 +333,7 @@ const useTimelinePagination = ( if ( !paginationToken && getTimelinesEventsCount(lTimelines) !== - getTimelinesEventsCount(getLinkedTimelines(timelineToPaginate)) + getTimelinesEventsCount(getLinkedTimelines(timelineToPaginate)) ) { recalibratePagination(lTimelines, timelinesEventsCount, backwards); return; @@ -430,6 +440,8 @@ const getRoomUnreadInfo = (room: Room, scrollTo = false) => { export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimelineProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const encryptedRoom = mx.isRoomEncrypted(room.roomId); const [messageLayout] = useSetting(settingsAtom, 'messageLayout'); const [messageSpacing] = useSetting(settingsAtom, 'messageSpacing'); @@ -447,9 +459,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const canRedact = canDoAction('redact', myPowerLevel); const canSendReaction = canSendEvent(MessageEvent.Reaction, myPowerLevel); const [editId, setEditId] = useState(); - const { navigateRoom, navigateSpace } = useRoomNavigate(); const roomToParents = useAtomValue(roomToParentsAtom); const unread = useRoomUnread(room.roomId, roomToUnreadAtom); + const { navigateRoom } = useRoomNavigate(); + const mentionClickHandler = useMentionClickHandler(room.roomId); + const spoilerClickHandler = useSpoilerClickHandler(); const imagePackRooms: Room[] = useMemo(() => { const allParentSpaces = [room.roomId].concat( @@ -481,42 +495,32 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const [focusItem, setFocusItem] = useState< | { - index: number; - scrollTo: boolean; - highlight: boolean; - } + index: number; + scrollTo: boolean; + highlight: boolean; + } | undefined >(); const alive = useAlive(); + const linkifyOpts = useMemo( + () => ({ + ...LINKIFY_OPTS, + render: factoryRenderLinkifyWithMention((href) => + renderMatrixMention(mx, room.roomId, href, makeMentionCustomProps(mentionClickHandler)) + ), + }), + [mx, room, mentionClickHandler] + ); const htmlReactParserOptions = useMemo( () => - getReactCustomHtmlParser(mx, room, { - handleSpoilerClick: (evt) => { - const target = evt.currentTarget; - if (target.getAttribute('aria-pressed') === 'true') { - evt.stopPropagation(); - target.setAttribute('aria-pressed', 'false'); - target.style.cursor = 'initial'; - } - }, - handleMentionClick: (evt) => { - const target = evt.currentTarget; - const mentionId = target.getAttribute('data-mention-id'); - if (typeof mentionId !== 'string') return; - if (isUserId(mentionId)) { - openProfileViewer(mentionId, room.roomId); - return; - } - if (isRoomId(mentionId) && mx.getRoom(mentionId)) { - if (mx.getRoom(mentionId)?.isSpaceRoom()) navigateSpace(mentionId); - else navigateRoom(mentionId); - return; - } - openJoinAlias(mentionId); - }, + getReactCustomHtmlParser(mx, room.roomId, { + linkifyOpts, + useAuthentication, + handleSpoilerClick: spoilerClickHandler, + handleMentionClick: mentionClickHandler, }), - [mx, room, navigateRoom, navigateSpace] + [mx, room, linkifyOpts, spoilerClickHandler, mentionClickHandler, useAuthentication] ); const parseMemberEvent = useMemberEventParser(); @@ -599,7 +603,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli // so timeline can be updated with evt like: edits, reactions etc if (atBottomRef.current) { if (document.hasFocus() && (!unreadInfo || mEvt.getSender() === mx.getUserId())) { - requestAnimationFrame(() => markAsRead(mx, mEvt.getRoomId())); + requestAnimationFrame(() => markAsRead(mx, mEvt.getRoomId()!)); } if (document.hasFocus()) { @@ -728,6 +732,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const editableEvtId = editableEvt?.getId(); if (!editableEvtId) return; setEditId(editableEvtId); + evt.preventDefault() } }, [mx, room, editor] @@ -821,6 +826,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli }, [scrollToElement, editId]); const handleJumpToLatest = () => { + if (eventId) { + navigateRoom(room.roomId, undefined, { replace: true }); + } setTimeline(getInitialTimeline(room)); scrollToBottomRef.current.count += 1; scrollToBottomRef.current.smooth = false; @@ -837,13 +845,13 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli markAsRead(mx, room.roomId); }; - const handleOpenReply: MouseEventHandler = useCallback( + const handleOpenReply: MouseEventHandler = useCallback( async (evt) => { - const replyId = evt.currentTarget.getAttribute('data-reply-id'); - if (typeof replyId !== 'string') return; - const replyTimeline = getEventTimeline(room, replyId); + const targetId = evt.currentTarget.getAttribute('data-event-id'); + if (!targetId) return; + const replyTimeline = getEventTimeline(room, targetId); const absoluteIndex = - replyTimeline && getEventIdAbsoluteIndex(timeline.linkedTimelines, replyTimeline, replyId); + replyTimeline && getEventIdAbsoluteIndex(timeline.linkedTimelines, replyTimeline, targetId); if (typeof absoluteIndex === 'number') { scrollToItem(absoluteIndex, { @@ -858,7 +866,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli }); } else { setTimeline(getEmptyTimeline()); - loadEventTimeline(replyId); + loadEventTimeline(targetId); } }, [room, timeline, scrollToItem, loadEventTimeline] @@ -909,8 +917,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const replyEvt = room.findEventById(replyId); if (!replyEvt) return; const editedReply = getEditedEvent(replyId, replyEvt, room.getUnfilteredTimelineSet()); - const { body, formatted_body: formattedBody }: Record = - editedReply?.getContent()['m.new_content'] ?? replyEvt.getContent(); + const content: IContent = editedReply?.getContent()['m.new_content'] ?? replyEvt.getContent(); + const { body, formatted_body: formattedBody } = content; + const { 'm.relates_to': relation } = replyEvt.getOriginalContent(); const senderId = replyEvt.getSender(); if (senderId && typeof body === 'string') { setReplyDraft({ @@ -918,6 +927,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli eventId: replyId, body, formattedBody, + relation, }); setTimeout(() => ReactEditor.focus(editor), 100); } @@ -959,6 +969,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli }, [editor] ); + const { t } = useTranslation(); const renderMatrixEvent = useMatrixEventRenderer< [string, MatrixEvent, number, EventTimelineSet, boolean] @@ -968,7 +979,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const reactionRelations = getEventReactions(timelineSet, mEventId); const reactions = reactionRelations && reactionRelations.getSortedAnnotationsByKey(); const hasReactions = reactions && reactions.length > 0; - const { replyEventId } = mEvent; + const { replyEventId, threadRootId } = mEvent; const highlighted = focusItem?.index === item && focusItem.highlight; const editedEvent = getEditedEvent(mEventId, mEvent, timelineSet); @@ -1003,12 +1014,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli reply={ replyEventId && ( ) @@ -1038,6 +1048,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli mediaAutoLoad={mediaAutoLoad} urlPreview={showUrlPreview} htmlReactParserOptions={htmlReactParserOptions} + linkifyOpts={linkifyOpts} outlineAttachment={messageLayout === 2} /> )} @@ -1048,7 +1059,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const reactionRelations = getEventReactions(timelineSet, mEventId); const reactions = reactionRelations && reactionRelations.getSortedAnnotationsByKey(); const hasReactions = reactions && reactions.length > 0; - const { replyEventId } = mEvent; + const { replyEventId, threadRootId } = mEvent; const highlighted = focusItem?.index === item && focusItem.highlight; return ( @@ -1075,12 +1086,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli reply={ replyEventId && ( ) @@ -1134,6 +1144,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli mediaAutoLoad={mediaAutoLoad} urlPreview={showUrlPreview} htmlReactParserOptions={htmlReactParserOptions} + linkifyOpts={linkifyOpts} outlineAttachment={messageLayout === 2} /> ); @@ -1272,7 +1283,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli {senderName} - {' changed room name'} + {t('Organisms.RoomCommon.changed_room_name')} } @@ -1461,14 +1472,14 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli const eventJSX = reactionOrEditEvent(mEvent) ? null : renderMatrixEvent( - mEvent.getType(), - typeof mEvent.getStateKey() === 'string', - mEventId, - mEvent, - item, - timelineSet, - collapsed - ); + mEvent.getType(), + typeof mEvent.getStateKey() === 'string', + mEventId, + mEvent, + item, + timelineSet, + collapsed + ); prevEvent = mEvent; isPrevRendered = !!eventJSX; @@ -1550,9 +1561,8 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli {!canPaginateBack && rangeAtStart && getItems().length > 0 && (
diff --git a/src/app/features/room/RoomTombstone.tsx b/src/app/features/room/RoomTombstone.tsx index e3f8251f..24f0b80e 100644 --- a/src/app/features/room/RoomTombstone.tsx +++ b/src/app/features/room/RoomTombstone.tsx @@ -3,11 +3,11 @@ import { Box, Button, Spinner, Text, color } from 'folds'; import * as css from './RoomTombstone.css'; import { useMatrixClient } from '../../hooks/useMatrixClient'; -import { genRoomVia } from '../../../util/matrixUtil'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import { Membership } from '../../../types/matrix/room'; import { RoomInputPlaceholder } from './RoomInputPlaceholder'; import { useRoomNavigate } from '../../hooks/useRoomNavigate'; +import { getViaServers } from '../../plugins/via-servers'; type RoomTombstoneProps = { roomId: string; body?: string; replacementRoomId: string }; export function RoomTombstone({ roomId, body, replacementRoomId }: RoomTombstoneProps) { @@ -17,7 +17,7 @@ export function RoomTombstone({ roomId, body, replacementRoomId }: RoomTombstone const [joinState, handleJoin] = useAsyncCallback( useCallback(() => { const currentRoom = mx.getRoom(roomId); - const via = currentRoom ? genRoomVia(currentRoom) : []; + const via = currentRoom ? getViaServers(currentRoom) : []; return mx.joinRoom(replacementRoomId, { viaServers: via, }); diff --git a/src/app/features/room/RoomView.tsx b/src/app/features/room/RoomView.tsx index 3eabd528..250afc93 100644 --- a/src/app/features/room/RoomView.tsx +++ b/src/app/features/room/RoomView.tsx @@ -25,6 +25,7 @@ const shouldFocusMessageField = (evt: KeyboardEvent): boolean => { if (evt.metaKey || evt.altKey || evt.ctrlKey) { return false; } + // do not focus on F keys if (/^F\d+$/.test(code)) return false; @@ -36,6 +37,9 @@ const shouldFocusMessageField = (evt: KeyboardEvent): boolean => { code.startsWith('Alt') || code.startsWith('Control') || code.startsWith('Arrow') || + code.startsWith('Page') || + code.startsWith('End') || + code.startsWith('Home') || code === 'Tab' || code === 'Space' || code === 'Enter' || diff --git a/src/app/features/room/RoomViewHeader.tsx b/src/app/features/room/RoomViewHeader.tsx index 6750f923..eaa90970 100644 --- a/src/app/features/room/RoomViewHeader.tsx +++ b/src/app/features/room/RoomViewHeader.tsx @@ -20,7 +20,7 @@ import { PopOut, RectCords, } from 'folds'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { JoinRule, Room } from 'matrix-js-sdk'; import { useAtomValue } from 'jotai'; @@ -35,15 +35,8 @@ import { useRoom } from '../../hooks/useRoom'; import { useSetSetting } from '../../state/hooks/settings'; import { settingsAtom } from '../../state/settings'; import { useSpaceOptionally } from '../../hooks/useSpace'; -import { - getHomeSearchPath, - getOriginBaseUrl, - getSpaceSearchPath, - joinPathComponent, - withOriginBaseUrl, - withSearchParam, -} from '../../pages/pathUtils'; -import { getCanonicalAliasOrRoomId } from '../../utils/matrix'; +import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils'; +import { getCanonicalAliasOrRoomId, isRoomAlias, mxcUrlToHttp } from '../../utils/matrix'; import { _SearchPathSearchParams } from '../../pages/paths'; import * as css from './RoomViewHeader.css'; import { useRoomUnread } from '../../state/hooks/unread'; @@ -55,132 +48,135 @@ import { copyToClipboard } from '../../utils/dom'; import { LeaveRoomPrompt } from '../../components/leave-room-prompt'; import { useRoomAvatar, useRoomName, useRoomTopic } from '../../hooks/useRoomMeta'; import { mDirectAtom } from '../../state/mDirectList'; -import { useClientConfig } from '../../hooks/useClientConfig'; import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; import { stopPropagation } from '../../utils/keyboard'; +import { getMatrixToRoom } from '../../plugins/matrix-to'; +import { getViaServers } from '../../plugins/via-servers'; +import { BackRouteHandler } from '../../components/BackRouteHandler'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; type RoomMenuProps = { room: Room; - linkPath: string; requestClose: () => void; }; -const RoomMenu = forwardRef( - ({ room, linkPath, requestClose }, ref) => { - const mx = useMatrixClient(); - const { hashRouter } = useClientConfig(); - const unread = useRoomUnread(room.roomId, roomToUnreadAtom); - const powerLevels = usePowerLevelsContext(); - const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); - const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? '')); +const RoomMenu = forwardRef(({ room, requestClose }, ref) => { + const mx = useMatrixClient(); + const unread = useRoomUnread(room.roomId, roomToUnreadAtom); + const powerLevels = usePowerLevelsContext(); + const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); + const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? '')); - const handleMarkAsRead = () => { - markAsRead(mx, room.roomId); - requestClose(); - }; + const handleMarkAsRead = () => { + markAsRead(mx, room.roomId); + requestClose(); + }; - const handleInvite = () => { - openInviteUser(room.roomId); - requestClose(); - }; + const handleInvite = () => { + openInviteUser(room.roomId); + requestClose(); + }; - const handleCopyLink = () => { - copyToClipboard(withOriginBaseUrl(getOriginBaseUrl(hashRouter), linkPath)); - requestClose(); - }; + const handleCopyLink = () => { + const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, room.roomId); + const viaServers = isRoomAlias(roomIdOrAlias) ? undefined : getViaServers(room); + copyToClipboard(getMatrixToRoom(roomIdOrAlias, viaServers)); + requestClose(); + }; - const handleRoomSettings = () => { - toggleRoomSettings(room.roomId); - requestClose(); - }; + const handleRoomSettings = () => { + toggleRoomSettings(room.roomId); + requestClose(); + }; - return ( - - - } - radii="300" - disabled={!unread} - > - - Mark as Read - - - - - - } - radii="300" - disabled={!canInvite} - > - - Invite - - - } - radii="300" - > - - Copy Link - - - } - radii="300" - > - - Room Settings - - - - - - - {(promptLeave, setPromptLeave) => ( - <> - setPromptLeave(true)} - variant="Critical" - fill="None" - size="300" - after={} - radii="300" - aria-pressed={promptLeave} - > - - Leave Room - - - {promptLeave && ( - setPromptLeave(false)} - /> - )} - - )} - - - - ); - } -); + return ( + + + } + radii="300" + disabled={!unread} + > + + Mark as Read + + + + + + } + radii="300" + disabled={!canInvite} + > + + Invite + + + } + radii="300" + > + + Copy Link + + + } + radii="300" + > + + Room Settings + + + + + + + {(promptLeave, setPromptLeave) => ( + <> + setPromptLeave(true)} + variant="Critical" + fill="None" + size="300" + after={} + radii="300" + aria-pressed={promptLeave} + > + + Leave Room + + + {promptLeave && ( + setPromptLeave(false)} + /> + )} + + )} + + + + ); +}); export function RoomViewHeader() { const navigate = useNavigate(); const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const screenSize = useScreenSizeContext(); const room = useRoom(); const space = useSpaceOptionally(); @@ -192,11 +188,9 @@ export function RoomViewHeader() { const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId)); const name = useRoomName(room); const topic = useRoomTopic(room); - const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined : undefined; + const avatarUrl = avatarMxc ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined : undefined; const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer'); - const location = useLocation(); - const currentPath = joinPathComponent(location); const handleSearchClick = () => { const searchParams: _SearchPathSearchParams = { @@ -213,19 +207,36 @@ export function RoomViewHeader() { }; return ( - + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + + + )} + + )} - - ( - - )} - /> - + {screenSize !== ScreenSize.Mobile && ( + + ( + + )} + /> + + )} {name} @@ -336,11 +347,7 @@ export function RoomViewHeader() { escapeDeactivates: stopPropagation, }} > - setMenuAnchor(undefined)} - /> + setMenuAnchor(undefined)} /> } /> diff --git a/src/app/features/room/message/Message.tsx b/src/app/features/room/message/Message.tsx index 6db366ac..94a5825c 100644 --- a/src/app/features/room/message/Message.tsx +++ b/src/app/features/room/message/Message.tsx @@ -51,7 +51,7 @@ import { getMemberAvatarMxc, getMemberDisplayName, } from '../../../utils/room'; -import { getCanonicalAliasOrRoomId, getMxIdLocalPart } from '../../../utils/matrix'; +import { getCanonicalAliasOrRoomId, getMxIdLocalPart, isRoomAlias, mxcUrlToHttp } from '../../../utils/matrix'; import { MessageLayout, MessageSpacing } from '../../../state/settings'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { useRecentEmoji } from '../../../hooks/useRecentEmoji'; @@ -63,18 +63,11 @@ import { EmojiBoard } from '../../../components/emoji-board'; import { ReactionViewer } from '../reaction-viewer'; import { MessageEditor } from './MessageEditor'; import { UserAvatar } from '../../../components/user-avatar'; -import { useSpaceOptionally } from '../../../hooks/useSpace'; -import { useDirectSelected } from '../../../hooks/router/useDirectSelected'; -import { - getDirectRoomPath, - getHomeRoomPath, - getOriginBaseUrl, - getSpaceRoomPath, - withOriginBaseUrl, -} from '../../../pages/pathUtils'; import { copyToClipboard } from '../../../utils/dom'; -import { useClientConfig } from '../../../hooks/useClientConfig'; import { stopPropagation } from '../../../utils/keyboard'; +import { getMatrixToRoomEvent } from '../../../plugins/matrix-to'; +import { getViaServers } from '../../../plugins/via-servers'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void; @@ -242,9 +235,9 @@ export const MessageSourceCodeItem = as< const getContent = (evt: MatrixEvent) => evt.isEncrypted() ? { - [`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(), - [`<== ORIGINAL_EVENT ==>`]: evt.event, - } + [`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(), + [`<== ORIGINAL_EVENT ==>`]: evt.event, + } : evt.event; const getText = (): string => { @@ -321,23 +314,13 @@ export const MessageCopyLinkItem = as< } >(({ room, mEvent, onClose, ...props }, ref) => { const mx = useMatrixClient(); - const { hashRouter } = useClientConfig(); - const space = useSpaceOptionally(); - const directSelected = useDirectSelected(); const handleCopy = () => { const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, room.roomId); - let eventPath = getHomeRoomPath(roomIdOrAlias, mEvent.getId()); - if (space) { - eventPath = getSpaceRoomPath( - getCanonicalAliasOrRoomId(mx, space.roomId), - roomIdOrAlias, - mEvent.getId() - ); - } else if (directSelected) { - eventPath = getDirectRoomPath(roomIdOrAlias, mEvent.getId()); - } - copyToClipboard(withOriginBaseUrl(getOriginBaseUrl(hashRouter), eventPath)); + const eventId = mEvent.getId(); + const viaServers = isRoomAlias(roomIdOrAlias) ? undefined : getViaServers(room); + if (!eventId) return; + copyToClipboard(getMatrixToRoomEvent(roomIdOrAlias, eventId, viaServers)); onClose?.(); }; @@ -668,6 +651,8 @@ export const Message = as<'div', MessageProps>( ref ) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const senderId = mEvent.getSender() ?? ''; const [hover, setHover] = useState(false); const { hoverProps } = useHover({ onHoverChange: setHover }); @@ -727,7 +712,7 @@ export const Message = as<'div', MessageProps>( userId={senderId} src={ senderAvatarMxc - ? mx.mxcUrlToHttp(senderAvatarMxc, 48, 48, 'crop') ?? undefined + ? mxcUrlToHttp(mx, senderAvatarMxc, useAuthentication, 48, 48, 'crop') ?? undefined : undefined } alt={senderDisplayName} @@ -968,26 +953,26 @@ export const Message = as<'div', MessageProps>( {((!mEvent.isRedacted() && canDelete) || mEvent.getSender() !== mx.getUserId()) && ( - <> - - - {!mEvent.isRedacted() && canDelete && ( - - )} - {mEvent.getSender() !== mx.getUserId() && ( - - )} - - - )} + <> + + + {!mEvent.isRedacted() && canDelete && ( + + )} + {mEvent.getSender() !== mx.getUserId() && ( + + )} + + + )} } @@ -1111,26 +1096,26 @@ export const Event = as<'div', EventProps>( {((!mEvent.isRedacted() && canDelete && !stateEvent) || (mEvent.getSender() !== mx.getUserId() && !stateEvent)) && ( - <> - - - {!mEvent.isRedacted() && canDelete && ( - - )} - {mEvent.getSender() !== mx.getUserId() && ( - - )} - - - )} + <> + + + {!mEvent.isRedacted() && canDelete && ( + + )} + {mEvent.getSender() !== mx.getUserId() && ( + + )} + + + )} } diff --git a/src/app/features/room/message/Reactions.tsx b/src/app/features/room/message/Reactions.tsx index a6d7f553..258ab629 100644 --- a/src/app/features/room/message/Reactions.tsx +++ b/src/app/features/room/message/Reactions.tsx @@ -22,6 +22,7 @@ import { useRelations } from '../../../hooks/useRelations'; import * as css from './styles.css'; import { ReactionViewer } from '../reaction-viewer'; import { stopPropagation } from '../../../utils/keyboard'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; export type ReactionsProps = { room: Room; @@ -33,6 +34,8 @@ export type ReactionsProps = { export const Reactions = as<'div', ReactionsProps>( ({ className, room, relations, mEventId, canSendReaction, onReactionToggle, ...props }, ref) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [viewer, setViewer] = useState(false); const myUserId = mx.getUserId(); const reactions = useRelations( @@ -86,6 +89,7 @@ export const Reactions = as<'div', ReactionsProps>( onClick={canSendReaction ? () => onReactionToggle(mEventId, key) : undefined} onContextMenu={handleViewReaction} aria-disabled={!canSendReaction} + useAuthentication={useAuthentication} /> )} diff --git a/src/app/features/room/reaction-viewer/ReactionViewer.tsx b/src/app/features/room/reaction-viewer/ReactionViewer.tsx index 1c1b79a7..9e166a9e 100644 --- a/src/app/features/room/reaction-viewer/ReactionViewer.tsx +++ b/src/app/features/room/reaction-viewer/ReactionViewer.tsx @@ -25,6 +25,7 @@ import { useRelations } from '../../../hooks/useRelations'; import { Reaction } from '../../../components/message'; import { getHexcodeForEmoji, getShortcodeFor } from '../../../plugins/emoji'; import { UserAvatar } from '../../../components/user-avatar'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; export type ReactionViewerProps = { room: Room; @@ -35,6 +36,8 @@ export type ReactionViewerProps = { export const ReactionViewer = as<'div', ReactionViewerProps>( ({ className, room, initialKey, relations, requestClose, ...props }, ref) => { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const reactions = useRelations( relations, useCallback((rel) => [...(rel.getSortedAnnotationsByKey() ?? [])], []) @@ -81,6 +84,7 @@ export const ReactionViewer = as<'div', ReactionViewerProps>( count={evts.size} aria-selected={key === selectedKey} onClick={() => setSelectedKey(key)} + useAuthentication={useAuthentication} /> ); })} @@ -107,14 +111,16 @@ export const ReactionViewer = as<'div', ReactionViewerProps>( const member = room.getMember(senderId); const name = (member ? getName(member) : getMxIdLocalPart(senderId)) ?? senderId; - const avatarUrl = member?.getAvatarUrl( - mx.baseUrl, + const avatarMxcUrl = member?.getMxcAvatarUrl(); + const avatarUrl = avatarMxcUrl ? mx.mxcUrlToHttp( + avatarMxcUrl, 100, 100, 'crop', undefined, - false - ); + false, + useAuthentication + ) : undefined; return ( { + const [searchParams] = useSearchParams(); + const roomSearchParams = useMemo(() => getRoomSearchParams(searchParams), [searchParams]); + const viaServers = roomSearchParams.viaServers + ? decodeSearchParamValueArray(roomSearchParams.viaServers) + : undefined; + + return viaServers; +}; diff --git a/src/app/hooks/useDeviceList.js b/src/app/hooks/useDeviceList.js deleted file mode 100644 index 7daaad1f..00000000 --- a/src/app/hooks/useDeviceList.js +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable import/prefer-default-export */ -import { useState, useEffect } from 'react'; -import { useMatrixClient } from './useMatrixClient'; - -export function useDeviceList() { - const mx = useMatrixClient(); - const [deviceList, setDeviceList] = useState(null); - - useEffect(() => { - let isMounted = true; - - const updateDevices = () => mx.getDevices().then((data) => { - if (!isMounted) return; - setDeviceList(data.devices || []); - }); - updateDevices(); - - const handleDevicesUpdate = (users) => { - if (users.includes(mx.getUserId())) { - updateDevices(); - } - }; - - mx.on('crypto.devicesUpdated', handleDevicesUpdate); - return () => { - mx.removeListener('crypto.devicesUpdated', handleDevicesUpdate); - isMounted = false; - }; - }, [mx]); - return deviceList; -} diff --git a/src/app/hooks/useDeviceList.ts b/src/app/hooks/useDeviceList.ts new file mode 100644 index 00000000..daec7cbe --- /dev/null +++ b/src/app/hooks/useDeviceList.ts @@ -0,0 +1,35 @@ +/* eslint-disable import/prefer-default-export */ +import { useState, useEffect } from 'react'; +import { CryptoEvent, IMyDevice } from 'matrix-js-sdk'; +import { CryptoEventHandlerMap } from 'matrix-js-sdk/lib/crypto'; +import { useMatrixClient } from './useMatrixClient'; + +export function useDeviceList() { + const mx = useMatrixClient(); + const [deviceList, setDeviceList] = useState(null); + + useEffect(() => { + let isMounted = true; + + const updateDevices = () => + mx.getDevices().then((data) => { + if (!isMounted) return; + setDeviceList(data.devices || []); + }); + updateDevices(); + + const handleDevicesUpdate: CryptoEventHandlerMap[CryptoEvent.DevicesUpdated] = (users) => { + const userId = mx.getUserId(); + if (userId && users.includes(userId)) { + updateDevices(); + } + }; + + mx.on(CryptoEvent.DevicesUpdated, handleDevicesUpdate); + return () => { + mx.removeListener(CryptoEvent.DevicesUpdated, handleDevicesUpdate); + isMounted = false; + }; + }, [mx]); + return deviceList; +} diff --git a/src/app/hooks/useMentionClickHandler.ts b/src/app/hooks/useMentionClickHandler.ts new file mode 100644 index 00000000..f8f4bf54 --- /dev/null +++ b/src/app/hooks/useMentionClickHandler.ts @@ -0,0 +1,43 @@ +import { ReactEventHandler, useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useRoomNavigate } from './useRoomNavigate'; +import { useMatrixClient } from './useMatrixClient'; +import { isRoomId, isUserId } from '../utils/matrix'; +import { openProfileViewer } from '../../client/action/navigation'; +import { getHomeRoomPath, withSearchParam } from '../pages/pathUtils'; +import { _RoomSearchParams } from '../pages/paths'; + +export const useMentionClickHandler = (roomId: string): ReactEventHandler => { + const mx = useMatrixClient(); + const { navigateRoom, navigateSpace } = useRoomNavigate(); + const navigate = useNavigate(); + + const handleClick: ReactEventHandler = useCallback( + (evt) => { + evt.preventDefault(); + const target = evt.currentTarget; + const mentionId = target.getAttribute('data-mention-id'); + if (typeof mentionId !== 'string') return; + + if (isUserId(mentionId)) { + openProfileViewer(mentionId, roomId); + return; + } + + const eventId = target.getAttribute('data-mention-event-id') || undefined; + if (isRoomId(mentionId) && mx.getRoom(mentionId)) { + if (mx.getRoom(mentionId)?.isSpaceRoom()) navigateSpace(mentionId); + else navigateRoom(mentionId, eventId); + return; + } + + const viaServers = target.getAttribute('data-mention-via') || undefined; + const path = getHomeRoomPath(mentionId, eventId); + + navigate(viaServers ? withSearchParam<_RoomSearchParams>(path, { viaServers }) : path); + }, + [mx, navigate, navigateRoom, navigateSpace, roomId] + ); + + return handleClick; +}; diff --git a/src/app/hooks/useParsedLoginFlows.ts b/src/app/hooks/useParsedLoginFlows.ts index 14ecfb9d..088a514e 100644 --- a/src/app/hooks/useParsedLoginFlows.ts +++ b/src/app/hooks/useParsedLoginFlows.ts @@ -1,16 +1,10 @@ import { useMemo } from 'react'; import { ILoginFlow, IPasswordFlow, ISSOFlow, LoginFlow } from 'matrix-js-sdk/lib/@types/auth'; -import { WithRequiredProp } from '../../types/utils'; -export type Required_SSOFlow = WithRequiredProp; -export const getSSOFlow = (loginFlows: LoginFlow[]): Required_SSOFlow | undefined => - loginFlows.find( - (flow) => - (flow.type === 'm.login.sso' || flow.type === 'm.login.cas') && - 'identity_providers' in flow && - Array.isArray(flow.identity_providers) && - flow.identity_providers.length > 0 - ) as Required_SSOFlow | undefined; +export const getSSOFlow = (loginFlows: LoginFlow[]): ISSOFlow | undefined => + loginFlows.find((flow) => flow.type === 'm.login.sso' || flow.type === 'm.login.cas') as + | ISSOFlow + | undefined; export const getPasswordFlow = (loginFlows: LoginFlow[]): IPasswordFlow | undefined => loginFlows.find((flow) => flow.type === 'm.login.password') as IPasswordFlow; @@ -22,7 +16,7 @@ export const getTokenFlow = (loginFlows: LoginFlow[]): LoginFlow | undefined => export type ParsedLoginFlows = { password?: LoginFlow; token?: LoginFlow; - sso?: Required_SSOFlow; + sso?: ISSOFlow; }; export const useParsedLoginFlows = (loginFlows: LoginFlow[]) => { const parsedFlow: ParsedLoginFlows = useMemo( diff --git a/src/app/hooks/useRoomNavigate.ts b/src/app/hooks/useRoomNavigate.ts index 55528e7e..0f9f365c 100644 --- a/src/app/hooks/useRoomNavigate.ts +++ b/src/app/hooks/useRoomNavigate.ts @@ -1,5 +1,5 @@ import { useCallback } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { NavigateOptions, useNavigate } from 'react-router-dom'; import { useAtomValue } from 'jotai'; import { getCanonicalAliasOrRoomId } from '../utils/matrix'; import { @@ -12,12 +12,14 @@ import { useMatrixClient } from './useMatrixClient'; import { getOrphanParents } from '../utils/room'; import { roomToParentsAtom } from '../state/room/roomToParents'; import { mDirectAtom } from '../state/mDirectList'; +import { useSelectedSpace } from './router/useSelectedSpace'; export const useRoomNavigate = () => { const navigate = useNavigate(); const mx = useMatrixClient(); const roomToParents = useAtomValue(roomToParentsAtom); const mDirects = useAtomValue(mDirectAtom); + const spaceSelectedId = useSelectedSpace(); const navigateSpace = useCallback( (roomId: string) => { @@ -28,24 +30,29 @@ export const useRoomNavigate = () => { ); const navigateRoom = useCallback( - (roomId: string, eventId?: string) => { + (roomId: string, eventId?: string, opts?: NavigateOptions) => { const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, roomId); const orphanParents = getOrphanParents(roomToParents, roomId); if (orphanParents.length > 0) { - const pSpaceIdOrAlias = getCanonicalAliasOrRoomId(mx, orphanParents[0]); - navigate(getSpaceRoomPath(pSpaceIdOrAlias, roomIdOrAlias, eventId)); + const pSpaceIdOrAlias = getCanonicalAliasOrRoomId( + mx, + spaceSelectedId && orphanParents.includes(spaceSelectedId) + ? spaceSelectedId + : orphanParents[0] + ); + navigate(getSpaceRoomPath(pSpaceIdOrAlias, roomIdOrAlias, eventId), opts); return; } if (mDirects.has(roomId)) { - navigate(getDirectRoomPath(roomIdOrAlias, eventId)); + navigate(getDirectRoomPath(roomIdOrAlias, eventId), opts); return; } - navigate(getHomeRoomPath(roomIdOrAlias, eventId)); + navigate(getHomeRoomPath(roomIdOrAlias, eventId), opts); }, - [mx, navigate, roomToParents, mDirects] + [mx, navigate, spaceSelectedId, roomToParents, mDirects] ); return { diff --git a/src/app/hooks/useSpoilerClickHandler.ts b/src/app/hooks/useSpoilerClickHandler.ts new file mode 100644 index 00000000..b2101188 --- /dev/null +++ b/src/app/hooks/useSpoilerClickHandler.ts @@ -0,0 +1,14 @@ +import { ReactEventHandler, useCallback } from 'react'; + +export const useSpoilerClickHandler = (): ReactEventHandler => { + const handleClick: ReactEventHandler = useCallback((evt) => { + const target = evt.currentTarget; + if (target.getAttribute('aria-pressed') === 'true') { + evt.stopPropagation(); + target.setAttribute('aria-pressed', 'false'); + target.style.cursor = 'initial'; + } + }, []); + + return handleClick; +}; diff --git a/src/app/i18n.ts b/src/app/i18n.ts new file mode 100644 index 00000000..9e83805d --- /dev/null +++ b/src/app/i18n.ts @@ -0,0 +1,31 @@ +import i18n from 'i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import Backend, { HttpBackendOptions } from 'i18next-http-backend'; +import { initReactI18next } from 'react-i18next'; +import { trimTrailingSlash } from './utils/common'; + +i18n + // i18next-http-backend + // loads translations from your server + // https://github.com/i18next/i18next-http-backend + .use(Backend) + // detect user language + // learn more: https://github.com/i18next/i18next-browser-languageDetector + .use(LanguageDetector) + // pass the i18n instance to react-i18next. + .use(initReactI18next) + // init i18next + // for all options read: https://www.i18next.com/overview/configuration-options + .init({ + debug: false, + fallbackLng: 'en', + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + }, + load: 'languageOnly', + backend: { + loadPath: `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/locales/{{lng}}.json`, + }, + }); + +export default i18n; diff --git a/src/app/molecules/space-add-existing/SpaceAddExisting.jsx b/src/app/molecules/space-add-existing/SpaceAddExisting.jsx index ff338f3f..83b967bc 100644 --- a/src/app/molecules/space-add-existing/SpaceAddExisting.jsx +++ b/src/app/molecules/space-add-existing/SpaceAddExisting.jsx @@ -5,7 +5,7 @@ import './SpaceAddExisting.scss'; import cons from '../../../client/state/cons'; import navigation from '../../../client/state/navigation'; -import { joinRuleToIconSrc, getIdServer, genRoomVia } from '../../../util/matrixUtil'; +import { joinRuleToIconSrc, getIdServer } from '../../../util/matrixUtil'; import { Debounce } from '../../../util/common'; import Text from '../../atoms/text/Text'; @@ -27,6 +27,7 @@ import { useDirects, useRooms, useSpaces } from '../../state/hooks/roomList'; import { allRoomsAtom } from '../../state/room-list/roomList'; import { mDirectAtom } from '../../state/mDirectList'; import { useMatrixClient } from '../../hooks/useMatrixClient'; +import { getViaServers } from '../../plugins/via-servers'; function SpaceAddExistingContent({ roomId, spaces: onlySpaces }) { const mountStore = useStore(roomId); @@ -69,7 +70,7 @@ function SpaceAddExistingContent({ roomId, spaces: onlySpaces }) { const promises = selected.map((rId) => { const room = mx.getRoom(rId); - const via = genRoomVia(room); + const via = getViaServers(room); if (via.length === 0) { via.push(getIdServer(rId)); } diff --git a/src/app/pages/Router.tsx b/src/app/pages/Router.tsx index 7d0f4fde..88fa9932 100644 --- a/src/app/pages/Router.tsx +++ b/src/app/pages/Router.tsx @@ -41,7 +41,7 @@ import { } from './pathUtils'; import { ClientBindAtoms, ClientLayout, ClientRoot } from './client'; import { Home, HomeRouteRoomProvider, HomeSearch } from './client/home'; -import { Direct, DirectRouteRoomProvider } from './client/direct'; +import { Direct, DirectCreate, DirectRouteRoomProvider } from './client/direct'; import { RouteSpaceProvider, Space, SpaceRouteRoomProvider, SpaceSearch } from './client/space'; import { Explore, FeaturedRooms, PublicRooms } from './client/explore'; import { Notifications, Inbox, Invites } from './client/inbox'; @@ -160,7 +160,7 @@ export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize) } > {mobile ? null : } />} - create

} /> + } /> - v4.0.3 + v4.1.0 Twitter diff --git a/src/app/pages/auth/AuthLayout.tsx b/src/app/pages/auth/AuthLayout.tsx index 63644a94..0ccabf87 100644 --- a/src/app/pages/auth/AuthLayout.tsx +++ b/src/app/pages/auth/AuthLayout.tsx @@ -29,6 +29,7 @@ import { AutoDiscoveryInfoProvider } from '../../hooks/useAutoDiscoveryInfo'; import { AuthFlowsLoader } from '../../components/AuthFlowsLoader'; import { AuthFlowsProvider } from '../../hooks/useAuthFlows'; import { AuthServerProvider } from '../../hooks/useAuthServer'; +import { tryDecodeURIComponent } from '../../utils/dom'; const currentAuthPath = (pathname: string): string => { if (matchPath(LOGIN_PATH, pathname)) { @@ -72,7 +73,7 @@ export function AuthLayout() { const clientConfig = useClientConfig(); const defaultServer = clientDefaultServer(clientConfig); - let server: string = urlEncodedServer ? decodeURIComponent(urlEncodedServer) : defaultServer; + let server: string = urlEncodedServer ? tryDecodeURIComponent(urlEncodedServer) : defaultServer; if (!clientAllowedServer(clientConfig, server)) { server = defaultServer; @@ -94,7 +95,7 @@ export function AuthLayout() { // if server is mismatches with path server, update path useEffect(() => { - if (!urlEncodedServer || decodeURIComponent(urlEncodedServer) !== server) { + if (!urlEncodedServer || tryDecodeURIComponent(urlEncodedServer) !== server) { navigate( generatePath(currentAuthPath(location.pathname), { server: encodeURIComponent(server), diff --git a/src/app/pages/auth/SSOLogin.tsx b/src/app/pages/auth/SSOLogin.tsx index 0d3d917f..d0cdaeb6 100644 --- a/src/app/pages/auth/SSOLogin.tsx +++ b/src/app/pages/auth/SSOLogin.tsx @@ -4,69 +4,89 @@ import React, { useMemo } from 'react'; import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo'; type SSOLoginProps = { - providers: IIdentityProvider[]; - asIcons?: boolean; + providers?: IIdentityProvider[]; redirectUrl: string; + saveScreenSpace?: boolean; }; -export function SSOLogin({ providers, redirectUrl, asIcons }: SSOLoginProps) { +export function SSOLogin({ providers, redirectUrl, saveScreenSpace }: SSOLoginProps) { const discovery = useAutoDiscoveryInfo(); const baseUrl = discovery['m.homeserver'].base_url; const mx = useMemo(() => createClient({ baseUrl }), [baseUrl]); - const getSSOIdUrl = (ssoId: string): string => mx.getSsoLoginUrl(redirectUrl, 'sso', ssoId); + const getSSOIdUrl = (ssoId?: string): string => mx.getSsoLoginUrl(redirectUrl, 'sso', ssoId); - const anyAsBtn = providers.find( - (provider) => !provider.icon || !mx.mxcUrlToHttp(provider.icon, 96, 96, 'crop', false) - ); + const withoutIcon = providers + ? providers.find( + (provider) => !provider.icon || !mx.mxcUrlToHttp(provider.icon, 96, 96, 'crop', false) + ) + : true; + + const renderAsIcons = withoutIcon ? false : saveScreenSpace && providers && providers.length > 2; return ( - {providers.map((provider) => { - const { id, name, icon } = provider; - const iconUrl = icon && mx.mxcUrlToHttp(icon, 96, 96, 'crop', false); + {providers ? ( + providers.map((provider) => { + const { id, name, icon } = provider; + const iconUrl = icon && mx.mxcUrlToHttp(icon, 96, 96, 'crop', false); - const buttonTitle = `Continue with ${name}`; + const buttonTitle = `Continue with ${name}`; + + if (renderAsIcons) { + return ( + + + + ); + } - if (!anyAsBtn && iconUrl && asIcons) { return ( - + + + ) + } > - - + + {buttonTitle} + + ); - } - - return ( - - ); - })} + }) + ) : ( + + )} ); } diff --git a/src/app/pages/auth/login/Login.tsx b/src/app/pages/auth/login/Login.tsx index e1689d1e..6b9f1223 100644 --- a/src/app/pages/auth/login/Login.tsx +++ b/src/app/pages/auth/login/Login.tsx @@ -76,9 +76,7 @@ export function Login() { 2 - } + saveScreenSpace={parsedFlows.password !== undefined} /> diff --git a/src/app/pages/auth/register/Register.tsx b/src/app/pages/auth/register/Register.tsx index c859d0e5..d2986d70 100644 --- a/src/app/pages/auth/register/Register.tsx +++ b/src/app/pages/auth/register/Register.tsx @@ -83,10 +83,7 @@ export function Register() { 2 - } + saveScreenSpace={registerFlows.status === RegisterFlowStatus.FlowRequired} /> diff --git a/src/app/pages/client/ClientNonUIFeatures.tsx b/src/app/pages/client/ClientNonUIFeatures.tsx index 845fceb3..9f3f129b 100644 --- a/src/app/pages/client/ClientNonUIFeatures.tsx +++ b/src/app/pages/client/ClientNonUIFeatures.tsx @@ -22,9 +22,10 @@ import { isNotificationEvent, } from '../../utils/room'; import { NotificationType, UnreadInfo } from '../../../types/matrix/room'; -import { getMxIdLocalPart } from '../../utils/matrix'; +import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix'; import { useSelectedRoom } from '../../hooks/router/useSelectedRoom'; import { useInboxNotificationsSelected } from '../../hooks/router/useInbox'; +import { useSpecVersions } from '../../hooks/useSpecVersions'; function SystemEmojiFeature() { const [twitterEmoji] = useSetting(settingsAtom, 'twitterEmoji'); @@ -132,6 +133,8 @@ function MessageNotifications() { const notifRef = useRef(); const unreadCacheRef = useRef>(new Map()); const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const [showNotifications] = useSetting(settingsAtom, 'showNotifications'); const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds'); @@ -183,17 +186,17 @@ function MessageNotifications() { removed, data ) => { + if (mx.getSyncState() !== 'SYNCING') return; + if (document.hasFocus() && (selectedRoomId === room?.roomId || notificationSelected)) return; if ( - mx.getSyncState() !== 'SYNCING' || - selectedRoomId === room?.roomId || - notificationSelected || !room || !data.liveEvent || room.isSpaceRoom() || !isNotificationEvent(mEvent) || getNotificationType(mx, room.roomId) === NotificationType.Mute - ) + ) { return; + } const sender = mEvent.getSender(); const eventId = mEvent.getId(); @@ -216,7 +219,7 @@ function MessageNotifications() { notify({ roomName: room.name ?? 'Unknown', roomAvatar: avatarMxc - ? mx.mxcUrlToHttp(avatarMxc, 96, 96, 'crop') ?? undefined + ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined : undefined, username: getMemberDisplayName(room, sender) ?? getMxIdLocalPart(sender) ?? sender, roomId: room.roomId, diff --git a/src/app/pages/client/SidebarNav.tsx b/src/app/pages/client/SidebarNav.tsx index fb6bd742..110e4694 100644 --- a/src/app/pages/client/SidebarNav.tsx +++ b/src/app/pages/client/SidebarNav.tsx @@ -10,7 +10,15 @@ import { SidebarItemTooltip, SidebarItem, } from '../../components/sidebar'; -import { DirectTab, HomeTab, SpaceTabs, InboxTab, ExploreTab, UserTab } from './sidebar'; +import { + DirectTab, + HomeTab, + SpaceTabs, + InboxTab, + ExploreTab, + UserTab, + UnverifiedTab, +} from './sidebar'; import { openCreateRoom, openSearch } from '../../../client/action/navigation'; export function SidebarNav() { @@ -65,6 +73,8 @@ export function SidebarNav() { + + diff --git a/src/app/pages/client/WelcomePage.tsx b/src/app/pages/client/WelcomePage.tsx index 8cf6b9ff..1e146a04 100644 --- a/src/app/pages/client/WelcomePage.tsx +++ b/src/app/pages/client/WelcomePage.tsx @@ -24,7 +24,7 @@ export function WelcomePage() { target="_blank" rel="noreferrer noopener" > - v4.0.3 + v4.1.0 } diff --git a/src/app/pages/client/direct/DirectCreate.tsx b/src/app/pages/client/direct/DirectCreate.tsx new file mode 100644 index 00000000..3affb9c1 --- /dev/null +++ b/src/app/pages/client/direct/DirectCreate.tsx @@ -0,0 +1,33 @@ +import React, { useEffect } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { WelcomePage } from '../WelcomePage'; +import { useMatrixClient } from '../../../hooks/useMatrixClient'; +import { getDirectCreateSearchParams } from '../../pathSearchParam'; +import { getDirectPath, getDirectRoomPath } from '../../pathUtils'; +import { getDMRoomFor } from '../../../utils/matrix'; +import { openInviteUser } from '../../../../client/action/navigation'; +import { useDirectRooms } from './useDirectRooms'; + +export function DirectCreate() { + const mx = useMatrixClient(); + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const { userId } = getDirectCreateSearchParams(searchParams); + const directs = useDirectRooms(); + + useEffect(() => { + if (userId) { + const room = getDMRoomFor(mx, userId); + const { roomId } = room ?? {}; + if (roomId && directs.includes(roomId)) { + navigate(getDirectRoomPath(roomId), { replace: true }); + } else { + openInviteUser(undefined, userId); + } + } else { + navigate(getDirectPath(), { replace: true }); + } + }, [mx, navigate, directs, userId]); + + return ; +} diff --git a/src/app/pages/client/direct/RoomProvider.tsx b/src/app/pages/client/direct/RoomProvider.tsx index c78a8f44..ca45aa19 100644 --- a/src/app/pages/client/direct/RoomProvider.tsx +++ b/src/app/pages/client/direct/RoomProvider.tsx @@ -10,12 +10,12 @@ export function DirectRouteRoomProvider({ children }: { children: ReactNode }) { const mx = useMatrixClient(); const rooms = useDirectRooms(); - const { roomIdOrAlias } = useParams(); + const { roomIdOrAlias, eventId } = useParams(); const roomId = useSelectedRoom(); const room = mx.getRoom(roomId); if (!room || !rooms.includes(room.roomId)) { - return ; + return ; } return ( diff --git a/src/app/pages/client/direct/index.ts b/src/app/pages/client/direct/index.ts index 36f44d63..d247bbc0 100644 --- a/src/app/pages/client/direct/index.ts +++ b/src/app/pages/client/direct/index.ts @@ -1,2 +1,3 @@ export * from './Direct'; export * from './RoomProvider'; +export * from './DirectCreate'; diff --git a/src/app/pages/client/explore/Featured.tsx b/src/app/pages/client/explore/Featured.tsx index 4838127f..f056cbb5 100644 --- a/src/app/pages/client/explore/Featured.tsx +++ b/src/app/pages/client/explore/Featured.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Icon, Icons, Scroll, Text } from 'folds'; +import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds'; import { useAtomValue } from 'jotai'; import { useClientConfig } from '../../../hooks/useClientConfig'; import { RoomCard, RoomCardGrid } from '../../../components/room-card'; @@ -9,21 +9,38 @@ import { Page, PageContent, PageContentCenter, + PageHeader, PageHero, PageHeroSection, } from '../../../components/page'; import { RoomTopicViewer } from '../../../components/room-topic-viewer'; import * as css from './style.css'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function FeaturedRooms() { const { featuredCommunities } = useClientConfig(); const { rooms, spaces } = featuredCommunities ?? {}; const allRooms = useAtomValue(allRoomsAtom); + const screenSize = useScreenSizeContext(); const { navigateSpace, navigateRoom } = useRoomNavigate(); return ( + {screenSize === ScreenSize.Mobile && ( + + + + {(onBack) => ( + + + + )} + + + + )} diff --git a/src/app/pages/client/explore/Server.tsx b/src/app/pages/client/explore/Server.tsx index 1a81c225..1f493df1 100644 --- a/src/app/pages/client/explore/Server.tsx +++ b/src/app/pages/client/explore/Server.tsx @@ -13,6 +13,7 @@ import { Button, Chip, Icon, + IconButton, Icons, Input, Line, @@ -42,6 +43,8 @@ import { allRoomsAtom } from '../../../state/room-list/roomList'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; import { getMxIdServer } from '../../../utils/matrix'; import { stopPropagation } from '../../../utils/keyboard'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; const useServerSearchParams = (searchParams: URLSearchParams): ExploreServerPathSearchParams => useMemo( @@ -344,6 +347,7 @@ export function PublicRooms() { const userServer = userId && getMxIdServer(userId); const allRooms = useAtomValue(allRoomsAtom); const { navigateSpace, navigateRoom } = useRoomNavigate(); + const screenSize = useScreenSizeContext(); const [searchParams] = useSearchParams(); const serverSearchParams = useServerSearchParams(searchParams); @@ -466,7 +470,7 @@ export function PublicRooms() { return ( - + {isSearch ? ( <> @@ -482,20 +486,34 @@ export function PublicRooms() { - + {screenSize !== ScreenSize.Mobile && } Search - + ) : ( - - - - {server} - - + <> + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + {server} + + + + )} diff --git a/src/app/pages/client/home/RoomProvider.tsx b/src/app/pages/client/home/RoomProvider.tsx index 282cee7d..aa14d153 100644 --- a/src/app/pages/client/home/RoomProvider.tsx +++ b/src/app/pages/client/home/RoomProvider.tsx @@ -5,17 +5,25 @@ import { RoomProvider } from '../../../hooks/useRoom'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { JoinBeforeNavigate } from '../../../features/join-before-navigate'; import { useHomeRooms } from './useHomeRooms'; +import { useSearchParamsViaServers } from '../../../hooks/router/useSearchParamsViaServers'; export function HomeRouteRoomProvider({ children }: { children: ReactNode }) { const mx = useMatrixClient(); const rooms = useHomeRooms(); - const { roomIdOrAlias } = useParams(); + const { roomIdOrAlias, eventId } = useParams(); + const viaServers = useSearchParamsViaServers(); const roomId = useSelectedRoom(); const room = mx.getRoom(roomId); if (!room || !rooms.includes(room.roomId)) { - return ; + return ( + + ); } return ( diff --git a/src/app/pages/client/home/Search.tsx b/src/app/pages/client/home/Search.tsx index af7b1eb9..d5ddfb77 100644 --- a/src/app/pages/client/home/Search.tsx +++ b/src/app/pages/client/home/Search.tsx @@ -1,21 +1,38 @@ import React, { useRef } from 'react'; -import { Box, Icon, Icons, Text, Scroll } from 'folds'; +import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds'; import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page'; import { MessageSearch } from '../../../features/message-search'; import { useHomeRooms } from './useHomeRooms'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function HomeSearch() { const scrollRef = useRef(null); const rooms = useHomeRooms(); + const screenSize = useScreenSizeContext(); return ( - - - - - Message Search - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Message Search + + + diff --git a/src/app/pages/client/inbox/Invites.tsx b/src/app/pages/client/inbox/Invites.tsx index 06e5f6c6..12ca65bb 100644 --- a/src/app/pages/client/inbox/Invites.tsx +++ b/src/app/pages/client/inbox/Invites.tsx @@ -4,6 +4,7 @@ import { Box, Button, Icon, + IconButton, Icons, Overlay, OverlayBackdrop, @@ -39,6 +40,9 @@ import { RoomTopicViewer } from '../../../components/room-topic-viewer'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { useRoomNavigate } from '../../../hooks/useRoomNavigate'; import { useRoomTopic } from '../../../hooks/useRoomMeta'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; const COMPACT_CARD_WIDTH = 548; @@ -51,6 +55,8 @@ type InviteCardProps = { }; function InviteCard({ room, userId, direct, compact, onNavigate }: InviteCardProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const roomName = room.name || room.getCanonicalAlias() || room.roomId; const member = room.getMember(userId); const memberEvent = member?.events.member; @@ -107,7 +113,7 @@ function InviteCard({ room, userId, direct, compact, onNavigate }: InviteCardPro ( @@ -205,6 +211,7 @@ export function Invites() { useCallback(() => containerRef.current, []), useCallback((width) => setCompact(width <= COMPACT_CARD_WIDTH), []) ); + const screenSize = useScreenSizeContext(); const { navigateRoom, navigateSpace } = useRoomNavigate(); @@ -225,12 +232,26 @@ export function Invites() { return ( - - - - - Invitations - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Invitations + + + diff --git a/src/app/pages/client/inbox/Notifications.tsx b/src/app/pages/client/inbox/Notifications.tsx index a01ecb8e..95f9b9ff 100644 --- a/src/app/pages/client/inbox/Notifications.tsx +++ b/src/app/pages/client/inbox/Notifications.tsx @@ -20,13 +20,15 @@ import { IRoomEvent, JoinRule, Method, + RelationType, Room, } from 'matrix-js-sdk'; import { useVirtualizer } from '@tanstack/react-virtual'; import { HTMLReactParserOptions } from 'html-react-parser'; +import { Opts as LinkifyOpts } from 'linkifyjs'; import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; -import { getMxIdLocalPart, isRoomId, isUserId } from '../../../utils/matrix'; +import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix'; import { InboxNotificationsPathSearchParams } from '../../paths'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { SequenceCard } from '../../../components/sequence-card'; @@ -52,8 +54,13 @@ import { Username, } from '../../../components/message'; import colorMXID from '../../../../util/colorMXID'; -import { getReactCustomHtmlParser } from '../../../plugins/react-custom-html-parser'; -import { openJoinAlias, openProfileViewer } from '../../../../client/action/navigation'; +import { + factoryRenderLinkifyWithMention, + getReactCustomHtmlParser, + LINKIFY_OPTS, + makeMentionCustomProps, + renderMatrixMention, +} from '../../../plugins/react-custom-html-parser'; import { RenderMessageContent } from '../../../components/RenderMessageContent'; import { useSetting } from '../../../state/hooks/settings'; import { settingsAtom } from '../../../state/settings'; @@ -70,6 +77,11 @@ import { ContainerColor } from '../../../styles/ContainerColor.css'; import { VirtualTile } from '../../../components/virtualizer'; import { UserAvatar } from '../../../components/user-avatar'; import { EncryptedContent } from '../../../features/room/message'; +import { useMentionClickHandler } from '../../../hooks/useMentionClickHandler'; +import { useSpoilerClickHandler } from '../../../hooks/useSpoilerClickHandler'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; type RoomNotificationsGroup = { roomId: string; @@ -180,37 +192,30 @@ function RoomNotificationsGroupComp({ onOpen, }: RoomNotificationsGroupProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const unread = useRoomUnread(room.roomId, roomToUnreadAtom); - const { navigateRoom, navigateSpace } = useRoomNavigate(); + const mentionClickHandler = useMentionClickHandler(room.roomId); + const spoilerClickHandler = useSpoilerClickHandler(); + const linkifyOpts = useMemo( + () => ({ + ...LINKIFY_OPTS, + render: factoryRenderLinkifyWithMention((href) => + renderMatrixMention(mx, room.roomId, href, makeMentionCustomProps(mentionClickHandler)) + ), + }), + [mx, room, mentionClickHandler] + ); const htmlReactParserOptions = useMemo( () => - getReactCustomHtmlParser(mx, room, { - handleSpoilerClick: (evt) => { - const target = evt.currentTarget; - if (target.getAttribute('aria-pressed') === 'true') { - evt.stopPropagation(); - target.setAttribute('aria-pressed', 'false'); - target.style.cursor = 'initial'; - } - }, - handleMentionClick: (evt) => { - const target = evt.currentTarget; - const mentionId = target.getAttribute('data-mention-id'); - if (typeof mentionId !== 'string') return; - if (isUserId(mentionId)) { - openProfileViewer(mentionId, room.roomId); - return; - } - if (isRoomId(mentionId) && mx.getRoom(mentionId)) { - if (mx.getRoom(mentionId)?.isSpaceRoom()) navigateSpace(mentionId); - else navigateRoom(mentionId); - return; - } - openJoinAlias(mentionId); - }, + getReactCustomHtmlParser(mx, room.roomId, { + linkifyOpts, + useAuthentication, + handleSpoilerClick: spoilerClickHandler, + handleMentionClick: mentionClickHandler, }), - [mx, room, navigateRoom, navigateSpace] + [mx, room, linkifyOpts, mentionClickHandler, spoilerClickHandler, useAuthentication] ); const renderMatrixEvent = useMatrixEventRenderer<[IRoomEvent, string, GetContentCallback]>( @@ -229,6 +234,7 @@ function RoomNotificationsGroupComp({ mediaAutoLoad={mediaAutoLoad} urlPreview={urlPreview} htmlReactParserOptions={htmlReactParserOptions} + linkifyOpts={linkifyOpts} outlineAttachment /> ); @@ -287,6 +293,7 @@ function RoomNotificationsGroupComp({ mediaAutoLoad={mediaAutoLoad} urlPreview={urlPreview} htmlReactParserOptions={htmlReactParserOptions} + linkifyOpts={linkifyOpts} /> ); } @@ -350,7 +357,7 @@ function RoomNotificationsGroupComp({ } ); - const handleOpenClick: MouseEventHandler = (evt) => { + const handleOpenClick: MouseEventHandler = (evt) => { const eventId = evt.currentTarget.getAttribute('data-event-id'); if (!eventId) return; onOpen(room.roomId, eventId); @@ -366,7 +373,7 @@ function RoomNotificationsGroupComp({ ( @@ -401,7 +408,10 @@ function RoomNotificationsGroupComp({ const senderAvatarMxc = getMemberAvatarMxc(room, event.sender); const getContent = (() => event.content) as GetContentCallback; - const replyEventId = event.content['m.relates_to']?.['m.in_reply_to']?.event_id; + const relation = event.content['m.relates_to']; + const replyEventId = relation?.['m.in_reply_to']?.event_id; + const threadRootId = + relation?.rel_type === RelationType.Thread ? relation.event_id : undefined; return ( {replyEventId && ( )} @@ -484,6 +493,7 @@ export function Notifications() { const mx = useMatrixClient(); const [mediaAutoLoad] = useSetting(settingsAtom, 'mediaAutoLoad'); const [urlPreview] = useSetting(settingsAtom, 'urlPreview'); + const screenSize = useScreenSizeContext(); const { navigateRoom } = useRoomNavigate(); const [searchParams, setSearchParams] = useSearchParams(); @@ -549,12 +559,26 @@ export function Notifications() { return ( - - - - - Notification Messages - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Notification Messages + + + diff --git a/src/app/pages/client/sidebar/SpaceTabs.tsx b/src/app/pages/client/sidebar/SpaceTabs.tsx index 7b3e61e7..d63bb24d 100644 --- a/src/app/pages/client/sidebar/SpaceTabs.tsx +++ b/src/app/pages/client/sidebar/SpaceTabs.tsx @@ -47,13 +47,7 @@ import { import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { roomToParentsAtom } from '../../../state/room/roomToParents'; import { allRoomsAtom } from '../../../state/room-list/roomList'; -import { - getOriginBaseUrl, - getSpaceLobbyPath, - getSpacePath, - joinPathComponent, - withOriginBaseUrl, -} from '../../pathUtils'; +import { getSpaceLobbyPath, getSpacePath, joinPathComponent } from '../../pathUtils'; import { SidebarAvatar, SidebarItem, @@ -67,7 +61,7 @@ import { import { RoomUnreadProvider, RoomsUnreadProvider } from '../../../components/RoomUnreadProvider'; import { useSelectedSpace } from '../../../hooks/router/useSelectedSpace'; import { UnreadBadge } from '../../../components/unread-badge'; -import { getCanonicalAliasOrRoomId } from '../../../utils/matrix'; +import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../../utils/matrix'; import { RoomAvatar } from '../../../components/room-avatar'; import { nameInitials, randomStr } from '../../../utils/common'; import { @@ -83,7 +77,6 @@ import { AccountDataEvent } from '../../../../types/matrix/accountData'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { useNavToActivePathAtom } from '../../../state/hooks/navToActivePath'; import { useOpenedSidebarFolderAtom } from '../../../state/hooks/openedSidebarFolder'; -import { useClientConfig } from '../../../hooks/useClientConfig'; import { usePowerLevels, usePowerLevelsAPI } from '../../../hooks/usePowerLevels'; import { useRoomsUnread } from '../../../state/hooks/unread'; import { roomToUnreadAtom } from '../../../state/room/roomToUnread'; @@ -91,6 +84,10 @@ import { markAsRead } from '../../../../client/action/notifications'; import { copyToClipboard } from '../../../utils/dom'; import { openInviteUser, openSpaceSettings } from '../../../../client/action/navigation'; import { stopPropagation } from '../../../utils/keyboard'; +import { getMatrixToRoom } from '../../../plugins/matrix-to'; +import { getViaServers } from '../../../plugins/via-servers'; +import { getRoomAvatarUrl } from '../../../utils/room'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; type SpaceMenuProps = { room: Room; @@ -100,7 +97,6 @@ type SpaceMenuProps = { const SpaceMenu = forwardRef( ({ room, requestClose, onUnpin }, ref) => { const mx = useMatrixClient(); - const { hashRouter } = useClientConfig(); const roomToParents = useAtomValue(roomToParentsAtom); const powerLevels = usePowerLevels(room); const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); @@ -124,8 +120,9 @@ const SpaceMenu = forwardRef( }; const handleCopyLink = () => { - const spacePath = getSpacePath(getCanonicalAliasOrRoomId(mx, room.roomId)); - copyToClipboard(withOriginBaseUrl(getOriginBaseUrl(hashRouter), spacePath)); + const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, room.roomId); + const viaServers = isRoomAlias(roomIdOrAlias) ? undefined : getViaServers(room); + copyToClipboard(getMatrixToRoom(roomIdOrAlias, viaServers)); requestClose(); }; @@ -230,18 +227,18 @@ const useDraggableItem = ( return !target ? undefined : draggable({ - element: target, - dragHandle, - getInitialData: () => ({ item }), - onDragStart: () => { - setDragging(true); - onDragging?.(item); - }, - onDrop: () => { - setDragging(false); - onDragging?.(undefined); - }, - }); + element: target, + dragHandle, + getInitialData: () => ({ item }), + onDragStart: () => { + setDragging(true); + onDragging?.(item); + }, + onDrop: () => { + setDragging(false); + onDragging?.(undefined); + }, + }); }, [targetRef, dragHandleRef, item, onDragging]); return dragging; @@ -384,15 +381,17 @@ function SpaceTab({ onUnpin, }: SpaceTabProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const targetRef = useRef(null); const spaceDraggable: SidebarDraggable = useMemo( () => folder ? { - folder, - spaceId: space.roomId, - } + folder, + spaceId: space.roomId, + } : space.roomId, [folder, space] ); @@ -436,7 +435,7 @@ function SpaceTab({ > ( {nameInitials(space.name, 2)} @@ -529,6 +528,8 @@ function ClosedSpaceFolder({ disabled, }: ClosedSpaceFolderProps) { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const handlerRef = useRef(null); const spaceDraggable: FolderDraggable = useMemo(() => ({ folder }), [folder]); @@ -561,7 +562,7 @@ function ClosedSpaceFolder({ ( diff --git a/src/app/pages/client/sidebar/UnverifiedTab.css.ts b/src/app/pages/client/sidebar/UnverifiedTab.css.ts new file mode 100644 index 00000000..e8fe8c51 --- /dev/null +++ b/src/app/pages/client/sidebar/UnverifiedTab.css.ts @@ -0,0 +1,24 @@ +import { keyframes, style } from '@vanilla-extract/css'; +import { color, toRem } from 'folds'; + +const pushRight = keyframes({ + from: { + transform: `translateX(${toRem(2)}) scale(1)`, + }, + to: { + transform: 'translateX(0) scale(1)', + }, +}); + +export const UnverifiedTab = style({ + animationName: pushRight, + animationDuration: '400ms', + animationIterationCount: 30, + animationDirection: 'alternate', +}); + +export const UnverifiedAvatar = style({ + backgroundColor: color.Critical.Container, + color: color.Critical.OnContainer, + borderColor: color.Critical.ContainerLine, +}); diff --git a/src/app/pages/client/sidebar/UnverifiedTab.tsx b/src/app/pages/client/sidebar/UnverifiedTab.tsx new file mode 100644 index 00000000..919c4a70 --- /dev/null +++ b/src/app/pages/client/sidebar/UnverifiedTab.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { Badge, color, Icon, Icons, Text } from 'folds'; +import { openSettings } from '../../../../client/action/navigation'; +import { isCrossVerified } from '../../../../util/matrixUtil'; +import { + SidebarAvatar, + SidebarItem, + SidebarItemBadge, + SidebarItemTooltip, +} from '../../../components/sidebar'; +import { useDeviceList } from '../../../hooks/useDeviceList'; +import { tabText } from '../../../organisms/settings/Settings'; +import { useMatrixClient } from '../../../hooks/useMatrixClient'; +import * as css from './UnverifiedTab.css'; + +export function UnverifiedTab() { + const mx = useMatrixClient(); + const deviceList = useDeviceList(); + const unverified = deviceList?.filter( + (device) => isCrossVerified(mx, device.device_id) === false + ); + + if (!unverified?.length) return null; + + return ( + + + {(triggerRef) => ( + openSettings(tabText.SECURITY)} + > + + + )} + + + + + {unverified.length} + + + + + ); +} diff --git a/src/app/pages/client/sidebar/UserTab.tsx b/src/app/pages/client/sidebar/UserTab.tsx index 89c035bb..09b3f251 100644 --- a/src/app/pages/client/sidebar/UserTab.tsx +++ b/src/app/pages/client/sidebar/UserTab.tsx @@ -5,8 +5,9 @@ import { SidebarItem, SidebarItemTooltip, SidebarAvatar } from '../../../compone import { openSettings } from '../../../../client/action/navigation'; import { UserAvatar } from '../../../components/user-avatar'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; -import { getMxIdLocalPart } from '../../../utils/matrix'; +import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix'; import { nameInitials } from '../../../utils/common'; +import { useSpecVersions } from '../../../hooks/useSpecVersions'; type UserProfile = { avatar_url?: string; @@ -14,12 +15,14 @@ type UserProfile = { }; export function UserTab() { const mx = useMatrixClient(); + const { versions } = useSpecVersions(); + const useAuthentication = versions.includes('v1.11'); const userId = mx.getUserId()!; const [profile, setProfile] = useState({}); const displayName = profile.displayname ?? getMxIdLocalPart(userId) ?? userId; const avatarUrl = profile.avatar_url - ? mx.mxcUrlToHttp(profile.avatar_url, 96, 96, 'crop') ?? undefined + ? mxcUrlToHttp(mx, profile.avatar_url, useAuthentication, 96, 96, 'crop') ?? undefined : undefined; useEffect(() => { diff --git a/src/app/pages/client/sidebar/index.ts b/src/app/pages/client/sidebar/index.ts index 63c5d4bb..5da8780b 100644 --- a/src/app/pages/client/sidebar/index.ts +++ b/src/app/pages/client/sidebar/index.ts @@ -4,3 +4,4 @@ export * from './SpaceTabs'; export * from './InboxTab'; export * from './ExploreTab'; export * from './UserTab'; +export * from './UnverifiedTab'; diff --git a/src/app/pages/client/space/RoomProvider.tsx b/src/app/pages/client/space/RoomProvider.tsx index 1105e220..0f13f933 100644 --- a/src/app/pages/client/space/RoomProvider.tsx +++ b/src/app/pages/client/space/RoomProvider.tsx @@ -9,6 +9,7 @@ import { useSpace } from '../../../hooks/useSpace'; import { getAllParents } from '../../../utils/room'; import { roomToParentsAtom } from '../../../state/room/roomToParents'; import { allRoomsAtom } from '../../../state/room-list/roomList'; +import { useSearchParamsViaServers } from '../../../hooks/router/useSearchParamsViaServers'; export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) { const mx = useMatrixClient(); @@ -16,7 +17,8 @@ export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) { const roomToParents = useAtomValue(roomToParentsAtom); const allRooms = useAtomValue(allRoomsAtom); - const { roomIdOrAlias } = useParams(); + const { roomIdOrAlias, eventId } = useParams(); + const viaServers = useSearchParamsViaServers(); const roomId = useSelectedRoom(); const room = mx.getRoom(roomId); @@ -26,7 +28,13 @@ export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) { !allRooms.includes(room.roomId) || !getAllParents(roomToParents, room.roomId).has(space.roomId) ) { - return ; + return ( + + ); } return ( diff --git a/src/app/pages/client/space/Search.tsx b/src/app/pages/client/space/Search.tsx index 6e7ac57d..017262b5 100644 --- a/src/app/pages/client/space/Search.tsx +++ b/src/app/pages/client/space/Search.tsx @@ -1,5 +1,5 @@ import React, { useRef } from 'react'; -import { Box, Icon, Icons, Text, Scroll } from 'folds'; +import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds'; import { useAtomValue } from 'jotai'; import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page'; import { MessageSearch } from '../../../features/message-search'; @@ -9,11 +9,14 @@ import { allRoomsAtom } from '../../../state/room-list/roomList'; import { mDirectAtom } from '../../../state/mDirectList'; import { roomToParentsAtom } from '../../../state/room/roomToParents'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; +import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; +import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function SpaceSearch() { const mx = useMatrixClient(); const scrollRef = useRef(null); const space = useSpace(); + const screenSize = useScreenSizeContext(); const mDirects = useAtomValue(mDirectAtom); const roomToParents = useAtomValue(roomToParentsAtom); @@ -25,12 +28,26 @@ export function SpaceSearch() { return ( - - - - - Message Search - + + + + {screenSize === ScreenSize.Mobile && ( + + {(onBack) => ( + + + + )} + + )} + + + {screenSize !== ScreenSize.Mobile && } + + Message Search + + + diff --git a/src/app/pages/client/space/Space.tsx b/src/app/pages/client/space/Space.tsx index e280c603..d3dc0be7 100644 --- a/src/app/pages/client/space/Space.tsx +++ b/src/app/pages/client/space/Space.tsx @@ -34,15 +34,8 @@ import { NavItemContent, NavLink, } from '../../../components/nav'; -import { - getOriginBaseUrl, - getSpaceLobbyPath, - getSpacePath, - getSpaceRoomPath, - getSpaceSearchPath, - withOriginBaseUrl, -} from '../../pathUtils'; -import { getCanonicalAliasOrRoomId } from '../../../utils/matrix'; +import { getSpaceLobbyPath, getSpaceRoomPath, getSpaceSearchPath } from '../../pathUtils'; +import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../../utils/matrix'; import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom'; import { useSpaceLobbySelected, @@ -69,11 +62,12 @@ import { useRoomsUnread } from '../../../state/hooks/unread'; import { UseStateProvider } from '../../../components/UseStateProvider'; import { LeaveSpacePrompt } from '../../../components/leave-space-prompt'; import { copyToClipboard } from '../../../utils/dom'; -import { useClientConfig } from '../../../hooks/useClientConfig'; import { useClosedNavCategoriesAtom } from '../../../state/hooks/closedNavCategories'; import { useStateEvent } from '../../../hooks/useStateEvent'; import { StateEvent } from '../../../../types/matrix/room'; import { stopPropagation } from '../../../utils/keyboard'; +import { getMatrixToRoom } from '../../../plugins/matrix-to'; +import { getViaServers } from '../../../plugins/via-servers'; type SpaceMenuProps = { room: Room; @@ -81,7 +75,6 @@ type SpaceMenuProps = { }; const SpaceMenu = forwardRef(({ room, requestClose }, ref) => { const mx = useMatrixClient(); - const { hashRouter } = useClientConfig(); const roomToParents = useAtomValue(roomToParentsAtom); const powerLevels = usePowerLevels(room); const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels); @@ -100,8 +93,9 @@ const SpaceMenu = forwardRef(({ room, requestClo }; const handleCopyLink = () => { - const spacePath = getSpacePath(getCanonicalAliasOrRoomId(mx, room.roomId)); - copyToClipboard(withOriginBaseUrl(getOriginBaseUrl(hashRouter), spacePath)); + const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, room.roomId); + const viaServers = isRoomAlias(roomIdOrAlias) ? undefined : getViaServers(room); + copyToClipboard(getMatrixToRoom(roomIdOrAlias, viaServers)); requestClose(); }; diff --git a/src/app/pages/client/space/SpaceProvider.tsx b/src/app/pages/client/space/SpaceProvider.tsx index 530fc3cc..2e0f79a2 100644 --- a/src/app/pages/client/space/SpaceProvider.tsx +++ b/src/app/pages/client/space/SpaceProvider.tsx @@ -6,6 +6,7 @@ import { allRoomsAtom } from '../../../state/room-list/roomList'; import { useSelectedSpace } from '../../../hooks/router/useSelectedSpace'; import { SpaceProvider } from '../../../hooks/useSpace'; import { JoinBeforeNavigate } from '../../../features/join-before-navigate'; +import { useSearchParamsViaServers } from '../../../hooks/router/useSearchParamsViaServers'; type RouteSpaceProviderProps = { children: ReactNode; @@ -13,13 +14,15 @@ type RouteSpaceProviderProps = { export function RouteSpaceProvider({ children }: RouteSpaceProviderProps) { const mx = useMatrixClient(); const joinedSpaces = useSpaces(mx, allRoomsAtom); + const { spaceIdOrAlias } = useParams(); + const viaServers = useSearchParamsViaServers(); const selectedSpaceId = useSelectedSpace(); const space = mx.getRoom(selectedSpaceId); if (!space || !joinedSpaces.includes(space.roomId)) { - return ; + return ; } return ( diff --git a/src/app/pages/pathSearchParam.ts b/src/app/pages/pathSearchParam.ts new file mode 100644 index 00000000..8e4c93e5 --- /dev/null +++ b/src/app/pages/pathSearchParam.ts @@ -0,0 +1,13 @@ +import { _RoomSearchParams, DirectCreateSearchParams } from './paths'; + +type SearchParamsGetter = (searchParams: URLSearchParams) => T; + +export const getRoomSearchParams: SearchParamsGetter<_RoomSearchParams> = (searchParams) => ({ + viaServers: searchParams.get('viaServers') ?? undefined, +}); + +export const getDirectCreateSearchParams: SearchParamsGetter = ( + searchParams +) => ({ + userId: searchParams.get('userId') ?? undefined, +}); diff --git a/src/app/pages/paths.ts b/src/app/pages/paths.ts index fd3266e9..57750383 100644 --- a/src/app/pages/paths.ts +++ b/src/app/pages/paths.ts @@ -35,6 +35,11 @@ export type _SearchPathSearchParams = { senders?: string; }; export const _SEARCH_PATH = 'search/'; + +export type _RoomSearchParams = { + /* comma separated string of servers */ + viaServers?: string; +}; export const _ROOM_PATH = ':roomIdOrAlias/:eventId?/'; export const HOME_PATH = '/home/'; @@ -44,6 +49,9 @@ export const HOME_SEARCH_PATH = `/home/${_SEARCH_PATH}`; export const HOME_ROOM_PATH = `/home/${_ROOM_PATH}`; export const DIRECT_PATH = '/direct/'; +export type DirectCreateSearchParams = { + userId?: string; +}; export const DIRECT_CREATE_PATH = `/direct/${_CREATE_PATH}`; export const DIRECT_ROOM_PATH = `/direct/${_ROOM_PATH}`; diff --git a/src/app/plugins/matrix-to.ts b/src/app/plugins/matrix-to.ts new file mode 100644 index 00000000..c9df0a87 --- /dev/null +++ b/src/app/plugins/matrix-to.ts @@ -0,0 +1,84 @@ +const MATRIX_TO_BASE = 'https://matrix.to'; + +export const getMatrixToUser = (userId: string): string => `${MATRIX_TO_BASE}/#/${userId}`; + +const withViaServers = (fragment: string, viaServers: string[]): string => + `${fragment}?${viaServers.map((server) => `via=${server}`).join('&')}`; + +export const getMatrixToRoom = (roomIdOrAlias: string, viaServers?: string[]): string => { + let fragment = roomIdOrAlias; + + if (Array.isArray(viaServers) && viaServers.length > 0) { + fragment = withViaServers(fragment, viaServers); + } + + return `${MATRIX_TO_BASE}/#/${fragment}`; +}; + +export const getMatrixToRoomEvent = ( + roomIdOrAlias: string, + eventId: string, + viaServers?: string[] +): string => { + let fragment = `${roomIdOrAlias}/${eventId}`; + + if (Array.isArray(viaServers) && viaServers.length > 0) { + fragment = withViaServers(fragment, viaServers); + } + + return `${MATRIX_TO_BASE}/#/${fragment}`; +}; + +export type MatrixToRoom = { + roomIdOrAlias: string; + viaServers?: string[]; +}; + +export type MatrixToRoomEvent = MatrixToRoom & { + eventId: string; +}; + +const MATRIX_TO = /^https?:\/\/matrix\.to\S*$/; +export const testMatrixTo = (href: string): boolean => MATRIX_TO.test(href); + +const MATRIX_TO_USER = /^https?:\/\/matrix\.to\/#\/(@[^:\s]+:[^?/\s]+)\/?$/; +const MATRIX_TO_ROOM = /^https?:\/\/matrix\.to\/#\/([#!][^:\s]+:[^?/\s]+)\/?(\?[\S]*)?$/; +const MATRIX_TO_ROOM_EVENT = + /^https?:\/\/matrix\.to\/#\/([#!][^:\s]+:[^?/\s]+)\/(\$[^?/\s]+)\/?(\?[\S]*)?$/; + +export const parseMatrixToUser = (href: string): string | undefined => { + const match = href.match(MATRIX_TO_USER); + if (!match) return undefined; + const userId = match[1]; + return userId; +}; + +export const parseMatrixToRoom = (href: string): MatrixToRoom | undefined => { + const match = href.match(MATRIX_TO_ROOM); + if (!match) return undefined; + + const roomIdOrAlias = match[1]; + const viaSearchStr = match[2]; + const viaServers = new URLSearchParams(viaSearchStr).getAll('via'); + + return { + roomIdOrAlias, + viaServers: viaServers.length === 0 ? undefined : viaServers, + }; +}; + +export const parseMatrixToRoomEvent = (href: string): MatrixToRoomEvent | undefined => { + const match = href.match(MATRIX_TO_ROOM_EVENT); + if (!match) return undefined; + + const roomIdOrAlias = match[1]; + const eventId = match[2]; + const viaSearchStr = match[3]; + const viaServers = new URLSearchParams(viaSearchStr).getAll('via'); + + return { + roomIdOrAlias, + eventId, + viaServers: viaServers.length === 0 ? undefined : viaServers, + }; +}; diff --git a/src/app/plugins/react-custom-html-parser.tsx b/src/app/plugins/react-custom-html-parser.tsx index a8086687..ab333704 100644 --- a/src/app/plugins/react-custom-html-parser.tsx +++ b/src/app/plugins/react-custom-html-parser.tsx @@ -1,5 +1,5 @@ /* eslint-disable jsx-a11y/alt-text */ -import React, { ReactEventHandler, Suspense, lazy } from 'react'; +import React, { ComponentPropsWithoutRef, ReactEventHandler, Suspense, lazy } from 'react'; import { Element, Text as DOMText, @@ -7,18 +7,26 @@ import { attributesToProps, domToReact, } from 'html-react-parser'; -import { MatrixClient, Room } from 'matrix-js-sdk'; +import { MatrixClient } from 'matrix-js-sdk'; import classNames from 'classnames'; import { Scroll, Text } from 'folds'; -import { Opts as LinkifyOpts } from 'linkifyjs'; +import { IntermediateRepresentation, Opts as LinkifyOpts, OptFn } from 'linkifyjs'; import Linkify from 'linkify-react'; import { ErrorBoundary } from 'react-error-boundary'; import * as css from '../styles/CustomHtml.css'; -import { getMxIdLocalPart, getCanonicalAliasRoomId } from '../utils/matrix'; +import { getMxIdLocalPart, getCanonicalAliasRoomId, isRoomAlias, mxcUrlToHttp } from '../utils/matrix'; import { getMemberDisplayName } from '../utils/room'; import { EMOJI_PATTERN, URL_NEG_LB } from '../utils/regex'; import { getHexcodeForEmoji, getShortcodeFor } from './emoji'; import { findAndReplace } from '../utils/findAndReplace'; +import { + parseMatrixToRoom, + parseMatrixToRoomEvent, + parseMatrixToUser, + testMatrixTo, +} from './matrix-to'; +import { onEnterOrSpace } from '../utils/keyboard'; +import { tryDecodeURIComponent } from '../utils/dom'; const ReactPrism = lazy(() => import('./react-prism/ReactPrism')); @@ -35,6 +43,107 @@ export const LINKIFY_OPTS: LinkifyOpts = { ignoreTags: ['span'], }; +export const makeMentionCustomProps = ( + handleMentionClick?: ReactEventHandler +): ComponentPropsWithoutRef<'a'> => ({ + style: { cursor: 'pointer' }, + target: '_blank', + rel: 'noreferrer noopener', + role: 'link', + tabIndex: handleMentionClick ? 0 : -1, + onKeyDown: handleMentionClick ? onEnterOrSpace(handleMentionClick) : undefined, + onClick: handleMentionClick, +}); + +export const renderMatrixMention = ( + mx: MatrixClient, + currentRoomId: string | undefined, + href: string, + customProps: ComponentPropsWithoutRef<'a'> +) => { + const userId = parseMatrixToUser(href); + if (userId) { + const currentRoom = mx.getRoom(currentRoomId); + + return ( + + {`@${(currentRoom && getMemberDisplayName(currentRoom, userId)) ?? getMxIdLocalPart(userId) + }`} + + ); + } + + const matrixToRoom = parseMatrixToRoom(href); + if (matrixToRoom) { + const { roomIdOrAlias, viaServers } = matrixToRoom; + const mentionRoom = mx.getRoom( + isRoomAlias(roomIdOrAlias) ? getCanonicalAliasRoomId(mx, roomIdOrAlias) : roomIdOrAlias + ); + + return ( + + {mentionRoom ? `#${mentionRoom.name}` : roomIdOrAlias} + + ); + } + + const matrixToRoomEvent = parseMatrixToRoomEvent(href); + if (matrixToRoomEvent) { + const { roomIdOrAlias, eventId, viaServers } = matrixToRoomEvent; + const mentionRoom = mx.getRoom( + isRoomAlias(roomIdOrAlias) ? getCanonicalAliasRoomId(mx, roomIdOrAlias) : roomIdOrAlias + ); + + return ( + + Message: {mentionRoom ? `#${mentionRoom.name}` : roomIdOrAlias} + + ); + } + + return undefined; +}; + +export const factoryRenderLinkifyWithMention = ( + mentionRender: (href: string) => JSX.Element | undefined +): OptFn<(ir: IntermediateRepresentation) => any> => { + const render: OptFn<(ir: IntermediateRepresentation) => any> = ({ + tagName, + attributes, + content, + }) => { + if (tagName === 'a' && testMatrixTo(tryDecodeURIComponent(attributes.href))) { + const mention = mentionRender(tryDecodeURIComponent(attributes.href)); + if (mention) return mention; + } + + return {content}; + }; + return render; +}; + export const scaleSystemEmoji = (text: string): (string | JSX.Element)[] => findAndReplace( text, @@ -76,11 +185,13 @@ export const highlightText = ( export const getReactCustomHtmlParser = ( mx: MatrixClient, - room: Room, + roomId: string | undefined, params: { + linkifyOpts: LinkifyOpts; highlightRegex?: RegExp; handleSpoilerClick?: ReactEventHandler; handleMentionClick?: ReactEventHandler; + useAuthentication?: boolean; } ): HTMLReactParserOptions => { const opts: HTMLReactParserOptions = { @@ -215,54 +326,14 @@ export const getReactCustomHtmlParser = ( } } - if (name === 'a') { - const mention = decodeURIComponent(props.href).match( - /^https?:\/\/matrix.to\/#\/((@|#|!).+:[^?/]+)/ + if (name === 'a' && testMatrixTo(tryDecodeURIComponent(props.href))) { + const mention = renderMatrixMention( + mx, + roomId, + tryDecodeURIComponent(props.href), + makeMentionCustomProps(params.handleMentionClick) ); - if (mention) { - // convert mention link to pill - const mentionId = mention[1]; - const mentionPrefix = mention[2]; - if (mentionPrefix === '#' || mentionPrefix === '!') { - const mentionRoom = mx.getRoom( - mentionPrefix === '#' ? getCanonicalAliasRoomId(mx, mentionId) : mentionId - ); - - return ( - - {domToReact(children, opts)} - - ); - } - if (mentionPrefix === '@') - return ( - - {`@${getMemberDisplayName(room, mentionId) ?? getMxIdLocalPart(mentionId)}`} - - ); - } + if (mention) return mention; } if (name === 'span' && 'data-mx-spoiler' in props) { @@ -283,7 +354,7 @@ export const getReactCustomHtmlParser = ( } if (name === 'img') { - const htmlSrc = mx.mxcUrlToHttp(props.src); + const htmlSrc = mxcUrlToHttp(mx, props.src, params.useAuthentication); if (htmlSrc && props.src.startsWith('mxc://') === false) { return ( @@ -316,7 +387,7 @@ export const getReactCustomHtmlParser = ( } if (linkify) { - return {jsx}; + return {jsx}; } return jsx; } diff --git a/src/app/plugins/via-servers.ts b/src/app/plugins/via-servers.ts new file mode 100644 index 00000000..75470999 --- /dev/null +++ b/src/app/plugins/via-servers.ts @@ -0,0 +1,65 @@ +import { Room } from 'matrix-js-sdk'; +import { IPowerLevels } from '../hooks/usePowerLevels'; +import { getMxIdServer } from '../utils/matrix'; +import { StateEvent } from '../../types/matrix/room'; +import { getStateEvent } from '../utils/room'; + +export const getViaServers = (room: Room): string[] => { + const getHighestPowerUserId = (): string | undefined => { + const powerLevels = getStateEvent(room, StateEvent.RoomPowerLevels)?.getContent(); + + if (!powerLevels) return undefined; + const userIdToPower = powerLevels.users; + if (!userIdToPower) return undefined; + let powerUserId: string | undefined; + + Object.keys(userIdToPower).forEach((userId) => { + if (userIdToPower[userId] <= (powerLevels.users_default ?? 0)) return; + + if (!powerUserId) { + powerUserId = userId; + return; + } + if (userIdToPower[userId] > userIdToPower[powerUserId]) { + powerUserId = userId; + } + }); + return powerUserId; + }; + + const getServerToPopulation = (): Record => { + const members = room.getMembers(); + const serverToPop: Record = {}; + + members?.forEach((member) => { + const { userId } = member; + const server = getMxIdServer(userId); + if (!server) return; + const serverPop = serverToPop[server]; + if (serverPop === undefined) { + serverToPop[server] = 1; + return; + } + serverToPop[server] = serverPop + 1; + }); + + return serverToPop; + }; + + const via: string[] = []; + const userId = getHighestPowerUserId(); + if (userId) { + const server = getMxIdServer(userId); + if (server) via.push(server); + } + const serverToPop = getServerToPopulation(); + const sortedServers = Object.keys(serverToPop).sort( + (svrA, svrB) => serverToPop[svrB] - serverToPop[svrA] + ); + const mostPop3 = sortedServers.slice(0, 3); + if (via.length === 0) return mostPop3; + if (mostPop3.includes(via[0])) { + mostPop3.splice(mostPop3.indexOf(via[0]), 1); + } + return via.concat(mostPop3.slice(0, 2)); +}; diff --git a/src/app/state/room/roomInputDrafts.ts b/src/app/state/room/roomInputDrafts.ts index 60b42fdb..33bd0607 100644 --- a/src/app/state/room/roomInputDrafts.ts +++ b/src/app/state/room/roomInputDrafts.ts @@ -2,6 +2,7 @@ import { atom } from 'jotai'; import { atomFamily } from 'jotai/utils'; import { Descendant } from 'slate'; import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment'; +import { IEventRelation } from 'matrix-js-sdk'; import { TListAtom, createListAtom } from '../list'; import { createUploadAtomFamily } from '../upload'; import { TUploadContent } from '../../utils/matrix'; @@ -39,7 +40,8 @@ export type IReplyDraft = { userId: string; eventId: string; body: string; - formattedBody?: string; + formattedBody?: string | undefined; + relation?: IEventRelation | undefined; }; const createReplyDraftAtom = () => atom(undefined); export type TReplyDraftAtom = ReturnType; diff --git a/src/app/state/room/roomToParents.ts b/src/app/state/room/roomToParents.ts index b58190cd..f66662ff 100644 --- a/src/app/state/room/roomToParents.ts +++ b/src/app/state/room/roomToParents.ts @@ -83,7 +83,7 @@ export const useBindRoomToParentsAtom = ( }; const handleMembershipChange = (room: Room, membership: string) => { - if (room.getMyMembership() === Membership.Leave) { + if (isSpace(room) && room.getMyMembership() === Membership.Leave) { setRoomToParents({ type: 'DELETE', roomId: room.roomId }); return; } diff --git a/src/app/utils/dom.ts b/src/app/utils/dom.ts index 1aea6754..ab4b8e65 100644 --- a/src/app/utils/dom.ts +++ b/src/app/utils/dom.ts @@ -196,3 +196,11 @@ export const setFavicon = (url: string): void => { if (!favicon) return; favicon.setAttribute('href', url); }; + +export const tryDecodeURIComponent = (encodedURIComponent: string): string => { + try { + return decodeURIComponent(encodedURIComponent); + } catch { + return encodedURIComponent; + } +}; diff --git a/src/app/utils/keyboard.ts b/src/app/utils/keyboard.ts index da3fe8cb..46a951ff 100644 --- a/src/app/utils/keyboard.ts +++ b/src/app/utils/keyboard.ts @@ -24,12 +24,14 @@ export const preventScrollWithArrowKey: KeyboardEventHandler = (evt) => { } }; -export const onEnterOrSpace = (callback: () => void) => (evt: KeyboardEventLike) => { - if (isKeyHotkey('enter', evt) || isKeyHotkey('space', evt)) { - evt.preventDefault(); - callback(); - } -}; +export const onEnterOrSpace = + (callback: (evt: T) => void) => + (evt: KeyboardEventLike) => { + if (isKeyHotkey('enter', evt) || isKeyHotkey('space', evt)) { + evt.preventDefault(); + callback(evt as T); + } + }; export const stopPropagation = (evt: KeyboardEvent): boolean => { evt.stopPropagation(); diff --git a/src/app/utils/matrix.ts b/src/app/utils/matrix.ts index 278bb46b..65a1080b 100644 --- a/src/app/utils/matrix.ts +++ b/src/app/utils/matrix.ts @@ -32,17 +32,14 @@ export const isRoomId = (id: string): boolean => validMxId(id) && id.startsWith( export const isRoomAlias = (id: string): boolean => validMxId(id) && id.startsWith('#'); -export const parseMatrixToUrl = (url: string): [string | undefined, string | undefined] => { - const href = decodeURIComponent(url); - - const match = href.match(/^https?:\/\/matrix.to\/#\/([@!$+#]\S+:[^\\?|^\s|^\\/]+)(\?(via=\S+))?/); - if (!match) return [undefined, undefined]; - const [, g1AsMxId, , g3AsVia] = match; - return [g1AsMxId, g3AsVia]; -}; - export const getCanonicalAliasRoomId = (mx: MatrixClient, alias: string): string | undefined => - mx.getRooms()?.find((room) => room.getCanonicalAlias() === alias)?.roomId; + mx + .getRooms() + ?.find( + (room) => + room.getCanonicalAlias() === alias && + getStateEvent(room, StateEvent.RoomTombstone) === undefined + )?.roomId; export const getCanonicalAliasOrRoomId = (mx: MatrixClient, roomId: string): string => { const room = mx.getRoom(roomId); @@ -256,3 +253,23 @@ export const removeRoomIdFromMDirect = async (mx: MatrixClient, roomId: string): await mx.setAccountData(AccountDataEvent.Direct, userIdToRoomIds); }; + +export const mxcUrlToHttp = ( + mx: MatrixClient, + mxcUrl: string, + useAuthentication?: boolean, + width?: number, + height?: number, + resizeMethod?: string, + allowDirectLinks?: boolean, + allowRedirects?: boolean +): string | null => + mx.mxcUrlToHttp( + mxcUrl, + width, + height, + resizeMethod, + allowDirectLinks, + allowRedirects, + useAuthentication + ); diff --git a/src/app/utils/room.ts b/src/app/utils/room.ts index 750dd6ca..5f4615a6 100644 --- a/src/app/utils/room.ts +++ b/src/app/utils/room.ts @@ -273,16 +273,26 @@ export const joinRuleToIconSrc = ( export const getRoomAvatarUrl = ( mx: MatrixClient, room: Room, - size: 32 | 96 = 32 -): string | undefined => room.getAvatarUrl(mx.baseUrl, size, size, 'crop') ?? undefined; + size: 32 | 96 = 32, + useAuthentication = false +): string | undefined => { + const mxcUrl = room.getMxcAvatarUrl(); + return mxcUrl + ? mx.mxcUrlToHttp(mxcUrl, size, size, 'crop', undefined, false, useAuthentication) ?? undefined + : undefined; +}; export const getDirectRoomAvatarUrl = ( mx: MatrixClient, room: Room, - size: 32 | 96 = 32 -): string | undefined => - room.getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, size, size, 'crop', undefined, false) ?? - undefined; + size: 32 | 96 = 32, + useAuthentication = false +): string | undefined => { + const mxcUrl = room.getAvatarFallbackMember()?.getMxcAvatarUrl(); + return mxcUrl + ? mx.mxcUrlToHttp(mxcUrl, size, size, 'crop', undefined, false, useAuthentication) ?? undefined + : undefined; +}; export const trimReplyFromBody = (body: string): string => { const match = body.match(/^> <.+?> .+\n(>.*\n)*?\n/m); @@ -389,13 +399,18 @@ export const getEditedEvent = ( return edits && getLatestEdit(mEvent, edits.getRelations()); }; -export const canEditEvent = (mx: MatrixClient, mEvent: MatrixEvent) => - mEvent.getSender() === mx.getUserId() && - !mEvent.isRelation() && - mEvent.getType() === MessageEvent.RoomMessage && - (mEvent.getContent().msgtype === MsgType.Text || - mEvent.getContent().msgtype === MsgType.Emote || - mEvent.getContent().msgtype === MsgType.Notice); +export const canEditEvent = (mx: MatrixClient, mEvent: MatrixEvent) => { + const content = mEvent.getContent(); + const relationType = content['m.relates_to']?.rel_type; + return ( + mEvent.getSender() === mx.getUserId() && + (!relationType || relationType === RelationType.Thread) && + mEvent.getType() === MessageEvent.RoomMessage && + (content.msgtype === MsgType.Text || + content.msgtype === MsgType.Emote || + content.msgtype === MsgType.Notice) + ); +}; export const getLatestEditableEvt = ( timeline: EventTimeline, diff --git a/src/client/initMatrix.ts b/src/client/initMatrix.ts index 5a156ad8..52e8317e 100644 --- a/src/client/initMatrix.ts +++ b/src/client/initMatrix.ts @@ -23,7 +23,6 @@ export const initClient = async (session: Session): Promise => { localStorage: global.localStorage, dbName: 'web-sync-store', }); - await indexedDBStore.startup(); const mx = createClient({ baseUrl: session.baseUrl, @@ -38,6 +37,7 @@ export const initClient = async (session: Session): Promise => { }); await mx.initCrypto(); + await indexedDBStore.startup(); mx.setGlobalErrorOnUnknownDevices(false); mx.setMaxListeners(50); diff --git a/src/client/state/cons.js b/src/client/state/cons.js index 157d4a62..f7f65db2 100644 --- a/src/client/state/cons.js +++ b/src/client/state/cons.js @@ -1,5 +1,5 @@ const cons = { - version: '4.0.3', + version: '4.1.0', secretKey: { ACCESS_TOKEN: 'cinny_access_token', DEVICE_ID: 'cinny_device_id', diff --git a/src/index.tsx b/src/index.tsx index 1d864203..58ecc42a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -12,11 +12,32 @@ import './index.scss'; import settings from './client/state/settings'; +import { trimTrailingSlash } from './app/utils/common'; import App from './app/pages/App'; +// import i18n (needs to be bundled ;)) +import './app/i18n'; + document.body.classList.add(configClass, varsClass); settings.applyTheme(); +// Register Service Worker +if ('serviceWorker' in navigator) { + navigator.serviceWorker.register( + import.meta.env.MODE === 'production' ? `${trimTrailingSlash(import.meta.env.BASE_URL)}/sw.js` : '/dev-sw.js?dev-sw' + ) + navigator.serviceWorker.addEventListener('message', (event) => { + if (event.data?.type === 'token' && event.data?.responseKey) { + // Get the token for SW. + const token = localStorage.getItem('cinny_access_token'); + event.source!.postMessage({ + responseKey: event.data.responseKey, + token, + }) + } + }) +} + const mountApp = () => { const rootContainer = document.getElementById('root'); diff --git a/src/sw.ts b/src/sw.ts new file mode 100644 index 00000000..11953917 --- /dev/null +++ b/src/sw.ts @@ -0,0 +1,43 @@ +async function askForAccessToken(client: Client): Promise { + return new Promise((resolve) => { + const responseKey = Math.random().toString(36); + const listener = (event: ExtendableMessageEvent) => { + if (event.data.responseKey !== responseKey) return; + resolve(event.data.token); + self.removeEventListener('message', listener); + }; + self.addEventListener('message', listener); + client.postMessage({ responseKey, type: 'token' }); + }); +} + +function fetchConfig(token?: string): RequestInit | undefined { + if (!token) return undefined; + + return { + headers: { + Authorization: `Bearer ${token}`, + }, + }; +} + +self.addEventListener('fetch', (event: FetchEvent) => { + const { url, method } = event.request; + if (method !== 'GET') return; + if ( + !url.includes('/_matrix/client/v1/media/download') && + !url.includes('/_matrix/client/v1/media/thumbnail') + ) { + return; + } + event.respondWith( + (async (): Promise => { + const client = await clients.get(event.clientId); + let token: string | undefined; + if (client) token = await askForAccessToken(client); + + // eslint-disable-next-line consistent-return + return fetch(url, fetchConfig(token)); + })() + ); +}); diff --git a/src/util/matrixUtil.js b/src/util/matrixUtil.js index e4fd40c3..7664c3a4 100644 --- a/src/util/matrixUtil.js +++ b/src/util/matrixUtil.js @@ -95,74 +95,18 @@ export function joinRuleToIconSrc(joinRule, isSpace) { }[joinRule]?.() || null); } -// NOTE: it gives userId with minimum power level 50; -function getHighestPowerUserId(room) { - const userIdToPower = room.currentState.getStateEvents('m.room.power_levels', '')?.getContent().users; - let powerUserId = null; - if (!userIdToPower) return powerUserId; - - Object.keys(userIdToPower).forEach((userId) => { - if (userIdToPower[userId] < 50) return; - if (powerUserId === null) { - powerUserId = userId; - return; - } - if (userIdToPower[userId] > userIdToPower[powerUserId]) { - powerUserId = userId; - } - }); - return powerUserId; -} - export function getIdServer(userId) { const idParts = userId.split(':'); return idParts[1]; } -export function getServerToPopulation(room) { - const members = room.getMembers(); - const serverToPop = {}; - - members?.forEach((member) => { - const { userId } = member; - const server = getIdServer(userId); - const serverPop = serverToPop[server]; - if (serverPop === undefined) { - serverToPop[server] = 1; - return; - } - serverToPop[server] = serverPop + 1; - }); - - return serverToPop; -} - -export function genRoomVia(room) { - const via = []; - const userId = getHighestPowerUserId(room); - if (userId) { - const server = getIdServer(userId); - if (server) via.push(server); - } - const serverToPop = getServerToPopulation(room); - const sortedServers = Object.keys(serverToPop).sort( - (svrA, svrB) => serverToPop[svrB] - serverToPop[svrA], - ); - const mostPop3 = sortedServers.slice(0, 3); - if (via.length === 0) return mostPop3; - if (mostPop3.includes(via[0])) { - mostPop3.splice(mostPop3.indexOf(via[0]), 1); - } - return via.concat(mostPop3.slice(0, 2)); -} - export function isCrossVerified(mx, deviceId) { try { const crossSignInfo = mx.getStoredCrossSigningForUser(mx.getUserId()); const deviceInfo = mx.getStoredDevice(mx.getUserId(), deviceId); const deviceTrust = crossSignInfo.checkDeviceTrust(crossSignInfo, deviceInfo, false, true); return deviceTrust.isCrossSigningVerified(); - } catch { + } catch (e) { // device does not support encryption return null; } diff --git a/tsconfig.json b/tsconfig.json index 60ff1853..7608e557 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,8 @@ "moduleResolution": "Node", "resolveJsonModule": true, "outDir": "dist", - "skipLibCheck": true + "skipLibCheck": true, + "lib": ["ES2016", "DOM"] }, "exclude": ["node_modules", "dist"], "include": ["src"] diff --git a/vite.config.js b/vite.config.js index 1255f81c..e629c751 100644 --- a/vite.config.js +++ b/vite.config.js @@ -6,6 +6,7 @@ import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill'; import inject from '@rollup/plugin-inject'; import topLevelAwait from 'vite-plugin-top-level-await'; +import { VitePWA } from 'vite-plugin-pwa'; import buildConfig from './build.config'; const copyFiles = { @@ -35,6 +36,10 @@ const copyFiles = { src: 'public/res/android', dest: 'public/', }, + { + src: 'public/locales', + dest: 'public/', + }, ], }; @@ -46,11 +51,11 @@ export default defineConfig({ port: 8080, host: true, proxy: { - "^\\/.*?\\/olm\\.wasm$": { + '^\\/.*?\\/olm\\.wasm$': { target: 'http://localhost:8080', - rewrite: () => '/olm.wasm' - } - } + rewrite: () => '/olm.wasm', + }, + }, }, plugins: [ topLevelAwait({ @@ -63,6 +68,16 @@ export default defineConfig({ vanillaExtractPlugin(), wasm(), react(), + VitePWA({ + srcDir: 'src', + filename: 'sw.ts', + strategies: 'injectManifest', + injectRegister: false, + manifest: false, + injectManifest: { + injectionPoint: undefined, + }, + }), ], optimizeDeps: { esbuildOptions: {