diff --git a/Dockerfile b/Dockerfile index 8841d4c8..1b1ed926 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,8 @@ COPY ./ /usr/local/app/ # Install all dependencies, both production and development, build, and remove dev dependencies RUN npm ci && \ - npm run build:local && \ - npm prune --force --production + npm run build:prod && \ + npm prune --omit=dev # ---------- Release ---------- FROM nginx:1.29.1-alpine-slim diff --git a/angular.json b/angular.json index de738110..0c5d8642 100644 --- a/angular.json +++ b/angular.json @@ -71,49 +71,27 @@ "serviceWorker": true, "ngswConfigPath": "ngsw-config.json" }, - "local": { - "crossOrigin": "anonymous", - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.local.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true, "vendorChunk": true, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ], - "serviceWorker": true, - "ngswConfigPath": "ngsw-config.json" + "buildOptimizer": false } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "buildTarget": "switcher-management:build" + "buildTarget": "switcher-management:build:development" }, "configurations": { "production": { "buildTarget": "switcher-management:build:production" }, - "local": { - "buildTarget": "switcher-management:build:local" + "development": { + "buildTarget": "switcher-management:build:development" } } }, @@ -131,18 +109,6 @@ "src/**/*.html" ] } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "switcher-management:serve" - }, - "configurations": { - "production": { - "devServerTarget": "switcher-management:serve:production" - } - } } } } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 7abd95a0..294df5f2 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -15,7 +15,6 @@ "@angular/compiler": "~20.2.4", "@angular/core": "~20.2.4", "@angular/forms": "~20.2.4", - "@angular/localize": "~20.2.4", "@angular/material": "~20.2.2", "@angular/platform-browser": "~20.2.4", "@angular/platform-browser-dynamic": "~20.2.4", @@ -23,7 +22,6 @@ "@angular/service-worker": "~20.2.4", "@apollo/client": "^3.14.0", "@ng-bootstrap/ng-bootstrap": "~19.0.1", - "@popperjs/core": "^2.11.8", "@types/grecaptcha": "^3.0.9", "apollo-angular": "^11.0.0", "chart.js": "^4.5.0", @@ -45,7 +43,7 @@ "eslint": "^9.35.0", "ts-node": "^10.9.2", "typescript": "^5.9.2", - "typescript-eslint": "8.42.0" + "typescript-eslint": "8.43.0" } }, "node_modules/@algolia/abtesting": { @@ -873,6 +871,7 @@ "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-20.2.4.tgz", "integrity": "sha512-8OimXwR/hzUHJdegLD4+Zhg1h3qaAVLwLLK3G6Ba4EU9W9HJCyqvxIXooXossLBp/toFKyjU/RxmH+dwy4ztCQ==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "7.28.3", "@types/babel__core": "7.20.5", @@ -3220,9 +3219,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.8.0.tgz", - "integrity": "sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "license": "MIT", "dependencies": { @@ -3909,9 +3908,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "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": { @@ -5447,6 +5446,7 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -5659,9 +5659,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", - "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", + "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", "cpu": [ "arm" ], @@ -5673,9 +5673,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", - "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", + "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", "cpu": [ "arm64" ], @@ -5687,9 +5687,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz", - "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", + "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", "cpu": [ "arm64" ], @@ -5701,9 +5701,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", - "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", + "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", "cpu": [ "x64" ], @@ -5715,9 +5715,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", - "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", + "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", "cpu": [ "arm64" ], @@ -5729,9 +5729,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", - "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", + "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", "cpu": [ "x64" ], @@ -5743,9 +5743,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", - "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", + "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", "cpu": [ "arm" ], @@ -5757,9 +5757,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", - "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", + "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", "cpu": [ "arm" ], @@ -5771,9 +5771,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", - "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", + "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", "cpu": [ "arm64" ], @@ -5785,9 +5785,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", - "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", + "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", "cpu": [ "arm64" ], @@ -5799,9 +5799,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", - "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", + "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", "cpu": [ "loong64" ], @@ -5813,9 +5813,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", - "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", + "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", "cpu": [ "ppc64" ], @@ -5827,9 +5827,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", - "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", + "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", "cpu": [ "riscv64" ], @@ -5841,9 +5841,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", - "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", + "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", "cpu": [ "riscv64" ], @@ -5855,9 +5855,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", - "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", + "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", "cpu": [ "s390x" ], @@ -5869,9 +5869,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz", - "integrity": "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", + "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", "cpu": [ "x64" ], @@ -5883,9 +5883,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", - "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", + "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", "cpu": [ "x64" ], @@ -5897,9 +5897,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", - "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", + "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", "cpu": [ "arm64" ], @@ -5911,9 +5911,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", - "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", + "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", "cpu": [ "arm64" ], @@ -5925,9 +5925,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", - "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", + "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", "cpu": [ "ia32" ], @@ -5939,9 +5939,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", - "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", + "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", "cpu": [ "x64" ], @@ -6117,6 +6117,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -6130,6 +6131,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.0.0" } @@ -6139,6 +6141,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -6149,6 +6152,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.28.2" } @@ -6690,17 +6694,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.42.0.tgz", - "integrity": "sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.43.0.tgz", + "integrity": "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.42.0", - "@typescript-eslint/type-utils": "8.42.0", - "@typescript-eslint/utils": "8.42.0", - "@typescript-eslint/visitor-keys": "8.42.0", + "@typescript-eslint/scope-manager": "8.43.0", + "@typescript-eslint/type-utils": "8.43.0", + "@typescript-eslint/utils": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -6714,22 +6718,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.42.0", + "@typescript-eslint/parser": "^8.43.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.42.0.tgz", - "integrity": "sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.43.0.tgz", + "integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.42.0", - "@typescript-eslint/types": "8.42.0", - "@typescript-eslint/typescript-estree": "8.42.0", - "@typescript-eslint/visitor-keys": "8.42.0", + "@typescript-eslint/scope-manager": "8.43.0", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/typescript-estree": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4" }, "engines": { @@ -6745,14 +6749,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.42.0.tgz", - "integrity": "sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.43.0.tgz", + "integrity": "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.42.0", - "@typescript-eslint/types": "^8.42.0", + "@typescript-eslint/tsconfig-utils": "^8.43.0", + "@typescript-eslint/types": "^8.43.0", "debug": "^4.3.4" }, "engines": { @@ -6767,14 +6771,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.42.0.tgz", - "integrity": "sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.43.0.tgz", + "integrity": "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.42.0", - "@typescript-eslint/visitor-keys": "8.42.0" + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6785,9 +6789,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.42.0.tgz", - "integrity": "sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.43.0.tgz", + "integrity": "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==", "dev": true, "license": "MIT", "engines": { @@ -6802,15 +6806,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.42.0.tgz", - "integrity": "sha512-9KChw92sbPTYVFw3JLRH1ockhyR3zqqn9lQXol3/YbI6jVxzWoGcT3AsAW0mu1MY0gYtsXnUGV/AKpkAj5tVlQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.43.0.tgz", + "integrity": "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.42.0", - "@typescript-eslint/typescript-estree": "8.42.0", - "@typescript-eslint/utils": "8.42.0", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/typescript-estree": "8.43.0", + "@typescript-eslint/utils": "8.43.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -6827,9 +6831,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.42.0.tgz", - "integrity": "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.43.0.tgz", + "integrity": "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==", "dev": true, "license": "MIT", "engines": { @@ -6841,16 +6845,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.42.0.tgz", - "integrity": "sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.43.0.tgz", + "integrity": "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.42.0", - "@typescript-eslint/tsconfig-utils": "8.42.0", - "@typescript-eslint/types": "8.42.0", - "@typescript-eslint/visitor-keys": "8.42.0", + "@typescript-eslint/project-service": "8.43.0", + "@typescript-eslint/tsconfig-utils": "8.43.0", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -6870,16 +6874,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.42.0.tgz", - "integrity": "sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.43.0.tgz", + "integrity": "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.42.0", - "@typescript-eslint/types": "8.42.0", - "@typescript-eslint/typescript-estree": "8.42.0" + "@typescript-eslint/scope-manager": "8.43.0", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/typescript-estree": "8.43.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6894,13 +6898,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.42.0.tgz", - "integrity": "sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.43.0.tgz", + "integrity": "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/types": "8.43.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -7416,9 +7420,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz", - "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -8158,9 +8162,9 @@ } }, "node_modules/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -8170,9 +8174,9 @@ } }, "node_modules/cliui/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "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==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -9414,9 +9418,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.214", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz", - "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==", + "version": "1.5.215", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.215.tgz", + "integrity": "sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -11607,9 +11611,9 @@ } }, "node_modules/listr2/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "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": { @@ -11627,9 +11631,9 @@ "license": "MIT" }, "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "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": { @@ -11765,9 +11769,9 @@ } }, "node_modules/log-symbols/node_modules/chalk": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", - "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", + "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": { @@ -11827,9 +11831,9 @@ } }, "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "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": { @@ -11856,9 +11860,9 @@ } }, "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", - "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "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": { @@ -11873,9 +11877,9 @@ } }, "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "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": { @@ -13110,9 +13114,9 @@ } }, "node_modules/ora/node_modules/chalk": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", - "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", + "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": { @@ -14231,9 +14235,9 @@ } }, "node_modules/rollup": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.0.tgz", - "integrity": "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", + "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", "dev": true, "license": "MIT", "dependencies": { @@ -14247,27 +14251,27 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.0", - "@rollup/rollup-android-arm64": "4.50.0", - "@rollup/rollup-darwin-arm64": "4.50.0", - "@rollup/rollup-darwin-x64": "4.50.0", - "@rollup/rollup-freebsd-arm64": "4.50.0", - "@rollup/rollup-freebsd-x64": "4.50.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", - "@rollup/rollup-linux-arm-musleabihf": "4.50.0", - "@rollup/rollup-linux-arm64-gnu": "4.50.0", - "@rollup/rollup-linux-arm64-musl": "4.50.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", - "@rollup/rollup-linux-ppc64-gnu": "4.50.0", - "@rollup/rollup-linux-riscv64-gnu": "4.50.0", - "@rollup/rollup-linux-riscv64-musl": "4.50.0", - "@rollup/rollup-linux-s390x-gnu": "4.50.0", - "@rollup/rollup-linux-x64-gnu": "4.50.0", - "@rollup/rollup-linux-x64-musl": "4.50.0", - "@rollup/rollup-openharmony-arm64": "4.50.0", - "@rollup/rollup-win32-arm64-msvc": "4.50.0", - "@rollup/rollup-win32-ia32-msvc": "4.50.0", - "@rollup/rollup-win32-x64-msvc": "4.50.0", + "@rollup/rollup-android-arm-eabi": "4.50.1", + "@rollup/rollup-android-arm64": "4.50.1", + "@rollup/rollup-darwin-arm64": "4.50.1", + "@rollup/rollup-darwin-x64": "4.50.1", + "@rollup/rollup-freebsd-arm64": "4.50.1", + "@rollup/rollup-freebsd-x64": "4.50.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", + "@rollup/rollup-linux-arm-musleabihf": "4.50.1", + "@rollup/rollup-linux-arm64-gnu": "4.50.1", + "@rollup/rollup-linux-arm64-musl": "4.50.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", + "@rollup/rollup-linux-ppc64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-musl": "4.50.1", + "@rollup/rollup-linux-s390x-gnu": "4.50.1", + "@rollup/rollup-linux-x64-gnu": "4.50.1", + "@rollup/rollup-linux-x64-musl": "4.50.1", + "@rollup/rollup-openharmony-arm64": "4.50.1", + "@rollup/rollup-win32-arm64-msvc": "4.50.1", + "@rollup/rollup-win32-ia32-msvc": "4.50.1", + "@rollup/rollup-win32-x64-msvc": "4.50.1", "fsevents": "~2.3.2" } }, @@ -14893,9 +14897,9 @@ } }, "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "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": { @@ -15218,9 +15222,9 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -15741,16 +15745,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.42.0.tgz", - "integrity": "sha512-ozR/rQn+aQXQxh1YgbCzQWDFrsi9mcg+1PM3l/z5o1+20P7suOIaNg515bpr/OYt6FObz/NHcBstydDLHWeEKg==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.43.0.tgz", + "integrity": "sha512-FyRGJKUGvcFekRRcBKFBlAhnp4Ng8rhe8tuvvkR9OiU0gfd4vyvTRQHEckO6VDlH57jbeUQem2IpqPq9kLJH+w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.42.0", - "@typescript-eslint/parser": "8.42.0", - "@typescript-eslint/typescript-estree": "8.42.0", - "@typescript-eslint/utils": "8.42.0" + "@typescript-eslint/eslint-plugin": "8.43.0", + "@typescript-eslint/parser": "8.43.0", + "@typescript-eslint/typescript-estree": "8.43.0", + "@typescript-eslint/utils": "8.43.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 61e7c857..66b661d1 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,10 @@ "ng": "ng", "start": "ng serve", "build": "ng build", - "build:prod": "ng build --prod", - "build:local": "ng build --configuration local", + "build:prod": "ng build --configuration production", + "build:dev": "ng build --configuration development", "lint": "ng lint", - "lint:fix": "ng lint --fix", - "e2e": "ng e2e" + "lint:fix": "ng lint --fix" }, "keywords": [ "feature", @@ -31,7 +30,6 @@ "@angular/compiler": "~20.2.4", "@angular/core": "~20.2.4", "@angular/forms": "~20.2.4", - "@angular/localize": "~20.2.4", "@angular/material": "~20.2.2", "@angular/platform-browser": "~20.2.4", "@angular/platform-browser-dynamic": "~20.2.4", @@ -39,7 +37,6 @@ "@angular/service-worker": "~20.2.4", "@apollo/client": "^3.14.0", "@ng-bootstrap/ng-bootstrap": "~19.0.1", - "@popperjs/core": "^2.11.8", "@types/grecaptcha": "^3.0.9", "apollo-angular": "^11.0.0", "chart.js": "^4.5.0", @@ -61,7 +58,7 @@ "eslint": "^9.35.0", "ts-node": "^10.9.2", "typescript": "^5.9.2", - "typescript-eslint": "8.42.0" + "typescript-eslint": "8.43.0" }, "repository": { "type": "git", diff --git a/src/app/app-version/app-version.component.ts b/src/app/app-version/app-version.component.ts index c041b546..82eb238e 100644 --- a/src/app/app-version/app-version.component.ts +++ b/src/app/app-version/app-version.component.ts @@ -47,10 +47,14 @@ export class AppVersionComponent implements OnInit { } private toLocaleString(utcDateString: string): string { - const utcDate = new Date(utcDateString); - const localDateString = utcDate.toLocaleString(); - - return localDateString; + try { + const utcDate = new Date(utcDateString); + const localDateString = utcDate.toLocaleString(); + + return localDateString; + } catch (error) { + ConsoleLogger.printError(error); + return utcDateString; + } } - } diff --git a/src/app/dashboard-module/domain-module/domain/domain.component.html b/src/app/dashboard-module/domain-module/domain/domain.component.html index bb99970f..ed39d5dc 100644 --- a/src/app/dashboard-module/domain-module/domain/domain.component.html +++ b/src/app/dashboard-module/domain-module/domain/domain.component.html @@ -116,8 +116,7 @@

