diff --git a/CHANGELOG.md b/CHANGELOG.md index 120bd06..b1d32e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased +## [2.0.131] - 2026-05-14 +### Changed +- Fixes to the rate limiting. + +## [2.0.130] - 2026-04-28 +### Changed +- Fixes to unit tests +- Upgraded .NET and Angular dependencies +- Added better qBittorrent capabilities for Cleanuparr +- Performance fixes + ## [2.0.129] - 2026-04-06 ### Added - Optimized mobile views, thanks to @sylvaindd! diff --git a/client/.ncurc.js b/client/.ncurc.js index 39bc4ef..a896cca 100644 --- a/client/.ncurc.js +++ b/client/.ncurc.js @@ -1,4 +1,4 @@ -const minorOnly = ["eslint"]; +const minorOnly = ["eslint", "typescript"]; const patchOnly = []; module.exports = { diff --git a/client/package-lock.json b/client/package-lock.json index 398a963..5a13185 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,42 +8,42 @@ "name": "client", "version": "0.0.0", "dependencies": { - "@angular/animations": "^21.2.4", - "@angular/cdk": "^21.2.2", - "@angular/common": "^21.2.4", - "@angular/compiler": "^21.2.4", - "@angular/core": "^21.2.4", - "@angular/forms": "^21.2.4", - "@angular/platform-browser": "^21.2.4", - "@angular/platform-browser-dynamic": "^21.2.4", - "@angular/router": "^21.2.4", + "@angular/animations": "^21.2.10", + "@angular/cdk": "^21.2.8", + "@angular/common": "^21.2.10", + "@angular/compiler": "^21.2.10", + "@angular/core": "^21.2.10", + "@angular/forms": "^21.2.10", + "@angular/platform-browser": "^21.2.10", + "@angular/platform-browser-dynamic": "^21.2.10", + "@angular/router": "^21.2.10", "@fortawesome/fontawesome-free": "^7.2.0", "@microsoft/signalr": "^10.0.0", "bulma": "^1.0.4", "curray": "^1.0.12", "file-saver-es": "^2.0.5", - "filesize": "^11.0.13", + "filesize": "^11.0.17", "rxjs": "^7.8.2", "tslib": "^2.8.1", "zone.js": "^0.16.1" }, "devDependencies": { - "@angular-eslint/builder": "21.3.0", - "@angular-eslint/eslint-plugin": "21.3.0", - "@angular-eslint/eslint-plugin-template": "21.3.0", - "@angular-eslint/schematics": "21.3.0", - "@angular-eslint/template-parser": "21.3.0", - "@angular/build": "^21.2.2", - "@angular/cli": "^21.2.2", - "@angular/compiler-cli": "^21.2.4", - "@angular/language-service": "^21.2.4", + "@angular-eslint/builder": "21.3.1", + "@angular-eslint/eslint-plugin": "21.3.1", + "@angular-eslint/eslint-plugin-template": "21.3.1", + "@angular-eslint/schematics": "21.3.1", + "@angular-eslint/template-parser": "21.3.1", + "@angular/build": "^21.2.8", + "@angular/cli": "^21.2.8", + "@angular/compiler-cli": "^21.2.10", + "@angular/language-service": "^21.2.10", "@types/file-saver": "^2.0.7", "@types/file-saver-es": "^2.0.3", - "@types/node": "^25.5.0", - "@typescript-eslint/eslint-plugin": "^8.57.0", - "@typescript-eslint/parser": "^8.57.0", + "@types/node": "^25.6.0", + "@typescript-eslint/eslint-plugin": "^8.59.1", + "@typescript-eslint/parser": "^8.59.1", "eslint": "^9.39.4", - "prettier": "^3.8.1", + "prettier": "^3.8.3", "typescript": "5.9.3" } }, @@ -271,13 +271,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2102.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.2.tgz", - "integrity": "sha512-CDvFtXwyBtMRkTQnm+LfBNLL0yLV8ZGskrM1T6VkcGwXGFDott1FxUdj96ViodYsYL5fbJr0MNA6TlLcanV3kQ==", + "version": "0.2102.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.8.tgz", + "integrity": "sha512-b7su7AHIO5F2I6InEu/Bx/oXvGjdCP7kos2tGX73he/lPrTuizooils62OgAzgJ2UeKscyRNUjBPieFCy6XvHQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.2", + "@angular-devkit/core": "21.2.8", "rxjs": "7.8.2" }, "bin": { @@ -290,16 +290,16 @@ } }, "node_modules/@angular-devkit/core": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.2.tgz", - "integrity": "sha512-xUeKGe4BDQpkz0E6fnAPIJXE0y0nqtap0KhJIBhvN7xi3NenIzTmoi6T9Yv5OOBUdLZbOm4SOel8MhdXiIBpAQ==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.8.tgz", + "integrity": "sha512-DyxCILaaic/hfcfiBjAC/SdKE1ybSQIrU62/K5Msn3gZtThZj/T7cG0VHfbmpEFcgYkrQ9caUt6MCg8OoOVDzw==", "dev": true, "license": "MIT", "dependencies": { "ajv": "8.18.0", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", - "picomatch": "4.0.3", + "picomatch": "4.0.4", "rxjs": "7.8.2", "source-map": "0.7.6" }, @@ -335,13 +335,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.2.tgz", - "integrity": "sha512-CCeyQxGUq+oyGnHd7PfcYIVbj9pRnqjQq0rAojoAqs1BJdtInx9weLBCLy+AjM3NHePeZrnwm+wEVr8apED8kg==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.8.tgz", + "integrity": "sha512-UTEMM1JXzzxufLsTGDsWth2E7+8e9PaFT7nbjUvJ2qevltACkiqAbHEpiD2ISzrSRIO3OirJ+cZtnzXO0FyoBQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.2", + "@angular-devkit/core": "21.2.8", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", "ora": "9.3.0", @@ -354,9 +354,9 @@ } }, "node_modules/@angular-eslint/builder": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.3.0.tgz", - "integrity": "sha512-26QUUouei52biUFAlJSrWNAU9tuF2miKwd8uHdxWwCF31xz+OxC5+NfudWvt1AFaYow7gWueX1QX3rNNtSPDrg==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.3.1.tgz", + "integrity": "sha512-1f1Lyp5e7OH6txiV224HaY3G1uRCj91OSKq7hT2Vw9NRw6zWFc1anBpDeLVjpL9ptUxzUGIQR5jEV54hOPayoQ==", "dev": true, "license": "MIT", "dependencies": { @@ -370,21 +370,21 @@ } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-21.3.0.tgz", - "integrity": "sha512-l521I24J9gJxyMbRkrM24Tc7W8J8BP+TDAmVs2nT8+lXbS3kg8QpWBRtd+hNUgq6o+vt+lKBkytnEfu8OiqeRg==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-21.3.1.tgz", + "integrity": "sha512-jjbnJPUXQeQBJ8RM+ahlbt4GH2emVN8JvG3AhFbPci1FrqXi9cOOfkbwLmvpoyTli4LF8gy7g4ctFqnlRgqryw==", "dev": true, "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-21.3.0.tgz", - "integrity": "sha512-Whf/AUUBekOlfSJRS78m76YGrBQAZ3waXE7oOdlW5xEQvn8jBDN9EGuNnjg/syZzvzjK4ZpYC4g1XYXrc+fQIg==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-21.3.1.tgz", + "integrity": "sha512-08NNTxwawRLTWPLl8dg1BnXMwimx93y4wMEwx2aWQpJbIt4pmNvwJzd+NgoD/Ag2VdLS/gOMadhJH5fgaYKsPQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.3.0", - "@angular-eslint/utils": "21.3.0", + "@angular-eslint/bundled-angular-compiler": "21.3.1", + "@angular-eslint/utils": "21.3.1", "ts-api-utils": "^2.1.0" }, "peerDependencies": { @@ -394,19 +394,19 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-21.3.0.tgz", - "integrity": "sha512-lVixd/KypPWgA/5/pUOhJV9MTcaHjYZEqyOi+IiLk+h+maGxn6/s6Ot+20n+XGS85zAgOY+qUw6EEQ11hoojIQ==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-21.3.1.tgz", + "integrity": "sha512-ndPWJodkcEOu2PVUxlUwyz4D2u3r9KO7veWmStVNOLeNrICJA+nQvrz2BWCu0l48rO0K5ezsy0JFcQDVwE/5mw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.3.0", - "@angular-eslint/utils": "21.3.0", + "@angular-eslint/bundled-angular-compiler": "21.3.1", + "@angular-eslint/utils": "21.3.1", "aria-query": "5.3.2", "axobject-query": "4.1.0" }, "peerDependencies": { - "@angular-eslint/template-parser": "21.3.0", + "@angular-eslint/template-parser": "21.3.1", "@typescript-eslint/types": "^7.11.0 || ^8.0.0", "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", @@ -414,16 +414,16 @@ } }, "node_modules/@angular-eslint/schematics": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-21.3.0.tgz", - "integrity": "sha512-8deU/zVY9f8k8kAQQ9PL130ox2VlrZw3fMxgsPNAY5tjQ0xk0J2YVSszYHhcqdMGG1J01IsxIjvQaJ4pFfEmMw==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-21.3.1.tgz", + "integrity": "sha512-1U2u4ZsZvwT30aXRLsIJf6tULIiioo9BtASNsldpYecU3/m/1+F61lCYG79qt7YWbif9KABPYZlFTJUFGN8HWA==", "dev": true, "license": "MIT", "dependencies": { "@angular-devkit/core": ">= 21.0.0 < 22.0.0", "@angular-devkit/schematics": ">= 21.0.0 < 22.0.0", - "@angular-eslint/eslint-plugin": "21.3.0", - "@angular-eslint/eslint-plugin-template": "21.3.0", + "@angular-eslint/eslint-plugin": "21.3.1", + "@angular-eslint/eslint-plugin-template": "21.3.1", "ignore": "7.0.5", "semver": "7.7.4", "strip-json-comments": "3.1.1" @@ -433,14 +433,14 @@ } }, "node_modules/@angular-eslint/template-parser": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-21.3.0.tgz", - "integrity": "sha512-ysyou1zAY6M6rSZNdIcYKGd4nk6TCapamyFNB3ivmTlVZ0O35TS9o/rJ0aUttuHgDp+Ysgs3ql+LA746PXgCyQ==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-21.3.1.tgz", + "integrity": "sha512-moERVCTekQKOvR8RMuEOtWSO3VS1qrzA3keI1dPto/JVB8Nqp9w3R5ZpEoXHzh4zgEryosxmPgdi6UczJe2ouQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.3.0", - "eslint-scope": "^9.1.1" + "@angular-eslint/bundled-angular-compiler": "21.3.1", + "eslint-scope": "9.1.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", @@ -467,13 +467,13 @@ } }, "node_modules/@angular-eslint/utils": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-21.3.0.tgz", - "integrity": "sha512-oNigH6w3l+owTMboj/uFG0tHOy43uH8BpQRtBOQL1/s2+5in/BJ2Fjobv3SyizxTgeJ1FhRefbkT8GmVjK7jAA==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-21.3.1.tgz", + "integrity": "sha512-Q3SGA1/36phZhmsp1mYrKzp/jcmqofRr861MYn46FaWIKSYXBYRzl+H3FIJKBu5CE36Bggu6hbNpwGPuUp+MCg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.3.0" + "@angular-eslint/bundled-angular-compiler": "21.3.1" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", @@ -482,9 +482,9 @@ } }, "node_modules/@angular/animations": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.4.tgz", - "integrity": "sha512-hO1P7ks9n7lW3D31bzHohSuoAaj05xJUlK8rZgX8IkH5DLx4qhvfNh0t4bbLuBJLP2r1TaLsQ8KFcemCkFRO2w==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.10.tgz", + "integrity": "sha512-sIzAcxwtRCJ/fu0tK4mo1ooiEaDxJ+Nl6s9nK1D1NP1em12VX03Jx8CMixp/kVtgh4mZnm1x6psBB0FUz3U3Ug==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -493,18 +493,18 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.4" + "@angular/core": "21.2.10" } }, "node_modules/@angular/build": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.2.tgz", - "integrity": "sha512-Vq2eIneNxzhHm1MwEmRqEJDwHU9ODfSRDaMWwtysGMhpoMQmLdfTqkQDmkC2qVUr8mV8Z1i5I+oe5ZJaMr/PlQ==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.8.tgz", + "integrity": "sha512-t0PHT7ONDMLwcjC9GaClNF+gsUKN78ofBikw4huiu6np5Rwmxp8KKCrdoRx20lOiibSolXgjZ2Ny0xxjNdNdQA==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2102.2", + "@angular-devkit/architect": "0.2102.8", "@babel/core": "7.29.0", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -520,15 +520,15 @@ "magic-string": "0.30.21", "mrmime": "2.0.1", "parse5-html-rewriting-stream": "8.0.0", - "picomatch": "4.0.3", + "picomatch": "4.0.4", "piscina": "5.1.4", "rolldown": "1.0.0-rc.4", "sass": "1.97.3", "semver": "7.7.4", "source-map-support": "0.5.21", "tinyglobby": "0.2.15", - "undici": "7.22.0", - "vite": "7.3.1", + "undici": "7.24.4", + "vite": "7.3.2", "watchpack": "2.5.1" }, "engines": { @@ -547,7 +547,7 @@ "@angular/platform-browser": "^21.0.0", "@angular/platform-server": "^21.0.0", "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.2.2", + "@angular/ssr": "^21.2.8", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^21.0.0", @@ -597,9 +597,9 @@ } }, "node_modules/@angular/cdk": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.2.tgz", - "integrity": "sha512-9AsZkwqy07No7+0qPydcJfXB6SpA9qLDBanoesNj5KsiZJ62PJH3oIjVyNeQEEe1HQWmSwBnhwN12OPLNMUlnw==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.8.tgz", + "integrity": "sha512-WdvMLpuFcRgDWLDyin3sw5a65PQYdI0Y+4BxiMxOkesoZ2RZTBAlLKIfQ9Nz5CY3LamUTO3Qel2T8ZhJ+Cqfuw==", "license": "MIT", "dependencies": { "parse5": "^8.0.0", @@ -613,19 +613,19 @@ } }, "node_modules/@angular/cli": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.2.tgz", - "integrity": "sha512-eZo8/qX+ZIpIWc0CN+cCX13Lbgi/031wAp8DRVhDDO6SMVtcr/ObOQ2S16+pQdOMXxiG3vby6IhzJuz9WACzMQ==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.8.tgz", + "integrity": "sha512-Y+/US12o+7X2774oeKPsEfHeeYM2SxwnyoXfcaLR8vrMn0zxUrhHebmlz9h83th4EJEuex1Qk0JtF7j5vcwrqQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2102.2", - "@angular-devkit/core": "21.2.2", - "@angular-devkit/schematics": "21.2.2", + "@angular-devkit/architect": "0.2102.8", + "@angular-devkit/core": "21.2.8", + "@angular-devkit/schematics": "21.2.8", "@inquirer/prompts": "7.10.1", "@listr2/prompt-adapter-inquirer": "3.0.5", "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.2", + "@schematics/angular": "21.2.8", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.48.1", "ini": "6.0.0", @@ -648,9 +648,9 @@ } }, "node_modules/@angular/common": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.4.tgz", - "integrity": "sha512-NrP6qOuUpo3fqq14UJ1b2bIRtWsfvxh1qLqOyFV4gfBrHhXd0XffU1LUlUw1qp4w1uBSgPJ0/N5bSPUWrAguVg==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.10.tgz", + "integrity": "sha512-WLyi/CRLtgALg2mmaqIuKuPnE4i+8PGt/uuz26pVqx+ASh28/TWr5KSCAMomgxEc8kt4OE7lopoQsTihrQCfEw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -659,14 +659,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.4", + "@angular/core": "21.2.10", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.4.tgz", - "integrity": "sha512-9+ulVK3idIo/Tu4X2ic7/V0+Uj7pqrOAbOuIirYe6Ymm3AjexuFRiGBbfcH0VJhQ5cf8TvIJ1fuh+MI4JiRIxA==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.10.tgz", + "integrity": "sha512-IrgdFuzzD7NTK3WQaSfowjAPxPbnTqsgR92NsOs5ZaWu3RgLl21dHThNc0BK1KwVwppLUSWmD4qePbcLW71VzQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -676,9 +676,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.4.tgz", - "integrity": "sha512-vGjd7DZo/Ox50pQCm5EycmBu91JclimPtZoyNXu/2hSxz3oAkzwiHCwlHwk2g58eheSSp+lYtYRLmHAqSVZLjg==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.10.tgz", + "integrity": "sha512-FDcnj3ogRmnTca4m2GbKP2khFOCtoVvWDZyfw2ZCPAf+zsQlKTyscKvx4GpTFo+KHrYXpawUpDIWHORFpuqFEA==", "dev": true, "license": "MIT", "dependencies": { @@ -699,7 +699,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.4", + "@angular/compiler": "21.2.10", "typescript": ">=5.9 <6.1" }, "peerDependenciesMeta": { @@ -709,9 +709,9 @@ } }, "node_modules/@angular/core": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.4.tgz", - "integrity": "sha512-2+gd67ZuXHpGOqeb2o7XZPueEWEP81eJza2tSHkT5QMV8lnYllDEmaNnkPxnIjSLGP1O3PmiXxo4z8ibHkLZwg==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.10.tgz", + "integrity": "sha512-uxH+mbPiCE7rInWKYOPe9Ytas97+mFM6FhFORoN234yBK3b8he+iDuxX6dsbhEFCxhRmfS6hLxe7BdLY6U6kIA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -720,7 +720,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.4", + "@angular/compiler": "21.2.10", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -734,9 +734,9 @@ } }, "node_modules/@angular/forms": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.4.tgz", - "integrity": "sha512-1fOhctA9ADEBYjI3nPQUR5dHsK2+UWAjup37Ksldk/k0w8UpD5YsN7JVNvsDMZRFMucKYcGykPblU7pABtsqnQ==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.10.tgz", + "integrity": "sha512-XOo9qkuBqCLzSBXmyga9ke2tSulxWl+E7Y9Uwqgz8sJtQUlyP/0GYJfu60jiC3NAYobk9K/6h6MsU8zftQKdaA==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -746,16 +746,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.4", - "@angular/core": "21.2.4", - "@angular/platform-browser": "21.2.4", + "@angular/common": "21.2.10", + "@angular/core": "21.2.10", + "@angular/platform-browser": "21.2.10", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-21.2.4.tgz", - "integrity": "sha512-seWlXWhayTwuL62Cfz+Ky/Wv67oYLX+cXplYoIinDVJPgQaU9jXpakLfKq8RwdRXVmgTE0HQ5dyoTozuWgJ8Nw==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-21.2.10.tgz", + "integrity": "sha512-9f5XgigqdscuCmUZ2WAbuCKgOZfq6dennEOsvqjfposnaU90Y01cD9O75xKf4ONEANOfTwVcQCqGZeZ6Cnpdvw==", "dev": true, "license": "MIT", "engines": { @@ -763,9 +763,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.4.tgz", - "integrity": "sha512-1A9e/cQVu+3BkRCktLcO3RZGuw8NOTHw1frUUrpAz+iMyvIT4sDRFbL+U1g8qmOCZqRNC1Pi1HZfZ1kl6kvrcQ==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.10.tgz", + "integrity": "sha512-5WMoHGU8BOV3eO9h3vGMIUDPf+3SHis7+X2dHKMtKfFBUtiO8m/lq2x3PzkkKj1782i7KYt92EqPHuADd/eWOw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -774,9 +774,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "21.2.4", - "@angular/common": "21.2.4", - "@angular/core": "21.2.4" + "@angular/animations": "21.2.10", + "@angular/common": "21.2.10", + "@angular/core": "21.2.10" }, "peerDependenciesMeta": { "@angular/animations": { @@ -785,9 +785,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.4.tgz", - "integrity": "sha512-LRJLnGh4rdgD0+S5xuDd4YRm5bV8WP2e6F1Pe5rIr6N4V9ofgpB0/uOjYy9se99FJZjoyPnpxaKsp8+XA753Zg==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.10.tgz", + "integrity": "sha512-+/HMJSLnF87EODkHj0AKE3Q8AfYO/8jpTfr731QmplqBtCoLlA/1XR8aYow2hB9YKL9HZWDb2qGkRtCXhrtt+w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -796,16 +796,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.4", - "@angular/compiler": "21.2.4", - "@angular/core": "21.2.4", - "@angular/platform-browser": "21.2.4" + "@angular/common": "21.2.10", + "@angular/compiler": "21.2.10", + "@angular/core": "21.2.10", + "@angular/platform-browser": "21.2.10" } }, "node_modules/@angular/router": { - "version": "21.2.4", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.4.tgz", - "integrity": "sha512-OjWze4XT8i2MThcBXMv7ru1k6/5L6QYZbcXuseqimFCHm2avEJ+mXPovY066fMBZJhqbXdjB82OhHAWkIHjglQ==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.10.tgz", + "integrity": "sha512-4cHHwewIhFEAAaRgJ80371EOtNlydFHbjj/UENLZitjU0azal0mfFCBdkaEdVehd7+mH5xO7MRjy6eFTcTYR5Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -814,9 +814,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.4", - "@angular/core": "21.2.4", - "@angular/platform-browser": "21.2.4", + "@angular/common": "21.2.10", + "@angular/core": "21.2.10", + "@angular/platform-browser": "21.2.10", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1114,35 +1114,38 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", - "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", - "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -2938,20 +2941,22 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@npmcli/agent": { @@ -4069,14 +4074,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.2.tgz", - "integrity": "sha512-Ywa6HDtX7TRBQZTVMMnxX3Mk7yVnG8KtSFaXWrkx779+q8tqYdBwNwAqbNd4Zatr1GccKaz9xcptHJta5+DTxw==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.8.tgz", + "integrity": "sha512-Kx3PmuZIXhwQqAqoERAXqDCORHFbKTMd+eflXwZfpKkrbWJTVPqKpL4R9RVdEr2E6/VEXDFrdL1whIvGd1xmDg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.2", - "@angular-devkit/schematics": "21.2.2", + "@angular-devkit/core": "21.2.8", + "@angular-devkit/schematics": "21.2.8", "jsonc-parser": "3.3.1" }, "engines": { @@ -4242,30 +4247,30 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", - "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", - "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.1.tgz", + "integrity": "sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/type-utils": "8.57.0", - "@typescript-eslint/utils": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", + "@typescript-eslint/scope-manager": "8.59.1", + "@typescript-eslint/type-utils": "8.59.1", + "@typescript-eslint/utils": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4275,22 +4280,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.0", + "@typescript-eslint/parser": "^8.59.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", - "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.1.tgz", + "integrity": "sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", + "@typescript-eslint/scope-manager": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1", "debug": "^4.4.3" }, "engines": { @@ -4302,18 +4307,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", - "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.1.tgz", + "integrity": "sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.0", - "@typescript-eslint/types": "^8.57.0", + "@typescript-eslint/tsconfig-utils": "^8.59.1", + "@typescript-eslint/types": "^8.59.1", "debug": "^4.4.3" }, "engines": { @@ -4324,18 +4329,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", - "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.1.tgz", + "integrity": "sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0" + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4346,9 +4351,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", - "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.1.tgz", + "integrity": "sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA==", "dev": true, "license": "MIT", "engines": { @@ -4359,21 +4364,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", - "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.1.tgz", + "integrity": "sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/utils": "8.57.0", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1", + "@typescript-eslint/utils": "8.59.1", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4384,13 +4389,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", - "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz", + "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==", "dev": true, "license": "MIT", "engines": { @@ -4402,21 +4407,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", - "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.1.tgz", + "integrity": "sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.0", - "@typescript-eslint/tsconfig-utils": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", + "@typescript-eslint/project-service": "8.59.1", + "@typescript-eslint/tsconfig-utils": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4426,20 +4431,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", - "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.1.tgz", + "integrity": "sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0" + "@typescript-eslint/scope-manager": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4450,17 +4455,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", - "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.1.tgz", + "integrity": "sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/types": "8.59.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -6012,9 +6017,9 @@ "license": "MIT" }, "node_modules/filesize": { - "version": "11.0.13", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-11.0.13.tgz", - "integrity": "sha512-mYJ/qXKvREuO0uH8LTQJ6v7GsUvVOguqxg2VTwQUkyTPXXRRWPdjuUPVqdBrJQhvci48OHlNGRnux+Slr2Rnvw==", + "version": "11.0.17", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-11.0.17.tgz", + "integrity": "sha512-oHLTvMLw6imZUl1se/RBQrFlyy50nXce4sU7yGR6Qc0JgCwqnfiFsAnEwotdGmfKLD7SArGUk2/5STU0k8LOBQ==", "license": "BSD-3-Clause", "engines": { "node": ">= 10.8.0" @@ -7927,9 +7932,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -8036,9 +8041,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { @@ -8922,9 +8927,9 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -8998,9 +9003,9 @@ } }, "node_modules/undici": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", - "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", + "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", "dev": true, "license": "MIT", "engines": { @@ -9008,9 +9013,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, @@ -9131,9 +9136,9 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/client/package.json b/client/package.json index 84f4bbe..8d6bb9d 100644 --- a/client/package.json +++ b/client/package.json @@ -13,42 +13,42 @@ }, "private": true, "dependencies": { - "@angular/animations": "^21.2.4", - "@angular/cdk": "^21.2.2", - "@angular/common": "^21.2.4", - "@angular/compiler": "^21.2.4", - "@angular/core": "^21.2.4", - "@angular/forms": "^21.2.4", - "@angular/platform-browser": "^21.2.4", - "@angular/platform-browser-dynamic": "^21.2.4", - "@angular/router": "^21.2.4", + "@angular/animations": "^21.2.10", + "@angular/cdk": "^21.2.8", + "@angular/common": "^21.2.10", + "@angular/compiler": "^21.2.10", + "@angular/core": "^21.2.10", + "@angular/forms": "^21.2.10", + "@angular/platform-browser": "^21.2.10", + "@angular/platform-browser-dynamic": "^21.2.10", + "@angular/router": "^21.2.10", "@fortawesome/fontawesome-free": "^7.2.0", "@microsoft/signalr": "^10.0.0", "bulma": "^1.0.4", "curray": "^1.0.12", "file-saver-es": "^2.0.5", - "filesize": "^11.0.13", + "filesize": "^11.0.17", "rxjs": "^7.8.2", "tslib": "^2.8.1", "zone.js": "^0.16.1" }, "devDependencies": { - "@angular-eslint/builder": "21.3.0", - "@angular-eslint/eslint-plugin": "21.3.0", - "@angular-eslint/eslint-plugin-template": "21.3.0", - "@angular-eslint/schematics": "21.3.0", - "@angular-eslint/template-parser": "21.3.0", - "@angular/build": "^21.2.2", - "@angular/cli": "^21.2.2", - "@angular/compiler-cli": "^21.2.4", - "@angular/language-service": "^21.2.4", + "@angular-eslint/builder": "21.3.1", + "@angular-eslint/eslint-plugin": "21.3.1", + "@angular-eslint/eslint-plugin-template": "21.3.1", + "@angular-eslint/schematics": "21.3.1", + "@angular-eslint/template-parser": "21.3.1", + "@angular/build": "^21.2.8", + "@angular/cli": "^21.2.8", + "@angular/compiler-cli": "^21.2.10", + "@angular/language-service": "^21.2.10", "@types/file-saver": "^2.0.7", "@types/file-saver-es": "^2.0.3", - "@types/node": "^25.5.0", - "@typescript-eslint/eslint-plugin": "^8.57.0", - "@typescript-eslint/parser": "^8.57.0", + "@types/node": "^25.6.0", + "@typescript-eslint/eslint-plugin": "^8.59.1", + "@typescript-eslint/parser": "^8.59.1", "eslint": "^9.39.4", - "prettier": "^3.8.1", + "prettier": "^3.8.3", "typescript": "5.9.3" } } diff --git a/client/src/app/add-new-torrent/add-new-torrent.component.ts b/client/src/app/add-new-torrent/add-new-torrent.component.ts index 873c6af..235ad8b 100644 --- a/client/src/app/add-new-torrent/add-new-torrent.component.ts +++ b/client/src/app/add-new-torrent/add-new-torrent.component.ts @@ -1,12 +1,12 @@ import { Component, DestroyRef, OnInit, inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { Router } from '@angular/router'; -import { TorrentService } from 'src/app/torrent.service'; import { DownloadType, Torrent, TorrentFileAvailability } from '../models/torrent.model'; import { SettingsService } from '../settings.service'; import { ActivatedRoute } from '@angular/router'; import { FormsModule } from '@angular/forms'; import { NgClass } from '@angular/common'; +import { TorrentService } from '../torrent.service'; @Component({ selector: 'app-add-new-torrent', @@ -119,7 +119,8 @@ export class AddNewTorrentComponent implements OnInit { this.includeRegex = settings.find((m) => m.key === 'Gui:Default:IncludeRegex')?.value as string; this.excludeRegex = settings.find((m) => m.key === 'Gui:Default:ExcludeRegex')?.value as string; this.torrentRetryAttempts = settings.find((m) => m.key === 'Gui:Default:TorrentRetryAttempts')?.value as number; - this.downloadRetryAttempts = settings.find((m) => m.key === 'Gui:Default:DownloadRetryAttempts')?.value as number; + this.downloadRetryAttempts = settings.find((m) => m.key === 'Gui:Default:DownloadRetryAttempts') + ?.value as number; this.torrentDeleteOnError = settings.find((m) => m.key === 'Gui:Default:DeleteOnError')?.value as number; this.torrentLifetime = settings.find((m) => m.key === 'Gui:Default:TorrentLifetime')?.value as number; this.priority = settings.find((m) => m.key === 'Gui:Default:Priority')?.value as number; diff --git a/client/src/app/settings/settings.component.ts b/client/src/app/settings/settings.component.ts index 69bf78d..36de1a2 100644 --- a/client/src/app/settings/settings.component.ts +++ b/client/src/app/settings/settings.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit, inject } from '@angular/core'; -import { SettingsService } from 'src/app/settings.service'; import { Setting } from '../models/setting.model'; import { NgClass, KeyValuePipe } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { Nl2BrPipe } from '../nl2br.pipe'; import { FileSizePipe } from '../filesize.pipe'; +import { SettingsService } from '../settings.service'; @Component({ selector: 'app-settings', diff --git a/server/RdtClient.Service.Test/Services/TorrentRunnerTest.cs b/server/RdtClient.Service.Test/Services/TorrentRunnerTest.cs new file mode 100644 index 0000000..af1da08 --- /dev/null +++ b/server/RdtClient.Service.Test/Services/TorrentRunnerTest.cs @@ -0,0 +1,88 @@ +using Microsoft.Extensions.Logging; +using Moq; +using RdtClient.Data.Data; +using RdtClient.Data.Enums; +using RdtClient.Data.Models.Data; +using RdtClient.Service.Helpers; +using RdtClient.Service.Services; + +namespace RdtClient.Service.Test.Services; + +public class TorrentRunnerTest +{ + [Fact] + public async Task Tick_ShouldNotRequeueCompletedErrorTorrent() + { + var originalApiKey = Settings.Get.Provider.ApiKey; + var originalProvider = Settings.Get.Provider.Provider; + var originalMaxParallelDownloads = Settings.Get.Provider.MaxParallelDownloads; + var originalDownloadPath = Settings.Get.DownloadClient.DownloadPath; + + TorrentRunner.ActiveDownloadClients.Clear(); + TorrentRunner.ActiveUnpackClients.Clear(); + + try + { + Settings.Get.Provider.ApiKey = "test-api-key"; + Settings.Get.Provider.Provider = Provider.RealDebrid; + Settings.Get.Provider.MaxParallelDownloads = 1; + Settings.Get.DownloadClient.DownloadPath = "/downloads"; + + var erroredTorrent = new Torrent + { + TorrentId = Guid.NewGuid(), + Hash = "hash-1", + RdName = "Torrent 1", + FileOrMagnet = "magnet:?xt=urn:btih:hash-1", + Type = DownloadType.Torrent, + RdStatus = TorrentStatus.Queued, + DeleteOnError = 10, + Error = "Could not add to provider: Infringing file", + Completed = DateTimeOffset.UtcNow.AddMinutes(-5), + Downloads = new List() + }; + + var torrentDataMock = new Mock(MockBehavior.Strict); + torrentDataMock.Setup(m => m.Get()).ReturnsAsync(new List + { + erroredTorrent + }); + + var torrents = new Torrents(Mock.Of>(), + torrentDataMock.Object, + Mock.Of(), + null!, + null!, + null!, + null!, + null!, + null!, + null!, + null!); + + var torrentRunner = new TorrentRunner(Mock.Of>(), + torrents, + new Downloads(null!), + new RemoteService(null!, torrents), + Mock.Of(), + new RateLimitCoordinator()); + + await torrentRunner.Tick(); + + torrentDataMock.Verify(m => m.UpdateComplete(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny()), + Times.Never); + } + finally + { + Settings.Get.Provider.ApiKey = originalApiKey; + Settings.Get.Provider.Provider = originalProvider; + Settings.Get.Provider.MaxParallelDownloads = originalMaxParallelDownloads; + Settings.Get.DownloadClient.DownloadPath = originalDownloadPath; + TorrentRunner.ActiveDownloadClients.Clear(); + TorrentRunner.ActiveUnpackClients.Clear(); + } + } +} \ No newline at end of file diff --git a/server/RdtClient.Service/BackgroundServices/Startup.cs b/server/RdtClient.Service/BackgroundServices/Startup.cs index 36dbaf2..648242f 100644 --- a/server/RdtClient.Service/BackgroundServices/Startup.cs +++ b/server/RdtClient.Service/BackgroundServices/Startup.cs @@ -1,4 +1,5 @@ using System.Reflection; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -39,6 +40,9 @@ public class Startup(IServiceProvider serviceProvider) : IHostedService public Task StopAsync(CancellationToken cancellationToken) { + Ready = false; + SqliteConnection.ClearAllPools(); + return Task.CompletedTask; } } diff --git a/server/RdtClient.Service/Services/TorrentRunner.cs b/server/RdtClient.Service/Services/TorrentRunner.cs index bb9da16..761057b 100644 --- a/server/RdtClient.Service/Services/TorrentRunner.cs +++ b/server/RdtClient.Service/Services/TorrentRunner.cs @@ -367,7 +367,7 @@ public class TorrentRunner( } // Process torrents in DebridQueue - var torrentsToAddToProvider = allTorrents.Where(m => m.RdId == null && m.RdAdded == null && m.FileOrMagnet != null && m.RdStatus == TorrentStatus.Queued) + var torrentsToAddToProvider = allTorrents.Where(m => m.Completed == null && m.Error == null && m.RdId == null && m.RdAdded == null && m.FileOrMagnet != null && m.RdStatus == TorrentStatus.Queued) .ToList(); if (torrentsToAddToProvider.Count != 0)