diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 167b91808..3b2a6cbb8 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -98,6 +98,31 @@ jobs:
run: npm test
+ frontend-knip:
+ name: Check the frontend for unused dependencies
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+
+ steps:
+ - name: Checkout the code
+ uses: actions/checkout@v4.2.2
+
+ - name: Install Node
+ uses: actions/setup-node@v4.1.0
+ with:
+ node-version: 20
+
+ - name: Install Node dependencies
+ working-directory: ./frontend
+ run: npm ci
+
+ - name: Check for unused dependencies
+ working-directory: ./frontend
+ run: npm run knip
+
+
rustfmt:
name: Check Rust style
runs-on: ubuntu-latest
@@ -362,6 +387,7 @@ jobs:
- opa-lint
- frontend-lint
- frontend-test
+ - frontend-knip
- rustfmt
- cargo-deny
- clippy
diff --git a/frontend/i18next-parser.config.ts b/frontend/i18next-parser.config.ts
index 2f0170dfe..4b003ccbd 100644
--- a/frontend/i18next-parser.config.ts
+++ b/frontend/i18next-parser.config.ts
@@ -6,7 +6,7 @@
import type { UserConfig } from "i18next-parser";
-const config: UserConfig = {
+export default {
keySeparator: ".",
pluralSeparator: ":",
defaultNamespace: "frontend",
@@ -30,6 +30,4 @@ const config: UserConfig = {
output: "locales/$LOCALE.json",
input: ["src/**/*.{ts,tsx}"],
sort: true,
-};
-
-export default config;
+} satisfies UserConfig;
diff --git a/frontend/knip.config.ts b/frontend/knip.config.ts
new file mode 100644
index 000000000..ad7343eaf
--- /dev/null
+++ b/frontend/knip.config.ts
@@ -0,0 +1,22 @@
+// Copyright 2024 New Vector Ltd.
+//
+// SPDX-License-Identifier: AGPL-3.0-only
+// Please see LICENSE in the repository root for full details.
+
+import type { KnipConfig } from "knip";
+
+export default {
+ entry: [
+ "src/main.tsx",
+ "src/swagger.tsx",
+ "src/routes/*",
+ "i18next-parser.config.ts",
+ ],
+ ignore: ["src/gql/*", "src/routeTree.gen.ts", ".storybook/locales.ts"],
+ ignoreDependencies: [
+ // This is used by the tailwind PostCSS plugin, but not detected by knip
+ "postcss-nesting",
+ // We're using @storybook/addon-essentials to simplify upgrades, but knip doesn't detect them
+ "@storybook/addon-*",
+ ],
+} satisfies KnipConfig;
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index 15ee71401..cdd48a779 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -96,7 +96,6 @@
"settings": "Settings"
},
"not_found_alert_title": "Not found.",
- "not_logged_in_alert": "You're not logged in.",
"oauth2_client_detail": {
"details_title": "Client info",
"name": "Name",
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index f701b60bd..1ceae1a9b 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -15,10 +15,6 @@
"@tanstack/react-query": "^5.62.15",
"@tanstack/react-router": "^1.95.1",
"@tanstack/router-zod-adapter": "^1.81.5",
- "@urql/core": "^5.0.8",
- "@urql/devtools": "^2.0.3",
- "@urql/exchange-refocus": "^1.1.0",
- "@urql/exchange-request-policy": "^1.2.0",
"@vector-im/compound-design-tokens": "2.1.3",
"@vector-im/compound-web": "^7.3.0",
"@zxcvbn-ts/core": "^3.0.4",
@@ -39,11 +35,9 @@
"@browser-logos/firefox": "^3.0.10",
"@browser-logos/safari": "^2.1.0",
"@codecov/vite-plugin": "^1.4.0",
- "@graphql-codegen/add": "^5.0.3",
"@graphql-codegen/cli": "^5.0.3",
"@graphql-codegen/client-preset": "^4.5.1",
"@graphql-codegen/typescript-msw": "^3.0.0",
- "@graphql-codegen/urql-introspection": "^3.0.0",
"@storybook/addon-essentials": "^8.4.7",
"@storybook/addon-interactions": "^8.4.7",
"@storybook/react": "^8.4.7",
@@ -54,10 +48,10 @@
"@tanstack/router-vite-plugin": "^1.95.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
+ "@testing-library/user-event": "^14.5.2",
"@types/node": "^22.10.5",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
- "@types/react-test-renderer": "^19.0.0",
"@types/swagger-ui-react": "^4.18.3",
"@vitejs/plugin-react": "^4.3.3",
"@vitest/coverage-v8": "^2.1.8",
@@ -66,16 +60,17 @@
"graphql": "^16.9.0",
"happy-dom": "^15.11.4",
"i18next-parser": "^9.1.0",
+ "knip": "^5.41.1",
"msw": "^2.6.5",
"msw-storybook-addon": "^2.0.4",
"postcss": "^8.4.49",
- "postcss-modules": "^6.0.1",
+ "postcss-import": "^16.1.0",
"postcss-nesting": "^13.0.1",
"rimraf": "^6.0.1",
"storybook": "^8.4.4",
"storybook-react-i18next": "^3.1.8",
"tailwindcss": "^3.4.17",
- "typescript": "5.7.2",
+ "typescript": "^5.7.2",
"vite": "5.4.11",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-graphql-codegen": "^3.3.8",
@@ -83,20 +78,6 @@
"vitest": "^2.1.2"
}
},
- "node_modules/@0no-co/graphql.web": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.11.tgz",
- "integrity": "sha512-xuSJ9WXwTmtngWkbdEoopMo6F8NLtjy84UNAMsAr5C3/2SgAL/dEU10TMqTIsipqPQ8HA/7WzeqQ9DEQxSvPPA==",
- "license": "MIT",
- "peerDependencies": {
- "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
- },
- "peerDependenciesMeta": {
- "graphql": {
- "optional": true
- }
- }
- },
"node_modules/@actions/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
@@ -2436,63 +2417,6 @@
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
}
},
- "node_modules/@graphql-codegen/urql-introspection": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@graphql-codegen/urql-introspection/-/urql-introspection-3.0.0.tgz",
- "integrity": "sha512-DBYfG3CO3G6MTzp+/FaXuxYS6cFSkpDMwxXKoJVqKR0jIGd/ev3Gh1pTgqxndcBu8oV9xjiaBQglKCge0EqLpQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@graphql-codegen/plugin-helpers": "^3.0.0",
- "@urql/introspection": "^0.3.2",
- "tslib": "~2.6.0"
- },
- "engines": {
- "node": ">= 16.0.0"
- },
- "peerDependencies": {
- "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
- }
- },
- "node_modules/@graphql-codegen/urql-introspection/node_modules/@graphql-codegen/plugin-helpers": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz",
- "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@graphql-tools/utils": "^9.0.0",
- "change-case-all": "1.0.15",
- "common-tags": "1.8.2",
- "import-from": "4.0.0",
- "lodash": "~4.17.0",
- "tslib": "~2.4.0"
- },
- "peerDependencies": {
- "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
- }
- },
- "node_modules/@graphql-codegen/urql-introspection/node_modules/@graphql-codegen/plugin-helpers/node_modules/tslib": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
- "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
- "dev": true,
- "license": "0BSD"
- },
- "node_modules/@graphql-codegen/urql-introspection/node_modules/@graphql-tools/utils": {
- "version": "9.2.1",
- "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz",
- "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@graphql-typed-document-node/core": "^3.1.1",
- "tslib": "^2.4.0"
- },
- "peerDependencies": {
- "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
- }
- },
"node_modules/@graphql-codegen/visitor-plugin-common": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.6.0.tgz",
@@ -4801,6 +4725,34 @@
"hasInstallScript": true,
"license": "Apache-2.0"
},
+ "node_modules/@snyk/github-codeowners": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@snyk/github-codeowners/-/github-codeowners-1.1.0.tgz",
+ "integrity": "sha512-lGFf08pbkEac0NYgVf4hdANpAgApRjNByLXB+WBip3qj1iendOIyAwP2GKkKbQMNVy2r1xxDf0ssfWscoiC+Vw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^4.1.1",
+ "ignore": "^5.1.8",
+ "p-map": "^4.0.0"
+ },
+ "bin": {
+ "github-codeowners": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=8.10"
+ }
+ },
+ "node_modules/@snyk/github-codeowners/node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/@storybook/addon-actions": {
"version": "8.4.7",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.4.7.tgz",
@@ -6323,6 +6275,7 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
@@ -6364,16 +6317,6 @@
"@types/react": "*"
}
},
- "node_modules/@types/react-test-renderer": {
- "version": "19.0.0",
- "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-19.0.0.tgz",
- "integrity": "sha512-qDVnNybqFm2eZKJ4jD34EvRd6VHD67KjgnWaEMM0Id9L22EpWe3nOSVKHWL1XWRCxUWe3lhXwlEeCKD1BlJCQA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/react": "*"
- }
- },
"node_modules/@types/resolve": {
"version": "1.20.6",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
@@ -6441,65 +6384,6 @@
"@types/node": "*"
}
},
- "node_modules/@urql/core": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.0.8.tgz",
- "integrity": "sha512-1GOnUw7/a9bzkcM0+U8U5MmxW2A7FE5YquuEmcJzTtW5tIs2EoS4F2ITpuKBjRBbyRjZgO860nWFPo1m4JImGA==",
- "license": "MIT",
- "dependencies": {
- "@0no-co/graphql.web": "^1.0.5",
- "wonka": "^6.3.2"
- }
- },
- "node_modules/@urql/devtools": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@urql/devtools/-/devtools-2.0.3.tgz",
- "integrity": "sha512-TktPLiBS9LcBPHD6qcnb8wqOVcg3Bx0iCtvQ80uPpfofwwBGJmqnQTjUdEFU6kwaLOFZULQ9+Uo4831G823mQw==",
- "license": "MIT",
- "dependencies": {
- "wonka": ">= 4.0.9"
- },
- "peerDependencies": {
- "@urql/core": ">= 1.14.0",
- "graphql": ">= 0.11.0"
- }
- },
- "node_modules/@urql/exchange-refocus": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@urql/exchange-refocus/-/exchange-refocus-1.1.0.tgz",
- "integrity": "sha512-tMgIqXUGIuNBeEoXDNOZ48Kut2m85etNIorwBG89tQZHDLxJM52N6A0eLm0Mv9BJFb0U94i3drwlD55He+9Uvw==",
- "license": "MIT",
- "dependencies": {
- "@urql/core": "^5.0.0",
- "wonka": "^6.3.2"
- },
- "peerDependencies": {
- "@urql/core": "^5.0.0"
- }
- },
- "node_modules/@urql/exchange-request-policy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@urql/exchange-request-policy/-/exchange-request-policy-1.2.0.tgz",
- "integrity": "sha512-30CwS5/YzX0YWVATg19rrDhruDCRIu96xUz6HGlhJPUw22M7njRldl44fmoU11ZbIemg01t8ysq6+0rdktYBgg==",
- "license": "MIT",
- "dependencies": {
- "@urql/core": "^5.0.0",
- "wonka": "^6.3.2"
- },
- "peerDependencies": {
- "@urql/core": "^5.0.0"
- }
- },
- "node_modules/@urql/introspection": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@urql/introspection/-/introspection-0.3.3.tgz",
- "integrity": "sha512-tekSLLqWnusfV6V7xaEnLJQSdXOD/lWy7f8JYQwrX+88Md+voGSCSx5WJXI7KLBN3Tat2OV08tAr8UROykls4Q==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
- }
- },
"node_modules/@vector-im/compound-design-tokens": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@vector-im/compound-design-tokens/-/compound-design-tokens-2.1.3.tgz",
@@ -8608,6 +8492,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/easy-table": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz",
+ "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "optionalDependencies": {
+ "wcwidth": "^1.0.1"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.58",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.58.tgz",
@@ -8646,6 +8543,20 @@
"once": "^1.4.0"
}
},
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz",
+ "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
"node_modules/ensure-posix-path": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz",
@@ -9249,16 +9160,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/generic-names": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz",
- "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "loader-utils": "^3.2.0"
- }
- },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -9463,6 +9364,7 @@
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz",
"integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
@@ -10374,19 +10276,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/icss-utils": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
- "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "^10 || ^12 || >= 14"
- },
- "peerDependencies": {
- "postcss": "^8.1.0"
- }
- },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -11091,6 +10980,79 @@
"graceful-fs": "^4.1.6"
}
},
+ "node_modules/knip": {
+ "version": "5.41.1",
+ "resolved": "https://registry.npmjs.org/knip/-/knip-5.41.1.tgz",
+ "integrity": "sha512-yNpCCe2REU7U3VRvMASnXSEtfEC2HmOoDW9Vp9teQ9FktJYnuagvSZD3xWq8Ru7sPABkmvbC5TVWuMzIaeADNA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/webpro"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/knip"
+ },
+ {
+ "type": "polar",
+ "url": "https://polar.sh/webpro-nl"
+ }
+ ],
+ "license": "ISC",
+ "dependencies": {
+ "@nodelib/fs.walk": "1.2.8",
+ "@snyk/github-codeowners": "1.1.0",
+ "easy-table": "1.2.0",
+ "enhanced-resolve": "^5.17.1",
+ "fast-glob": "^3.3.2",
+ "jiti": "^2.4.0",
+ "js-yaml": "^4.1.0",
+ "minimist": "^1.2.8",
+ "picocolors": "^1.1.0",
+ "picomatch": "^4.0.1",
+ "pretty-ms": "^9.0.0",
+ "smol-toml": "^1.3.1",
+ "strip-json-comments": "5.0.1",
+ "summary": "2.1.0",
+ "zod": "^3.22.4",
+ "zod-validation-error": "^3.0.3"
+ },
+ "bin": {
+ "knip": "bin/knip.js",
+ "knip-bun": "bin/knip-bun.js"
+ },
+ "engines": {
+ "node": ">=18.6.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18",
+ "typescript": ">=5.0.4"
+ }
+ },
+ "node_modules/knip/node_modules/jiti": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
+ "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/knip/node_modules/strip-json-comments": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz",
+ "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/lead": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz",
@@ -11166,16 +11128,6 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/loader-utils": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz",
- "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 12.13.0"
- }
- },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -11198,13 +11150,6 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
- "node_modules/lodash.camelcase": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
- "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -12175,6 +12120,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse-ms": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+ "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/parse5": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
@@ -12457,9 +12415,9 @@
}
},
"node_modules/postcss-import": {
- "version": "15.1.0",
- "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
- "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz",
+ "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12468,7 +12426,7 @@
"resolve": "^1.1.7"
},
"engines": {
- "node": ">=14.0.0"
+ "node": ">=18.0.0"
},
"peerDependencies": {
"postcss": "^8.0.0"
@@ -12530,89 +12488,6 @@
}
}
},
- "node_modules/postcss-modules": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-6.0.1.tgz",
- "integrity": "sha512-zyo2sAkVvuZFFy0gc2+4O+xar5dYlaVy/ebO24KT0ftk/iJevSNyPyQellsBLlnccwh7f6V6Y4GvuKRYToNgpQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "generic-names": "^4.0.0",
- "icss-utils": "^5.1.0",
- "lodash.camelcase": "^4.3.0",
- "postcss-modules-extract-imports": "^3.1.0",
- "postcss-modules-local-by-default": "^4.0.5",
- "postcss-modules-scope": "^3.2.0",
- "postcss-modules-values": "^4.0.0",
- "string-hash": "^1.1.3"
- },
- "peerDependencies": {
- "postcss": "^8.0.0"
- }
- },
- "node_modules/postcss-modules-extract-imports": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
- "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "^10 || ^12 || >= 14"
- },
- "peerDependencies": {
- "postcss": "^8.1.0"
- }
- },
- "node_modules/postcss-modules-local-by-default": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz",
- "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "icss-utils": "^5.0.0",
- "postcss-selector-parser": "^7.0.0",
- "postcss-value-parser": "^4.1.0"
- },
- "engines": {
- "node": "^10 || ^12 || >= 14"
- },
- "peerDependencies": {
- "postcss": "^8.1.0"
- }
- },
- "node_modules/postcss-modules-scope": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz",
- "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "postcss-selector-parser": "^7.0.0"
- },
- "engines": {
- "node": "^10 || ^12 || >= 14"
- },
- "peerDependencies": {
- "postcss": "^8.1.0"
- }
- },
- "node_modules/postcss-modules-values": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
- "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "icss-utils": "^5.0.0"
- },
- "engines": {
- "node": "^10 || ^12 || >= 14"
- },
- "peerDependencies": {
- "postcss": "^8.1.0"
- }
- },
"node_modules/postcss-nested": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
@@ -12772,6 +12647,22 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/pretty-ms": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz",
+ "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parse-ms": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
@@ -14059,6 +13950,19 @@
"node": ">=8"
}
},
+ "node_modules/smol-toml": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.1.tgz",
+ "integrity": "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/cyyynthia"
+ }
+ },
"node_modules/snake-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
@@ -14264,13 +14168,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/string-hash": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
- "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==",
- "dev": true,
- "license": "CC0-1.0"
- },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -14485,6 +14382,13 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/summary": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/summary/-/summary-2.1.0.tgz",
+ "integrity": "sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -14674,6 +14578,24 @@
"node": ">=10.13.0"
}
},
+ "node_modules/tailwindcss/node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
"node_modules/tailwindcss/node_modules/postcss-selector-parser": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
@@ -14688,6 +14610,16 @@
"node": ">=4"
}
},
+ "node_modules/tapable": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/tar-fs": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
@@ -15220,6 +15152,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
"devOptional": true,
+ "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -16493,12 +16426,6 @@
"node": ">=8"
}
},
- "node_modules/wonka": {
- "version": "6.3.4",
- "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.4.tgz",
- "integrity": "sha512-CjpbqNtBGNAeyNS/9W6q3kSkKE52+FjIj7AkFlLr11s/VWGUu6a2CdYSdGxocIhIVjaW/zchesBQUKPVU69Cqg==",
- "license": "MIT"
- },
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -16692,6 +16619,19 @@
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
+ },
+ "node_modules/zod-validation-error": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz",
+ "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.18.0"
+ }
}
}
}
diff --git a/frontend/package.json b/frontend/package.json
index 2daf4e55b..a7546808b 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -14,7 +14,8 @@
"coverage": "vitest run --coverage",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
- "i18n": "i18next"
+ "i18n": "i18next",
+ "knip": "knip"
},
"dependencies": {
"@fontsource/inconsolata": "^5.1.1",
@@ -24,10 +25,6 @@
"@tanstack/react-query": "^5.62.15",
"@tanstack/react-router": "^1.95.1",
"@tanstack/router-zod-adapter": "^1.81.5",
- "@urql/core": "^5.0.8",
- "@urql/devtools": "^2.0.3",
- "@urql/exchange-refocus": "^1.1.0",
- "@urql/exchange-request-policy": "^1.2.0",
"@vector-im/compound-design-tokens": "2.1.3",
"@vector-im/compound-web": "^7.3.0",
"@zxcvbn-ts/core": "^3.0.4",
@@ -48,11 +45,9 @@
"@browser-logos/firefox": "^3.0.10",
"@browser-logos/safari": "^2.1.0",
"@codecov/vite-plugin": "^1.4.0",
- "@graphql-codegen/add": "^5.0.3",
"@graphql-codegen/cli": "^5.0.3",
"@graphql-codegen/client-preset": "^4.5.1",
"@graphql-codegen/typescript-msw": "^3.0.0",
- "@graphql-codegen/urql-introspection": "^3.0.0",
"@storybook/addon-essentials": "^8.4.7",
"@storybook/addon-interactions": "^8.4.7",
"@storybook/react": "^8.4.7",
@@ -63,10 +58,10 @@
"@tanstack/router-vite-plugin": "^1.95.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
+ "@testing-library/user-event": "^14.5.2",
"@types/node": "^22.10.5",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
- "@types/react-test-renderer": "^19.0.0",
"@types/swagger-ui-react": "^4.18.3",
"@vitejs/plugin-react": "^4.3.3",
"@vitest/coverage-v8": "^2.1.8",
@@ -75,16 +70,17 @@
"graphql": "^16.9.0",
"happy-dom": "^15.11.4",
"i18next-parser": "^9.1.0",
+ "knip": "^5.41.1",
"msw": "^2.6.5",
"msw-storybook-addon": "^2.0.4",
"postcss": "^8.4.49",
- "postcss-modules": "^6.0.1",
+ "postcss-import": "^16.1.0",
"postcss-nesting": "^13.0.1",
"rimraf": "^6.0.1",
"storybook": "^8.4.4",
"storybook-react-i18next": "^3.1.8",
"tailwindcss": "^3.4.17",
- "typescript": "5.7.2",
+ "typescript": "^5.7.2",
"vite": "5.4.11",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-graphql-codegen": "^3.3.8",
diff --git a/frontend/src/components/NotLoggedIn.tsx b/frontend/src/components/NotLoggedIn.tsx
deleted file mode 100644
index 9727c76fc..000000000
--- a/frontend/src/components/NotLoggedIn.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2024 New Vector Ltd.
-// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
-//
-// SPDX-License-Identifier: AGPL-3.0-only
-// Please see LICENSE in the repository root for full details.
-
-import { Alert } from "@vector-im/compound-web";
-import type { ReactNode } from "react";
-import { Translation } from "react-i18next";
-
-const NotLoggedIn: React.FC = () => (
-
- {(t): ReactNode => (
-
- )}
-
-);
-
-export default NotLoggedIn;
diff --git a/frontend/src/components/PasswordCreationDoubleInput.tsx b/frontend/src/components/PasswordCreationDoubleInput.tsx
index 6c53ddcab..284cb7001 100644
--- a/frontend/src/components/PasswordCreationDoubleInput.tsx
+++ b/frontend/src/components/PasswordCreationDoubleInput.tsx
@@ -20,7 +20,9 @@ const CONFIG_FRAGMENT = graphql(/* GraphQL */ `
// This will load the password complexity module lazily,
// so that it doesn't block the initial render and can be code-split
-const loadPromise = import("../utils/password_complexity");
+const loadPromise = import("../utils/password_complexity").then(
+ ({ estimatePasswordComplexity }) => estimatePasswordComplexity,
+);
const usePasswordComplexity = (password: string): PasswordComplexity => {
const { t } = useTranslation();
@@ -40,7 +42,7 @@ const usePasswordComplexity = (password: string): PasswordComplexity => {
});
} else {
loadPromise
- .then(({ estimatePasswordComplexity }) =>
+ .then((estimatePasswordComplexity) =>
estimatePasswordComplexity(deferredPassword, t),
)
.then((response) => setResult(response));
diff --git a/frontend/src/components/SessionDetail/SessionDetails.tsx b/frontend/src/components/SessionDetail/SessionDetails.tsx
index b5905ecc5..3b1775fd0 100644
--- a/frontend/src/components/SessionDetail/SessionDetails.tsx
+++ b/frontend/src/components/SessionDetail/SessionDetails.tsx
@@ -21,7 +21,7 @@ import { VisualList, VisualListItem } from "../VisualList/VisualList";
import styles from "./SessionDetails.module.css";
-export type Detail = { label: string; value: ReactNode };
+type Detail = { label: string; value: ReactNode };
type Props = {
title: string | ReactNode;
lastActive?: Date;
diff --git a/frontend/src/components/Typography.tsx b/frontend/src/components/Typography.tsx
index 82f27697e..af9dcb423 100644
--- a/frontend/src/components/Typography.tsx
+++ b/frontend/src/components/Typography.tsx
@@ -48,31 +48,4 @@ const Typography: React.FC = ({
return createElement(element, { className }, ...Children.toArray(children));
};
-type SimpleProps = { children: React.ReactNode };
-
-export const Bold: React.FC = ({ children }) => (
- {children}
-);
-
-export const Code: React.FC = ({ children }) => (
- {children}
-);
-
-export const Title: React.FC = ({ children }) => (
- {children}
-);
-
-export const Subtitle: React.FC = ({ children }) => (
- {children}
-);
-
-export const Body: React.FC<{
- children: React.ReactNode;
- justified?: boolean;
-}> = ({ children, justified }) => (
-
- {children}
-
-);
-
export default Typography;
diff --git a/frontend/src/components/UserProfile/UserEmailList.tsx b/frontend/src/components/UserProfile/UserEmailList.tsx
index 9edf7b065..9af5b0fb0 100644
--- a/frontend/src/components/UserProfile/UserEmailList.tsx
+++ b/frontend/src/components/UserProfile/UserEmailList.tsx
@@ -49,7 +49,7 @@ const QUERY = graphql(/* GraphQL */ `
}
`);
-export const FRAGMENT = graphql(/* GraphQL */ `
+const FRAGMENT = graphql(/* GraphQL */ `
fragment UserEmailList_user on User {
id
primaryEmail {
diff --git a/frontend/src/config.ts b/frontend/src/config.ts
index 1b26c7f55..177817178 100644
--- a/frontend/src/config.ts
+++ b/frontend/src/config.ts
@@ -4,7 +4,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
-export type AppConfig = {
+type AppConfig = {
root: string;
graphqlEndpoint: string;
};
diff --git a/frontend/src/pagination.ts b/frontend/src/pagination.ts
index 0929618b1..14a323e81 100644
--- a/frontend/src/pagination.ts
+++ b/frontend/src/pagination.ts
@@ -16,7 +16,7 @@ type PageInfo = {
};
export const FIRST_PAGE = Symbol("FIRST_PAGE");
-export const LAST_PAGE = Symbol("LAST_PAGE");
+const LAST_PAGE = Symbol("LAST_PAGE");
export const anyPaginationSchema = z.object({
first: z.number().nullish(),
@@ -25,7 +25,7 @@ export const anyPaginationSchema = z.object({
before: z.string().nullish(),
});
-export const forwardPaginationSchema = z.object({
+const forwardPaginationSchema = z.object({
first: z.number(),
after: z.string().nullish(),
});
@@ -46,20 +46,20 @@ export type Pagination = z.infer;
export type AnyPagination = z.infer;
// Check if the pagination is a valid pagination
-export const isValidPagination = (
+const isValidPagination = (
pagination: AnyPagination,
): pagination is Pagination =>
typeof pagination.first === "number" || typeof pagination.last === "number";
// Check if the pagination is forward pagination.
-export const isForwardPagination = (
+const isForwardPagination = (
pagination: Pagination,
): pagination is ForwardPagination => {
return Object.hasOwn(pagination, "first");
};
// Check if the pagination is backward pagination.
-export const isBackwardPagination = (
+const isBackwardPagination = (
pagination: Pagination,
): pagination is BackwardPagination => {
return Object.hasOwn(pagination, "last");
diff --git a/frontend/src/result.ts b/frontend/src/result.ts
deleted file mode 100644
index 3b3523489..000000000
--- a/frontend/src/result.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2024 New Vector Ltd.
-// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
-//
-// SPDX-License-Identifier: AGPL-3.0-only
-// Please see LICENSE in the repository root for full details.
-
-const RESULT = Symbol("Result");
-const ERR = Symbol("Err");
-const OK = Symbol("Ok");
-
-/**
- * An `Ok` is a type that represents a successful result.
- */
-export type Ok = {
- [RESULT]: typeof OK;
- [OK]: T;
-};
-
-/**
- * An `Err` is a type that represents an error.
- */
-export type Err = {
- [RESULT]: typeof ERR;
- [ERR]: E;
-};
-
-/**
- * A `Result` is a type that represents either an `Ok` or an `Err`.
- */
-export type Result = Ok | Err;
-
-// Construct an `Ok`
-export const ok = (data: T): Ok => ({ [RESULT]: OK, [OK]: data });
-
-// Construct an `Err`
-export const err = (error: E): Err => ({
- [RESULT]: ERR,
- [ERR]: error,
-});
-
-// Check if a `Result` is an `Ok`
-export const isOk = (result: Result): result is Ok =>
- result[RESULT] === OK;
-
-// Check if a `Result` is an `Err`
-export const isErr = (result: Result): result is Err =>
- result[RESULT] === ERR;
-
-// Extract the data from an `Ok`
-export const unwrapOk = (result: Ok): T => result[OK];
-
-// Extract the error from an `Err`
-export const unwrapErr = (result: Err): E => result[ERR];
-
-/**
- * Check result for error and throw unwrapped error
- * Otherwise return unwrapped Ok result
- */
-export const unwrap = (result: Result): T => {
- if (isErr(result)) {
- throw unwrapErr(result);
- }
- return unwrapOk(result);
-};