- } - @if (!loading) { + } @else {
@if (domain) { diff --git a/src/app/dashboard-module/domain-module/domain/domain.component.ts b/src/app/dashboard-module/domain-module/domain/domain.component.ts index 7e1f426d..835e2965 100644 --- a/src/app/dashboard-module/domain-module/domain/domain.component.ts +++ b/src/app/dashboard-module/domain-module/domain/domain.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; +import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef } from '@angular/core'; import { Router, ActivatedRoute, RouterOutlet } from '@angular/router'; import { takeUntil } from 'rxjs/operators'; import { Observable, Subject } from 'rxjs'; @@ -49,6 +49,7 @@ export class DomainComponent extends BasicComponent implements OnInit, OnDestroy private readonly groupService = inject(GroupService); private readonly featureService = inject(FeatureService); private readonly toastService = inject(ToastService); + private readonly cdr = inject(ChangeDetectorRef); private readonly unsubscribe = new Subject(); @@ -107,6 +108,7 @@ export class DomainComponent extends BasicComponent implements OnInit, OnDestroy .subscribe(data => { this.title = data.title; this.icon = data.icon; + this.cdr.detectChanges(); }); } @@ -248,7 +250,7 @@ export class DomainComponent extends BasicComponent implements OnInit, OnDestroy } private loadConfiguration(forceFetch = false) { - this.loading = true; + this.setLoading(true); const path = this.domainRouteService.getStoredPath(); if (path) { @@ -273,7 +275,7 @@ export class DomainComponent extends BasicComponent implements OnInit, OnDestroy }, error: error => { ConsoleLogger.printError(error); - this.loading = false; + this.setLoading(false); } }); } @@ -287,7 +289,7 @@ export class DomainComponent extends BasicComponent implements OnInit, OnDestroy this.selectedGroupPath = `${this.selectedDomainPath}/groups/${this.group?.id}`; this.selectedConfigPath = `${this.selectedGroupPath}/switchers/${this.config?.id}`; - this.loading = false; + this.setLoading(false); } private checkDomainOwner() { @@ -356,4 +358,9 @@ export class DomainComponent extends BasicComponent implements OnInit, OnDestroy }); } + private setLoading(value: boolean) { + this.loading = value; + this.cdr.detectChanges(); + } + } diff --git a/src/app/dashboard-module/domain-module/team-module/team/team.component.html b/src/app/dashboard-module/domain-module/team-module/team/team.component.html index 8286178b..508b2b63 100644 --- a/src/app/dashboard-module/domain-module/team-module/team/team.component.html +++ b/src/app/dashboard-module/domain-module/team-module/team/team.component.html @@ -6,8 +6,7 @@ } @if (error) {
{{error}}
-} -@if (!error) { +} @else {
@if (!loading) {
diff --git a/src/app/login-reset/login-reset.component.css b/src/app/login-reset/login-reset.component.css index 011cdd18..c6d49a95 100644 --- a/src/app/login-reset/login-reset.component.css +++ b/src/app/login-reset/login-reset.component.css @@ -50,12 +50,6 @@ h4 { animation: 10s ease-out 0s 1 fadeIn; } -.g-recaptcha { - padding-bottom: 10px; - display: table; - margin: auto; -} - /* Safari */ @-webkit-keyframes spin { 0% { @@ -101,11 +95,3 @@ h4 { margin-left: 0px; } } - -@media only screen and (max-width: 450px) { - .g-recaptcha { - transform: scale(0.85); - transform-origin: 0 0; - } -} - diff --git a/src/app/login-reset/login-reset.component.html b/src/app/login-reset/login-reset.component.html index 993989c4..4ad50296 100644 --- a/src/app/login-reset/login-reset.component.html +++ b/src/app/login-reset/login-reset.component.html @@ -13,12 +13,8 @@

- - @if (!error) { - diff --git a/src/app/login-reset/login-reset.component.ts b/src/app/login-reset/login-reset.component.ts index 3859831f..a96271f2 100644 --- a/src/app/login-reset/login-reset.component.ts +++ b/src/app/login-reset/login-reset.component.ts @@ -7,21 +7,21 @@ import { AuthService } from '../auth/services/auth.service'; import { FormGroup, FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { environment } from 'src/environments/environment'; import { MatFormField, MatLabel, MatInput } from '@angular/material/input'; -import { RecaptchaComponent } from '../../libs/ng-recaptcha-module/lib/recaptcha.component'; -import { RecaptchaValueAccessorDirective } from '../../libs/ng-recaptcha-module/lib/recaptcha-value-accessor.directive'; +import { ReCaptchaV3Service } from '../../libs/ng-recaptcha-module/lib/recaptcha-v3.service'; import { MatButton } from '@angular/material/button'; @Component({ selector: 'app-login-reset', templateUrl: './login-reset.component.html', styleUrls: ['./login-reset.component.css'], - imports: [FormsModule, ReactiveFormsModule, MatFormField, MatLabel, MatInput, RecaptchaComponent, RecaptchaValueAccessorDirective, MatButton] + imports: [FormsModule, ReactiveFormsModule, MatFormField, MatLabel, MatInput, MatButton] }) export class LoginResetComponent implements OnInit, OnDestroy { private readonly formBuilder = inject(FormBuilder); private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); private readonly authService = inject(AuthService); + private readonly recaptchaV3Service = inject(ReCaptchaV3Service); private readonly unsubscribe = new Subject(); @@ -34,8 +34,7 @@ export class LoginResetComponent implements OnInit, OnDestroy { ngOnInit() { this.loginForm = this.formBuilder.group({ - password: ['', Validators.required], - captcha: ['', Validators.required] + password: ['', Validators.required] }); this.route.queryParams.subscribe(params => { @@ -54,19 +53,16 @@ export class LoginResetComponent implements OnInit, OnDestroy { this.loading = true; - this.authService.resetPassword(this.code, this.f.password.value, this.recaptcha_token) + this.recaptchaV3Service.execute('password_reset') .pipe(takeUntil(this.unsubscribe)) .subscribe({ - next: success => { - if (success) { - this.router.navigateByUrl('/dashboard'); - this.authService.releaseOldSessions.emit(true); - } - this.loading = false; + next: (token) => { + this.recaptcha_token = token; + this.submitPasswordReset(); }, - error: error => { - ConsoleLogger.printError(error); - this.error = 'Invalid password format'; + error: (error) => { + ConsoleLogger.printError('reCAPTCHA error:', error); + this.error = 'reCAPTCHA verification failed. Please try again.'; this.loading = false; } }); @@ -87,8 +83,23 @@ export class LoginResetComponent implements OnInit, OnDestroy { get f() { return this.loginForm.controls; } - resolved(captchaResponse: string) { - this.recaptcha_token = captchaResponse; + private submitPasswordReset() { + this.authService.resetPassword(this.code, this.f.password.value, this.recaptcha_token) + .pipe(takeUntil(this.unsubscribe)) + .subscribe({ + next: success => { + if (success) { + this.router.navigateByUrl('/dashboard'); + this.authService.releaseOldSessions.emit(true); + } + this.loading = false; + }, + error: error => { + ConsoleLogger.printError(error); + this.error = 'Invalid password format'; + this.loading = false; + } + }); } } diff --git a/src/app/signup/signup.component.css b/src/app/signup/signup.component.css index 3e175fb1..30963472 100644 --- a/src/app/signup/signup.component.css +++ b/src/app/signup/signup.component.css @@ -63,11 +63,6 @@ h4 { animation: 10s ease-out 0s 1 fadeIn; } -.g-recaptcha { - display: inline-block; - margin: auto; -} - /* Safari */ @-webkit-keyframes spin { 0% { @@ -113,12 +108,3 @@ h4 { margin-left: 0px; } } - -@media only screen and (max-width: 450px) { - .g-recaptcha { - transform: scale(0.85); - transform-origin: 0 0; - } -} - - diff --git a/src/app/signup/signup.component.html b/src/app/signup/signup.component.html index 586d0756..5d09d2d7 100644 --- a/src/app/signup/signup.component.html +++ b/src/app/signup/signup.component.html @@ -33,20 +33,8 @@

}

- @if (getRecaptchaPublicKey()) { - - - }
- @if (getRecaptchaPublicKey() && hasInternalAuthEnabled()) { - - } - @if (!getRecaptchaPublicKey() && hasInternalAuthEnabled()) { + @if (hasInternalAuthEnabled()) { } @if (hasBitbucketIntegration()) { diff --git a/src/app/signup/signup.component.ts b/src/app/signup/signup.component.ts index 4992c7df..c12b652e 100644 --- a/src/app/signup/signup.component.ts +++ b/src/app/signup/signup.component.ts @@ -8,127 +8,139 @@ import { takeUntil } from 'rxjs/operators'; import { environment } from 'src/environments/environment'; import { ConsoleLogger } from '../_helpers/console-logger'; import { MatFormField, MatLabel, MatInput } from '@angular/material/input'; -import { RecaptchaComponent } from '../../libs/ng-recaptcha-module/lib/recaptcha.component'; -import { RecaptchaValueAccessorDirective } from '../../libs/ng-recaptcha-module/lib/recaptcha-value-accessor.directive'; +import { ReCaptchaV3Service } from '../../libs/ng-recaptcha-module/lib/recaptcha-v3.service'; import { MatButton } from '@angular/material/button'; import { AppVersionComponent } from '../app-version/app-version.component'; @Component({ - selector: 'app-signup', - templateUrl: './signup.component.html', - styleUrls: ['./signup.component.css'], - imports: [FormsModule, ReactiveFormsModule, MatFormField, MatLabel, MatInput, RecaptchaComponent, - RecaptchaValueAccessorDirective, MatButton, AppVersionComponent - ] + selector: 'app-signup', + templateUrl: './signup.component.html', + styleUrls: ['./signup.component.css'], + imports: [FormsModule, ReactiveFormsModule, MatFormField, MatLabel, MatInput, + MatButton, AppVersionComponent + ] }) export class SignupComponent implements OnInit, OnDestroy { - private readonly formBuilder = inject(FormBuilder); - private readonly router = inject(Router); - private readonly authService = inject(AuthService); - - private readonly unsubscribe = new Subject(); - - loginForm: FormGroup; - loading = false; - returnUrl: string; - apiVersion: string; - error = ''; - recaptcha_token: string; - status = ''; - - ngOnInit() { - if (this.authService.isLoggedIn()) { - this.router.navigate(['/dashboard']); - } - - this.loginForm = this.formBuilder.group({ - name: ['', Validators.required], - email: ['', [Validators.required, Validators.email]], - password: ['', Validators.required], - captcha: ['', environment.recaptchaPublicKey ? Validators.required : ''] - }); - - this.returnUrl = '/dashboard'; - this.isAlive(); - } - - getRecaptchaPublicKey(): string { - return environment.recaptchaPublicKey; - } - - get f() { return this.loginForm.controls; } - - onSubmit() { - if (this.loginForm.invalid) - return; - - this.status = ''; - this.loading = true; - this.authService.signup({ - name: this.f.name.value, - email: this.f.email.value, - password: this.f.password.value, - token: this.recaptcha_token || '' - }).pipe(takeUntil(this.unsubscribe)) - .subscribe({ - next: () => { - this.router.navigate(['/login']); - }, - error: error => { - ConsoleLogger.printError(error); - this.error = error; - this.loading = false; - } - }); + private readonly formBuilder = inject(FormBuilder); + private readonly router = inject(Router); + private readonly authService = inject(AuthService); + private readonly recaptchaV3Service = inject(ReCaptchaV3Service); + + private readonly unsubscribe = new Subject(); + + loginForm: FormGroup; + loading = false; + returnUrl: string; + apiVersion: string; + error = ''; + recaptcha_token: string; + status = ''; + + ngOnInit() { + if (this.authService.isLoggedIn()) { + this.router.navigate(['/dashboard']); } - onGitHubLogin() { - this.loading = true; - window.location.href = `https://github.com/login/oauth/authorize?client_id=${environment.githubApiClientId}`; - } - - onBitBucketLogin() { - this.loading = true; - window.location.href = `https://bitbucket.org/site/oauth2/authorize?client_id=${environment.bitbucketApiClientId}&response_type=code`; - } - - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); - } - - onKey() { - this.error = ''; - } - - resolved(captchaResponse: string) { - this.recaptcha_token = captchaResponse; - } - - hasGithubIntegration(): boolean { - return environment.githubApiClientId != undefined; - } - - hasBitbucketIntegration(): boolean { - return environment.bitbucketApiClientId != undefined; - } - - hasInternalAuthEnabled(): boolean { - return environment.allowInternalAuth; - } - - private isAlive(): void { - this.authService.isAlive().pipe(takeUntil(this.unsubscribe)) - .subscribe({ - next: data => { - if (data) { - this.apiVersion = data.attributes.version; - } - }, - error: error => { - ConsoleLogger.printError(error); - this.status = 'Offline for Maintenance'; - } - }); - } + this.loginForm = this.formBuilder.group({ + name: ['', Validators.required], + email: ['', [Validators.required, Validators.email]], + password: ['', Validators.required] + }); + + this.returnUrl = '/dashboard'; + this.isAlive(); + } + + getRecaptchaPublicKey(): string { + return environment.recaptchaPublicKey; + } + + get f() { return this.loginForm.controls; } + + onSubmit() { + if (this.loginForm.invalid) + return; + + this.status = ''; + this.loading = true; + + this.recaptchaV3Service.execute('signup') + .pipe(takeUntil(this.unsubscribe)) + .subscribe({ + next: (token) => { + this.recaptcha_token = token; + this.submitForm(); + }, + error: (error) => { + ConsoleLogger.printError('reCAPTCHA error:', error); + this.error = 'reCAPTCHA verification failed. Please try again.'; + this.loading = false; + } + }); + } + + onGitHubLogin() { + this.loading = true; + window.location.href = `https://github.com/login/oauth/authorize?client_id=${environment.githubApiClientId}`; + } + + onBitBucketLogin() { + this.loading = true; + window.location.href = `https://bitbucket.org/site/oauth2/authorize?client_id=${environment.bitbucketApiClientId}&response_type=code`; + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + onKey() { + this.error = ''; + } + + hasGithubIntegration(): boolean { + return environment.githubApiClientId != undefined; + } + + hasBitbucketIntegration(): boolean { + return environment.bitbucketApiClientId != undefined; + } + + hasInternalAuthEnabled(): boolean { + return environment.allowInternalAuth; + } + + private submitForm() { + this.authService.signup({ + name: this.f.name.value, + email: this.f.email.value, + password: this.f.password.value, + token: this.recaptcha_token || '' + }).pipe(takeUntil(this.unsubscribe)) + .subscribe({ + next: () => { + this.router.navigate(['/login']); + }, + error: error => { + ConsoleLogger.printError(error); + this.error = error; + this.loading = false; + } + }); + } + + private isAlive(): void { + this.authService.isAlive().pipe(takeUntil(this.unsubscribe)) + .subscribe({ + next: data => { + if (data) { + this.apiVersion = data.attributes.version; + } + }, + error: error => { + ConsoleLogger.printError(error); + this.status = 'Offline for Maintenance'; + } + }); + } } diff --git a/src/assets/documentation/libjava.md b/src/assets/documentation/libjava.md index 7658d853..71ada117 100644 --- a/src/assets/documentation/libjava.md +++ b/src/assets/documentation/libjava.md @@ -23,7 +23,7 @@ A Java SDK for Switcher API - Adding as a dependency - Maven ```xml - com.github.switcherapi + com.switcherapi switcher-client ${switcher-client.version} @@ -32,7 +32,7 @@ A Java SDK for Switcher API - Gradle ``` -implementation 'com.github.switcherapi:switcher-client:[VERSION]' +implementation 'com.switcherapi:switcher-client:[VERSION]' ``` ###### Compatibility with Jakarta EE 9 @@ -119,7 +119,7 @@ Instead of using SwitcherContext, which is used to automatically load from the s ```java MyAppFeatures.configure(ContextBuilder.builder() - .contextLocation("com.github.switcherapi.playground.Features") + .contextLocation("com.switcherapi.playground.Features") .apiKey("API_KEY") .url("https://api.switcherapi.com") .domain("Playground") diff --git a/src/environments/environment.global.ts b/src/environments/environment.global.ts index 3bfc4ecb..014640f6 100644 --- a/src/environments/environment.global.ts +++ b/src/environments/environment.global.ts @@ -1,12 +1,16 @@ export const environment_global = { version: 'v2.1.1', releaseTime: new Date().toUTCString(), - recaptchaPublicKey: '6LcpJ74ZAAAAAGY88BXVyk1qwjPhb2PmKXeoh5yT', + recaptchaPublicKey: '6Lc4fMErAAAAAJSdF2ZRV6HJI_m-nhiDu8Gue18P', allowInternalAuth: true, allowHomeView: false, githubApiClientId: '5745650fe81a1f1f3486', bitbucketApiClientId: 'JNfFteJqcjcDytFAh5', timeout: 5000, + teamInviteLink: 'http://localhost:4200/collab/join', + domainTransferLink: 'http://localhost:4200/domain/transfer', apiSearchDocsUrl: 'https://docs.switcherapi.com', apiFeatureUrl: 'https://switcherapi.com/feature', + apiUrl: 'https://switcherapi.com/api', + slackUrl: 'https://slack.switcherapi.com/slack/install' } \ No newline at end of file diff --git a/src/environments/environment.local.ts b/src/environments/environment.local.ts deleted file mode 100644 index ed154a14..00000000 --- a/src/environments/environment.local.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { environment_global } from "./environment.global"; - -const getEnv = (key: string, defaultValue?: string | boolean) => { - const value = window["env"][key]; - if (value === undefined || value === "") { - return defaultValue; - } - - if (typeof defaultValue === "boolean") { - return value === "true"; - } - - return value; -} - -export const environment = { - production: true, - version: environment_global.version, - releaseTime: getEnv("RELEASE_TIME"), - recaptchaPublicKey: getEnv("GOOGLE_RECAPTCHA"), - allowInternalAuth: getEnv("ALLOW_INTERNAL_AUTH", environment_global.allowInternalAuth), - allowHomeView: getEnv("ALLOW_HOME_VIEW", environment_global.allowHomeView), - githubApiClientId: getEnv("GITHUB_CLIENTID"), - bitbucketApiClientId: getEnv("BITBUCKET_CLIENTID"), - teamInviteLink: `${getEnv('SM_IP', 'localhost')}/collab/join`, - domainTransferLink: `${getEnv('SM_IP', 'localhost')}/domain/transfer`, - apiUrl: getEnv('SWITCHERAPI_URL', 'http://localhost:3000'), - apiSearchDocsUrl: environment_global.apiSearchDocsUrl, - apiFeatureUrl: environment_global.apiFeatureUrl, - slackUrl: getEnv('SWITCHERSLACKAPP_URL'), - docsUrl: 'assets/', - timeout: 5000 -}; \ No newline at end of file diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 05c26672..ed154a14 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,20 +1,33 @@ import { environment_global } from "./environment.global"; +const getEnv = (key: string, defaultValue?: string | boolean) => { + const value = window["env"][key]; + if (value === undefined || value === "") { + return defaultValue; + } + + if (typeof defaultValue === "boolean") { + return value === "true"; + } + + return value; +} + export const environment = { production: true, version: environment_global.version, - releaseTime: environment_global.releaseTime, - recaptchaPublicKey: environment_global.recaptchaPublicKey, - githubApiClientId: environment_global.githubApiClientId, - allowInternalAuth: environment_global.allowInternalAuth, - allowHomeView: environment_global.allowHomeView, - bitbucketApiClientId: environment_global.bitbucketApiClientId, - teamInviteLink: 'https://cloud.switcherapi.com/collab/join', - domainTransferLink: 'https://cloud.switcherapi.com/domain/transfer', - apiUrl: 'https://switcherapi.com/api', + releaseTime: getEnv("RELEASE_TIME"), + recaptchaPublicKey: getEnv("GOOGLE_RECAPTCHA"), + allowInternalAuth: getEnv("ALLOW_INTERNAL_AUTH", environment_global.allowInternalAuth), + allowHomeView: getEnv("ALLOW_HOME_VIEW", environment_global.allowHomeView), + githubApiClientId: getEnv("GITHUB_CLIENTID"), + bitbucketApiClientId: getEnv("BITBUCKET_CLIENTID"), + teamInviteLink: `${getEnv('SM_IP', 'localhost')}/collab/join`, + domainTransferLink: `${getEnv('SM_IP', 'localhost')}/domain/transfer`, + apiUrl: getEnv('SWITCHERAPI_URL', 'http://localhost:3000'), apiSearchDocsUrl: environment_global.apiSearchDocsUrl, apiFeatureUrl: environment_global.apiFeatureUrl, - slackUrl: 'https://slack.switcherapi.com/slack/install', - docsUrl: 'https://raw.githubusercontent.com/switcherapi/switcher-management/master/src/assets/', - timeout: environment_global.timeout -}; + slackUrl: getEnv('SWITCHERSLACKAPP_URL'), + docsUrl: 'assets/', + timeout: 5000 +}; \ No newline at end of file diff --git a/src/environments/environment.ts b/src/environments/environment.ts index fd946746..487e3fd3 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -9,12 +9,12 @@ export const environment = { allowInternalAuth: environment_global.allowInternalAuth, allowHomeView: environment_global.allowHomeView, bitbucketApiClientId: environment_global.bitbucketApiClientId, - teamInviteLink: 'http://localhost:4200/collab/join', - domainTransferLink: 'http://localhost:4200/domain/transfer', - apiUrl: 'https://switcherapi.com/api', + teamInviteLink: environment_global.teamInviteLink, + domainTransferLink: environment_global.domainTransferLink, + apiUrl: environment_global.apiUrl, apiSearchDocsUrl: environment_global.apiSearchDocsUrl, apiFeatureUrl: environment_global.apiFeatureUrl, - slackUrl: 'https://slack.switcherapi.com/slack/install', + slackUrl: environment_global.slackUrl, + timeout: environment_global.timeout, docsUrl: 'assets/', - timeout: environment_global.timeout }; \ No newline at end of file diff --git a/src/libs/ng-recaptcha-module/lib/load-script.ts b/src/libs/ng-recaptcha-module/lib/load-script.ts index 73a53e30..f6a6b06b 100644 --- a/src/libs/ng-recaptcha-module/lib/load-script.ts +++ b/src/libs/ng-recaptcha-module/lib/load-script.ts @@ -1,8 +1,11 @@ +/// + import { RecaptchaLoaderOptions } from "./tokens"; declare global { interface Window { ng2recaptchaloaded?(): void; + grecaptcha: ReCaptchaV2.ReCaptcha; } } @@ -15,7 +18,7 @@ function loadScript( { url, lang, nonce }: { url?: string; lang?: string; nonce?: string } = {}, ): void { window.ng2recaptchaloaded = () => { - onLoaded(grecaptcha); + onLoaded(window.grecaptcha); }; const script = document.createElement("script"); script.innerHTML = ""; diff --git a/src/libs/ng-recaptcha-module/lib/recaptcha-loader.service.ts b/src/libs/ng-recaptcha-module/lib/recaptcha-loader.service.ts index 7e78ca31..45f61c4f 100644 --- a/src/libs/ng-recaptcha-module/lib/recaptcha-loader.service.ts +++ b/src/libs/ng-recaptcha-module/lib/recaptcha-loader.service.ts @@ -6,6 +6,7 @@ import { filter } from "rxjs/operators"; import { loader } from "./load-script"; import { RECAPTCHA_LOADER_OPTIONS, + RECAPTCHA_V3_SITE_KEY, RecaptchaLoaderOptions, } from "./tokens"; @@ -38,8 +39,11 @@ export class RecaptchaLoaderService { constructor() { const options = inject(RECAPTCHA_LOADER_OPTIONS, { optional: true }); + const v3SiteKey = inject(RECAPTCHA_V3_SITE_KEY, { optional: true }); this.options = options; + this.v3SiteKey = v3SiteKey; + const subject = this.init(); this.ready = subject ? toNonNullObservable(subject) : of(); } diff --git a/src/libs/ng-recaptcha-module/lib/recaptcha-v3.module.ts b/src/libs/ng-recaptcha-module/lib/recaptcha-v3.module.ts new file mode 100644 index 00000000..3b8b5c25 --- /dev/null +++ b/src/libs/ng-recaptcha-module/lib/recaptcha-v3.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; + +import { ReCaptchaV3Service } from "./recaptcha-v3.service"; +import { RecaptchaLoaderService } from "./recaptcha-loader.service"; + +@NgModule({ + providers: [ + ReCaptchaV3Service, + RecaptchaLoaderService + ], +}) +export class RecaptchaV3Module {} diff --git a/src/libs/ng-recaptcha-module/lib/recaptcha-v3.service.ts b/src/libs/ng-recaptcha-module/lib/recaptcha-v3.service.ts new file mode 100644 index 00000000..c733a41c --- /dev/null +++ b/src/libs/ng-recaptcha-module/lib/recaptcha-v3.service.ts @@ -0,0 +1,150 @@ +import { inject, Injectable, NgZone } from "@angular/core"; +import { Observable, Subject } from "rxjs"; + +import { RECAPTCHA_V3_SITE_KEY } from "./tokens"; +import { RecaptchaLoaderService } from "./recaptcha-loader.service"; + +export interface OnExecuteData { + /** + * The name of the action that has been executed. + */ + action: string; + /** + * The token that reCAPTCHA v3 provided when executing the action. + */ + token: string; +} + +export interface OnExecuteErrorData { + /** + * The name of the action that has been executed. + */ + action: string; + /** + * The error which was encountered + */ + error: any; +} + +type ActionBacklogEntry = [string, Subject]; + +/** + * The main service for working with reCAPTCHA v3 APIs. + * + * Use the `execute` method for executing a single action, and + * `onExecute` observable for listening to all actions at once. + */ +@Injectable() +export class ReCaptchaV3Service { + /** @internal */ + private readonly siteKey: string; + /** @internal */ + private readonly zone: NgZone; + /** @internal */ + private actionBacklog: ActionBacklogEntry[] | undefined; + /** @internal */ + private grecaptcha: ReCaptchaV2.ReCaptcha; + + /** @internal */ + private onExecuteSubject: Subject; + /** @internal */ + private onExecuteErrorSubject: Subject; + /** @internal */ + private onExecuteObservable: Observable; + /** @internal */ + private onExecuteErrorObservable: Observable; + + private readonly recaptchaLoader = inject(RecaptchaLoaderService); + + constructor() { + this.zone = inject(NgZone); + this.siteKey = inject(RECAPTCHA_V3_SITE_KEY); + + this.init(); + } + + public get onExecute(): Observable { + if (!this.onExecuteSubject) { + this.onExecuteSubject = new Subject(); + this.onExecuteObservable = this.onExecuteSubject.asObservable(); + } + + return this.onExecuteObservable; + } + + public get onExecuteError(): Observable { + if (!this.onExecuteErrorSubject) { + this.onExecuteErrorSubject = new Subject(); + this.onExecuteErrorObservable = this.onExecuteErrorSubject.asObservable(); + } + + return this.onExecuteErrorObservable; + } + + /** + * Executes the provided `action` with reCAPTCHA v3 API. + * Use the emitted token value for verification purposes on the backend. + * + * For more information about reCAPTCHA v3 actions and tokens refer to the official documentation at + * https://developers.google.com/recaptcha/docs/v3. + * + * @param {string} action the action to execute + * @returns {Observable} an `Observable` that will emit the reCAPTCHA v3 string `token` value whenever ready. + * The returned `Observable` completes immediately after emitting a value. + */ + public execute(action: string): Observable { + const subject = new Subject(); + if (!this.grecaptcha) { + if (!this.actionBacklog) { + this.actionBacklog = []; + } + + this.actionBacklog.push([action, subject]); + } else { + this.executeActionWithSubject(action, subject); + } + + return subject.asObservable(); + } + + /** @internal */ + private executeActionWithSubject(action: string, subject: Subject): void { + const onError = (error: any) => { + this.zone.run(() => { + subject.error(error); + if (this.onExecuteErrorSubject) { + // We don't know any better at this point, unfortunately, so have to resort to `any` + this.onExecuteErrorSubject.next({ action, error }); + } + }); + }; + + this.zone.runOutsideAngular(() => { + (async () => { + try { + const token = await this.grecaptcha.execute(this.siteKey, { action }); + this.zone.run(() => { + subject.next(token); + subject.complete(); + if (this.onExecuteSubject) { + this.onExecuteSubject.next({ action, token }); + } + }); + } catch (error) { + onError(error); + } + })(); + }); + } + + /** @internal */ + private init() { + this.recaptchaLoader.ready.subscribe((value) => { + this.grecaptcha = value; + if (this.actionBacklog && this.actionBacklog.length > 0) { + this.actionBacklog.forEach(([action, subject]) => this.executeActionWithSubject(action, subject)); + this.actionBacklog = undefined; + } + }); + } +} diff --git a/src/libs/ng-recaptcha-module/lib/tokens.ts b/src/libs/ng-recaptcha-module/lib/tokens.ts index 1525ac3f..70e863d8 100644 --- a/src/libs/ng-recaptcha-module/lib/tokens.ts +++ b/src/libs/ng-recaptcha-module/lib/tokens.ts @@ -3,6 +3,7 @@ import { InjectionToken } from "@angular/core"; import { RecaptchaSettings } from "./recaptcha-settings"; export const RECAPTCHA_SETTINGS = new InjectionToken("recaptcha-settings"); +export const RECAPTCHA_V3_SITE_KEY = new InjectionToken("recaptcha-v3-site-key"); /** * Specifies the options for loading the reCAPTCHA script tag. diff --git a/src/main.ts b/src/main.ts index 29efb996..1ceff665 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,7 +14,8 @@ import { AuthGuard } from './app/auth/guards/auth.guard'; import { AuthService } from './app/auth/services/auth.service'; import { TokenInterceptor } from './app/auth/token.interceptor'; import { PwaService } from './app/services/pwa.service'; -import { RecaptchaModule } from './libs/ng-recaptcha-module'; +import { RecaptchaV3Module } from './libs/ng-recaptcha-module/lib/recaptcha-v3.module'; +import { RECAPTCHA_V3_SITE_KEY } from './libs/ng-recaptcha-module/lib/tokens'; import { ServiceWorkerModule } from '@angular/service-worker'; import { provideCharts, withDefaultRegisterables } from './libs/ng2-charts/src/lib/ng-charts.provider'; @@ -97,8 +98,9 @@ bootstrapApplication(AppComponent, { }; }), importProvidersFrom( - RecaptchaModule, + RecaptchaV3Module, ServiceWorkerModule.register('./ngsw-worker.js', { enabled: environment.production }) - ) + ), + { provide: RECAPTCHA_V3_SITE_KEY, useValue: environment.recaptchaPublicKey } ] }).catch(err => console.error(err));