From 4256236be07f49eecf36108eb06b2b613a70f7e8 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 18:31:02 +0800 Subject: [PATCH 01/19] chore: add engineering improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Configure Prettier with unified code style rules - Add husky + lint-staged for automated pre-commit checks - Add commitlint to enforce conventional commit messages - Add PR check workflow for CI automation - Auto-format all files with Prettier - Fix TypeScript any types in field-crypto.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .commitlintrc.json | 21 + .github/workflows/pr-check.yml | 34 + .husky/commit-msg | 1 + .husky/pre-commit | 1 + .prettierignore | 20 + .prettierrc | 10 +- package-lock.json | 1506 ++++++++++++++++++++++++++++- package.json | 16 +- src/backend/utils/field-crypto.ts | 15 +- 9 files changed, 1578 insertions(+), 46 deletions(-) create mode 100644 .commitlintrc.json create mode 100644 .github/workflows/pr-check.yml create mode 100644 .husky/commit-msg create mode 100644 .husky/pre-commit diff --git a/.commitlintrc.json b/.commitlintrc.json new file mode 100644 index 00000000..cba65ea5 --- /dev/null +++ b/.commitlintrc.json @@ -0,0 +1,21 @@ +{ + "extends": ["@commitlint/config-conventional"], + "rules": { + "type-enum": [ + 2, + "always", + [ + "feat", + "fix", + "docs", + "style", + "refactor", + "perf", + "test", + "chore", + "revert" + ] + ], + "subject-case": [0] + } +} diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml new file mode 100644 index 00000000..252adbcb --- /dev/null +++ b/.github/workflows/pr-check.yml @@ -0,0 +1,34 @@ +name: PR Check + +on: + pull_request: + branches: [main, dev-*] + +jobs: + lint-and-build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Run ESLint + run: npx eslint . + + - name: Run Prettier check + run: npx prettier --check . + + - name: Type check + run: npx tsc --noEmit + + - name: Build + run: npm run build diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 00000000..0a4b97de --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..2312dc58 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.prettierignore b/.prettierignore index 1b8ac889..5f52bf45 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,23 @@ # Ignore artifacts: build coverage +dist +dist-ssr +release + +# Dependencies +node_modules +package-lock.json +pnpm-lock.yaml +yarn.lock + +# Database +db + +# Environment +.env + +# Misc +*.min.js +*.min.css +openapi.json diff --git a/.prettierrc b/.prettierrc index 0967ef42..fd873cbb 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1 +1,9 @@ -{} +{ + "semi": true, + "singleQuote": false, + "tabWidth": 2, + "trailingComma": "all", + "printWidth": 80, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/package-lock.json b/package-lock.json index b7de7ca7..2b07667d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "termix", - "version": "1.7.0", + "version": "1.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "termix", - "version": "1.7.0", + "version": "1.7.1", "dependencies": { "@codemirror/autocomplete": "^6.18.7", "@codemirror/commands": "^6.3.3", @@ -90,6 +90,8 @@ "zod": "^4.0.5" }, "devDependencies": { + "@commitlint/cli": "^20.1.0", + "@commitlint/config-conventional": "^20.0.0", "@eslint/js": "^9.34.0", "@types/better-sqlite3": "^7.6.13", "@types/cors": "^2.8.19", @@ -108,12 +110,39 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.3.0", + "husky": "^9.1.7", + "lint-staged": "^16.2.3", "prettier": "3.6.2", "typescript": "~5.9.2", "typescript-eslint": "^8.40.0", "vite": "^7.1.5" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/runtime": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", @@ -128,7 +157,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.19.0.tgz", "integrity": "sha512-61Hfv3cF07XvUxNeC3E7jhG8XNi1Yom1G0lRC936oLnlF+jrbrv8rc/J98XlYzcsAoTVupfsf5fLej1aI8kyIg==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", @@ -177,7 +205,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", @@ -204,7 +231,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.10.tgz", "integrity": "sha512-h/SceTVsN5r+WE+TVP2g3KDvNoSzbSrtZXCKo4vkKdbfT5t4otuVgngGdFukOO/rwRD2++pCxoh6xD4TEVMkQA==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-css": "^6.0.0", @@ -232,7 +258,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz", "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.6.0", @@ -420,7 +445,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -496,7 +520,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", "license": "MIT", - "peer": true, "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } @@ -518,7 +541,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.4.tgz", "integrity": "sha512-hduz0suCcUSC/kM8Fq3A9iLwInJDl8fD1xLpTIk+5xkNm8z/FT7UsIa9sOXrkpChh+XXc18RzswE8QqELsVl+g==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -526,6 +548,438 @@ "w3c-keyname": "^2.2.4" } }, + "node_modules/@commitlint/cli": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.1.0.tgz", + "integrity": "sha512-pW5ujjrOovhq5RcYv5xCpb4GkZxkO2+GtOdBW2/qrr0Ll9tl3PX0aBBobGQl3mdZUbOBgwAexEQLeH6uxL0VYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^20.0.0", + "@commitlint/lint": "^20.0.0", + "@commitlint/load": "^20.1.0", + "@commitlint/read": "^20.0.0", + "@commitlint/types": "^20.0.0", + "tinyexec": "^1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.0.0.tgz", + "integrity": "sha512-q7JroPIkDBtyOkVe9Bca0p7kAUYxZMxkrBArCfuD3yN4KjRAenP9PmYwnn7rsw8Q+hHq1QB2BRmBh0/Z19ZoJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.0.0", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.0.0.tgz", + "integrity": "sha512-BeyLMaRIJDdroJuYM2EGhDMGwVBMZna9UiIqV9hxj+J551Ctc6yoGuGSmghOy/qPhBSuhA6oMtbEiTmxECafsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.0.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@commitlint/ensure": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.0.0.tgz", + "integrity": "sha512-WBV47Fffvabe68n+13HJNFBqiMH5U1Ryls4W3ieGwPC0C7kJqp3OVQQzG2GXqOALmzrgAB+7GXmyy8N9ct8/Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.0.0", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", + "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.0.0.tgz", + "integrity": "sha512-zrZQXUcSDmQ4eGGrd+gFESiX0Rw+WFJk7nW4VFOmxub4mAATNKBQ4vNw5FgMCVehLUKG2OT2LjOqD0Hk8HvcRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.0.0.tgz", + "integrity": "sha512-ayPLicsqqGAphYIQwh9LdAYOVAQ9Oe5QCgTNTj+BfxZb9b/JW222V5taPoIBzYnAP0z9EfUtljgBk+0BN4T4Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.0.0", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/is-ignored/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@commitlint/lint": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.0.0.tgz", + "integrity": "sha512-kWrX8SfWk4+4nCexfLaQT3f3EcNjJwJBsSZ5rMBw6JCd6OzXufFHgel2Curos4LKIxwec9WSvs2YUD87rXlxNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^20.0.0", + "@commitlint/parse": "^20.0.0", + "@commitlint/rules": "^20.0.0", + "@commitlint/types": "^20.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.1.0.tgz", + "integrity": "sha512-qo9ER0XiAimATQR5QhvvzePfeDfApi/AFlC1G+YN+ZAY8/Ua6IRrDrxRvQAr+YXUKAxUsTDSp9KXeXLBPsNRWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^20.0.0", + "@commitlint/execute-rule": "^20.0.0", + "@commitlint/resolve-extends": "^20.1.0", + "@commitlint/types": "^20.0.0", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/message": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.0.0.tgz", + "integrity": "sha512-gLX4YmKnZqSwkmSB9OckQUrI5VyXEYiv3J5JKZRxIp8jOQsWjZgHSG/OgEfMQBK9ibdclEdAyIPYggwXoFGXjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.0.0.tgz", + "integrity": "sha512-j/PHCDX2bGM5xGcWObOvpOc54cXjn9g6xScXzAeOLwTsScaL4Y+qd0pFC6HBwTtrH92NvJQc+2Lx9HFkVi48cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.0.0", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.0.0.tgz", + "integrity": "sha512-Ti7Y7aEgxsM1nkwA4ZIJczkTFRX/+USMjNrL9NXwWQHqNqrBX2iMi+zfuzZXqfZ327WXBjdkRaytJ+z5vNqTOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^20.0.0", + "@commitlint/types": "^20.0.0", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.1.0.tgz", + "integrity": "sha512-cxKXQrqHjZT3o+XPdqDCwOWVFQiae++uwd9dUBC7f2MdV58ons3uUvASdW7m55eat5sRiQ6xUHyMWMRm6atZWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^20.0.0", + "@commitlint/types": "^20.0.0", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/rules": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.0.0.tgz", + "integrity": "sha512-gvg2k10I/RfvHn5I5sxvVZKM1fl72Sqrv2YY/BnM7lMHcYqO0E2jnRWoYguvBfEcZ39t+rbATlciggVe77E4zA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^20.0.0", + "@commitlint/message": "^20.0.0", + "@commitlint/to-lines": "^20.0.0", + "@commitlint/types": "^20.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-20.0.0.tgz", + "integrity": "sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.0.0.tgz", + "integrity": "sha512-drXaPSP2EcopukrUXvUXmsQMu3Ey/FuJDc/5oiW4heoCfoE5BdLQyuc7veGeE3aoQaTVqZnh4D5WTWe2vefYKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^7.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level/node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@commitlint/top-level/node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.0.0.tgz", + "integrity": "sha512-bVUNBqG6aznYcYjTjnc3+Cat/iBgbgpflxbIBTnsHTX0YVpnmINPEkSRWymT2Q8aSH3Y7aKnEbunilkYe8TybA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -1211,6 +1665,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -1232,6 +1687,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ms": "^2.1.3" }, @@ -1251,6 +1707,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1267,6 +1724,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -1280,7 +1738,8 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@electron/windows-sign/node_modules/universalify": { "version": "2.0.1", @@ -1289,6 +1748,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -2313,8 +2773,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@lezer/cpp": { "version": "1.1.3", @@ -2354,7 +2813,6 @@ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", "license": "MIT", - "peer": true, "dependencies": { "@lezer/common": "^1.0.0" } @@ -2386,7 +2844,6 @@ "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", "license": "MIT", - "peer": true, "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.1.3", @@ -2409,7 +2866,6 @@ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", "license": "MIT", - "peer": true, "dependencies": { "@lezer/common": "^1.0.0" } @@ -4837,7 +5293,6 @@ "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*" } @@ -4874,6 +5329,16 @@ "@types/node": "*" } }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz", + "integrity": "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cookie-parser": { "version": "1.4.9", "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", @@ -4922,7 +5387,6 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", "license": "MIT", - "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -5087,7 +5551,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz", "integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -5098,7 +5561,6 @@ "integrity": "sha512-3BKc/yGdNTYQVVw4idqHtSOcFsgGuBbMveKCOgF8wQ5QtrYOc3jDIlzg3jef04zcXFIHLelyGlj0T+BJ8+KN+w==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -5174,7 +5636,8 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz", "integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/unist": { "version": "3.0.3", @@ -5739,8 +6202,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/7zip-bin": { "version": "5.2.0", @@ -5775,7 +6237,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5836,7 +6297,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5858,6 +6318,22 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-escapes": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", + "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -6080,6 +6556,13 @@ "node": ">=10" } }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -6261,7 +6744,6 @@ "integrity": "sha512-3yVdyZhklTiNrtg+4WqHpJpFDd+WHTg2oM7UcR80GqL05AOV0xEJzc6qNvFYoEtE+hRp1n9MpN6/+4yhlGkDXQ==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" @@ -7039,6 +7521,13 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -7071,6 +7560,17 @@ "node": ">= 6" } }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, "node_modules/compare-version": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", @@ -7247,6 +7747,51 @@ "node": ">= 0.6" } }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", @@ -7294,6 +7839,51 @@ "node": ">= 0.10" } }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz", + "integrity": "sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "^2.4.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, "node_modules/cpu-features": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", @@ -7331,7 +7921,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -7360,6 +7951,19 @@ "integrity": "sha512-cjrsQufETwxjvwZbYbKBCJNvmQ2++G9AvT45zDi7NXL9k2PdVcs2h0jQz96J6G4TMKRCcEsoJ+QTgQD00Igtjw==", "license": "MIT" }, + "node_modules/dargs": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dash-video-element": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dash-video-element/-/dash-video-element-0.2.0.tgz", @@ -7732,6 +8336,19 @@ "node": ">=8" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dotenv": { "version": "17.2.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", @@ -8108,6 +8725,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -8128,6 +8746,7 @@ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.3" }, @@ -8146,6 +8765,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -8160,7 +8780,8 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/electron/node_modules/@types/node": { "version": "22.18.8", @@ -8251,6 +8872,19 @@ "node": ">=6" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -8258,6 +8892,16 @@ "dev": true, "license": "MIT" }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -8387,7 +9031,6 @@ "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8617,6 +9260,13 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -8921,6 +9571,23 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -9318,6 +9985,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -9380,6 +10060,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/git-raw-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -9467,6 +10165,32 @@ "node": ">=10" } }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/globals": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", @@ -9940,6 +10664,22 @@ "ms": "^2.0.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/i18next": { "version": "25.5.3", "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.3.tgz", @@ -9959,7 +10699,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.27.6" }, @@ -10064,6 +10803,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imsc": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.5.tgz", @@ -10179,6 +10929,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -10271,6 +11028,16 @@ "node": ">=0.12.0" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -10289,6 +11056,19 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -10430,6 +11210,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -10475,6 +11262,33 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -10816,6 +11630,218 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "16.2.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.3.tgz", + "integrity": "sha512-1OnJEESB9zZqsp61XHH2fvpS1es3hRCxMplF/AJUDa8Ho8VrscYDIuxGrj3m8KPXbcWZ8fT9XTMUhEQmOVKpKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.1", + "listr2": "^9.0.4", + "micromatch": "^4.0.8", + "nano-spawn": "^1.0.3", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", + "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/listr2": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.4.tgz", + "integrity": "sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.0.tgz", + "integrity": "sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/localforage": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", @@ -10856,6 +11882,13 @@ "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.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -10892,6 +11925,13 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -10899,12 +11939,47 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -10922,6 +11997,206 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -11471,6 +12746,19 @@ "node": ">= 0.6" } }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-descriptors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", @@ -12154,6 +13442,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -12364,6 +13665,19 @@ "license": "MIT", "optional": true }, + "node_modules/nano-spawn": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.3.tgz", + "integrity": "sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, "node_modules/nanoid": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", @@ -12771,6 +14085,25 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -12912,6 +14245,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/player.style": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/player.style/-/player.style-0.2.0.tgz", @@ -13014,6 +14360,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -13031,6 +14378,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -13440,7 +14788,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13450,7 +14797,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -13477,7 +14823,6 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.63.0.tgz", "integrity": "sha512-ZwueDMvUeucovM2VjkCf7zIHcs1aAlDimZu2Hvel5C5907gUzMpm4xCrQXtRzCvsBqFjonB4m3x4LzCFI1ZKWA==", "license": "MIT", - "peer": true, "engines": { "node": ">=18.0.0" }, @@ -13984,6 +15329,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -14073,6 +15428,13 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -14727,6 +16089,16 @@ "node": ">= 0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/spotify-audio-element": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/spotify-audio-element/-/spotify-audio-element-1.0.3.tgz", @@ -14819,6 +16191,16 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -15120,6 +16502,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -15183,6 +16566,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -15197,6 +16581,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -15204,6 +16589,26 @@ "rimraf": "bin.js" } }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, "node_modules/tiktok-video-element": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/tiktok-video-element/-/tiktok-video-element-0.1.1.tgz", @@ -15236,6 +16641,13 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -15274,7 +16686,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -15480,7 +16891,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15545,6 +16955,19 @@ "integrity": "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==", "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -15818,7 +17241,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz", "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -15910,7 +17332,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -16130,6 +17551,19 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "devOptional": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index d8c1fa4b..045aa3d2 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "build:linux-appimage": "npm run build && electron-builder --linux AppImage", "build:linux-targz": "npm run build && electron-builder --linux tar.gz", "test:encryption": "tsc -p tsconfig.node.json && node ./dist/backend/backend/utils/encryption-test.js", - "migrate:encryption": "tsc -p tsconfig.node.json && node ./dist/backend/backend/utils/encryption-migration.js" + "migrate:encryption": "tsc -p tsconfig.node.json && node ./dist/backend/backend/utils/encryption-migration.js", + "prepare": "husky" }, "dependencies": { "@codemirror/autocomplete": "^6.18.7", @@ -105,6 +106,8 @@ "zod": "^4.0.5" }, "devDependencies": { + "@commitlint/cli": "^20.1.0", + "@commitlint/config-conventional": "^20.0.0", "@eslint/js": "^9.34.0", "@types/better-sqlite3": "^7.6.13", "@types/cors": "^2.8.19", @@ -123,9 +126,20 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.3.0", + "husky": "^9.1.7", + "lint-staged": "^16.2.3", "prettier": "3.6.2", "typescript": "~5.9.2", "typescript-eslint": "^8.40.0", "vite": "^7.1.5" + }, + "lint-staged": { + "*.{js,jsx,ts,tsx}": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,css,md}": [ + "prettier --write" + ] } } diff --git a/src/backend/utils/field-crypto.ts b/src/backend/utils/field-crypto.ts index 2be3935e..a23dc086 100644 --- a/src/backend/utils/field-crypto.ts +++ b/src/backend/utils/field-crypto.ts @@ -27,12 +27,7 @@ class FieldCrypto { "oidc_identifier", "oidcIdentifier", ]), - ssh_data: new Set([ - "password", - "key", - "key_password", - "keyPassword", - ]), + ssh_data: new Set(["password", "key", "key_password", "keyPassword"]), ssh_credentials: new Set([ "password", "private_key", @@ -60,7 +55,11 @@ class FieldCrypto { ); const iv = crypto.randomBytes(this.IV_LENGTH); - const cipher = crypto.createCipheriv(this.ALGORITHM, fieldKey, iv) as any; + const cipher = crypto.createCipheriv( + this.ALGORITHM, + fieldKey, + iv, + ) as crypto.CipherGCM; let encrypted = cipher.update(plaintext, "utf8", "hex"); encrypted += cipher.final("hex"); @@ -102,7 +101,7 @@ class FieldCrypto { this.ALGORITHM, fieldKey, Buffer.from(encrypted.iv, "hex"), - ) as any; + ) as crypto.DecipherGCM; decipher.setAuthTag(Buffer.from(encrypted.tag, "hex")); let decrypted = decipher.update(encrypted.data, "hex", "utf8"); -- 2.49.1 From 829666f84de2be4cb9efe3a682d6c6bf55a13d73 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 18:34:09 +0800 Subject: [PATCH 02/19] chore: enhance development environment - Add .editorconfig for unified editor settings - Add .nvmrc to specify Node.js version (20) - Add useful npm scripts: format, format:check, lint, lint:fix, type-check --- .editorconfig | 20 ++++++++++++++++++++ .nvmrc | 2 +- package.json | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..3a6a1797 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +# Matches multiple files with brace expansion notation +[*.{js,jsx,ts,tsx,json,css,scss,md,yml,yaml}] +indent_style = space +indent_size = 2 + +# Markdown files +[*.md] +trim_trailing_whitespace = false diff --git a/.nvmrc b/.nvmrc index 2bd5a0a9..209e3ef4 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22 +20 diff --git a/package.json b/package.json index 045aa3d2..8b51a9ec 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,11 @@ "type": "module", "scripts": { "clean": "npx prettier . --write", + "format": "prettier --write .", + "format:check": "prettier --check .", + "lint": "eslint .", + "lint:fix": "eslint --fix .", + "type-check": "tsc --noEmit", "dev": "vite", "build": "vite build && tsc -p tsconfig.node.json", "build:backend": "tsc -p tsconfig.node.json", -- 2.49.1 From bf2ad57042f65bbfb6f052f7f2076a849a581fe5 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 18:35:30 +0800 Subject: [PATCH 03/19] chore: add IDE and Git configuration - Add VS Code workspace settings for consistent development experience - Add VS Code extension recommendations (ESLint, Prettier, EditorConfig) - Add .gitattributes to enforce LF line endings --- .gitattributes | 36 ++++++++++++++++++++++++++++++++++++ .vscode/extensions.json | 7 +++++++ 2 files changed, 43 insertions(+) create mode 100644 .gitattributes create mode 100644 .vscode/extensions.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..0716d3da --- /dev/null +++ b/.gitattributes @@ -0,0 +1,36 @@ +# Auto detect text files and perform LF normalization +* text=auto eol=lf + +# Source code +*.js text eol=lf +*.jsx text eol=lf +*.ts text eol=lf +*.tsx text eol=lf +*.json text eol=lf +*.css text eol=lf +*.scss text eol=lf +*.html text eol=lf +*.md text eol=lf +*.yaml text eol=lf +*.yml text eol=lf + +# Scripts +*.sh text eol=lf +*.bash text eol=lf + +# Windows scripts should use CRLF +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf + +# Binary files +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.svg binary +*.woff binary +*.woff2 binary +*.ttf binary +*.eot binary diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..034db5d6 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "editorconfig.editorconfig" + ] +} -- 2.49.1 From 3533ce5a3434f61d46ed1dba87979a964d9262ae Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 19:51:17 +0800 Subject: [PATCH 04/19] refactor: clean up unused variables and empty blocks - database.ts: Remove unused variables (authManager, format, HTTPS_PORT, etc.) - database.ts: Fix empty catch blocks with descriptive comments - database.ts: Add eslint-disable for required middleware parameter - db/index.ts: Remove unused variables and fix empty catch blocks - Temporarily remove ESLint from pre-commit to allow incremental fixes Reduced total errors from 947 to 913 (34 fixes) --- package.json | 1 - src/backend/database/database.ts | 48 +++++++------------ src/backend/database/db/index.ts | 23 ++++++--- src/backend/database/routes/credentials.ts | 4 +- src/backend/database/routes/users.ts | 2 +- src/backend/ssh/file-manager.ts | 2 +- .../Desktop/Apps/File Manager/FileManager.tsx | 2 +- src/ui/main-axios.ts | 2 +- 8 files changed, 40 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 8b51a9ec..6ee59e8f 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,6 @@ }, "lint-staged": { "*.{js,jsx,ts,tsx}": [ - "eslint --fix", "prettier --write" ], "*.{json,css,md}": [ diff --git a/src/backend/database/database.ts b/src/backend/database/database.ts index 55f955e9..ca085f68 100644 --- a/src/backend/database/database.ts +++ b/src/backend/database/database.ts @@ -257,7 +257,7 @@ app.get("/version", authenticateJWT, async (req, res) => { localVersion = foundVersion; break; } - } catch (error) { + } catch { continue; } } @@ -372,7 +372,6 @@ app.get("/releases/rss", authenticateJWT, async (req, res) => { app.get("/encryption/status", requireAdmin, async (req, res) => { try { - const authManager = AuthManager.getInstance(); const securityStatus = { initialized: true, system: { hasSecret: true, isValid: true }, @@ -417,8 +416,6 @@ app.post("/encryption/initialize", requireAdmin, async (req, res) => { app.post("/encryption/regenerate", requireAdmin, async (req, res) => { try { - const authManager = AuthManager.getInstance(); - apiLogger.warn("System JWT secret regenerated via API", { operation: "jwt_regenerate_api", }); @@ -440,8 +437,6 @@ app.post("/encryption/regenerate", requireAdmin, async (req, res) => { app.post("/encryption/regenerate-jwt", requireAdmin, async (req, res) => { try { - const authManager = AuthManager.getInstance(); - apiLogger.warn("JWT secret regenerated via API", { operation: "jwt_secret_regenerate_api", }); @@ -968,7 +963,7 @@ app.post( try { importDb = new Database(req.file.path, { readonly: true }); - const tables = importDb + importDb .prepare("SELECT name FROM sqlite_master WHERE type='table'") .all(); } catch (sqliteError) { @@ -1059,7 +1054,7 @@ app.post( ); } } - } catch (tableError) { + } catch { apiLogger.info("ssh_data table not found in import file, skipping"); } @@ -1120,7 +1115,7 @@ app.post( ); } } - } catch (tableError) { + } catch { apiLogger.info( "ssh_credentials table not found in import file, skipping", ); @@ -1191,7 +1186,7 @@ app.post( ); } } - } catch (tableError) { + } catch { apiLogger.info(`${table} table not found in import file, skipping`); } } @@ -1229,7 +1224,7 @@ app.post( ); } } - } catch (tableError) { + } catch { apiLogger.info( "dismissed_alerts table not found in import file, skipping", ); @@ -1270,7 +1265,7 @@ app.post( ); } } - } catch (tableError) { + } catch { apiLogger.info("settings table not found in import file, skipping"); } } else { @@ -1288,7 +1283,7 @@ app.post( try { fs.unlinkSync(req.file.path); - } catch (cleanupError) { + } catch { apiLogger.warn("Failed to clean up uploaded file", { operation: "file_cleanup_warning", filePath: req.file.path, @@ -1314,7 +1309,7 @@ app.post( if (req.file?.path && fs.existsSync(req.file.path)) { try { fs.unlinkSync(req.file.path); - } catch (cleanupError) { + } catch { apiLogger.warn("Failed to clean up uploaded file after error", { operation: "file_cleanup_error", filePath: req.file.path, @@ -1337,11 +1332,7 @@ app.post( app.post("/database/export/preview", authenticateJWT, async (req, res) => { try { const userId = (req as any).userId; - const { - format = "encrypted", - scope = "user_data", - includeCredentials = true, - } = req.body; + const { scope = "user_data", includeCredentials = true } = req.body; const exportData = await UserDataExport.exportUserData(userId, { format: "encrypted", @@ -1417,7 +1408,8 @@ app.use( err: unknown, req: express.Request, res: express.Response, - next: express.NextFunction, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _next: express.NextFunction, ) => { apiLogger.error("Unhandled error in request", err, { operation: "error_handler", @@ -1430,7 +1422,6 @@ app.use( ); const HTTP_PORT = 30001; -const HTTPS_PORT = process.env.SSL_PORT || 8443; async function initializeSecurity() { try { @@ -1443,13 +1434,6 @@ async function initializeSecurity() { if (!isValid) { throw new Error("Security system validation failed"); } - - const securityStatus = { - initialized: true, - system: { hasSecret: true, isValid: true }, - activeSessions: {}, - activeSessionCount: 0, - }; } catch (error) { databaseLogger.error("Failed to initialize security system", error, { operation: "security_init_error", @@ -1481,13 +1465,17 @@ app.get( if (status.hasUnencryptedDb) { try { unencryptedSize = fs.statSync(dbPath).size; - } catch (error) {} + } catch { + // Ignore file access errors + } } if (status.hasEncryptedDb) { try { encryptedSize = fs.statSync(encryptedDbPath).size; - } catch (error) {} + } catch { + // Ignore file access errors + } } res.json({ diff --git a/src/backend/database/db/index.ts b/src/backend/database/db/index.ts index 88cca125..03c614f7 100644 --- a/src/backend/database/db/index.ts +++ b/src/backend/database/db/index.ts @@ -23,7 +23,7 @@ const enableFileEncryption = process.env.DB_FILE_ENCRYPTION !== "false"; const dbPath = path.join(dataDir, "db.sqlite"); const encryptedDbPath = `${dbPath}.encrypted`; -let actualDbPath = ":memory:"; +const actualDbPath = ":memory:"; let memoryDatabase: Database.Database; let isNewDatabase = false; let sqlite: Database.Database; @@ -31,7 +31,8 @@ let sqlite: Database.Database; async function initializeDatabaseAsync(): Promise { const systemCrypto = SystemCrypto.getInstance(); - const dbKey = await systemCrypto.getDatabaseKey(); + // Ensure database key is initialized + await systemCrypto.getDatabaseKey(); if (enableFileEncryption) { try { if (DatabaseFileEncryption.isEncryptedDatabaseFile(encryptedDbPath)) { @@ -277,7 +278,7 @@ const addColumnIfNotExists = ( FROM ${table} LIMIT 1`, ) .get(); - } catch (e) { + } catch { try { sqlite.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition};`); @@ -476,21 +477,29 @@ async function cleanupDatabase() { for (const file of files) { try { fs.unlinkSync(path.join(tempDir, file)); - } catch {} + } catch { + // Ignore cleanup errors + } } try { fs.rmdirSync(tempDir); - } catch {} + } catch { + // Ignore cleanup errors + } } - } catch (error) {} + } catch { + // Ignore cleanup errors + } } process.on("exit", () => { if (sqlite) { try { sqlite.close(); - } catch {} + } catch { + // Ignore close errors on exit + } } }); diff --git a/src/backend/database/routes/credentials.ts b/src/backend/database/routes/credentials.ts index 9c6dc909..b6a510ca 100644 --- a/src/backend/database/routes/credentials.ts +++ b/src/backend/database/routes/credentials.ts @@ -970,7 +970,7 @@ router.post( try { let privateKeyObj; - let parseAttempts = []; + const parseAttempts = []; try { privateKeyObj = crypto.createPrivateKey({ @@ -1521,7 +1521,7 @@ router.post( const hostData = targetHost[0]; - let hostConfig = { + const hostConfig = { ip: hostData.ip, port: hostData.port, username: hostData.username, diff --git a/src/backend/database/routes/users.ts b/src/backend/database/routes/users.ts index 3c2303cc..43e1794d 100644 --- a/src/backend/database/routes/users.ts +++ b/src/backend/database/routes/users.ts @@ -606,7 +606,7 @@ router.get("/oidc/callback", async (req, res) => { const tokenData = (await tokenResponse.json()) as any; let userInfo: any = null; - let userInfoUrls: string[] = []; + const userInfoUrls: string[] = []; const normalizedIssuerUrl = config.issuer_url.endsWith("/") ? config.issuer_url.slice(0, -1) diff --git a/src/backend/ssh/file-manager.ts b/src/backend/ssh/file-manager.ts index 99ce1e95..33b38439 100644 --- a/src/backend/ssh/file-manager.ts +++ b/src/backend/ssh/file-manager.ts @@ -461,7 +461,7 @@ app.get("/ssh/file_manager/ssh/listFiles", (req, res) => { const size = parseInt(parts[4], 10); let dateStr = ""; - let nameStartIndex = 8; + const nameStartIndex = 8; if (parts[5] && parts[6] && parts[7]) { dateStr = `${parts[5]} ${parts[6]} ${parts[7]}`; diff --git a/src/ui/Desktop/Apps/File Manager/FileManager.tsx b/src/ui/Desktop/Apps/File Manager/FileManager.tsx index 73ac9bc6..fdf26575 100644 --- a/src/ui/Desktop/Apps/File Manager/FileManager.tsx +++ b/src/ui/Desktop/Apps/File Manager/FileManager.tsx @@ -709,7 +709,7 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) { } try { - let currentSessionId = sshSessionId; + const currentSessionId = sshSessionId; try { const status = await getSSHStatus(currentSessionId); if (!status.connected) { diff --git a/src/ui/main-axios.ts b/src/ui/main-axios.ts index c1f2a660..57360fe4 100644 --- a/src/ui/main-axios.ts +++ b/src/ui/main-axios.ts @@ -320,7 +320,7 @@ function isDev(): boolean { ); } -let apiHost = import.meta.env.VITE_API_HOST || "localhost"; +const apiHost = import.meta.env.VITE_API_HOST || "localhost"; let apiPort = 30001; let configuredServerUrl: string | null = null; -- 2.49.1 From afd254d1ffcb734885f80e3f501efab9aabada5c Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:01:56 +0800 Subject: [PATCH 05/19] refactor: clean up unused variables and empty blocks in routes Routes updated: - credentials.ts: Remove 12 unused variables/imports - alerts.ts: Remove 1 unused variable - users.ts: Remove 9 unused variables/imports Changes: - Remove unused imports (NextFunction, jwt, UserCrypto, detectKeyType) - Fix empty catch blocks with descriptive comments - Prefix reserved parameters with underscore - Clean up unused error variables in catch blocks Reduced errors from 913 to 886 (27 fixes) --- src/backend/database/routes/alerts.ts | 2 +- src/backend/database/routes/credentials.ts | 33 ++++++++++++++-------- src/backend/database/routes/users.ts | 22 +++++---------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/backend/database/routes/alerts.ts b/src/backend/database/routes/alerts.ts index 4f836894..f1f113ff 100644 --- a/src/backend/database/routes/alerts.ts +++ b/src/backend/database/routes/alerts.ts @@ -170,7 +170,7 @@ router.post("/dismiss", authenticateJWT, async (req, res) => { return res.status(409).json({ error: "Alert already dismissed" }); } - const result = await db.insert(dismissedAlerts).values({ + await db.insert(dismissedAlerts).values({ userId, alertId, }); diff --git a/src/backend/database/routes/credentials.ts b/src/backend/database/routes/credentials.ts index b6a510ca..38614195 100644 --- a/src/backend/database/routes/credentials.ts +++ b/src/backend/database/routes/credentials.ts @@ -2,15 +2,13 @@ import express from "express"; import { db } from "../db/index.js"; import { sshCredentials, sshCredentialUsage, sshData } from "../db/schema.js"; import { eq, and, desc, sql } from "drizzle-orm"; -import type { Request, Response, NextFunction } from "express"; -import jwt from "jsonwebtoken"; +import type { Request, Response } from "express"; import { authLogger } from "../../utils/logger.js"; import { SimpleDBOps } from "../../utils/simple-db-ops.js"; import { AuthManager } from "../../utils/auth-manager.js"; import { parseSSHKey, parsePublicKey, - detectKeyType, validateKeyPair, } from "../../utils/ssh-key-utils.js"; import crypto from "crypto"; @@ -1093,7 +1091,9 @@ router.post( finalPublicKey = `${keyType} ${base64Data}`; formatType = "ssh"; } - } catch (sshError) {} + } catch { + // Ignore validation errors + } const response = { success: true, @@ -1119,7 +1119,8 @@ router.post( async function deploySSHKeyToHost( hostConfig: any, publicKey: string, - credentialData: any, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _credentialData: any, ): Promise<{ success: boolean; message?: string; error?: string }> { return new Promise((resolve) => { const conn = new Client(); @@ -1158,7 +1159,9 @@ async function deploySSHKeyToHost( } }); - stream.on("data", (data) => {}); + stream.on("data", () => { + // Ignore output + }); }, ); }); @@ -1175,7 +1178,9 @@ async function deploySSHKeyToHost( if (parsed.data) { actualPublicKey = parsed.data; } - } catch (e) {} + } catch { + // Ignore parse errors + } const keyParts = actualPublicKey.trim().split(" "); if (keyParts.length < 2) { @@ -1202,7 +1207,7 @@ async function deploySSHKeyToHost( output += data.toString(); }); - stream.on("close", (code) => { + stream.on("close", () => { clearTimeout(checkTimeout); const exists = output.trim() === "0"; resolveCheck(exists); @@ -1229,7 +1234,9 @@ async function deploySSHKeyToHost( if (parsed.data) { actualPublicKey = parsed.data; } - } catch (e) {} + } catch { + // Ignore parse errors + } const escapedKey = actualPublicKey .replace(/\\/g, "\\\\") @@ -1269,7 +1276,9 @@ async function deploySSHKeyToHost( if (parsed.data) { actualPublicKey = parsed.data; } - } catch (e) {} + } catch { + // Ignore parse errors + } const keyParts = actualPublicKey.trim().split(" "); if (keyParts.length < 2) { @@ -1295,7 +1304,7 @@ async function deploySSHKeyToHost( output += data.toString(); }); - stream.on("close", (code) => { + stream.on("close", () => { clearTimeout(verifyTimeout); const verified = output.trim() === "0"; resolveVerify(verified); @@ -1571,7 +1580,7 @@ router.post( error: "Host credential not found", }); } - } catch (error) { + } catch { return res.status(500).json({ success: false, error: "Failed to resolve host credentials", diff --git a/src/backend/database/routes/users.ts b/src/backend/database/routes/users.ts index 43e1794d..7ea4f49c 100644 --- a/src/backend/database/routes/users.ts +++ b/src/backend/database/routes/users.ts @@ -18,7 +18,6 @@ import QRCode from "qrcode"; import type { Request, Response } from "express"; import { authLogger } from "../../utils/logger.js"; import { AuthManager } from "../../utils/auth-manager.js"; -import { UserCrypto } from "../../utils/user-crypto.js"; import { DataCrypto } from "../../utils/data-crypto.js"; import { LazyFieldEncryption } from "../../utils/lazy-field-encryption.js"; @@ -60,7 +59,6 @@ async function verifyOIDCToken( } let jwks: any = null; - let jwksUrl: string | null = null; for (const url of jwksUrls) { try { @@ -69,7 +67,6 @@ async function verifyOIDCToken( const jwksData = (await response.json()) as any; if (jwksData && jwksData.keys && Array.isArray(jwksData.keys)) { jwks = jwksData; - jwksUrl = url; break; } else { authLogger.error( @@ -77,8 +74,9 @@ async function verifyOIDCToken( ); } } else { + // Non-200 response } - } catch (error) { + } catch { continue; } } @@ -125,15 +123,8 @@ function isNonEmptyString(val: any): val is string { return typeof val === "string" && val.trim().length > 0; } -interface JWTPayload { - userId: string; - iat?: number; - exp?: number; -} - const authenticateJWT = authManager.createAuthMiddleware(); const requireAdmin = authManager.createAdminMiddleware(); -const requireDataAccess = authManager.createDataAccessMiddleware(); // Route: Create traditional user (username/password) // POST /users/create @@ -451,7 +442,7 @@ router.get("/oidc-config", async (req, res) => { } else { config.client_secret = "[ENCRYPTED - PASSWORD REQUIRED]"; } - } catch (decryptError) { + } catch { authLogger.warn("Failed to decrypt OIDC config for admin", { operation: "oidc_config_decrypt_failed", userId, @@ -651,7 +642,8 @@ router.get("/oidc/callback", async (req, res) => { config.issuer_url, config.client_id, ); - } catch (error) { + } catch { + // Fallback to manual decoding try { const parts = tokenData.id_token.split("."); if (parts.length === 3) { @@ -894,7 +886,7 @@ router.post("/login", async (req, res) => { if (kekSalt.length === 0) { await authManager.registerUser(userRecord.id, password); } - } catch (setupError) { + } catch { // Continue if setup fails - authenticateUser will handle it } @@ -1561,7 +1553,7 @@ router.post("/totp/verify-login", async (req, res) => { backupCodes = userRecord.totp_backup_codes ? JSON.parse(userRecord.totp_backup_codes) : []; - } catch (parseError) { + } catch { backupCodes = []; } -- 2.49.1 From ffaccaadf257cc150bf41c04f4893bfd13052674 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:15:10 +0800 Subject: [PATCH 06/19] refactor: clean up unused variables in routes/ssh.ts - Remove unused imports (NextFunction, jwt) - Remove 6 unused variables (result, updateResult, name x3) - All 8 no-unused-vars errors fixed --- src/backend/database/routes/ssh.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/backend/database/routes/ssh.ts b/src/backend/database/routes/ssh.ts index 3cb76e67..23f7191d 100644 --- a/src/backend/database/routes/ssh.ts +++ b/src/backend/database/routes/ssh.ts @@ -9,8 +9,7 @@ import { fileManagerShortcuts, } from "../db/schema.js"; import { eq, and, desc, isNotNull, or } from "drizzle-orm"; -import type { Request, Response, NextFunction } from "express"; -import jwt from "jsonwebtoken"; +import type { Request, Response } from "express"; import multer from "multer"; import { sshLogger } from "../../utils/logger.js"; import { SimpleDBOps } from "../../utils/simple-db-ops.js"; @@ -816,7 +815,7 @@ router.delete( ), ); - const result = await db + await db .delete(sshData) .where(and(eq(sshData.id, numericHostId), eq(sshData.userId, userId))); @@ -943,7 +942,7 @@ router.delete( authenticateJWT, async (req: Request, res: Response) => { const userId = (req as any).userId; - const { hostId, path, name } = req.body; + const { hostId, path } = req.body; if (!isNonEmptyString(userId) || !hostId || !path) { sshLogger.warn("Invalid data for recent file deletion"); @@ -1063,7 +1062,7 @@ router.delete( authenticateJWT, async (req: Request, res: Response) => { const userId = (req as any).userId; - const { hostId, path, name } = req.body; + const { hostId, path } = req.body; if (!isNonEmptyString(userId) || !hostId || !path) { sshLogger.warn("Invalid data for pinned file deletion"); @@ -1183,7 +1182,7 @@ router.delete( authenticateJWT, async (req: Request, res: Response) => { const userId = (req as any).userId; - const { hostId, path, name } = req.body; + const { hostId, path } = req.body; if (!isNonEmptyString(userId) || !hostId || !path) { sshLogger.warn("Invalid data for shortcut deletion"); @@ -1558,7 +1557,7 @@ router.post( } } - const updateResult = await db + await db .update(sshData) .set({ autostartPassword: decryptedConfig.password || null, @@ -1615,7 +1614,7 @@ router.delete( } try { - const result = await db + await db .update(sshData) .set({ autostartPassword: null, -- 2.49.1 From 93a74277dcb6219025c5c0a6fc4a9a2197543c0a Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:23:15 +0800 Subject: [PATCH 07/19] refactor: clean up unused variables and empty blocks in file-manager.ts - Remove 22 unused variables (linkCount, hostId, userId, content, escapedTempFile, index, code) - Fix 1 empty catch block - Simplify multiple route handlers by removing unused destructured parameters Reduced errors from 878 to 855 (23 fixes) --- src/backend/ssh/file-manager.ts | 43 ++++++++++----------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/src/backend/ssh/file-manager.ts b/src/backend/ssh/file-manager.ts index 33b38439..bdd2892a 100644 --- a/src/backend/ssh/file-manager.ts +++ b/src/backend/ssh/file-manager.ts @@ -101,7 +101,9 @@ function cleanupSession(sessionId: string) { if (session) { try { session.client.end(); - } catch {} + } catch { + // Ignore connection close errors + } clearTimeout(session.timeout); delete sshSessions[sessionId]; } @@ -455,7 +457,6 @@ app.get("/ssh/file_manager/ssh/listFiles", (req, res) => { const parts = line.split(/\s+/); if (parts.length >= 9) { const permissions = parts[0]; - const linkCount = parts[1]; const owner = parts[2]; const group = parts[3]; const size = parseInt(parts[4], 10); @@ -694,7 +695,7 @@ app.get("/ssh/file_manager/ssh/readFile", (req, res) => { }); app.post("/ssh/file_manager/ssh/writeFile", async (req, res) => { - const { sessionId, path: filePath, content, hostId, userId } = req.body; + const { sessionId, path: filePath, content } = req.body; const sshConn = sshSessions[sessionId]; if (!sessionId) { @@ -881,14 +882,7 @@ app.post("/ssh/file_manager/ssh/writeFile", async (req, res) => { }); app.post("/ssh/file_manager/ssh/uploadFile", async (req, res) => { - const { - sessionId, - path: filePath, - content, - fileName, - hostId, - userId, - } = req.body; + const { sessionId, path: filePath, content, fileName } = req.body; const sshConn = sshSessions[sessionId]; if (!sessionId) { @@ -1022,8 +1016,6 @@ app.post("/ssh/file_manager/ssh/uploadFile", async (req, res) => { } if (chunks.length === 1) { - const tempFile = `/tmp/upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; - const escapedTempFile = tempFile.replace(/'/g, "'\"'\"'"); const escapedPath = fullPath.replace(/'/g, "'\"'\"'"); const writeCommand = `echo '${chunks[0]}' | base64 -d > '${escapedPath}' && echo "SUCCESS"`; @@ -1088,13 +1080,11 @@ app.post("/ssh/file_manager/ssh/uploadFile", async (req, res) => { }); }); } else { - const tempFile = `/tmp/upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; - const escapedTempFile = tempFile.replace(/'/g, "'\"'\"'"); const escapedPath = fullPath.replace(/'/g, "'\"'\"'"); let writeCommand = `> '${escapedPath}'`; - chunks.forEach((chunk, index) => { + chunks.forEach((chunk) => { writeCommand += ` && echo '${chunk}' | base64 -d >> '${escapedPath}'`; }); @@ -1177,14 +1167,7 @@ app.post("/ssh/file_manager/ssh/uploadFile", async (req, res) => { }); app.post("/ssh/file_manager/ssh/createFile", async (req, res) => { - const { - sessionId, - path: filePath, - fileName, - content = "", - hostId, - userId, - } = req.body; + const { sessionId, path: filePath, fileName } = req.body; const sshConn = sshSessions[sessionId]; if (!sessionId) { @@ -1285,7 +1268,7 @@ app.post("/ssh/file_manager/ssh/createFile", async (req, res) => { }); app.post("/ssh/file_manager/ssh/createFolder", async (req, res) => { - const { sessionId, path: folderPath, folderName, hostId, userId } = req.body; + const { sessionId, path: folderPath, folderName } = req.body; const sshConn = sshSessions[sessionId]; if (!sessionId) { @@ -1386,7 +1369,7 @@ app.post("/ssh/file_manager/ssh/createFolder", async (req, res) => { }); app.delete("/ssh/file_manager/ssh/deleteItem", async (req, res) => { - const { sessionId, path: itemPath, isDirectory, hostId, userId } = req.body; + const { sessionId, path: itemPath, isDirectory } = req.body; const sshConn = sshSessions[sessionId]; if (!sessionId) { @@ -1488,7 +1471,7 @@ app.delete("/ssh/file_manager/ssh/deleteItem", async (req, res) => { }); app.put("/ssh/file_manager/ssh/renameItem", async (req, res) => { - const { sessionId, oldPath, newName, hostId, userId } = req.body; + const { sessionId, oldPath, newName } = req.body; const sshConn = sshSessions[sessionId]; if (!sessionId) { @@ -1596,7 +1579,7 @@ app.put("/ssh/file_manager/ssh/renameItem", async (req, res) => { }); app.put("/ssh/file_manager/ssh/moveItem", async (req, res) => { - const { sessionId, oldPath, newPath, hostId, userId } = req.body; + const { sessionId, oldPath, newPath } = req.body; const sshConn = sshSessions[sessionId]; if (!sessionId) { @@ -1985,7 +1968,7 @@ app.post("/ssh/file_manager/ssh/copyItem", async (req, res) => { }); app.post("/ssh/file_manager/ssh/executeFile", async (req, res) => { - const { sessionId, filePath, hostId, userId } = req.body; + const { sessionId, filePath } = req.body; const sshConn = sshSessions[sessionId]; if (!sshConn || !sshConn.isConnected) { @@ -2022,7 +2005,7 @@ app.post("/ssh/file_manager/ssh/executeFile", async (req, res) => { checkResult += data.toString(); }); - checkStream.on("close", (code) => { + checkStream.on("close", () => { if (!checkResult.includes("EXECUTABLE")) { return res.status(400).json({ error: "File is not executable" }); } -- 2.49.1 From 83610cb0779f51f65d9e8ca7f887248e6e6b83be Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:31:34 +0800 Subject: [PATCH 08/19] refactor: clean up unused variables and empty blocks in utils database-migration.ts: - Remove 3 unused variables (encryptedSize, totalOriginalRows, totalMemoryRows) lazy-field-encryption.ts: - Fix 6 empty catch blocks with descriptive comments - Keep error variables where they are used in logging tunnel.ts: - Fix multiple empty catch blocks - Remove empty else blocks - Partially fixed (10/21 issues resolved) Reduced errors from 855 to 833 (22 fixes) --- src/backend/ssh/tunnel.ts | 20 +++++++++++++------- src/backend/utils/database-migration.ts | 7 ------- src/backend/utils/lazy-field-encryption.ts | 18 +++++++++++------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/backend/ssh/tunnel.ts b/src/backend/ssh/tunnel.ts index b49606e6..fea461c6 100644 --- a/src/backend/ssh/tunnel.ts +++ b/src/backend/ssh/tunnel.ts @@ -217,7 +217,9 @@ function cleanupTunnelResources( if (verification?.timeout) clearTimeout(verification.timeout); try { verification?.conn.end(); - } catch (e) {} + } catch { + // Ignore errors + } tunnelVerifications.delete(tunnelName); } @@ -282,7 +284,9 @@ function handleDisconnect( const verification = tunnelVerifications.get(tunnelName); if (verification?.timeout) clearTimeout(verification.timeout); verification?.conn.end(); - } catch (e) {} + } catch { + // Ignore errors + } tunnelVerifications.delete(tunnelName); } @@ -518,9 +522,7 @@ async function connectSSHTunnel( keyType: credential.key_type || credential.keyType, authMethod: credential.auth_type || credential.authType, }; - } else { } - } else { } } catch (error) { tunnelLogger.warn("Failed to resolve source credentials from database", { @@ -631,7 +633,9 @@ async function connectSSHTunnel( try { conn.end(); - } catch (e) {} + } catch { + // Ignore errors + } activeTunnels.delete(tunnelName); @@ -771,7 +775,9 @@ async function connectSSHTunnel( const verification = tunnelVerifications.get(tunnelName); if (verification?.timeout) clearTimeout(verification.timeout); verification?.conn.end(); - } catch (e) {} + } catch { + // Ignore errors + } tunnelVerifications.delete(tunnelName); } @@ -1186,7 +1192,7 @@ async function killRemoteTunnelByMarker( } else { } - stream.on("close", (code) => { + stream.on("close", () => { commandIndex++; executeNextKillCommand(); }); diff --git a/src/backend/utils/database-migration.ts b/src/backend/utils/database-migration.ts index ebf3192b..0fba053e 100644 --- a/src/backend/utils/database-migration.ts +++ b/src/backend/utils/database-migration.ts @@ -55,7 +55,6 @@ export class DatabaseMigration { if (hasEncryptedDb && hasUnencryptedDb) { const unencryptedSize = fs.statSync(this.unencryptedDbPath).size; - const encryptedSize = fs.statSync(this.encryptedDbPath).size; if (unencryptedSize === 0) { needsMigration = false; @@ -168,9 +167,6 @@ export class DatabaseMigration { return false; } - let totalOriginalRows = 0; - let totalMemoryRows = 0; - for (const table of originalTables) { const originalCount = originalDb .prepare(`SELECT COUNT(*) as count FROM ${table.name}`) @@ -179,9 +175,6 @@ export class DatabaseMigration { .prepare(`SELECT COUNT(*) as count FROM ${table.name}`) .get() as { count: number }; - totalOriginalRows += originalCount.count; - totalMemoryRows += memoryCount.count; - if (originalCount.count !== memoryCount.count) { databaseLogger.error( "Row count mismatch for table during migration verification", diff --git a/src/backend/utils/lazy-field-encryption.ts b/src/backend/utils/lazy-field-encryption.ts index 06c43d8c..2fd7cce1 100644 --- a/src/backend/utils/lazy-field-encryption.ts +++ b/src/backend/utils/lazy-field-encryption.ts @@ -29,7 +29,7 @@ export class LazyFieldEncryption { return false; } return true; - } catch (jsonError) { + } catch { return true; } } @@ -53,7 +53,7 @@ export class LazyFieldEncryption { fieldName, ); return decrypted; - } catch (error) { + } catch { const legacyFieldName = this.LEGACY_FIELD_NAME_MAP[fieldName]; if (legacyFieldName) { try { @@ -64,7 +64,9 @@ export class LazyFieldEncryption { legacyFieldName, ); return decrypted; - } catch (legacyError) {} + } catch { + // Ignore legacy format errors + } } const sensitiveFields = [ @@ -135,7 +137,7 @@ export class LazyFieldEncryption { wasPlaintext: false, wasLegacyEncryption: false, }; - } catch (error) { + } catch { const legacyFieldName = this.LEGACY_FIELD_NAME_MAP[fieldName]; if (legacyFieldName) { try { @@ -156,7 +158,9 @@ export class LazyFieldEncryption { wasPlaintext: false, wasLegacyEncryption: true, }; - } catch (legacyError) {} + } catch { + // Ignore legacy format errors + } } return { encrypted: fieldValue, @@ -243,7 +247,7 @@ export class LazyFieldEncryption { try { FieldCrypto.decryptField(fieldValue, userKEK, recordId, fieldName); return false; - } catch (error) { + } catch { const legacyFieldName = this.LEGACY_FIELD_NAME_MAP[fieldName]; if (legacyFieldName) { try { @@ -254,7 +258,7 @@ export class LazyFieldEncryption { legacyFieldName, ); return true; - } catch (legacyError) { + } catch { return false; } } -- 2.49.1 From bbceb671fce7542597fa9b4d1f1988f91e5f9d73 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:33:41 +0800 Subject: [PATCH 09/19] fix: restore error variable in catch block for logging Fix TypeScript error where error variable was removed from catch block but still used in logging statements. The error variable is needed for proper error logging and re-throwing. --- src/backend/utils/lazy-field-encryption.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/utils/lazy-field-encryption.ts b/src/backend/utils/lazy-field-encryption.ts index 2fd7cce1..5b376c4f 100644 --- a/src/backend/utils/lazy-field-encryption.ts +++ b/src/backend/utils/lazy-field-encryption.ts @@ -53,7 +53,7 @@ export class LazyFieldEncryption { fieldName, ); return decrypted; - } catch { + } catch (error) { const legacyFieldName = this.LEGACY_FIELD_NAME_MAP[fieldName]; if (legacyFieldName) { try { -- 2.49.1 From 78ae23f680a99e6891d254dd2cf109785208cb70 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:37:43 +0800 Subject: [PATCH 10/19] fix: clean up tunnel.ts empty blocks and unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除了 tunnel.ts 中的空块和未使用的变量: - 移除 2 个空 else 块 - 修复 2 个空 if 块并添加注释 - 修复空错误处理器并添加注释 - 将未使用的 err 参数重命名为 _err 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/backend/ssh/tunnel.ts | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/backend/ssh/tunnel.ts b/src/backend/ssh/tunnel.ts index fea461c6..b652d857 100644 --- a/src/backend/ssh/tunnel.ts +++ b/src/backend/ssh/tunnel.ts @@ -607,7 +607,6 @@ async function connectSSHTunnel( credentialId: tunnelConfig.endpointCredentialId, }); } - } else { } } catch (error) { tunnelLogger.warn( @@ -829,12 +828,12 @@ async function connectSSHTunnel( }); stream.stdout?.on("data", (data: Buffer) => { - const output = data.toString().trim(); - if (output) { - } + // Silently consume stdout data }); - stream.on("error", (err: Error) => {}); + stream.on("error", () => { + // Silently consume stream errors + }); stream.stderr.on("data", (data) => { const errorMsg = data.toString().trim(); @@ -1040,7 +1039,6 @@ async function killRemoteTunnelByMarker( authMethod: credential.auth_type || credential.authType, }; } - } else { } } catch (error) { tunnelLogger.warn("Failed to resolve source credentials for cleanup", { @@ -1128,7 +1126,7 @@ async function killRemoteTunnelByMarker( conn.on("ready", () => { const checkCmd = `ps aux | grep -E '(${tunnelMarker}|ssh.*-R.*${tunnelConfig.endpointPort}:localhost:${tunnelConfig.sourcePort}.*${tunnelConfig.endpointUsername}@${tunnelConfig.endpointIP}|sshpass.*ssh.*-R.*${tunnelConfig.endpointPort})' | grep -v grep`; - conn.exec(checkCmd, (err, stream) => { + conn.exec(checkCmd, (_err, stream) => { let foundProcesses = false; stream.on("data", (data) => { @@ -1156,7 +1154,7 @@ async function killRemoteTunnelByMarker( function executeNextKillCommand() { if (commandIndex >= killCmds.length) { - conn.exec(checkCmd, (err, verifyStream) => { + conn.exec(checkCmd, (_err, verifyStream) => { let stillRunning = false; verifyStream.on("data", (data) => { @@ -1189,7 +1187,6 @@ async function killRemoteTunnelByMarker( tunnelLogger.warn( `Kill command ${commandIndex + 1} failed for '${tunnelName}': ${err.message}`, ); - } else { } stream.on("close", () => { @@ -1197,10 +1194,8 @@ async function killRemoteTunnelByMarker( executeNextKillCommand(); }); - stream.on("data", (data) => { - const output = data.toString().trim(); - if (output) { - } + stream.on("data", () => { + // Silently consume stream data }); stream.stderr.on("data", (data) => { -- 2.49.1 From d75b76dbb9e87d5f64bb0271cc318e7be7e84e12 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:40:45 +0800 Subject: [PATCH 11/19] fix: clean up empty blocks and unused variables in backend utils MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了后端工具文件中的空块和未使用的变量: - auth-manager.ts: 移除空 else 块 - system-crypto.ts: 修复空 catch 块并添加注释 - starter.ts: 修复空 catch 块并添加注释 - server-stats.ts: 将未使用的 reject 参数重命名为 _reject - credentials.ts: 将 connectionTimeout 从 let 改为 const 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/backend/database/routes/credentials.ts | 3 +-- src/backend/ssh/server-stats.ts | 2 +- src/backend/starter.ts | 4 +++- src/backend/utils/auth-manager.ts | 1 - src/backend/utils/system-crypto.ts | 4 +++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/backend/database/routes/credentials.ts b/src/backend/database/routes/credentials.ts index 38614195..86a46705 100644 --- a/src/backend/database/routes/credentials.ts +++ b/src/backend/database/routes/credentials.ts @@ -1124,9 +1124,8 @@ async function deploySSHKeyToHost( ): Promise<{ success: boolean; message?: string; error?: string }> { return new Promise((resolve) => { const conn = new Client(); - let connectionTimeout: NodeJS.Timeout; - connectionTimeout = setTimeout(() => { + const connectionTimeout = setTimeout(() => { conn.destroy(); resolve({ success: false, error: "Connection timeout" }); }, 120000); diff --git a/src/backend/ssh/server-stats.ts b/src/backend/ssh/server-stats.ts index f580bb96..1dfd27e3 100644 --- a/src/backend/ssh/server-stats.ts +++ b/src/backend/ssh/server-stats.ts @@ -60,7 +60,7 @@ class SSHConnectionPool { return client; } - return new Promise((resolve, reject) => { + return new Promise((resolve, _reject) => { const checkAvailable = () => { const available = connections.find((conn) => !conn.inUse); if (available) { diff --git a/src/backend/starter.ts b/src/backend/starter.ts index fb0cfc89..a7244082 100644 --- a/src/backend/starter.ts +++ b/src/backend/starter.ts @@ -21,7 +21,9 @@ import { systemLogger, versionLogger } from "./utils/logger.js"; if (persistentConfig.parsed) { Object.assign(process.env, persistentConfig.parsed); } - } catch {} + } catch { + // Ignore errors if .env file doesn't exist + } let version = "unknown"; diff --git a/src/backend/utils/auth-manager.ts b/src/backend/utils/auth-manager.ts index 541d889f..e85bae28 100644 --- a/src/backend/utils/auth-manager.ts +++ b/src/backend/utils/auth-manager.ts @@ -108,7 +108,6 @@ class AuthManager { if (migrationResult.migrated) { await saveMemoryDatabaseToFile(); - } else { } } catch (error) { databaseLogger.error("Lazy encryption migration failed", error, { diff --git a/src/backend/utils/system-crypto.ts b/src/backend/utils/system-crypto.ts index cd805bfc..ea0ab8ef 100644 --- a/src/backend/utils/system-crypto.ts +++ b/src/backend/utils/system-crypto.ts @@ -37,7 +37,9 @@ class SystemCrypto { process.env.JWT_SECRET = jwtMatch[1]; return; } - } catch {} + } catch { + // Ignore file read errors, will generate new secret + } await this.generateAndGuideUser(); } catch (error) { -- 2.49.1 From 91aed889a7f157740f5b45102cf8130bcda972eb Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:45:04 +0800 Subject: [PATCH 12/19] fix: clean up empty catch blocks in frontend components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了前端组件中的空 catch 块: - Tunnel.tsx: 修复空 catch 块并添加注释 - ServerConfig.tsx: 修复空 catch 块并添加注释 - TerminalKeyboard.tsx: 修复空 catch 块并添加注释 - system-crypto.ts: 修复遗漏的空 catch 块 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/backend/utils/system-crypto.ts | 4 +++- src/ui/Desktop/Apps/Tunnel/Tunnel.tsx | 3 ++- src/ui/Desktop/Electron Only/ServerConfig.tsx | 4 +++- src/ui/Mobile/Apps/Terminal/TerminalKeyboard.tsx | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/system-crypto.ts b/src/backend/utils/system-crypto.ts index ea0ab8ef..689a3137 100644 --- a/src/backend/utils/system-crypto.ts +++ b/src/backend/utils/system-crypto.ts @@ -76,7 +76,9 @@ class SystemCrypto { process.env.DATABASE_KEY = dbKeyMatch[1]; return; } - } catch {} + } catch { + // Ignore file read errors, will generate new key + } await this.generateAndGuideDatabaseKey(); } catch (error) { diff --git a/src/ui/Desktop/Apps/Tunnel/Tunnel.tsx b/src/ui/Desktop/Apps/Tunnel/Tunnel.tsx index 45c6f7cf..f658c3e1 100644 --- a/src/ui/Desktop/Apps/Tunnel/Tunnel.tsx +++ b/src/ui/Desktop/Apps/Tunnel/Tunnel.tsx @@ -191,7 +191,8 @@ export function Tunnel({ filterHostKey }: SSHTunnelProps): React.ReactElement { } await fetchTunnelStatuses(); - } catch (err) { + } catch { + // Ignore tunnel action errors } finally { setTunnelActions((prev) => ({ ...prev, [tunnelName]: false })); } diff --git a/src/ui/Desktop/Electron Only/ServerConfig.tsx b/src/ui/Desktop/Electron Only/ServerConfig.tsx index 3096ccf1..2343b519 100644 --- a/src/ui/Desktop/Electron Only/ServerConfig.tsx +++ b/src/ui/Desktop/Electron Only/ServerConfig.tsx @@ -43,7 +43,9 @@ export function ServerConfig({ setServerUrl(config.serverUrl); setConnectionStatus("success"); } - } catch (error) {} + } catch { + // Ignore config loading errors + } }; const handleTestConnection = async () => { diff --git a/src/ui/Mobile/Apps/Terminal/TerminalKeyboard.tsx b/src/ui/Mobile/Apps/Terminal/TerminalKeyboard.tsx index 66667060..597d10dc 100644 --- a/src/ui/Mobile/Apps/Terminal/TerminalKeyboard.tsx +++ b/src/ui/Mobile/Apps/Terminal/TerminalKeyboard.tsx @@ -110,7 +110,9 @@ export function TerminalKeyboard({ if (navigator.vibrate) { navigator.vibrate(20); } - } catch (e) {} + } catch { + // Ignore vibration errors on unsupported devices + } onSendInput(input); }, -- 2.49.1 From f12c08845cc3cc51a1b9e316b83849bf12bb9a0f Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 20:58:55 +0800 Subject: [PATCH 13/19] fix: clean up empty catch blocks in backend utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了后端工具文件中的 10 个空 catch 块: - system-crypto.ts: 修复 1 个空 catch 块 - server-stats.ts: 修复 4 个空 catch 块 - auto-ssl-setup.ts: 修复 1 个空 catch 块 - ssh-key-utils.ts: 修复 4 个空 catch 块 所有空块都添加了描述性注释说明为何忽略错误。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/backend/ssh/server-stats.ts | 16 ++++++++++++---- src/backend/utils/auto-ssl-setup.ts | 4 +++- src/backend/utils/ssh-key-utils.ts | 16 ++++++++++++---- src/backend/utils/system-crypto.ts | 4 +++- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/backend/ssh/server-stats.ts b/src/backend/ssh/server-stats.ts index 1dfd27e3..73911848 100644 --- a/src/backend/ssh/server-stats.ts +++ b/src/backend/ssh/server-stats.ts @@ -123,7 +123,9 @@ class SSHConnectionPool { if (!conn.inUse && now - conn.lastUsed > maxAge) { try { conn.client.end(); - } catch {} + } catch { + // Ignore errors when closing stale connections + } return false; } return true; @@ -143,7 +145,9 @@ class SSHConnectionPool { for (const conn of connections) { try { conn.client.end(); - } catch {} + } catch { + // Ignore errors when closing connections during cleanup + } } } this.connections.clear(); @@ -181,7 +185,9 @@ class RequestQueue { if (request) { try { await request(); - } catch (error) {} + } catch { + // Ignore errors from queued requests + } } } @@ -829,7 +835,9 @@ function tcpPing( settled = true; try { socket.destroy(); - } catch {} + } catch { + // Ignore errors when destroying socket + } resolve(result); }; diff --git a/src/backend/utils/auto-ssl-setup.ts b/src/backend/utils/auto-ssl-setup.ts index e2d1034a..5d9a6fc8 100644 --- a/src/backend/utils/auto-ssl-setup.ts +++ b/src/backend/utils/auto-ssl-setup.ts @@ -234,7 +234,9 @@ IP.3 = 0.0.0.0 let envContent = ""; try { envContent = await fs.readFile(this.ENV_FILE, "utf8"); - } catch {} + } catch { + // File doesn't exist yet, will create with SSL config + } let updatedContent = envContent; let hasChanges = false; diff --git a/src/backend/utils/ssh-key-utils.ts b/src/backend/utils/ssh-key-utils.ts index b19f95c9..9a9f813d 100644 --- a/src/backend/utils/ssh-key-utils.ts +++ b/src/backend/utils/ssh-key-utils.ts @@ -84,7 +84,9 @@ function detectKeyTypeFromContent(keyContent: string): string { } else if (decodedString.includes("1.3.101.112")) { return "ssh-ed25519"; } - } catch (error) {} + } catch { + // Cannot decode key, fallback to length-based detection + } if (content.length < 800) { return "ssh-ed25519"; @@ -140,7 +142,9 @@ function detectPublicKeyTypeFromContent(publicKeyContent: string): string { } else if (decodedString.includes("1.3.101.112")) { return "ssh-ed25519"; } - } catch (error) {} + } catch { + // Cannot decode key, fallback to length-based detection + } if (content.length < 400) { return "ssh-ed25519"; @@ -242,7 +246,9 @@ export function parseSSHKey( useSSH2 = true; } - } catch (error) {} + } catch { + // SSH2 parsing failed, will use fallback method + } } if (!useSSH2) { @@ -268,7 +274,9 @@ export function parseSSHKey( success: true, }; } - } catch (fallbackError) {} + } catch { + // Fallback parsing also failed + } return { privateKey: privateKeyData, diff --git a/src/backend/utils/system-crypto.ts b/src/backend/utils/system-crypto.ts index 689a3137..9f9c15b0 100644 --- a/src/backend/utils/system-crypto.ts +++ b/src/backend/utils/system-crypto.ts @@ -115,7 +115,9 @@ class SystemCrypto { process.env.INTERNAL_AUTH_TOKEN = tokenMatch[1]; return; } - } catch {} + } catch { + // Ignore file read errors, will generate new token + } await this.generateAndGuideInternalAuthToken(); } catch (error) { -- 2.49.1 From 3f9d0fad6b1ec095324f6369d17d06c3c7c5ea38 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 21:03:41 +0800 Subject: [PATCH 14/19] fix: clean up empty catch blocks in UI hooks and components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了 5 个 UI 组件和 hooks 中的空 catch 块: - useDragToSystemDesktop.ts: 修复 2 个空 catch 块 - HomepageAuth.tsx: 修复 1 个空 catch 块 - HostManagerEditor.tsx: 修复 2 个空 catch 块 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/ui/Desktop/Apps/Host Manager/HostManagerEditor.tsx | 6 ++++-- src/ui/Desktop/Homepage/HomepageAuth.tsx | 4 +++- src/ui/hooks/useDragToSystemDesktop.ts | 8 ++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/ui/Desktop/Apps/Host Manager/HostManagerEditor.tsx b/src/ui/Desktop/Apps/Host Manager/HostManagerEditor.tsx index 08a41724..565078eb 100644 --- a/src/ui/Desktop/Apps/Host Manager/HostManagerEditor.tsx +++ b/src/ui/Desktop/Apps/Host Manager/HostManagerEditor.tsx @@ -118,7 +118,8 @@ export function HostManagerEditor({ setFolders(uniqueFolders); setSshConfigurations(uniqueConfigurations); - } catch (error) { + } catch { + // Failed to load hosts data } finally { setLoading(false); } @@ -152,7 +153,8 @@ export function HostManagerEditor({ setFolders(uniqueFolders); setSshConfigurations(uniqueConfigurations); - } catch (error) { + } catch { + // Failed to reload hosts after credential change } finally { setLoading(false); } diff --git a/src/ui/Desktop/Homepage/HomepageAuth.tsx b/src/ui/Desktop/Homepage/HomepageAuth.tsx index 70fd6ec4..21c533aa 100644 --- a/src/ui/Desktop/Homepage/HomepageAuth.tsx +++ b/src/ui/Desktop/Homepage/HomepageAuth.tsx @@ -105,7 +105,9 @@ export function HomepageAuth({ const clearJWTOnLoad = async () => { try { await logoutUser(); - } catch (error) {} + } catch { + // Ignore logout errors on initial load + } }; clearJWTOnLoad(); diff --git a/src/ui/hooks/useDragToSystemDesktop.ts b/src/ui/hooks/useDragToSystemDesktop.ts index 3258876f..3f0f1368 100644 --- a/src/ui/hooks/useDragToSystemDesktop.ts +++ b/src/ui/hooks/useDragToSystemDesktop.ts @@ -59,7 +59,9 @@ export function useDragToSystemDesktop({ }; }); } - } catch (error) {} + } catch { + // IndexedDB not available or failed to retrieve directory + } return null; }; @@ -75,7 +77,9 @@ export function useDragToSystemDesktop({ store.put({ handle: dirHandle }, "lastSaveDir"); }; } - } catch (error) {} + } catch { + // Failed to save directory handle + } }; const isFileSystemAPISupported = () => { -- 2.49.1 From dea1ca90b1a0b387dd16530013b0670be6b4a821 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 21:05:36 +0800 Subject: [PATCH 15/19] fix: clean up empty blocks in file manager and credential editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了 5 个空块: - FileManagerGrid.tsx: 移除 1 个空 else 块和 1 个空 if 块 - CredentialEditor.tsx: 修复 1 个空 catch 块,移除 2 个空 if/else 块 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/ui/Desktop/Apps/Credentials/CredentialEditor.tsx | 7 ++----- src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx | 3 --- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ui/Desktop/Apps/Credentials/CredentialEditor.tsx b/src/ui/Desktop/Apps/Credentials/CredentialEditor.tsx index 9303c0b8..84119637 100644 --- a/src/ui/Desktop/Apps/Credentials/CredentialEditor.tsx +++ b/src/ui/Desktop/Apps/Credentials/CredentialEditor.tsx @@ -79,7 +79,8 @@ export function CredentialEditor({ ].sort() as string[]; setFolders(uniqueFolders); - } catch (error) { + } catch { + // Failed to load credentials } finally { setLoading(false); } @@ -636,10 +637,6 @@ export function CredentialEditor({ form.setValue("key", null); form.setValue("keyPassword", ""); form.setValue("keyType", "auto"); - - if (newAuthType === "password") { - } else if (newAuthType === "key") { - } }} className="flex-1 flex flex-col h-full min-h-0" > diff --git a/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx b/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx index 039f75eb..0a636411 100644 --- a/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx +++ b/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx @@ -327,7 +327,6 @@ export function FileManagerGrid({ dragState.files[0].type === "file" ) { onFileDiff?.(dragState.files[0], targetFile); - } else { } setDragState({ type: "none", files: [], counter: 0 }); @@ -458,8 +457,6 @@ export function FileManagerGrid({ type: "external", counter: prev.counter + 1, })); - if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { - } } }, [dragState.type], -- 2.49.1 From 57a99ae31b342c27033a6bcdddc3afaa6a47b7ab Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 21:18:10 +0800 Subject: [PATCH 16/19] fix: clean up all empty catch blocks in Terminal components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了 Terminal 组件中的所有 8 个空 catch 块: - Desktop/Apps/Terminal/Terminal.tsx: 修复 5 个空 catch 块 - Mobile/Apps/Terminal/Terminal.tsx: 修复 3 个空 catch 块 所有空块都添加了描述性注释。这是空块修复的最后一批。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/ui/Desktop/Apps/Terminal/Terminal.tsx | 20 +++++++++++++++----- src/ui/Mobile/Apps/Terminal/Terminal.tsx | 12 +++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/ui/Desktop/Apps/Terminal/Terminal.tsx b/src/ui/Desktop/Apps/Terminal/Terminal.tsx index 7367ff6f..1a53502e 100644 --- a/src/ui/Desktop/Apps/Terminal/Terminal.tsx +++ b/src/ui/Desktop/Apps/Terminal/Terminal.tsx @@ -99,7 +99,9 @@ export const Terminal = forwardRef(function SSHTerminal( if (terminal && typeof (terminal as any).refresh === "function") { (terminal as any).refresh(0, terminal.rows - 1); } - } catch (_) {} + } catch { + // Ignore terminal refresh errors + } } function scheduleNotify(cols: number, rows: number) { @@ -161,7 +163,9 @@ export const Terminal = forwardRef(function SSHTerminal( scheduleNotify(cols, rows); hardRefresh(); } - } catch (_) {} + } catch { + // Ignore resize notification errors + } }, refresh: () => hardRefresh(), }), @@ -480,7 +484,9 @@ export const Terminal = forwardRef(function SSHTerminal( await navigator.clipboard.writeText(text); return; } - } catch (_) {} + } catch { + // Clipboard API not available, fallback to textarea method + } const textarea = document.createElement("textarea"); textarea.value = text; textarea.style.position = "fixed"; @@ -500,7 +506,9 @@ export const Terminal = forwardRef(function SSHTerminal( if (navigator.clipboard && navigator.clipboard.readText) { return await navigator.clipboard.readText(); } - } catch (_) {} + } catch { + // Clipboard read not available or not permitted + } return ""; } @@ -560,7 +568,9 @@ export const Terminal = forwardRef(function SSHTerminal( const pasteText = await readTextFromClipboard(); if (pasteText) terminal.paste(pasteText); } - } catch (_) {} + } catch { + // Ignore clipboard operation errors + } }; element?.addEventListener("contextmenu", handleContextMenu); diff --git a/src/ui/Mobile/Apps/Terminal/Terminal.tsx b/src/ui/Mobile/Apps/Terminal/Terminal.tsx index ac164b98..4a442686 100644 --- a/src/ui/Mobile/Apps/Terminal/Terminal.tsx +++ b/src/ui/Mobile/Apps/Terminal/Terminal.tsx @@ -73,7 +73,9 @@ export const Terminal = forwardRef(function SSHTerminal( if (terminal && typeof (terminal as any).refresh === "function") { (terminal as any).refresh(0, terminal.rows - 1); } - } catch (_) {} + } catch { + // Ignore terminal refresh errors + } } function scheduleNotify(cols: number, rows: number) { @@ -122,7 +124,9 @@ export const Terminal = forwardRef(function SSHTerminal( scheduleNotify(cols, rows); hardRefresh(); } - } catch (_) {} + } catch { + // Ignore resize notification errors + } }, refresh: () => hardRefresh(), }), @@ -175,7 +179,9 @@ export const Terminal = forwardRef(function SSHTerminal( `\r\n[${msg.message || t("terminal.disconnected")}]`, ); } - } catch (error) {} + } catch { + // Ignore message parsing errors + } }); ws.addEventListener("close", (event) => { -- 2.49.1 From f3fde836bc75e040453537ef7e3e20776f70cd1a Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 21:37:34 +0800 Subject: [PATCH 17/19] refactor: remove useless try/catch wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除了 3 个无用的 try/catch 包装器: - users.ts: 移除只重新抛出错误的外层 try/catch - FileManager.tsx: 移除只重新抛出错误的内层 try/catch - DiffViewer.tsx: 移除只重新抛出错误的内层 try/catch 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/backend/database/routes/users.ts | 162 +++++++++--------- .../Desktop/Apps/File Manager/FileManager.tsx | 34 ++-- .../File Manager/components/DiffViewer.tsx | 28 ++- 3 files changed, 106 insertions(+), 118 deletions(-) diff --git a/src/backend/database/routes/users.ts b/src/backend/database/routes/users.ts index 7ea4f49c..f7a7c066 100644 --- a/src/backend/database/routes/users.ts +++ b/src/backend/database/routes/users.ts @@ -28,93 +28,89 @@ async function verifyOIDCToken( issuerUrl: string, clientId: string, ): Promise { + const normalizedIssuerUrl = issuerUrl.endsWith("/") + ? issuerUrl.slice(0, -1) + : issuerUrl; + const possibleIssuers = [ + issuerUrl, + normalizedIssuerUrl, + issuerUrl.replace(/\/application\/o\/[^\/]+$/, ""), + normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, ""), + ]; + + const jwksUrls = [ + `${normalizedIssuerUrl}/.well-known/jwks.json`, + `${normalizedIssuerUrl}/jwks/`, + `${normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, "")}/.well-known/jwks.json`, + ]; + try { - const normalizedIssuerUrl = issuerUrl.endsWith("/") - ? issuerUrl.slice(0, -1) - : issuerUrl; - const possibleIssuers = [ - issuerUrl, - normalizedIssuerUrl, - issuerUrl.replace(/\/application\/o\/[^\/]+$/, ""), - normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, ""), - ]; - - const jwksUrls = [ - `${normalizedIssuerUrl}/.well-known/jwks.json`, - `${normalizedIssuerUrl}/jwks/`, - `${normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, "")}/.well-known/jwks.json`, - ]; - - try { - const discoveryUrl = `${normalizedIssuerUrl}/.well-known/openid-configuration`; - const discoveryResponse = await fetch(discoveryUrl); - if (discoveryResponse.ok) { - const discovery = (await discoveryResponse.json()) as any; - if (discovery.jwks_uri) { - jwksUrls.unshift(discovery.jwks_uri); - } - } - } catch (discoveryError) { - authLogger.error(`OIDC discovery failed: ${discoveryError}`); - } - - let jwks: any = null; - - for (const url of jwksUrls) { - try { - const response = await fetch(url); - if (response.ok) { - const jwksData = (await response.json()) as any; - if (jwksData && jwksData.keys && Array.isArray(jwksData.keys)) { - jwks = jwksData; - break; - } else { - authLogger.error( - `Invalid JWKS structure from ${url}: ${JSON.stringify(jwksData)}`, - ); - } - } else { - // Non-200 response - } - } catch { - continue; + const discoveryUrl = `${normalizedIssuerUrl}/.well-known/openid-configuration`; + const discoveryResponse = await fetch(discoveryUrl); + if (discoveryResponse.ok) { + const discovery = (await discoveryResponse.json()) as any; + if (discovery.jwks_uri) { + jwksUrls.unshift(discovery.jwks_uri); } } - - if (!jwks) { - throw new Error("Failed to fetch JWKS from any URL"); - } - - if (!jwks.keys || !Array.isArray(jwks.keys)) { - throw new Error( - `Invalid JWKS response structure. Expected 'keys' array, got: ${JSON.stringify(jwks)}`, - ); - } - - const header = JSON.parse( - Buffer.from(idToken.split(".")[0], "base64").toString(), - ); - const keyId = header.kid; - - const publicKey = jwks.keys.find((key: any) => key.kid === keyId); - if (!publicKey) { - throw new Error( - `No matching public key found for key ID: ${keyId}. Available keys: ${jwks.keys.map((k: any) => k.kid).join(", ")}`, - ); - } - - const { importJWK, jwtVerify } = await import("jose"); - const key = await importJWK(publicKey); - - const { payload } = await jwtVerify(idToken, key, { - issuer: possibleIssuers, - audience: clientId, - }); - - return payload; - } catch (error) { - throw error; + } catch (discoveryError) { + authLogger.error(`OIDC discovery failed: ${discoveryError}`); } + + let jwks: any = null; + + for (const url of jwksUrls) { + try { + const response = await fetch(url); + if (response.ok) { + const jwksData = (await response.json()) as any; + if (jwksData && jwksData.keys && Array.isArray(jwksData.keys)) { + jwks = jwksData; + break; + } else { + authLogger.error( + `Invalid JWKS structure from ${url}: ${JSON.stringify(jwksData)}`, + ); + } + } else { + // Non-200 response + } + } catch { + continue; + } + } + + if (!jwks) { + throw new Error("Failed to fetch JWKS from any URL"); + } + + if (!jwks.keys || !Array.isArray(jwks.keys)) { + throw new Error( + `Invalid JWKS response structure. Expected 'keys' array, got: ${JSON.stringify(jwks)}`, + ); + } + + const header = JSON.parse( + Buffer.from(idToken.split(".")[0], "base64").toString(), + ); + const keyId = header.kid; + + const publicKey = jwks.keys.find((key: any) => key.kid === keyId); + if (!publicKey) { + throw new Error( + `No matching public key found for key ID: ${keyId}. Available keys: ${jwks.keys.map((k: any) => k.kid).join(", ")}`, + ); + } + + const { importJWK, jwtVerify } = await import("jose"); + const key = await importJWK(publicKey); + + const { payload } = await jwtVerify(idToken, key, { + issuer: possibleIssuers, + audience: clientId, + }); + + return payload; } const router = express.Router(); diff --git a/src/ui/Desktop/Apps/File Manager/FileManager.tsx b/src/ui/Desktop/Apps/File Manager/FileManager.tsx index fdf26575..884e3ce8 100644 --- a/src/ui/Desktop/Apps/File Manager/FileManager.tsx +++ b/src/ui/Desktop/Apps/File Manager/FileManager.tsx @@ -710,27 +710,23 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) { try { const currentSessionId = sshSessionId; - try { - const status = await getSSHStatus(currentSessionId); - if (!status.connected) { - const result = await connectSSH(currentSessionId, { - hostId: currentHost.id, - host: currentHost.ip, - port: currentHost.port, - username: currentHost.username, - authType: currentHost.authType, - password: currentHost.password, - key: currentHost.key, - keyPassword: currentHost.keyPassword, - credentialId: currentHost.credentialId, - }); + const status = await getSSHStatus(currentSessionId); + if (!status.connected) { + const result = await connectSSH(currentSessionId, { + hostId: currentHost.id, + host: currentHost.ip, + port: currentHost.port, + username: currentHost.username, + authType: currentHost.authType, + password: currentHost.password, + key: currentHost.key, + keyPassword: currentHost.keyPassword, + credentialId: currentHost.credentialId, + }); - if (!result.success) { - throw new Error(t("fileManager.failedToReconnectSSH")); - } + if (!result.success) { + throw new Error(t("fileManager.failedToReconnectSSH")); } - } catch (sessionErr) { - throw sessionErr; } const symlinkInfo = await identifySSHSymlink(currentSessionId, file.path); diff --git a/src/ui/Desktop/Apps/File Manager/components/DiffViewer.tsx b/src/ui/Desktop/Apps/File Manager/components/DiffViewer.tsx index e9312924..be0bc85a 100644 --- a/src/ui/Desktop/Apps/File Manager/components/DiffViewer.tsx +++ b/src/ui/Desktop/Apps/File Manager/components/DiffViewer.tsx @@ -62,22 +62,18 @@ export function DiffViewer({ }); } } catch (error) { - try { - await connectSSH(sshSessionId, { - hostId: sshHost.id, - ip: sshHost.ip, - port: sshHost.port, - username: sshHost.username, - password: sshHost.password, - sshKey: sshHost.key, - keyPassword: sshHost.keyPassword, - authType: sshHost.authType, - credentialId: sshHost.credentialId, - userId: sshHost.userId, - }); - } catch (reconnectError) { - throw reconnectError; - } + await connectSSH(sshSessionId, { + hostId: sshHost.id, + ip: sshHost.ip, + port: sshHost.port, + username: sshHost.username, + password: sshHost.password, + sshKey: sshHost.key, + keyPassword: sshHost.keyPassword, + authType: sshHost.authType, + credentialId: sshHost.credentialId, + userId: sshHost.userId, + }); } }; -- 2.49.1 From 80b22390c9ec46381506170f2521549b548f7015 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 21:39:23 +0800 Subject: [PATCH 18/19] refactor: remove unused imports and mark unused parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除了未使用的导入和标记未使用的参数: - auto-ssl-setup.ts: 移除未使用的 crypto 导入 - user-crypto.ts: 移除未使用的 users 导入 - user-data-import.ts: 移除未使用的 nanoid 导入 - simple-db-ops.ts: 标记未使用的 userId 和 tableName 参数 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/backend/utils/auto-ssl-setup.ts | 1 - src/backend/utils/simple-db-ops.ts | 4 ++-- src/backend/utils/user-crypto.ts | 2 +- src/backend/utils/user-data-import.ts | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/auto-ssl-setup.ts b/src/backend/utils/auto-ssl-setup.ts index 5d9a6fc8..a8d022d4 100644 --- a/src/backend/utils/auto-ssl-setup.ts +++ b/src/backend/utils/auto-ssl-setup.ts @@ -1,7 +1,6 @@ import { execSync } from "child_process"; import { promises as fs } from "fs"; import path from "path"; -import crypto from "crypto"; import { systemLogger } from "./logger.js"; export class AutoSSLSetup { diff --git a/src/backend/utils/simple-db-ops.ts b/src/backend/utils/simple-db-ops.ts index c324e0a2..933a3a5e 100644 --- a/src/backend/utils/simple-db-ops.ts +++ b/src/backend/utils/simple-db-ops.ts @@ -127,7 +127,7 @@ class SimpleDBOps { table: SQLiteTable, tableName: TableName, where: any, - userId: string, + _userId: string, ): Promise { const result = await getDb().delete(table).where(where).returning(); @@ -146,7 +146,7 @@ class SimpleDBOps { static async selectEncrypted( query: any, - tableName: TableName, + _tableName: TableName, ): Promise { const results = await query; diff --git a/src/backend/utils/user-crypto.ts b/src/backend/utils/user-crypto.ts index 4164ece4..7caed3a3 100644 --- a/src/backend/utils/user-crypto.ts +++ b/src/backend/utils/user-crypto.ts @@ -1,6 +1,6 @@ import crypto from "crypto"; import { getDb } from "../database/db/index.js"; -import { settings, users } from "../database/db/schema.js"; +import { settings } from "../database/db/schema.js"; import { eq } from "drizzle-orm"; import { databaseLogger } from "./logger.js"; diff --git a/src/backend/utils/user-data-import.ts b/src/backend/utils/user-data-import.ts index 448d3c00..60f41dac 100644 --- a/src/backend/utils/user-data-import.ts +++ b/src/backend/utils/user-data-import.ts @@ -12,7 +12,6 @@ import { eq, and } from "drizzle-orm"; import { DataCrypto } from "./data-crypto.js"; import { UserDataExport, type UserExportData } from "./user-data-export.js"; import { databaseLogger } from "./logger.js"; -import { nanoid } from "nanoid"; interface ImportOptions { replaceExisting?: boolean; -- 2.49.1 From 3972c20a5a60b311717de9ca2071d3cc14ddae6a Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Sun, 5 Oct 2025 21:44:04 +0800 Subject: [PATCH 19/19] fix: remove unnecessary escape characters in regex patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除了正则表达式中不必要的转义字符: - users.ts: 修复 5 个 \/ 不必要的转义 - TabContext.tsx: 修复 1 个 \/ 不必要的转义 在字符串形式的正则表达式中,/ 不需要转义。 --- src/backend/database/routes/users.ts | 13 +++++-------- src/ui/Desktop/Navigation/Tabs/TabContext.tsx | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/backend/database/routes/users.ts b/src/backend/database/routes/users.ts index f7a7c066..c70676cc 100644 --- a/src/backend/database/routes/users.ts +++ b/src/backend/database/routes/users.ts @@ -34,14 +34,14 @@ async function verifyOIDCToken( const possibleIssuers = [ issuerUrl, normalizedIssuerUrl, - issuerUrl.replace(/\/application\/o\/[^\/]+$/, ""), - normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, ""), + issuerUrl.replace(/\/application\/o\/[^/]+$/, ""), + normalizedIssuerUrl.replace(/\/application\/o\/[^/]+$/, ""), ]; const jwksUrls = [ `${normalizedIssuerUrl}/.well-known/jwks.json`, `${normalizedIssuerUrl}/jwks/`, - `${normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, "")}/.well-known/jwks.json`, + `${normalizedIssuerUrl.replace(/\/application\/o\/[^/]+$/, "")}/.well-known/jwks.json`, ]; try { @@ -491,7 +491,7 @@ router.get("/oidc/authorize", async (req, res) => { let origin = req.get("Origin") || - req.get("Referer")?.replace(/\/[^\/]*$/, "") || + req.get("Referer")?.replace(/\/[^/]*$/, "") || "http://localhost:5173"; if (origin.includes("localhost")) { @@ -598,10 +598,7 @@ router.get("/oidc/callback", async (req, res) => { const normalizedIssuerUrl = config.issuer_url.endsWith("/") ? config.issuer_url.slice(0, -1) : config.issuer_url; - const baseUrl = normalizedIssuerUrl.replace( - /\/application\/o\/[^\/]+$/, - "", - ); + const baseUrl = normalizedIssuerUrl.replace(/\/application\/o\/[^/]+$/, ""); try { const discoveryUrl = `${normalizedIssuerUrl}/.well-known/openid-configuration`; diff --git a/src/ui/Desktop/Navigation/Tabs/TabContext.tsx b/src/ui/Desktop/Navigation/Tabs/TabContext.tsx index 42b9b885..0f5d6d32 100644 --- a/src/ui/Desktop/Navigation/Tabs/TabContext.tsx +++ b/src/ui/Desktop/Navigation/Tabs/TabContext.tsx @@ -69,7 +69,7 @@ export function TabProvider({ children }: TabProviderProps) { } const m = t.title.match( new RegExp( - `^${root.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&")} \\((\\d+)\\)$`, + `^${root.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")} \\((\\d+)\\)$`, ), ); if (m) { -- 2.49.1