diff --git a/.env b/.env
new file mode 100644
index 0000000..94d94fa
--- /dev/null
+++ b/.env
@@ -0,0 +1,3 @@
+VITE_APP_NAME=Dust Mail
+VITE_DEFAULT_SERVER=https://app.dust.email/api
+VITE_REPO=Guusvanmeerveld/Dust-Mail
\ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..2962aae
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,55 @@
+{
+ "root": true,
+ "env": {
+ "node": true,
+ "es6": true
+ },
+ "parserOptions": {
+ "ecmaVersion": 8
+ },
+ "plugins": ["prettier"],
+ "ignorePatterns": ["node_modules/*", ".next/*", ".out/*", "isolation-dist/*"],
+ "extends": ["eslint:recommended"],
+ "overrides": [
+ {
+ "files": ["**/*.ts", "**/*.tsx"],
+ "parser": "@typescript-eslint/parser",
+ "settings": {
+ "react": {
+ "version": "detect"
+ }
+ },
+ "env": {
+ "browser": true,
+ "node": true,
+ "es6": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:react/recommended",
+ "plugin:react-hooks/recommended",
+ "plugin:jsx-a11y/recommended"
+ ],
+ "rules": {
+ "prettier/prettier": "error",
+ "react/prop-types": "off",
+ "no-sparse-arrays": "off",
+ "react/react-in-jsx-scope": "off",
+ "react-hooks/exhaustive-deps": "off",
+ "jsx-a11y/anchor-is-valid": "off",
+ "jsx-a11y/no-autofocus": "off",
+ "no-mixed-spaces-and-tabs": "off",
+ "@typescript-eslint/no-unused-vars": ["warn"],
+ "@typescript-eslint/explicit-function-return-type": [
+ "warn",
+ {
+ "allowExpressions": true,
+ "allowConciseArrowFunctionExpressionsStartingWithVoid": true,
+ "allowTypedFunctionExpressions": true
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7f9c95f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,28 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+/dist
+node_modules
+target
+
+dist-ssr
+*.local
+
+/stats.*
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..3c1f6b9
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,45 @@
+{
+ "trailingComma": "none",
+ "useTabs": true,
+ "semi": true,
+ "printWidth": 80,
+ "arrowParens": "always",
+ "importOrderParserPlugins": [
+ "classProperties",
+ "decorators-legacy",
+ "typescript",
+ "jsx"
+ ],
+ "importOrderSeparation": true,
+ "importOrder": [
+ "@rollup/.*",
+ "rollup-.*",
+ "^..?/.*",
+ "^slate.*",
+ "^react.*",
+ "^preact$",
+ "^preact.*",
+ "^axios.*",
+ "^redis.*",
+ "@redis/.*",
+ "@dust-mail/.*",
+ "^@nestjs/.*",
+ "^@emotion/.*",
+ "^@mui/material/.*",
+ "^@mui/.*",
+ "^@src/.*",
+ "^@models/.*",
+ "^@interfaces/.*",
+ "^@styles/.*",
+ "^@shared/.*",
+ "^@utils/.*",
+ "^@cache/.*",
+ "^@mail/.*",
+ "^@auth/.*",
+ "^@components/.*",
+ ".*sass$",
+ ".*css$",
+ "^@svg/.*"
+ ],
+ "plugins": ["@trivago/prettier-plugin-sort-imports"]
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..2d50808
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,31 @@
+ARG BASE_IMAGE=node:16-alpine
+
+# Builder
+FROM $BASE_IMAGE as deployer
+
+RUN apk add --no-cache curl git
+
+RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
+
+WORKDIR /repo
+
+COPY pnpm-lock.yaml ./
+
+RUN pnpm fetch
+
+COPY apps ./apps
+COPY packages ./packages
+
+COPY package.json pnpm-workspace.yaml .npmrc turbo.json ./
+
+RUN pnpm install -r --offline --ignore-scripts
+
+RUN pnpm run build --filter @dust-mail/web
+
+RUN pnpm --filter @dust-mail/web --prod deploy /app
+
+FROM nginx:alpine AS runner
+
+COPY --from=deployer /app/dist /usr/share/nginx/html
+
+EXPOSE 80
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b173683
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# @dust-mail/web
+
+This the Dust mail web and desktop client. It's build using React and Material UI for the frontend and uses Vite as its main build tool. It uses Tauri to turn this exported static html into a multiplatform desktop app
+
+For more information about setting up a client, contributing or implementing the client api, please check the [docs](https://docs.dust.email).
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..57fe6cb
--- /dev/null
+++ b/index.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+ Dust Mail
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0243c55
--- /dev/null
+++ b/package.json
@@ -0,0 +1,84 @@
+{
+ "name": "@dust-mail/web",
+ "displayName": "Dust Mail Client",
+ "description": "A simple and fast mail client",
+ "version": "0.2.4",
+ "repository": {
+ "url": "https://github.com/Guusvanmeerveld/Dust-Mail"
+ },
+ "homepage": "https://github.com/Guusvanmeerveld/Dust-Mail",
+ "author": {
+ "name": "Guus van Meerveld",
+ "url": "https://guusvanmeerveld.dev",
+ "email": "contact@guusvanmeerveld.dev"
+ },
+ "contributors": [],
+ "packageManager": "pnpm@7.5.2",
+ "size-limit": [
+ {
+ "path": "dist/assets/*.js",
+ "limit": "500 kB"
+ }
+ ],
+ "license": "MIT",
+ "scripts": {
+ "dev": "vite",
+ "size": "size-limit",
+ "lint": "eslint src",
+ "build": "tsc && vite build",
+ "test": "vitest --passWithNoTests",
+ "coverage": "vitest run --coverage",
+ "preview": "vite preview",
+ "tauri": "tauri"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.9.3",
+ "@emotion/styled": "^11.9.3",
+ "@fontsource/roboto": "^4.5.7",
+ "@mui/icons-material": "^5.8.0",
+ "@mui/material": "^5.8.0",
+ "@mui/styled-engine": "^5.8.0",
+ "@tauri-apps/api": "^1.2.0",
+ "js-md5": "^0.7.3",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-markdown": "^8.0.3",
+ "react-query": "^3.39.1",
+ "react-router": "^6.3.0",
+ "react-router-dom": "^6.3.0",
+ "slate": "^0.81.1",
+ "slate-react": "^0.81.0",
+ "use-local-storage-state": "^17.2.0",
+ "zod": "^3.21.4",
+ "zustand": "^4.0.0-rc.1"
+ },
+ "devDependencies": {
+ "@babel/plugin-transform-react-jsx-source": "^7.18.6",
+ "@rollup/plugin-alias": "^3.1.9",
+ "@size-limit/preset-app": "^7.0.8",
+ "@tauri-apps/cli": "^1.0.4",
+ "@types/jest": "^28.1.4",
+ "@types/js-md5": "^0.7.0",
+ "@types/node": "^17.0.35",
+ "@types/react": "^18.0.15",
+ "@types/react-dom": "^18.0.6",
+ "@typescript-eslint/eslint-plugin": "^5.30.7",
+ "@typescript-eslint/parser": "^5.30.7",
+ "@vitejs/plugin-react": "^2.0.0",
+ "c8": "^7.12.0",
+ "eslint": "^8.20.0",
+ "eslint-plugin-jsx-a11y": "^6.6.0",
+ "eslint-plugin-prettier": "^4.2.1",
+ "eslint-plugin-react": "^7.30.1",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "prettier": "^2.7.1",
+ "rollup-plugin-visualizer": "^5.8.1",
+ "size-limit": "^7.0.8",
+ "typescript": "^4.5.4",
+ "vite": "^3.0.3",
+ "vite-plugin-pwa": "^0.12.2",
+ "vite-tsconfig-paths": "^3.4.1",
+ "vitest": "^0.20.3",
+ "workbox-window": "^6.5.3"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..babd4ce
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,6522 @@
+lockfileVersion: 5.4
+
+specifiers:
+ '@babel/plugin-transform-react-jsx-source': ^7.18.6
+ '@emotion/react': ^11.9.3
+ '@emotion/styled': ^11.9.3
+ '@fontsource/roboto': ^4.5.7
+ '@mui/icons-material': ^5.8.0
+ '@mui/material': ^5.8.0
+ '@mui/styled-engine': ^5.8.0
+ '@rollup/plugin-alias': ^3.1.9
+ '@size-limit/preset-app': ^7.0.8
+ '@tauri-apps/api': ^1.2.0
+ '@tauri-apps/cli': ^1.0.4
+ '@types/jest': ^28.1.4
+ '@types/js-md5': ^0.7.0
+ '@types/node': ^17.0.35
+ '@types/react': ^18.0.15
+ '@types/react-dom': ^18.0.6
+ '@typescript-eslint/eslint-plugin': ^5.30.7
+ '@typescript-eslint/parser': ^5.30.7
+ '@vitejs/plugin-react': ^2.0.0
+ c8: ^7.12.0
+ eslint: ^8.20.0
+ eslint-plugin-jsx-a11y: ^6.6.0
+ eslint-plugin-prettier: ^4.2.1
+ eslint-plugin-react: ^7.30.1
+ eslint-plugin-react-hooks: ^4.6.0
+ js-md5: ^0.7.3
+ prettier: ^2.7.1
+ react: ^18.2.0
+ react-dom: ^18.2.0
+ react-markdown: ^8.0.3
+ react-query: ^3.39.1
+ react-router: ^6.3.0
+ react-router-dom: ^6.3.0
+ rollup-plugin-visualizer: ^5.8.1
+ size-limit: ^7.0.8
+ slate: ^0.81.1
+ slate-react: ^0.81.0
+ typescript: ^4.5.4
+ use-local-storage-state: ^17.2.0
+ vite: ^3.0.3
+ vite-plugin-pwa: ^0.12.2
+ vite-tsconfig-paths: ^3.4.1
+ vitest: ^0.20.3
+ workbox-window: ^6.5.3
+ zod: ^3.21.4
+ zustand: ^4.0.0-rc.1
+
+dependencies:
+ '@emotion/react': 11.10.6_yuz6bkerhkjfjuf6zeb7j6ybc4
+ '@emotion/styled': 11.10.6_bpa2amdickk76qs7xzoz3lzv3m
+ '@fontsource/roboto': 4.5.8
+ '@mui/icons-material': 5.11.16_i5qtfz56gxv345p4d7l42p6ta4
+ '@mui/material': 5.12.0_rg2yyp2bpmu7sjcft7cf5grtye
+ '@mui/styled-engine': 5.12.0_xqp3pgpqjlfxxa3zxu4zoc4fba
+ '@tauri-apps/api': 1.2.0
+ js-md5: 0.7.3
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ react-markdown: 8.0.7_yuz6bkerhkjfjuf6zeb7j6ybc4
+ react-query: 3.39.3_biqbaboplfbrettd7655fr4n2y
+ react-router: 6.10.0_react@18.2.0
+ react-router-dom: 6.10.0_biqbaboplfbrettd7655fr4n2y
+ slate: 0.81.3
+ slate-react: 0.81.0_njwfekudbehx2lwpmvgkrdxmhi
+ use-local-storage-state: 17.3.0_biqbaboplfbrettd7655fr4n2y
+ zod: 3.21.4
+ zustand: 4.3.7_react@18.2.0
+
+devDependencies:
+ '@babel/plugin-transform-react-jsx-source': 7.19.6
+ '@rollup/plugin-alias': 3.1.9
+ '@size-limit/preset-app': 7.0.8_size-limit@7.0.8
+ '@tauri-apps/cli': 1.2.3
+ '@types/jest': 28.1.8
+ '@types/js-md5': 0.7.0
+ '@types/node': 17.0.45
+ '@types/react': 18.0.35
+ '@types/react-dom': 18.0.11
+ '@typescript-eslint/eslint-plugin': 5.58.0_hzv37tkb63et4viajosjuuyxgi
+ '@typescript-eslint/parser': 5.58.0_ze6bmax3gcsfve3yrzu6npguhe
+ '@vitejs/plugin-react': 2.2.0_vite@3.2.5
+ c8: 7.13.0
+ eslint: 8.38.0
+ eslint-plugin-jsx-a11y: 6.7.1_eslint@8.38.0
+ eslint-plugin-prettier: 4.2.1_7bukkzi2qfqwzn63s5moor2wwy
+ eslint-plugin-react: 7.32.2_eslint@8.38.0
+ eslint-plugin-react-hooks: 4.6.0_eslint@8.38.0
+ prettier: 2.8.7
+ rollup-plugin-visualizer: 5.9.0
+ size-limit: 7.0.8
+ typescript: 4.9.5
+ vite: 3.2.5_@types+node@17.0.45
+ vite-plugin-pwa: 0.12.8_vite@3.2.5
+ vite-tsconfig-paths: 3.6.0_vite@3.2.5
+ vitest: 0.20.3_c8@7.13.0
+ workbox-window: 6.5.4
+
+packages:
+
+ /@ampproject/remapping/2.2.1:
+ resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.3
+ '@jridgewell/trace-mapping': 0.3.18
+ dev: true
+
+ /@apideck/better-ajv-errors/0.3.6_ajv@8.12.0:
+ resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ ajv: '>=8'
+ dependencies:
+ ajv: 8.12.0
+ json-schema: 0.4.0
+ jsonpointer: 5.0.1
+ leven: 3.1.0
+ dev: true
+
+ /@babel/code-frame/7.21.4:
+ resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/highlight': 7.18.6
+
+ /@babel/compat-data/7.21.4:
+ resolution: {integrity: sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/core/7.21.4:
+ resolution: {integrity: sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@ampproject/remapping': 2.2.1
+ '@babel/code-frame': 7.21.4
+ '@babel/generator': 7.21.4
+ '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-module-transforms': 7.21.2
+ '@babel/helpers': 7.21.0
+ '@babel/parser': 7.21.4
+ '@babel/template': 7.20.7
+ '@babel/traverse': 7.21.4
+ '@babel/types': 7.21.4
+ convert-source-map: 1.9.0
+ debug: 4.3.4
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/generator/7.21.4:
+ resolution: {integrity: sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ '@jridgewell/gen-mapping': 0.3.3
+ '@jridgewell/trace-mapping': 0.3.18
+ jsesc: 2.5.2
+ dev: true
+
+ /@babel/helper-annotate-as-pure/7.18.6:
+ resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-builder-binary-assignment-operator-visitor/7.18.9:
+ resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-explode-assignable-expression': 7.18.6
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-compilation-targets/7.21.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/compat-data': 7.21.4
+ '@babel/core': 7.21.4
+ '@babel/helper-validator-option': 7.21.0
+ browserslist: 4.21.5
+ lru-cache: 5.1.1
+ semver: 6.3.0
+ dev: true
+
+ /@babel/helper-create-class-features-plugin/7.21.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-annotate-as-pure': 7.18.6
+ '@babel/helper-environment-visitor': 7.18.9
+ '@babel/helper-function-name': 7.21.0
+ '@babel/helper-member-expression-to-functions': 7.21.0
+ '@babel/helper-optimise-call-expression': 7.18.6
+ '@babel/helper-replace-supers': 7.20.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+ '@babel/helper-split-export-declaration': 7.18.6
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-create-regexp-features-plugin/7.21.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-annotate-as-pure': 7.18.6
+ regexpu-core: 5.3.2
+ dev: true
+
+ /@babel/helper-define-polyfill-provider/0.3.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==}
+ peerDependencies:
+ '@babel/core': ^7.4.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ debug: 4.3.4
+ lodash.debounce: 4.0.8
+ resolve: 1.22.3
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-environment-visitor/7.18.9:
+ resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-explode-assignable-expression/7.18.6:
+ resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-function-name/7.21.0:
+ resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.20.7
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-hoist-variables/7.18.6:
+ resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-member-expression-to-functions/7.21.0:
+ resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-module-imports/7.21.4:
+ resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+
+ /@babel/helper-module-transforms/7.21.2:
+ resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-environment-visitor': 7.18.9
+ '@babel/helper-module-imports': 7.21.4
+ '@babel/helper-simple-access': 7.20.2
+ '@babel/helper-split-export-declaration': 7.18.6
+ '@babel/helper-validator-identifier': 7.19.1
+ '@babel/template': 7.20.7
+ '@babel/traverse': 7.21.4
+ '@babel/types': 7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-optimise-call-expression/7.18.6:
+ resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-plugin-utils/7.20.2:
+ resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-remap-async-to-generator/7.18.9_@babel+core@7.21.4:
+ resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-annotate-as-pure': 7.18.6
+ '@babel/helper-environment-visitor': 7.18.9
+ '@babel/helper-wrap-function': 7.20.5
+ '@babel/types': 7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-replace-supers/7.20.7:
+ resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-environment-visitor': 7.18.9
+ '@babel/helper-member-expression-to-functions': 7.21.0
+ '@babel/helper-optimise-call-expression': 7.18.6
+ '@babel/template': 7.20.7
+ '@babel/traverse': 7.21.4
+ '@babel/types': 7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-simple-access/7.20.2:
+ resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-skip-transparent-expression-wrappers/7.20.0:
+ resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-split-export-declaration/7.18.6:
+ resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/helper-string-parser/7.19.4:
+ resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
+ engines: {node: '>=6.9.0'}
+
+ /@babel/helper-validator-identifier/7.19.1:
+ resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
+ engines: {node: '>=6.9.0'}
+
+ /@babel/helper-validator-option/7.21.0:
+ resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-wrap-function/7.20.5:
+ resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-function-name': 7.21.0
+ '@babel/template': 7.20.7
+ '@babel/traverse': 7.21.4
+ '@babel/types': 7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helpers/7.21.0:
+ resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.20.7
+ '@babel/traverse': 7.21.4
+ '@babel/types': 7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/highlight/7.18.6:
+ resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-validator-identifier': 7.19.1
+ chalk: 2.4.2
+ js-tokens: 4.0.0
+
+ /@babel/parser/7.21.4:
+ resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.13.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+ '@babel/plugin-proposal-optional-chaining': 7.21.0_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-async-generator-functions/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-environment-visitor': 7.18.9
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-remap-async-to-generator': 7.18.9_@babel+core@7.21.4
+ '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-class-properties/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-create-class-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-class-static-block/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.12.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-create-class-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-class-static-block': 7.14.5_@babel+core@7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-dynamic-import/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-export-namespace-from/7.18.9_@babel+core@7.21.4:
+ resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-json-strings/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-logical-assignment-operators/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-nullish-coalescing-operator/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-numeric-separator/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-object-rest-spread/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/compat-data': 7.21.4
+ '@babel/core': 7.21.4
+ '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-transform-parameters': 7.21.3_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-optional-catch-binding/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-optional-chaining/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+ '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-proposal-private-methods/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-create-class-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-private-property-in-object/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-annotate-as-pure': 7.18.6
+ '@babel/helper-create-class-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5_@babel+core@7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-unicode-property-regex/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-create-regexp-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.21.4:
+ resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-class-static-block/7.14.5_@babel+core@7.21.4:
+ resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-dynamic-import/7.8.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-export-namespace-from/7.8.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-import-assertions/7.20.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-jsx/7.21.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-private-property-in-object/7.14.5_@babel+core@7.21.4:
+ resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.21.4:
+ resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-arrow-functions/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-async-to-generator/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-module-imports': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-remap-async-to-generator': 7.18.9_@babel+core@7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-block-scoped-functions/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-block-scoping/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-classes/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-annotate-as-pure': 7.18.6
+ '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-environment-visitor': 7.18.9
+ '@babel/helper-function-name': 7.21.0
+ '@babel/helper-optimise-call-expression': 7.18.6
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-replace-supers': 7.20.7
+ '@babel/helper-split-export-declaration': 7.18.6
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-computed-properties/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/template': 7.20.7
+ dev: true
+
+ /@babel/plugin-transform-destructuring/7.21.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-dotall-regex/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-create-regexp-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-duplicate-keys/7.18.9_@babel+core@7.21.4:
+ resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-exponentiation-operator/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-for-of/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-function-name/7.18.9_@babel+core@7.21.4:
+ resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-function-name': 7.21.0
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-literals/7.18.9_@babel+core@7.21.4:
+ resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-member-expression-literals/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-modules-amd/7.20.11_@babel+core@7.21.4:
+ resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-module-transforms': 7.21.2
+ '@babel/helper-plugin-utils': 7.20.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-modules-commonjs/7.21.2_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-module-transforms': 7.21.2
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-simple-access': 7.20.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-modules-systemjs/7.20.11_@babel+core@7.21.4:
+ resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-hoist-variables': 7.18.6
+ '@babel/helper-module-transforms': 7.21.2
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-validator-identifier': 7.19.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-modules-umd/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-module-transforms': 7.21.2
+ '@babel/helper-plugin-utils': 7.20.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-named-capturing-groups-regex/7.20.5_@babel+core@7.21.4:
+ resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-create-regexp-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-new-target/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-object-super/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-replace-supers': 7.20.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-parameters/7.21.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-property-literals/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-development/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/plugin-transform-react-jsx': 7.21.0_@babel+core@7.21.4
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-self/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-f/Eq+79JEu+KUANFks9UZCcvydOOGMgF7jBrcwjHa5jTZD8JivnhCJYvmlhR/WTXBWonDExPoW0eO/CR4QJirA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-source/7.19.6:
+ resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-source/7.19.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-react-jsx/7.21.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-annotate-as-pure': 7.18.6
+ '@babel/helper-module-imports': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-syntax-jsx': 7.21.4_@babel+core@7.21.4
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/plugin-transform-regenerator/7.20.5_@babel+core@7.21.4:
+ resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ regenerator-transform: 0.15.1
+ dev: true
+
+ /@babel/plugin-transform-reserved-words/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-shorthand-properties/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-spread/7.20.7_@babel+core@7.21.4:
+ resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+ dev: true
+
+ /@babel/plugin-transform-sticky-regex/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-template-literals/7.18.9_@babel+core@7.21.4:
+ resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-typeof-symbol/7.18.9_@babel+core@7.21.4:
+ resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-unicode-escapes/7.18.10_@babel+core@7.21.4:
+ resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/plugin-transform-unicode-regex/7.18.6_@babel+core@7.21.4:
+ resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-create-regexp-features-plugin': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ dev: true
+
+ /@babel/preset-env/7.21.4_@babel+core@7.21.4:
+ resolution: {integrity: sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/compat-data': 7.21.4
+ '@babel/core': 7.21.4
+ '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/helper-validator-option': 7.21.0
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-proposal-async-generator-functions': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-proposal-class-properties': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-proposal-class-static-block': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-proposal-dynamic-import': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-proposal-export-namespace-from': 7.18.9_@babel+core@7.21.4
+ '@babel/plugin-proposal-json-strings': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-proposal-logical-assignment-operators': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-proposal-numeric-separator': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-proposal-object-rest-spread': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-proposal-optional-catch-binding': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-proposal-optional-chaining': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-proposal-private-methods': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-proposal-private-property-in-object': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-proposal-unicode-property-regex': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.21.4
+ '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.21.4
+ '@babel/plugin-syntax-class-static-block': 7.14.5_@babel+core@7.21.4
+ '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-syntax-import-assertions': 7.20.0_@babel+core@7.21.4
+ '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.21.4
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.21.4
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.21.4
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5_@babel+core@7.21.4
+ '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.21.4
+ '@babel/plugin-transform-arrow-functions': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-transform-async-to-generator': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-transform-block-scoped-functions': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-block-scoping': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-transform-classes': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-transform-computed-properties': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-transform-destructuring': 7.21.3_@babel+core@7.21.4
+ '@babel/plugin-transform-dotall-regex': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-duplicate-keys': 7.18.9_@babel+core@7.21.4
+ '@babel/plugin-transform-exponentiation-operator': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-for-of': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-transform-function-name': 7.18.9_@babel+core@7.21.4
+ '@babel/plugin-transform-literals': 7.18.9_@babel+core@7.21.4
+ '@babel/plugin-transform-member-expression-literals': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-modules-amd': 7.20.11_@babel+core@7.21.4
+ '@babel/plugin-transform-modules-commonjs': 7.21.2_@babel+core@7.21.4
+ '@babel/plugin-transform-modules-systemjs': 7.20.11_@babel+core@7.21.4
+ '@babel/plugin-transform-modules-umd': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5_@babel+core@7.21.4
+ '@babel/plugin-transform-new-target': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-object-super': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-parameters': 7.21.3_@babel+core@7.21.4
+ '@babel/plugin-transform-property-literals': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-regenerator': 7.20.5_@babel+core@7.21.4
+ '@babel/plugin-transform-reserved-words': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-shorthand-properties': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-spread': 7.20.7_@babel+core@7.21.4
+ '@babel/plugin-transform-sticky-regex': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-template-literals': 7.18.9_@babel+core@7.21.4
+ '@babel/plugin-transform-typeof-symbol': 7.18.9_@babel+core@7.21.4
+ '@babel/plugin-transform-unicode-escapes': 7.18.10_@babel+core@7.21.4
+ '@babel/plugin-transform-unicode-regex': 7.18.6_@babel+core@7.21.4
+ '@babel/preset-modules': 0.1.5_@babel+core@7.21.4
+ '@babel/types': 7.21.4
+ babel-plugin-polyfill-corejs2: 0.3.3_@babel+core@7.21.4
+ babel-plugin-polyfill-corejs3: 0.6.0_@babel+core@7.21.4
+ babel-plugin-polyfill-regenerator: 0.4.1_@babel+core@7.21.4
+ core-js-compat: 3.30.1
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/preset-modules/0.1.5_@babel+core@7.21.4:
+ resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-plugin-utils': 7.20.2
+ '@babel/plugin-proposal-unicode-property-regex': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-dotall-regex': 7.18.6_@babel+core@7.21.4
+ '@babel/types': 7.21.4
+ esutils: 2.0.3
+ dev: true
+
+ /@babel/regjsgen/0.8.0:
+ resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==}
+ dev: true
+
+ /@babel/runtime/7.21.0:
+ resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.13.11
+
+ /@babel/template/7.20.7:
+ resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.21.4
+ '@babel/parser': 7.21.4
+ '@babel/types': 7.21.4
+ dev: true
+
+ /@babel/traverse/7.21.4:
+ resolution: {integrity: sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.21.4
+ '@babel/generator': 7.21.4
+ '@babel/helper-environment-visitor': 7.18.9
+ '@babel/helper-function-name': 7.21.0
+ '@babel/helper-hoist-variables': 7.18.6
+ '@babel/helper-split-export-declaration': 7.18.6
+ '@babel/parser': 7.21.4
+ '@babel/types': 7.21.4
+ debug: 4.3.4
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/types/7.21.4:
+ resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-string-parser': 7.19.4
+ '@babel/helper-validator-identifier': 7.19.1
+ to-fast-properties: 2.0.0
+
+ /@bcoe/v8-coverage/0.2.3:
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+ dev: true
+
+ /@cush/relative/1.0.0:
+ resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
+ dev: true
+
+ /@emotion/babel-plugin/11.10.6:
+ resolution: {integrity: sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==}
+ dependencies:
+ '@babel/helper-module-imports': 7.21.4
+ '@babel/runtime': 7.21.0
+ '@emotion/hash': 0.9.0
+ '@emotion/memoize': 0.8.0
+ '@emotion/serialize': 1.1.1
+ babel-plugin-macros: 3.1.0
+ convert-source-map: 1.9.0
+ escape-string-regexp: 4.0.0
+ find-root: 1.1.0
+ source-map: 0.5.7
+ stylis: 4.1.3
+ dev: false
+
+ /@emotion/cache/11.10.7:
+ resolution: {integrity: sha512-VLl1/2D6LOjH57Y8Vem1RoZ9haWF4jesHDGiHtKozDQuBIkJm2gimVo0I02sWCuzZtVACeixTVB4jeE8qvCBoQ==}
+ dependencies:
+ '@emotion/memoize': 0.8.0
+ '@emotion/sheet': 1.2.1
+ '@emotion/utils': 1.2.0
+ '@emotion/weak-memoize': 0.3.0
+ stylis: 4.1.3
+ dev: false
+
+ /@emotion/hash/0.9.0:
+ resolution: {integrity: sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==}
+ dev: false
+
+ /@emotion/is-prop-valid/1.2.0:
+ resolution: {integrity: sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==}
+ dependencies:
+ '@emotion/memoize': 0.8.0
+ dev: false
+
+ /@emotion/memoize/0.8.0:
+ resolution: {integrity: sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==}
+ dev: false
+
+ /@emotion/react/11.10.6_yuz6bkerhkjfjuf6zeb7j6ybc4:
+ resolution: {integrity: sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@emotion/babel-plugin': 11.10.6
+ '@emotion/cache': 11.10.7
+ '@emotion/serialize': 1.1.1
+ '@emotion/use-insertion-effect-with-fallbacks': 1.0.0_react@18.2.0
+ '@emotion/utils': 1.2.0
+ '@emotion/weak-memoize': 0.3.0
+ '@types/react': 18.0.35
+ hoist-non-react-statics: 3.3.2
+ react: 18.2.0
+ dev: false
+
+ /@emotion/serialize/1.1.1:
+ resolution: {integrity: sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==}
+ dependencies:
+ '@emotion/hash': 0.9.0
+ '@emotion/memoize': 0.8.0
+ '@emotion/unitless': 0.8.0
+ '@emotion/utils': 1.2.0
+ csstype: 3.1.2
+ dev: false
+
+ /@emotion/sheet/1.2.1:
+ resolution: {integrity: sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==}
+ dev: false
+
+ /@emotion/styled/11.10.6_bpa2amdickk76qs7xzoz3lzv3m:
+ resolution: {integrity: sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==}
+ peerDependencies:
+ '@emotion/react': ^11.0.0-rc.0
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@emotion/babel-plugin': 11.10.6
+ '@emotion/is-prop-valid': 1.2.0
+ '@emotion/react': 11.10.6_yuz6bkerhkjfjuf6zeb7j6ybc4
+ '@emotion/serialize': 1.1.1
+ '@emotion/use-insertion-effect-with-fallbacks': 1.0.0_react@18.2.0
+ '@emotion/utils': 1.2.0
+ '@types/react': 18.0.35
+ react: 18.2.0
+ dev: false
+
+ /@emotion/unitless/0.8.0:
+ resolution: {integrity: sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==}
+ dev: false
+
+ /@emotion/use-insertion-effect-with-fallbacks/1.0.0_react@18.2.0:
+ resolution: {integrity: sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==}
+ peerDependencies:
+ react: '>=16.8.0'
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@emotion/utils/1.2.0:
+ resolution: {integrity: sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==}
+ dev: false
+
+ /@emotion/weak-memoize/0.3.0:
+ resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==}
+ dev: false
+
+ /@esbuild/android-arm/0.15.18:
+ resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-loong64/0.15.18:
+ resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@eslint-community/eslint-utils/4.4.0_eslint@8.38.0:
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ dependencies:
+ eslint: 8.38.0
+ eslint-visitor-keys: 3.4.0
+ dev: true
+
+ /@eslint-community/regexpp/4.5.0:
+ resolution: {integrity: sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dev: true
+
+ /@eslint/eslintrc/2.0.2:
+ resolution: {integrity: sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.4
+ espree: 9.5.1
+ globals: 13.20.0
+ ignore: 5.2.4
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@eslint/js/8.38.0:
+ resolution: {integrity: sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@fontsource/roboto/4.5.8:
+ resolution: {integrity: sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA==}
+ dev: false
+
+ /@humanwhocodes/config-array/0.11.8:
+ resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 1.2.1
+ debug: 4.3.4
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@humanwhocodes/module-importer/1.0.1:
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+ dev: true
+
+ /@humanwhocodes/object-schema/1.2.1:
+ resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
+ dev: true
+
+ /@istanbuljs/schema/0.1.3:
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /@jest/expect-utils/28.1.3:
+ resolution: {integrity: sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ jest-get-type: 28.0.2
+ dev: true
+
+ /@jest/schemas/28.1.3:
+ resolution: {integrity: sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ '@sinclair/typebox': 0.24.51
+ dev: true
+
+ /@jest/types/28.1.3:
+ resolution: {integrity: sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ '@jest/schemas': 28.1.3
+ '@types/istanbul-lib-coverage': 2.0.4
+ '@types/istanbul-reports': 3.0.1
+ '@types/node': 17.0.45
+ '@types/yargs': 17.0.24
+ chalk: 4.1.2
+ dev: true
+
+ /@jridgewell/gen-mapping/0.3.3:
+ resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/set-array': 1.1.2
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/trace-mapping': 0.3.18
+ dev: true
+
+ /@jridgewell/resolve-uri/3.1.0:
+ resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/set-array/1.1.2:
+ resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/source-map/0.3.3:
+ resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==}
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.3
+ '@jridgewell/trace-mapping': 0.3.18
+ dev: true
+
+ /@jridgewell/sourcemap-codec/1.4.14:
+ resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
+ dev: true
+
+ /@jridgewell/sourcemap-codec/1.4.15:
+ resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ dev: true
+
+ /@jridgewell/trace-mapping/0.3.18:
+ resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.0
+ '@jridgewell/sourcemap-codec': 1.4.14
+ dev: true
+
+ /@mui/base/5.0.0-alpha.125_7geocmx3442bocz6x6zwg5lxxi:
+ resolution: {integrity: sha512-hAHJJ97SATu6SrkLH/HsAayK1zMZt89lrWyKuAInBKVyn363H78d1MnwyZwre9vDK5MrPoDL/NnZxtAXhwTnBA==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0
+ react: ^17.0.0 || ^18.0.0
+ react-dom: ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@emotion/is-prop-valid': 1.2.0
+ '@mui/types': 7.2.4_@types+react@18.0.35
+ '@mui/utils': 5.12.0_react@18.2.0
+ '@popperjs/core': 2.11.7
+ '@types/react': 18.0.35
+ clsx: 1.2.1
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ react-is: 18.2.0
+ dev: false
+
+ /@mui/core-downloads-tracker/5.12.0:
+ resolution: {integrity: sha512-1hoFIdlLI0sG+mkJgm70FjgIVpfLcE1vxPtNolg1tLFXrvbXGUYp9NHy3d6c41nDkg2OajuVS+Mn6A8UirFuMw==}
+ dev: false
+
+ /@mui/icons-material/5.11.16_i5qtfz56gxv345p4d7l42p6ta4:
+ resolution: {integrity: sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ '@mui/material': ^5.0.0
+ '@types/react': ^17.0.0 || ^18.0.0
+ react: ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@mui/material': 5.12.0_rg2yyp2bpmu7sjcft7cf5grtye
+ '@types/react': 18.0.35
+ react: 18.2.0
+ dev: false
+
+ /@mui/material/5.12.0_rg2yyp2bpmu7sjcft7cf5grtye:
+ resolution: {integrity: sha512-IMellv153zJ6+xfhLWgXpAm/9hsX8qE6gP66xWcW/Pf2B8ubyVhmkTXsp8pAJxk81D6p/EyYcnAjo5DiDVkj9g==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@types/react': ^17.0.0 || ^18.0.0
+ react: ^17.0.0 || ^18.0.0
+ react-dom: ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@emotion/react': 11.10.6_yuz6bkerhkjfjuf6zeb7j6ybc4
+ '@emotion/styled': 11.10.6_bpa2amdickk76qs7xzoz3lzv3m
+ '@mui/base': 5.0.0-alpha.125_7geocmx3442bocz6x6zwg5lxxi
+ '@mui/core-downloads-tracker': 5.12.0
+ '@mui/system': 5.12.0_lc5335i77nvisulh5l5jax5g44
+ '@mui/types': 7.2.4_@types+react@18.0.35
+ '@mui/utils': 5.12.0_react@18.2.0
+ '@types/react': 18.0.35
+ '@types/react-transition-group': 4.4.5
+ clsx: 1.2.1
+ csstype: 3.1.2
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ react-is: 18.2.0
+ react-transition-group: 4.4.5_biqbaboplfbrettd7655fr4n2y
+ dev: false
+
+ /@mui/private-theming/5.12.0_yuz6bkerhkjfjuf6zeb7j6ybc4:
+ resolution: {integrity: sha512-w5dwMen1CUm1puAtubqxY9BIzrBxbOThsg2iWMvRJmWyJAPdf3Z583fPXpqeA2lhTW79uH2jajk5Ka4FuGlTPg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0
+ react: ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@mui/utils': 5.12.0_react@18.2.0
+ '@types/react': 18.0.35
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
+ /@mui/styled-engine/5.12.0_xqp3pgpqjlfxxa3zxu4zoc4fba:
+ resolution: {integrity: sha512-frh8L7CRnvD0RDmIqEv6jFeKQUIXqW90BaZ6OrxJ2j4kIsiVLu29Gss4SbBvvrWwwatR72sBmC3w1aG4fjp9mQ==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.4.1
+ '@emotion/styled': ^11.3.0
+ react: ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@emotion/cache': 11.10.7
+ '@emotion/react': 11.10.6_yuz6bkerhkjfjuf6zeb7j6ybc4
+ '@emotion/styled': 11.10.6_bpa2amdickk76qs7xzoz3lzv3m
+ csstype: 3.1.2
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
+ /@mui/system/5.12.0_lc5335i77nvisulh5l5jax5g44:
+ resolution: {integrity: sha512-Zi+WHuiJfK1ya+9+oeJQ1rLIBdY8CGDYT5oVlQg/6kIuyiCaE6SnN9PVzxBxfY77wHuOPwz4kxcPe9srdZc12Q==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@types/react': ^17.0.0 || ^18.0.0
+ react: ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@emotion/react': 11.10.6_yuz6bkerhkjfjuf6zeb7j6ybc4
+ '@emotion/styled': 11.10.6_bpa2amdickk76qs7xzoz3lzv3m
+ '@mui/private-theming': 5.12.0_yuz6bkerhkjfjuf6zeb7j6ybc4
+ '@mui/styled-engine': 5.12.0_xqp3pgpqjlfxxa3zxu4zoc4fba
+ '@mui/types': 7.2.4_@types+react@18.0.35
+ '@mui/utils': 5.12.0_react@18.2.0
+ '@types/react': 18.0.35
+ clsx: 1.2.1
+ csstype: 3.1.2
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
+ /@mui/types/7.2.4_@types+react@18.0.35:
+ resolution: {integrity: sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==}
+ peerDependencies:
+ '@types/react': '*'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.0.35
+ dev: false
+
+ /@mui/utils/5.12.0_react@18.2.0:
+ resolution: {integrity: sha512-RmQwgzF72p7Yr4+AAUO6j1v2uzt6wr7SWXn68KBsnfVpdOHyclCzH2lr/Xu6YOw9su4JRtdAIYfJFXsS6Cjkmw==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ react: ^17.0.0 || ^18.0.0
+ dependencies:
+ '@babel/runtime': 7.21.0
+ '@types/prop-types': 15.7.5
+ '@types/react-is': 17.0.3
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-is: 18.2.0
+ dev: false
+
+ /@nodelib/fs.scandir/2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+ dev: true
+
+ /@nodelib/fs.stat/2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /@nodelib/fs.walk/1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.15.0
+ dev: true
+
+ /@popperjs/core/2.11.7:
+ resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==}
+ dev: false
+
+ /@remix-run/router/1.5.0:
+ resolution: {integrity: sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==}
+ engines: {node: '>=14'}
+ dev: false
+
+ /@rollup/plugin-alias/3.1.9:
+ resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==}
+ engines: {node: '>=8.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0
+ dependencies:
+ slash: 3.0.0
+ dev: true
+
+ /@rollup/plugin-babel/5.3.1_b6cdhqm2xsfe2bpl424qdsl4ei:
+ resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
+ 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
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-module-imports': 7.21.4
+ '@rollup/pluginutils': 3.1.0_rollup@2.79.1
+ rollup: 2.79.1
+ dev: true
+
+ /@rollup/plugin-node-resolve/11.2.1_rollup@2.79.1:
+ resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==}
+ engines: {node: '>= 10.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0
+ dependencies:
+ '@rollup/pluginutils': 3.1.0_rollup@2.79.1
+ '@types/resolve': 1.17.1
+ builtin-modules: 3.3.0
+ deepmerge: 4.3.1
+ is-module: 1.0.0
+ resolve: 1.22.3
+ rollup: 2.79.1
+ dev: true
+
+ /@rollup/plugin-replace/2.4.2_rollup@2.79.1:
+ resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==}
+ peerDependencies:
+ rollup: ^1.20.0 || ^2.0.0
+ dependencies:
+ '@rollup/pluginutils': 3.1.0_rollup@2.79.1
+ magic-string: 0.25.9
+ rollup: 2.79.1
+ dev: true
+
+ /@rollup/pluginutils/3.1.0_rollup@2.79.1:
+ resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
+ engines: {node: '>= 8.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0
+ dependencies:
+ '@types/estree': 0.0.39
+ estree-walker: 1.0.1
+ picomatch: 2.3.1
+ rollup: 2.79.1
+ dev: true
+
+ /@sinclair/typebox/0.24.51:
+ resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==}
+ dev: true
+
+ /@sitespeed.io/tracium/0.3.3:
+ resolution: {integrity: sha512-dNZafjM93Y+F+sfwTO5gTpsGXlnc/0Q+c2+62ViqP3gkMWvHEMSKkaEHgVJLcLg3i/g19GSIPziiKpgyne07Bw==}
+ engines: {node: '>=8'}
+ dependencies:
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@size-limit/file/7.0.8_size-limit@7.0.8:
+ resolution: {integrity: sha512-1KeFQuMXIXAH/iELqIX7x+YNYDFvzIvmxcp9PrdwEoSNL0dXdaDIo9WE/yz8xvOmUcKaLfqbWkL75DM0k91WHQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ peerDependencies:
+ size-limit: 7.0.8
+ dependencies:
+ semver: 7.3.5
+ size-limit: 7.0.8
+ dev: true
+
+ /@size-limit/preset-app/7.0.8_size-limit@7.0.8:
+ resolution: {integrity: sha512-s1mgOXODeFCD1RCnx0ynyCbyQGrhFg4gIzVRSzVDUIVxIQWKstX/OiAXtudEYYF4XJWX6+jgGTwNwrgBZmGqMQ==}
+ peerDependencies:
+ size-limit: 7.0.8
+ dependencies:
+ '@size-limit/file': 7.0.8_size-limit@7.0.8
+ '@size-limit/time': 7.0.8_size-limit@7.0.8
+ size-limit: 7.0.8
+ transitivePeerDependencies:
+ - bufferutil
+ - encoding
+ - supports-color
+ - utf-8-validate
+ dev: true
+
+ /@size-limit/time/7.0.8_size-limit@7.0.8:
+ resolution: {integrity: sha512-CS3pHTxeQXgrrMbhlqYfSR+b4QGp1rjEcYYkByIP+X/Go88R44yp19tyBFmmCQzs2Te2BAxfq3jv8FG+54oBew==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ peerDependencies:
+ size-limit: 7.0.8
+ dependencies:
+ estimo: 2.3.6
+ react: 17.0.2
+ size-limit: 7.0.8
+ transitivePeerDependencies:
+ - bufferutil
+ - encoding
+ - supports-color
+ - utf-8-validate
+ dev: true
+
+ /@surma/rollup-plugin-off-main-thread/2.2.3:
+ resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
+ dependencies:
+ ejs: 3.1.9
+ json5: 2.2.3
+ magic-string: 0.25.9
+ string.prototype.matchall: 4.0.8
+ dev: true
+
+ /@tauri-apps/api/1.2.0:
+ resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==}
+ engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
+ dev: false
+
+ /@tauri-apps/cli-darwin-arm64/1.2.3:
+ resolution: {integrity: sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-darwin-x64/1.2.3:
+ resolution: {integrity: sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-linux-arm-gnueabihf/1.2.3:
+ resolution: {integrity: sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-linux-arm64-gnu/1.2.3:
+ resolution: {integrity: sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-linux-arm64-musl/1.2.3:
+ resolution: {integrity: sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-linux-x64-gnu/1.2.3:
+ resolution: {integrity: sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-linux-x64-musl/1.2.3:
+ resolution: {integrity: sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-win32-ia32-msvc/1.2.3:
+ resolution: {integrity: sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==}
+ engines: {node: '>= 10'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli-win32-x64-msvc/1.2.3:
+ resolution: {integrity: sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@tauri-apps/cli/1.2.3:
+ resolution: {integrity: sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==}
+ engines: {node: '>= 10'}
+ hasBin: true
+ optionalDependencies:
+ '@tauri-apps/cli-darwin-arm64': 1.2.3
+ '@tauri-apps/cli-darwin-x64': 1.2.3
+ '@tauri-apps/cli-linux-arm-gnueabihf': 1.2.3
+ '@tauri-apps/cli-linux-arm64-gnu': 1.2.3
+ '@tauri-apps/cli-linux-arm64-musl': 1.2.3
+ '@tauri-apps/cli-linux-x64-gnu': 1.2.3
+ '@tauri-apps/cli-linux-x64-musl': 1.2.3
+ '@tauri-apps/cli-win32-ia32-msvc': 1.2.3
+ '@tauri-apps/cli-win32-x64-msvc': 1.2.3
+ dev: true
+
+ /@types/chai-subset/1.3.3:
+ resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
+ dependencies:
+ '@types/chai': 4.3.4
+ dev: true
+
+ /@types/chai/4.3.4:
+ resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==}
+ dev: true
+
+ /@types/debug/4.1.7:
+ resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
+ dependencies:
+ '@types/ms': 0.7.31
+ dev: false
+
+ /@types/estree/0.0.39:
+ resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
+ dev: true
+
+ /@types/hast/2.3.4:
+ resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: false
+
+ /@types/is-hotkey/0.1.7:
+ resolution: {integrity: sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==}
+ dev: false
+
+ /@types/istanbul-lib-coverage/2.0.4:
+ resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
+ dev: true
+
+ /@types/istanbul-lib-report/3.0.0:
+ resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==}
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.4
+ dev: true
+
+ /@types/istanbul-reports/3.0.1:
+ resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==}
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.0
+ dev: true
+
+ /@types/jest/28.1.8:
+ resolution: {integrity: sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==}
+ dependencies:
+ expect: 28.1.3
+ pretty-format: 28.1.3
+ dev: true
+
+ /@types/js-md5/0.7.0:
+ resolution: {integrity: sha512-4mN02EhCni6MlvCUl9bpcbMfu7R3G+ac+J37b7gKCu3tWhZc5/Ya41T+2QNR2aFt6vnMe+uTa5rFQ+nT2kl6cA==}
+ dev: true
+
+ /@types/json-schema/7.0.11:
+ resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
+ dev: true
+
+ /@types/lodash/4.14.194:
+ resolution: {integrity: sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==}
+ dev: false
+
+ /@types/mdast/3.0.11:
+ resolution: {integrity: sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: false
+
+ /@types/ms/0.7.31:
+ resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
+ dev: false
+
+ /@types/node/17.0.45:
+ resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
+ dev: true
+
+ /@types/parse-json/4.0.0:
+ resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
+ dev: false
+
+ /@types/prop-types/15.7.5:
+ resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
+
+ /@types/react-dom/18.0.11:
+ resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==}
+ dependencies:
+ '@types/react': 18.0.35
+ dev: true
+
+ /@types/react-is/17.0.3:
+ resolution: {integrity: sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==}
+ dependencies:
+ '@types/react': 18.0.35
+ dev: false
+
+ /@types/react-transition-group/4.4.5:
+ resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==}
+ dependencies:
+ '@types/react': 18.0.35
+ dev: false
+
+ /@types/react/18.0.35:
+ resolution: {integrity: sha512-6Laome31HpetaIUGFWl1VQ3mdSImwxtFZ39rh059a1MNnKGqBpC88J6NJ8n/Is3Qx7CefDGLgf/KhN/sYCf7ag==}
+ dependencies:
+ '@types/prop-types': 15.7.5
+ '@types/scheduler': 0.16.3
+ csstype: 3.1.2
+
+ /@types/resolve/1.17.1:
+ resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
+ dependencies:
+ '@types/node': 17.0.45
+ dev: true
+
+ /@types/scheduler/0.16.3:
+ resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==}
+
+ /@types/semver/7.3.13:
+ resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
+ dev: true
+
+ /@types/stack-utils/2.0.1:
+ resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
+ dev: true
+
+ /@types/trusted-types/2.0.3:
+ resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==}
+ dev: true
+
+ /@types/unist/2.0.6:
+ resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
+ dev: false
+
+ /@types/yargs-parser/21.0.0:
+ resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
+ dev: true
+
+ /@types/yargs/17.0.24:
+ resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==}
+ dependencies:
+ '@types/yargs-parser': 21.0.0
+ dev: true
+
+ /@types/yauzl/2.10.0:
+ resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
+ requiresBuild: true
+ dependencies:
+ '@types/node': 17.0.45
+ dev: true
+ optional: true
+
+ /@typescript-eslint/eslint-plugin/5.58.0_hzv37tkb63et4viajosjuuyxgi:
+ resolution: {integrity: sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^5.0.0
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@eslint-community/regexpp': 4.5.0
+ '@typescript-eslint/parser': 5.58.0_ze6bmax3gcsfve3yrzu6npguhe
+ '@typescript-eslint/scope-manager': 5.58.0
+ '@typescript-eslint/type-utils': 5.58.0_ze6bmax3gcsfve3yrzu6npguhe
+ '@typescript-eslint/utils': 5.58.0_ze6bmax3gcsfve3yrzu6npguhe
+ debug: 4.3.4
+ eslint: 8.38.0
+ grapheme-splitter: 1.0.4
+ ignore: 5.2.4
+ natural-compare-lite: 1.4.0
+ semver: 7.4.0
+ tsutils: 3.21.0_typescript@4.9.5
+ typescript: 4.9.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/parser/5.58.0_ze6bmax3gcsfve3yrzu6npguhe:
+ resolution: {integrity: sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/scope-manager': 5.58.0
+ '@typescript-eslint/types': 5.58.0
+ '@typescript-eslint/typescript-estree': 5.58.0_typescript@4.9.5
+ debug: 4.3.4
+ eslint: 8.38.0
+ typescript: 4.9.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/scope-manager/5.58.0:
+ resolution: {integrity: sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ '@typescript-eslint/types': 5.58.0
+ '@typescript-eslint/visitor-keys': 5.58.0
+ dev: true
+
+ /@typescript-eslint/type-utils/5.58.0_ze6bmax3gcsfve3yrzu6npguhe:
+ resolution: {integrity: sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '*'
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/typescript-estree': 5.58.0_typescript@4.9.5
+ '@typescript-eslint/utils': 5.58.0_ze6bmax3gcsfve3yrzu6npguhe
+ debug: 4.3.4
+ eslint: 8.38.0
+ tsutils: 3.21.0_typescript@4.9.5
+ typescript: 4.9.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/types/5.58.0:
+ resolution: {integrity: sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@typescript-eslint/typescript-estree/5.58.0_typescript@4.9.5:
+ resolution: {integrity: sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/types': 5.58.0
+ '@typescript-eslint/visitor-keys': 5.58.0
+ debug: 4.3.4
+ globby: 11.1.0
+ is-glob: 4.0.3
+ semver: 7.4.0
+ tsutils: 3.21.0_typescript@4.9.5
+ typescript: 4.9.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/utils/5.58.0_ze6bmax3gcsfve3yrzu6npguhe:
+ resolution: {integrity: sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0_eslint@8.38.0
+ '@types/json-schema': 7.0.11
+ '@types/semver': 7.3.13
+ '@typescript-eslint/scope-manager': 5.58.0
+ '@typescript-eslint/types': 5.58.0
+ '@typescript-eslint/typescript-estree': 5.58.0_typescript@4.9.5
+ eslint: 8.38.0
+ eslint-scope: 5.1.1
+ semver: 7.4.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /@typescript-eslint/visitor-keys/5.58.0:
+ resolution: {integrity: sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ '@typescript-eslint/types': 5.58.0
+ eslint-visitor-keys: 3.4.0
+ dev: true
+
+ /@vitejs/plugin-react/2.2.0_vite@3.2.5:
+ resolution: {integrity: sha512-FFpefhvExd1toVRlokZgxgy2JtnBOdp4ZDsq7ldCWaqGSGn9UhWMAVm/1lxPL14JfNS5yGz+s9yFrQY6shoStA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: ^3.0.0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/plugin-transform-react-jsx': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-transform-react-jsx-development': 7.18.6_@babel+core@7.21.4
+ '@babel/plugin-transform-react-jsx-self': 7.21.0_@babel+core@7.21.4
+ '@babel/plugin-transform-react-jsx-source': 7.19.6_@babel+core@7.21.4
+ magic-string: 0.26.7
+ react-refresh: 0.14.0
+ vite: 3.2.5_@types+node@17.0.45
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /acorn-jsx/5.3.2_acorn@8.8.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ acorn: 8.8.2
+ dev: true
+
+ /acorn/8.8.2:
+ resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /agent-base/6.0.2:
+ resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
+ engines: {node: '>= 6.0.0'}
+ dependencies:
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /ajv/6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+ dev: true
+
+ /ajv/8.12.0:
+ resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+ uri-js: 4.4.1
+ dev: true
+
+ /ansi-regex/5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /ansi-styles/3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+ engines: {node: '>=4'}
+ dependencies:
+ color-convert: 1.9.3
+
+ /ansi-styles/4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+ dependencies:
+ color-convert: 2.0.1
+ dev: true
+
+ /ansi-styles/5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /any-promise/1.3.0:
+ resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+ dev: true
+
+ /anymatch/3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+ dev: true
+
+ /argparse/2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ dev: true
+
+ /aria-query/5.1.3:
+ resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
+ dependencies:
+ deep-equal: 2.2.0
+ dev: true
+
+ /array-buffer-byte-length/1.0.0:
+ resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
+ dependencies:
+ call-bind: 1.0.2
+ is-array-buffer: 3.0.2
+ dev: true
+
+ /array-includes/3.1.6:
+ resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ get-intrinsic: 1.2.0
+ is-string: 1.0.7
+ dev: true
+
+ /array-union/2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /array.prototype.flatmap/1.3.1:
+ resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ es-shim-unscopables: 1.0.0
+ dev: true
+
+ /array.prototype.tosorted/1.1.1:
+ resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ es-shim-unscopables: 1.0.0
+ get-intrinsic: 1.2.0
+ dev: true
+
+ /assertion-error/1.1.0:
+ resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+ dev: true
+
+ /ast-types-flow/0.0.7:
+ resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==}
+ dev: true
+
+ /async/3.2.4:
+ resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
+ dev: true
+
+ /at-least-node/1.0.0:
+ resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
+ engines: {node: '>= 4.0.0'}
+ dev: true
+
+ /available-typed-arrays/1.0.5:
+ resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /axe-core/4.6.3:
+ resolution: {integrity: sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /axobject-query/3.1.1:
+ resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==}
+ dependencies:
+ deep-equal: 2.2.0
+ dev: true
+
+ /babel-plugin-macros/3.1.0:
+ resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
+ engines: {node: '>=10', npm: '>=6'}
+ dependencies:
+ '@babel/runtime': 7.21.0
+ cosmiconfig: 7.1.0
+ resolve: 1.22.3
+ dev: false
+
+ /babel-plugin-polyfill-corejs2/0.3.3_@babel+core@7.21.4:
+ resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/compat-data': 7.21.4
+ '@babel/core': 7.21.4
+ '@babel/helper-define-polyfill-provider': 0.3.3_@babel+core@7.21.4
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-polyfill-corejs3/0.6.0_@babel+core@7.21.4:
+ resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-define-polyfill-provider': 0.3.3_@babel+core@7.21.4
+ core-js-compat: 3.30.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-polyfill-regenerator/0.4.1_@babel+core@7.21.4:
+ resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.21.4
+ '@babel/helper-define-polyfill-provider': 0.3.3_@babel+core@7.21.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /bail/2.0.2:
+ resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
+ dev: false
+
+ /balanced-match/1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ /base64-js/1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ dev: true
+
+ /big-integer/1.6.51:
+ resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
+ engines: {node: '>=0.6'}
+ dev: false
+
+ /binary-extensions/2.2.0:
+ resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /bl/4.1.0:
+ resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+ dependencies:
+ buffer: 5.7.1
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: true
+
+ /brace-expansion/1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ /brace-expansion/2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+ dev: true
+
+ /braces/3.0.2:
+ resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+ engines: {node: '>=8'}
+ dependencies:
+ fill-range: 7.0.1
+ dev: true
+
+ /broadcast-channel/3.7.0:
+ resolution: {integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==}
+ dependencies:
+ '@babel/runtime': 7.21.0
+ detect-node: 2.1.0
+ js-sha3: 0.8.0
+ microseconds: 0.2.0
+ nano-time: 1.0.0
+ oblivious-set: 1.0.0
+ rimraf: 3.0.2
+ unload: 2.2.0
+ dev: false
+
+ /browserslist/4.21.5:
+ resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+ dependencies:
+ caniuse-lite: 1.0.30001478
+ electron-to-chromium: 1.4.365
+ node-releases: 2.0.10
+ update-browserslist-db: 1.0.11_browserslist@4.21.5
+ dev: true
+
+ /buffer-crc32/0.2.13:
+ resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+ dev: true
+
+ /buffer-from/1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+ dev: true
+
+ /buffer/5.7.1:
+ resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: true
+
+ /builtin-modules/3.3.0:
+ resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /bytes-iec/3.1.1:
+ resolution: {integrity: sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /c8/7.13.0:
+ resolution: {integrity: sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==}
+ engines: {node: '>=10.12.0'}
+ hasBin: true
+ dependencies:
+ '@bcoe/v8-coverage': 0.2.3
+ '@istanbuljs/schema': 0.1.3
+ find-up: 5.0.0
+ foreground-child: 2.0.0
+ istanbul-lib-coverage: 3.2.0
+ istanbul-lib-report: 3.0.0
+ istanbul-reports: 3.1.5
+ rimraf: 3.0.2
+ test-exclude: 6.0.0
+ v8-to-istanbul: 9.1.0
+ yargs: 16.2.0
+ yargs-parser: 20.2.9
+ dev: true
+
+ /call-bind/1.0.2:
+ resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+ dependencies:
+ function-bind: 1.1.1
+ get-intrinsic: 1.2.0
+ dev: true
+
+ /callsites/3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ /caniuse-lite/1.0.30001478:
+ resolution: {integrity: sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==}
+ dev: true
+
+ /chai/4.3.7:
+ resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==}
+ engines: {node: '>=4'}
+ dependencies:
+ assertion-error: 1.1.0
+ check-error: 1.0.2
+ deep-eql: 4.1.3
+ get-func-name: 2.0.0
+ loupe: 2.3.6
+ pathval: 1.1.1
+ type-detect: 4.0.8
+ dev: true
+
+ /chalk/2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ ansi-styles: 3.2.1
+ escape-string-regexp: 1.0.5
+ supports-color: 5.5.0
+
+ /chalk/4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+ dev: true
+
+ /character-entities/2.0.2:
+ resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
+ dev: false
+
+ /check-error/1.0.2:
+ resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
+ dev: true
+
+ /chokidar/3.5.3:
+ resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /chownr/1.1.4:
+ resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+ dev: true
+
+ /ci-info/3.8.0:
+ resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /ci-job-number/1.2.2:
+ resolution: {integrity: sha512-CLOGsVDrVamzv8sXJGaILUVI6dsuAkouJP/n6t+OxLPeeA4DDby7zn9SB6EUpa1H7oIKoE+rMmkW80zYsFfUjA==}
+ dev: true
+
+ /cliui/7.0.4:
+ resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+ dev: true
+
+ /cliui/8.0.1:
+ resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+ dev: true
+
+ /clsx/1.2.1:
+ resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /color-convert/1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ dependencies:
+ color-name: 1.1.3
+
+ /color-convert/2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+ dependencies:
+ color-name: 1.1.4
+ dev: true
+
+ /color-name/1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+
+ /color-name/1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ dev: true
+
+ /comma-separated-tokens/2.0.3:
+ resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
+ dev: false
+
+ /commander/2.20.3:
+ resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+ dev: true
+
+ /commander/4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /commander/9.5.0:
+ resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
+ engines: {node: ^12.20.0 || >=14}
+ dev: true
+
+ /common-tags/1.8.2:
+ resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
+ engines: {node: '>=4.0.0'}
+ dev: true
+
+ /compute-scroll-into-view/1.0.20:
+ resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==}
+ dev: false
+
+ /concat-map/0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ /convert-source-map/1.9.0:
+ resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
+
+ /core-js-compat/3.30.1:
+ resolution: {integrity: sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw==}
+ dependencies:
+ browserslist: 4.21.5
+ dev: true
+
+ /cosmiconfig/7.1.0:
+ resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@types/parse-json': 4.0.0
+ import-fresh: 3.3.0
+ parse-json: 5.2.0
+ path-type: 4.0.0
+ yaml: 1.10.2
+ dev: false
+
+ /cross-fetch/3.1.5:
+ resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
+ dependencies:
+ node-fetch: 2.6.7
+ transitivePeerDependencies:
+ - encoding
+ dev: true
+
+ /cross-spawn/7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+ dev: true
+
+ /crypto-random-string/2.0.0:
+ resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /csstype/3.1.2:
+ resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
+
+ /damerau-levenshtein/1.0.8:
+ resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
+ dev: true
+
+ /debug/4.3.4:
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+
+ /decode-named-character-reference/1.0.2:
+ resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
+ dependencies:
+ character-entities: 2.0.2
+ dev: false
+
+ /deep-eql/4.1.3:
+ resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
+ engines: {node: '>=6'}
+ dependencies:
+ type-detect: 4.0.8
+ dev: true
+
+ /deep-equal/2.2.0:
+ resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==}
+ dependencies:
+ call-bind: 1.0.2
+ es-get-iterator: 1.1.3
+ get-intrinsic: 1.2.0
+ is-arguments: 1.1.1
+ is-array-buffer: 3.0.2
+ is-date-object: 1.0.5
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.2
+ isarray: 2.0.5
+ object-is: 1.1.5
+ object-keys: 1.1.1
+ object.assign: 4.1.4
+ regexp.prototype.flags: 1.4.3
+ side-channel: 1.0.4
+ which-boxed-primitive: 1.0.2
+ which-collection: 1.0.1
+ which-typed-array: 1.1.9
+ dev: true
+
+ /deep-is/0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ dev: true
+
+ /deepmerge/4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /define-lazy-prop/2.0.0:
+ resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /define-properties/1.2.0:
+ resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-property-descriptors: 1.0.0
+ object-keys: 1.1.1
+ dev: true
+
+ /dequal/2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /detect-node/2.1.0:
+ resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
+ dev: false
+
+ /devtools-protocol/0.0.981744:
+ resolution: {integrity: sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==}
+ dev: true
+
+ /diff-sequences/28.1.1:
+ resolution: {integrity: sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dev: true
+
+ /diff/5.1.0:
+ resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==}
+ engines: {node: '>=0.3.1'}
+ dev: false
+
+ /dir-glob/3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+ dependencies:
+ path-type: 4.0.0
+ dev: true
+
+ /direction/1.0.4:
+ resolution: {integrity: sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==}
+ hasBin: true
+ dev: false
+
+ /doctrine/2.1.0:
+ resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /doctrine/3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /dom-helpers/5.2.1:
+ resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
+ dependencies:
+ '@babel/runtime': 7.21.0
+ csstype: 3.1.2
+ dev: false
+
+ /ejs/3.1.9:
+ resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==}
+ engines: {node: '>=0.10.0'}
+ hasBin: true
+ dependencies:
+ jake: 10.8.5
+ dev: true
+
+ /electron-to-chromium/1.4.365:
+ resolution: {integrity: sha512-FRHZO+1tUNO4TOPXmlxetkoaIY8uwHzd1kKopK/Gx2SKn1L47wJXWD44wxP5CGRyyP98z/c8e1eBzJrgPeiBOg==}
+ dev: true
+
+ /emoji-regex/8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ dev: true
+
+ /emoji-regex/9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ dev: true
+
+ /end-of-stream/1.4.4:
+ resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
+ dependencies:
+ once: 1.4.0
+ dev: true
+
+ /error-ex/1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+ dependencies:
+ is-arrayish: 0.2.1
+ dev: false
+
+ /es-abstract/1.21.2:
+ resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ array-buffer-byte-length: 1.0.0
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.2
+ es-set-tostringtag: 2.0.1
+ es-to-primitive: 1.2.1
+ function.prototype.name: 1.1.5
+ get-intrinsic: 1.2.0
+ get-symbol-description: 1.0.0
+ globalthis: 1.0.3
+ gopd: 1.0.1
+ has: 1.0.3
+ has-property-descriptors: 1.0.0
+ has-proto: 1.0.1
+ has-symbols: 1.0.3
+ internal-slot: 1.0.5
+ is-array-buffer: 3.0.2
+ is-callable: 1.2.7
+ is-negative-zero: 2.0.2
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.2
+ is-string: 1.0.7
+ is-typed-array: 1.1.10
+ is-weakref: 1.0.2
+ object-inspect: 1.12.3
+ object-keys: 1.1.1
+ object.assign: 4.1.4
+ regexp.prototype.flags: 1.4.3
+ safe-regex-test: 1.0.0
+ string.prototype.trim: 1.2.7
+ string.prototype.trimend: 1.0.6
+ string.prototype.trimstart: 1.0.6
+ typed-array-length: 1.0.4
+ unbox-primitive: 1.0.2
+ which-typed-array: 1.1.9
+ dev: true
+
+ /es-get-iterator/1.1.3:
+ resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.2.0
+ has-symbols: 1.0.3
+ is-arguments: 1.1.1
+ is-map: 2.0.2
+ is-set: 2.0.2
+ is-string: 1.0.7
+ isarray: 2.0.5
+ stop-iteration-iterator: 1.0.0
+ dev: true
+
+ /es-set-tostringtag/2.0.1:
+ resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.0
+ has: 1.0.3
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /es-shim-unscopables/1.0.0:
+ resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==}
+ dependencies:
+ has: 1.0.3
+ dev: true
+
+ /es-to-primitive/1.2.1:
+ resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ is-callable: 1.2.7
+ is-date-object: 1.0.5
+ is-symbol: 1.0.4
+ dev: true
+
+ /esbuild-android-64/0.15.18:
+ resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-android-arm64/0.15.18:
+ resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-darwin-64/0.15.18:
+ resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-darwin-arm64/0.15.18:
+ resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-freebsd-64/0.15.18:
+ resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-freebsd-arm64/0.15.18:
+ resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-32/0.15.18:
+ resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-64/0.15.18:
+ resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-arm/0.15.18:
+ resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-arm64/0.15.18:
+ resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-mips64le/0.15.18:
+ resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-ppc64le/0.15.18:
+ resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-riscv64/0.15.18:
+ resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-s390x/0.15.18:
+ resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-netbsd-64/0.15.18:
+ resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-openbsd-64/0.15.18:
+ resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-sunos-64/0.15.18:
+ resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-32/0.15.18:
+ resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-64/0.15.18:
+ resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-arm64/0.15.18:
+ resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild/0.15.18:
+ resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/android-arm': 0.15.18
+ '@esbuild/linux-loong64': 0.15.18
+ esbuild-android-64: 0.15.18
+ esbuild-android-arm64: 0.15.18
+ esbuild-darwin-64: 0.15.18
+ esbuild-darwin-arm64: 0.15.18
+ esbuild-freebsd-64: 0.15.18
+ esbuild-freebsd-arm64: 0.15.18
+ esbuild-linux-32: 0.15.18
+ esbuild-linux-64: 0.15.18
+ esbuild-linux-arm: 0.15.18
+ esbuild-linux-arm64: 0.15.18
+ esbuild-linux-mips64le: 0.15.18
+ esbuild-linux-ppc64le: 0.15.18
+ esbuild-linux-riscv64: 0.15.18
+ esbuild-linux-s390x: 0.15.18
+ esbuild-netbsd-64: 0.15.18
+ esbuild-openbsd-64: 0.15.18
+ esbuild-sunos-64: 0.15.18
+ esbuild-windows-32: 0.15.18
+ esbuild-windows-64: 0.15.18
+ esbuild-windows-arm64: 0.15.18
+ dev: true
+
+ /escalade/3.1.1:
+ resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /escape-string-regexp/1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+ engines: {node: '>=0.8.0'}
+
+ /escape-string-regexp/2.0.0:
+ resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /escape-string-regexp/4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ /eslint-plugin-jsx-a11y/6.7.1_eslint@8.38.0:
+ resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ dependencies:
+ '@babel/runtime': 7.21.0
+ aria-query: 5.1.3
+ array-includes: 3.1.6
+ array.prototype.flatmap: 1.3.1
+ ast-types-flow: 0.0.7
+ axe-core: 4.6.3
+ axobject-query: 3.1.1
+ damerau-levenshtein: 1.0.8
+ emoji-regex: 9.2.2
+ eslint: 8.38.0
+ has: 1.0.3
+ jsx-ast-utils: 3.3.3
+ language-tags: 1.0.5
+ minimatch: 3.1.2
+ object.entries: 1.1.6
+ object.fromentries: 2.0.6
+ semver: 6.3.0
+ dev: true
+
+ /eslint-plugin-prettier/4.2.1_7bukkzi2qfqwzn63s5moor2wwy:
+ resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ eslint: '>=7.28.0'
+ eslint-config-prettier: '*'
+ prettier: '>=2.0.0'
+ peerDependenciesMeta:
+ eslint-config-prettier:
+ optional: true
+ dependencies:
+ eslint: 8.38.0
+ prettier: 2.8.7
+ prettier-linter-helpers: 1.0.0
+ dev: true
+
+ /eslint-plugin-react-hooks/4.6.0_eslint@8.38.0:
+ resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+ dependencies:
+ eslint: 8.38.0
+ dev: true
+
+ /eslint-plugin-react/7.32.2_eslint@8.38.0:
+ resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ dependencies:
+ array-includes: 3.1.6
+ array.prototype.flatmap: 1.3.1
+ array.prototype.tosorted: 1.1.1
+ doctrine: 2.1.0
+ eslint: 8.38.0
+ estraverse: 5.3.0
+ jsx-ast-utils: 3.3.3
+ minimatch: 3.1.2
+ object.entries: 1.1.6
+ object.fromentries: 2.0.6
+ object.hasown: 1.1.2
+ object.values: 1.1.6
+ prop-types: 15.8.1
+ resolve: 2.0.0-next.4
+ semver: 6.3.0
+ string.prototype.matchall: 4.0.8
+ dev: true
+
+ /eslint-scope/5.1.1:
+ resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 4.3.0
+ dev: true
+
+ /eslint-scope/7.2.0:
+ resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
+ /eslint-visitor-keys/3.4.0:
+ resolution: {integrity: sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /eslint/8.38.0:
+ resolution: {integrity: sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0_eslint@8.38.0
+ '@eslint-community/regexpp': 4.5.0
+ '@eslint/eslintrc': 2.0.2
+ '@eslint/js': 8.38.0
+ '@humanwhocodes/config-array': 0.11.8
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.4
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.2.0
+ eslint-visitor-keys: 3.4.0
+ espree: 9.5.1
+ esquery: 1.5.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ globals: 13.20.0
+ grapheme-splitter: 1.0.4
+ ignore: 5.2.4
+ import-fresh: 3.3.0
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ js-sdsl: 4.4.0
+ js-yaml: 4.1.0
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.1
+ strip-ansi: 6.0.1
+ strip-json-comments: 3.1.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /espree/9.5.1:
+ resolution: {integrity: sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.8.2
+ acorn-jsx: 5.3.2_acorn@8.8.2
+ eslint-visitor-keys: 3.4.0
+ dev: true
+
+ /esquery/1.5.0:
+ resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /esrecurse/4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /estimo/2.3.6:
+ resolution: {integrity: sha512-aPd3VTQAL1TyDyhFfn6fqBTJ9WvbRZVN4Z29Buk6+P6xsI0DuF5Mh3dGv6kYCUxWnZkB4Jt3aYglUxOtuwtxoA==}
+ engines: {node: '>=12'}
+ hasBin: true
+ dependencies:
+ '@sitespeed.io/tracium': 0.3.3
+ commander: 9.5.0
+ find-chrome-bin: 0.1.0
+ nanoid: 3.3.6
+ puppeteer-core: 13.7.0
+ transitivePeerDependencies:
+ - bufferutil
+ - encoding
+ - supports-color
+ - utf-8-validate
+ dev: true
+
+ /estraverse/4.3.0:
+ resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /estraverse/5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /estree-walker/1.0.1:
+ resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==}
+ dev: true
+
+ /esutils/2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /expect/28.1.3:
+ resolution: {integrity: sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ '@jest/expect-utils': 28.1.3
+ jest-get-type: 28.0.2
+ jest-matcher-utils: 28.1.3
+ jest-message-util: 28.1.3
+ jest-util: 28.1.3
+ dev: true
+
+ /extend/3.0.2:
+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+ dev: false
+
+ /extract-zip/2.0.1:
+ resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
+ engines: {node: '>= 10.17.0'}
+ hasBin: true
+ dependencies:
+ debug: 4.3.4
+ get-stream: 5.2.0
+ yauzl: 2.10.0
+ optionalDependencies:
+ '@types/yauzl': 2.10.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /fast-deep-equal/3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ dev: true
+
+ /fast-diff/1.2.0:
+ resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
+ dev: true
+
+ /fast-glob/3.2.12:
+ resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.5
+ dev: true
+
+ /fast-json-stable-stringify/2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+ dev: true
+
+ /fast-levenshtein/2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ dev: true
+
+ /fastq/1.15.0:
+ resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+ dependencies:
+ reusify: 1.0.4
+ dev: true
+
+ /fd-slicer/1.1.0:
+ resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
+ dependencies:
+ pend: 1.2.0
+ dev: true
+
+ /file-entry-cache/6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flat-cache: 3.0.4
+ dev: true
+
+ /filelist/1.0.4:
+ resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
+ dependencies:
+ minimatch: 5.1.6
+ dev: true
+
+ /fill-range/7.0.1:
+ resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ to-regex-range: 5.0.1
+ dev: true
+
+ /find-chrome-bin/0.1.0:
+ resolution: {integrity: sha512-XoFZwaEn1R3pE6zNG8kH64l2e093hgB9+78eEKPmJK0o1EXEou+25cEWdtu2qq4DBQPDSe90VJAWVI2Sz9pX6Q==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dev: true
+
+ /find-root/1.1.0:
+ resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
+ dev: false
+
+ /find-up/4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /find-up/5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /flat-cache/3.0.4:
+ resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flatted: 3.2.7
+ rimraf: 3.0.2
+ dev: true
+
+ /flatted/3.2.7:
+ resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
+ dev: true
+
+ /for-each/0.3.3:
+ resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+ dependencies:
+ is-callable: 1.2.7
+ dev: true
+
+ /foreground-child/2.0.0:
+ resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ cross-spawn: 7.0.3
+ signal-exit: 3.0.7
+ dev: true
+
+ /fs-constants/1.0.0:
+ resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+ dev: true
+
+ /fs-extra/9.1.0:
+ resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ at-least-node: 1.0.0
+ graceful-fs: 4.2.11
+ jsonfile: 6.1.0
+ universalify: 2.0.0
+ dev: true
+
+ /fs.realpath/1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+ /fsevents/2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /function-bind/1.1.1:
+ resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
+
+ /function.prototype.name/1.1.5:
+ resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ functions-have-names: 1.2.3
+ dev: true
+
+ /functions-have-names/1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ dev: true
+
+ /gensync/1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /get-caller-file/2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ dev: true
+
+ /get-func-name/2.0.0:
+ resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
+ dev: true
+
+ /get-intrinsic/1.2.0:
+ resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
+ dependencies:
+ function-bind: 1.1.1
+ has: 1.0.3
+ has-symbols: 1.0.3
+ dev: true
+
+ /get-own-enumerable-property-symbols/3.0.2:
+ resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
+ dev: true
+
+ /get-stream/5.2.0:
+ resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
+ engines: {node: '>=8'}
+ dependencies:
+ pump: 3.0.0
+ dev: true
+
+ /get-symbol-description/1.0.0:
+ resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.2.0
+ dev: true
+
+ /glob-parent/5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-parent/6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-regex/0.3.2:
+ resolution: {integrity: sha512-m5blUd3/OqDTWwzBBtWBPrGlAzatRywHameHeekAZyZrskYouOGdNB8T/q6JucucvJXtOuyHIn0/Yia7iDasDw==}
+ dev: true
+
+ /glob/7.1.6:
+ resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: true
+
+ /glob/7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+
+ /globals/11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /globals/13.20.0:
+ resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.20.2
+ dev: true
+
+ /globalthis/1.0.3:
+ resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-properties: 1.2.0
+ dev: true
+
+ /globby/11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.2.12
+ ignore: 5.2.4
+ merge2: 1.4.1
+ slash: 3.0.0
+ dev: true
+
+ /globrex/0.1.2:
+ resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
+ dev: true
+
+ /gopd/1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+ dependencies:
+ get-intrinsic: 1.2.0
+ dev: true
+
+ /graceful-fs/4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ dev: true
+
+ /grapheme-splitter/1.0.4:
+ resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
+ dev: true
+
+ /has-bigints/1.0.2:
+ resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
+ dev: true
+
+ /has-flag/3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
+ /has-flag/4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /has-property-descriptors/1.0.0:
+ resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+ dependencies:
+ get-intrinsic: 1.2.0
+ dev: true
+
+ /has-proto/1.0.1:
+ resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /has-symbols/1.0.3:
+ resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /has-tostringtag/1.0.0:
+ resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.3
+ dev: true
+
+ /has/1.0.3:
+ resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
+ engines: {node: '>= 0.4.0'}
+ dependencies:
+ function-bind: 1.1.1
+
+ /hast-util-whitespace/2.0.1:
+ resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==}
+ dev: false
+
+ /hoist-non-react-statics/3.3.2:
+ resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
+ dependencies:
+ react-is: 16.13.1
+ dev: false
+
+ /html-escaper/2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+ dev: true
+
+ /https-proxy-agent/5.0.1:
+ resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ agent-base: 6.0.2
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /idb/7.1.1:
+ resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
+ dev: true
+
+ /ieee754/1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ dev: true
+
+ /ignore/5.2.4:
+ resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /immer/9.0.21:
+ resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
+ dev: false
+
+ /import-fresh/3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ /imurmurhash/0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+ dev: true
+
+ /inflight/1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+
+ /inherits/2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ /inline-style-parser/0.1.1:
+ resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==}
+ dev: false
+
+ /internal-slot/1.0.5:
+ resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.0
+ has: 1.0.3
+ side-channel: 1.0.4
+ dev: true
+
+ /is-arguments/1.1.1:
+ resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-array-buffer/3.0.2:
+ resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.2.0
+ is-typed-array: 1.1.10
+ dev: true
+
+ /is-arrayish/0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+ dev: false
+
+ /is-bigint/1.0.4:
+ resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+ dependencies:
+ has-bigints: 1.0.2
+ dev: true
+
+ /is-binary-path/2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+ dependencies:
+ binary-extensions: 2.2.0
+ dev: true
+
+ /is-boolean-object/1.1.2:
+ resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-buffer/2.0.5:
+ resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /is-callable/1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-core-module/2.12.0:
+ resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==}
+ dependencies:
+ has: 1.0.3
+
+ /is-date-object/1.0.5:
+ resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-docker/2.2.1:
+ resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
+ engines: {node: '>=8'}
+ hasBin: true
+ dev: true
+
+ /is-extglob/2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-fullwidth-code-point/3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-glob/4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+ dev: true
+
+ /is-hotkey/0.1.8:
+ resolution: {integrity: sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==}
+ dev: false
+
+ /is-map/2.0.2:
+ resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
+ dev: true
+
+ /is-module/1.0.0:
+ resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
+ dev: true
+
+ /is-negative-zero/2.0.2:
+ resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-number-object/1.0.7:
+ resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-number/7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+ dev: true
+
+ /is-obj/1.0.1:
+ resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-path-inside/3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-plain-obj/4.1.0:
+ resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /is-plain-object/5.0.0:
+ resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /is-regex/1.1.4:
+ resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-regexp/1.0.0:
+ resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-set/2.0.2:
+ resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
+ dev: true
+
+ /is-shared-array-buffer/1.0.2:
+ resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
+ dependencies:
+ call-bind: 1.0.2
+ dev: true
+
+ /is-stream/2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-string/1.0.7:
+ resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-symbol/1.0.4:
+ resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.3
+ dev: true
+
+ /is-typed-array/1.1.10:
+ resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.2
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-weakmap/2.0.1:
+ resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
+ dev: true
+
+ /is-weakref/1.0.2:
+ resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+ dependencies:
+ call-bind: 1.0.2
+ dev: true
+
+ /is-weakset/2.0.2:
+ resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.2.0
+ dev: true
+
+ /is-wsl/2.2.0:
+ resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
+ engines: {node: '>=8'}
+ dependencies:
+ is-docker: 2.2.1
+ dev: true
+
+ /isarray/2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+ dev: true
+
+ /isexe/2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ dev: true
+
+ /istanbul-lib-coverage/3.2.0:
+ resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /istanbul-lib-report/3.0.0:
+ resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==}
+ engines: {node: '>=8'}
+ dependencies:
+ istanbul-lib-coverage: 3.2.0
+ make-dir: 3.1.0
+ supports-color: 7.2.0
+ dev: true
+
+ /istanbul-reports/3.1.5:
+ resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==}
+ engines: {node: '>=8'}
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.0
+ dev: true
+
+ /jake/10.8.5:
+ resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ async: 3.2.4
+ chalk: 4.1.2
+ filelist: 1.0.4
+ minimatch: 3.1.2
+ dev: true
+
+ /jest-diff/28.1.3:
+ resolution: {integrity: sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ chalk: 4.1.2
+ diff-sequences: 28.1.1
+ jest-get-type: 28.0.2
+ pretty-format: 28.1.3
+ dev: true
+
+ /jest-get-type/28.0.2:
+ resolution: {integrity: sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dev: true
+
+ /jest-matcher-utils/28.1.3:
+ resolution: {integrity: sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ chalk: 4.1.2
+ jest-diff: 28.1.3
+ jest-get-type: 28.0.2
+ pretty-format: 28.1.3
+ dev: true
+
+ /jest-message-util/28.1.3:
+ resolution: {integrity: sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ '@babel/code-frame': 7.21.4
+ '@jest/types': 28.1.3
+ '@types/stack-utils': 2.0.1
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ micromatch: 4.0.5
+ pretty-format: 28.1.3
+ slash: 3.0.0
+ stack-utils: 2.0.6
+ dev: true
+
+ /jest-util/28.1.3:
+ resolution: {integrity: sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ '@jest/types': 28.1.3
+ '@types/node': 17.0.45
+ chalk: 4.1.2
+ ci-info: 3.8.0
+ graceful-fs: 4.2.11
+ picomatch: 2.3.1
+ dev: true
+
+ /jest-worker/26.6.2:
+ resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
+ engines: {node: '>= 10.13.0'}
+ dependencies:
+ '@types/node': 17.0.45
+ merge-stream: 2.0.0
+ supports-color: 7.2.0
+ dev: true
+
+ /js-md5/0.7.3:
+ resolution: {integrity: sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==}
+ dev: false
+
+ /js-sdsl/4.4.0:
+ resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==}
+ dev: true
+
+ /js-sha3/0.8.0:
+ resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
+ dev: false
+
+ /js-tokens/4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ /js-yaml/4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ dev: true
+
+ /jsesc/0.5.0:
+ resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
+ hasBin: true
+ dev: true
+
+ /jsesc/2.5.2:
+ resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /json-parse-even-better-errors/2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+ dev: false
+
+ /json-schema-traverse/0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ dev: true
+
+ /json-schema-traverse/1.0.0:
+ resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+ dev: true
+
+ /json-schema/0.4.0:
+ resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
+ dev: true
+
+ /json-stable-stringify-without-jsonify/1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ dev: true
+
+ /json5/2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+ dev: true
+
+ /jsonfile/6.1.0:
+ resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ dependencies:
+ universalify: 2.0.0
+ optionalDependencies:
+ graceful-fs: 4.2.11
+ dev: true
+
+ /jsonpointer/5.0.1:
+ resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /jsx-ast-utils/3.3.3:
+ resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ array-includes: 3.1.6
+ object.assign: 4.1.4
+ dev: true
+
+ /kleur/4.1.5:
+ resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /language-subtag-registry/0.3.22:
+ resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
+ dev: true
+
+ /language-tags/1.0.5:
+ resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==}
+ dependencies:
+ language-subtag-registry: 0.3.22
+ dev: true
+
+ /leven/3.1.0:
+ resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /levn/0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /lilconfig/2.1.0:
+ resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /lines-and-columns/1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ /local-pkg/0.4.3:
+ resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /locate-path/5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+ dependencies:
+ p-locate: 4.1.0
+ dev: true
+
+ /locate-path/6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-locate: 5.0.0
+ dev: true
+
+ /lodash.debounce/4.0.8:
+ resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+ dev: true
+
+ /lodash.merge/4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ dev: true
+
+ /lodash.sortby/4.7.0:
+ resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
+ dev: true
+
+ /lodash/4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+ /loose-envify/1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+ dependencies:
+ js-tokens: 4.0.0
+
+ /loupe/2.3.6:
+ resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==}
+ dependencies:
+ get-func-name: 2.0.0
+ dev: true
+
+ /lru-cache/5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ dependencies:
+ yallist: 3.1.1
+ dev: true
+
+ /lru-cache/6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+ dependencies:
+ yallist: 4.0.0
+ dev: true
+
+ /magic-string/0.25.9:
+ resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
+ dependencies:
+ sourcemap-codec: 1.4.8
+ dev: true
+
+ /magic-string/0.26.7:
+ resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==}
+ engines: {node: '>=12'}
+ dependencies:
+ sourcemap-codec: 1.4.8
+ dev: true
+
+ /make-dir/3.1.0:
+ resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
+ engines: {node: '>=8'}
+ dependencies:
+ semver: 6.3.0
+ dev: true
+
+ /match-sorter/6.3.1:
+ resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==}
+ dependencies:
+ '@babel/runtime': 7.21.0
+ remove-accents: 0.4.2
+ dev: false
+
+ /mdast-util-definitions/5.1.2:
+ resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==}
+ dependencies:
+ '@types/mdast': 3.0.11
+ '@types/unist': 2.0.6
+ unist-util-visit: 4.1.2
+ dev: false
+
+ /mdast-util-from-markdown/1.3.0:
+ resolution: {integrity: sha512-HN3W1gRIuN/ZW295c7zi7g9lVBllMgZE40RxCX37wrTPWXCWtpvOZdfnuK+1WNpvZje6XuJeI3Wnb4TJEUem+g==}
+ dependencies:
+ '@types/mdast': 3.0.11
+ '@types/unist': 2.0.6
+ decode-named-character-reference: 1.0.2
+ mdast-util-to-string: 3.2.0
+ micromark: 3.1.0
+ micromark-util-decode-numeric-character-reference: 1.0.0
+ micromark-util-decode-string: 1.0.2
+ micromark-util-normalize-identifier: 1.0.0
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ unist-util-stringify-position: 3.0.3
+ uvu: 0.5.6
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /mdast-util-to-hast/12.3.0:
+ resolution: {integrity: sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==}
+ dependencies:
+ '@types/hast': 2.3.4
+ '@types/mdast': 3.0.11
+ mdast-util-definitions: 5.1.2
+ micromark-util-sanitize-uri: 1.1.0
+ trim-lines: 3.0.1
+ unist-util-generated: 2.0.1
+ unist-util-position: 4.0.4
+ unist-util-visit: 4.1.2
+ dev: false
+
+ /mdast-util-to-string/3.2.0:
+ resolution: {integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==}
+ dependencies:
+ '@types/mdast': 3.0.11
+ dev: false
+
+ /merge-stream/2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+ dev: true
+
+ /merge2/1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /micromark-core-commonmark/1.0.6:
+ resolution: {integrity: sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==}
+ dependencies:
+ decode-named-character-reference: 1.0.2
+ micromark-factory-destination: 1.0.0
+ micromark-factory-label: 1.0.2
+ micromark-factory-space: 1.0.0
+ micromark-factory-title: 1.0.2
+ micromark-factory-whitespace: 1.0.0
+ micromark-util-character: 1.1.0
+ micromark-util-chunked: 1.0.0
+ micromark-util-classify-character: 1.0.0
+ micromark-util-html-tag-name: 1.1.0
+ micromark-util-normalize-identifier: 1.0.0
+ micromark-util-resolve-all: 1.0.0
+ micromark-util-subtokenize: 1.0.2
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ uvu: 0.5.6
+ dev: false
+
+ /micromark-factory-destination/1.0.0:
+ resolution: {integrity: sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==}
+ dependencies:
+ micromark-util-character: 1.1.0
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ dev: false
+
+ /micromark-factory-label/1.0.2:
+ resolution: {integrity: sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==}
+ dependencies:
+ micromark-util-character: 1.1.0
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ uvu: 0.5.6
+ dev: false
+
+ /micromark-factory-space/1.0.0:
+ resolution: {integrity: sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==}
+ dependencies:
+ micromark-util-character: 1.1.0
+ micromark-util-types: 1.0.2
+ dev: false
+
+ /micromark-factory-title/1.0.2:
+ resolution: {integrity: sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==}
+ dependencies:
+ micromark-factory-space: 1.0.0
+ micromark-util-character: 1.1.0
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ uvu: 0.5.6
+ dev: false
+
+ /micromark-factory-whitespace/1.0.0:
+ resolution: {integrity: sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==}
+ dependencies:
+ micromark-factory-space: 1.0.0
+ micromark-util-character: 1.1.0
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ dev: false
+
+ /micromark-util-character/1.1.0:
+ resolution: {integrity: sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==}
+ dependencies:
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ dev: false
+
+ /micromark-util-chunked/1.0.0:
+ resolution: {integrity: sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==}
+ dependencies:
+ micromark-util-symbol: 1.0.1
+ dev: false
+
+ /micromark-util-classify-character/1.0.0:
+ resolution: {integrity: sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==}
+ dependencies:
+ micromark-util-character: 1.1.0
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ dev: false
+
+ /micromark-util-combine-extensions/1.0.0:
+ resolution: {integrity: sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==}
+ dependencies:
+ micromark-util-chunked: 1.0.0
+ micromark-util-types: 1.0.2
+ dev: false
+
+ /micromark-util-decode-numeric-character-reference/1.0.0:
+ resolution: {integrity: sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==}
+ dependencies:
+ micromark-util-symbol: 1.0.1
+ dev: false
+
+ /micromark-util-decode-string/1.0.2:
+ resolution: {integrity: sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==}
+ dependencies:
+ decode-named-character-reference: 1.0.2
+ micromark-util-character: 1.1.0
+ micromark-util-decode-numeric-character-reference: 1.0.0
+ micromark-util-symbol: 1.0.1
+ dev: false
+
+ /micromark-util-encode/1.0.1:
+ resolution: {integrity: sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==}
+ dev: false
+
+ /micromark-util-html-tag-name/1.1.0:
+ resolution: {integrity: sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==}
+ dev: false
+
+ /micromark-util-normalize-identifier/1.0.0:
+ resolution: {integrity: sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==}
+ dependencies:
+ micromark-util-symbol: 1.0.1
+ dev: false
+
+ /micromark-util-resolve-all/1.0.0:
+ resolution: {integrity: sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==}
+ dependencies:
+ micromark-util-types: 1.0.2
+ dev: false
+
+ /micromark-util-sanitize-uri/1.1.0:
+ resolution: {integrity: sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==}
+ dependencies:
+ micromark-util-character: 1.1.0
+ micromark-util-encode: 1.0.1
+ micromark-util-symbol: 1.0.1
+ dev: false
+
+ /micromark-util-subtokenize/1.0.2:
+ resolution: {integrity: sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==}
+ dependencies:
+ micromark-util-chunked: 1.0.0
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ uvu: 0.5.6
+ dev: false
+
+ /micromark-util-symbol/1.0.1:
+ resolution: {integrity: sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==}
+ dev: false
+
+ /micromark-util-types/1.0.2:
+ resolution: {integrity: sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==}
+ dev: false
+
+ /micromark/3.1.0:
+ resolution: {integrity: sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==}
+ dependencies:
+ '@types/debug': 4.1.7
+ debug: 4.3.4
+ decode-named-character-reference: 1.0.2
+ micromark-core-commonmark: 1.0.6
+ micromark-factory-space: 1.0.0
+ micromark-util-character: 1.1.0
+ micromark-util-chunked: 1.0.0
+ micromark-util-combine-extensions: 1.0.0
+ micromark-util-decode-numeric-character-reference: 1.0.0
+ micromark-util-encode: 1.0.1
+ micromark-util-normalize-identifier: 1.0.0
+ micromark-util-resolve-all: 1.0.0
+ micromark-util-sanitize-uri: 1.1.0
+ micromark-util-subtokenize: 1.0.2
+ micromark-util-symbol: 1.0.1
+ micromark-util-types: 1.0.2
+ uvu: 0.5.6
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /micromatch/4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+ dev: true
+
+ /microseconds/0.2.0:
+ resolution: {integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==}
+ dev: false
+
+ /minimatch/3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ dependencies:
+ brace-expansion: 1.1.11
+
+ /minimatch/5.1.6:
+ resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
+ engines: {node: '>=10'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
+ /minimist/1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+ dev: true
+
+ /mkdirp-classic/0.5.3:
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+ dev: true
+
+ /mkdirp/1.0.4:
+ resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dev: true
+
+ /mri/1.2.0:
+ resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /ms/2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+ /mz/2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+ dev: true
+
+ /nano-time/1.0.0:
+ resolution: {integrity: sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==}
+ dependencies:
+ big-integer: 1.6.51
+ dev: false
+
+ /nanoid/3.3.6:
+ resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: true
+
+ /nanospinner/1.1.0:
+ resolution: {integrity: sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==}
+ dependencies:
+ picocolors: 1.0.0
+ dev: true
+
+ /natural-compare-lite/1.4.0:
+ resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
+ dev: true
+
+ /natural-compare/1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ dev: true
+
+ /node-fetch/2.6.7:
+ resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ dependencies:
+ whatwg-url: 5.0.0
+ dev: true
+
+ /node-releases/2.0.10:
+ resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
+ dev: true
+
+ /normalize-path/3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /object-assign/4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ /object-inspect/1.12.3:
+ resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
+ dev: true
+
+ /object-is/1.1.5:
+ resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ dev: true
+
+ /object-keys/1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /object.assign/4.1.4:
+ resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ has-symbols: 1.0.3
+ object-keys: 1.1.1
+ dev: true
+
+ /object.entries/1.1.6:
+ resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /object.fromentries/2.0.6:
+ resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /object.hasown/1.1.2:
+ resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==}
+ dependencies:
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /object.values/1.1.6:
+ resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /oblivious-set/1.0.0:
+ resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==}
+ dev: false
+
+ /once/1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ dependencies:
+ wrappy: 1.0.2
+
+ /open/8.4.2:
+ resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ define-lazy-prop: 2.0.0
+ is-docker: 2.2.1
+ is-wsl: 2.2.0
+ dev: true
+
+ /optionator/0.9.1:
+ resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.3
+ dev: true
+
+ /p-limit/2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+ dependencies:
+ p-try: 2.2.0
+ dev: true
+
+ /p-limit/3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ yocto-queue: 0.1.0
+ dev: true
+
+ /p-locate/4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+ dependencies:
+ p-limit: 2.3.0
+ dev: true
+
+ /p-locate/5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-limit: 3.1.0
+ dev: true
+
+ /p-try/2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /parent-module/1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+ dependencies:
+ callsites: 3.1.0
+
+ /parse-json/5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/code-frame': 7.21.4
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+ dev: false
+
+ /path-exists/4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-is-absolute/1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+
+ /path-key/3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-parse/1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ /path-type/4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
+ /pathval/1.1.1:
+ resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+ dev: true
+
+ /pend/1.2.0:
+ resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
+ dev: true
+
+ /picocolors/1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+ dev: true
+
+ /picomatch/2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+ dev: true
+
+ /pirates/4.0.5:
+ resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /pkg-dir/4.2.0:
+ resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ find-up: 4.1.0
+ dev: true
+
+ /postcss/8.4.22:
+ resolution: {integrity: sha512-XseknLAfRHzVWjCEtdviapiBtfLdgyzExD50Rg2ePaucEesyh8Wv4VPdW0nbyDa1ydbrAxV19jvMT4+LFmcNUA==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.6
+ picocolors: 1.0.0
+ source-map-js: 1.0.2
+ dev: true
+
+ /prelude-ls/1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /prettier-linter-helpers/1.0.0:
+ resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ fast-diff: 1.2.0
+ dev: true
+
+ /prettier/2.8.7:
+ resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ dev: true
+
+ /pretty-bytes/5.6.0:
+ resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /pretty-bytes/6.1.0:
+ resolution: {integrity: sha512-Rk753HI8f4uivXi4ZCIYdhmG1V+WKzvRMg/X+M42a6t7D07RcmopXJMDNk6N++7Bl75URRGsb40ruvg7Hcp2wQ==}
+ engines: {node: ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /pretty-format/28.1.3:
+ resolution: {integrity: sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==}
+ engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
+ dependencies:
+ '@jest/schemas': 28.1.3
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 18.2.0
+ dev: true
+
+ /progress/2.0.3:
+ resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /prop-types/15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
+ /property-information/6.2.0:
+ resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==}
+ dev: false
+
+ /proxy-from-env/1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+ dev: true
+
+ /pump/3.0.0:
+ resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
+ dependencies:
+ end-of-stream: 1.4.4
+ once: 1.4.0
+ dev: true
+
+ /punycode/2.3.0:
+ resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /puppeteer-core/13.7.0:
+ resolution: {integrity: sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==}
+ engines: {node: '>=10.18.1'}
+ dependencies:
+ cross-fetch: 3.1.5
+ debug: 4.3.4
+ devtools-protocol: 0.0.981744
+ extract-zip: 2.0.1
+ https-proxy-agent: 5.0.1
+ pkg-dir: 4.2.0
+ progress: 2.0.3
+ proxy-from-env: 1.1.0
+ rimraf: 3.0.2
+ tar-fs: 2.1.1
+ unbzip2-stream: 1.4.3
+ ws: 8.5.0
+ transitivePeerDependencies:
+ - bufferutil
+ - encoding
+ - supports-color
+ - utf-8-validate
+ dev: true
+
+ /queue-microtask/1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ dev: true
+
+ /randombytes/2.1.0:
+ resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /react-dom/18.2.0_react@18.2.0:
+ resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
+ peerDependencies:
+ react: ^18.2.0
+ dependencies:
+ loose-envify: 1.4.0
+ react: 18.2.0
+ scheduler: 0.23.0
+ dev: false
+
+ /react-is/16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ /react-is/18.2.0:
+ resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
+
+ /react-markdown/8.0.7_yuz6bkerhkjfjuf6zeb7j6ybc4:
+ resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==}
+ peerDependencies:
+ '@types/react': '>=16'
+ react: '>=16'
+ dependencies:
+ '@types/hast': 2.3.4
+ '@types/prop-types': 15.7.5
+ '@types/react': 18.0.35
+ '@types/unist': 2.0.6
+ comma-separated-tokens: 2.0.3
+ hast-util-whitespace: 2.0.1
+ prop-types: 15.8.1
+ property-information: 6.2.0
+ react: 18.2.0
+ react-is: 18.2.0
+ remark-parse: 10.0.1
+ remark-rehype: 10.1.0
+ space-separated-tokens: 2.0.2
+ style-to-object: 0.4.1
+ unified: 10.1.2
+ unist-util-visit: 4.1.2
+ vfile: 5.3.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /react-query/3.39.3_biqbaboplfbrettd7655fr4n2y:
+ resolution: {integrity: sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: '*'
+ react-native: '*'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.21.0
+ broadcast-channel: 3.7.0
+ match-sorter: 6.3.1
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ dev: false
+
+ /react-refresh/0.14.0:
+ resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /react-router-dom/6.10.0_biqbaboplfbrettd7655fr4n2y:
+ resolution: {integrity: sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ react: '>=16.8'
+ react-dom: '>=16.8'
+ dependencies:
+ '@remix-run/router': 1.5.0
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ react-router: 6.10.0_react@18.2.0
+ dev: false
+
+ /react-router/6.10.0_react@18.2.0:
+ resolution: {integrity: sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ react: '>=16.8'
+ dependencies:
+ '@remix-run/router': 1.5.0
+ react: 18.2.0
+ dev: false
+
+ /react-transition-group/4.4.5_biqbaboplfbrettd7655fr4n2y:
+ resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
+ peerDependencies:
+ react: '>=16.6.0'
+ react-dom: '>=16.6.0'
+ dependencies:
+ '@babel/runtime': 7.21.0
+ dom-helpers: 5.2.1
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ dev: false
+
+ /react/17.0.2:
+ resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ dev: true
+
+ /react/18.2.0:
+ resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ loose-envify: 1.4.0
+ dev: false
+
+ /readable-stream/3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /readdirp/3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+ dev: true
+
+ /recrawl-sync/2.2.3:
+ resolution: {integrity: sha512-vSaTR9t+cpxlskkdUFrsEpnf67kSmPk66yAGT1fZPrDudxQjoMzPgQhSMImQ0pAw5k0NPirefQfhopSjhdUtpQ==}
+ dependencies:
+ '@cush/relative': 1.0.0
+ glob-regex: 0.3.2
+ slash: 3.0.0
+ sucrase: 3.32.0
+ tslib: 1.14.1
+ dev: true
+
+ /regenerate-unicode-properties/10.1.0:
+ resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ regenerate: 1.4.2
+ dev: true
+
+ /regenerate/1.4.2:
+ resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==}
+ dev: true
+
+ /regenerator-runtime/0.13.11:
+ resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+
+ /regenerator-transform/0.15.1:
+ resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==}
+ dependencies:
+ '@babel/runtime': 7.21.0
+ dev: true
+
+ /regexp.prototype.flags/1.4.3:
+ resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ functions-have-names: 1.2.3
+ dev: true
+
+ /regexpu-core/5.3.2:
+ resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==}
+ engines: {node: '>=4'}
+ 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
+ dev: true
+
+ /regjsparser/0.9.1:
+ resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==}
+ hasBin: true
+ dependencies:
+ jsesc: 0.5.0
+ dev: true
+
+ /remark-parse/10.0.1:
+ resolution: {integrity: sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==}
+ dependencies:
+ '@types/mdast': 3.0.11
+ mdast-util-from-markdown: 1.3.0
+ unified: 10.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /remark-rehype/10.1.0:
+ resolution: {integrity: sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==}
+ dependencies:
+ '@types/hast': 2.3.4
+ '@types/mdast': 3.0.11
+ mdast-util-to-hast: 12.3.0
+ unified: 10.1.2
+ dev: false
+
+ /remove-accents/0.4.2:
+ resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==}
+ dev: false
+
+ /require-directory/2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /require-from-string/2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /resolve-from/4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ /resolve/1.22.3:
+ resolution: {integrity: sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.12.0
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ /resolve/2.0.0-next.4:
+ resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.12.0
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: true
+
+ /reusify/1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ dev: true
+
+ /rimraf/3.0.2:
+ resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ hasBin: true
+ dependencies:
+ glob: 7.2.3
+
+ /rollup-plugin-terser/7.0.2_rollup@2.79.1:
+ resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
+ deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
+ peerDependencies:
+ rollup: ^2.0.0
+ dependencies:
+ '@babel/code-frame': 7.21.4
+ jest-worker: 26.6.2
+ rollup: 2.79.1
+ serialize-javascript: 4.0.0
+ terser: 5.16.9
+ dev: true
+
+ /rollup-plugin-visualizer/5.9.0:
+ resolution: {integrity: sha512-bbDOv47+Bw4C/cgs0czZqfm8L82xOZssk4ayZjG40y9zbXclNk7YikrZTDao6p7+HDiGxrN0b65SgZiVm9k1Cg==}
+ engines: {node: '>=14'}
+ hasBin: true
+ peerDependencies:
+ rollup: 2.x || 3.x
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+ dependencies:
+ open: 8.4.2
+ picomatch: 2.3.1
+ source-map: 0.7.4
+ yargs: 17.7.1
+ dev: true
+
+ /rollup/2.79.1:
+ resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==}
+ engines: {node: '>=10.0.0'}
+ hasBin: true
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /run-parallel/1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+ dev: true
+
+ /sade/1.8.1:
+ resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
+ engines: {node: '>=6'}
+ dependencies:
+ mri: 1.2.0
+ dev: false
+
+ /safe-buffer/5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ dev: true
+
+ /safe-regex-test/1.0.0:
+ resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.2.0
+ is-regex: 1.1.4
+ dev: true
+
+ /scheduler/0.23.0:
+ resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
+ dependencies:
+ loose-envify: 1.4.0
+ dev: false
+
+ /scroll-into-view-if-needed/2.2.31:
+ resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==}
+ dependencies:
+ compute-scroll-into-view: 1.0.20
+ dev: false
+
+ /semver/6.3.0:
+ resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
+ hasBin: true
+ dev: true
+
+ /semver/7.3.5:
+ resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+ dev: true
+
+ /semver/7.4.0:
+ resolution: {integrity: sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+ dev: true
+
+ /serialize-javascript/4.0.0:
+ resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==}
+ dependencies:
+ randombytes: 2.1.0
+ dev: true
+
+ /shebang-command/2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+ dependencies:
+ shebang-regex: 3.0.0
+ dev: true
+
+ /shebang-regex/3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /side-channel/1.0.4:
+ resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.2.0
+ object-inspect: 1.12.3
+ dev: true
+
+ /signal-exit/3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ dev: true
+
+ /size-limit/7.0.8:
+ resolution: {integrity: sha512-3h76c9E0e/nNhYLSR7IBI/bSoXICeo7EYkYjlyVqNIsu7KvN/PQmMbIXeyd2QKIF8iZKhaiZQoXLkGWbyPDtvQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ bytes-iec: 3.1.1
+ chokidar: 3.5.3
+ ci-job-number: 1.2.2
+ globby: 11.1.0
+ lilconfig: 2.1.0
+ mkdirp: 1.0.4
+ nanospinner: 1.1.0
+ picocolors: 1.0.0
+ dev: true
+
+ /slash/3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /slate-react/0.81.0_njwfekudbehx2lwpmvgkrdxmhi:
+ resolution: {integrity: sha512-bwryad4EvOmc7EFKb8aGg9DWNDh3KvToaggGieIgGTTbHJYHc9ADFC3A87Ittlpd5XUVopR0MpChQ3g3ODyvqw==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+ slate: '>=0.65.3'
+ dependencies:
+ '@types/is-hotkey': 0.1.7
+ '@types/lodash': 4.14.194
+ direction: 1.0.4
+ is-hotkey: 0.1.8
+ is-plain-object: 5.0.0
+ lodash: 4.17.21
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ scroll-into-view-if-needed: 2.2.31
+ slate: 0.81.3
+ tiny-invariant: 1.0.6
+ dev: false
+
+ /slate/0.81.3:
+ resolution: {integrity: sha512-9rME3rSOsR76BsTGezNp6kiwjJL4yVJLwVQawj9xUf8wEZqoPU8d38hyQ3Jeg1SG6me2aS43m6H+n163/BhGWw==}
+ dependencies:
+ immer: 9.0.21
+ is-plain-object: 5.0.0
+ tiny-warning: 1.0.3
+ dev: false
+
+ /source-map-js/1.0.2:
+ resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /source-map-support/0.5.21:
+ resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+ dependencies:
+ buffer-from: 1.1.2
+ source-map: 0.6.1
+ dev: true
+
+ /source-map/0.5.7:
+ resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /source-map/0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /source-map/0.7.4:
+ resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /source-map/0.8.0-beta.0:
+ resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
+ engines: {node: '>= 8'}
+ dependencies:
+ whatwg-url: 7.1.0
+ dev: true
+
+ /sourcemap-codec/1.4.8:
+ resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
+ deprecated: Please use @jridgewell/sourcemap-codec instead
+ dev: true
+
+ /space-separated-tokens/2.0.2:
+ resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
+ dev: false
+
+ /stack-utils/2.0.6:
+ resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ escape-string-regexp: 2.0.0
+ dev: true
+
+ /stop-iteration-iterator/1.0.0:
+ resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ internal-slot: 1.0.5
+ dev: true
+
+ /string-width/4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+ dev: true
+
+ /string.prototype.matchall/4.0.8:
+ resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ get-intrinsic: 1.2.0
+ has-symbols: 1.0.3
+ internal-slot: 1.0.5
+ regexp.prototype.flags: 1.4.3
+ side-channel: 1.0.4
+ dev: true
+
+ /string.prototype.trim/1.2.7:
+ resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /string.prototype.trimend/1.0.6:
+ resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /string.prototype.trimstart/1.0.6:
+ resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ es-abstract: 1.21.2
+ dev: true
+
+ /string_decoder/1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /stringify-object/3.3.0:
+ resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==}
+ engines: {node: '>=4'}
+ dependencies:
+ get-own-enumerable-property-symbols: 3.0.2
+ is-obj: 1.0.1
+ is-regexp: 1.0.0
+ dev: true
+
+ /strip-ansi/6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-regex: 5.0.1
+ dev: true
+
+ /strip-bom/3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /strip-comments/2.0.1:
+ resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /strip-json-comments/3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /style-to-object/0.4.1:
+ resolution: {integrity: sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==}
+ dependencies:
+ inline-style-parser: 0.1.1
+ dev: false
+
+ /stylis/4.1.3:
+ resolution: {integrity: sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==}
+ dev: false
+
+ /sucrase/3.32.0:
+ resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==}
+ engines: {node: '>=8'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.3
+ commander: 4.1.1
+ glob: 7.1.6
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.5
+ ts-interface-checker: 0.1.13
+ dev: true
+
+ /supports-color/5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: 3.0.0
+
+ /supports-color/7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+ dependencies:
+ has-flag: 4.0.0
+ dev: true
+
+ /supports-preserve-symlinks-flag/1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ /tar-fs/2.1.1:
+ resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+ dependencies:
+ chownr: 1.1.4
+ mkdirp-classic: 0.5.3
+ pump: 3.0.0
+ tar-stream: 2.2.0
+ dev: true
+
+ /tar-stream/2.2.0:
+ resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ bl: 4.1.0
+ end-of-stream: 1.4.4
+ fs-constants: 1.0.0
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: true
+
+ /temp-dir/2.0.0:
+ resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /tempy/0.6.0:
+ resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==}
+ engines: {node: '>=10'}
+ dependencies:
+ is-stream: 2.0.1
+ temp-dir: 2.0.0
+ type-fest: 0.16.0
+ unique-string: 2.0.0
+ dev: true
+
+ /terser/5.16.9:
+ resolution: {integrity: sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/source-map': 0.3.3
+ acorn: 8.8.2
+ commander: 2.20.3
+ source-map-support: 0.5.21
+ dev: true
+
+ /test-exclude/6.0.0:
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 7.2.3
+ minimatch: 3.1.2
+ dev: true
+
+ /text-table/0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ dev: true
+
+ /thenify-all/1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ thenify: 3.3.1
+ dev: true
+
+ /thenify/3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ dependencies:
+ any-promise: 1.3.0
+ dev: true
+
+ /through/2.3.8:
+ resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+ dev: true
+
+ /tiny-invariant/1.0.6:
+ resolution: {integrity: sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==}
+ dev: false
+
+ /tiny-warning/1.0.3:
+ resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
+ dev: false
+
+ /tinypool/0.2.4:
+ resolution: {integrity: sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==}
+ engines: {node: '>=14.0.0'}
+ dev: true
+
+ /tinyspy/1.1.1:
+ resolution: {integrity: sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==}
+ engines: {node: '>=14.0.0'}
+ dev: true
+
+ /to-fast-properties/2.0.0:
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+ engines: {node: '>=4'}
+
+ /to-regex-range/5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ is-number: 7.0.0
+ dev: true
+
+ /tr46/0.0.3:
+ resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ dev: true
+
+ /tr46/1.0.1:
+ resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
+ dependencies:
+ punycode: 2.3.0
+ dev: true
+
+ /trim-lines/3.0.1:
+ resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
+ dev: false
+
+ /trough/2.1.0:
+ resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==}
+ dev: false
+
+ /ts-interface-checker/0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+ dev: true
+
+ /tsconfig-paths/4.2.0:
+ resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
+ engines: {node: '>=6'}
+ dependencies:
+ json5: 2.2.3
+ minimist: 1.2.8
+ strip-bom: 3.0.0
+ dev: true
+
+ /tslib/1.14.1:
+ resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+ dev: true
+
+ /tsutils/3.21.0_typescript@4.9.5:
+ resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+ engines: {node: '>= 6'}
+ peerDependencies:
+ typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+ dependencies:
+ tslib: 1.14.1
+ typescript: 4.9.5
+ dev: true
+
+ /type-check/0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ dev: true
+
+ /type-detect/4.0.8:
+ resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /type-fest/0.16.0:
+ resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /type-fest/0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /typed-array-length/1.0.4:
+ resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
+ dependencies:
+ call-bind: 1.0.2
+ for-each: 0.3.3
+ is-typed-array: 1.1.10
+ dev: true
+
+ /typescript/4.9.5:
+ resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
+ engines: {node: '>=4.2.0'}
+ hasBin: true
+ dev: true
+
+ /unbox-primitive/1.0.2:
+ resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+ dependencies:
+ call-bind: 1.0.2
+ has-bigints: 1.0.2
+ has-symbols: 1.0.3
+ which-boxed-primitive: 1.0.2
+ dev: true
+
+ /unbzip2-stream/1.4.3:
+ resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==}
+ dependencies:
+ buffer: 5.7.1
+ through: 2.3.8
+ dev: true
+
+ /unicode-canonical-property-names-ecmascript/2.0.0:
+ resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /unicode-match-property-ecmascript/2.0.0:
+ resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==}
+ engines: {node: '>=4'}
+ dependencies:
+ unicode-canonical-property-names-ecmascript: 2.0.0
+ unicode-property-aliases-ecmascript: 2.1.0
+ dev: true
+
+ /unicode-match-property-value-ecmascript/2.1.0:
+ resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /unicode-property-aliases-ecmascript/2.1.0:
+ resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /unified/10.1.2:
+ resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==}
+ dependencies:
+ '@types/unist': 2.0.6
+ bail: 2.0.2
+ extend: 3.0.2
+ is-buffer: 2.0.5
+ is-plain-obj: 4.1.0
+ trough: 2.1.0
+ vfile: 5.3.7
+ dev: false
+
+ /unique-string/2.0.0:
+ resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
+ engines: {node: '>=8'}
+ dependencies:
+ crypto-random-string: 2.0.0
+ dev: true
+
+ /unist-util-generated/2.0.1:
+ resolution: {integrity: sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==}
+ dev: false
+
+ /unist-util-is/5.2.1:
+ resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: false
+
+ /unist-util-position/4.0.4:
+ resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: false
+
+ /unist-util-stringify-position/3.0.3:
+ resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: false
+
+ /unist-util-visit-parents/5.1.3:
+ resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==}
+ dependencies:
+ '@types/unist': 2.0.6
+ unist-util-is: 5.2.1
+ dev: false
+
+ /unist-util-visit/4.1.2:
+ resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==}
+ dependencies:
+ '@types/unist': 2.0.6
+ unist-util-is: 5.2.1
+ unist-util-visit-parents: 5.1.3
+ dev: false
+
+ /universalify/2.0.0:
+ resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
+ engines: {node: '>= 10.0.0'}
+ dev: true
+
+ /unload/2.2.0:
+ resolution: {integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==}
+ dependencies:
+ '@babel/runtime': 7.21.0
+ detect-node: 2.1.0
+ dev: false
+
+ /upath/1.2.0:
+ resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /update-browserslist-db/1.0.11_browserslist@4.21.5:
+ resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+ dependencies:
+ browserslist: 4.21.5
+ escalade: 3.1.1
+ picocolors: 1.0.0
+ dev: true
+
+ /uri-js/4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ dependencies:
+ punycode: 2.3.0
+ dev: true
+
+ /use-local-storage-state/17.3.0_biqbaboplfbrettd7655fr4n2y:
+ resolution: {integrity: sha512-PZruqtmMkYCgcC5t+0Mbka1rN2jjhC1SMA2UD8o6HbpblZf8E9aaXF0sEwlQAWlBpKGlNYvbqueB8dlbwX7n/g==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ react: '>=16.8.0 < 18'
+ react-dom: '>=16.8.0 < 18'
+ dependencies:
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ dev: false
+
+ /use-sync-external-store/1.2.0_react@18.2.0:
+ resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /util-deprecate/1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ dev: true
+
+ /uvu/0.5.6:
+ resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==}
+ engines: {node: '>=8'}
+ hasBin: true
+ dependencies:
+ dequal: 2.0.3
+ diff: 5.1.0
+ kleur: 4.1.5
+ sade: 1.8.1
+ dev: false
+
+ /v8-to-istanbul/9.1.0:
+ resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==}
+ engines: {node: '>=10.12.0'}
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.18
+ '@types/istanbul-lib-coverage': 2.0.4
+ convert-source-map: 1.9.0
+ dev: true
+
+ /vfile-message/3.1.4:
+ resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==}
+ dependencies:
+ '@types/unist': 2.0.6
+ unist-util-stringify-position: 3.0.3
+ dev: false
+
+ /vfile/5.3.7:
+ resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==}
+ dependencies:
+ '@types/unist': 2.0.6
+ is-buffer: 2.0.5
+ unist-util-stringify-position: 3.0.3
+ vfile-message: 3.1.4
+ dev: false
+
+ /vite-plugin-pwa/0.12.8_vite@3.2.5:
+ resolution: {integrity: sha512-pSiFHmnJGMQJJL8aJzQ8SaraZBSBPMGvGUkCNzheIq9UQCEk/eP3UmANNmS9eupuhIpTK8AdxTOHcaMcAqAbCA==}
+ peerDependencies:
+ vite: ^2.0.0 || ^3.0.0-0
+ dependencies:
+ debug: 4.3.4
+ fast-glob: 3.2.12
+ pretty-bytes: 6.1.0
+ rollup: 2.79.1
+ vite: 3.2.5_@types+node@17.0.45
+ workbox-build: 6.5.4
+ workbox-window: 6.5.4
+ transitivePeerDependencies:
+ - '@types/babel__core'
+ - supports-color
+ dev: true
+
+ /vite-tsconfig-paths/3.6.0_vite@3.2.5:
+ resolution: {integrity: sha512-UfsPYonxLqPD633X8cWcPFVuYzx/CMNHAjZTasYwX69sXpa4gNmQkR0XCjj82h7zhLGdTWagMjC1qfb9S+zv0A==}
+ peerDependencies:
+ vite: '>2.0.0-0'
+ dependencies:
+ debug: 4.3.4
+ globrex: 0.1.2
+ recrawl-sync: 2.2.3
+ tsconfig-paths: 4.2.0
+ vite: 3.2.5_@types+node@17.0.45
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /vite/3.2.5_@types+node@17.0.45:
+ resolution: {integrity: sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': '>= 14'
+ less: '*'
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ dependencies:
+ '@types/node': 17.0.45
+ esbuild: 0.15.18
+ postcss: 8.4.22
+ resolve: 1.22.3
+ rollup: 2.79.1
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /vitest/0.20.3_c8@7.13.0:
+ resolution: {integrity: sha512-cXMjTbZxBBUUuIF3PUzEGPLJWtIMeURBDXVxckSHpk7xss4JxkiiWh5cnIlfGyfJne2Ii3QpbiRuFL5dMJtljw==}
+ engines: {node: '>=v14.16.0'}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@vitest/browser': '*'
+ '@vitest/ui': '*'
+ c8: '*'
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ c8:
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+ dependencies:
+ '@types/chai': 4.3.4
+ '@types/chai-subset': 1.3.3
+ '@types/node': 17.0.45
+ c8: 7.13.0
+ chai: 4.3.7
+ debug: 4.3.4
+ local-pkg: 0.4.3
+ tinypool: 0.2.4
+ tinyspy: 1.1.1
+ vite: 3.2.5_@types+node@17.0.45
+ transitivePeerDependencies:
+ - less
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ dev: true
+
+ /webidl-conversions/3.0.1:
+ resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ dev: true
+
+ /webidl-conversions/4.0.2:
+ resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
+ dev: true
+
+ /whatwg-url/5.0.0:
+ resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+ dev: true
+
+ /whatwg-url/7.1.0:
+ resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
+ dependencies:
+ lodash.sortby: 4.7.0
+ tr46: 1.0.1
+ webidl-conversions: 4.0.2
+ dev: true
+
+ /which-boxed-primitive/1.0.2:
+ resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+ dependencies:
+ is-bigint: 1.0.4
+ is-boolean-object: 1.1.2
+ is-number-object: 1.0.7
+ is-string: 1.0.7
+ is-symbol: 1.0.4
+ dev: true
+
+ /which-collection/1.0.1:
+ resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==}
+ dependencies:
+ is-map: 2.0.2
+ is-set: 2.0.2
+ is-weakmap: 2.0.1
+ is-weakset: 2.0.2
+ dev: true
+
+ /which-typed-array/1.1.9:
+ resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.2
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-tostringtag: 1.0.0
+ is-typed-array: 1.1.10
+ dev: true
+
+ /which/2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+ dev: true
+
+ /word-wrap/1.2.3:
+ resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /workbox-background-sync/6.5.4:
+ resolution: {integrity: sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g==}
+ dependencies:
+ idb: 7.1.1
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-broadcast-update/6.5.4:
+ resolution: {integrity: sha512-I/lBERoH1u3zyBosnpPEtcAVe5lwykx9Yg1k6f8/BGEPGaMMgZrwVrqL1uA9QZ1NGGFoyE6t9i7lBjOlDhFEEw==}
+ dependencies:
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-build/6.5.4:
+ resolution: {integrity: sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==}
+ engines: {node: '>=10.0.0'}
+ dependencies:
+ '@apideck/better-ajv-errors': 0.3.6_ajv@8.12.0
+ '@babel/core': 7.21.4
+ '@babel/preset-env': 7.21.4_@babel+core@7.21.4
+ '@babel/runtime': 7.21.0
+ '@rollup/plugin-babel': 5.3.1_b6cdhqm2xsfe2bpl424qdsl4ei
+ '@rollup/plugin-node-resolve': 11.2.1_rollup@2.79.1
+ '@rollup/plugin-replace': 2.4.2_rollup@2.79.1
+ '@surma/rollup-plugin-off-main-thread': 2.2.3
+ ajv: 8.12.0
+ common-tags: 1.8.2
+ fast-json-stable-stringify: 2.1.0
+ fs-extra: 9.1.0
+ glob: 7.2.3
+ lodash: 4.17.21
+ pretty-bytes: 5.6.0
+ rollup: 2.79.1
+ rollup-plugin-terser: 7.0.2_rollup@2.79.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: 6.5.4
+ workbox-broadcast-update: 6.5.4
+ workbox-cacheable-response: 6.5.4
+ workbox-core: 6.5.4
+ workbox-expiration: 6.5.4
+ workbox-google-analytics: 6.5.4
+ workbox-navigation-preload: 6.5.4
+ workbox-precaching: 6.5.4
+ workbox-range-requests: 6.5.4
+ workbox-recipes: 6.5.4
+ workbox-routing: 6.5.4
+ workbox-strategies: 6.5.4
+ workbox-streams: 6.5.4
+ workbox-sw: 6.5.4
+ workbox-window: 6.5.4
+ transitivePeerDependencies:
+ - '@types/babel__core'
+ - supports-color
+ dev: true
+
+ /workbox-cacheable-response/6.5.4:
+ resolution: {integrity: sha512-DCR9uD0Fqj8oB2TSWQEm1hbFs/85hXXoayVwFKLVuIuxwJaihBsLsp4y7J9bvZbqtPJ1KlCkmYVGQKrBU4KAug==}
+ dependencies:
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-core/6.5.4:
+ resolution: {integrity: sha512-OXYb+m9wZm8GrORlV2vBbE5EC1FKu71GGp0H4rjmxmF4/HLbMCoTFws87M3dFwgpmg0v00K++PImpNQ6J5NQ6Q==}
+ dev: true
+
+ /workbox-expiration/6.5.4:
+ resolution: {integrity: sha512-jUP5qPOpH1nXtjGGh1fRBa1wJL2QlIb5mGpct3NzepjGG2uFFBn4iiEBiI9GUmfAFR2ApuRhDydjcRmYXddiEQ==}
+ dependencies:
+ idb: 7.1.1
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-google-analytics/6.5.4:
+ resolution: {integrity: sha512-8AU1WuaXsD49249Wq0B2zn4a/vvFfHkpcFfqAFHNHwln3jK9QUYmzdkKXGIZl9wyKNP+RRX30vcgcyWMcZ9VAg==}
+ dependencies:
+ workbox-background-sync: 6.5.4
+ workbox-core: 6.5.4
+ workbox-routing: 6.5.4
+ workbox-strategies: 6.5.4
+ dev: true
+
+ /workbox-navigation-preload/6.5.4:
+ resolution: {integrity: sha512-IIwf80eO3cr8h6XSQJF+Hxj26rg2RPFVUmJLUlM0+A2GzB4HFbQyKkrgD5y2d84g2IbJzP4B4j5dPBRzamHrng==}
+ dependencies:
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-precaching/6.5.4:
+ resolution: {integrity: sha512-hSMezMsW6btKnxHB4bFy2Qfwey/8SYdGWvVIKFaUm8vJ4E53JAY+U2JwLTRD8wbLWoP6OVUdFlXsTdKu9yoLTg==}
+ dependencies:
+ workbox-core: 6.5.4
+ workbox-routing: 6.5.4
+ workbox-strategies: 6.5.4
+ dev: true
+
+ /workbox-range-requests/6.5.4:
+ resolution: {integrity: sha512-Je2qR1NXCFC8xVJ/Lux6saH6IrQGhMpDrPXWZWWS8n/RD+WZfKa6dSZwU+/QksfEadJEr/NfY+aP/CXFFK5JFg==}
+ dependencies:
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-recipes/6.5.4:
+ resolution: {integrity: sha512-QZNO8Ez708NNwzLNEXTG4QYSKQ1ochzEtRLGaq+mr2PyoEIC1xFW7MrWxrONUxBFOByksds9Z4//lKAX8tHyUA==}
+ dependencies:
+ workbox-cacheable-response: 6.5.4
+ workbox-core: 6.5.4
+ workbox-expiration: 6.5.4
+ workbox-precaching: 6.5.4
+ workbox-routing: 6.5.4
+ workbox-strategies: 6.5.4
+ dev: true
+
+ /workbox-routing/6.5.4:
+ resolution: {integrity: sha512-apQswLsbrrOsBUWtr9Lf80F+P1sHnQdYodRo32SjiByYi36IDyL2r7BH1lJtFX8fwNHDa1QOVY74WKLLS6o5Pg==}
+ dependencies:
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-strategies/6.5.4:
+ resolution: {integrity: sha512-DEtsxhx0LIYWkJBTQolRxG4EI0setTJkqR4m7r4YpBdxtWJH1Mbg01Cj8ZjNOO8etqfA3IZaOPHUxCs8cBsKLw==}
+ dependencies:
+ workbox-core: 6.5.4
+ dev: true
+
+ /workbox-streams/6.5.4:
+ resolution: {integrity: sha512-FXKVh87d2RFXkliAIheBojBELIPnWbQdyDvsH3t74Cwhg0fDheL1T8BqSM86hZvC0ZESLsznSYWw+Va+KVbUzg==}
+ dependencies:
+ workbox-core: 6.5.4
+ workbox-routing: 6.5.4
+ dev: true
+
+ /workbox-sw/6.5.4:
+ resolution: {integrity: sha512-vo2RQo7DILVRoH5LjGqw3nphavEjK4Qk+FenXeUsknKn14eCNedHOXWbmnvP4ipKhlE35pvJ4yl4YYf6YsJArA==}
+ dev: true
+
+ /workbox-window/6.5.4:
+ resolution: {integrity: sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==}
+ dependencies:
+ '@types/trusted-types': 2.0.3
+ workbox-core: 6.5.4
+ dev: true
+
+ /wrap-ansi/7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ dev: true
+
+ /wrappy/1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ /ws/8.5.0:
+ resolution: {integrity: sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ dev: true
+
+ /y18n/5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yallist/3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+ dev: true
+
+ /yallist/4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ dev: true
+
+ /yaml/1.10.2:
+ resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
+ engines: {node: '>= 6'}
+ dev: false
+
+ /yargs-parser/20.2.9:
+ resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yargs-parser/21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /yargs/16.2.0:
+ resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
+ engines: {node: '>=10'}
+ dependencies:
+ cliui: 7.0.4
+ escalade: 3.1.1
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 20.2.9
+ dev: true
+
+ /yargs/17.7.1:
+ resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==}
+ engines: {node: '>=12'}
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.1.1
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+ dev: true
+
+ /yauzl/2.10.0:
+ resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
+ dependencies:
+ buffer-crc32: 0.2.13
+ fd-slicer: 1.1.0
+ dev: true
+
+ /yocto-queue/0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /zod/3.21.4:
+ resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
+ dev: false
+
+ /zustand/4.3.7_react@18.2.0:
+ resolution: {integrity: sha512-dY8ERwB9Nd21ellgkBZFhudER8KVlelZm8388B5nDAXhO/+FZDhYMuRnqDgu5SYyRgz/iaf8RKnbUs/cHfOGlQ==}
+ engines: {node: '>=12.7.0'}
+ peerDependencies:
+ immer: '>=9.0'
+ react: '>=16.8'
+ peerDependenciesMeta:
+ immer:
+ optional: true
+ react:
+ optional: true
+ dependencies:
+ react: 18.2.0
+ use-sync-external-store: 1.2.0_react@18.2.0
+ dev: false
diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png
new file mode 100644
index 0000000..368af39
Binary files /dev/null and b/public/android-chrome-192x192.png differ
diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png
new file mode 100644
index 0000000..4c147d5
Binary files /dev/null and b/public/android-chrome-512x512.png differ
diff --git a/public/apple-touch-icon-114x114.png b/public/apple-touch-icon-114x114.png
new file mode 100644
index 0000000..0eb3cf5
Binary files /dev/null and b/public/apple-touch-icon-114x114.png differ
diff --git a/public/apple-touch-icon-120x120.png b/public/apple-touch-icon-120x120.png
new file mode 100644
index 0000000..05cd5c3
Binary files /dev/null and b/public/apple-touch-icon-120x120.png differ
diff --git a/public/apple-touch-icon-144x144.png b/public/apple-touch-icon-144x144.png
new file mode 100644
index 0000000..e2b29d0
Binary files /dev/null and b/public/apple-touch-icon-144x144.png differ
diff --git a/public/apple-touch-icon-152x152.png b/public/apple-touch-icon-152x152.png
new file mode 100644
index 0000000..33e5bd1
Binary files /dev/null and b/public/apple-touch-icon-152x152.png differ
diff --git a/public/apple-touch-icon-180x180.png b/public/apple-touch-icon-180x180.png
new file mode 100644
index 0000000..652b296
Binary files /dev/null and b/public/apple-touch-icon-180x180.png differ
diff --git a/public/apple-touch-icon-57x57.png b/public/apple-touch-icon-57x57.png
new file mode 100644
index 0000000..5837293
Binary files /dev/null and b/public/apple-touch-icon-57x57.png differ
diff --git a/public/apple-touch-icon-60x60.png b/public/apple-touch-icon-60x60.png
new file mode 100644
index 0000000..e122391
Binary files /dev/null and b/public/apple-touch-icon-60x60.png differ
diff --git a/public/apple-touch-icon-72x72.png b/public/apple-touch-icon-72x72.png
new file mode 100644
index 0000000..ee72790
Binary files /dev/null and b/public/apple-touch-icon-72x72.png differ
diff --git a/public/apple-touch-icon-76x76.png b/public/apple-touch-icon-76x76.png
new file mode 100644
index 0000000..48dcaf2
Binary files /dev/null and b/public/apple-touch-icon-76x76.png differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
new file mode 100644
index 0000000..652b296
Binary files /dev/null and b/public/apple-touch-icon.png differ
diff --git a/public/browserconfig.xml b/public/browserconfig.xml
new file mode 100644
index 0000000..b3930d0
--- /dev/null
+++ b/public/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #da532c
+
+
+
diff --git a/public/logo/google.png b/public/logo/google.png
new file mode 100644
index 0000000..7906ea0
Binary files /dev/null and b/public/logo/google.png differ
diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png
new file mode 100644
index 0000000..5c4dec5
Binary files /dev/null and b/public/mstile-150x150.png differ
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..5537f07
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
\ No newline at end of file
diff --git a/public/safari-pinned-tab.svg b/public/safari-pinned-tab.svg
new file mode 100644
index 0000000..300199e
--- /dev/null
+++ b/public/safari-pinned-tab.svg
@@ -0,0 +1,342 @@
+
+
+
diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore
new file mode 100644
index 0000000..c123704
--- /dev/null
+++ b/src-tauri/.gitignore
@@ -0,0 +1,4 @@
+# Generated by Cargo
+# will have compiled files and executables
+/target/
+WixTools
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
new file mode 100644
index 0000000..21e694d
--- /dev/null
+++ b/src-tauri/Cargo.toml
@@ -0,0 +1,37 @@
+[package]
+name = "dust-mail-client"
+version = "0.1.4"
+description = "A simple material mail client"
+authors = ["Guus van Meerveld"]
+license = "MIT"
+repository = "https://github.com/Guusvanmeerveld/Dust-Mail"
+edition = "2021"
+rust-version = "1.61"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[build-dependencies]
+tauri-build = { version = "1.2", features = ["isolation"] }
+
+[dependencies]
+serde_json = "1.0"
+serde = { version = "1.0", features = ["derive"] }
+tauri = { version = "1.2", features = ["devtools", "isolation", "shell-open", "system-tray", "window-close", "window-create"] }
+sdk = { path = "../../../packages/sdk", version = "0.1" }
+open = "3.0"
+base64 = "0.21"
+directories = "4.0"
+futures = "0.3"
+dashmap = "5.4.0"
+keyring = "2.0.2"
+data-encoding = "2.3.3"
+ring = "0.16.20"
+whoami = "1.4.0"
+
+[features]
+# by default Tauri runs in production mode
+# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
+default = [ "custom-protocol" ]
+# this feature is used used for production builds where `devPath` points to the filesystem
+# DO NOT remove this
+custom-protocol = [ "tauri/custom-protocol" ]
diff --git a/src-tauri/build.rs b/src-tauri/build.rs
new file mode 100644
index 0000000..795b9b7
--- /dev/null
+++ b/src-tauri/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+ tauri_build::build()
+}
diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png
new file mode 100644
index 0000000..beffffa
Binary files /dev/null and b/src-tauri/icons/128x128.png differ
diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png
new file mode 100644
index 0000000..c664975
Binary files /dev/null and b/src-tauri/icons/128x128@2x.png differ
diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png
new file mode 100644
index 0000000..b7dcb5c
Binary files /dev/null and b/src-tauri/icons/32x32.png differ
diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png
new file mode 100644
index 0000000..1cd82bb
Binary files /dev/null and b/src-tauri/icons/Square107x107Logo.png differ
diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png
new file mode 100644
index 0000000..3b16c27
Binary files /dev/null and b/src-tauri/icons/Square142x142Logo.png differ
diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png
new file mode 100644
index 0000000..f18883b
Binary files /dev/null and b/src-tauri/icons/Square150x150Logo.png differ
diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png
new file mode 100644
index 0000000..458e03e
Binary files /dev/null and b/src-tauri/icons/Square284x284Logo.png differ
diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png
new file mode 100644
index 0000000..817a574
Binary files /dev/null and b/src-tauri/icons/Square30x30Logo.png differ
diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png
new file mode 100644
index 0000000..c96d973
Binary files /dev/null and b/src-tauri/icons/Square310x310Logo.png differ
diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png
new file mode 100644
index 0000000..42ea5cd
Binary files /dev/null and b/src-tauri/icons/Square44x44Logo.png differ
diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png
new file mode 100644
index 0000000..f434d85
Binary files /dev/null and b/src-tauri/icons/Square71x71Logo.png differ
diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png
new file mode 100644
index 0000000..e7ef1c9
Binary files /dev/null and b/src-tauri/icons/Square89x89Logo.png differ
diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png
new file mode 100644
index 0000000..2d82509
Binary files /dev/null and b/src-tauri/icons/StoreLogo.png differ
diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns
new file mode 100644
index 0000000..7f497bb
Binary files /dev/null and b/src-tauri/icons/icon.icns differ
diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico
new file mode 100644
index 0000000..7a66ec8
Binary files /dev/null and b/src-tauri/icons/icon.ico differ
diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png
new file mode 100644
index 0000000..3b87008
Binary files /dev/null and b/src-tauri/icons/icon.png differ
diff --git a/src-tauri/isolation-dist/index.html b/src-tauri/isolation-dist/index.html
new file mode 100644
index 0000000..94b6654
--- /dev/null
+++ b/src-tauri/isolation-dist/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Isolation Secure Script
+
+
+
+
+
diff --git a/src-tauri/isolation-dist/index.js b/src-tauri/isolation-dist/index.js
new file mode 100644
index 0000000..1eb85f2
--- /dev/null
+++ b/src-tauri/isolation-dist/index.js
@@ -0,0 +1,3 @@
+window.__TAURI_ISOLATION_HOOK__ = (payload) => {
+ return payload;
+};
diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs
new file mode 100644
index 0000000..3c2ce29
--- /dev/null
+++ b/src-tauri/src/commands.rs
@@ -0,0 +1,115 @@
+use sdk::{
+ detect::{self, Config},
+ session::FullLoginOptions,
+ types::{MailBox, Message, Preview},
+};
+
+use crate::{identifier::Identifier, keyring, parse::to_json, sessions::Sessions, types::Result};
+
+use tauri::State;
+
+#[tauri::command(async)]
+pub async fn detect_config(email_address: String) -> Result {
+ Ok(detect::from_email(&email_address).await?)
+}
+
+#[tauri::command(async)]
+pub async fn login(
+ credentials: FullLoginOptions,
+ session_handler: State<'_, Sessions>,
+) -> Result {
+ // Connect and login to the mail servers using the user provided credentials.
+ let mail_sessions = sdk::session::create_sessions(&credentials).await?;
+
+ let mut identifier = Identifier::from(&credentials);
+
+ identifier.hash()?;
+
+ let identifier: String = identifier.into();
+
+ let credentials_json = to_json(&credentials)?;
+
+ keyring::set(&identifier, credentials_json)?;
+
+ session_handler.insert_session(&identifier, mail_sessions)?;
+
+ // Return the key and nonce to the frontend so it can verify its session later.
+ Ok(identifier)
+}
+
+#[tauri::command(async)]
+/// Gets a list of all of the mail boxes in the currently logged in account.
+pub async fn list(token: String, sessions: State<'_, Sessions>) -> Result> {
+ let session = sessions.get_incoming_session(&token).await?;
+
+ let mut session_lock = session.lock().await;
+
+ let list = session_lock
+ .box_list()
+ .await
+ .map(|box_list| box_list.clone())?;
+
+ Ok(list)
+}
+
+#[tauri::command(async)]
+/// Gets a mailbox by its box id.
+pub async fn get(token: String, box_id: String, sessions: State<'_, Sessions>) -> Result {
+ let session = sessions.get_incoming_session(&token).await?;
+
+ let mut session_lock = session.lock().await;
+
+ let mailbox = session_lock
+ .get(&box_id)
+ .await
+ .map(|mailbox| mailbox.clone())?;
+
+ Ok(mailbox)
+}
+
+#[tauri::command(async)]
+/// Gets a list of 'previews' from a mailbox. This preview contains some basic data about a message such as the subject and the sender.
+pub async fn messages(
+ token: String,
+ box_id: String,
+ start: u32,
+ end: u32,
+ sessions: State<'_, Sessions>,
+) -> Result> {
+ let session = sessions.get_incoming_session(&token).await?;
+
+ let mut session_lock = session.lock().await;
+
+ let message_list = session_lock.messages(&box_id, start, end).await?;
+
+ Ok(message_list)
+}
+
+#[tauri::command(async)]
+/// Gets the full message data from a given mailbox and a given message id.
+pub async fn get_message(
+ token: String,
+ box_id: String,
+ message_id: String,
+ sessions: State<'_, Sessions>,
+) -> Result {
+ let session = sessions.get_incoming_session(&token).await?;
+
+ let mut session_lock = session.lock().await;
+
+ let message = session_lock.get_message(&box_id, &message_id).await?;
+
+ Ok(message)
+}
+
+#[tauri::command(async)]
+/// Log out of the currently logged in account.
+pub async fn logout(identifier: String, sessions: State<'_, Sessions>) -> Result<()> {
+ let session = sessions.get_incoming_session(&identifier).await?;
+
+ let mut session_lock = session.lock().await;
+
+ session_lock.logout().await?;
+
+ Ok(())
+}
diff --git a/src-tauri/src/hash.rs b/src-tauri/src/hash.rs
new file mode 100644
index 0000000..e955603
--- /dev/null
+++ b/src-tauri/src/hash.rs
@@ -0,0 +1,31 @@
+use std::io::Read;
+
+use crate::types::Result;
+
+use data_encoding::HEXUPPER;
+use ring::digest::{Context, Digest, SHA256};
+
+fn sha256_digest(mut reader: R) -> Result {
+ let mut context = Context::new(&SHA256);
+ let mut buffer = [0; 1024];
+
+ loop {
+ let count = reader.read(&mut buffer)?;
+
+ if count == 0 {
+ break;
+ }
+
+ context.update(&buffer[..count]);
+ }
+
+ Ok(context.finish())
+}
+
+pub fn sha256_hex(reader: R) -> Result {
+ let digest = sha256_digest(reader)?;
+
+ let hex = HEXUPPER.encode(digest.as_ref());
+
+ Ok(hex)
+}
diff --git a/src-tauri/src/identifier.rs b/src-tauri/src/identifier.rs
new file mode 100644
index 0000000..7c1081c
--- /dev/null
+++ b/src-tauri/src/identifier.rs
@@ -0,0 +1,47 @@
+use sdk::session::{FullLoginOptions, LoginType};
+
+use crate::{hash::sha256_hex, types::Result};
+
+pub struct Identifier {
+ id: String,
+}
+
+impl Identifier {
+ /// Hash the currently stored identifier
+ pub fn hash(&mut self) -> Result<()> {
+ self.id = sha256_hex(self.id.as_bytes())?;
+
+ Ok(())
+ }
+}
+
+impl Into for Identifier {
+ fn into(self) -> String {
+ self.id
+ }
+}
+
+impl From<&FullLoginOptions> for Identifier {
+ fn from(login_options: &FullLoginOptions) -> Self {
+ // TODO: Outgoing support
+ let incoming = login_options.incoming_options();
+
+ let (username, password) = match incoming.login_type() {
+ LoginType::PasswordBased(creds) => (creds.username(), creds.password()),
+ LoginType::OAuthBased(creds) => (creds.username(), creds.access_token()),
+ };
+
+ // A string that is unique to these login options.
+ let credentials_string = format!(
+ "{}:{}@{}:{}",
+ username,
+ password,
+ incoming.domain(),
+ incoming.port()
+ );
+
+ Self {
+ id: credentials_string,
+ }
+ }
+}
diff --git a/src-tauri/src/keyring.rs b/src-tauri/src/keyring.rs
new file mode 100644
index 0000000..379a127
--- /dev/null
+++ b/src-tauri/src/keyring.rs
@@ -0,0 +1,31 @@
+use crate::types::Result;
+
+use keyring::Entry;
+
+const APPLICATION_NAME: &str = "Dust-Mail";
+
+fn build_entry_from_identifier>(identifier: T) -> Result {
+ let username = whoami::username();
+
+ let name = format!("{}:{}", APPLICATION_NAME, identifier.as_ref());
+
+ let entry = Entry::new(&name, &username)?;
+
+ Ok(entry)
+}
+
+pub fn get>(identifier: T) -> Result {
+ let entry = build_entry_from_identifier(identifier)?;
+
+ let password = entry.get_password()?;
+
+ Ok(password)
+}
+
+pub fn set, S: AsRef>(identifier: T, value: S) -> Result<()> {
+ let entry = build_entry_from_identifier(identifier)?;
+
+ entry.set_password(value.as_ref())?;
+
+ Ok(())
+}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
new file mode 100644
index 0000000..2f23df7
--- /dev/null
+++ b/src-tauri/src/main.rs
@@ -0,0 +1,91 @@
+#![cfg_attr(
+ all(not(debug_assertions), target_os = "windows"),
+ windows_subsystem = "windows"
+)]
+
+mod commands;
+mod hash;
+mod keyring;
+mod sessions;
+
+mod identifier;
+mod menu;
+mod parse;
+mod tray;
+mod types;
+
+use sessions::Sessions;
+use tauri::{Manager, SystemTrayEvent};
+
+#[derive(Clone, serde::Serialize)]
+struct Payload {
+ message: String,
+}
+
+fn main() {
+ let github_page = "https://github.com/Guusvanmeerveld/Dust-Mail";
+
+ let menu = menu::create_menu();
+ let tray = tray::create_tray();
+
+ tauri::Builder::default()
+ .menu(menu)
+ .system_tray(tray)
+ .manage(Sessions::new())
+ .on_menu_event(move |event| match event.menu_item_id() {
+ "repository" => {
+ open::that(github_page).unwrap();
+ }
+ "donate" => {
+ open::that("https://ko-fi.com/Guusvanmeerveld").unwrap();
+ }
+ "report_issue" => {
+ open::that([github_page, "issues"].join("/")).unwrap();
+ }
+ "license" => {
+ open::that([github_page, "blob/main/LICENSE"].join("/")).unwrap();
+ }
+ "about" => {
+ event
+ .window()
+ .emit(
+ "show_about",
+ Payload {
+ message: "Show about".into(),
+ },
+ )
+ .unwrap();
+ }
+ _ => {}
+ })
+ .on_system_tray_event(|app, event| match event {
+ SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
+ "hide" => {
+ let window = app.get_window("main").unwrap();
+
+ window.hide().unwrap();
+ }
+ "show" => {
+ let window = app.get_window("main").unwrap();
+
+ window.show().unwrap();
+ }
+ "quit" => {
+ std::process::exit(0);
+ }
+ _ => {}
+ },
+ _ => {}
+ })
+ .invoke_handler(tauri::generate_handler![
+ commands::detect_config,
+ commands::login,
+ commands::logout,
+ commands::get,
+ commands::messages,
+ commands::get_message,
+ commands::list
+ ])
+ .run(tauri::generate_context!())
+ .expect("error while running tauri application");
+}
diff --git a/src-tauri/src/menu.rs b/src-tauri/src/menu.rs
new file mode 100644
index 0000000..47b0662
--- /dev/null
+++ b/src-tauri/src/menu.rs
@@ -0,0 +1,25 @@
+use tauri::{CustomMenuItem, Menu, MenuItem, Submenu};
+
+pub fn create_menu() -> Menu {
+ // Help menu
+ let repository = CustomMenuItem::new("repository", "Repository");
+ let donate = CustomMenuItem::new("donate", "Donate");
+ let report_issue = CustomMenuItem::new("report_issue", "Report Issue");
+ let license = CustomMenuItem::new("license", "License");
+ let about = CustomMenuItem::new("about", "About");
+
+ let help_submenu = Submenu::new(
+ "Help",
+ Menu::new()
+ // .add_item(MenuItem::About((), ()))
+ .add_item(repository)
+ .add_native_item(MenuItem::Separator)
+ .add_item(donate)
+ .add_item(report_issue)
+ .add_item(license)
+ .add_native_item(MenuItem::Separator)
+ .add_item(about),
+ );
+
+ Menu::os_default("Dust-Mail").add_submenu(help_submenu)
+}
diff --git a/src-tauri/src/parse.rs b/src-tauri/src/parse.rs
new file mode 100644
index 0000000..8eb4d7c
--- /dev/null
+++ b/src-tauri/src/parse.rs
@@ -0,0 +1,11 @@
+use serde::Serialize;
+
+use serde_json;
+
+use crate::types::Result;
+
+pub fn to_json(data: &T) -> Result {
+ let serialized = serde_json::to_string(data)?;
+
+ Ok(serialized)
+}
diff --git a/src-tauri/src/sessions.rs b/src-tauri/src/sessions.rs
new file mode 100644
index 0000000..5371d8a
--- /dev/null
+++ b/src-tauri/src/sessions.rs
@@ -0,0 +1,64 @@
+use dashmap::DashMap;
+use serde_json::from_str;
+
+use std::sync::Arc;
+
+use sdk::session::{MailSessions, ThreadSafeIncomingSession};
+
+use crate::{keyring, types::Result};
+
+pub struct Sessions {
+ sessions_map: DashMap>,
+}
+
+impl Sessions {
+ pub fn new() -> Self {
+ Self {
+ sessions_map: DashMap::new(),
+ }
+ }
+
+ pub fn insert_session>(
+ &self,
+ identifier: S,
+ sessions: MailSessions,
+ ) -> Result<()> {
+ let identifier = identifier.into();
+
+ self.sessions_map.insert(identifier, Arc::new(sessions));
+
+ Ok(())
+ }
+
+ pub async fn get_incoming_session>(
+ &self,
+ identifier: S,
+ ) -> Result {
+ let mail_sessions = self.get_session(identifier.as_ref()).await?;
+
+ Ok(mail_sessions.incoming().clone())
+ }
+
+ pub async fn get_session>(&self, identifier: S) -> Result> {
+ let identifier = identifier.into();
+
+ match self.sessions_map.get(&identifier) {
+ Some(sessions) => Ok(sessions.clone()),
+ None => {
+ // If we don't have a session stored, we try to get it from the credentials stored in the keyring.
+ let credentials_json = keyring::get(&identifier)?;
+
+ let credentials = from_str(&credentials_json)?;
+
+ let mail_sessions = sdk::session::create_sessions(&credentials).await?;
+
+ self.insert_session(identifier.clone(), mail_sessions)?;
+
+ match self.sessions_map.get(&identifier) {
+ Some(sessions) => Ok(sessions.clone()),
+ None => unreachable!(),
+ }
+ }
+ }
+ }
+}
diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs
new file mode 100644
index 0000000..5eb8255
--- /dev/null
+++ b/src-tauri/src/tray.rs
@@ -0,0 +1,15 @@
+use tauri::{CustomMenuItem, SystemTray, SystemTrayMenu, SystemTrayMenuItem};
+
+pub fn create_tray() -> SystemTray {
+ let show = CustomMenuItem::new("show", "Show");
+ let hide = CustomMenuItem::new("hide", "Hide");
+ let quit = CustomMenuItem::new("quit", "Quit");
+
+ let tray_menu = SystemTrayMenu::new()
+ .add_item(show)
+ .add_item(hide)
+ .add_native_item(SystemTrayMenuItem::Separator)
+ .add_item(quit);
+
+ SystemTray::new().with_menu(tray_menu)
+}
diff --git a/src-tauri/src/types/mod.rs b/src-tauri/src/types/mod.rs
new file mode 100644
index 0000000..211a47b
--- /dev/null
+++ b/src-tauri/src/types/mod.rs
@@ -0,0 +1,109 @@
+use std::{
+ error::{self, Error as StdError},
+ fmt,
+ io::Error as IoError,
+ result,
+};
+
+// pub use credentials::Credentials;
+
+use keyring::Error as KeyringError;
+use sdk::types::Error as SdkError;
+use serde_json::Error as JsonError;
+
+use serde::{ser::SerializeStruct, Serialize};
+
+#[derive(Debug)]
+pub struct Error {
+ message: String,
+ kind: ErrorKind,
+}
+
+impl Error {
+ pub fn new>(kind: ErrorKind, msg: S) -> Self {
+ Self {
+ message: msg.into(),
+ kind,
+ }
+ }
+
+ pub fn kind(&self) -> &ErrorKind {
+ &self.kind
+ }
+}
+
+impl From for Error {
+ fn from(sdk_error: SdkError) -> Self {
+ Error::new(
+ ErrorKind::Mail(sdk_error),
+ "Error with upstream mail server",
+ )
+ }
+}
+
+impl From for Error {
+ fn from(keyring_error: KeyringError) -> Self {
+ Error::new(ErrorKind::Keyring(keyring_error), "Error with keyring")
+ }
+}
+
+impl From for Error {
+ fn from(json_error: JsonError) -> Self {
+ Error::new(
+ ErrorKind::Json(json_error),
+ "Failed to serialize/deserialize json data",
+ )
+ }
+}
+
+impl From for Error {
+ fn from(io_error: IoError) -> Self {
+ Error::new(ErrorKind::Io(io_error), "IO error")
+ }
+}
+
+impl Serialize for Error {
+ fn serialize(&self, serializer: S) -> result::Result
+ where
+ S: serde::Serializer,
+ {
+ let source = self.source().unwrap_or(&self);
+ let mut state = serializer.serialize_struct("Error", 2)?;
+
+ state.serialize_field("message", &source.to_string())?;
+ state.serialize_field("kind", "MailError")?;
+ state.end()
+ }
+}
+
+impl StdError for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match self.kind() {
+ ErrorKind::Io(e) => e.source(),
+ ErrorKind::Json(e) => e.source(),
+ ErrorKind::Keyring(e) => e.source(),
+ ErrorKind::Mail(e) => e.source(),
+ _ => None,
+ }
+ }
+
+ fn description(&self) -> &str {
+ &self.message
+ }
+}
+
+#[derive(Debug)]
+pub enum ErrorKind {
+ Mail(SdkError),
+ Io(IoError),
+ Keyring(KeyringError),
+ Json(JsonError),
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.message)
+ }
+}
+
+pub type Result = result::Result;
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
new file mode 100644
index 0000000..09a9d35
--- /dev/null
+++ b/src-tauri/tauri.conf.json
@@ -0,0 +1,85 @@
+{
+ "$schema": "../node_modules/@tauri-apps/cli/schema.json",
+ "build": {
+ "beforeBuildCommand": "cd ../../ && turbo run build --filter @dust-mail/web",
+ "beforeDevCommand": "pnpm dev",
+ "devPath": "http://localhost:5173/",
+ "distDir": "../dist",
+ "withGlobalTauri": true
+ },
+ "package": {
+ "productName": "Dust-Mail",
+ "version": "../package.json"
+ },
+ "tauri": {
+ "pattern": {
+ "use": "isolation",
+ "options": {
+ "dir": "isolation-dist"
+ }
+ },
+ "allowlist": {
+ "all": false,
+ "window": {
+ "close": true,
+ "create": true
+ },
+ "shell": {
+ "open": true
+ }
+ },
+ "systemTray": {
+ "iconPath": "icons/icon.png",
+ "iconAsTemplate": true
+ },
+ "bundle": {
+ "active": true,
+ "category": "Productivity",
+ "copyright": "Guus van Meerveld",
+ "deb": {
+ "depends": []
+ },
+ "externalBin": [],
+ "icon": [
+ "icons/32x32.png",
+ "icons/128x128.png",
+ "icons/128x128@2x.png",
+ "icons/icon.icns",
+ "icons/icon.ico"
+ ],
+ "identifier": "dust.guusvanmeerveld.dev",
+ "longDescription": "An opensource mail client supporting multiple platforms.",
+ "macOS": {
+ "entitlements": null,
+ "exceptionDomain": "",
+ "frameworks": [],
+ "providerShortName": null,
+ "signingIdentity": null
+ },
+ "resources": [],
+ "shortDescription": "A simple and fast mail client",
+ "targets": "all",
+ "windows": {
+ "certificateThumbprint": null,
+ "digestAlgorithm": "sha256",
+ "timestampUrl": ""
+ }
+ },
+ "security": {},
+ "updater": {
+ "active": false,
+ "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEM3OTY1OTUxNjk3ODMxRApSV1FkZzVjV2xXVjVETmsyblI4b1p0eDVrRHRPUlkvb3d1VjZKMnFYME1nUXdyNVpiNlNwR09KVQo="
+ },
+ "windows": [
+ {
+ "maximized": true,
+ "minHeight": 300,
+ "minWidth": 300,
+ "focus": false,
+ "resizable": true,
+ "label": "main",
+ "title": "Dust-Mail"
+ }
+ ]
+ }
+}
diff --git a/src/components/About.tsx b/src/components/About.tsx
new file mode 100644
index 0000000..cb45228
--- /dev/null
+++ b/src/components/About.tsx
@@ -0,0 +1,115 @@
+import { listen } from "@tauri-apps/api/event";
+
+import {
+ author,
+ contributors,
+ description,
+ repository,
+ homepage
+} from "../../package.json";
+
+import { FC } from "react";
+import { useEffect } from "react";
+
+import Box from "@mui/material/Box";
+import IconButton from "@mui/material/IconButton";
+import List from "@mui/material/List";
+import ListItem from "@mui/material/ListItem";
+import ListItemIcon from "@mui/material/ListItemIcon";
+import ListItemText from "@mui/material/ListItemText";
+import ListSubheader from "@mui/material/ListSubheader";
+import Modal from "@mui/material/Modal";
+import Stack from "@mui/material/Stack";
+import Tooltip from "@mui/material/Tooltip";
+import Typography from "@mui/material/Typography";
+
+import CodeIcon from "@mui/icons-material/Code";
+import EmailIcon from "@mui/icons-material/Email";
+import PersonIcon from "@mui/icons-material/Person";
+import GlobeIcon from "@mui/icons-material/Public";
+
+import modalStyles from "@styles/modal";
+
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+
+const Contributor: FC<{
+ name: string;
+ url: string;
+ email: string;
+}> = ({ name, url, email }) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+const About: FC = () => {
+ const theme = useTheme();
+
+ const isOpen = useStore((state) => state.showAbout);
+ const setOpen = useStore((state) => state.setShowAbout);
+
+ useEffect(() => {
+ if ("__TAURI_METADATA__" in window) {
+ const unlisten = listen("show_about", () => setOpen(true));
+
+ return () => {
+ unlisten.then((unlisten) => unlisten());
+ };
+ }
+ }, []);
+
+ return (
+ setOpen(false)}>
+
+
+
+
+ About {import.meta.env.VITE_APP_NAME}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {description}
+
+
+ List of contributors}>
+ {[author, ...contributors].map((contributor) => (
+
+ ))}
+
+
+
+ );
+};
+
+export default About;
diff --git a/src/components/Boxes/Add.tsx b/src/components/Boxes/Add.tsx
new file mode 100644
index 0000000..d8c6f76
--- /dev/null
+++ b/src/components/Boxes/Add.tsx
@@ -0,0 +1,321 @@
+import create from "zustand";
+
+import { FC, memo, useEffect, useMemo, useState } from "react";
+
+import Alert from "@mui/material/Alert";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import FormControl from "@mui/material/FormControl";
+import InputLabel from "@mui/material/InputLabel";
+import MenuItem from "@mui/material/MenuItem";
+import Modal from "@mui/material/Modal";
+import Select from "@mui/material/Select";
+import Stack from "@mui/material/Stack";
+import TextField from "@mui/material/TextField";
+import Typography from "@mui/material/Typography";
+
+import SelectAllIcon from "@mui/icons-material/CheckBox";
+import DeselectAllIcon from "@mui/icons-material/CheckBoxOutlineBlank";
+
+import MailBox from "@interfaces/box";
+
+import modalStyles from "@styles/modal";
+import scrollbarStyles from "@styles/scrollbar";
+
+import useBoxes from "@utils/hooks/useBoxes";
+import useSnackbar from "@utils/hooks/useSnackbar";
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+import useUser from "@utils/hooks/useUser";
+
+import FolderTree, {
+ CheckedBoxesContext,
+ CheckedBoxesStore
+} from "@components/Boxes/FolderTree";
+
+export const checkedBoxesStore = create((set) => ({
+ checkedBoxes: {},
+ setChecked: (id, checked) =>
+ set((state) => ({ checkedBoxes: { ...state.checkedBoxes, [id]: checked } }))
+}));
+
+export type FolderType = "unified" | "normal" | "none";
+
+interface AddBoxStore {
+ folderType: FolderType;
+ setFolderType: (folderType: FolderType) => void;
+ parentFolder: MailBox | undefined;
+ setParentFolder: (parentFolder: MailBox | undefined) => void;
+ folderName: string;
+ setFolderName: (folderName: string) => void;
+}
+
+export const addBoxStore = create((set) => ({
+ folderType: "none",
+ setFolderType: (folderType) => set(() => ({ folderType })),
+ parentFolder: undefined,
+ setParentFolder: (parentFolder) => set(() => ({ parentFolder })),
+ folderName: "",
+ setFolderName: (folderName) => set(() => ({ folderName }))
+}));
+
+const UnMemoizedAddBox: FC = () => {
+ const theme = useTheme();
+
+ const user = useUser();
+ // const addBox = useAddBox();
+
+ const showSnackbar = useSnackbar();
+
+ const setShowAddBox = useStore((state) => state.setShowAddBox);
+ const showAddBox = useStore((state) => state.showAddBox);
+
+ const setFetching = useStore((state) => state.setFetching);
+
+ const unifiedBoxes = checkedBoxesStore((state) => state.checkedBoxes);
+
+ const { boxes, error: boxesError, findBox } = useBoxes();
+
+ const [error, setError] = useState();
+
+ const checkedBoxes = useMemo(
+ () =>
+ Object.entries(unifiedBoxes)
+ .filter(([, checked]) => checked)
+ .map(([id]) => id),
+ [unifiedBoxes]
+ );
+
+ const folderType = addBoxStore((state) => state.folderType);
+ const setFolderType = addBoxStore((state) => state.setFolderType);
+
+ const parentFolder = addBoxStore((state) => state.parentFolder);
+ const setParentFolder = addBoxStore((state) => state.setParentFolder);
+
+ const folderName = addBoxStore((state) => state.folderName);
+ const setFolderName = addBoxStore((state) => state.setFolderName);
+
+ const handleClose = (): void => setShowAddBox(false);
+
+ useEffect(
+ () => setError(undefined),
+ [folderType, parentFolder, folderName, showAddBox]
+ );
+
+ useEffect(() => {
+ if (boxesError) setError(boxesError);
+ }, [boxesError]);
+
+ useEffect(() => {
+ if (!showAddBox) {
+ setFolderType("none");
+ setParentFolder(undefined);
+ setFolderName("");
+ }
+ }, [showAddBox]);
+
+ const [modalSx, scrollbarSx] = useMemo(
+ () => [modalStyles(theme), scrollbarStyles(theme)],
+ [theme]
+ );
+
+ const checkAllBoxes = (checked: boolean): void => {
+ if (!user) return;
+ };
+
+ const createBox = async (box: MailBox): Promise => {
+ // addBox(box);
+
+ // if (!box.unifies) {
+ setFetching(true);
+
+ // await fetcher
+ // .createBox(box.id)
+ // .then(() => {
+ // showSnackbar(`Folder '${box.name}' created`);
+ // setShowAddBox(false);
+ // })
+ // .catch((error: AxiosError<{ message: string }>) => {
+ // const message = error.response?.data.message;
+
+ // if (message) setError(message);
+ // });
+
+ setFetching(false);
+ // }
+ };
+
+ return (
+ <>
+
+
+ <>
+
+ Create a new folder
+
+
+
+ Folder type
+
+
+
+ {folderType != "none" && (
+ setFolderName(e.target.value)}
+ label="Folder name"
+ />
+ )}
+
+ {folderType != "none" && (
+
+ Parent folder
+
+
+ )}
+
+ {folderType == "unified" && boxes && (
+ <>
+
+
+ Select the folders you want to be unified
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+
+ {error && {error}}
+ >
+
+
+ >
+ );
+};
+
+const AddBox = memo(UnMemoizedAddBox);
+
+export default AddBox;
diff --git a/src/components/Boxes/Delete.tsx b/src/components/Boxes/Delete.tsx
new file mode 100644
index 0000000..1c35389
--- /dev/null
+++ b/src/components/Boxes/Delete.tsx
@@ -0,0 +1,98 @@
+import create from "zustand";
+
+import { FC, memo, useState } from "react";
+
+import Alert from "@mui/material/Alert";
+import Button from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import DialogActions from "@mui/material/DialogActions";
+import DialogContent from "@mui/material/DialogContent";
+import DialogContentText from "@mui/material/DialogContentText";
+import DialogTitle from "@mui/material/DialogTitle";
+
+import useSnackbar from "@utils/hooks/useSnackbar";
+import useStore from "@utils/hooks/useStore";
+
+interface DeleteBoxStore {
+ boxesToDelete: string[];
+ setBoxesToDelete: (boxesToDelete: string[]) => void;
+}
+
+export const deleteBoxStore = create((set) => ({
+ boxesToDelete: [],
+ setBoxesToDelete: (boxesToDelete) => set({ boxesToDelete })
+}));
+
+const UnMemoizedDeleteBox: FC = () => {
+ const openSnackbar = useSnackbar();
+
+ const showDeleteItemsDialog = useStore(
+ (state) => state.showDeleteItemsDialog
+ );
+ const setShowDeleteItemsDialog = useStore(
+ (state) => state.setShowDeleteItemsDialog
+ );
+
+ const setFetching = useStore((state) => state.setFetching);
+
+ const boxesToDelete = deleteBoxStore((state) => state.boxesToDelete);
+ const setBoxesToDelete = deleteBoxStore((state) => state.setBoxesToDelete);
+
+ const [error, setError] = useState();
+
+ const deleteItemsDialogOnClose = (): void => {
+ setShowDeleteItemsDialog(false);
+ setError(undefined);
+ setBoxesToDelete([]);
+ };
+
+ const deleteSelectedItems = async (): Promise => {
+ setFetching(true);
+
+ // await fetcher
+ // .deleteBox(boxesToDelete)
+ // .then(() => {
+ // openSnackbar(`Folder(s) '${boxesToDelete.join("', '")}' deleted`);
+
+ // deleteItemsDialogOnClose();
+ // setBoxesToDelete([]);
+ // })
+ // .catch((error: AxiosError) => {
+ // const errorMessage = error.response?.data.message;
+
+ // if (errorMessage) setError(errorMessage);
+ // });
+
+ setFetching(false);
+ };
+
+ return (
+
+ );
+};
+
+const DeleteBox = memo(UnMemoizedDeleteBox);
+
+export default DeleteBox;
diff --git a/src/components/Boxes/FolderTree.tsx b/src/components/Boxes/FolderTree.tsx
new file mode 100644
index 0000000..853daf7
--- /dev/null
+++ b/src/components/Boxes/FolderTree.tsx
@@ -0,0 +1,211 @@
+import { StoreApi, UseBoundStore, useStore } from "zustand";
+
+import {
+ FC,
+ memo,
+ useMemo,
+ useState,
+ createContext,
+ useContext,
+ MouseEvent
+} from "react";
+
+import Badge from "@mui/material/Badge";
+import Box from "@mui/material/Box";
+import Checkbox from "@mui/material/Checkbox";
+import Collapse from "@mui/material/Collapse";
+import IconButton from "@mui/material/IconButton";
+import List from "@mui/material/List";
+import MUIListItem from "@mui/material/ListItem";
+import ListItemButton from "@mui/material/ListItemButton";
+import ListItemIcon from "@mui/material/ListItemIcon";
+import ListItemText from "@mui/material/ListItemText";
+import ListSubheader from "@mui/material/ListSubheader";
+import Typography from "@mui/material/Typography";
+
+import ExpandLessIcon from "@mui/icons-material/ExpandLess";
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import FolderIcon from "@mui/icons-material/Folder";
+
+import MailBox from "@interfaces/box";
+
+import useSelectedBox from "@utils/hooks/useSelectedBox";
+import useTheme from "@utils/hooks/useTheme";
+
+export interface CheckedBoxesStore {
+ checkedBoxes: Record;
+ setChecked: (id: string, checked: boolean) => void;
+}
+
+export const CheckedBoxesContext = createContext
+> | null>(null);
+
+export interface FolderTreeProps {
+ onClick?: (box: MailBox, e: MouseEvent) => void;
+ onContextMenu?: (box: MailBox, e: MouseEvent) => void;
+ showCheckBox: boolean;
+}
+
+const UnMemoizedFolderTree: FC<
+ {
+ boxes: MailBox[];
+ title?: string;
+ } & FolderTreeProps
+> = ({ boxes, title, ...props }) => {
+ const { box: selectedBox } = useSelectedBox();
+
+ return (
+
+ );
+};
+
+const FolderTree = memo(UnMemoizedFolderTree);
+
+const UnMemoizedListItem: FC<
+ {
+ box: MailBox;
+ isSelectedBox: boolean;
+ } & FolderTreeProps
+> = ({ box, isSelectedBox, showCheckBox, onClick, onContextMenu }) => {
+ const store = useContext(CheckedBoxesContext);
+
+ if (!store) throw new Error("No context provided");
+
+ const checked =
+ useStore(store, (state) => state.checkedBoxes[box.id]) ?? false;
+ const setChecked = useStore(store, (state) => state.setChecked);
+
+ const [isOpen, setOpen] = useState(true);
+
+ const theme = useTheme();
+
+ const indent = useMemo(
+ () =>
+ theme.spacing(
+ (showCheckBox ? 0 : 2) + box.id.split(box.delimiter ?? "").length
+ ),
+ [theme.spacing, box.id, showCheckBox]
+ );
+
+ const handleClick = box.selectable
+ ? onClick && !showCheckBox
+ ? (e: MouseEvent) => {
+ onClick(box, e);
+ }
+ : () => setChecked(box.id, !checked)
+ : undefined;
+
+ const handleContextMenu = (e: MouseEvent): void => {
+ if (onContextMenu && !showCheckBox) onContextMenu(box, e);
+ };
+
+ const badge =
+ box.counts && box.counts.unseen != 0 ? box.counts.unseen : undefined;
+
+ return (
+ <>
+ {box.children && box.children.length != 0 && (
+ <>
+
+
+ {showCheckBox && }
+
+
+
+
+
+
+ {box.name}
+
+
+ setOpen((state) => !state)}>
+ {isOpen ? : }
+
+
+
+
+
+ >
+ )}
+ {(!box.children || (box.children && box.children.length == 0)) && (
+
+
+
+ {showCheckBox && }
+
+
+
+
+
+
+ {box.name}
+
+
+
+
+ )}
+ >
+ );
+};
+
+const Icon: FC<{
+ icon?: JSX.Element;
+ badge?: number;
+}> = ({ icon, badge }) => {
+ if (badge && badge != 0)
+ return (
+
+ {icon ?? }
+
+ );
+
+ return icon ?? ;
+};
+
+const ListItem = memo(UnMemoizedListItem);
+
+export default FolderTree;
diff --git a/src/components/Boxes/List.tsx b/src/components/Boxes/List.tsx
new file mode 100644
index 0000000..62266ee
--- /dev/null
+++ b/src/components/Boxes/List.tsx
@@ -0,0 +1,313 @@
+import create from "zustand";
+
+import { useEffect, useMemo, memo, FC, useState, MouseEvent } from "react";
+
+import Divider from "@mui/material/Divider";
+import IconButton from "@mui/material/IconButton";
+import ListItemIcon from "@mui/material/ListItemIcon";
+import ListItemText from "@mui/material/ListItemText";
+import Menu from "@mui/material/Menu";
+import MenuItem from "@mui/material/MenuItem";
+import Stack from "@mui/material/Stack";
+import Tooltip from "@mui/material/Tooltip";
+
+import AddIcon from "@mui/icons-material/Add";
+import CheckBoxIcon from "@mui/icons-material/CheckBoxOutlineBlank";
+import CloseIcon from "@mui/icons-material/Close";
+import DeleteIcon from "@mui/icons-material/Delete";
+import MarkAsReadIcon from "@mui/icons-material/DoneAll";
+import RenameIcon from "@mui/icons-material/TextFields";
+
+import MailBox from "@interfaces/box";
+
+import findBoxInPrimaryBoxesList from "@utils/findBoxInPrimaryBoxesList";
+import useAddBox from "@utils/hooks/useAddBox";
+import useBoxes from "@utils/hooks/useBoxes";
+import useDeleteBox from "@utils/hooks/useDeleteBox";
+import useRenameBox from "@utils/hooks/useRenameBox";
+import useSelectedBox from "@utils/hooks/useSelectedBox";
+import useSnackbar from "@utils/hooks/useSnackbar";
+import useStore from "@utils/hooks/useStore";
+
+import FolderTree, {
+ FolderTreeProps,
+ CheckedBoxesContext,
+ CheckedBoxesStore
+} from "@components/Boxes/FolderTree";
+
+export const checkedBoxesStore = create((set) => ({
+ checkedBoxes: {},
+ setChecked: (id, checked) =>
+ set((state) => ({ checkedBoxes: { ...state.checkedBoxes, [id]: checked } }))
+}));
+
+const UnMemoizedBoxContextMenu: FC<{
+ contextMenuAnchorEl: HTMLElement | null;
+ contextMenuCurrentBox?: MailBox;
+ handleContextMenuClose: () => void;
+}> = ({
+ contextMenuAnchorEl,
+ handleContextMenuClose,
+ contextMenuCurrentBox
+}) => {
+ const showAddBox = useAddBox();
+ const showRenameBox = useRenameBox();
+ const showDeleteBox = useDeleteBox();
+
+ const menuItems = useMemo(
+ () => [
+ {
+ name: "Create sub folder",
+ icon: ,
+ action: () => {
+ handleContextMenuClose();
+
+ if (!contextMenuCurrentBox) return;
+
+ showAddBox({ parentFolder: contextMenuCurrentBox });
+ }
+ },
+ {
+ name: "Rename",
+ icon: ,
+ action: () => {
+ handleContextMenuClose();
+
+ if (!contextMenuCurrentBox) return;
+ showRenameBox(contextMenuCurrentBox);
+ }
+ },
+ {
+ name: "Delete",
+ icon: ,
+ action: () => {
+ handleContextMenuClose();
+
+ if (!contextMenuCurrentBox) return;
+ showDeleteBox([contextMenuCurrentBox.id]);
+ }
+ }
+ ],
+ [showAddBox, showRenameBox, showDeleteBox]
+ );
+
+ return (
+
+ );
+};
+
+const BoxContextMenu = memo(UnMemoizedBoxContextMenu);
+
+const UnMemoizedActionBar: FC<{
+ showSelector: boolean;
+ setShowSelector: (show: boolean) => void;
+}> = ({ showSelector, setShowSelector }) => {
+ const showDeleteBox = useDeleteBox();
+ const setShowAddBox = useStore((state) => state.setShowAddBox);
+
+ const checkedBoxes = checkedBoxesStore((state) => state.checkedBoxes);
+ const setChecked = checkedBoxesStore((state) => state.setChecked);
+
+ const selectedBoxesArray = useMemo(
+ () =>
+ Object.entries(checkedBoxes)
+ .filter(([, checked]) => checked)
+ .map(([id]) => id),
+ [checkedBoxes]
+ );
+
+ const unCheckAllSelectedBoxes = (): void => {
+ selectedBoxesArray.forEach((deleted) => setChecked(deleted, false));
+ };
+
+ useEffect(() => {
+ if (!showSelector) unCheckAllSelectedBoxes();
+ }, [showSelector]);
+
+ return (
+
+ {!showSelector && (
+ <>
+ setShowSelector(true)}>
+
+
+
+
+ setShowAddBox(true)}>
+
+
+
+
+ >
+ )}
+ {showSelector && (
+ <>
+ setShowSelector(false)}>
+
+
+
+
+ {
+ if (selectedBoxesArray.length > 0) {
+ showDeleteBox(selectedBoxesArray);
+ }
+ }}
+ >
+
+
+
+
+ setShowSelector(false)}>
+
+
+
+
+ >
+ )}
+
+ );
+};
+
+const ActionBar = memo(UnMemoizedActionBar);
+
+const UnMemoizedBoxesList: FC<{ clickOnBox?: (e: MouseEvent) => void }> = ({
+ clickOnBox
+}) => {
+ const {
+ box: selectedBox,
+ error: selectedBoxError,
+ setSelectedBox
+ } = useSelectedBox();
+
+ const { boxes, error: boxesError } = useBoxes();
+
+ const [showSelector, setShowSelector] = useState(false);
+
+ const showSnackbar = useSnackbar();
+
+ useEffect(() => {
+ const errorVariant = "error";
+ if (selectedBoxError !== null) showSnackbar(selectedBoxError, errorVariant);
+ else if (boxesError !== null) showSnackbar(boxesError, errorVariant);
+ }, [boxesError, selectedBoxError]);
+
+ const [contextMenuAnchorEl, setContextMenuAnchorEl] =
+ useState(null);
+
+ const [contextMenuCurrentBox, setContextMenuCurrentBox] = useState();
+
+ const handleContextMenuClose = useMemo(
+ () => (): void => {
+ setContextMenuAnchorEl(null);
+ },
+ [setContextMenuAnchorEl]
+ );
+
+ useEffect(() => {
+ if (selectedBox) {
+ const name = selectedBox.name ?? selectedBox.id;
+
+ document.title = `${import.meta.env.VITE_APP_NAME}${
+ name ? ` - ${name}` : ""
+ }`;
+ }
+ }, [selectedBox]);
+
+ const folderTreeProps = useMemo(
+ (): FolderTreeProps => ({
+ showCheckBox: showSelector,
+ onClick: (box, e) => {
+ setSelectedBox(box.id);
+ if (clickOnBox) clickOnBox(e);
+ },
+ onContextMenu: (box: MailBox, e: MouseEvent): void => {
+ e.preventDefault();
+ setContextMenuAnchorEl(e.currentTarget);
+ setContextMenuCurrentBox(box);
+ }
+ }),
+ [showSelector, setSelectedBox]
+ );
+
+ // Find all of the primary boxes and sort them alphabetically
+ const primaryBoxes: MailBox[] | undefined = useMemo(
+ () =>
+ boxes
+ ?.filter((box) => !!findBoxInPrimaryBoxesList(box.id))
+ .map((box) => {
+ const found = findBoxInPrimaryBoxesList(box.id);
+
+ return { ...box, ...found };
+ })
+ .sort((a, b) => a.id.localeCompare(b.id)),
+ [boxes]
+ );
+
+ // Find all of the other boxes and sort them alphabetically
+ const otherBoxes: MailBox[] | undefined = useMemo(
+ () =>
+ boxes
+ ?.filter((box) => !findBoxInPrimaryBoxesList(box.id))
+ .sort((a, b) => a.id.localeCompare(b.id)),
+ [boxes]
+ );
+
+ return (
+ <>
+
+
+
+ {(primaryBoxes || otherBoxes) && }
+ {primaryBoxes && (
+
+ )}
+
+ {primaryBoxes && otherBoxes && otherBoxes.length != 0 && }
+ {otherBoxes && otherBoxes.length != 0 && (
+
+ )}
+
+ >
+ );
+};
+
+const BoxesList = memo(UnMemoizedBoxesList);
+
+export default BoxesList;
diff --git a/src/components/Boxes/Rename.tsx b/src/components/Boxes/Rename.tsx
new file mode 100644
index 0000000..a8df32c
--- /dev/null
+++ b/src/components/Boxes/Rename.tsx
@@ -0,0 +1,122 @@
+import create from "zustand";
+
+import { FC, memo, useState } from "react";
+
+import Alert from "@mui/material/Alert";
+import Button from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import DialogActions from "@mui/material/DialogActions";
+import DialogContent from "@mui/material/DialogContent";
+import DialogTitle from "@mui/material/DialogTitle";
+import TextField from "@mui/material/TextField";
+
+import Box from "@interfaces/box";
+
+import useSnackbar from "@utils/hooks/useSnackbar";
+import useStore from "@utils/hooks/useStore";
+
+interface RenameBoxStore {
+ boxToRename: Box | undefined;
+ setBoxToRename: (boxToRename: Box) => void;
+}
+
+export const renameBoxStore = create((set) => ({
+ boxToRename: undefined,
+ setBoxToRename: (boxToRename: Box) => set({ boxToRename })
+}));
+
+const UnMemoizedRenameBox: FC = () => {
+ const showRenameBoxDialog = useStore((state) => state.showRenameBoxDialog);
+ const setShowRenameBoxDialog = useStore(
+ (state) => state.setShowRenameBoxDialog
+ );
+
+ const setFetching = useStore((state) => state.setFetching);
+
+ const boxToRename = renameBoxStore((state) => state.boxToRename);
+
+ const openSnackbar = useSnackbar();
+
+ const [newName, setNewName] = useState("");
+
+ const [error, setError] = useState();
+
+ const handleClose = (): void => {
+ setShowRenameBoxDialog(false);
+ setNewName("");
+ setError(undefined);
+ };
+
+ const renameBox = async (): Promise => {
+ if (!boxToRename || !newName) return;
+
+ const prefix = boxToRename.delimiter
+ ? boxToRename.id.split(boxToRename.delimiter)
+ : [boxToRename.id];
+
+ prefix.pop();
+
+ prefix.push(newName);
+
+ const newBoxID = boxToRename.delimiter
+ ? prefix.join(boxToRename.delimiter)
+ : prefix[0];
+
+ setFetching(true);
+
+ // await fetcher
+ // .renameBox(boxToRename.id, newBoxID)
+ // .then(() => {
+ // openSnackbar(`Folder '${boxToRename.name}' renamed to '${newName}'`);
+
+ // // const newBox: Box = { ...boxToRename, id: newBoxID, name: newName };
+
+ // // modifyBox(boxToRename.id, newBox);
+
+ // handleClose();
+ // })
+ // .catch((e: AxiosError) => {
+ // const errorMessage = e.response?.data.message;
+
+ // if (errorMessage) setError(errorMessage);
+ // });
+
+ setFetching(false);
+ };
+
+ return (
+
+ );
+};
+
+const RenameBox = memo(UnMemoizedRenameBox);
+
+export default RenameBox;
diff --git a/src/components/Changelog.tsx b/src/components/Changelog.tsx
new file mode 100644
index 0000000..f135bed
--- /dev/null
+++ b/src/components/Changelog.tsx
@@ -0,0 +1,57 @@
+import { FC, memo } from "react";
+import ReactMarkdown from "react-markdown";
+import { useQuery } from "react-query";
+
+import Box from "@mui/material/Box";
+import CircularProgress from "@mui/material/CircularProgress";
+import Modal from "@mui/material/Modal";
+import Typography from "@mui/material/Typography";
+
+import modalStyles from "@styles/modal";
+
+import useApiClient from "@utils/hooks/useApiClient";
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+import { createResultFromUnknown, errorToString } from "@utils/parseError";
+
+const UnMemoizedChangelog: FC = () => {
+ const theme = useTheme();
+
+ const showChangelog = useStore((state) => state.showChangelog);
+ const setShowChangelog = useStore((state) => state.setShowChangelog);
+
+ const apiClient = useApiClient();
+
+ const { data, error, isFetching } = useQuery(
+ ["changelog"],
+ async () => {
+ const result = await apiClient
+ .getChangelog()
+ .catch(createResultFromUnknown);
+
+ if (result.ok) {
+ return result.data;
+ } else {
+ throw errorToString(result.error);
+ }
+ },
+ { enabled: showChangelog }
+ );
+
+ return (
+ setShowChangelog(false)} open={showChangelog}>
+
+ Changelog
+ {error !== null && {error}}
+ {isFetching && }
+ {data && {data}}
+
+
+ );
+};
+
+const Changelog = memo(UnMemoizedChangelog);
+
+export default Changelog;
diff --git a/src/components/DarkModeSwitch.tsx b/src/components/DarkModeSwitch.tsx
new file mode 100644
index 0000000..4bce34d
--- /dev/null
+++ b/src/components/DarkModeSwitch.tsx
@@ -0,0 +1,23 @@
+import useLocalStorageState from "use-local-storage-state";
+
+import { ChangeEvent, FC } from "react";
+
+import Switch from "@mui/material/Switch";
+
+const DarkModeSwitch: FC = () => {
+ const [darkMode, setDarkMode] = useLocalStorageState("darkMode");
+
+ const handleChange = (e: ChangeEvent): void => {
+ setDarkMode(e.currentTarget.checked);
+ };
+
+ return (
+
+ );
+};
+
+export default DarkModeSwitch;
diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
new file mode 100644
index 0000000..306e578
--- /dev/null
+++ b/src/components/Layout.tsx
@@ -0,0 +1,23 @@
+import { FC, ReactNode } from "react";
+
+import About from "@components/About";
+import Changelog from "@components/Changelog";
+import MessageComposer from "@components/Message/Composer";
+import Navbar from "@components/Navbar";
+
+const Layout: FC<{ withNavbar?: boolean; children?: ReactNode }> = ({
+ children,
+ withNavbar
+}) => {
+ return (
+ <>
+
+
+ {withNavbar && }
+
+ {children}
+ >
+ );
+};
+
+export default Layout;
diff --git a/src/components/Login/Form.tsx b/src/components/Login/Form.tsx
new file mode 100644
index 0000000..ee03d49
--- /dev/null
+++ b/src/components/Login/Form.tsx
@@ -0,0 +1,637 @@
+import React, {
+ useEffect,
+ useState,
+ FC,
+ memo,
+ FormEvent,
+ useMemo,
+ FormEventHandler,
+ useCallback
+} from "react";
+
+import {
+ incomingMailServerTypeList,
+ Credentials,
+ outgoingMailServerTypeList,
+ ServerType,
+ MailServerType,
+ ConnectionSecurity,
+ IncomingMailServerType,
+ OutgoingMailServerType
+} from "@dust-mail/structures";
+
+import Alert from "@mui/material/Alert";
+import AlertTitle from "@mui/material/AlertTitle";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import FormControl from "@mui/material/FormControl";
+import Grid from "@mui/material/Grid";
+import IconButton from "@mui/material/IconButton";
+import InputAdornment from "@mui/material/InputAdornment";
+import InputLabel from "@mui/material/InputLabel";
+import MenuItem from "@mui/material/MenuItem";
+import Modal from "@mui/material/Modal";
+import OutlinedInput from "@mui/material/OutlinedInput";
+import Select from "@mui/material/Select";
+import Stack from "@mui/material/Stack";
+import Tab from "@mui/material/Tab";
+import Tabs from "@mui/material/Tabs";
+import TextField from "@mui/material/TextField";
+import Tooltip from "@mui/material/Tooltip";
+import Typography from "@mui/material/Typography";
+
+import VisibilityIcon from "@mui/icons-material/Visibility";
+import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
+
+import modalStyles from "@styles/modal";
+import scrollbarStyles from "@styles/scrollbar";
+
+import { useMailLogin } from "@utils/hooks/useLogin";
+import useMailClient from "@utils/hooks/useMailClient";
+import useMultiServerLoginStore, {
+ defaultConfigs,
+ MultiServerLoginOptions
+} from "@utils/hooks/useMultiServerLoginStore";
+import useOAuth2Client from "@utils/hooks/useOAuth2Client";
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+import parseEmail from "@utils/parseEmail";
+import {
+ createErrorFromUnknown,
+ errorIsOfErrorKind,
+ errorToString
+} from "@utils/parseError";
+
+const CredentialsForm: FC<{
+ setError: (error?: string) => void;
+ identifier: string;
+ password: string;
+ setPassword: (password: string) => void;
+ username: string;
+ setUsername: (username: string) => void;
+}> = ({
+ identifier,
+ setError,
+ setPassword,
+ password,
+ setUsername,
+ username
+}) => {
+ const [showPassword, setShowPassword] = useState(false);
+
+ return (
+ <>
+ {
+ setError(undefined);
+ setUsername(e.currentTarget.value);
+ }}
+ id={"username-" + identifier}
+ value={username}
+ label="Username"
+ variant="outlined"
+ type="email"
+ />
+
+
+ Password
+ {
+ setError(undefined);
+ setPassword(e.currentTarget.value);
+ }}
+ endAdornment={
+
+
+ setShowPassword((state) => !state)}
+ onMouseDown={() => setShowPassword((state) => !state)}
+ edge="end"
+ >
+ {showPassword ? : }
+
+
+
+ }
+ value={password}
+ id={"password-" + identifier}
+ label="Password"
+ type={showPassword ? "text" : "password"}
+ />
+
+ >
+ );
+};
+
+const UnMemoizedServerConfigColumn: FC<{
+ type: ServerType;
+ selectedMailServerType: MailServerType;
+ security: ConnectionSecurity;
+ port: number;
+ server: string;
+ password: string;
+ username: string;
+}> = ({
+ type,
+ selectedMailServerType,
+ port,
+ security,
+ server,
+ username,
+ password
+}) => {
+ const setSetting = useMultiServerLoginStore(
+ (state) => state.setLoginOptionsProperty
+ );
+
+ const setSelectedMailServerType = useMultiServerLoginStore(
+ (state) => state.setSelectedMailServerType
+ );
+
+ const setError = useMultiServerLoginStore((state) => state.setError);
+
+ useEffect(() => setError(undefined), [security, port, server]);
+
+ const mailServerTypeList = useMemo(() => {
+ switch (type) {
+ case "incoming":
+ return incomingMailServerTypeList;
+
+ case "outgoing":
+ return outgoingMailServerTypeList;
+ }
+ }, []);
+
+ return (
+
+
+ {
+ setSelectedMailServerType(type, newValue);
+ }}
+ centered
+ >
+ {mailServerTypeList.map((item) => (
+
+ ))}
+
+
+ setSetting(type, selectedMailServerType)("domain")(
+ e.currentTarget.value
+ )
+ }
+ value={server}
+ label="Server url/ip"
+ variant="outlined"
+ type="text"
+ />
+
+
+ Security
+
+
+
+
+ setSetting(type, selectedMailServerType)("port")(
+ parseInt(e.currentTarget.value)
+ )
+ }
+ value={port}
+ label="Port"
+ helperText={`Default: ${
+ type == "incoming"
+ ? security == "StartTls" || security == "Tls"
+ ? 993
+ : 143
+ : security == "StartTls"
+ ? 587
+ : security == "Tls"
+ ? 465
+ : 25
+ }`}
+ variant="outlined"
+ type="number"
+ />
+
+
+
+
+ );
+};
+
+const ServerConfigColumn = memo(UnMemoizedServerConfigColumn);
+
+const createCredentials = (
+ incomingConfig: MultiServerLoginOptions,
+ incomingType: IncomingMailServerType
+): Credentials => {
+ const {
+ username: incomingUsername,
+ password: incomingPassword,
+ ...incoming
+ } = incomingConfig;
+
+ const options: Credentials = {
+ incoming: {
+ ...incoming,
+ loginType: {
+ passwordBased: {
+ password: incomingPassword,
+ username: incomingUsername
+ }
+ }
+ },
+ incomingType
+ };
+
+ return options;
+};
+
+const LoginOptionsMenu: FC = () => {
+ const theme = useTheme();
+
+ const [modalSx, scrollBarSx] = useMemo(
+ () => [modalStyles(theme), scrollbarStyles(theme)],
+ [theme]
+ );
+
+ const login = useMailLogin();
+
+ const isOpen = useMultiServerLoginStore((state) => state.showMenu);
+ const setOpen = useMultiServerLoginStore((state) => state.setShowMenu);
+
+ const setError = useMultiServerLoginStore((state) => state.setError);
+ const error = useMultiServerLoginStore((state) => state.error);
+
+ const fetching = useStore((state) => state.fetching);
+
+ const selectedMailServerTypes = useMultiServerLoginStore(
+ (state) => state.selectedMailServerType
+ );
+
+ const provider = useMultiServerLoginStore((state) => state.provider);
+
+ const incomingConfig = useMultiServerLoginStore(
+ (state) => state.incoming[selectedMailServerTypes.incoming]
+ );
+ const outgoingConfig = useMultiServerLoginStore(
+ (state) => state.outgoing[selectedMailServerTypes.outgoing]
+ );
+
+ const resetToDefaults = useMultiServerLoginStore(
+ (state) => state.resetToDefaults
+ );
+
+ const onClose = useCallback(() => {
+ resetToDefaults();
+ setOpen(false);
+ }, [resetToDefaults, setOpen]);
+
+ const missingFields = useMemo(() => {
+ return !incomingConfig.username || !incomingConfig.password;
+ }, [incomingConfig.username, incomingConfig.password]);
+
+ const onSubmit: FormEventHandler = async (e): Promise => {
+ e.preventDefault();
+
+ if (missingFields) {
+ setError("Missing required fields");
+
+ return;
+ }
+
+ const credentials = createCredentials(
+ incomingConfig,
+ selectedMailServerTypes.incoming
+ );
+
+ await login(credentials)
+ .then((result) => {
+ if (result.ok) {
+ onClose();
+ } else {
+ const message = errorToString(result.error);
+
+ setError(message);
+ }
+ })
+ .catch(createErrorFromUnknown);
+ };
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+};
+
+const LoginForm: FC<{
+ children: React.ReactNode;
+ trailing?: React.ReactNode;
+}> = ({ children, trailing }) => {
+ const fetching = useStore((state) => state.fetching);
+ const setFetching = useStore((state) => state.setFetching);
+
+ const [username, setUsername] = useState("");
+ const [password, setPassword] = useState("");
+ const [displayName, setDisplayName] = useState("");
+
+ const setLoginOptions = useMultiServerLoginStore(
+ (state) => state.setLoginOptions
+ );
+
+ const setProvider = useMultiServerLoginStore((state) => state.setProvider);
+
+ const setShowLoginOptionsMenu = useMultiServerLoginStore(
+ (state) => state.setShowMenu
+ );
+
+ const setMultiServerLoginError = useMultiServerLoginStore(
+ (state) => state.setError
+ );
+
+ const [error, setError] = useState();
+
+ const mailClient = useMailClient();
+ const oauthClient = useOAuth2Client();
+
+ useEffect(() => setError(undefined), [username, password]);
+
+ useEffect(() => {
+ document.title = `${import.meta.env.VITE_APP_NAME} - Login`;
+ }, []);
+
+ const missingFields = !username || !password;
+
+ /**
+ * Runs when the form should be submitted to the server
+ */
+ const onSubmit = async (e?: FormEvent): Promise => {
+ if (e) e.preventDefault();
+
+ // Reject the form if there any fields empty
+ if (missingFields) {
+ setError("Missing required fields");
+ return;
+ }
+
+ setFetching(true);
+
+ const configResult = await mailClient
+ .detectConfig(username)
+ .catch((error: unknown) => setError(JSON.stringify(error)));
+
+ setFetching(false);
+
+ const emailAddressResult = parseEmail(username);
+
+ if (!emailAddressResult.ok) {
+ setError(errorToString(emailAddressResult.error));
+ return;
+ }
+
+ const mailDomain = `mail.${emailAddressResult.data.domain}`;
+
+ incomingMailServerTypeList.forEach((loginType) =>
+ setLoginOptions("incoming", loginType, {
+ ...defaultConfigs["incoming"][loginType],
+ domain: mailDomain,
+ username,
+ password
+ })
+ );
+
+ outgoingMailServerTypeList.forEach((loginType) =>
+ setLoginOptions("outgoing", loginType, {
+ ...defaultConfigs["outgoing"][loginType],
+ domain: mailDomain,
+ username,
+ password
+ })
+ );
+
+ if (!configResult) return;
+
+ if (!configResult.ok) {
+ if (errorIsOfErrorKind(configResult.error, "ConfigNotFound")) {
+ setMultiServerLoginError(
+ "Could not automagically detect your login servers, please fill the information in manually or try again."
+ );
+
+ setShowLoginOptionsMenu(true);
+ } else {
+ const message = errorToString(configResult.error);
+
+ setError(message);
+ }
+
+ return;
+ }
+
+ const config = configResult.data;
+
+ oauthClient.getGrant(
+ config.displayName,
+ config.oauth2?.oauthUrl ?? "",
+ config.oauth2?.tokenUrl ?? "",
+ config.oauth2?.scopes ?? []
+ );
+
+ if (
+ typeof config.type != "string" &&
+ config.type.multiServer?.incoming &&
+ config.type.multiServer.outgoing
+ ) {
+ const incomingConfigs: (MultiServerLoginOptions & {
+ type: IncomingMailServerType;
+ })[] = config.type.multiServer.incoming.map(
+ ({ authType, ...config }) => ({
+ ...config,
+ loginType: authType,
+ username,
+ password
+ })
+ );
+
+ const outgoingConfigs: (MultiServerLoginOptions & {
+ type: OutgoingMailServerType;
+ })[] = config.type.multiServer.outgoing.map(
+ ({ authType, ...config }) => ({
+ ...config,
+ loginType: authType,
+ username,
+ password
+ })
+ );
+
+ setProvider(config.displayName);
+
+ incomingConfigs.forEach(({ type, ...incomingConfig }) =>
+ setLoginOptions("incoming", type, incomingConfig)
+ );
+
+ outgoingConfigs.forEach(({ type, ...outgoingConfig }) =>
+ setLoginOptions("outgoing", type, outgoingConfig)
+ );
+
+ setShowLoginOptionsMenu(true);
+ }
+ };
+
+ return (
+
+
+ {trailing}
+
+
+ );
+};
+
+export default LoginForm;
diff --git a/src/components/Login/Settings.tsx b/src/components/Login/Settings.tsx
new file mode 100644
index 0000000..02650ad
--- /dev/null
+++ b/src/components/Login/Settings.tsx
@@ -0,0 +1,223 @@
+import z from "zod";
+
+import { repository } from "../../../package.json";
+
+import { FC, useCallback, useEffect } from "react";
+import { useState } from "react";
+
+import { AppError, ApiSettings } from "@dust-mail/structures";
+
+import Alert from "@mui/material/Alert";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import CircularProgress from "@mui/material/CircularProgress";
+import FormControl from "@mui/material/FormControl";
+import IconButton from "@mui/material/IconButton";
+import InputAdornment from "@mui/material/InputAdornment";
+import InputLabel from "@mui/material/InputLabel";
+import Link from "@mui/material/Link";
+import Modal from "@mui/material/Modal";
+import OutlinedInput from "@mui/material/OutlinedInput";
+import Stack from "@mui/material/Stack";
+import TextField from "@mui/material/TextField";
+import Typography from "@mui/material/Typography";
+
+import CheckIcon from "@mui/icons-material/Check";
+import ErrorIcon from "@mui/icons-material/Error";
+import RefreshIcon from "@mui/icons-material/Refresh";
+import SettingsIcon from "@mui/icons-material/Settings";
+
+import { Result } from "@interfaces/result";
+
+import modalStyles from "@styles/modal";
+
+import useApiClient from "@utils/hooks/useApiClient";
+import useSettings from "@utils/hooks/useSettings";
+import useTheme from "@utils/hooks/useTheme";
+import { createResultFromUnknown, errorToString } from "@utils/parseError";
+
+const LoginSettingsMenu: FC = () => {
+ const theme = useTheme();
+
+ const [settings, setSetting] = useSettings();
+
+ const [isOpen, setOpen] = useState(false);
+ const [apiUrl, setApiUrl] = useState(settings.httpServerUrl ?? "");
+ const [password, setPassword] = useState("");
+
+ const apiClient = useApiClient();
+
+ const [connectError, setConnectError] = useState(null);
+ const [serverSettings, setServerSettings] = useState(
+ null
+ );
+ const [fetching, setFetching] = useState(false);
+
+ const [loginError, setLoginError] = useState(null);
+
+ const fetchApiSettings = useCallback(
+ async (baseUrl: string): Promise => {
+ setFetching(true);
+ setConnectError(null);
+ setServerSettings(null);
+
+ const response = await apiClient
+ .getSettings(baseUrl)
+ .catch(createResultFromUnknown);
+
+ setFetching(false);
+
+ if (response.ok) {
+ setServerSettings(response.data);
+ } else {
+ setConnectError(response.error);
+ }
+ },
+ []
+ );
+
+ const loginToApiServer = useCallback(
+ async (
+ baseUrl?: string,
+ password?: string,
+ username?: string
+ ): Promise> =>
+ await apiClient
+ .login(baseUrl, password, username)
+ .catch(createResultFromUnknown),
+ []
+ );
+
+ useEffect(() => {
+ if (isOpen) fetchApiSettings(apiUrl);
+ }, [isOpen]);
+
+ useEffect(() => {
+ setLoginError(null);
+ }, [isOpen, password, apiUrl]);
+
+ return (
+ <>
+
+ setOpen(true)}
+ aria-label="Open custom server settings"
+ >
+
+
+
+ {isOpen && (
+ setOpen(false)} open={isOpen}>
+
+
+
+ Set custom {import.meta.env.VITE_APP_NAME} backend server
+
+
+
+
+ Only update this value if you know what you are doing!
+
+
+
+ For more information visit{" "}
+
+ the Github repo
+
+ .
+
+
+
+
+
+
+ Custom server url/path
+
+
+ setApiUrl(z.string().parse(e.currentTarget.value))
+ }
+ value={apiUrl}
+ id="custom-server"
+ label="Custom server url/path"
+ type="text"
+ endAdornment={
+
+ {connectError !== null && }
+ {serverSettings !== null && (
+
+ )}
+ {fetching && }
+
+ }
+ />
+
+ fetchApiSettings(apiUrl)}>
+
+
+
+ {serverSettings?.authorization && (
+
+
+ setPassword(z.string().parse(e.currentTarget.value))
+ }
+ value={password}
+ id="password"
+ required
+ label="Password for server"
+ variant="outlined"
+ type="password"
+ />
+
+ )}
+
+ {loginError !== null && (
+ {errorToString(loginError)}
+ )}
+
+
+
+
+
+
+
+ )}
+ >
+ );
+};
+
+export default LoginSettingsMenu;
diff --git a/src/components/Message/ActionButton.tsx b/src/components/Message/ActionButton.tsx
new file mode 100644
index 0000000..c2261a1
--- /dev/null
+++ b/src/components/Message/ActionButton.tsx
@@ -0,0 +1,41 @@
+import { FC } from "react";
+
+import SpeedDial from "@mui/material/SpeedDial";
+import SpeedDialAction from "@mui/material/SpeedDialAction";
+import SpeedDialIcon from "@mui/material/SpeedDialIcon";
+
+import useMessageActions from "@utils/hooks/useMessageActions";
+import useSelectedMessage from "@utils/hooks/useSelectedMessage";
+
+const MessageActionButton: FC = () => {
+ const { selectedMessage } = useSelectedMessage();
+
+ const actions = useMessageActions();
+
+ if (selectedMessage)
+ return (
+ }
+ >
+ {actions.reverse().map((action) => (
+ action.handler(selectedMessage)}
+ key={action.name}
+ icon={action.icon}
+ tooltipTitle={action.name}
+ />
+ ))}
+
+ );
+
+ return <>>;
+};
+
+export default MessageActionButton;
diff --git a/src/components/Message/Composer.tsx b/src/components/Message/Composer.tsx
new file mode 100644
index 0000000..94639da
--- /dev/null
+++ b/src/components/Message/Composer.tsx
@@ -0,0 +1,265 @@
+/* eslint-disable */
+import useLocalStorageState from "use-local-storage-state";
+
+import { Descendant, createEditor, Transforms, Text, Editor } from "slate";
+import { Editable, Slate, withReact } from "slate-react";
+
+import {
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+ FC,
+ ReactNode,
+ KeyboardEvent
+} from "react";
+import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
+
+import Box from "@mui/material/Box";
+import Modal from "@mui/material/Modal";
+import Stack from "@mui/material/Stack";
+import TextField from "@mui/material/TextField";
+import Typography from "@mui/material/Typography";
+
+import { CustomElement, CustomText } from "@interfaces/slate";
+
+import modalStyles from "@styles/modal";
+
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+
+const isBoldMarkActive = (editor: Editor) => {
+ const [match] = Editor.nodes(editor, {
+ match: (n: any) => n.bold === true,
+ universal: true
+ });
+
+ return !!match;
+};
+
+const isCodeBlockActive = (editor: Editor) => {
+ const [match] = Editor.nodes(editor, {
+ match: (n: any) => n.type === "code"
+ });
+
+ return !!match;
+};
+
+const toggleBoldMark = (editor: Editor) => {
+ const isActive = isBoldMarkActive(editor);
+
+ Transforms.setNodes(
+ editor,
+ { bold: !isActive },
+ { match: (n) => Text.isText(n), split: true }
+ );
+};
+
+const toggleCodeBlock = (editor: Editor) => {
+ const isActive = isCodeBlockActive(editor);
+
+ Transforms.setNodes(
+ editor,
+ { type: isActive ? "paragraph" : "code" },
+ { match: (n) => Editor.isBlock(editor, n) }
+ );
+};
+
+const isMarkActive = (
+ editor: Editor,
+ format: keyof Omit
+) => {
+ const marks = Editor.marks(editor);
+ return marks ? marks[format] === true : false;
+};
+
+const toggleMark = (editor: Editor, format: keyof Omit) => {
+ const isActive = isMarkActive(editor, format);
+
+ if (isActive) {
+ Editor.removeMark(editor, format);
+ } else {
+ Editor.addMark(editor, format, true);
+ }
+};
+
+const CodeElement: FC<{
+ attributes: Record;
+ children?: ReactNode;
+}> = (props) => (
+
+ {props.children}
+
+);
+
+const DefaultElement: FC<{
+ attributes: Record;
+ children?: ReactNode;
+}> = (props) => {props.children}
;
+
+const Leaf: FC<{
+ leaf: Omit;
+ attributes: Record;
+ children?: ReactNode;
+}> = (props) => (
+
+ {props.children}
+
+);
+
+// const TextEditor: FC<{ initialValue?: string }> = ({ initialValue }) => {
+// const [value, setValue] = useState([
+// {
+// type: "paragraph",
+// children: [{ text: initialValue ?? "" }]
+// }
+// ]);
+
+// const renderElement = useCallback<
+// (props: {
+// element: CustomElement;
+// attributes: Record;
+// children: ReactNode;
+// }) => JSX.Element
+// >((props) => {
+// switch (props.element.type) {
+// case "code":
+// return ;
+// default:
+// return ;
+// }
+// }, []);
+
+// const renderLeaf = useCallback<
+// (props: {
+// leaf: CustomText;
+// children?: ReactNode;
+// attributes: Record;
+// }) => JSX.Element
+// >((props) => {
+// return ;
+// }, []);
+
+// const editor = useMemo(() => withReact(createEditor()), []);
+
+// return (
+// setValue(value)}>
+// {
+// if (!event.ctrlKey) {
+// return;
+// }
+
+// switch (event.key) {
+// // When "`" is pressed, keep our existing code block logic.
+// case "`": {
+// event.preventDefault();
+
+// toggleCodeBlock(editor);
+
+// break;
+// }
+
+// // When "B" is pressed, bold the text in the selection.
+// case "b": {
+// event.preventDefault();
+
+// toggleBoldMark(editor);
+
+// break;
+// }
+// }
+// }}
+// />
+//
+// );
+// };
+
+const MessageComposer: FC = () => {
+ const theme = useTheme();
+
+ const location = useLocation();
+ const navigate = useNavigate();
+ let [searchParams] = useSearchParams();
+
+ const [to, setTo] = useState();
+ const [body, setBody] = useState(undefined);
+ const [subject, setSubject] = useState();
+
+ const showMessageComposer =
+ useStore((state) => state.showMessageComposer) ||
+ location.pathname == "/dashboard/compose";
+
+ const setShowMessageComposer = useStore(
+ (state) => state.setShowMessageComposer
+ );
+
+ useEffect(() => {
+ if (showMessageComposer) {
+ document.title = `${import.meta.env.VITE_APP_NAME} - Compose`;
+ }
+ }, [showMessageComposer]);
+
+ if (!showMessageComposer) return <>>;
+
+ const uriParam = searchParams.get("uri");
+
+ useEffect(() => {
+ if (uriParam) {
+ try {
+ const uri = new URL(uriParam);
+
+ if (uri.searchParams.has("body")) {
+ setBody(uri.searchParams.get("body")!);
+ }
+
+ if (uri.searchParams.has("subject")) {
+ setSubject(uri.searchParams.get("subject")!);
+ }
+
+ if (uri.pathname && uri.pathname.length != 0) setTo(uri.pathname);
+ } catch {}
+ }
+ }, [uriParam]);
+
+ return (
+ {
+ if (location.pathname == "/dashboard/compose") navigate("/dashboard");
+
+ document.title = import.meta.env.VITE_APP_NAME;
+
+ setShowMessageComposer(false);
+ }}
+ >
+
+
+
+ Compose a new message
+
+ setTo(e.currentTarget.value)}
+ />
+ setSubject(e.currentTarget.value)}
+ />
+ {/* */}
+
+
+
+ );
+};
+
+export default MessageComposer;
diff --git a/src/components/Message/List.tsx b/src/components/Message/List.tsx
new file mode 100644
index 0000000..6196824
--- /dev/null
+++ b/src/components/Message/List.tsx
@@ -0,0 +1,347 @@
+import {
+ useEffect,
+ useRef,
+ useState,
+ memo,
+ FC,
+ useMemo,
+ FormEvent
+} from "react";
+import { useInfiniteQuery } from "react-query";
+
+import { Preview, AppError } from "@dust-mail/structures";
+
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import CircularProgress from "@mui/material/CircularProgress";
+import FormControl from "@mui/material/FormControl";
+import IconButton from "@mui/material/IconButton";
+import InputAdornment from "@mui/material/InputAdornment";
+import InputLabel from "@mui/material/InputLabel";
+import ListItemIcon from "@mui/material/ListItemIcon";
+import ListItemText from "@mui/material/ListItemText";
+import Menu from "@mui/material/Menu";
+import MenuItem from "@mui/material/MenuItem";
+import OutlinedInput from "@mui/material/OutlinedInput";
+import Stack from "@mui/material/Stack";
+import Tooltip from "@mui/material/Tooltip";
+import Typography from "@mui/material/Typography";
+import { useTheme } from "@mui/material/styles";
+
+import CloseIcon from "@mui/icons-material/Close";
+import RefreshIcon from "@mui/icons-material/Refresh";
+import SearchIcon from "@mui/icons-material/Search";
+
+import { messageCountForPage } from "@src/constants";
+
+import useMailClient from "@utils/hooks/useMailClient";
+import useMessageActions from "@utils/hooks/useMessageActions";
+import useSelectedBox from "@utils/hooks/useSelectedBox";
+import useSelectedMessage from "@utils/hooks/useSelectedMessage";
+import useStore from "@utils/hooks/useStore";
+import useUser from "@utils/hooks/useUser";
+import {
+ createBaseError,
+ createErrorFromUnknown,
+ errorToString
+} from "@utils/parseError";
+
+import MessageListItem from "@components/Message/ListItem";
+
+interface RightClickMenuAnchor {
+ x: number;
+ y: number;
+ id?: string;
+}
+
+const UnMemoizedActionBar: FC<{
+ setFilter: (filter: string) => void;
+ refetch: () => void;
+}> = ({ setFilter, refetch }) => {
+ const theme = useTheme();
+
+ const [search, setSearch] = useState("");
+
+ const handleSubmit = (e: FormEvent): void => {
+ e.preventDefault();
+
+ setFilter(search);
+ };
+
+ useEffect(() => {
+ if (search.length == 0) setFilter("");
+ }, [search]);
+
+ const label = "Search messages";
+
+ return (
+ <>
+
+
+
+
+
+
+ refetch()}>
+
+
+
+
+ >
+ );
+};
+
+const ActionBar = memo(UnMemoizedActionBar);
+
+const UnMemoizedMessageListItems: FC<{
+ data?: Preview[][];
+ selectedMessageID?: string;
+ setRightClickMenuAnchor: (anchor: RightClickMenuAnchor) => void;
+}> = ({ data, selectedMessageID, setRightClickMenuAnchor }) => {
+ return (
+ <>
+ {data &&
+ data.map((messages) =>
+ messages.map((message) => {
+ const selected = selectedMessageID == message.id;
+
+ return (
+
+ );
+ })
+ )}
+ >
+ );
+};
+
+const MessageListItems = memo(UnMemoizedMessageListItems);
+
+const UnMemoizedMessageList: FC = () => {
+ const mailClient = useMailClient();
+
+ const setFetching = useStore((state) => state.setFetching);
+
+ const [filter, setFilter] = useState("");
+
+ const { box: selectedBox } = useSelectedBox();
+ const { selectedMessage } = useSelectedMessage();
+
+ const user = useUser();
+
+ // Request the messages using react-query
+ const {
+ data,
+ error,
+ fetchNextPage,
+ isFetching,
+ isFetchingNextPage,
+ refetch
+ } = useInfiniteQuery(
+ ["messageList", selectedBox?.id, filter],
+ async ({ pageParam = 0 }) => {
+ if (pageParam === false) {
+ return [];
+ }
+
+ if (!selectedBox?.id) return [];
+
+ const result = await mailClient
+ .messageList(pageParam, selectedBox.id)
+ .catch((error) => createBaseError(createErrorFromUnknown(error)));
+
+ if (result.ok) return result.data;
+ else throw result.error;
+ },
+ {
+ getNextPageParam: (lastPage, pages) => {
+ const morePagesExist = lastPage?.length === messageCountForPage;
+
+ if (!morePagesExist) return false;
+
+ return pages.length;
+ },
+ enabled:
+ selectedBox?.id != undefined &&
+ selectedBox.selectable &&
+ user?.token != undefined
+ }
+ );
+
+ useEffect(
+ () => setFetching(isFetching || isFetchingNextPage),
+ [isFetching, isFetchingNextPage]
+ );
+
+ const rightClickMenuBox = useRef(null);
+
+ const [rightClickMenuAnchor, setRightClickMenuAnchor] =
+ useState({ x: 0, y: 0 });
+
+ const messageActions = useMessageActions();
+
+ const rightClickMenuOpen = useMemo(
+ () => rightClickMenuAnchor.x != 0 || rightClickMenuAnchor.y != 0,
+ [rightClickMenuAnchor, selectedMessage]
+ );
+
+ const handleMenuClose = (): void => setRightClickMenuAnchor({ x: 0, y: 0 });
+
+ return (
+ <>
+ {rightClickMenuOpen && rightClickMenuBox && (
+
+ )}
+
+
+
+
+
+
+
+
+
+ {(isFetching || isFetchingNextPage) && (
+
+
+
+ )}
+
+ {!selectedBox?.id && (
+
+ No mail box selected.
+
+ )}
+
+ {error && (
+
+ {errorToString(error)}
+
+
+
+ )}
+
+ {data && data.pages && data.pages[0].length == 0 && (
+
+ Empty 🙃
+
+ )}
+
+ {/* Show a load more button, unless the last page doesn't have a full set of items */}
+ {data && data.pages[data.pages.length - 1].length == messageCountForPage && (
+
+ )}
+ >
+ );
+};
+
+const MessageList = memo(UnMemoizedMessageList);
+
+export default MessageList;
diff --git a/src/components/Message/ListItem.tsx b/src/components/Message/ListItem.tsx
new file mode 100644
index 0000000..78ef8b5
--- /dev/null
+++ b/src/components/Message/ListItem.tsx
@@ -0,0 +1,153 @@
+import { FC, memo, MouseEvent, useMemo, useState } from "react";
+
+import { Preview } from "@dust-mail/structures";
+
+import Avatar from "@mui/material/Avatar";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+
+import createAvatarUrl from "@utils/avatarUrl";
+import { useSetSelectedMessage } from "@utils/hooks/useSelectedMessage";
+import useTheme from "@utils/hooks/useTheme";
+
+// interface Message {
+// id: string;
+// seen: boolean;
+// }
+
+// interface UnSeenMessagesStore {
+// messages: Message[];
+// addMessage: (msg: Message) => void;
+// setSeen: (id: string, seen: boolean) => void;
+// isSeen: (id: string) => void;
+// }
+
+// export const unSeenMessagesStore = create((set) => ({
+// messages: [],
+// addMessage: (msg) => set((state) => ({ messages: [...state.messages, msg] })),
+// setSeen: (id, seen) =>
+// set((state) => ({
+// messages: [...state.messages.filter((msg) => msg.id != id), { id, seen }]
+// })),
+// isSeen: (id) =>
+// }));
+
+const UnMemoizedMessageListItem: FC<{
+ message: Preview;
+ selectedMessage: boolean;
+ setRightClickMenuAnchor: (anchor: {
+ x: number;
+ y: number;
+ id?: string;
+ }) => void;
+}> = ({ message, selectedMessage, setRightClickMenuAnchor }) => {
+ const theme = useTheme();
+
+ const setSelectedMessage = useSetSelectedMessage();
+
+ const [unSeen, setUnSeen] = useState(!message.flags.includes("Read"));
+
+ const from = useMemo(
+ () => message.from.map((from) => from.name || from.address).join(", "),
+ [message]
+ );
+
+ const primarySender = message.from[0] ?? null;
+
+ const avatar =
+ primarySender?.address !== null
+ ? createAvatarUrl(primarySender.address)
+ : undefined;
+
+ const handleClick = useMemo(
+ () => (): void => {
+ if (!message.id) return;
+
+ setUnSeen(false);
+
+ if (selectedMessage) setSelectedMessage();
+ else setSelectedMessage(message.id);
+ },
+ [message.id, selectedMessage]
+ );
+
+ const handleContextMenu = useMemo(
+ () =>
+ (e: MouseEvent): void => {
+ e.preventDefault();
+
+ setRightClickMenuAnchor({ x: e.pageX, y: e.pageY, id: message.id });
+ },
+ [setRightClickMenuAnchor]
+ );
+
+ return (
+ <>
+
+
+ {unSeen && (
+
+ )}
+
+
+
+
+
+ {from || "(Unknown sender)"} •{" "}
+ {new Date((message.sent ?? 0) * 1000).toLocaleDateString()}
+
+
+
+ {!message.subject ||
+ (message.subject && message.subject.length == 0)
+ ? "(No subject)"
+ : message.subject}
+
+ {/*
+
+ */}
+
+
+
+ >
+ );
+};
+
+const MessageListItem = memo(UnMemoizedMessageListItem);
+
+export default MessageListItem;
diff --git a/src/components/Message/Overview.tsx b/src/components/Message/Overview.tsx
new file mode 100644
index 0000000..1f90ed1
--- /dev/null
+++ b/src/components/Message/Overview.tsx
@@ -0,0 +1,455 @@
+import useLocalStorageState from "use-local-storage-state";
+
+import { useEffect, useRef, useState, memo, FC, MouseEvent } from "react";
+
+import { Address } from "@dust-mail/structures";
+
+import Avatar from "@mui/material/Avatar";
+import Box from "@mui/material/Box";
+import Card from "@mui/material/Card";
+import Chip from "@mui/material/Chip";
+import IconButton from "@mui/material/IconButton";
+import Link from "@mui/material/Link";
+import ListItemIcon from "@mui/material/ListItemIcon";
+import ListItemText from "@mui/material/ListItemText";
+import Menu from "@mui/material/Menu";
+import MenuItem from "@mui/material/MenuItem";
+import Skeleton from "@mui/material/Skeleton";
+import Stack from "@mui/material/Stack";
+import Tooltip from "@mui/material/Tooltip";
+import Typography from "@mui/material/Typography";
+
+import CloseIcon from "@mui/icons-material/Close";
+import HtmlMarkupIcon from "@mui/icons-material/Code";
+import DarkModeIcon from "@mui/icons-material/DarkMode";
+import CollapseIcon from "@mui/icons-material/ExpandLess";
+import ExpandIcon from "@mui/icons-material/ExpandMore";
+import HideImageIcon from "@mui/icons-material/HideImage";
+import ImageIcon from "@mui/icons-material/Image";
+import BrowserIcon from "@mui/icons-material/Language";
+import LightModeIcon from "@mui/icons-material/LightMode";
+import MoreIcon from "@mui/icons-material/MoreHoriz";
+import TextOnlyIcon from "@mui/icons-material/TextFields";
+
+import scrollbarStyles from "@styles/scrollbar";
+
+import createAvatarUrl from "@utils/avatarUrl";
+// import useAvatar from "@utils/hooks/useAvatar";
+import useMessageActions from "@utils/hooks/useMessageActions";
+import useSelectedMessage, {
+ useSetSelectedMessage
+} from "@utils/hooks/useSelectedMessage";
+import useTheme from "@utils/hooks/useTheme";
+import { errorToString } from "@utils/parseError";
+
+const AddressListItem: FC<{ address: string | null; name: string | null }> = ({
+ address,
+ name
+}) => {
+ const theme = useTheme();
+
+ const avatar = address !== null ? createAvatarUrl(address) : undefined;
+
+ const displayName = name || address || "Unknown";
+
+ return (
+
+ }
+ label={
+ displayName == address ? displayName : `${displayName} <${address}>`
+ }
+ />
+ );
+};
+
+const ADDRESSES_TO_SHOW = 3;
+
+const AddressList: FC<{
+ data: Address[];
+ prefixText: string;
+}> = ({ data, prefixText }) => {
+ const [showMore, setShowMore] = useState(false);
+
+ return (
+
+ {prefixText}
+ {data &&
+ data
+ .slice(0, showMore ? data.length : ADDRESSES_TO_SHOW)
+ .map((address, i) => (
+
+ ))}
+ {data && data.length > ADDRESSES_TO_SHOW && (
+ setShowMore((state) => !state)}
+ sx={{ cursor: "pointer" }}
+ >
+ {showMore ? "Hide" : `And ${data.length - ADDRESSES_TO_SHOW} more`}
+
+ )}
+
+ );
+};
+
+const UnMemoizedMessageDisplay: FC<{ content: string }> = ({ content }) => {
+ const iframeRef = useRef(null);
+
+ useEffect(() => {
+ const document =
+ iframeRef.current?.contentDocument ||
+ iframeRef.current?.contentWindow?.document;
+
+ // iframeRef.current?.contentWindow?.addEventListener("message", console.log);
+
+ document?.open();
+
+ document?.write(content);
+
+ document?.close();
+
+ // return () =>
+ // iframeRef.current?.contentWindow?.removeEventListener(
+ // "message",
+ // console.log
+ // );
+ }, [content]);
+
+ return (
+
+ );
+};
+
+const MessageDisplay = memo(UnMemoizedMessageDisplay);
+
+const CloseButton: FC = () => {
+ const setSelectedMessage = useSetSelectedMessage();
+
+ return (
+
+ setSelectedMessage()}>
+
+
+
+ );
+};
+
+// const AttachmentList: FC<{
+// attachments: Attachment[];
+// }> = ({ attachments }) => {
+// const [backendServer] = useLocalStorageState("customServerUrl");
+
+// return (
+// <>
+// {attachments.map((attachment) => {
+// let url;
+// if (attachment.token)
+// url = `${backendServer}/mail/message/attachment?token=${attachment.token}`;
+
+// return (
+//
+// {attachment.name}
+//
+// );
+// })}
+// >
+// );
+// };
+
+const UnMemoizedMessageOverview: FC = () => {
+ const theme = useTheme();
+
+ const {
+ selectedMessage: data,
+ selectedMessageError: error,
+ selectedMessageFetching: isFetching
+ } = useSelectedMessage();
+
+ const messageActions = useMessageActions();
+
+ // const setShowMessageComposer = useStore(
+ // (state) => state.setShowMessageComposer
+ // );
+
+ const [minimized, setMinimized] = useState(false);
+
+ const [darkMode, setDarkMode] =
+ useLocalStorageState("messageDarkMode");
+
+ const [showImages, setShowImages] =
+ useLocalStorageState("showImages");
+
+ const [showTextOnly, setShowTextOnly] = useLocalStorageState(
+ "showTextOnly",
+ { defaultValue: false }
+ );
+
+ const [messageActionsAnchor, setMessageActionsAnchor] =
+ useState(null);
+ const messageActionsAnchorOpen = Boolean(messageActionsAnchor);
+
+ return (
+ <>
+ {data && (
+ <>
+
+
+ <>
+ {error && (
+
+ {errorToString(error)}
+
+ )}
+ {data && !error && (
+
+
+
+ {isFetching || !data ? (
+
+ ) : (
+ data.subject ?? "(No subject)"
+ )}
+
+
+ {isFetching || !data ? (
+
+ ) : (
+ `${new Date(
+ (data.sent ?? 0) * 1000
+ ).toLocaleDateString()} - ${new Date(
+ (data.sent ?? 0) * 1000
+ ).toLocaleTimeString()}`
+ )}
+
+
+
+ {data?.from && data?.from.length != 0 && (
+
+ )}
+ {data?.to && data?.to.length != 0 && (
+
+ )}
+ {data?.cc && data?.cc.length != 0 && (
+
+ )}
+ {data?.bcc && data?.bcc.length != 0 && (
+
+ )}
+ {/* {data?.attachments && data.attachments.length != 0 && (
+
+ )} */}
+
+
+ )}
+
+
+
+
+
+
+ setShowTextOnly(() => !showTextOnly)}
+ >
+ {showTextOnly ? : }
+
+
+ {!showTextOnly && data.content.html && (
+ <>
+
+ setDarkMode(() => !darkMode)}
+ >
+ {darkMode ? : }
+
+
+
+ setShowImages((state) => !state)}
+ >
+ {showImages ? : }
+
+
+ >
+ )}
+
+
+ setMessageActionsAnchor(e.currentTarget as Element)
+ }
+ >
+
+
+
+
+
+ setMinimized((state) => !state)}>
+
+
+
+
+
+
+ >
+
+
+
+ {(isFetching || !data) && (
+
+ )}
+ {!isFetching && data?.content && (
+ <>
+ {!showTextOnly && data.content.html && (
+
+ )}
+ {(!data.content.html || showTextOnly) && data.content.text && (
+
+ )}
+ {!(
+ (data.content.html && !showTextOnly) ||
+ data.content.text
+ ) && (
+
+ {showTextOnly && data.content.html ? (
+ <>
+ You need to allow html to view this email.{" "}
+ setShowTextOnly(false)}
+ >
+ Enable now
+
+ >
+ ) : (
+ "No message content "
+ )}
+
+ )}
+ >
+ )}
+
+ >
+ )}
+
+
+ No message selected.
+ Get started by selecting a message on the left.
+ {/*
+ Or start by{" "}
+ setShowMessageComposer(true)}
+ >
+ composing a new message
+
+ .
+ */}
+
+ >
+ );
+};
+
+const MessageOverview = memo(UnMemoizedMessageOverview);
+
+export default MessageOverview;
diff --git a/src/components/Navbar/Avatar.tsx b/src/components/Navbar/Avatar.tsx
new file mode 100644
index 0000000..def4080
--- /dev/null
+++ b/src/components/Navbar/Avatar.tsx
@@ -0,0 +1,198 @@
+import useLocalStorageState from "use-local-storage-state";
+
+import { FC, memo, useState, MouseEvent, useMemo } from "react";
+import { useNavigate } from "react-router";
+
+import MUIAvatar from "@mui/material/Avatar";
+import Divider from "@mui/material/Divider";
+import IconButton from "@mui/material/IconButton";
+import ListItemIcon from "@mui/material/ListItemIcon";
+import ListItemText from "@mui/material/ListItemText";
+import Menu from "@mui/material/Menu";
+import MenuItem from "@mui/material/MenuItem";
+
+import DarkModeIcon from "@mui/icons-material/DarkMode";
+// import ComposeIcon from "@mui/icons-material/Edit";
+import LightModeIcon from "@mui/icons-material/LightMode";
+import LogoutIcon from "@mui/icons-material/Logout";
+import AddAccountIcon from "@mui/icons-material/PersonAdd";
+import SettingsIcon from "@mui/icons-material/Settings";
+
+import User from "@interfaces/user";
+
+import createAvatarUrl from "@utils/avatarUrl";
+import useLogout from "@utils/hooks/useLogout";
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+import useUser, { useCurrentUser, useUsers } from "@utils/hooks/useUser";
+
+const DarkModeListItem: FC = () => {
+ const [darkMode, setDarkMode] = useLocalStorageState("darkMode");
+
+ const handleClick = (): void => {
+ setDarkMode(!darkMode);
+ };
+
+ return (
+
+ );
+};
+
+const AccountListItem: FC<{ user: User }> = ({ user }) => {
+ const theme = useTheme();
+
+ const [currentUser, setCurrentUser] = useCurrentUser();
+
+ const avatar =
+ user?.usernames.incoming !== undefined
+ ? createAvatarUrl(user?.usernames.incoming)
+ : undefined;
+
+ return (
+
+ );
+};
+
+const AccountList: FC = () => {
+ const [users] = useUsers();
+
+ const [currentUser] = useCurrentUser();
+
+ return (
+ <>
+ {currentUser && }
+
+ {users
+ ?.filter((user) => user.id != currentUser?.id)
+ .slice(0, 5)
+ .map((user) => (
+
+ ))}
+ >
+ );
+};
+
+const AddAccountListItem: FC = () => {
+ const navigate = useNavigate();
+
+ return (
+
+ );
+};
+
+const UnMemoizedAvatar: FC = () => {
+ const theme = useTheme();
+
+ const user = useUser();
+
+ const logout = useLogout();
+
+ const [menuAnchor, setMenuAnchor] = useState();
+ const open = Boolean(menuAnchor);
+
+ const setShowSettings = useStore((state) => state.setShowSettings);
+
+ const avatar =
+ user?.usernames.incoming !== undefined
+ ? createAvatarUrl(user?.usernames.incoming)
+ : undefined;
+
+ // const setShowMessageComposer = useStore(
+ // (state) => state.setShowMessageComposer
+ // );
+
+ const menuItems: { title: string; icon: JSX.Element; onClick: () => void }[] =
+ useMemo(
+ () => [
+ // {
+ // title: "New message",
+ // icon: ,
+ // onClick: () => setShowMessageComposer(true)
+ // },
+ {
+ title: "Settings",
+ icon: ,
+ onClick: () => setShowSettings(true)
+ },
+ {
+ title: "Logout",
+ icon: ,
+ onClick: () => logout()
+ }
+ ],
+ [setShowSettings, logout]
+ );
+
+ return (
+ <>
+ setMenuAnchor(e.currentTarget)}
+ sx={{ p: 0 }}
+ >
+
+
+
+
+ >
+ );
+};
+
+const Avatar = memo(UnMemoizedAvatar);
+
+export default Avatar;
diff --git a/src/components/Navbar/Drawer.tsx b/src/components/Navbar/Drawer.tsx
new file mode 100644
index 0000000..50ceabc
--- /dev/null
+++ b/src/components/Navbar/Drawer.tsx
@@ -0,0 +1,59 @@
+import { FC, memo, KeyboardEvent, MouseEvent, useMemo } from "react";
+
+import Box from "@mui/material/Box";
+import Divider from "@mui/material/Divider";
+import MUIDrawer from "@mui/material/Drawer";
+import IconButton from "@mui/material/IconButton";
+
+import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
+
+import scrollbarStyles from "@styles/scrollbar";
+
+import useTheme from "@utils/hooks/useTheme";
+import useWindowWidth from "@utils/hooks/useWindowWidth";
+
+import BoxesList from "@components/Boxes/List";
+
+const UnMemoizedDrawer: FC<{
+ toggleDrawer: (open: boolean) => (event: KeyboardEvent | MouseEvent) => void;
+ drawerState: boolean;
+}> = ({ toggleDrawer, drawerState }) => {
+ const theme = useTheme();
+
+ const windowWidth = useWindowWidth();
+
+ const scrollBarSx = useMemo(() => scrollbarStyles(theme), [theme]);
+
+ const isMobile = theme.breakpoints.values.md >= windowWidth;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const Drawer = memo(UnMemoizedDrawer);
+
+export default Drawer;
diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx
new file mode 100644
index 0000000..6f24d82
--- /dev/null
+++ b/src/components/Navbar/index.tsx
@@ -0,0 +1,190 @@
+import { FC, memo, useMemo, useState, MouseEvent, KeyboardEvent } from "react";
+
+import AppBar from "@mui/material/AppBar";
+import Box from "@mui/material/Box";
+import MUIBreadCrumbs from "@mui/material/Breadcrumbs";
+import IconButton from "@mui/material/IconButton";
+import LinearProgress from "@mui/material/LinearProgress";
+import Stack from "@mui/material/Stack";
+import Toolbar from "@mui/material/Toolbar";
+import Typography from "@mui/material/Typography";
+
+import MenuIcon from "@mui/icons-material/Menu";
+import NavigateNext from "@mui/icons-material/NavigateNext";
+
+import useBoxes from "@utils/hooks/useBoxes";
+import useSelectedBox from "@utils/hooks/useSelectedBox";
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+
+import Avatar from "@components/Navbar/Avatar";
+import Drawer from "@components/Navbar/Drawer";
+
+const UnMemoizedBreadCrumbs: FC = () => {
+ const theme = useTheme();
+
+ const { box: selectedBox, setSelectedBox } = useSelectedBox();
+
+ const { boxes, findBox } = useBoxes();
+
+ const secondaryColor = useMemo(
+ () =>
+ theme.palette.mode == "dark"
+ ? theme.palette.text.secondary
+ : theme.palette.primary.contrastText,
+ [theme.palette]
+ );
+
+ const primaryColor = useMemo(
+ () =>
+ theme.palette.mode == "dark"
+ ? theme.palette.text.primary
+ : theme.palette.primary.contrastText,
+ [theme.palette]
+ );
+
+ const breadcrumbs = useMemo(() => {
+ if (!selectedBox) return [];
+
+ const boxIDSplit = selectedBox.delimiter
+ ? selectedBox.id.split(selectedBox.delimiter)
+ : [selectedBox.id];
+
+ return boxIDSplit.map((crumb, i) => {
+ const boxID: string = selectedBox?.delimiter
+ ? boxIDSplit.slice(0, i + 1).join(selectedBox.delimiter)
+ : boxIDSplit[0];
+
+ const boxName = boxes ? findBox(boxID)?.name : undefined;
+
+ const isSelectedBox = boxID == selectedBox.id;
+
+ return (
+ {
+ if (!isSelectedBox) setSelectedBox(boxID);
+ }}
+ >
+ {boxName ?? "Unknown box"}
+
+ );
+ });
+ }, [selectedBox, primaryColor, secondaryColor]);
+
+ return (
+ }
+ aria-label="breadcrumb"
+ >
+ {breadcrumbs}
+
+ );
+};
+
+const BreadCrumbs = memo(UnMemoizedBreadCrumbs);
+
+const FetchBar: FC = () => {
+ const fetching = useStore((state) => state.fetching);
+
+ return (
+
+
+
+ );
+};
+
+const UnMemoizedNavbar: FC = () => {
+ const theme = useTheme();
+
+ const [drawerState, setDrawerState] = useState(false);
+
+ const toggleDrawer = useMemo(
+ () => (open: boolean) => (event: KeyboardEvent | MouseEvent) => {
+ if (
+ event.type === "keydown" &&
+ ((event as KeyboardEvent).key === "Tab" ||
+ (event as KeyboardEvent).key === "Shift")
+ ) {
+ return;
+ }
+
+ setDrawerState(open);
+ },
+ []
+ );
+
+ return (
+ <>
+
+ <>
+
+
+
+
+
+
+
+
+
+ {import.meta.env.VITE_APP_NAME}
+
+
+
+
+
+
+
+
+
+ >
+
+
+
+ >
+ );
+};
+
+const Navbar = memo(UnMemoizedNavbar);
+
+export default Navbar;
diff --git a/src/components/ParamStateHandler.tsx b/src/components/ParamStateHandler.tsx
new file mode 100644
index 0000000..67f2e87
--- /dev/null
+++ b/src/components/ParamStateHandler.tsx
@@ -0,0 +1,49 @@
+import { FC, useEffect } from "react";
+import { useNavigate, useParams } from "react-router";
+
+import useSelectedStore from "@utils/hooks/useSelected";
+import useUser from "@utils/hooks/useUser";
+
+const ParamStateHandler: FC = () => {
+ const navigate = useNavigate();
+
+ const setSelectedBox = useSelectedStore((state) => state.setSelectedBox);
+ const setSelectedMessage = useSelectedStore(
+ (state) => state.setSelectedMessage
+ );
+
+ const user = useUser();
+
+ const selectedBox = useSelectedStore((state) => state.selectedBox);
+ const selectedMessage = useSelectedStore((state) => state.selectedMessage);
+
+ const { boxID, messageID } = useParams<{
+ boxID: string;
+ messageID: string;
+ }>();
+
+ useEffect(() => {
+ if (boxID) setSelectedBox(boxID);
+ if (messageID) setSelectedMessage(messageID);
+ }, []);
+
+ useEffect(() => {
+ if (user) {
+ if (selectedBox) {
+ const box = encodeURIComponent(selectedBox);
+
+ if (!selectedMessage) navigate(`/dashboard/${box}`);
+
+ if (selectedMessage) {
+ const message = encodeURIComponent(selectedMessage);
+
+ navigate(`/dashboard/${box}/${message}`);
+ }
+ } else if (!selectedBox && !selectedMessage) navigate(`/dashboard`);
+ }
+ }, [selectedMessage, selectedBox]);
+
+ return <>>;
+};
+
+export default ParamStateHandler;
diff --git a/src/components/Settings/index.tsx b/src/components/Settings/index.tsx
new file mode 100644
index 0000000..163bc92
--- /dev/null
+++ b/src/components/Settings/index.tsx
@@ -0,0 +1,92 @@
+// import useLocalStorageState from "use-local-storage-state";
+import { FC, memo, ReactNode } from "react";
+
+// import Autocomplete from "@mui/material/Autocomplete";
+import Box from "@mui/material/Box";
+import Modal from "@mui/material/Modal";
+import Stack from "@mui/material/Stack";
+// import TextField from "@mui/material/TextField";
+import Typography from "@mui/material/Typography";
+
+import modalStyles from "@styles/modal";
+
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+
+const Setting: FC<{
+ title: string;
+ children?: ReactNode;
+ subtitle?: string;
+}> = ({ title, children, subtitle }) => {
+ const theme = useTheme();
+
+ return (
+
+
+ {title}
+
+ {subtitle}
+
+
+ {children}
+
+ );
+};
+
+const UnMemoizedSettings: FC = () => {
+ const theme = useTheme();
+
+ const setShowSettings = useStore((state) => state.setShowSettings);
+ const showSettings = useStore((state) => state.showSettings);
+
+ // const [boxes] = useLocalStorageState("boxes");
+
+ // const [defaultBox, setDefaultBox] =
+ // useLocalStorageState("defaultBox");
+
+ const handleClose = (): void => setShowSettings(false);
+
+ if (showSettings)
+ return (
+
+
+
+ Settings
+
+
+
+ {/* {boxes && (
+ setDefaultBox(newValue)}
+ sx={{ width: 200 }}
+ renderInput={(params) => (
+
+ )}
+ />
+ )} */}
+
+
+
+
+ );
+ else return <>>;
+};
+
+const Settings = memo(UnMemoizedSettings);
+
+export default Settings;
diff --git a/src/components/Slider.tsx b/src/components/Slider.tsx
new file mode 100644
index 0000000..790067c
--- /dev/null
+++ b/src/components/Slider.tsx
@@ -0,0 +1,59 @@
+import { FC, memo, MouseEvent } from "react";
+
+import Box from "@mui/material/Box";
+
+// import DragIcon from "@mui/icons-material/DragHandle";
+import useTheme from "@utils/hooks/useTheme";
+
+const UnMemoizedSlider: FC<{
+ widthSetter: (width: number) => void;
+ grabberWidth: number;
+ currentWidth: number;
+}> = ({ widthSetter, currentWidth, grabberWidth }) => {
+ const theme = useTheme();
+
+ const handleDragStart = (
+ originalWidth: number,
+ dragEvent: MouseEvent
+ ): void => {
+ const pageX = dragEvent.pageX;
+
+ const run = (moveEvent: globalThis.MouseEvent): void => {
+ moveEvent.preventDefault();
+
+ const difference = pageX - moveEvent.pageX;
+
+ const newWidth = originalWidth - difference;
+
+ if (newWidth >= 200 && newWidth <= 600) widthSetter(newWidth);
+ };
+
+ const unsub = (): void => {
+ document.removeEventListener("mousemove", run);
+ document.removeEventListener("mouseup", unsub);
+ };
+
+ document.addEventListener("mousemove", run);
+ document.addEventListener("mouseup", unsub);
+ };
+
+ return (
+ handleDragStart(currentWidth, e)}
+ sx={{
+ width: `${grabberWidth}px`,
+ bgcolor: theme.palette.divider,
+ cursor: "col-resize",
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center"
+ }}
+ >
+ {/* */}
+
+ );
+};
+
+const Slider = memo(UnMemoizedSlider);
+
+export default Slider;
diff --git a/src/components/Snackbar.tsx b/src/components/Snackbar.tsx
new file mode 100644
index 0000000..5b82c90
--- /dev/null
+++ b/src/components/Snackbar.tsx
@@ -0,0 +1,71 @@
+import create from "zustand";
+
+import { FC } from "react";
+
+import Alert from "@mui/material/Alert";
+// import IconButton from "@mui/material/IconButton";
+import MaterialSnackbar from "@mui/material/Snackbar";
+
+// import CloseIcon from "@mui/icons-material/Close";
+
+interface SnackbarStore {
+ variant: SnackbarVariant;
+ setVariant: (variant: SnackbarVariant) => void;
+ message: string;
+ setMessage: (message: string) => void;
+ open: boolean;
+ setOpen: (open: boolean) => void;
+}
+
+export type SnackbarVariant = "error" | "success";
+
+export const useSnackbarStore = create((set) => ({
+ message: "",
+ setMessage: (message) => set({ message }),
+ variant: "success",
+ setVariant: (variant) => set({ variant }),
+ open: false,
+ setOpen: (open) => set({ open })
+}));
+
+const Snackbar: FC = () => {
+ const open = useSnackbarStore((state) => state.open);
+ const message = useSnackbarStore((state) => state.message);
+ const variant = useSnackbarStore((state) => state.variant);
+
+ const setOpen = useSnackbarStore((state) => state.setOpen);
+
+ const handleClose = (
+ event: React.SyntheticEvent | Event,
+ reason?: string
+ ): void => {
+ if (reason === "clickaway") {
+ return;
+ }
+
+ setOpen(false);
+ };
+
+ // const SnackBarActions = (
+ // <>
+ //
+ //
+ //
+ // >
+ // );
+
+ return (
+
+
+ {message}
+
+
+ );
+};
+
+export default Snackbar;
diff --git a/src/constants.ts b/src/constants.ts
new file mode 100644
index 0000000..8edae72
--- /dev/null
+++ b/src/constants.ts
@@ -0,0 +1,2 @@
+export const messageCountForPage =
+ parseInt(import.meta.env.VITE_MESSAGE_COUNT_PAGE ?? "") || 20;
diff --git a/src/favicon-16x16.png b/src/favicon-16x16.png
new file mode 100644
index 0000000..ab72062
Binary files /dev/null and b/src/favicon-16x16.png differ
diff --git a/src/favicon-32x32.png b/src/favicon-32x32.png
new file mode 100644
index 0000000..f2f9524
Binary files /dev/null and b/src/favicon-32x32.png differ
diff --git a/src/favicon.ico b/src/favicon.ico
new file mode 100644
index 0000000..c95596e
Binary files /dev/null and b/src/favicon.ico differ
diff --git a/src/interfaces/api.ts b/src/interfaces/api.ts
new file mode 100644
index 0000000..8f733e4
--- /dev/null
+++ b/src/interfaces/api.ts
@@ -0,0 +1,13 @@
+import { Result } from "./result";
+
+import { ApiSettings } from "@dust-mail/structures";
+
+export default interface ApiClient {
+ getChangelog: () => Promise>;
+ getSettings: (baseUrl?: string) => Promise>;
+ login: (
+ baseUrl?: string,
+ password?: string,
+ username?: string
+ ) => Promise>;
+}
diff --git a/src/interfaces/box.ts b/src/interfaces/box.ts
new file mode 100644
index 0000000..26c53a3
--- /dev/null
+++ b/src/interfaces/box.ts
@@ -0,0 +1,5 @@
+import { MailBox as ServerMailBox } from "@dust-mail/structures";
+
+type MailBox = ServerMailBox & { icon?: JSX.Element };
+
+export default MailBox;
diff --git a/src/interfaces/client.ts b/src/interfaces/client.ts
new file mode 100644
index 0000000..40061fa
--- /dev/null
+++ b/src/interfaces/client.ts
@@ -0,0 +1,24 @@
+import {
+ MailConfig,
+ Credentials,
+ MailBoxList,
+ MailBox,
+ Message,
+ Preview,
+ Version
+} from "@dust-mail/structures";
+
+import { Result } from "@interfaces/result";
+
+// TODO: Fully implement api specification
+
+export default interface MailClient {
+ getVersion: () => Promise>;
+ detectConfig: (emailAddress: string) => Promise>;
+ login: (options: Credentials) => Promise>;
+ logout: () => Promise>;
+ get: (boxId?: string) => Promise>;
+ list: () => Promise>;
+ messageList: (page: number, boxId?: string) => Promise>;
+ getMessage: (messageId?: string, boxId?: string) => Promise>;
+}
diff --git a/src/interfaces/messageAction.ts b/src/interfaces/messageAction.ts
new file mode 100644
index 0000000..18ac491
--- /dev/null
+++ b/src/interfaces/messageAction.ts
@@ -0,0 +1,7 @@
+import { Message } from "@dust-mail/structures";
+
+export default interface MessageAction {
+ name: string;
+ icon: JSX.Element;
+ handler: (message: Message) => void;
+}
diff --git a/src/interfaces/oauth2.ts b/src/interfaces/oauth2.ts
new file mode 100644
index 0000000..a2b058d
--- /dev/null
+++ b/src/interfaces/oauth2.ts
@@ -0,0 +1,10 @@
+import { Result } from "./result";
+
+export default interface OAuth2Client {
+ getGrant: (
+ providerName: string,
+ grantUrl: string,
+ tokenUrl: string,
+ scopes: string[]
+ ) => Promise>;
+}
diff --git a/src/interfaces/result.ts b/src/interfaces/result.ts
new file mode 100644
index 0000000..f72b2c9
--- /dev/null
+++ b/src/interfaces/result.ts
@@ -0,0 +1,13 @@
+import { AppError } from "@dust-mail/structures";
+
+export interface ErrorResult {
+ ok: false;
+ error: AppError;
+}
+
+export interface OkResult {
+ ok: true;
+ data: T;
+}
+
+export type Result = OkResult | ErrorResult;
diff --git a/src/interfaces/slate.ts b/src/interfaces/slate.ts
new file mode 100644
index 0000000..d876362
--- /dev/null
+++ b/src/interfaces/slate.ts
@@ -0,0 +1,14 @@
+import { BaseEditor } from "slate";
+import { ReactEditor } from "slate-react";
+
+export type CustomTextType = "paragraph" | "code";
+export type CustomText = { text: string; bold?: boolean };
+export type CustomElement = { type: CustomTextType; children: CustomText[] };
+
+declare module "slate" {
+ interface CustomTypes {
+ Editor: BaseEditor & ReactEditor;
+ Element: CustomElement;
+ Text: CustomText;
+ }
+}
diff --git a/src/interfaces/user.ts b/src/interfaces/user.ts
new file mode 100644
index 0000000..871dc5b
--- /dev/null
+++ b/src/interfaces/user.ts
@@ -0,0 +1,7 @@
+import { ServerType } from "@dust-mail/structures";
+
+export default interface User {
+ id: string;
+ usernames: Record;
+ token: string;
+}
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 0000000..1a338bb
--- /dev/null
+++ b/src/main.tsx
@@ -0,0 +1,18 @@
+import App from "./pages/app";
+
+import React from "react";
+import ReactDOM from "react-dom/client";
+
+import "@fontsource/roboto/300.css";
+import "@fontsource/roboto/400.css";
+import "@fontsource/roboto/500.css";
+import "@fontsource/roboto/700.css";
+
+if ("navigator" in window && "registerProtocolHandler" in navigator)
+ navigator.registerProtocolHandler("mailto", "/dashboard/compose?uri=%s");
+
+ReactDOM.createRoot(document.getElementById("app") as HTMLElement).render(
+
+
+
+);
diff --git a/src/pages/404.tsx b/src/pages/404.tsx
new file mode 100644
index 0000000..0511632
--- /dev/null
+++ b/src/pages/404.tsx
@@ -0,0 +1,45 @@
+import { FC } from "react";
+import { useNavigate } from "react-router-dom";
+
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import Typography from "@mui/material/Typography";
+
+import Layout from "@components/Layout";
+
+const NotFound: FC = () => {
+ const navigate = useNavigate();
+
+ const goBack = (): void => {
+ navigate(-1);
+ };
+
+ return (
+
+
+
+
+ Page not found
+
+
+
+
+
+ );
+};
+
+export default NotFound;
diff --git a/src/pages/addAccount.tsx b/src/pages/addAccount.tsx
new file mode 100644
index 0000000..2fe638d
--- /dev/null
+++ b/src/pages/addAccount.tsx
@@ -0,0 +1,59 @@
+import { FC } from "react";
+import { useNavigate } from "react-router";
+
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import LinearProgress from "@mui/material/LinearProgress";
+import Typography from "@mui/material/Typography";
+
+import useStore from "@utils/hooks/useStore";
+
+import Layout from "@components/Layout";
+import LoginForm from "@components/Login/Form";
+
+const FetchBar: FC = () => {
+ const fetching = useStore((state) => state.fetching);
+
+ return (
+
+
+
+ );
+};
+
+const AddAccount: FC = () => {
+ const navigate = useNavigate();
+
+ const goBack = (): void => {
+ navigate(-1);
+ };
+
+ return (
+
+
+
+ goBack()}>Go back}>
+ Add account
+
+
+
+ );
+};
+
+export default AddAccount;
diff --git a/src/pages/app.tsx b/src/pages/app.tsx
new file mode 100644
index 0000000..8b1d9da
--- /dev/null
+++ b/src/pages/app.tsx
@@ -0,0 +1,43 @@
+import NotFound from "./404";
+import AddAccount from "./addAccount";
+import Dashboard from "./dashboard";
+import Login from "./login";
+
+import { FC } from "react";
+import { QueryClientProvider } from "react-query";
+import { ReactQueryDevtools } from "react-query/devtools";
+import { BrowserRouter, Routes, Route } from "react-router-dom";
+
+import CssBaseline from "@mui/material/CssBaseline";
+import { ThemeProvider } from "@mui/material/styles";
+
+import queryClient from "@utils/createQueryClient";
+import useTheme from "@utils/hooks/useTheme";
+
+const App: FC = () => {
+ const theme = useTheme();
+
+ return (
+
+
+
+
+
+
+ } />
+ } />
+ }>
+ } />
+ }>
+ } />
+
+
+ } />
+
+
+
+
+ );
+};
+
+export default App;
diff --git a/src/pages/dashboard.tsx b/src/pages/dashboard.tsx
new file mode 100644
index 0000000..95075d2
--- /dev/null
+++ b/src/pages/dashboard.tsx
@@ -0,0 +1,147 @@
+import useLocalStorageState from "use-local-storage-state";
+
+import { FC, useMemo } from "react";
+import { Navigate } from "react-router-dom";
+
+import Box from "@mui/material/Box";
+import Stack from "@mui/material/Stack";
+
+import scrollbarStyles from "@styles/scrollbar";
+
+import useSelectedMessage from "@utils/hooks/useSelectedMessage";
+import useTheme from "@utils/hooks/useTheme";
+import useUser from "@utils/hooks/useUser";
+import useWindowWidth from "@utils/hooks/useWindowWidth";
+
+import AddBox from "@components/Boxes/Add";
+import DeleteBox from "@components/Boxes/Delete";
+import BoxesList from "@components/Boxes/List";
+import RenameBox from "@components/Boxes/Rename";
+import Layout from "@components/Layout";
+import MessageActionButton from "@components/Message/ActionButton";
+import MessageList from "@components/Message/List";
+import MessageOverview from "@components/Message/Overview";
+import ParamStateHandler from "@components/ParamStateHandler";
+import Settings from "@components/Settings";
+import Slider from "@components/Slider";
+import Snackbar from "@components/Snackbar";
+
+const defaultMessageListWidth = 400;
+
+const Dashboard: FC = () => {
+ const theme = useTheme();
+
+ const scrollBarSx = useMemo(() => scrollbarStyles(theme), [theme]);
+
+ const user = useUser();
+
+ const isLoggedIn = !!user;
+
+ const [messageListWidth, setMessageListWidth] = useLocalStorageState(
+ "messageListWidth",
+ {
+ defaultValue: defaultMessageListWidth
+ }
+ );
+
+ const [boxesListWidth, setBoxesListWidth] = useLocalStorageState(
+ "boxesListWidth",
+ {
+ defaultValue: 300
+ }
+ );
+
+ const fullpageHeight = useMemo(
+ () => `calc(100vh - ${theme.spacing(8)})`,
+ [theme.spacing]
+ );
+
+ const windowWidth = useWindowWidth();
+
+ const grabberWidth = 2;
+
+ const isMobile = theme.breakpoints.values.md >= windowWidth;
+
+ const { selectedMessage } = useSelectedMessage();
+
+ return (
+ <>
+ {!isLoggedIn && }
+
+
+
+
+
+
+
+
+ {!isMobile && (
+ <>
+
+
+
+
+ >
+ )}
+
+
+
+
+ <>
+ {!isMobile && (
+
+ )}
+
+
+
+
+ >
+
+
+
+
+ >
+ );
+};
+
+export default Dashboard;
diff --git a/src/pages/login.tsx b/src/pages/login.tsx
new file mode 100644
index 0000000..1a93e8a
--- /dev/null
+++ b/src/pages/login.tsx
@@ -0,0 +1,110 @@
+import { description } from "../../package.json";
+
+import { FC } from "react";
+import { Navigate } from "react-router-dom";
+
+import Box from "@mui/material/Box";
+import IconButton from "@mui/material/IconButton";
+import LinearProgress from "@mui/material/LinearProgress";
+import Stack from "@mui/material/Stack";
+import Typography from "@mui/material/Typography";
+
+import DarkModeIcon from "@mui/icons-material/DarkMode";
+import InfoIcon from "@mui/icons-material/Info";
+import LightModeIcon from "@mui/icons-material/LightMode";
+import UpdateIcon from "@mui/icons-material/Update";
+
+import useStore from "@utils/hooks/useStore";
+import useTheme from "@utils/hooks/useTheme";
+import useUser from "@utils/hooks/useUser";
+
+import DarkModeSwitch from "@components/DarkModeSwitch";
+import Layout from "@components/Layout";
+import LoginForm from "@components/Login/Form";
+import LoginSettingsMenu from "@components/Login/Settings";
+
+const Login: FC = () => {
+ const theme = useTheme();
+
+ const fetching = useStore((state) => state.fetching);
+
+ const appVersion = useStore((state) => state.appVersion);
+ const setShowAbout = useStore((state) => state.setShowAbout);
+
+ const setShowChangelog = useStore((state) => state.setShowChangelog);
+
+ const user = useUser();
+
+ return (
+ <>
+ {fetching && (
+
+
+
+ )}
+ {!!user && }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {import.meta.env.VITE_APP_NAME}
+
+ {description}
+
+
+
+
+ setShowChangelog(true)}>
+
+
+ setShowAbout(true)}>
+
+
+
+ Version: {appVersion.title} ({appVersion.type})
+
+
+
+
+ >
+ );
+};
+
+export default Login;
diff --git a/src/styles/index.ts b/src/styles/index.ts
new file mode 100644
index 0000000..2ccf1dc
--- /dev/null
+++ b/src/styles/index.ts
@@ -0,0 +1,3 @@
+import { SxProps } from "@mui/material/styles";
+
+export const defineStyles = (sx: T): T => sx;
diff --git a/src/styles/modal.ts b/src/styles/modal.ts
new file mode 100644
index 0000000..cfcbff4
--- /dev/null
+++ b/src/styles/modal.ts
@@ -0,0 +1,19 @@
+import { Theme } from "@mui/material/styles";
+
+import { defineStyles } from "@src/styles";
+
+// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
+const modalStyles = (theme: Theme) =>
+ defineStyles({
+ position: "absolute",
+ top: "50%",
+ left: "50%",
+ width: { lg: "40vw", xs: "80vw" },
+ transform: "translate(-50%, -50%)",
+ bgcolor: theme.palette.background.paper,
+ outline: 0,
+ boxShadow: 24,
+ p: 4
+ });
+
+export default modalStyles;
diff --git a/src/styles/scrollbar.ts b/src/styles/scrollbar.ts
new file mode 100644
index 0000000..e871b10
--- /dev/null
+++ b/src/styles/scrollbar.ts
@@ -0,0 +1,19 @@
+import { Theme } from "@mui/material/styles";
+
+import { defineStyles } from "@src/styles";
+
+// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
+const scrollbarStyles = (theme: Theme) =>
+ defineStyles({
+ "&::-webkit-scrollbar": {
+ width: theme.spacing(1)
+ },
+ "&::-webkit-scrollbar-track": {
+ bgcolor: "transparent"
+ },
+ "&::-webkit-scrollbar-thumb": {
+ backgroundColor: theme.palette.action.hover
+ }
+ });
+
+export default scrollbarStyles;
diff --git a/src/utils/avatarUrl.ts b/src/utils/avatarUrl.ts
new file mode 100644
index 0000000..c2bdc34
--- /dev/null
+++ b/src/utils/avatarUrl.ts
@@ -0,0 +1,14 @@
+import createMd5Hash from "js-md5";
+
+const createAvatarUrl = (email: string): string => {
+ const hashed = createMd5Hash(email.trim().toLowerCase());
+
+ const url = new URL("https://www.gravatar.com/avatar/" + hashed);
+
+ url.searchParams.set("s", "64");
+ url.searchParams.set("d", "404");
+
+ return url.toString();
+};
+
+export default createAvatarUrl;
diff --git a/src/utils/createQueryClient.ts b/src/utils/createQueryClient.ts
new file mode 100644
index 0000000..7ca5904
--- /dev/null
+++ b/src/utils/createQueryClient.ts
@@ -0,0 +1,11 @@
+import { QueryClient } from "react-query";
+
+const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ refetchOnWindowFocus: false
+ }
+ }
+});
+
+export default queryClient;
diff --git a/src/utils/defaultErrors.ts b/src/utils/defaultErrors.ts
new file mode 100644
index 0000000..cc20560
--- /dev/null
+++ b/src/utils/defaultErrors.ts
@@ -0,0 +1,23 @@
+import { createBaseError } from "./parseError";
+
+import { ErrorResult } from "@interfaces/result";
+
+export const NotLoggedIn = (): ErrorResult =>
+ createBaseError({
+ kind: "NotLoggedIn",
+ message: "Could not find session token in local storage"
+ });
+
+export const NotImplemented = (feature?: string): ErrorResult =>
+ createBaseError({
+ kind: "NotImplemented",
+ message: `The feature ${
+ feature ? `'${feature}'` : ""
+ } is not yet implemented`
+ });
+
+export const MissingRequiredParam = (): ErrorResult =>
+ createBaseError({
+ kind: "MissingRequiredParam",
+ message: "Missing a required parameter"
+ });
diff --git a/src/utils/findBox.ts b/src/utils/findBox.ts
new file mode 100644
index 0000000..a9caa0c
--- /dev/null
+++ b/src/utils/findBox.ts
@@ -0,0 +1,23 @@
+import findBoxInPrimaryBoxesList from "./findBoxInPrimaryBoxesList";
+
+import { MailBoxList, MailBox } from "@dust-mail/structures";
+
+const findBox = (idToFind: string, boxes: MailBoxList): MailBox | undefined => {
+ if (boxes.length < 1) return undefined;
+
+ const foundBox = boxes.find((mailbox) => mailbox.id == idToFind);
+
+ if (foundBox) {
+ const primaryBoxData = findBoxInPrimaryBoxesList(foundBox.id);
+
+ return { ...foundBox, ...primaryBoxData };
+ }
+
+ const foundBoxes = boxes
+ .map((mailbox) => findBox(idToFind, mailbox.children))
+ .filter((box) => box != undefined);
+
+ return foundBoxes[0];
+};
+
+export default findBox;
diff --git a/src/utils/findBoxInPrimaryBoxesList.tsx b/src/utils/findBoxInPrimaryBoxesList.tsx
new file mode 100644
index 0000000..aa7bfb0
--- /dev/null
+++ b/src/utils/findBoxInPrimaryBoxesList.tsx
@@ -0,0 +1,63 @@
+import Archive from "@mui/icons-material/Archive";
+import ChangeCircle from "@mui/icons-material/ChangeCircle";
+import Dangerous from "@mui/icons-material/Dangerous";
+import Delete from "@mui/icons-material/Delete";
+import Drafts from "@mui/icons-material/Drafts";
+import Forum from "@mui/icons-material/Forum";
+import Google from "@mui/icons-material/Google";
+import Inbox from "@mui/icons-material/Inbox";
+import Unread from "@mui/icons-material/MarkEmailUnread";
+import People from "@mui/icons-material/People";
+import Person from "@mui/icons-material/Person";
+import Promotions from "@mui/icons-material/Recommend";
+import Schedule from "@mui/icons-material/Schedule";
+import Send from "@mui/icons-material/Send";
+import Star from "@mui/icons-material/Star";
+import Updates from "@mui/icons-material/TipsAndUpdates";
+
+const DEFAULT_PRIMARY_BOXES: {
+ id: string[] | string;
+ name: string;
+ icon: JSX.Element;
+}[] = [
+ { name: "Inbox", id: "INBOX", icon: },
+ { name: "Sent", id: "Sent", icon: },
+ { name: "Drafts", id: ["Drafts", "Draft"], icon: },
+ { name: "Starred", id: "STARRED", icon: },
+ { name: "Unread", id: "UNREAD", icon: },
+ { name: "Spam", id: "Spam", icon: },
+ { name: "Trash", id: ["Trash", "Deleted"], icon: },
+ { name: "Scheduled", id: "Scheduled", icon: },
+ { name: "Archive", id: "Archive", icon: },
+ { name: "Junk", id: "Junk", icon: },
+ { name: "Forums", id: "CATEGORY_FORUMS", icon: },
+ { name: "Personal", id: ["CATEGORY_PERSONAL", "Personal"], icon: },
+ { name: "Promotions", id: "CATEGORY_PROMOTIONS", icon: },
+ { name: "Social", id: "CATEGORY_SOCIAL", icon: },
+ { name: "Updates", id: "CATEGORY_UPDATES", icon: },
+ { name: "Gmail", id: ["[Gmail]", "Gmail"], icon: }
+];
+
+interface PrimaryBox {
+ name: string;
+ id: string[] | string;
+ icon: JSX.Element;
+}
+
+const findBoxInPrimaryBoxesList = (
+ id: string
+): (Omit & { id: string }) | undefined => {
+ const foundBox = DEFAULT_PRIMARY_BOXES.find((box) => {
+ if (Array.isArray(box.id)) {
+ const found = box.id.find(
+ (item) => item.toLowerCase() == id.toLowerCase()
+ );
+
+ return found != undefined;
+ } else return box.id.toLowerCase() == id.toLowerCase();
+ });
+
+ if (foundBox) return { ...foundBox, id };
+};
+
+export default findBoxInPrimaryBoxesList;
diff --git a/src/utils/hooks/useAddBox.ts b/src/utils/hooks/useAddBox.ts
new file mode 100644
index 0000000..1cf3e1f
--- /dev/null
+++ b/src/utils/hooks/useAddBox.ts
@@ -0,0 +1,29 @@
+import Box from "@interfaces/box";
+
+import useStore from "@utils/hooks/useStore";
+
+import { addBoxStore, FolderType } from "@components/Boxes/Add";
+
+interface BoxOptions {
+ folderName?: string;
+ parentFolder?: Box;
+ folderType?: FolderType;
+}
+
+const useAddBox = (): ((boxOptions: BoxOptions) => void) => {
+ const setShowAddBox = useStore((state) => state.setShowAddBox);
+
+ const setFolderType = addBoxStore((state) => state.setFolderType);
+ const setParentFolder = addBoxStore((state) => state.setParentFolder);
+ const setFolderName = addBoxStore((state) => state.setFolderName);
+
+ return ({ folderName, parentFolder, folderType }: BoxOptions) => {
+ setShowAddBox(true);
+
+ if (folderType) setFolderType(folderType);
+ if (parentFolder) setParentFolder(parentFolder);
+ if (folderName) setFolderName(folderName);
+ };
+};
+
+export default useAddBox;
diff --git a/src/utils/hooks/useApiClient.ts b/src/utils/hooks/useApiClient.ts
new file mode 100644
index 0000000..8f3150b
--- /dev/null
+++ b/src/utils/hooks/useApiClient.ts
@@ -0,0 +1,87 @@
+import { z } from "zod";
+
+import { version } from "../../../package.json";
+import useFetchClient from "./useFetchClient";
+
+import { ApiSettingsModel } from "@dust-mail/structures";
+
+import ApiClient from "@interfaces/api";
+
+import { createBaseError, createResultFromUnknown } from "@utils/parseError";
+import parseZodOutput from "@utils/parseZodOutput";
+
+const useApiClient = (): ApiClient => {
+ const fetch = useFetchClient();
+
+ return {
+ async getChangelog() {
+ const response = await window
+ .fetch(
+ `https://raw.githubusercontent.com/${
+ import.meta.env.VITE_REPO
+ }/${version}/CHANGELOG.md`,
+ { method: "GET" }
+ )
+ .then((response) => response.text())
+ .then((data) => ({ ok: true as const, data }))
+ .catch((error) => {
+ return createBaseError({
+ kind: "GithubError",
+ message: JSON.stringify(error)
+ });
+ });
+
+ return response;
+ },
+ async getSettings(baseUrl?: string) {
+ return await fetch("/settings", {
+ baseUrl,
+ method: "GET",
+ sendAuth: false,
+ useMailSessionToken: false
+ })
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = ApiSettingsModel.safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ },
+ async login(baseUrl, password, username) {
+ const formData = new FormData();
+
+ if (password !== undefined) formData.append("password", password);
+ if (username !== undefined) formData.append("username", username);
+
+ return await fetch("/login", {
+ method: "POST",
+ contentType: "none",
+ baseUrl,
+ useMailSessionToken: false,
+ body: formData
+ })
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = z.string().safeParse(response.data);
+
+ const parsedOutput = parseZodOutput(output);
+
+ if (!parsedOutput.ok) {
+ return parsedOutput;
+ }
+
+ return { ...parsedOutput, data: undefined };
+ })
+ .catch(createResultFromUnknown);
+ }
+ };
+};
+
+export default useApiClient;
diff --git a/src/utils/hooks/useBoxes.ts b/src/utils/hooks/useBoxes.ts
new file mode 100644
index 0000000..d68a067
--- /dev/null
+++ b/src/utils/hooks/useBoxes.ts
@@ -0,0 +1,48 @@
+import useMailClient from "./useMailClient";
+import useUser from "./useUser";
+
+import { useCallback } from "react";
+import { useQuery } from "react-query";
+
+import { MailBox, MailBoxList, AppError } from "@dust-mail/structures";
+
+import findBoxFromBoxes from "@utils/findBox";
+import { createResultFromUnknown, errorToString } from "@utils/parseError";
+
+type UseBoxes = {
+ boxes: MailBoxList | void;
+ error: string | null;
+ findBox: (id: string) => MailBox | void;
+};
+
+const useBoxes = (): UseBoxes => {
+ const mailClient = useMailClient();
+
+ const user = useUser();
+
+ const { data: boxes, error } = useQuery(
+ ["boxes", user?.id],
+ async () => {
+ const result = await mailClient.list().catch(createResultFromUnknown);
+
+ if (result.ok) {
+ return result.data;
+ } else {
+ throw result.error;
+ }
+ }
+ );
+
+ const findBox = useCallback(
+ (id: string) => {
+ if (!boxes) return;
+
+ return findBoxFromBoxes(id, boxes);
+ },
+ [boxes]
+ );
+
+ return { boxes, error: error ? errorToString(error) : null, findBox };
+};
+
+export default useBoxes;
diff --git a/src/utils/hooks/useDeleteBox.ts b/src/utils/hooks/useDeleteBox.ts
new file mode 100644
index 0000000..cd27421
--- /dev/null
+++ b/src/utils/hooks/useDeleteBox.ts
@@ -0,0 +1,17 @@
+import useStore from "@utils/hooks/useStore";
+
+import { deleteBoxStore } from "@components/Boxes/Delete";
+
+const useDeleteBox = (): ((boxesToDelete: string[]) => void) => {
+ const setShowDeleteBox = useStore((state) => state.setShowDeleteItemsDialog);
+
+ const setBoxesToDelete = deleteBoxStore((state) => state.setBoxesToDelete);
+
+ return (boxesToDelete: string[]) => {
+ setShowDeleteBox(true);
+
+ setBoxesToDelete(boxesToDelete);
+ };
+};
+
+export default useDeleteBox;
diff --git a/src/utils/hooks/useFetchClient.ts b/src/utils/hooks/useFetchClient.ts
new file mode 100644
index 0000000..ae4888e
--- /dev/null
+++ b/src/utils/hooks/useFetchClient.ts
@@ -0,0 +1,117 @@
+import useSettings from "./useSettings";
+import useUser from "./useUser";
+
+import { ApiResponseModel } from "@dust-mail/structures";
+
+import { Result } from "@interfaces/result";
+
+import { createBaseError, parseError } from "@utils/parseError";
+import parseJsonAsync from "@utils/parseJson";
+import parseZodOutput from "@utils/parseZodOutput";
+
+type FetchFunction = (
+ url: string,
+ config?: {
+ body?: BodyInit;
+ params?: Record;
+ baseUrl?: string;
+ method?: "POST" | "GET" | "DELETE" | "PUT";
+ sendAuth?: boolean;
+ useMailSessionToken?: boolean;
+ contentType?: "json" | "form" | "none";
+ }
+) => Promise>;
+
+const useFetchClient = (): FetchFunction => {
+ const [settings] = useSettings();
+
+ const user = useUser();
+
+ const httpServerUrl = settings.httpServerUrl;
+
+ const fetch: FetchFunction = async (path, config) => {
+ const backendUrl = config?.baseUrl ?? httpServerUrl;
+
+ if (backendUrl == null) {
+ return createBaseError({
+ kind: "NoBackendUrl",
+ message: "Backend url for api server is not set"
+ });
+ }
+
+ const url = new URL(path, backendUrl);
+
+ if (config?.params !== undefined)
+ Object.entries(config.params).forEach(([key, value]) => {
+ url.searchParams.set(key, value);
+ });
+
+ if (config?.useMailSessionToken !== false && user?.token !== undefined)
+ url.searchParams.set("session_token", user.token);
+
+ if (typeof window === "undefined" || !("fetch" in window)) {
+ return createBaseError({
+ kind: "FetchUnsupported",
+ message: "The fetch api is not supported in this environment"
+ });
+ }
+
+ const headers = new Headers();
+
+ if (config?.contentType === "form") {
+ headers.append("Content-Type", "application/x-www-form-urlencoded");
+ } else if (config?.contentType !== "none") {
+ headers.append("Content-Type", "application/json");
+ }
+
+ return await window
+ .fetch(url.toString(), {
+ body: config?.body,
+ method: config?.method ?? "GET",
+ credentials: config?.sendAuth !== false ? "include" : "omit",
+ referrerPolicy: "no-referrer",
+ headers
+ })
+ .then(async (response) => {
+ const responseString = await response.text().catch(() => null);
+
+ if (responseString === null)
+ return createBaseError({
+ kind: "InvalidResponseBody",
+ message: "Invalid response body from server response"
+ });
+
+ return await parseJsonAsync(responseString)
+ .then((parsedOutput) => {
+ const parseOutputResult = ApiResponseModel.safeParse(parsedOutput);
+
+ const parsedZodOutput = parseZodOutput(parseOutputResult);
+
+ if (parsedZodOutput.ok) {
+ const serverResponseResult = parsedZodOutput.data;
+
+ // We have to do this ugly little workaround because the zod unknown parser returns an optional unknown in its ts type.
+ // See https://github.com/colinhacks/zod/issues/493
+ if (serverResponseResult.ok) {
+ return {
+ ...serverResponseResult,
+ data: serverResponseResult.data as unknown
+ };
+ } else {
+ return serverResponseResult;
+ }
+ } else {
+ return parsedZodOutput;
+ }
+ })
+ .catch((error: string) =>
+ createBaseError({ kind: "ParseJSON", message: error })
+ );
+ })
+ .catch(parseError);
+ };
+
+ return fetch;
+};
+
+export default useFetchClient;
diff --git a/src/utils/hooks/useLogin.ts b/src/utils/hooks/useLogin.ts
new file mode 100644
index 0000000..1fa37fe
--- /dev/null
+++ b/src/utils/hooks/useLogin.ts
@@ -0,0 +1,161 @@
+import useMailClient from "./useMailClient";
+import useUser, { useCurrentUser, useModifyUser } from "./useUser";
+
+import { useNavigate } from "react-router-dom";
+
+import {
+ Credentials,
+ LoginOptions,
+ ServerType,
+ Version
+} from "@dust-mail/structures";
+
+import { Result } from "@interfaces/result";
+
+import useStore from "@utils/hooks/useStore";
+import {
+ createBaseError,
+ createErrorFromUnknown,
+ parseError
+} from "@utils/parseError";
+
+// TODO: Fix this mess of a file.
+
+const findUsernameInLoginOptions = (loginOptions: LoginOptions): string => {
+ return (
+ loginOptions.loginType.oAuthBased?.username ??
+ loginOptions.loginType.passwordBased?.username ??
+ // Should never occur, but just in case it does happen there will be a fallback
+ "test@example.com"
+ );
+};
+
+const createIdentifier = (
+ incomingConfig: LoginOptions,
+ outgoingConfig: LoginOptions
+): string => {
+ const incomingUsername = findUsernameInLoginOptions(incomingConfig);
+ const outgoingUsername = findUsernameInLoginOptions(outgoingConfig);
+
+ const identifier = btoa(
+ `${incomingUsername}@${incomingConfig.domain}|${outgoingUsername}@${outgoingConfig.domain}`
+ );
+
+ return identifier;
+};
+
+export const useMailLogin = (): ((
+ config: Credentials
+) => Promise>) => {
+ const appVersion = useStore((state) => state.appVersion);
+ const setFetching = useStore((state) => state.setFetching);
+
+ const isTauri: boolean = "__TAURI__" in window;
+
+ const login = useLoginFromToken();
+
+ const mailClient = useMailClient();
+
+ return async (config) => {
+ // Show the fetching animation
+ setFetching(true);
+
+ if (!isTauri) {
+ console.log("Checking if server version matches with client version...");
+
+ const versionResponseResult = await mailClient
+ .getVersion()
+ .catch((error) => createBaseError(createErrorFromUnknown(error)));
+
+ if (!versionResponseResult.ok) {
+ return versionResponseResult;
+ }
+
+ const { version: serverVersion, type: serverVersionType }: Version =
+ versionResponseResult.data;
+
+ if (serverVersion != appVersion.title) {
+ setFetching(false);
+
+ return createBaseError({
+ message: `Server and client versions did not match, server has version ${serverVersion} (${serverVersionType}) while client has version ${appVersion.title} (${appVersion.type})`,
+ kind: "VersionMismatch"
+ });
+ }
+ }
+
+ console.log("Sending login request...");
+
+ // Request the login token
+ const loginResult = await mailClient
+ .login(config)
+ // If there was anything wrong with the request, catch it
+ .catch(parseError);
+
+ if (!loginResult.ok) {
+ setFetching(false);
+
+ return loginResult;
+ }
+
+ const incomingConfig = config.incoming;
+ // Outgoing config is incoming because there is no support for outgoing servers yet.
+ const outgoingConfig = config.incoming;
+
+ if (incomingConfig === undefined || outgoingConfig === undefined)
+ return createBaseError({
+ kind: "ConfigNotComplete",
+ message: "Config is missing items"
+ });
+
+ const id = createIdentifier(incomingConfig, outgoingConfig);
+
+ login(loginResult.data, {
+ id,
+ usernames: {
+ incoming: findUsernameInLoginOptions(incomingConfig),
+ outgoing: findUsernameInLoginOptions(outgoingConfig)
+ },
+ redirectToDashboard: true,
+ setAsDefault: true
+ });
+
+ setFetching(false);
+
+ return { ok: true, data: undefined };
+ };
+};
+
+const useLoginFromToken = (): ((
+ token: string,
+ options?: {
+ id: string;
+ usernames: Record;
+ redirectToDashboard?: boolean;
+ setAsDefault?: boolean;
+ }
+) => void) => {
+ const modifyUser = useModifyUser();
+ const [, setCurrentUser] = useCurrentUser();
+
+ const user = useUser();
+
+ const navigate = useNavigate();
+
+ return (token, options) => {
+ const id = options?.id ?? user?.id;
+ const usernames = options?.usernames ?? user?.usernames;
+
+ if (id === undefined || usernames === undefined) return;
+
+ console.log("Successfully authorized with mail servers");
+
+ modifyUser(id, { token, id, usernames });
+
+ setCurrentUser(id);
+
+ if (options?.redirectToDashboard) navigate(`/dashboard`);
+ };
+};
+
+export default useLoginFromToken;
diff --git a/src/utils/hooks/useLogout.ts b/src/utils/hooks/useLogout.ts
new file mode 100644
index 0000000..1ba360d
--- /dev/null
+++ b/src/utils/hooks/useLogout.ts
@@ -0,0 +1,43 @@
+import useMailClient from "./useMailClient";
+import useSelectedStore from "./useSelected";
+import { useCurrentUser, useRemoveUser, useUsers } from "./useUser";
+
+import { useCallback } from "react";
+
+import useStore from "@utils/hooks/useStore";
+
+const useLogout = (): (() => void) => {
+ const removeUser = useRemoveUser();
+
+ const [users] = useUsers();
+
+ const [currentUser, setCurrentUser] = useCurrentUser();
+
+ const mailClient = useMailClient();
+
+ const setSelectedBox = useSelectedStore((state) => state.setSelectedBox);
+
+ const setFetching = useStore((state) => state.setFetching);
+
+ const logout = useCallback(async (): Promise => {
+ setFetching(false);
+
+ if (!currentUser || !users) return;
+
+ await mailClient.logout();
+
+ removeUser(currentUser?.id);
+
+ const newCurrentUser = users
+ .filter((user) => user.id != currentUser.id)
+ ?.shift();
+
+ setCurrentUser(newCurrentUser?.id);
+
+ if (newCurrentUser?.id) setSelectedBox();
+ }, [users, currentUser, setFetching]);
+
+ return logout;
+};
+
+export default useLogout;
diff --git a/src/utils/hooks/useMailClient.ts b/src/utils/hooks/useMailClient.ts
new file mode 100644
index 0000000..cd040fe
--- /dev/null
+++ b/src/utils/hooks/useMailClient.ts
@@ -0,0 +1,272 @@
+import { invoke } from "@tauri-apps/api/tauri";
+import z from "zod";
+
+import useFetchClient from "./useFetchClient";
+import useUser from "./useUser";
+
+import {
+ CredentialsModel,
+ MailBoxListModel,
+ MailBoxModel,
+ MailConfigModel,
+ MessageModel,
+ PreviewModel,
+ VersionModel
+} from "@dust-mail/structures";
+
+import { messageCountForPage } from "@src/constants";
+
+import MailClient from "@interfaces/client";
+
+import { MissingRequiredParam, NotLoggedIn } from "@utils/defaultErrors";
+import parseEmail from "@utils/parseEmail";
+import {
+ createBaseError,
+ createResultFromUnknown,
+ parseError
+} from "@utils/parseError";
+import parseZodOutput from "@utils/parseZodOutput";
+
+const useMailClient = (): MailClient => {
+ const isTauri: boolean = "__TAURI__" in window;
+
+ const user = useUser();
+
+ const fetch = useFetchClient();
+
+ return {
+ async getVersion() {
+ if (isTauri) {
+ return createBaseError({
+ message: "Version check is not needed in Tauri application",
+ kind: "Unsupported"
+ });
+ }
+
+ return fetch("/version", {
+ method: "GET",
+ useMailSessionToken: false,
+ sendAuth: false
+ })
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = VersionModel.safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ },
+ async detectConfig(emailAddress) {
+ const emailAddressParsed = parseEmail(emailAddress);
+
+ if (!emailAddressParsed.ok) {
+ return emailAddressParsed;
+ }
+
+ emailAddress = emailAddressParsed.data.full;
+
+ if (isTauri) {
+ return invoke("detect_config", { emailAddress })
+ .then((data: unknown) => {
+ const output = MailConfigModel.safeParse(data);
+
+ return parseZodOutput(output);
+ })
+ .catch(parseError);
+ }
+
+ return fetch(`/detect/${emailAddress}`, {
+ method: "GET",
+ useMailSessionToken: false
+ })
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = MailConfigModel.safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ },
+ async login(options) {
+ const optionsResult = parseZodOutput(CredentialsModel.safeParse(options));
+
+ if (!optionsResult.ok) {
+ return optionsResult;
+ }
+
+ if (isTauri) {
+ return invoke("login", { credentials: optionsResult.data })
+ .then((data: unknown) => {
+ const output = z.string().safeParse(data);
+
+ return parseZodOutput(output);
+ })
+ .catch(parseError);
+ }
+
+ return fetch(`/mail/login`, {
+ method: "POST",
+ body: JSON.stringify(optionsResult.data),
+ useMailSessionToken: false
+ })
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = z.string().safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ },
+ async logout() {
+ const okResponse = { ok: true, data: undefined } as const;
+
+ if (isTauri) {
+ const token = user?.token;
+
+ return invoke("logout", { token })
+ .then(() => okResponse)
+ .catch(parseError);
+ }
+
+ return fetch("/mail/logout", { method: "POST" })
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ return okResponse;
+ })
+ .catch(createResultFromUnknown);
+ },
+ async get(boxId) {
+ if (boxId === undefined) return MissingRequiredParam();
+
+ if (isTauri) {
+ const token = user?.token;
+
+ if (token === undefined) return NotLoggedIn();
+
+ return invoke("get", { token, boxId })
+ .then((data: unknown) => {
+ const output = MailBoxModel.safeParse(data);
+
+ return parseZodOutput(output);
+ })
+ .catch(parseError);
+ }
+
+ return fetch(`/mail/boxes/${boxId}`)
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = MailBoxModel.safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ },
+ async list() {
+ if (isTauri) {
+ const token = user?.token;
+
+ if (!token) return NotLoggedIn();
+
+ return invoke("list", { token })
+ .then((data: unknown) => {
+ const output = MailBoxListModel.safeParse(data);
+
+ return parseZodOutput(output);
+ })
+ .catch(parseError);
+ }
+
+ return fetch("/mail/boxes/list")
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = MailBoxListModel.safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ },
+ async messageList(page, boxId) {
+ if (!boxId) return MissingRequiredParam();
+
+ const start = page * messageCountForPage;
+ const end = page * messageCountForPage + messageCountForPage;
+
+ if (isTauri) {
+ const token = user?.token;
+
+ if (!token) return NotLoggedIn();
+
+ return invoke("messages", { token, boxId, start, end })
+ .then((data: unknown) => {
+ const output = PreviewModel.array().safeParse(data);
+
+ return parseZodOutput(output);
+ })
+ .catch(parseError);
+ }
+
+ return fetch(`/mail/boxes/${boxId}/messages`, {
+ params: { start: start.toString(), end: end.toString() }
+ })
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = PreviewModel.array().safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ },
+ async getMessage(messageId, boxId) {
+ if (!boxId || !messageId) return MissingRequiredParam();
+
+ if (isTauri) {
+ const token = user?.token;
+
+ if (!token) return NotLoggedIn();
+
+ return invoke("get_message", { token, boxId, messageId })
+ .then((data: unknown) => {
+ const output = MessageModel.safeParse(data);
+
+ return parseZodOutput(output);
+ })
+ .catch(parseError);
+ }
+
+ return fetch(`/mail/boxes/${boxId}/${messageId}`)
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = MessageModel.safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+ }
+ };
+};
+
+export default useMailClient;
diff --git a/src/utils/hooks/useMessageActions.tsx b/src/utils/hooks/useMessageActions.tsx
new file mode 100644
index 0000000..0eb6705
--- /dev/null
+++ b/src/utils/hooks/useMessageActions.tsx
@@ -0,0 +1,37 @@
+import useSnackbar from "./useSnackbar";
+
+import DeleteIcon from "@mui/icons-material/Delete";
+import FolderMoveIcon from "@mui/icons-material/DriveFileMove";
+import ForwardIcon from "@mui/icons-material/Forward";
+import DetailsIcon from "@mui/icons-material/Info";
+import ReplyIcon from "@mui/icons-material/Reply";
+
+import MessageAction from "@interfaces/messageAction";
+
+const useMessageActions = (): MessageAction[] => {
+ const showSnackbar = useSnackbar();
+
+ const actions: MessageAction[] = [
+ {
+ name: "Move message",
+ icon: ,
+ handler: (message) => console.log(message?.id)
+ },
+ {
+ name: "Forward message",
+ icon: ,
+ handler: () => showSnackbar("yeet")
+ },
+ {
+ name: "Reply",
+ icon: ,
+ handler: () => null
+ },
+ { name: "Delete message", icon: , handler: () => null },
+ { name: "Show details", icon: , handler: () => null }
+ ];
+
+ return actions;
+};
+
+export default useMessageActions;
diff --git a/src/utils/hooks/useMultiServerLoginStore.ts b/src/utils/hooks/useMultiServerLoginStore.ts
new file mode 100644
index 0000000..ee1da51
--- /dev/null
+++ b/src/utils/hooks/useMultiServerLoginStore.ts
@@ -0,0 +1,183 @@
+import create from "zustand";
+
+import {
+ IncomingMailServerTypeModel,
+ OutgoingMailServerTypeModel,
+ IncomingMailServerType,
+ OutgoingMailServerType,
+ IncomingServerType,
+ OutgoingServerType,
+ ServerType,
+ MailServerType,
+ ConnectionSecurity,
+ LoginOptions
+} from "@dust-mail/structures";
+
+export type MultiServerLoginOptions = {
+ password: string;
+ username: string;
+} & Omit;
+
+type Store = Record<
+ IncomingServerType,
+ Record
+> &
+ Record<
+ OutgoingServerType,
+ Record
+ > & {
+ showMenu: boolean;
+ setShowMenu: (show: boolean) => void;
+ provider?: string;
+ setProvider: (provider?: string) => void;
+ selectedMailServerType: Record &
+ Record;
+ setSelectedMailServerType: (
+ type: ServerType,
+ mailType: MailServerType
+ ) => void;
+ error?: string;
+ setError: (error?: string) => void;
+ setLoginOptions: (
+ type: ServerType,
+ mailType: MailServerType,
+ options: Partial
+ ) => void;
+ resetToDefaults: () => void;
+ setLoginOptionsProperty: (
+ type: ServerType,
+ mailType: MailServerType
+ ) => (
+ property: keyof MultiServerLoginOptions
+ ) => (newValue?: string | number) => void;
+ };
+
+export const defaultIncomingServer: IncomingMailServerType = "Imap" as const;
+export const defaultOutgoingServer: OutgoingMailServerType = "Smtp" as const;
+
+export const defaultUsername = "" as const;
+export const defaultPassword = "" as const;
+
+export const defaultPorts: Record = {
+ Imap: 993,
+ Pop: 995,
+ Exchange: 443,
+ Smtp: 465
+} as const;
+
+export const defaultSecuritySetting: ConnectionSecurity = "Tls";
+
+const defaultImapConfig: MultiServerLoginOptions = {
+ username: defaultUsername,
+ password: defaultPassword,
+ domain: "imap.example.com",
+ security: defaultSecuritySetting,
+ port: defaultPorts["Imap"]
+};
+
+const defaultExchangeConfig: MultiServerLoginOptions = {
+ username: defaultUsername,
+ password: defaultPassword,
+ domain: "exchange.example.com",
+ security: defaultSecuritySetting,
+ port: defaultPorts["Exchange"]
+};
+
+const defaultPopConfig: MultiServerLoginOptions = {
+ username: defaultUsername,
+ password: defaultPassword,
+ domain: "pop.example.com",
+ security: defaultSecuritySetting,
+ port: defaultPorts["Pop"]
+};
+
+const defaultSmtpConfig: MultiServerLoginOptions = {
+ username: defaultUsername,
+ password: defaultPassword,
+ domain: "smtp.example.com",
+ security: defaultSecuritySetting,
+ port: defaultPorts["Smtp"]
+};
+
+export const defaultConfigs = {
+ incoming: {
+ Imap: defaultImapConfig,
+ Exchange: defaultExchangeConfig,
+ Pop: defaultPopConfig
+ },
+ outgoing: {
+ Smtp: defaultSmtpConfig
+ }
+};
+
+const useMultiServerLoginStore = create((set) => ({
+ ...defaultConfigs,
+ showMenu: false,
+ setShowMenu: (show) => set({ showMenu: show }),
+ provider: undefined,
+ setProvider: (provider) => set({ provider }),
+ error: undefined,
+ setError: (error) => set({ error }),
+ selectedMailServerType: {
+ incoming: defaultIncomingServer,
+ outgoing: defaultOutgoingServer
+ },
+ setSelectedMailServerType: (type, mailType) =>
+ set((state) => ({
+ selectedMailServerType: {
+ ...state.selectedMailServerType,
+ [type]: mailType
+ }
+ })),
+ setLoginOptions: (type, mailType, options) => {
+ set((state) => ({
+ [type]: {
+ ...state[type],
+ [mailType]: options
+ }
+ }));
+ },
+ resetToDefaults: () =>
+ set({
+ ...defaultConfigs,
+ provider: undefined,
+ selectedMailServerType: {
+ incoming: defaultIncomingServer,
+ outgoing: defaultOutgoingServer
+ }
+ }),
+ setLoginOptionsProperty: (type, mailType) => (property) => (newValue) =>
+ set((state) => {
+ switch (type) {
+ case "incoming":
+ // eslint-disable-next-line no-case-declarations
+ const incomingMailType = IncomingMailServerTypeModel.parse(mailType);
+
+ return {
+ [type]: {
+ ...state[type],
+ [mailType]: {
+ ...state[type][incomingMailType],
+ [property]: newValue
+ }
+ }
+ };
+
+ case "outgoing":
+ // eslint-disable-next-line no-case-declarations
+ const outgoingMailType = OutgoingMailServerTypeModel.parse(mailType);
+
+ return {
+ [type]: {
+ ...state[type],
+ [mailType]: {
+ ...state[type][outgoingMailType],
+ [property]: newValue
+ }
+ }
+ };
+ }
+ })
+}));
+
+export default useMultiServerLoginStore;
diff --git a/src/utils/hooks/useOAuth2Client.ts b/src/utils/hooks/useOAuth2Client.ts
new file mode 100644
index 0000000..74e7048
--- /dev/null
+++ b/src/utils/hooks/useOAuth2Client.ts
@@ -0,0 +1,143 @@
+import z from "zod";
+
+import useFetchClient from "./useFetchClient";
+import useSettings from "./useSettings";
+
+import { OAuthState } from "@dust-mail/structures";
+
+import OAuth2Client from "@interfaces/oauth2";
+import { Result } from "@interfaces/result";
+
+import { NotImplemented } from "@utils/defaultErrors";
+import { createBaseError, createResultFromUnknown } from "@utils/parseError";
+import parseZodOutput from "@utils/parseZodOutput";
+
+const useGetPublicOAuthTokens = (): (() => Promise<
+ Result>
+>) => {
+ const fetch = useFetchClient();
+
+ return () =>
+ fetch("/mail/oauth2/tokens")
+ .then((response) => {
+ if (!response.ok) {
+ return response;
+ }
+
+ const output = z
+ .record(z.string(), z.string())
+ .safeParse(response.data);
+
+ return parseZodOutput(output);
+ })
+ .catch(createResultFromUnknown);
+};
+
+const findProviderToken = (
+ providerName: string,
+ tokens: Record
+): [string, string] | null => {
+ for (const [key, value] of Object.entries(tokens)) {
+ const isProvider = providerName
+ .toLowerCase()
+ .includes(key.trim().toLowerCase());
+
+ if (isProvider) return [value, key];
+ }
+
+ return null;
+};
+
+const useOAuth2Client = (): OAuth2Client => {
+ const isTauri: boolean = "__TAURI__" in window;
+
+ const getPublicTokens = useGetPublicOAuthTokens();
+
+ const [settings] = useSettings();
+
+ return {
+ async getGrant(providerName, authUrl, tokenUrl, scopes) {
+ const authUrlResult = z.string().url().safeParse(authUrl);
+
+ const authUrlOutput = parseZodOutput(authUrlResult);
+
+ if (!authUrlOutput.ok) {
+ return authUrlOutput;
+ }
+
+ if (settings.httpServerUrl === null)
+ return createBaseError({
+ kind: "NoBackend",
+ message: "Backend server url is not set"
+ });
+
+ const publicTokensResult = await getPublicTokens().catch(
+ createResultFromUnknown
+ );
+
+ if (!publicTokensResult.ok) {
+ return publicTokensResult;
+ }
+
+ const publicTokens = publicTokensResult.data;
+
+ const providerDetails = findProviderToken(providerName, publicTokens);
+
+ if (providerDetails === null)
+ return createBaseError({
+ kind: "NoOAuthToken",
+ message:
+ "Could not find a oauth token on remote Dust-Mail server to authorize with email provider"
+ });
+
+ const providerToken = providerDetails[0];
+ const providerId = providerDetails[1];
+
+ if (!isTauri) {
+ if (typeof window !== "undefined" && "open" in window) {
+ const url = new URL(authUrlOutput.data);
+ const redirectUri = new URL(
+ "/mail/oauth2/redirect",
+ settings.httpServerUrl
+ );
+
+ const state: OAuthState = {
+ provider: providerId,
+ application: isTauri ? "desktop" : "web"
+ };
+
+ // https://www.rfc-editor.org/rfc/rfc6749#section-1.1
+ url.searchParams.set("response_type", "code");
+ url.searchParams.set("redirect_uri", redirectUri.toString());
+ url.searchParams.set("client_id", providerToken);
+ url.searchParams.set("scope", scopes.join(" "));
+ url.searchParams.set("state", JSON.stringify(state));
+ url.searchParams.set("access_type", "offline");
+
+ const oauthLoginWindow = window.open(url, "_blank", "popup");
+
+ if (oauthLoginWindow === null)
+ return createBaseError({
+ kind: "UnsupportedEnvironment",
+ message:
+ "Your browser environment does not support intercommunication between windows"
+ });
+
+ oauthLoginWindow.addEventListener("message", console.log);
+
+ return { ok: true as const, data: "" };
+ } else {
+ return createBaseError({
+ kind: "UnsupportedEnvironment",
+ message:
+ "Your browser environment does not support opening a new window"
+ });
+ }
+ }
+
+ return NotImplemented("oauth-grant-tauri");
+ }
+ };
+};
+
+export default useOAuth2Client;
diff --git a/src/utils/hooks/useRenameBox.ts b/src/utils/hooks/useRenameBox.ts
new file mode 100644
index 0000000..7765a51
--- /dev/null
+++ b/src/utils/hooks/useRenameBox.ts
@@ -0,0 +1,19 @@
+import Box from "@interfaces/box";
+
+import useStore from "@utils/hooks/useStore";
+
+import { renameBoxStore } from "@components/Boxes/Rename";
+
+const useRenameBox = (): ((boxToRename: Box) => void) => {
+ const setShowRenameBox = useStore((state) => state.setShowRenameBoxDialog);
+
+ const setBoxToRename = renameBoxStore((state) => state.setBoxToRename);
+
+ return (boxToRename: Box) => {
+ setShowRenameBox(true);
+
+ setBoxToRename(boxToRename);
+ };
+};
+
+export default useRenameBox;
diff --git a/src/utils/hooks/useSelected.ts b/src/utils/hooks/useSelected.ts
new file mode 100644
index 0000000..50e7bbb
--- /dev/null
+++ b/src/utils/hooks/useSelected.ts
@@ -0,0 +1,22 @@
+import create from "zustand";
+
+interface SelectedStore {
+ selectedBox?: string;
+ setSelectedBox: (id?: string) => void;
+ selectedMessage?: string;
+ setSelectedMessage: (id?: string) => void;
+}
+
+const useSelectedStore = create((set) => ({
+ setSelectedBox: (id) =>
+ set((state) => {
+ return {
+ selectedBox: id,
+ selectedMessage:
+ id == state.selectedBox ? state.selectedMessage : undefined
+ };
+ }),
+ setSelectedMessage: (id) => set({ selectedMessage: id })
+}));
+
+export default useSelectedStore;
diff --git a/src/utils/hooks/useSelectedBox.ts b/src/utils/hooks/useSelectedBox.ts
new file mode 100644
index 0000000..69d58e1
--- /dev/null
+++ b/src/utils/hooks/useSelectedBox.ts
@@ -0,0 +1,80 @@
+import useMailClient from "./useMailClient";
+import useSelectedStore from "./useSelected";
+
+import { useMemo } from "react";
+import { useQuery } from "react-query";
+
+import { AppError, MailBox } from "@dust-mail/structures";
+
+import Box from "@interfaces/box";
+
+import findBoxInPrimaryBoxesList from "@utils/findBoxInPrimaryBoxesList";
+import {
+ createBaseError,
+ createErrorFromUnknown,
+ errorToString
+} from "@utils/parseError";
+
+interface UseSelectedBox {
+ box: Box | null;
+ error: string | null;
+ setSelectedBox: (boxID?: string) => void;
+}
+
+export const useSetSelectedBox = (): ((id?: string) => void) => {
+ const setSelectedBox = useSelectedStore((state) => state.setSelectedBox);
+
+ return setSelectedBox;
+};
+
+const defaultBox: (boxId: string) => Box = (boxId) => ({
+ children: [],
+ counts: null,
+ delimiter: null,
+ id: boxId,
+ selectable: true,
+ name: ""
+});
+
+const useSelectedBox = (): UseSelectedBox => {
+ const setSelectedBox = useSetSelectedBox();
+
+ const boxId = useSelectedStore((state) => state.selectedBox);
+
+ const mailClient = useMailClient();
+
+ const { data, error } = useQuery(
+ ["box", boxId],
+ async () => {
+ const result = await mailClient
+ .get(boxId)
+ .catch((error) => createBaseError(createErrorFromUnknown(error)));
+
+ if (result.ok) return result.data;
+ else throw result.error;
+ },
+ {
+ enabled: boxId !== undefined
+ }
+ );
+
+ const selectedBox: UseSelectedBox = useMemo(() => {
+ const primaryBoxData = data
+ ? findBoxInPrimaryBoxesList(data.id)
+ : undefined;
+
+ return {
+ box: boxId
+ ? data
+ ? { ...data, icon: primaryBoxData?.icon }
+ : defaultBox(boxId)
+ : null,
+ error: error ? errorToString(error) : null,
+ setSelectedBox
+ };
+ }, [data, error, setSelectedBox]);
+
+ return selectedBox;
+};
+
+export default useSelectedBox;
diff --git a/src/utils/hooks/useSelectedMessage.ts b/src/utils/hooks/useSelectedMessage.ts
new file mode 100644
index 0000000..2913e12
--- /dev/null
+++ b/src/utils/hooks/useSelectedMessage.ts
@@ -0,0 +1,94 @@
+// import useLocalStorageState from "use-local-storage-state";
+import useMailClient from "./useMailClient";
+import useSelectedStore from "./useSelected";
+import useUser from "./useUser";
+
+import { useEffect, useMemo } from "react";
+import { useQuery } from "react-query";
+
+import { AppError, Message } from "@dust-mail/structures";
+
+import useSelectedBox from "@utils/hooks/useSelectedBox";
+import useStore from "@utils/hooks/useStore";
+import { createResultFromUnknown } from "@utils/parseError";
+
+interface UseSelectedMessage {
+ selectedMessage: Message | undefined;
+ selectedMessageError: AppError | null;
+ selectedMessageFetching: boolean;
+}
+
+export const useSetSelectedMessage = (): ((id?: string) => void) => {
+ const setSelectedMessage = useSelectedStore(
+ (state) => state.setSelectedMessage
+ );
+
+ return setSelectedMessage;
+};
+
+const defaultMessage: (messageId: string) => Message = (messageId) => ({
+ id: messageId,
+ bcc: [],
+ cc: [],
+ to: [],
+ headers: {},
+ subject: null,
+ content: { html: null, text: null },
+ sent: Date.now(),
+ flags: ["Read"],
+ from: []
+});
+
+const useSelectedMessage = (): UseSelectedMessage => {
+ const { box: selectedBox } = useSelectedBox();
+
+ const mailClient = useMailClient();
+
+ const setFetching = useStore((state) => state.setFetching);
+
+ const user = useUser();
+
+ // const [darkMode] = useLocalStorageState("messageDarkMode", {
+ // defaultValue: false
+ // });
+
+ // const [showImages] = useLocalStorageState("showImages", {
+ // defaultValue: false
+ // });
+
+ const messageId = useSelectedStore((state) => state.selectedMessage);
+
+ const { data, isFetching, error } = useQuery(
+ ["message", messageId, selectedBox?.id],
+ async () => {
+ const result = await mailClient
+ .getMessage(messageId, selectedBox?.id)
+ .catch(createResultFromUnknown);
+
+ if (result.ok) return result.data;
+ else throw result.error;
+ },
+ {
+ enabled:
+ messageId != undefined &&
+ selectedBox?.id != undefined &&
+ selectedBox.selectable &&
+ user?.token != undefined
+ }
+ );
+
+ useEffect(() => setFetching(isFetching), [isFetching]);
+
+ return useMemo(
+ () => ({
+ selectedMessage: messageId
+ ? data ?? defaultMessage(messageId)
+ : undefined,
+ selectedMessageError: error,
+ selectedMessageFetching: isFetching
+ }),
+ [data, error, isFetching]
+ );
+};
+
+export default useSelectedMessage;
diff --git a/src/utils/hooks/useSettings.ts b/src/utils/hooks/useSettings.ts
new file mode 100644
index 0000000..926ad4c
--- /dev/null
+++ b/src/utils/hooks/useSettings.ts
@@ -0,0 +1,29 @@
+import useLocalStorageState from "use-local-storage-state";
+
+import { useCallback } from "react";
+
+import Settings from "@components/Settings";
+
+export interface Settings {
+ httpServerUrl: string | null;
+}
+
+const useSettings = (): [
+ Settings,
+ (setting: keyof Settings, value: string | null) => void
+] => {
+ const [settings, setValue] = useLocalStorageState("settings", {
+ defaultValue: { httpServerUrl: import.meta.env.VITE_DEFAULT_SERVER }
+ });
+
+ const setSetting = useCallback(
+ (setting: keyof Settings, value: string | null) => {
+ setValue({ ...settings, [setting]: value });
+ },
+ [settings]
+ );
+
+ return [settings, setSetting];
+};
+
+export default useSettings;
diff --git a/src/utils/hooks/useSnackbar.ts b/src/utils/hooks/useSnackbar.ts
new file mode 100644
index 0000000..da1ec91
--- /dev/null
+++ b/src/utils/hooks/useSnackbar.ts
@@ -0,0 +1,18 @@
+import { useSnackbarStore } from "@components/Snackbar";
+
+const useSnackbar = (): ((
+ message: string,
+ variant?: "error" | "success"
+) => void) => {
+ const setMessage = useSnackbarStore((state) => state.setMessage);
+ const setVariant = useSnackbarStore((state) => state.setVariant);
+ const setOpen = useSnackbarStore((state) => state.setOpen);
+
+ return (message, variant) => {
+ setMessage(message);
+ setVariant(variant ?? "success");
+ setOpen(true);
+ };
+};
+
+export default useSnackbar;
diff --git a/src/utils/hooks/useStore.ts b/src/utils/hooks/useStore.ts
new file mode 100644
index 0000000..820c7a8
--- /dev/null
+++ b/src/utils/hooks/useStore.ts
@@ -0,0 +1,56 @@
+import create from "zustand";
+
+import { version as appVersion } from "../../../package.json";
+
+interface Store {
+ fetching: boolean;
+ setFetching: (fetching: boolean) => void;
+ showAddBox: boolean;
+ setShowAddBox: (show: boolean) => void;
+ showAbout: boolean;
+ setShowAbout: (show: boolean) => void;
+ showDeleteItemsDialog: boolean;
+ setShowDeleteItemsDialog: (show: boolean) => void;
+ showRenameBoxDialog: boolean;
+ setShowRenameBoxDialog: (showRenameBoxDialog: boolean) => void;
+ showSettings: boolean;
+ setShowSettings: (show: boolean) => void;
+ toggleShowSettings: () => void;
+ showChangelog: boolean;
+ setShowChangelog: (show: boolean) => void;
+ showMessageComposer: boolean;
+ setShowMessageComposer: (open: boolean) => void;
+ appVersion: { title: string; type: "git" | "stable" };
+}
+
+const createStore = create((set) => ({
+ fetching: false,
+ setFetching: (fetching: boolean) => set({ fetching }),
+ showAbout: false,
+ setShowAbout: (showAbout) =>
+ set((state) => ({
+ showAbout,
+ showSettings: showAbout === true ? false : state.showSettings
+ })),
+ showDeleteItemsDialog: false,
+ setShowDeleteItemsDialog: (showDeleteItemsDialog) =>
+ set({ showDeleteItemsDialog }),
+ showAddBox: false,
+ setShowAddBox: (showAddBox) => set({ showAddBox }),
+ showRenameBoxDialog: false,
+ setShowRenameBoxDialog: (showRenameBoxDialog) => set({ showRenameBoxDialog }),
+ showSettings: false,
+ setShowSettings: (showSettings) => set({ showSettings }),
+ toggleShowSettings: () =>
+ set(({ showSettings }) => ({ showSettings: !showSettings })),
+ showChangelog: false,
+ setShowChangelog: (show) => set({ showChangelog: show }),
+ showMessageComposer: false,
+ setShowMessageComposer: (open) => set({ showMessageComposer: open }),
+ appVersion: {
+ title: appVersion,
+ type: import.meta.env.VITE_UNSTABLE != undefined ? "git" : "stable"
+ }
+}));
+
+export default createStore;
diff --git a/src/utils/hooks/useTheme.ts b/src/utils/hooks/useTheme.ts
new file mode 100644
index 0000000..531dbec
--- /dev/null
+++ b/src/utils/hooks/useTheme.ts
@@ -0,0 +1,37 @@
+import useLocalStorageState from "use-local-storage-state";
+
+import { useMemo } from "react";
+
+import { blue, orange } from "@mui/material/colors";
+import createTheme, { Theme } from "@mui/material/styles/createTheme";
+import useMediaQuery from "@mui/material/useMediaQuery";
+
+const useTheme = (): Theme => {
+ let darkMode = true;
+
+ darkMode = useMediaQuery("(prefers-color-scheme: dark)");
+
+ const [hasDarkModeInSettings] = useLocalStorageState("darkMode");
+
+ if (hasDarkModeInSettings !== undefined) darkMode = hasDarkModeInSettings;
+
+ const theme = useMemo(
+ () =>
+ createTheme({
+ palette: {
+ mode: darkMode ? "dark" : "light",
+ primary: {
+ main: blue[500]
+ },
+ secondary: {
+ main: orange[500]
+ }
+ }
+ }),
+ [hasDarkModeInSettings]
+ );
+
+ return theme;
+};
+
+export default useTheme;
diff --git a/src/utils/hooks/useUser.ts b/src/utils/hooks/useUser.ts
new file mode 100644
index 0000000..9d27a6d
--- /dev/null
+++ b/src/utils/hooks/useUser.ts
@@ -0,0 +1,101 @@
+import useLocalStorageState from "use-local-storage-state";
+
+import useSelectedStore from "./useSelected";
+
+import { useCallback, useMemo } from "react";
+
+import User from "@interfaces/user";
+
+export const useUsers = (): [
+ users: User[] | undefined,
+ setUsers: (users: User[], oldUsers?: User[]) => void
+] => {
+ const [users, setUsers] = useLocalStorageState("users", {
+ defaultValue: []
+ });
+
+ const setNewUsers = useCallback(
+ (newUsers: User[], oldUsers: User[] = []) =>
+ setUsers([...oldUsers, ...newUsers]),
+ [setUsers]
+ );
+
+ return [users, setNewUsers];
+};
+
+export const useCurrentUser = (): [
+ currentUser: User | undefined,
+ setCurrentUser: (id?: string) => void
+] => {
+ const [users] = useUsers();
+
+ const [currentUserId, setUsername] =
+ useLocalStorageState("currentUser");
+
+ const setSelectedBox = useSelectedStore((state) => state.setSelectedBox);
+
+ const setUser = useCallback(
+ (id?: string) => {
+ setUsername(id);
+ setSelectedBox();
+ },
+ [setSelectedBox]
+ );
+
+ const [currentUser, setCurrentUser] = useMemo(() => {
+ const user = users?.find((user) => user.id == currentUserId);
+
+ return [user, setUser];
+ }, [currentUserId, users]);
+
+ return [currentUser, setCurrentUser];
+};
+
+export const useAddUser = (): ((user: User) => void) => {
+ const [users, setUsers] = useUsers();
+
+ return (user) => {
+ if (!users) return;
+
+ setUsers([user], users);
+ };
+};
+
+export const useRemoveUser = (): ((id: string) => void) => {
+ const [users, setUsers] = useUsers();
+
+ return useCallback(
+ (id) => {
+ if (!users) return;
+
+ setUsers(
+ [],
+ users.filter((user) => user.id != id)
+ );
+ },
+ [users, setUsers]
+ );
+};
+
+export const useModifyUser = (): ((id: string, newUser: User) => void) => {
+ const [users, setUsers] = useUsers();
+
+ return (id, newUser) => {
+ if (!users) return;
+
+ setUsers(
+ [newUser],
+ users.filter((user) => user.id != id)
+ );
+ };
+};
+
+const useUser = (): User | undefined => {
+ const [currentUser] = useCurrentUser();
+
+ const user = useMemo(() => currentUser, [currentUser]);
+
+ return user;
+};
+
+export default useUser;
diff --git a/src/utils/hooks/useWindowWidth.ts b/src/utils/hooks/useWindowWidth.ts
new file mode 100644
index 0000000..63d7613
--- /dev/null
+++ b/src/utils/hooks/useWindowWidth.ts
@@ -0,0 +1,19 @@
+import { useEffect, useState } from "react";
+
+const useWindowWidth = (): number => {
+ const [windowWidth, setWindowWidth] = useState(window.innerWidth);
+
+ const setter = (): void => {
+ setWindowWidth(window.innerWidth);
+ };
+
+ useEffect(() => {
+ window.addEventListener("resize", setter);
+
+ return () => window.removeEventListener("resize", setter);
+ }, []);
+
+ return windowWidth;
+};
+
+export default useWindowWidth;
diff --git a/src/utils/parseEmail.ts b/src/utils/parseEmail.ts
new file mode 100644
index 0000000..0912c61
--- /dev/null
+++ b/src/utils/parseEmail.ts
@@ -0,0 +1,30 @@
+import z from "zod";
+
+import parseZodOutput from "./parseZodOutput";
+
+import { Result } from "@interfaces/result";
+
+const parseEmail = (
+ emailAddressToCheck: unknown
+): Result<{ full: string; identifier: string; domain: string }> => {
+ const emailAddressParsed = z.string().email().safeParse(emailAddressToCheck);
+
+ const emailAddressResult = parseZodOutput(emailAddressParsed);
+
+ if (emailAddressResult.ok) {
+ const emailAdressSplit = emailAddressResult.data.split("@");
+
+ const identifier = emailAdressSplit[0];
+
+ const domain = emailAdressSplit[1];
+
+ return {
+ ok: true,
+ data: { full: emailAddressResult.data, domain, identifier }
+ };
+ } else {
+ return emailAddressResult;
+ }
+};
+
+export default parseEmail;
diff --git a/src/utils/parseError.ts b/src/utils/parseError.ts
new file mode 100644
index 0000000..be36bb7
--- /dev/null
+++ b/src/utils/parseError.ts
@@ -0,0 +1,56 @@
+import parseZodOutput from "./parseZodOutput";
+
+import { AppError, AppErrorModel } from "@dust-mail/structures";
+
+import { ErrorResult } from "@interfaces/result";
+
+export const errorToString = (error: AppError): string => {
+ const messages: string[] = [];
+
+ if (typeof error.kind != "string") {
+ Object.values(error.kind).forEach((error) =>
+ messages.push(errorToString(error))
+ );
+ } else {
+ messages.push(`[${error.kind}]: ` + error.message);
+ }
+
+ return messages.join(": ");
+};
+
+export const parseError = (error: unknown): { ok: false; error: AppError } => {
+ const errorParsed = AppErrorModel.safeParse(error);
+
+ const errorResult = parseZodOutput(errorParsed);
+
+ if (errorResult.ok) {
+ return { ok: false, error: errorResult.data };
+ } else {
+ return errorResult;
+ }
+};
+
+export const createBaseError = (error: AppError): ErrorResult => ({
+ ok: false,
+ error
+});
+
+export const createErrorFromUnknown = (unknown: unknown): AppError => {
+ return {
+ kind: "Unknown",
+ message: JSON.stringify(unknown)
+ };
+};
+
+export const createResultFromUnknown = (unknown: unknown): ErrorResult =>
+ createBaseError(createErrorFromUnknown(unknown));
+
+export const errorIsOfErrorKind = (error: AppError, kind: string): boolean => {
+ if (typeof error.kind != "string") {
+ const isOfKindArray = Object.values(error.kind).map((error) =>
+ errorIsOfErrorKind(error, kind)
+ );
+
+ return isOfKindArray.find((isOfKind) => isOfKind) == true;
+ } else return error.kind == kind;
+};
diff --git a/src/utils/parseJson.ts b/src/utils/parseJson.ts
new file mode 100644
index 0000000..e7dd3b0
--- /dev/null
+++ b/src/utils/parseJson.ts
@@ -0,0 +1,11 @@
+const parseJsonAsync = async (input: string): Promise => {
+ return new Promise((resolve, reject) => {
+ try {
+ resolve(JSON.parse(input));
+ } catch (error) {
+ reject(error);
+ }
+ });
+};
+
+export default parseJsonAsync;
diff --git a/src/utils/parseZodOutput.ts b/src/utils/parseZodOutput.ts
new file mode 100644
index 0000000..f63ac0f
--- /dev/null
+++ b/src/utils/parseZodOutput.ts
@@ -0,0 +1,21 @@
+import z from "zod";
+
+import { Result } from "@interfaces/result";
+
+const parseZodOutput = (output: z.SafeParseReturnType): Result => {
+ if (!output.success) {
+ const errorList = output.error.format();
+
+ return {
+ ok: false,
+ error: {
+ message: `Error parsing server response: ${JSON.stringify(errorList)}`,
+ kind: "ZodError"
+ }
+ };
+ } else {
+ return { ok: true, data: output.data };
+ }
+};
+
+export default parseZodOutput;
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..1735ddb
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,14 @@
+///
+
+interface ImportMetaEnv {
+ readonly VITE_APP_NAME: string;
+ readonly VITE_DEFAULT_SERVER: string;
+ readonly VITE_MESSAGE_COUNT_PAGE?: string;
+ readonly VITE_DEFAULT_BOX?: string;
+ readonly VITE_UNSTABLE?: string;
+ readonly VITE_REPO: string;
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..d3f7527
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,36 @@
+{
+ "compilerOptions": {
+ "composite": false,
+ "forceConsistentCasingInFileNames": true,
+ "inlineSources": false,
+ "moduleResolution": "node",
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
+ "preserveWatchOutput": true,
+ "strict": true,
+ "noEmit": true,
+ "types": ["vite/client"],
+ "skipLibCheck": true,
+ "baseUrl": "src",
+ "paths": {
+ "@utils/*": ["utils/*"],
+ "@components/*": ["components/*"],
+ "@interfaces/*": ["interfaces/*"],
+ "@styles/*": ["styles/*"],
+ "@models/*": ["models/*"],
+ "@src/*": ["./*"]
+ },
+ "useDefineForClassFields": true,
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
+ "allowJs": false,
+ "esModuleInterop": false,
+ "allowSyntheticDefaultImports": true,
+ "target": "ESNext",
+ "module": "ESNext",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx"
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 0000000..d3bf4b8
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..e9a0b17
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,68 @@
+import react from "@vitejs/plugin-react";
+import { resolve } from "path";
+import { defineConfig } from "vite";
+import { VitePWA } from "vite-plugin-pwa";
+import tsconfigPaths from "vite-tsconfig-paths";
+
+import { visualizer } from "rollup-plugin-visualizer";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ VitePWA({
+ includeAssets: ["favicon.ico", "robots.txt", "apple-touch-icon.png"],
+ registerType: "autoUpdate",
+ manifest: {
+ short_name: "dust-mail",
+ name: "Dust Mail",
+ icons: [
+ {
+ src: "android-chrome-192x192.png",
+ sizes: "192x192",
+ type: "image/png"
+ },
+ {
+ src: "android-chrome-512x512.png",
+ sizes: "512x512",
+ type: "image/png"
+ },
+ {
+ src: "android-chrome-512x512.png",
+ sizes: "512x512",
+ type: "image/png",
+ purpose: "any maskable"
+ }
+ ],
+ start_url: "/",
+ theme_color: "#2196F3",
+ background_color: "#121212",
+ display: "standalone",
+ scope: "/",
+ protocol_handlers: [
+ {
+ protocol: "mailto",
+ url: "/dashboard/compose?uri=%s"
+ }
+ ]
+ }
+ }),
+ react(),
+ tsconfigPaths(),
+ visualizer({ template: "sunburst" })
+ ],
+ esbuild: {
+ logOverride: { "this-is-undefined-in-esm": "silent" }
+ },
+ build: {
+ chunkSizeWarningLimit: 1000,
+ target: ["es2021", "chrome97", "safari13"],
+ minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
+ sourcemap: !!process.env.TAURI_DEBUG,
+ outDir: "dist",
+ rollupOptions: {
+ input: {
+ main: resolve(__dirname, "index.html")
+ }
+ }
+ }
+});