From 173883000f1f0762cceeba3dfa7327cd7828b1d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 14:42:40 -0700 Subject: [PATCH 01/56] Chore(deps): Bump dockerode from 4.0.7 to 4.0.10 (#6497) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 142 +++++++++++++++++++++++++++---------------------- 2 files changed, 78 insertions(+), 66 deletions(-) diff --git a/package.json b/package.json index c0c5acd3c..aea2cdfa5 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@kubernetes/client-node": "^1.0.0", "classnames": "^2.5.1", "compare-versions": "^6.1.1", - "dockerode": "^4.0.7", + "dockerode": "^4.0.10", "follow-redirects": "^1.15.11", "gamedig": "^5.3.2", "i18next": "^25.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c7bc87aa..4378f5747 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^6.1.1 version: 6.1.1 dockerode: - specifier: ^4.0.7 - version: 4.0.7 + specifier: ^4.0.10 + version: 4.0.10 follow-redirects: specifier: ^1.15.11 version: 1.15.11 @@ -125,7 +125,7 @@ importers: version: 16.3.2(@testing-library/dom@10.4.1)(@types/react@19.0.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@vitest/coverage-v8': specifier: ^3.2.4 - version: 3.2.4(vitest@3.2.4(@types/node@24.1.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)) + version: 3.2.4(vitest@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)) eslint: specifier: ^9.25.1 version: 9.25.1(jiti@2.6.1) @@ -173,7 +173,7 @@ importers: version: 5.7.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.1.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2) + version: 3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2) optionalDependencies: osx-temperature-sensor: specifier: ^1.0.8 @@ -537,8 +537,8 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@grpc/grpc-js@1.13.4': - resolution: {integrity: sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg==} + '@grpc/grpc-js@1.14.3': + resolution: {integrity: sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==} engines: {node: '>=12.10.0'} '@grpc/proto-loader@0.7.15': @@ -546,6 +546,11 @@ packages: engines: {node: '>=6'} hasBin: true + '@grpc/proto-loader@0.8.0': + resolution: {integrity: sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==} + engines: {node: '>=6'} + hasBin: true + '@headlessui/react@2.2.9': resolution: {integrity: sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==} engines: {node: '>=10'} @@ -1262,8 +1267,8 @@ packages: '@types/node@22.13.4': resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==} - '@types/node@24.1.0': - resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==} + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} '@types/prismjs@1.26.5': resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} @@ -1606,8 +1611,8 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buildcheck@0.0.6: - resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} + buildcheck@0.0.7: + resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==} engines: {node: '>=10.0.0'} bytes@3.1.2: @@ -1890,12 +1895,12 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - docker-modem@5.0.6: - resolution: {integrity: sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ==} + docker-modem@5.0.7: + resolution: {integrity: sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==} engines: {node: '>= 8.0'} - dockerode@4.0.7: - resolution: {integrity: sha512-R+rgrSRTRdU5mH14PZTCPZtW/zw3HDWNTS/1ZAQpL/5Upe/ye5K9WQkIysu4wBoiMwKynsz0a8qWuGsHgEvSAA==} + dockerode@4.0.10: + resolution: {integrity: sha512-8L/P9JynLBiG7/coiA4FlQXegHltRqS0a+KqI44P1zgQh8QLHTg7FKOwhkBgSJwZTeHsq30WRoVFLuwkfK0YFg==} engines: {node: '>= 8.0'} doctrine@2.1.0: @@ -2862,8 +2867,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nan@2.23.0: - resolution: {integrity: sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==} + nan@2.26.2: + resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} @@ -3089,12 +3094,12 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - protobufjs@7.5.3: - resolution: {integrity: sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==} + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} engines: {node: '>=12.0.0'} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -3357,8 +3362,8 @@ packages: split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} - ssh2@1.16.0: - resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} + ssh2@1.17.0: + resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==} engines: {node: '>=10.16.0'} stable-hash@0.0.5: @@ -3512,8 +3517,8 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - tar-fs@2.1.3: - resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} @@ -3646,8 +3651,8 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - undici-types@7.8.0: - resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} undici@7.24.4: resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==} @@ -4163,16 +4168,23 @@ snapshots: '@floating-ui/utils@0.2.10': {} - '@grpc/grpc-js@1.13.4': + '@grpc/grpc-js@1.14.3': dependencies: - '@grpc/proto-loader': 0.7.15 + '@grpc/proto-loader': 0.8.0 '@js-sdsl/ordered-map': 4.4.2 '@grpc/proto-loader@0.7.15': dependencies: lodash.camelcase: 4.3.0 long: 5.3.2 - protobufjs: 7.5.3 + protobufjs: 7.5.4 + yargs: 17.7.2 + + '@grpc/proto-loader@0.8.0': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.5.4 yargs: 17.7.2 '@headlessui/react@2.2.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -4781,9 +4793,9 @@ snapshots: dependencies: undici-types: 6.20.0 - '@types/node@24.1.0': + '@types/node@25.5.0': dependencies: - undici-types: 7.8.0 + undici-types: 7.18.2 '@types/prismjs@1.26.5': {} @@ -4859,7 +4871,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.29.0 '@typescript-eslint/visitor-keys': 8.29.0 - debug: 4.4.3 + debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -4932,7 +4944,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.3.3': optional: true - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@24.1.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -4947,7 +4959,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@24.1.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2) + vitest: 3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2) transitivePeerDependencies: - supports-color @@ -4959,13 +4971,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2))': + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) '@vitest/pretty-format@3.2.4': dependencies: @@ -5180,7 +5192,7 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - buildcheck@0.0.6: + buildcheck@0.0.7: optional: true bytes@3.1.2: {} @@ -5293,8 +5305,8 @@ snapshots: cpu-features@0.0.10: dependencies: - buildcheck: 0.0.6 - nan: 2.23.0 + buildcheck: 0.0.7 + nan: 2.26.2 optional: true cross-spawn@7.0.6: @@ -5434,23 +5446,23 @@ snapshots: detect-libc@2.1.2: {} - docker-modem@5.0.6: + docker-modem@5.0.7: dependencies: - debug: 4.4.1 + debug: 4.4.3 readable-stream: 3.6.2 split-ca: 1.0.1 - ssh2: 1.16.0 + ssh2: 1.17.0 transitivePeerDependencies: - supports-color - dockerode@4.0.7: + dockerode@4.0.10: dependencies: '@balena/dockerignore': 1.0.2 - '@grpc/grpc-js': 1.13.4 + '@grpc/grpc-js': 1.14.3 '@grpc/proto-loader': 0.7.15 - docker-modem: 5.0.6 - protobufjs: 7.5.3 - tar-fs: 2.1.3 + docker-modem: 5.0.7 + protobufjs: 7.5.4 + tar-fs: 2.1.4 uuid: 10.0.0 transitivePeerDependencies: - supports-color @@ -6618,7 +6630,7 @@ snapshots: ms@2.1.3: {} - nan@2.23.0: + nan@2.26.2: optional: true nanoid@3.3.11: {} @@ -6837,7 +6849,7 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - protobufjs@7.5.3: + protobufjs@7.5.4: dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 @@ -6849,10 +6861,10 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 24.1.0 + '@types/node': 25.5.0 long: 5.3.2 - pump@3.0.3: + pump@3.0.4: dependencies: end-of-stream: 1.4.5 once: 1.4.0 @@ -7190,13 +7202,13 @@ snapshots: split-ca@1.0.1: {} - ssh2@1.16.0: + ssh2@1.17.0: dependencies: asn1: 0.2.6 bcrypt-pbkdf: 1.0.2 optionalDependencies: cpu-features: 0.0.10 - nan: 2.23.0 + nan: 2.26.2 stable-hash@0.0.5: {} @@ -7356,11 +7368,11 @@ snapshots: tapable@2.3.0: {} - tar-fs@2.1.3: + tar-fs@2.1.4: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.3 + pump: 3.0.4 tar-stream: 2.2.0 tar-stream@2.2.0: @@ -7507,7 +7519,7 @@ snapshots: undici-types@6.20.0: {} - undici-types@7.8.0: {} + undici-types@7.18.2: {} undici@7.24.4: {} @@ -7570,13 +7582,13 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-node@3.2.4(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2): + vite-node@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - '@types/node' - jiti @@ -7591,7 +7603,7 @@ snapshots: - tsx - yaml - vite@7.3.1(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2): + vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.4) @@ -7600,16 +7612,16 @@ snapshots: rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.1.0 + '@types/node': 25.5.0 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 - vitest@3.2.4(@types/node@24.1.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2): + vitest@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2)) + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -7627,11 +7639,11 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2) - vite-node: 3.2.4(@types/node@24.1.0)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) + vite-node: 3.2.4(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.1.0 + '@types/node': 25.5.0 jsdom: 28.1.0 transitivePeerDependencies: - jiti From 9fe5ad62f1308d7e876b68c2755b1be4f6c18588 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:47:23 +0000 Subject: [PATCH 02/56] Chore(deps-dev): Bump postcss from 8.5.6 to 8.5.8 (#6499) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index aea2cdfa5..9760960cb 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-hooks": "^5.2.0", "jsdom": "^28.1.0", - "postcss": "^8.5.6", + "postcss": "^8.5.8", "prettier": "^3.8.1", "prettier-plugin-organize-imports": "^4.3.0", "tailwind-scrollbar": "^4.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4378f5747..b4459db9b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -154,8 +154,8 @@ importers: specifier: ^28.1.0 version: 28.1.0 postcss: - specifier: ^8.5.6 - version: 8.5.6 + specifier: ^8.5.8 + version: 8.5.8 prettier: specifier: ^3.8.1 version: 3.8.1 @@ -3048,8 +3048,8 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -4689,7 +4689,7 @@ snapshots: '@alloc/quick-lru': 5.2.0 '@tailwindcss/node': 4.1.18 '@tailwindcss/oxide': 4.1.18 - postcss: 8.5.6 + postcss: 8.5.8 tailwindcss: 4.1.18 '@tanstack/react-virtual@3.13.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -6808,7 +6808,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.6: + postcss@8.5.8: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -7608,7 +7608,7 @@ snapshots: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.6 + postcss: 8.5.8 rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: From e1023466b1b9938d8443e292083c0c6d03c9316d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:53:25 +0000 Subject: [PATCH 03/56] Chore(deps-dev): Bump @eslint/compat from 2.0.2 to 2.0.3 (#6498) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 9760960cb..77cafdfa8 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "xml-js": "^1.6.11" }, "devDependencies": { - "@eslint/compat": "^2.0.2", + "@eslint/compat": "^2.0.3", "@eslint/eslintrc": "^3.3.3", "@eslint/js": "^9.39.2", "@tailwindcss/forms": "^0.5.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4459db9b..ec0383d45 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,8 +103,8 @@ importers: version: 1.6.11 devDependencies: '@eslint/compat': - specifier: ^2.0.2 - version: 2.0.2(eslint@9.25.1(jiti@2.6.1)) + specifier: ^2.0.3 + version: 2.0.3(eslint@9.25.1(jiti@2.6.1)) '@eslint/eslintrc': specifier: ^3.3.3 version: 3.3.3 @@ -462,8 +462,8 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@2.0.2': - resolution: {integrity: sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==} + '@eslint/compat@2.0.3': + resolution: {integrity: sha512-SjIJhGigp8hmd1YGIBwh7Ovri7Kisl42GYFjrOyHhtfYGGoLW6teYi/5p8W50KSsawUPpuLOSmsq1bD0NGQLBw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: eslint: ^8.40 || 9 || 10 @@ -483,8 +483,8 @@ packages: resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@1.1.0': - resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} + '@eslint/core@1.1.1': + resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/eslintrc@3.3.3': @@ -4092,9 +4092,9 @@ snapshots: '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@2.0.2(eslint@9.25.1(jiti@2.6.1))': + '@eslint/compat@2.0.3(eslint@9.25.1(jiti@2.6.1))': dependencies: - '@eslint/core': 1.1.0 + '@eslint/core': 1.1.1 optionalDependencies: eslint: 9.25.1(jiti@2.6.1) @@ -4112,7 +4112,7 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/core@1.1.0': + '@eslint/core@1.1.1': dependencies: '@types/json-schema': 7.0.15 From 2ed1da44112448e9f8f2d30b432eb039a77e3852 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:58:21 +0000 Subject: [PATCH 04/56] Chore(deps): Bump i18next from 25.8.0 to 25.10.9 (#6501) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 77cafdfa8..7f8d6aad9 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dockerode": "^4.0.10", "follow-redirects": "^1.15.11", "gamedig": "^5.3.2", - "i18next": "^25.8.0", + "i18next": "^25.10.9", "ical.js": "^2.2.1", "js-yaml": "^4.1.1", "json-rpc-2.0": "^1.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec0383d45..bc640e5c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ importers: specifier: ^5.3.2 version: 5.3.2 i18next: - specifier: ^25.8.0 - version: 25.8.0(typescript@5.7.3) + specifier: ^25.10.9 + version: 25.10.9(typescript@5.7.3) ical.js: specifier: ^2.2.1 version: 2.2.1 @@ -55,7 +55,7 @@ importers: version: 16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) next-i18next: specifier: ^15.4.3 - version: 15.4.3(@types/react@19.0.10)(i18next@25.8.0(typescript@5.7.3))(next@16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.8.0(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4) + version: 15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4) ping: specifier: ^0.4.4 version: 0.4.4 @@ -73,7 +73,7 @@ importers: version: 19.2.4(react@19.2.4) react-i18next: specifier: ^15.5.3 - version: 15.5.3(i18next@25.8.0(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) + version: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) react-icons: specifier: ^5.6.0 version: 5.6.0(react@19.2.4) @@ -2393,10 +2393,10 @@ packages: i18next-fs-backend@2.6.1: resolution: {integrity: sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ==} - i18next@25.8.0: - resolution: {integrity: sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==} + i18next@25.10.9: + resolution: {integrity: sha512-hQY9/bFoQKGlSKMlaCuLR8w1h5JjieqrsnZvEmj1Ja6Ec7fbyc4cTrCsY9mb9Sd8YQ/swsrKz1S9M8AcvVI70w==} peerDependencies: - typescript: ^5 + typescript: ^5 || ^6 peerDependenciesMeta: typescript: optional: true @@ -6194,9 +6194,9 @@ snapshots: i18next-fs-backend@2.6.1: {} - i18next@25.8.0(typescript@5.7.3): + i18next@25.10.9(typescript@5.7.3): dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 optionalDependencies: typescript: 5.7.3 @@ -6639,17 +6639,17 @@ snapshots: net@1.0.2: {} - next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.8.0(typescript@5.7.3))(next@16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.8.0(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4): + next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4): dependencies: '@babel/runtime': 7.28.6 '@types/hoist-non-react-statics': 3.3.7(@types/react@19.0.10) core-js: 3.48.0 hoist-non-react-statics: 3.3.2 - i18next: 25.8.0(typescript@5.7.3) + i18next: 25.10.9(typescript@5.7.3) i18next-fs-backend: 2.6.1 next: 16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 - react-i18next: 15.5.3(i18next@25.8.0(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) + react-i18next: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) transitivePeerDependencies: - '@types/react' @@ -6887,11 +6887,11 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-i18next@15.5.3(i18next@25.8.0(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3): + react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3): dependencies: '@babel/runtime': 7.27.6 html-parse-stringify: 3.0.1 - i18next: 25.8.0(typescript@5.7.3) + i18next: 25.10.9(typescript@5.7.3) react: 19.2.4 optionalDependencies: react-dom: 19.2.4(react@19.2.4) From f0f5c3c15c2321e6d6c1368fc193711c9cc61880 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 22:02:55 +0000 Subject: [PATCH 05/56] Chore(deps-dev): Bump @tailwindcss/forms from 0.5.10 to 0.5.11 (#6500) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 7f8d6aad9..ee1552b35 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@eslint/compat": "^2.0.3", "@eslint/eslintrc": "^3.3.3", "@eslint/js": "^9.39.2", - "@tailwindcss/forms": "^0.5.10", + "@tailwindcss/forms": "^0.5.11", "@tailwindcss/postcss": "^4.1.18", "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc640e5c0..2e5916d9e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -112,8 +112,8 @@ importers: specifier: ^9.39.2 version: 9.39.2 '@tailwindcss/forms': - specifier: ^0.5.10 - version: 0.5.10(tailwindcss@4.1.18) + specifier: ^0.5.11 + version: 0.5.11(tailwindcss@4.1.18) '@tailwindcss/postcss': specifier: ^4.1.18 version: 4.1.18 @@ -1074,8 +1074,8 @@ packages: resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} - '@tailwindcss/forms@0.5.10': - resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==} + '@tailwindcss/forms@0.5.11': + resolution: {integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==} peerDependencies: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' @@ -4618,7 +4618,7 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/forms@0.5.10(tailwindcss@4.1.18)': + '@tailwindcss/forms@0.5.11(tailwindcss@4.1.18)': dependencies: mini-svg-data-uri: 1.4.4 tailwindcss: 4.1.18 From 5af0ab1686be87e888b66e21dbadbb379a09692b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:49:43 -0700 Subject: [PATCH 06/56] Chore(deps): Bump astral-sh/setup-uv from 94527f2e458b27549849d47d273a16bec83a01e9 to 37802adc94f370d6bfd71619e3f0bf239e1f3b78 (#6503) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index 99ec06365..2f4f3964e 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -25,7 +25,7 @@ jobs: with: python-version-file: ".python-version" - name: Install uv - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 - run: sudo apt-get install pngquant - name: Test Docs Build run: uv run --frozen zensical build --clean @@ -43,7 +43,7 @@ jobs: with: python-version-file: ".python-version" - name: Install uv - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 - run: sudo apt-get install pngquant - name: Build Docs run: uv run --frozen zensical build --clean From 3cc3986ec37ae8a591f0bff9a7455707860b89fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2026 03:55:12 +0000 Subject: [PATCH 07/56] Chore(deps): Bump pnpm/action-setup from a8198c4bff370c8506180b035930dea56dbd5288 to fc06bc1257f339d1d5d8b3a19a8cae5388b55320 (#6505) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-publish.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index db7ab9cb7..2ac35005b 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -60,7 +60,7 @@ jobs: nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Install pnpm - uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 with: version: 10 run_install: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 10e2628e1..af3b40626 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -23,7 +23,7 @@ jobs: uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 - name: Install pnpm - uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 with: version: 10 run_install: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 153359bd9..9a77d8d16 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5 + - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 with: version: 9 From 5f7e5430c41a6a3f751e091fad85bd01dbefbd51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2026 03:59:04 +0000 Subject: [PATCH 08/56] Chore(deps): Bump actions/configure-pages from 5.0.0 to 6.0.0 (#6506) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index 2f4f3964e..9a103424e 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -37,7 +37,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 + - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: From d64fbae7762f3e06cc226a109c24d250d137c009 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2026 04:04:05 +0000 Subject: [PATCH 09/56] Chore(deps): Update release-drafter/release-drafter requirement to 139054aeaa9adc52ab36ddf67437541f039b88e2 (#6504) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-drafter.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 50e51415e..c5c262769 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -26,14 +26,14 @@ jobs: runs-on: ubuntu-latest steps: - if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' - uses: release-drafter/release-drafter@a6acf82562eee06318b77ab8cb0b11ed81c677a7 # v7 + uses: release-drafter/release-drafter@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7 with: config-name: release-drafter.yml version: ${{ github.event.inputs.version }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == '' - uses: release-drafter/release-drafter@a6acf82562eee06318b77ab8cb0b11ed81c677a7 # v7 + uses: release-drafter/release-drafter@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7 with: config-name: release-drafter.yml env: @@ -47,7 +47,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter/autolabeler@ebb69bb56f1b0ebd19897745035726b19bef973e + - uses: release-drafter/release-drafter/autolabeler@139054aeaa9adc52ab36ddf67437541f039b88e2 with: config-name: release-drafter.yml env: From 6df1cfdeba058a52a1363a7a7f4a3a1a61cdb007 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2026 04:07:54 +0000 Subject: [PATCH 10/56] Chore(deps): Bump peakoss/anti-slop from a5a4b2440c9de6f65b64f0718a0136a1fdb04f6f to 85daca1880e9e1af197fc06ea03349daf08f4202 (#6507) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pr-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-quality.yml b/.github/workflows/pr-quality.yml index e662a51b7..b0a7e9de5 100644 --- a/.github/workflows/pr-quality.yml +++ b/.github/workflows/pr-quality.yml @@ -13,6 +13,6 @@ jobs: anti-slop: runs-on: ubuntu-latest steps: - - uses: peakoss/anti-slop@a5a4b2440c9de6f65b64f0718a0136a1fdb04f6f # v0 + - uses: peakoss/anti-slop@85daca1880e9e1af197fc06ea03349daf08f4202 # v0 with: max-failures: 4 From 11d1ceb7559dab8cc786cb947857daf4016363a0 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 5 Apr 2026 07:21:06 -0700 Subject: [PATCH 11/56] Enhancement: increase resources page size for pangolin widget (#6523) --- src/widgets/pangolin/widget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/pangolin/widget.js b/src/widgets/pangolin/widget.js index 899949fa6..05ce0b9a9 100644 --- a/src/widgets/pangolin/widget.js +++ b/src/widgets/pangolin/widget.js @@ -9,7 +9,7 @@ const widget = { endpoint: "org/{org}/sites", }, resources: { - endpoint: "org/{org}/resources", + endpoint: "org/{org}/resources?pageSize=200", }, }, }; From a56a05b5532a78039d3099e33389589e88d1f9d6 Mon Sep 17 00:00:00 2001 From: Gabe Dunn Date: Mon, 6 Apr 2026 09:45:47 -0700 Subject: [PATCH 12/56] Documentation: add reference to required settings to ingressroute docs (#6527) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/configs/kubernetes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configs/kubernetes.md b/docs/configs/kubernetes.md index 88748f177..9592a1cd5 100644 --- a/docs/configs/kubernetes.md +++ b/docs/configs/kubernetes.md @@ -122,7 +122,7 @@ Use the `gethomepage.dev/pod-selector` selector to specify the pod used for the ### Traefik IngressRoute support -Homepage can also read ingresses defined using the Traefik IngressRoute custom resource definition. Due to the complex nature of Traefik routing rules, it is required for the `gethomepage.dev/href` annotation to be set: +If enabled (with `traefik: true` in kubernetes.yaml), homepage can also read ingresses defined using the Traefik IngressRoute custom resource definition. Due to the complex nature of Traefik routing rules, it is required for the `gethomepage.dev/href` annotation to be set: ```yaml apiVersion: traefik.io/v1alpha1 From 5f4b0b4e33399499b75cd7b15960bb63ffd02168 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 7 Apr 2026 08:04:35 -0700 Subject: [PATCH 13/56] Enhancement: Cache and reuse keep-alive HTTP(S) agents (#6536) --- src/utils/proxy/http.js | 34 +++++++++++++++++++++++++++------- src/utils/proxy/http.test.js | 16 ++++++++++++++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/utils/proxy/http.js b/src/utils/proxy/http.js index df451ec26..8cf50899f 100644 --- a/src/utils/proxy/http.js +++ b/src/utils/proxy/http.js @@ -224,23 +224,43 @@ function homepageDNSLookupFn() { }; } +const homepageLookup = homepageDNSLookupFn(); +const agentCache = new Map(); + +function getAgent(protocol, disableIpv6) { + const cacheKey = `${protocol}:${disableIpv6 ? "ipv4" : "auto"}`; + const cachedAgent = agentCache.get(cacheKey); + if (cachedAgent) { + return cachedAgent; + } + + const agentOptions = { + keepAlive: true, + ...(disableIpv6 ? { family: 4, autoSelectFamily: false } : { autoSelectFamilyAttemptTimeout: 500 }), + lookup: homepageLookup, + }; + + const agent = + protocol === "https:" + ? new https.Agent({ ...agentOptions, rejectUnauthorized: false }) + : new http.Agent(agentOptions); + + agentCache.set(cacheKey, agent); + return agent; +} + export async function httpProxy(url, params = {}) { const constructedUrl = new URL(url); const disableIpv6 = process.env.HOMEPAGE_PROXY_DISABLE_IPV6 === "true"; - const agentOptions = { - ...(disableIpv6 ? { family: 4, autoSelectFamily: false } : { autoSelectFamilyAttemptTimeout: 500 }), - lookup: homepageDNSLookupFn(), - }; - let request = null; if (constructedUrl.protocol === "https:") { request = httpsRequest(constructedUrl, { - agent: new https.Agent({ ...agentOptions, rejectUnauthorized: false }), + agent: getAgent(constructedUrl.protocol, disableIpv6), ...params, }); } else { request = httpRequest(constructedUrl, { - agent: new http.Agent(agentOptions), + agent: getAgent(constructedUrl.protocol, disableIpv6), ...params, }); } diff --git a/src/utils/proxy/http.test.js b/src/utils/proxy/http.test.js index e2cdf1087..8f3cc0198 100644 --- a/src/utils/proxy/http.test.js +++ b/src/utils/proxy/http.test.js @@ -8,6 +8,7 @@ const { state, cache, logger, dns, net, cookieJar } = vi.hoisted(() => ({ body: Buffer.from(""), }, error: null, + lastAgent: null, lastAgentOptions: null, lastRequestParams: null, lastWrittenBody: null, @@ -59,6 +60,7 @@ vi.mock("follow-redirects", async () => { state.lastWrittenBody = chunk; }); req.end = vi.fn(() => { + state.lastAgent = params?.agent ?? null; state.lastAgentOptions = params?.agent?.opts ?? null; if (state.error) { req.emit("error", state.error); @@ -104,6 +106,7 @@ describe("utils/proxy/http cachedRequest", () => { headers: { "content-type": "application/json" }, body: Buffer.from(""), }; + state.lastAgent = null; state.lastAgentOptions = null; state.lastRequestParams = null; state.lastWrittenBody = null; @@ -307,6 +310,7 @@ describe("utils/proxy/http httpProxy", () => { headers: { "content-type": "application/json" }, body: Buffer.from("ok"), }; + state.lastAgent = null; state.lastAgentOptions = null; state.lastRequestParams = null; state.lastWrittenBody = null; @@ -397,6 +401,7 @@ describe("utils/proxy/http httpProxy", () => { await httpMod.httpProxy("http://example.com"); + expect(state.lastAgentOptions.keepAlive).toBe(true); expect(state.lastAgentOptions.family).toBe(4); expect(state.lastAgentOptions.autoSelectFamily).toBe(false); }); @@ -409,6 +414,17 @@ describe("utils/proxy/http httpProxy", () => { expect(state.lastAgentOptions.rejectUnauthorized).toBe(false); }); + it("reuses the same keep-alive agent for repeated http requests", async () => { + const httpMod = await import("./http"); + + await httpMod.httpProxy("http://example.com/first"); + const firstAgent = state.lastAgent; + await httpMod.httpProxy("http://example.com/second"); + + expect(state.lastAgentOptions.keepAlive).toBe(true); + expect(state.lastAgent).toBe(firstAgent); + }); + it("returns a sanitized error response when the request fails", async () => { state.error = Object.assign(new Error("boom"), { code: "EHOSTUNREACH" }); const httpMod = await import("./http"); From bdbd2e6ff000955c88124dae5c8682d1c27f4953 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:44:10 -0700 Subject: [PATCH 14/56] Chore(deps): Bump vite from 7.3.1 to 7.3.2 in the npm_and_yarn group across 1 directory (#6539) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e5916d9e..aa676dc3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3699,8 +3699,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@7.3.2: + resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4971,13 +4971,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2))': + '@vitest/mocker@3.2.4(vite@7.3.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) '@vitest/pretty-format@3.2.4': dependencies: @@ -7588,7 +7588,7 @@ snapshots: debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - '@types/node' - jiti @@ -7603,7 +7603,7 @@ snapshots: - tsx - yaml - vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2): + vite@7.3.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.4) @@ -7621,7 +7621,7 @@ snapshots: dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)) + '@vitest/mocker': 3.2.4(vite@7.3.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -7639,7 +7639,7 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) vite-node: 3.2.4(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2) why-is-node-running: 2.3.0 optionalDependencies: From ade4c733c719e6d8133b0eb57860433a0b38dba3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:11:26 -0700 Subject: [PATCH 15/56] Chore(deps): Bump codecov/codecov-action from 5.5.4 to 6.0.0 (#6543) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9a77d8d16..3b7d43609 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: # Run Vitest directly so `--shard` is parsed as an option - run: pnpm -s exec vitest run --coverage --shard ${{ matrix.shard }}/4 --pool forks - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage/lcov.info From 038f5c3b9fce5d694fada7991656687f3424f21a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:15:15 +0000 Subject: [PATCH 16/56] Chore(deps): Bump actions/deploy-pages from 4.0.5 to 5.0.0 (#6542) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index 9a103424e..8b6bd1f6d 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -50,5 +50,5 @@ jobs: - uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 with: path: site - - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 + - uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 id: deployment From 70f8c67d3c3b3c9e92af78789a35e5e8eb5f21ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:19:12 +0000 Subject: [PATCH 17/56] Chore(deps): Bump astral-sh/setup-uv from 7.6.0 to 8.0.0 (#6541) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index 8b6bd1f6d..ad0e960a1 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -25,7 +25,7 @@ jobs: with: python-version-file: ".python-version" - name: Install uv - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - run: sudo apt-get install pngquant - name: Test Docs Build run: uv run --frozen zensical build --clean @@ -43,7 +43,7 @@ jobs: with: python-version-file: ".python-version" - name: Install uv - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - run: sudo apt-get install pngquant - name: Build Docs run: uv run --frozen zensical build --clean From 24804f39fc06b46eac00fa17b1f00b08c2715e49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:23:32 +0000 Subject: [PATCH 18/56] Chore(deps): Bump docker/login-action from 4.0.0 to 4.1.0 (#6540) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 2ac35005b..abcd872da 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -83,7 +83,7 @@ jobs: - name: Log into registry ${{ env.REGISTRY }} if: github.event_name != 'pull_request' - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -91,7 +91,7 @@ jobs: - name: Login to Docker Hub if: github.event_name != 'pull_request' - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} From d048888d99e045022a182b7d6b6602601b62fa37 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:24:05 -0700 Subject: [PATCH 19/56] Trigger Docker publish on fix/** branches --- .github/workflows/docker-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index abcd872da..64bd01b81 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -7,6 +7,7 @@ on: branches: - main - feature/** + - fix/** - dev tags: [ 'v*.*.*' ] pull_request: From 636d62106cb97566fd96a48a812d0a84cff0c19b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:47:20 -0700 Subject: [PATCH 20/56] Chore(deps): Bump next from 16.1.7 to 16.2.3 in the npm_and_yarn group across 1 directory (#6547) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 132 ++++++++++++++++++++++++------------------------- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index ee1552b35..5d5bdf606 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "luxon": "^3.6.1", "memory-cache": "^0.2.0", "minecraftstatuspinger": "^1.2.2", - "next": "^16.1.7", + "next": "^16.2.3", "next-i18next": "^15.4.3", "ping": "^0.4.4", "pretty-bytes": "^7.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa676dc3b..58c85862c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,11 +51,11 @@ importers: specifier: ^1.2.2 version: 1.2.2 next: - specifier: ^16.1.7 - version: 16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^16.2.3 + version: 16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) next-i18next: specifier: ^15.4.3 - version: 15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4) + version: 15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4) ping: specifier: ^0.4.4 version: 0.4.4 @@ -290,8 +290,8 @@ packages: '@emnapi/core@1.4.0': resolution: {integrity: sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==} - '@emnapi/runtime@1.9.0': - resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==} + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} '@emnapi/wasi-threads@1.0.1': resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} @@ -764,56 +764,56 @@ packages: '@napi-rs/wasm-runtime@0.2.8': resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==} - '@next/env@16.1.7': - resolution: {integrity: sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==} + '@next/env@16.2.3': + resolution: {integrity: sha512-ZWXyj4uNu4GCWQw9cjRxWlbD+33mcDszIo9iQxFnBX3Wmgq9ulaSJcl6VhuWx5pCWqqD+9W6Wfz7N0lM5lYPMA==} '@next/eslint-plugin-next@15.5.11': resolution: {integrity: sha512-tS/HYQOjIoX9ZNDQitba/baS8sTvo3ekY6Vgdx5lmhN4jov082bdApIChXr94qhMZHvEciz9DZglFFnhguQp/A==} - '@next/swc-darwin-arm64@16.1.7': - resolution: {integrity: sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==} + '@next/swc-darwin-arm64@16.2.3': + resolution: {integrity: sha512-u37KDKTKQ+OQLvY+z7SNXixwo4Q2/IAJFDzU1fYe66IbCE51aDSAzkNDkWmLN0yjTUh4BKBd+hb69jYn6qqqSg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.1.7': - resolution: {integrity: sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==} + '@next/swc-darwin-x64@16.2.3': + resolution: {integrity: sha512-gHjL/qy6Q6CG3176FWbAKyKh9IfntKZTB3RY/YOJdDFpHGsUDXVH38U4mMNpHVGXmeYW4wj22dMp1lTfmu/bTQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.1.7': - resolution: {integrity: sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==} + '@next/swc-linux-arm64-gnu@16.2.3': + resolution: {integrity: sha512-U6vtblPtU/P14Y/b/n9ZY0GOxbbIhTFuaFR7F4/uMBidCi2nSdaOFhA0Go81L61Zd6527+yvuX44T4ksnf8T+Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.1.7': - resolution: {integrity: sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==} + '@next/swc-linux-arm64-musl@16.2.3': + resolution: {integrity: sha512-/YV0LgjHUmfhQpn9bVoGc4x4nan64pkhWR5wyEV8yCOfwwrH630KpvRg86olQHTwHIn1z59uh6JwKvHq1h4QEw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@16.1.7': - resolution: {integrity: sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==} + '@next/swc-linux-x64-gnu@16.2.3': + resolution: {integrity: sha512-/HiWEcp+WMZ7VajuiMEFGZ6cg0+aYZPqCJD3YJEfpVWQsKYSjXQG06vJP6F1rdA03COD9Fef4aODs3YxKx+RDQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.1.7': - resolution: {integrity: sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==} + '@next/swc-linux-x64-musl@16.2.3': + resolution: {integrity: sha512-Kt44hGJfZSefebhk/7nIdivoDr3Ugp5+oNz9VvF3GUtfxutucUIHfIO0ZYO8QlOPDQloUVQn4NVC/9JvHRk9hw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@16.1.7': - resolution: {integrity: sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==} + '@next/swc-win32-arm64-msvc@16.2.3': + resolution: {integrity: sha512-O2NZ9ie3Tq6xj5Z5CSwBT3+aWAMW2PIZ4egUi9MaWLkwaehgtB7YZjPm+UpcNpKOme0IQuqDcor7BsW6QBiQBw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.1.7': - resolution: {integrity: sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==} + '@next/swc-win32-x64-msvc@16.2.3': + resolution: {integrity: sha512-Ibm29/GgB/ab5n7XKqlStkm54qqZE8v2FnijUPBgrd67FWrac45o/RsNlaOWjme/B5UqeWt/8KM4aWBwA1D2Kw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1067,8 +1067,8 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@swc/helpers@0.5.19': - resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==} + '@swc/helpers@0.5.21': + resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} '@szmarczak/http-timer@5.0.1': resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} @@ -1584,8 +1584,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.8: - resolution: {integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==} + baseline-browser-mapping@2.10.17: + resolution: {integrity: sha512-HdrkN8eVG2CXxeifv/VdJ4A4RSra1DTW8dc/hdxzhGHN8QePs6gKaWM9pHPcpCoxYZJuOZ8drHmbdpLHjCYjLA==} engines: {node: '>=6.0.0'} hasBin: true @@ -1651,8 +1651,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001780: - resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} + caniuse-lite@1.0.30001787: + resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==} chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} @@ -2890,8 +2890,8 @@ packages: react: '>= 17.0.2' react-i18next: '>= 13.5.0' - next@16.1.7: - resolution: {integrity: sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==} + next@16.2.3: + resolution: {integrity: sha512-9V3zV4oZFza3PVev5/poB9g0dEafVcgNyQ8eTRop8GvxZjV2G15FC5ARuG1eFD42QgeYkzJBJzHghNP8Ad9xtA==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -3997,7 +3997,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.0': + '@emnapi/runtime@1.9.2': dependencies: tslib: 2.8.1 optional: true @@ -4295,7 +4295,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.9.0 + '@emnapi/runtime': 1.9.2 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -4379,38 +4379,38 @@ snapshots: '@napi-rs/wasm-runtime@0.2.8': dependencies: '@emnapi/core': 1.4.0 - '@emnapi/runtime': 1.9.0 + '@emnapi/runtime': 1.9.2 '@tybys/wasm-util': 0.9.0 optional: true - '@next/env@16.1.7': {} + '@next/env@16.2.3': {} '@next/eslint-plugin-next@15.5.11': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@16.1.7': + '@next/swc-darwin-arm64@16.2.3': optional: true - '@next/swc-darwin-x64@16.1.7': + '@next/swc-darwin-x64@16.2.3': optional: true - '@next/swc-linux-arm64-gnu@16.1.7': + '@next/swc-linux-arm64-gnu@16.2.3': optional: true - '@next/swc-linux-arm64-musl@16.1.7': + '@next/swc-linux-arm64-musl@16.2.3': optional: true - '@next/swc-linux-x64-gnu@16.1.7': + '@next/swc-linux-x64-gnu@16.2.3': optional: true - '@next/swc-linux-x64-musl@16.1.7': + '@next/swc-linux-x64-musl@16.2.3': optional: true - '@next/swc-win32-arm64-msvc@16.1.7': + '@next/swc-win32-arm64-msvc@16.2.3': optional: true - '@next/swc-win32-x64-msvc@16.1.7': + '@next/swc-win32-x64-msvc@16.2.3': optional: true '@nodelib/fs.scandir@2.1.5': @@ -4460,7 +4460,7 @@ snapshots: '@react-aria/interactions': 3.25.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/utils': 3.31.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-types/shared': 3.32.1(react@19.2.4) - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.21 clsx: 2.1.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -4471,13 +4471,13 @@ snapshots: '@react-aria/utils': 3.31.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-stately/flags': 3.1.2 '@react-types/shared': 3.32.1(react@19.2.4) - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.21 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) '@react-aria/ssr@3.9.10(react@19.2.4)': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.21 react: 19.2.4 '@react-aria/utils@3.31.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -4486,18 +4486,18 @@ snapshots: '@react-stately/flags': 3.1.2 '@react-stately/utils': 3.10.8(react@19.2.4) '@react-types/shared': 3.32.1(react@19.2.4) - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.21 clsx: 2.1.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) '@react-stately/flags@3.1.2': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.21 '@react-stately/utils@3.10.8(react@19.2.4)': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.21 react: 19.2.4 '@react-types/shared@3.32.1(react@19.2.4)': @@ -4610,7 +4610,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/helpers@0.5.19': + '@swc/helpers@0.5.21': dependencies: tslib: 2.8.1 @@ -5158,7 +5158,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.8: {} + baseline-browser-mapping@2.10.17: {} bcrypt-pbkdf@1.0.2: dependencies: @@ -5235,7 +5235,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001780: {} + caniuse-lite@1.0.30001787: {} chai@5.3.3: dependencies: @@ -6639,7 +6639,7 @@ snapshots: net@1.0.2: {} - next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4): + next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4): dependencies: '@babel/runtime': 7.28.6 '@types/hoist-non-react-statics': 3.3.7(@types/react@19.0.10) @@ -6647,31 +6647,31 @@ snapshots: hoist-non-react-statics: 3.3.2 i18next: 25.10.9(typescript@5.7.3) i18next-fs-backend: 2.6.1 - next: 16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: 16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-i18next: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) transitivePeerDependencies: - '@types/react' - next@16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - '@next/env': 16.1.7 + '@next/env': 16.2.3 '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.8 - caniuse-lite: 1.0.30001780 + baseline-browser-mapping: 2.10.17 + caniuse-lite: 1.0.30001787 postcss: 8.4.31 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) styled-jsx: 5.1.6(react@19.2.4) optionalDependencies: - '@next/swc-darwin-arm64': 16.1.7 - '@next/swc-darwin-x64': 16.1.7 - '@next/swc-linux-arm64-gnu': 16.1.7 - '@next/swc-linux-arm64-musl': 16.1.7 - '@next/swc-linux-x64-gnu': 16.1.7 - '@next/swc-linux-x64-musl': 16.1.7 - '@next/swc-win32-arm64-msvc': 16.1.7 - '@next/swc-win32-x64-msvc': 16.1.7 + '@next/swc-darwin-arm64': 16.2.3 + '@next/swc-darwin-x64': 16.2.3 + '@next/swc-linux-arm64-gnu': 16.2.3 + '@next/swc-linux-arm64-musl': 16.2.3 + '@next/swc-linux-x64-gnu': 16.2.3 + '@next/swc-linux-x64-musl': 16.2.3 + '@next/swc-win32-arm64-msvc': 16.2.3 + '@next/swc-win32-x64-msvc': 16.2.3 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' From 1accddf29a76baa581cec7a1aa0994db76c3dc0d Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:48:38 -0700 Subject: [PATCH 21/56] Fix: prevent omada race conditions with auth and cookie caching (#6549) --- src/utils/proxy/cookie-jar.js | 5 +- src/utils/proxy/cookie-jar.test.js | 12 + src/widgets/omada/proxy.js | 442 +++++++++++++++++----------- src/widgets/omada/proxy.test.js | 454 ++++++++++++++++++++++++++++- 4 files changed, 735 insertions(+), 178 deletions(-) diff --git a/src/utils/proxy/cookie-jar.js b/src/utils/proxy/cookie-jar.js index 3161d1d2f..66e00dca1 100644 --- a/src/utils/proxy/cookie-jar.js +++ b/src/utils/proxy/cookie-jar.js @@ -7,7 +7,10 @@ export function setCookieHeader(url, params) { const existingCookie = cookieJar.getCookieStringSync(url.toString()); if (existingCookie) { params.headers = params.headers ?? {}; - params.headers[params.cookieHeader ?? "Cookie"] = existingCookie; + const cookieHeader = params.cookieHeader ?? "Cookie"; + if (!params.headers[cookieHeader]) { + params.headers[cookieHeader] = existingCookie; + } } } diff --git a/src/utils/proxy/cookie-jar.test.js b/src/utils/proxy/cookie-jar.test.js index 29c4bee96..83e459b3c 100644 --- a/src/utils/proxy/cookie-jar.test.js +++ b/src/utils/proxy/cookie-jar.test.js @@ -42,4 +42,16 @@ describe("utils/proxy/cookie-jar", () => { expect(params.headers.Cookie).toContain("c=d"); }); + + it("does not overwrite an explicit cookie header", async () => { + const { addCookieToJar, setCookieHeader } = await import("./cookie-jar"); + + const url = new URL("http://example4.test/path"); + addCookieToJar(url, { "set-cookie": ["sid=1; Path=/"] }); + + const params = { headers: { Cookie: "manual=1" } }; + setCookieHeader(url, params); + + expect(params.headers.Cookie).toBe("manual=1"); + }); }); diff --git a/src/widgets/omada/proxy.js b/src/widgets/omada/proxy.js index 04d173de1..d5cc86cf6 100644 --- a/src/widgets/omada/proxy.js +++ b/src/widgets/omada/proxy.js @@ -1,12 +1,40 @@ +import cache from "memory-cache"; + import getServiceWidget from "utils/config/service-helpers"; import createLogger from "utils/logger"; import { httpProxy } from "utils/proxy/http"; const proxyName = "omadaProxyHandler"; +const sessionCacheKey = `${proxyName}__session`; const logger = createLogger(proxyName); -async function login(loginUrl, username, password, controllerVersionMajor) { +function getSessionCacheId(group, service, index) { + return [sessionCacheKey, group, service, index ?? "0"].join("."); +} + +function shouldRetryWithFreshSession(status, responseData, attempt, usedCachedSession) { + return attempt === 0 && usedCachedSession && (status === 401 || status === 403 || responseData?.errorCode > 0); +} + +function getCookieHeader(responseHeaders) { + const setCookie = responseHeaders?.["set-cookie"]; + if (!setCookie) return null; + + const cookies = new Map(); + (Array.isArray(setCookie) ? setCookie : [setCookie]).forEach((cookie) => { + const cookiePair = cookie.split(";")[0]; + if (!cookiePair) return; + + const separatorIndex = cookiePair.indexOf("="); + const cookieName = separatorIndex === -1 ? cookiePair : cookiePair.slice(0, separatorIndex); + cookies.set(cookieName, cookiePair); + }); + + return cookies.size > 0 ? Array.from(cookies.values()).join("; ") : null; +} + +async function login(loginUrl, username, password, controllerVersionMajor, sessionCacheId) { const params = { username, password, @@ -20,7 +48,7 @@ async function login(loginUrl, username, password, controllerVersionMajor) { }; } - const [status, contentType, data] = await httpProxy(loginUrl, { + const [status, contentType, data, responseHeaders] = await httpProxy(loginUrl, { method: "POST", body: JSON.stringify(params), headers: { @@ -28,7 +56,20 @@ async function login(loginUrl, username, password, controllerVersionMajor) { }, }); - return [status, JSON.parse(data.toString())]; + const loginResponseData = JSON.parse(data.toString()); + + if (status === 200 && loginResponseData.errorCode === 0) { + cache.put( + sessionCacheId, + { + token: loginResponseData.result.token, + cookieHeader: getCookieHeader(responseHeaders), + }, + 55 * 60 * 1000, // Cache session for 55 minutes + ); + } + + return [status, loginResponseData]; } export default async function omadaProxyHandler(req, res) { @@ -86,182 +127,247 @@ export default async function omadaProxyHandler(req, res) { break; } - const [loginStatus, loginResponseData] = await login( - loginUrl, - widget.username, - widget.password, - controllerVersionMajor, - ); + const sessionCacheId = getSessionCacheId(group, service, index); + let session = cache.get(sessionCacheId); - if (loginStatus !== 200 || loginResponseData.errorCode > 0) { - return res - .status(loginStatus) - .json({ error: { message: "Error logging in to Omada controller", url: loginUrl, data: loginResponseData } }); - } + for (let attempt = 0; attempt < 2; attempt += 1) { + try { + const usedCachedSession = Boolean(session); - const { token } = loginResponseData.result; + if (!session) { + const [loginStatus, loginResponseData] = await login( + loginUrl, + widget.username, + widget.password, + controllerVersionMajor, + sessionCacheId, + ); - let sitesUrl; - let body = {}; - let params = { token }; - let headers = { "Csrf-Token": token }; - let method = "GET"; + if (loginStatus !== 200 || loginResponseData.errorCode > 0) { + return res.status(loginStatus).json({ + error: { message: "Error logging in to Omada controller", url: loginUrl, data: loginResponseData }, + }); + } - switch (controllerVersionMajor) { - case 3: - sitesUrl = `${url}/web/v1/controller?ajax=&token=${token}`; - body = { - method: "getUserSites", - params: { - userName: widget.username, - }, - }; - method = "POST"; - break; - case 4: - sitesUrl = `${url}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; - break; - case 5: - case 6: - sitesUrl = `${url}/${cId}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; - break; - default: - break; - } + session = cache.get(sessionCacheId); + } - [status, contentType, data] = await httpProxy(sitesUrl, { - method, - params, - body: JSON.stringify(body), - headers, - }); + const { token, cookieHeader } = session; - const sitesResponseData = JSON.parse(data); + let sitesUrl; + let body = {}; + let params = { token }; + let headers = { "Csrf-Token": token }; + if (cookieHeader) { + headers.Cookie = cookieHeader; + } + let method = "GET"; - if (status !== 200 || sitesResponseData.errorCode > 0) { - logger.debug(`HTTP ${status} getting sites list: ${sitesResponseData.msg}`); - return res - .status(status) - .json({ error: { message: "Error getting sites list", url, data: sitesResponseData } }); - } + switch (controllerVersionMajor) { + case 3: + sitesUrl = `${url}/web/v1/controller?ajax=&token=${token}`; + body = { + method: "getUserSites", + params: { + userName: widget.username, + }, + }; + headers = { "Content-Type": "application/json" }; + if (cookieHeader) { + headers.Cookie = cookieHeader; + } + method = "POST"; + break; + case 4: + sitesUrl = `${url}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; + break; + case 5: + case 6: + sitesUrl = `${url}/${cId}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; + break; + default: + break; + } - const site = - controllerVersionMajor === 3 - ? sitesResponseData.result.siteList.find((s) => s.name === widget.site) - : sitesResponseData.result.data.find((s) => s.name === widget.site); - - if (!site) { - return res.status(status).json({ error: { message: `Site ${widget.site} is not found`, url: sitesUrl, data } }); - } - - let siteResponseData; - - let connectedAp; - let activeUser; - let connectedSwitches; - let connectedGateways; - let alerts; - - if (controllerVersionMajor === 3) { - // Omada v3 controller requires switching site - const switchUrl = `${url}/web/v1/controller?ajax=&token=${token}`; - method = "POST"; - body = { - method: "switchSite", - params: { - siteName: site.siteName, - userName: widget.username, - }, - }; - headers = { "Content-Type": "application/json" }; - params = { token }; - - [status, contentType, data] = await httpProxy(switchUrl, { - method, - params, - body: JSON.stringify(body), - headers, - }); - - const switchResponseData = JSON.parse(data); - if (status !== 200 || switchResponseData.errorCode > 0) { - logger.error(`HTTP ${status} getting sites list: ${data}`); - return res.status(status).json({ error: { message: "Error switching site", url: switchUrl, data } }); - } - - const statsUrl = `${url}/web/v1/controller?getGlobalStat=&token=${token}`; - [status, contentType, data] = await httpProxy(statsUrl, { - method, - params, - body: JSON.stringify({ - method: "getGlobalStat", - }), - headers, - }); - - siteResponseData = JSON.parse(data); - - if (status !== 200 || siteResponseData.errorCode > 0) { - return res.status(status).json({ error: { message: "Error getting stats", url: statsUrl, data } }); - } - - connectedAp = siteResponseData.result.connectedAp; - activeUser = siteResponseData.result.activeUser; - alerts = siteResponseData.result.alerts; - } else if ([4, 5, 6].includes(controllerVersionMajor)) { - const siteName = controllerVersionMajor > 4 ? site.id : site.key; - const siteStatsUrl = - controllerVersionMajor === 4 - ? `${url}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000` - : `${url}/${cId}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000`; - - [status, contentType, data] = await httpProxy(siteStatsUrl, { - headers: { - "Csrf-Token": token, - }, - }); - - siteResponseData = JSON.parse(data); - - if (status !== 200 || siteResponseData.errorCode > 0) { - logger.debug(`HTTP ${status} getting stats for site ${widget.site} with message ${siteResponseData.msg}`); - return res.status(status === 200 ? 500 : status).json({ - error: { - message: "Error getting stats", - url: siteStatsUrl, - data: siteResponseData, - }, + [status, contentType, data] = await httpProxy(sitesUrl, { + method, + params, + body: JSON.stringify(body), + headers: { ...headers }, }); + + const sitesResponseData = JSON.parse(data); + + if (status !== 200 || sitesResponseData.errorCode > 0) { + logger.debug(`HTTP ${status} getting sites list: ${sitesResponseData.msg}`); + if (shouldRetryWithFreshSession(status, sitesResponseData, attempt, usedCachedSession)) { + cache.del(sessionCacheId); + session = null; + continue; + } + return res + .status(status) + .json({ error: { message: "Error getting sites list", url, data: sitesResponseData } }); + } + + const site = + controllerVersionMajor === 3 + ? sitesResponseData.result.siteList.find((s) => s.name === widget.site) + : sitesResponseData.result.data.find((s) => s.name === widget.site); + + if (!site) { + return res + .status(status) + .json({ error: { message: `Site ${widget.site} is not found`, url: sitesUrl, data } }); + } + + let siteResponseData; + + let connectedAp; + let activeUser; + let connectedSwitches; + let connectedGateways; + let alerts; + + if (controllerVersionMajor === 3) { + // Omada v3 controller requires switching site + const switchUrl = `${url}/web/v1/controller?ajax=&token=${token}`; + method = "POST"; + body = { + method: "switchSite", + params: { + siteName: site.siteName, + userName: widget.username, + }, + }; + headers = { "Content-Type": "application/json" }; + if (cookieHeader) { + headers.Cookie = cookieHeader; + } + params = { token }; + + [status, contentType, data] = await httpProxy(switchUrl, { + method, + params, + body: JSON.stringify(body), + headers: { ...headers }, + }); + + const switchResponseData = JSON.parse(data); + if (status !== 200 || switchResponseData.errorCode > 0) { + logger.error(`HTTP ${status} getting sites list: ${data}`); + if (shouldRetryWithFreshSession(status, switchResponseData, attempt, usedCachedSession)) { + cache.del(sessionCacheId); + session = null; + continue; + } + return res.status(status).json({ error: { message: "Error switching site", url: switchUrl, data } }); + } + + const statsUrl = `${url}/web/v1/controller?getGlobalStat=&token=${token}`; + [status, contentType, data] = await httpProxy(statsUrl, { + method, + params, + body: JSON.stringify({ + method: "getGlobalStat", + }), + headers: { ...headers }, + }); + + siteResponseData = JSON.parse(data); + + if (status !== 200 || siteResponseData.errorCode > 0) { + if (shouldRetryWithFreshSession(status, siteResponseData, attempt, usedCachedSession)) { + cache.del(sessionCacheId); + session = null; + continue; + } + return res.status(status).json({ error: { message: "Error getting stats", url: statsUrl, data } }); + } + + connectedAp = siteResponseData.result.connectedAp; + activeUser = siteResponseData.result.activeUser; + alerts = siteResponseData.result.alerts; + } else if ([4, 5, 6].includes(controllerVersionMajor)) { + const siteName = controllerVersionMajor > 4 ? site.id : site.key; + const siteStatsUrl = + controllerVersionMajor === 4 + ? `${url}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000` + : `${url}/${cId}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000`; + + [status, contentType, data] = await httpProxy(siteStatsUrl, { + headers: { ...headers }, + }); + + siteResponseData = JSON.parse(data); + + if (status !== 200 || siteResponseData.errorCode > 0) { + logger.debug(`HTTP ${status} getting stats for site ${widget.site} with message ${siteResponseData.msg}`); + if (shouldRetryWithFreshSession(status, siteResponseData, attempt, usedCachedSession)) { + cache.del(sessionCacheId); + session = null; + continue; + } + return res.status(status === 200 ? 500 : status).json({ + error: { + message: "Error getting stats", + url: siteStatsUrl, + data: siteResponseData, + }, + }); + } + + const alertUrl = + controllerVersionMajor === 4 + ? `${url}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000` + : `${url}/${cId}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000`; + + [status, contentType, data] = await httpProxy(alertUrl, { + headers: { ...headers }, + }); + const alertResponseData = JSON.parse(data); + + if (status !== 200 || alertResponseData.errorCode > 0) { + if (shouldRetryWithFreshSession(status, alertResponseData, attempt, usedCachedSession)) { + cache.del(sessionCacheId); + session = null; + continue; + } + return res.status(status === 200 ? 500 : status).json({ + error: { + message: "Error getting alerts", + url: alertUrl, + data: alertResponseData, + }, + }); + } + + activeUser = siteResponseData.result.totalClientNum; + connectedAp = siteResponseData.result.connectedApNum; + connectedGateways = siteResponseData.result.connectedGatewayNum; + connectedSwitches = siteResponseData.result.connectedSwitchNum; + alerts = alertResponseData.result.alertNum; + } + + return res.send( + JSON.stringify({ + connectedAp, + activeUser, + alerts, + connectedGateways, + connectedSwitches, + }), + ); + } catch (error) { + if (error instanceof SyntaxError && attempt === 0) { + cache.del(sessionCacheId); + session = null; + continue; + } + + throw error; } - - const alertUrl = - controllerVersionMajor === 4 - ? `${url}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000` - : `${url}/${cId}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000`; - - [status, contentType, data] = await httpProxy(alertUrl, { - headers: { - "Csrf-Token": token, - }, - }); - const alertResponseData = JSON.parse(data); - - activeUser = siteResponseData.result.totalClientNum; - connectedAp = siteResponseData.result.connectedApNum; - connectedGateways = siteResponseData.result.connectedGatewayNum; - connectedSwitches = siteResponseData.result.connectedSwitchNum; - alerts = alertResponseData.result.alertNum; } - - return res.send( - JSON.stringify({ - connectedAp, - activeUser, - alerts, - connectedGateways, - connectedSwitches, - }), - ); } } diff --git a/src/widgets/omada/proxy.test.js b/src/widgets/omada/proxy.test.js index 060ab9a35..ff29f4eb6 100644 --- a/src/widgets/omada/proxy.test.js +++ b/src/widgets/omada/proxy.test.js @@ -2,14 +2,24 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import createMockRes from "test-utils/create-mock-res"; -const { httpProxy, getServiceWidget, logger } = vi.hoisted(() => ({ - httpProxy: vi.fn(), - getServiceWidget: vi.fn(), - logger: { - debug: vi.fn(), - error: vi.fn(), - }, -})); +const { httpProxy, getServiceWidget, cache, logger } = vi.hoisted(() => { + const store = new Map(); + + return { + httpProxy: vi.fn(), + getServiceWidget: vi.fn(), + cache: { + get: vi.fn((k) => store.get(k)), + put: vi.fn((k, v) => store.set(k, v)), + del: vi.fn((k) => store.delete(k)), + _reset: () => store.clear(), + }, + logger: { + debug: vi.fn(), + error: vi.fn(), + }, + }; +}); vi.mock("utils/logger", () => ({ default: () => logger, @@ -20,15 +30,19 @@ vi.mock("utils/config/service-helpers", () => ({ vi.mock("utils/proxy/http", () => ({ httpProxy, })); +vi.mock("memory-cache", () => ({ + default: cache, + ...cache, +})); import omadaProxyHandler from "./proxy"; describe("widgets/omada/proxy", () => { beforeEach(() => { vi.clearAllMocks(); - // Clear one-off implementations between tests (some branches return early). httpProxy.mockReset(); getServiceWidget.mockReset(); + cache._reset(); }); it("fetches controller info, logs in, selects site, and returns overview stats (v4)", async () => { @@ -51,6 +65,7 @@ describe("widgets/omada/proxy", () => { 200, "application/json", Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, ]) // sites list .mockResolvedValueOnce([ @@ -91,6 +106,12 @@ describe("widgets/omada/proxy", () => { connectedSwitches: 3, }), ); + expect(httpProxy.mock.calls[2][1]).toMatchObject({ + headers: { + "Csrf-Token": "t", + Cookie: "TPOMADA_SESSIONID=sid", + }, + }); }); it("returns an error when controller info cannot be retrieved", async () => { @@ -169,6 +190,7 @@ describe("widgets/omada/proxy", () => { 200, "application/json", Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, ]) .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 2, msg: "bad" })]); @@ -195,6 +217,7 @@ describe("widgets/omada/proxy", () => { 200, "application/json", Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, ]) .mockResolvedValueOnce([ 200, @@ -222,6 +245,7 @@ describe("widgets/omada/proxy", () => { 200, "application/json", Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, ]) // getUserSites .mockResolvedValueOnce([ @@ -271,6 +295,7 @@ describe("widgets/omada/proxy", () => { 200, "application/json", Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, ]) .mockResolvedValueOnce([ 200, @@ -301,6 +326,7 @@ describe("widgets/omada/proxy", () => { 200, "application/json", Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, ]) .mockResolvedValueOnce([ 200, @@ -324,4 +350,414 @@ describe("widgets/omada/proxy", () => { }, }); }); + + it("reuses a cached Omada session across polls", async () => { + getServiceWidget.mockResolvedValue({ + url: "http://omada", + username: "u", + password: "p", + site: "Default", + }); + + httpProxy + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]); + + const req = { query: { group: "g", service: "svc", index: "0" } }; + + await omadaProxyHandler(req, createMockRes()); + await omadaProxyHandler(req, createMockRes()); + + const loginCalls = httpProxy.mock.calls.filter(([url]) => url.toString().includes("/api/v2/login")); + expect(loginCalls).toHaveLength(1); + expect(httpProxy.mock.calls[6][1].headers.Cookie).toBe("TPOMADA_SESSIONID=sid"); + }); + + it("does not reuse a cached session across different widget identities", async () => { + getServiceWidget.mockResolvedValue({ + url: "http://omada", + username: "u", + password: "p", + site: "Default", + }); + + httpProxy + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t1" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid1; Path=/; HttpOnly"] }, + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t2" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid2; Path=/; HttpOnly"] }, + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]); + + await omadaProxyHandler({ query: { group: "g1", service: "svc", index: "0" } }, createMockRes()); + await omadaProxyHandler({ query: { group: "g2", service: "svc", index: "0" } }, createMockRes()); + + const loginCalls = httpProxy.mock.calls.filter(([url]) => url.toString().includes("/api/v2/login")); + expect(loginCalls).toHaveLength(2); + expect(httpProxy.mock.calls[2][1].headers.Cookie).toBe("TPOMADA_SESSIONID=sid1"); + expect(httpProxy.mock.calls[7][1].headers.Cookie).toBe("TPOMADA_SESSIONID=sid2"); + }); + + it("keeps the latest value when Omada sets the same cookie more than once during login", async () => { + getServiceWidget.mockResolvedValue({ + url: "http://omada", + username: "u", + password: "p", + site: "Default", + }); + + httpProxy + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { + "set-cookie": [ + "TPOMADA_SESSIONID=deleteMe; Path=/; Max-Age=0", + "TPOMADA_SESSIONID=sid; Path=/; HttpOnly", + "rememberMe=deleteMe; Path=/; Max-Age=0", + ], + }, + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]); + + const req = { query: { group: "g", service: "svc", index: "0" } }; + const res = createMockRes(); + + await omadaProxyHandler(req, res); + + expect(httpProxy.mock.calls[2][1].headers.Cookie).toBe("TPOMADA_SESSIONID=sid; rememberMe=deleteMe"); + expect(res.body).toBe( + JSON.stringify({ + connectedAp: 2, + activeUser: 10, + alerts: 4, + connectedGateways: 1, + connectedSwitches: 3, + }), + ); + }); + + it("does not reuse a mutated content-length header on later GET requests", async () => { + getServiceWidget.mockResolvedValue({ + url: "http://omada", + username: "u", + password: "p", + site: "Default", + }); + + const responses = [ + [200, "application/json", JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } })], + [ + 200, + "application/json", + Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })), + { "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] }, + ], + [ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ], + [ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ], + [200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })], + ]; + + httpProxy.mockImplementation(async (_url, params = {}) => { + if (params.body) { + params.headers["content-length"] = Buffer.byteLength(params.body); + } + + return responses.shift(); + }); + + const req = { query: { group: "g", service: "svc", index: "0" } }; + const res = createMockRes(); + + await omadaProxyHandler(req, res); + + expect(httpProxy.mock.calls[2][1].headers["content-length"]).toBe(2); + expect(httpProxy.mock.calls[3][1].headers["content-length"]).toBeUndefined(); + expect(httpProxy.mock.calls[4][1].headers["content-length"]).toBeUndefined(); + expect(res.body).toBe( + JSON.stringify({ + connectedAp: 2, + activeUser: 10, + alerts: 4, + connectedGateways: 1, + connectedSwitches: 3, + }), + ); + }); + + it("clears the cached session and re-authenticates when an authenticated response is not JSON", async () => { + cache.put("omadaProxyHandler__session.g.svc.0", { + token: "stale-token", + cookieHeader: "TPOMADA_SESSIONID=stale", + }); + + getServiceWidget.mockResolvedValue({ + url: "http://omada", + username: "u", + password: "p", + site: "Default", + }); + + httpProxy + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }), + ]) + .mockResolvedValueOnce([200, "text/html", Buffer.from("login")]) + .mockResolvedValueOnce([ + 200, + "application/json", + Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "fresh-token" } })), + { "set-cookie": ["TPOMADA_SESSIONID=fresh; Path=/; HttpOnly"] }, + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]); + + const req = { query: { group: "g", service: "svc", index: "0" } }; + const res = createMockRes(); + + await omadaProxyHandler(req, res); + + expect(cache.del).toHaveBeenCalledWith("omadaProxyHandler__session.g.svc.0"); + const loginCalls = httpProxy.mock.calls.filter(([url]) => url.toString().includes("/api/v2/login")); + expect(loginCalls).toHaveLength(1); + expect(res.body).toBe( + JSON.stringify({ + connectedAp: 2, + activeUser: 10, + alerts: 4, + connectedGateways: 1, + connectedSwitches: 3, + }), + ); + }); + + it("clears the cached session and re-authenticates when a cached session returns a JSON auth error", async () => { + cache.put("omadaProxyHandler__session.g.svc.0", { + token: "stale-token", + cookieHeader: "TPOMADA_SESSIONID=stale", + }); + + getServiceWidget.mockResolvedValue({ + url: "http://omada", + username: "u", + password: "p", + site: "Default", + }); + + httpProxy + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 1, msg: "Login required" })]) + .mockResolvedValueOnce([ + 200, + "application/json", + Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "fresh-token" } })), + { "set-cookie": ["TPOMADA_SESSIONID=fresh; Path=/; HttpOnly"] }, + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }), + ]) + .mockResolvedValueOnce([ + 200, + "application/json", + JSON.stringify({ + errorCode: 0, + result: { + totalClientNum: 10, + connectedApNum: 2, + connectedGatewayNum: 1, + connectedSwitchNum: 3, + }, + }), + ]) + .mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]); + + const req = { query: { group: "g", service: "svc", index: "0" } }; + const res = createMockRes(); + + await omadaProxyHandler(req, res); + + expect(cache.del).toHaveBeenCalledWith("omadaProxyHandler__session.g.svc.0"); + const loginCalls = httpProxy.mock.calls.filter(([url]) => url.toString().includes("/api/v2/login")); + expect(loginCalls).toHaveLength(1); + expect(res.body).toBe( + JSON.stringify({ + connectedAp: 2, + activeUser: 10, + alerts: 4, + connectedGateways: 1, + connectedSwitches: 3, + }), + ); + }); }); From a7bab17f9726a66bcbba556b2912aa0c37708e4a Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 12 Apr 2026 11:00:54 -0700 Subject: [PATCH 22/56] Enhancement: support pyload API key, fix error message (#6558) --- docs/widgets/services/pyload.md | 1 + src/widgets/pyload/proxy.js | 25 +++++++++++++------- src/widgets/pyload/proxy.test.js | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/docs/widgets/services/pyload.md b/docs/widgets/services/pyload.md index 3a37d083a..1e03c3299 100644 --- a/docs/widgets/services/pyload.md +++ b/docs/widgets/services/pyload.md @@ -13,4 +13,5 @@ widget: url: http://pyload.host.or.ip:port username: username password: password # only needed if set + key: pyloadapikey # only needed if set, takes precedence over username/password ``` diff --git a/src/widgets/pyload/proxy.js b/src/widgets/pyload/proxy.js index 57bd68fd7..9dc071ad2 100644 --- a/src/widgets/pyload/proxy.js +++ b/src/widgets/pyload/proxy.js @@ -45,17 +45,20 @@ async function fetchFromPyloadAPI(url, sessionId, params, service) { return [status, returnData, responseHeaders]; } -async function fetchFromPyloadAPIBasic(url, params, username, password) { +async function fetchFromPyloadAPIWithCredentials(url, params, username, password, key) { const parsedUrl = new URL(url); const isGetRequest = !params || Object.keys(params).length === 0; const options = { method: isGetRequest ? "GET" : "POST", - headers: { - Authorization: `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`, - }, }; + if (key) { + options.headers = { "X-API-Key": key }; + } else { + options.headers = { Authorization: `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}` }; + } + if (isGetRequest) { if (params) { Object.keys(params).forEach((key) => parsedUrl.searchParams.append(key, params[key])); @@ -106,10 +109,16 @@ export default async function pyloadProxyHandler(req, res, map = {}) { const url = new URL(formatApiCall(apiTemplate, { endpoint, ...widget })); const ngUrl = ngEndpoint ? new URL(formatApiCall(apiTemplate, { endpoint: ngEndpoint, ...widget })) : url; const loginUrl = `${widget.url}/api/login`; - const hasCredentials = widget.username && widget.password; + const hasCredentials = widget.key || (widget.username && widget.password); if (hasCredentials) { - const [status, data] = await fetchFromPyloadAPIBasic(ngUrl, null, widget.username, widget.password); + const [status, data] = await fetchFromPyloadAPIWithCredentials( + ngUrl, + null, + widget.username, + widget.password, + widget.key, + ); if (status === 200 && !data?.error) { cache.put(`${isNgCacheKey}.${service}`, true); @@ -117,9 +126,7 @@ export default async function pyloadProxyHandler(req, res, map = {}) { } if (status === 401) { - return res - .status(status) - .send({ error: { message: "Invalid credentials communicating with Pyload API", data } }); + return res.status(status).send({ error: "Invalid credentials communicating with Pyload API", data }); } } diff --git a/src/widgets/pyload/proxy.test.js b/src/widgets/pyload/proxy.test.js index d9d558fb7..0a4ad1599 100644 --- a/src/widgets/pyload/proxy.test.js +++ b/src/widgets/pyload/proxy.test.js @@ -75,6 +75,46 @@ describe("widgets/pyload/proxy", () => { expect(res.body).toEqual({ ok: true }); }); + it("uses api key auth and returns data", async () => { + getServiceWidget.mockResolvedValue({ + type: "pyload", + url: "http://pyload", + key: "apikey", + }); + + httpProxy.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ ok: true })), {}]); + + const req = { query: { group: "g", service: "svc", endpoint: "status", index: "0" } }; + const res = createMockRes(); + + await pyloadProxyHandler(req, res); + + expect(httpProxy).toHaveBeenCalledTimes(1); + expect(httpProxy.mock.calls[0][1].headers["X-API-Key"]).toBe("apikey"); + expect(cache.put).toHaveBeenCalledWith("pyloadProxyHandler__isNg.svc", true); + expect(res.body).toEqual({ ok: true }); + }); + + it("returns error if login fails", async () => { + getServiceWidget.mockResolvedValue({ + type: "pyload", + url: "http://pyload", + username: "u", + password: "p", + }); + + httpProxy.mockResolvedValueOnce([401, "application/json", Buffer.from(JSON.stringify({ error: "bad" })), {}]); + + const req = { query: { group: "g", service: "svc", endpoint: "status", index: "0" } }; + const res = createMockRes(); + + await pyloadProxyHandler(req, res); + + expect(httpProxy).toHaveBeenCalledTimes(1); + expect(res.statusCode).toBe(401); + expect(res.body).toMatchObject({ error: "Invalid credentials communicating with Pyload API" }); + }); + it("retries after 403 by clearing session and logging in again", async () => { getServiceWidget.mockResolvedValue({ type: "pyload", From 463e94d933b4c6097251ab2a3209e2746aa02c2d Mon Sep 17 00:00:00 2001 From: Steven Harris Date: Wed, 15 Apr 2026 11:10:45 -0400 Subject: [PATCH 23/56] Fix: use v2 storage API for UniFi Drive widget (#6567) --- src/widgets/unifi_drive/component.jsx | 13 ++-- src/widgets/unifi_drive/component.test.jsx | 86 ++++++++++++++++++---- src/widgets/unifi_drive/widget.js | 2 +- 3 files changed, 79 insertions(+), 22 deletions(-) diff --git a/src/widgets/unifi_drive/component.jsx b/src/widgets/unifi_drive/component.jsx index a616dbd20..aaa844db2 100644 --- a/src/widgets/unifi_drive/component.jsx +++ b/src/widgets/unifi_drive/component.jsx @@ -25,9 +25,9 @@ export default function Component({ service }) { ); } - const { data: storage } = storageData; + const { pools } = storageData; - if (!storage) { + if (!Array.isArray(pools) || pools.length === 0) { return ( @@ -35,12 +35,13 @@ export default function Component({ service }) { ); } - const { totalQuota, usage, status } = storage; - const totalBytes = totalQuota ?? 0; - const usedBytes = (usage?.system || 0) + (usage?.myDrives || 0) + (usage?.sharedDrives || 0); + const totalBytes = pools.reduce((sum, p) => sum + (p.capacity ?? 0), 0); + const usedBytes = pools.reduce((sum, p) => sum + (p.usage ?? 0), 0); const availableBytes = Math.max(0, totalBytes - usedBytes); + + const status = pools.some((p) => p.status === "degraded") ? "degraded" : pools[0]?.status; let statusValue = status; - if (status === "healthy") statusValue = t("unifi_drive.healthy"); + if (status === "fullyOperational" || status === "noDataProtectionYet") statusValue = t("unifi_drive.healthy"); else if (status === "degraded") statusValue = t("unifi_drive.degraded"); return ( diff --git a/src/widgets/unifi_drive/component.test.jsx b/src/widgets/unifi_drive/component.test.jsx index 46f23ce1e..36137e515 100644 --- a/src/widgets/unifi_drive/component.test.jsx +++ b/src/widgets/unifi_drive/component.test.jsx @@ -39,8 +39,8 @@ describe("widgets/unifi_drive/component", () => { expect(screen.getAllByText("widget.api_error", { exact: false }).length).toBeGreaterThan(0); }); - it("renders no_data when storage data is missing", () => { - useWidgetAPI.mockReturnValue({ data: { data: null }, error: undefined }); + it("renders no_data when pools array is empty", () => { + useWidgetAPI.mockReturnValue({ data: { pools: [] }, error: undefined }); const service = { widget: { type: "unifi_drive" } }; renderWithProviders(, { settings: { hideErrors: false } }); @@ -48,14 +48,19 @@ describe("widgets/unifi_drive/component", () => { expect(screen.getByText("unifi_drive.no_data")).toBeInTheDocument(); }); - it("renders storage statistics when data is loaded", () => { + it("renders no_data when pools is missing", () => { + useWidgetAPI.mockReturnValue({ data: {}, error: undefined }); + + const service = { widget: { type: "unifi_drive" } }; + renderWithProviders(, { settings: { hideErrors: false } }); + + expect(screen.getByText("unifi_drive.no_data")).toBeInTheDocument(); + }); + + it("renders storage statistics from single pool", () => { useWidgetAPI.mockReturnValue({ data: { - data: { - totalQuota: 1000000000000, - usage: { system: 100000000000, myDrives: 200000000000, sharedDrives: 50000000000 }, - status: "healthy", - }, + pools: [{ capacity: 1000000000000, usage: 350000000000, status: "fullyOperational" }], }, error: undefined, }); @@ -70,14 +75,34 @@ describe("widgets/unifi_drive/component", () => { expectBlockValue(container, "widget.status", "unifi_drive.healthy"); }); - it("renders degraded status", () => { + it("aggregates storage across multiple pools", () => { useWidgetAPI.mockReturnValue({ data: { - data: { - totalQuota: 100, - usage: { system: 10, myDrives: 20, sharedDrives: 5 }, - status: "degraded", - }, + pools: [ + { capacity: 1000000000000, usage: 300000000000, status: "fullyOperational" }, + { capacity: 500000000000, usage: 100000000000, status: "noDataProtectionYet" }, + ], + }, + error: undefined, + }); + + const service = { widget: { type: "unifi_drive" } }; + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expectBlockValue(container, "resources.total", 1500000000000); + expectBlockValue(container, "resources.used", 400000000000); + expectBlockValue(container, "resources.free", 1100000000000); + expectBlockValue(container, "widget.status", "unifi_drive.healthy"); + }); + + it("renders degraded status when any pool is degraded", () => { + useWidgetAPI.mockReturnValue({ + data: { + pools: [ + { capacity: 1000, usage: 400, status: "fullyOperational" }, + { capacity: 500, usage: 100, status: "degraded" }, + ], }, error: undefined, }); @@ -87,6 +112,37 @@ describe("widgets/unifi_drive/component", () => { expect(container.querySelectorAll(".service-block")).toHaveLength(4); expectBlockValue(container, "widget.status", "unifi_drive.degraded"); - expectBlockValue(container, "resources.free", 65); + expectBlockValue(container, "resources.free", 1000); + }); + + it("renders noDataProtectionYet as healthy", () => { + useWidgetAPI.mockReturnValue({ + data: { + pools: [{ capacity: 1000, usage: 200, status: "noDataProtectionYet" }], + }, + error: undefined, + }); + + const service = { widget: { type: "unifi_drive" } }; + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expectBlockValue(container, "widget.status", "unifi_drive.healthy"); + }); + + it("handles pools with missing capacity or usage", () => { + useWidgetAPI.mockReturnValue({ + data: { + pools: [{ status: "fullyOperational" }], + }, + error: undefined, + }); + + const service = { widget: { type: "unifi_drive" } }; + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expectBlockValue(container, "resources.total", 0); + expectBlockValue(container, "resources.used", 0); + expectBlockValue(container, "resources.free", 0); }); }); diff --git a/src/widgets/unifi_drive/widget.js b/src/widgets/unifi_drive/widget.js index 4e78c5a5f..f876ba899 100644 --- a/src/widgets/unifi_drive/widget.js +++ b/src/widgets/unifi_drive/widget.js @@ -6,7 +6,7 @@ const widget = { mappings: { storage: { - endpoint: "v1/systems/storage?type=detail", + endpoint: "v2/storage", }, }, }; From 92ec6ccefcc8ef0f8f5897b467d14d42f3e62cf2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Apr 2026 12:56:56 -0700 Subject: [PATCH 24/56] Chore(deps): Bump follow-redirects from 1.15.11 to 1.16.0 in the npm_and_yarn group across 1 directory (#6568) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 5d5bdf606..01f728f17 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "classnames": "^2.5.1", "compare-versions": "^6.1.1", "dockerode": "^4.0.10", - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "gamedig": "^5.3.2", "i18next": "^25.10.9", "ical.js": "^2.2.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58c85862c..d1985167a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^4.0.10 version: 4.0.10 follow-redirects: - specifier: ^1.15.11 - version: 1.15.11 + specifier: ^1.16.0 + version: 1.16.0 gamedig: specifier: ^5.3.2 version: 5.3.2 @@ -2217,8 +2217,8 @@ packages: fn.name@1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -5978,7 +5978,7 @@ snapshots: fn.name@1.1.0: {} - follow-redirects@1.15.11: {} + follow-redirects@1.16.0: {} for-each@0.3.5: dependencies: From 03dd54ee2eac76bf9ade24eb5ff4f348de06f408 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 10:25:03 -0700 Subject: [PATCH 25/56] Chore(deps): Bump docker/build-push-action from 7.0.0 to 7.1.0 (#6573) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 64bd01b81..5314dc3b6 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -105,7 +105,7 @@ jobs: - name: Build and push Docker image id: build-and-push - uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7 + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7 with: context: . push: ${{ github.event_name != 'pull_request' }} From b8672ddc9b601d6595333eeb69cb1066757d514e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:29:04 +0000 Subject: [PATCH 26/56] Chore(deps): Bump release-drafter/release-drafter from 7.1.1 to 7.2.0 (#6570) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-drafter.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index c5c262769..083c04af4 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -26,14 +26,14 @@ jobs: runs-on: ubuntu-latest steps: - if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' - uses: release-drafter/release-drafter@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7 + uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7 with: config-name: release-drafter.yml version: ${{ github.event.inputs.version }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == '' - uses: release-drafter/release-drafter@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7 + uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7 with: config-name: release-drafter.yml env: @@ -47,7 +47,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter/autolabeler@139054aeaa9adc52ab36ddf67437541f039b88e2 + - uses: release-drafter/release-drafter/autolabeler@5de93583980a40bd78603b6dfdcda5b4df377b32 with: config-name: release-drafter.yml env: From b2b299d63472e0004c2842c1d695ebae22e315de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:33:19 +0000 Subject: [PATCH 27/56] Chore(deps): Bump actions/upload-pages-artifact from 4.0.0 to 5.0.0 (#6571) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index ad0e960a1..11f74ba47 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -47,7 +47,7 @@ jobs: - run: sudo apt-get install pngquant - name: Build Docs run: uv run --frozen zensical build --clean - - uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 + - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: site - uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 From 0c8fd6904e13b151dc91dcbeea62bf1c41486bef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 23:27:05 -0700 Subject: [PATCH 28/56] Chore(deps): Bump protobufjs from 7.5.4 to 7.5.5 in the npm_and_yarn group across 1 directory (#6575) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d1985167a..0fda9c842 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3094,8 +3094,8 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - protobufjs@7.5.4: - resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + protobufjs@7.5.5: + resolution: {integrity: sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==} engines: {node: '>=12.0.0'} pump@3.0.4: @@ -4177,14 +4177,14 @@ snapshots: dependencies: lodash.camelcase: 4.3.0 long: 5.3.2 - protobufjs: 7.5.4 + protobufjs: 7.5.5 yargs: 17.7.2 '@grpc/proto-loader@0.8.0': dependencies: lodash.camelcase: 4.3.0 long: 5.3.2 - protobufjs: 7.5.4 + protobufjs: 7.5.5 yargs: 17.7.2 '@headlessui/react@2.2.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -5461,7 +5461,7 @@ snapshots: '@grpc/grpc-js': 1.14.3 '@grpc/proto-loader': 0.7.15 docker-modem: 5.0.7 - protobufjs: 7.5.4 + protobufjs: 7.5.5 tar-fs: 2.1.4 uuid: 10.0.0 transitivePeerDependencies: @@ -6849,7 +6849,7 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - protobufjs@7.5.4: + protobufjs@7.5.5: dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 From a0f9fbf614c50dbd3b14f60acd2fdf3e01b7b6ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 06:31:18 +0000 Subject: [PATCH 29/56] Chore(deps): Bump actions/github-script from 8.0.0 to 9.0.0 (#6572) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/repo-maintenance.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/repo-maintenance.yml index 8b4435034..f473f05db 100644 --- a/.github/workflows/repo-maintenance.yml +++ b/.github/workflows/repo-maintenance.yml @@ -57,7 +57,7 @@ jobs: name: 'Close Answered Discussions' runs-on: ubuntu-latest steps: - - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | function sleep(ms) { @@ -113,7 +113,7 @@ jobs: name: 'Close Outdated Discussions' runs-on: ubuntu-latest steps: - - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | function sleep(ms) { @@ -204,7 +204,7 @@ jobs: name: 'Close Unsupported Feature Requests' runs-on: ubuntu-latest steps: - - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | function sleep(ms) { From 10ade1d32f14e1e0ea0b9e35e9eb471315709313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Astori?= Date: Sat, 18 Apr 2026 02:18:46 -0400 Subject: [PATCH 30/56] Fix: Swap `cputemp` and `disk` resources in glances loading state skeleton (#6577) --- src/components/widgets/glances/glances.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/widgets/glances/glances.jsx b/src/components/widgets/glances/glances.jsx index 7b1e27a57..567a73de1 100644 --- a/src/components/widgets/glances/glances.jsx +++ b/src/components/widgets/glances/glances.jsx @@ -38,7 +38,6 @@ export default function Widget({ options }) { {options.cpu !== false && } {options.mem !== false && } - {options.cputemp && } {options.disk && !Array.isArray(options.disk) && ( )} @@ -47,6 +46,7 @@ export default function Widget({ options }) { options.disk.map((disk) => ( ))} + {options.cputemp && } {options.uptime && } {options.label && } From 8322dd9016598cb89b57edbf39e4ac4b998a7e39 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 19 Apr 2026 07:53:25 -0700 Subject: [PATCH 31/56] Fix: use seconds for PBS since (#6583) --- src/widgets/proxmoxbackupserver/component.jsx | 7 ++++++- .../proxmoxbackupserver/component.test.jsx | 19 +++++++++++++++++++ src/widgets/proxmoxbackupserver/widget.js | 4 +--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/widgets/proxmoxbackupserver/component.jsx b/src/widgets/proxmoxbackupserver/component.jsx index 0af1134be..8e31ad100 100644 --- a/src/widgets/proxmoxbackupserver/component.jsx +++ b/src/widgets/proxmoxbackupserver/component.jsx @@ -8,9 +8,14 @@ export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; + const taskQueryParams = { + errors: true, + limit: 100, + since: Math.floor(Date.now() / 1000) - 24 * 60 * 60, + }; const { data: datastoreData, error: datastoreError } = useWidgetAPI(widget, "status/datastore-usage"); - const { data: tasksData, error: tasksError } = useWidgetAPI(widget, "nodes/localhost/tasks"); + const { data: tasksData, error: tasksError } = useWidgetAPI(widget, "nodes/localhost/tasks", taskQueryParams); const { data: hostData, error: hostError } = useWidgetAPI(widget, "nodes/localhost/status"); if (datastoreError || tasksError || hostError) { diff --git a/src/widgets/proxmoxbackupserver/component.test.jsx b/src/widgets/proxmoxbackupserver/component.test.jsx index c4a2ddd0a..3129ae996 100644 --- a/src/widgets/proxmoxbackupserver/component.test.jsx +++ b/src/widgets/proxmoxbackupserver/component.test.jsx @@ -74,4 +74,23 @@ describe("widgets/proxmoxbackupserver/component", () => { expect(screen.getByText("25")).toBeInTheDocument(); // memory usage expect(screen.getByText("99+")).toBeInTheDocument(); }); + + it("requests failed tasks with a 24 hour since filter in epoch seconds", () => { + vi.spyOn(Date, "now").mockReturnValue(1_776_519_498_000); + + useWidgetAPI + .mockReturnValueOnce({ data: undefined, error: undefined }) + .mockReturnValueOnce({ data: undefined, error: undefined }) + .mockReturnValueOnce({ data: undefined, error: undefined }); + + renderWithProviders(, { + settings: { hideErrors: false }, + }); + + expect(useWidgetAPI).toHaveBeenNthCalledWith(2, { type: "proxmoxbackupserver" }, "nodes/localhost/tasks", { + errors: true, + limit: 100, + since: 1_776_433_098, + }); + }); }); diff --git a/src/widgets/proxmoxbackupserver/widget.js b/src/widgets/proxmoxbackupserver/widget.js index 65298a17c..719849185 100644 --- a/src/widgets/proxmoxbackupserver/widget.js +++ b/src/widgets/proxmoxbackupserver/widget.js @@ -1,7 +1,5 @@ import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; -const since = Date.now() - 24 * 60 * 60 * 1000; - const widget = { api: "{url}/api2/json/{endpoint}", proxyHandler: credentialedProxyHandler, @@ -11,7 +9,7 @@ const widget = { endpoint: "status/datastore-usage", }, "nodes/localhost/tasks": { - endpoint: `nodes/localhost/tasks?errors=true&limit=100&since=${since}`, + endpoint: "nodes/localhost/tasks", }, "nodes/localhost/status": { endpoint: "nodes/localhost/status", From bf55e8acabbe9f57f451ef09298c422738fa8bc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 11:17:35 -0700 Subject: [PATCH 32/56] Chore(deps): Bump i18next-fs-backend from 2.6.1 to 2.6.4 in the npm_and_yarn group across 1 directory (#6588) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0fda9c842..8709aaa03 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2390,8 +2390,8 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - i18next-fs-backend@2.6.1: - resolution: {integrity: sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ==} + i18next-fs-backend@2.6.4: + resolution: {integrity: sha512-lzbUnowXYd5RFO8flpQhd9khYWNgrzwtxHw1kktJCiTRBaAEiLB2t9EPSXRj8qlC7WcEgFDIsmBUixyludcznw==} i18next@25.10.9: resolution: {integrity: sha512-hQY9/bFoQKGlSKMlaCuLR8w1h5JjieqrsnZvEmj1Ja6Ec7fbyc4cTrCsY9mb9Sd8YQ/swsrKz1S9M8AcvVI70w==} @@ -6192,7 +6192,7 @@ snapshots: transitivePeerDependencies: - supports-color - i18next-fs-backend@2.6.1: {} + i18next-fs-backend@2.6.4: {} i18next@25.10.9(typescript@5.7.3): dependencies: @@ -6646,7 +6646,7 @@ snapshots: core-js: 3.48.0 hoist-non-react-statics: 3.3.2 i18next: 25.10.9(typescript@5.7.3) - i18next-fs-backend: 2.6.1 + i18next-fs-backend: 2.6.4 next: 16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-i18next: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) From d721bb661fe6ff7da640a7efa5ac5adbd03d8f0e Mon Sep 17 00:00:00 2001 From: finlay-mcaree <13505775+finlay-mcaree@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:01:31 -0700 Subject: [PATCH 33/56] Enhancement: add additional fields to Tailscale Widget (#6589) --- docs/widgets/services/tailscale.md | 2 +- public/locales/en/common.json | 14 ++- src/widgets/tailscale/component.jsx | 44 +++++++- src/widgets/tailscale/component.test.jsx | 138 +++++++++++++++++++++-- 4 files changed, 182 insertions(+), 16 deletions(-) diff --git a/docs/widgets/services/tailscale.md b/docs/widgets/services/tailscale.md index e4f3ec2eb..f33482282 100644 --- a/docs/widgets/services/tailscale.md +++ b/docs/widgets/services/tailscale.md @@ -9,7 +9,7 @@ You will need to generate an API access token from the [keys page](https://login To find your device ID, go to the [machine overview page](https://login.tailscale.com/admin/machines) and select your machine. In the "Machine Details" section, copy your `ID`. It will end with `CNTRL`. -Allowed fields: `["address", "last_seen", "expires"]`. +Allowed fields: `[ "address", "last_seen", "expires", "user", "hostname", "name", "client_version", "os", "created", "authorized", "is_external", "update_available", "tags" ]`. ```yaml widget: diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 9528341b8..6d2204774 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -344,6 +344,16 @@ "address": "Address", "expires": "Expires", "never": "Never", + "user": "User", + "hostname": "Hostname", + "name": "Name", + "client_version": "Client Version", + "os": "OS", + "created": "Created", + "authorized": "Authorized", + "is_external": "Is External", + "update_available": "Update Available", + "tags": "Tags", "last_seen": "Last Seen", "now": "Now", "years": "{{number}}y", @@ -352,7 +362,9 @@ "hours": "{{number}}h", "minutes": "{{number}}m", "seconds": "{{number}}s", - "ago": "{{value}} Ago" + "ago": "{{value}} Ago", + "true": "Yes", + "false": "No" }, "technitium": { "totalQueries": "Queries", diff --git a/src/widgets/tailscale/component.jsx b/src/widgets/tailscale/component.jsx index b95cb016b..f303fd4c9 100644 --- a/src/widgets/tailscale/component.jsx +++ b/src/widgets/tailscale/component.jsx @@ -9,13 +9,13 @@ export default function Component({ service }) { const { widget } = service; - const { data: statsData, error: statsError } = useWidgetAPI(widget, "device"); + const { data: tailscaleData, error: tailscaleError } = useWidgetAPI(widget, "device"); - if (statsError || statsData?.message) { - return ; + if (tailscaleError || tailscaleData?.message) { + return ; } - if (!statsData) { + if (!tailscaleData) { return ( @@ -25,12 +25,29 @@ export default function Component({ service }) { ); } + const MAX_ALLOWED_FIELDS = 4; + if (widget.fields?.length == 0 || !widget.fields) { + widget.fields = ["address", "last_seen", "expires"]; + } else if (widget.fields?.length > MAX_ALLOWED_FIELDS) { + widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS); + } + const { addresses: [address], keyExpiryDisabled, lastSeen, expires, - } = statsData; + user, + hostname, + name, + clientVersion, + os, + created, + authorized, + isExternal, + updateAvailable, + tags, + } = tailscaleData; const now = new Date(); const compareDifferenceInTwoDates = (priorDate, futureDate) => { @@ -62,11 +79,28 @@ export default function Component({ service }) { return compareDifferenceInTwoDates(now, date); }; + const getBooleanAsString = (value) => { + return value ? t("tailscale.true") : t("tailscale.false"); + }; + + const clientVersionString = clientVersion ? clientVersion.toString() : "-"; + const tagsString = tags && Array.isArray(tags) ? tags.join(", ") : "-"; + return ( + + + + + + + + + + ); } diff --git a/src/widgets/tailscale/component.test.jsx b/src/widgets/tailscale/component.test.jsx index 602d6ba1c..13d6851d4 100644 --- a/src/widgets/tailscale/component.test.jsx +++ b/src/widgets/tailscale/component.test.jsx @@ -22,6 +22,23 @@ describe("widgets/tailscale/component", () => { vi.useRealTimers(); }); + const fullData = { + addresses: ["127.0.0.1"], + keyExpiryDisabled: false, + expires: "2020-06-01T00:00:00Z", + lastSeen: "2019-12-31T23:55:00Z", + user: "fin@example.com", + hostname: "localhost", + name: "localhost.tail1234.ts.net", + clientVersion: "1.1.0", + os: "linux", + created: "2019-06-01T00:00:00Z", + authorized: true, + isExternal: false, + updateAvailable: true, + tags: ["server", "prod"], + }; + it("renders placeholders while loading", () => { useWidgetAPI.mockReturnValue({ data: undefined, error: undefined }); @@ -35,14 +52,108 @@ describe("widgets/tailscale/component", () => { expect(screen.getByText("tailscale.expires")).toBeInTheDocument(); }); - it("renders address and expiry/last-seen strings when loaded", () => { + describe("fields group: address, last_seen, expires, user", () => { + it("renders only the specified 4 fields", () => { + useWidgetAPI.mockReturnValue({ data: fullData, error: undefined }); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expectBlockValue(container, "tailscale.address", "127.0.0.1"); + expectBlockValue(container, "tailscale.last_seen", "tailscale.ago"); + expectBlockValue(container, "tailscale.expires", "tailscale.weeks"); + expectBlockValue(container, "tailscale.user", "fin@example.com"); + }); + }); + + describe("fields group: hostname, name, client_version, os", () => { + it("renders only the specified 4 fields", () => { + useWidgetAPI.mockReturnValue({ data: fullData, error: undefined }); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expectBlockValue(container, "tailscale.hostname", "localhost"); + expectBlockValue(container, "tailscale.name", "localhost.tail1234.ts.net"); + expectBlockValue(container, "tailscale.client_version", "1.1.0"); + expectBlockValue(container, "tailscale.os", "linux"); + }); + }); + + describe("fields group: created, authorized, is_external, update_available", () => { + it("renders only the specified 4 fields", () => { + useWidgetAPI.mockReturnValue({ data: fullData, error: undefined }); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expectBlockValue(container, "tailscale.created", "2019-06-01T00:00:00Z"); + expectBlockValue(container, "tailscale.authorized", "tailscale.true"); + expectBlockValue(container, "tailscale.is_external", "tailscale.false"); + expectBlockValue(container, "tailscale.update_available", "tailscale.true"); + }); + }); + + describe("fields group: tags with defaults", () => { + it("renders tags alongside default fields", () => { + useWidgetAPI.mockReturnValue({ data: fullData, error: undefined }); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expectBlockValue(container, "tailscale.address", "127.0.0.1"); + expectBlockValue(container, "tailscale.tags", "server, prod"); + }); + }); + + describe("fields truncation", () => { + it("truncates to 4 fields when more than 4 are specified", () => { + useWidgetAPI.mockReturnValue({ data: fullData, error: undefined }); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expect(findServiceBlockByLabel(container, "tailscale.hostname")).toBeFalsy(); + }); + + it("defaults to address, last_seen, expires when fields is empty", () => { + useWidgetAPI.mockReturnValue({ data: fullData, error: undefined }); + + const { container } = renderWithProviders(, { + settings: { hideErrors: false }, + }); + + expect(container.querySelectorAll(".service-block")).toHaveLength(3); + expectBlockValue(container, "tailscale.address", "127.0.0.1"); + expectBlockValue(container, "tailscale.last_seen", "tailscale.ago"); + expectBlockValue(container, "tailscale.expires", "tailscale.weeks"); + }); + }); + + it("renders never for expires if key expiry is disabled", () => { useWidgetAPI.mockReturnValue({ - data: { - addresses: ["100.64.0.1"], - keyExpiryDisabled: true, - lastSeen: "2019-12-31T23:00:00Z", - expires: "2021-01-01T00:00:00Z", - }, + data: { ...fullData, keyExpiryDisabled: true }, error: undefined, }); @@ -50,8 +161,17 @@ describe("widgets/tailscale/component", () => { settings: { hideErrors: false }, }); - expectBlockValue(container, "tailscale.address", "100.64.0.1"); - expect(findServiceBlockByLabel(container, "tailscale.last_seen")?.textContent).toContain("tailscale.ago"); expectBlockValue(container, "tailscale.expires", "tailscale.never"); }); + + it("renders error message when API returns an error", () => { + useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "API error" } }); + + const { container } = renderWithProviders(, { + settings: { hideErrors: false }, + }); + + expect(container.querySelectorAll(".service-block")).toHaveLength(0); + expect(container.textContent).toContain("API error"); + }); }); From f762135eb33533cc707dd2ac50e15bea6c8eeec8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:37:02 +0000 Subject: [PATCH 34/56] Chore(deps): Bump astral-sh/setup-uv from 8.0.0 to 8.1.0 (#6592) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index 11f74ba47..47ae6cbe4 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -25,7 +25,7 @@ jobs: with: python-version-file: ".python-version" - name: Install uv - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 - run: sudo apt-get install pngquant - name: Test Docs Build run: uv run --frozen zensical build --clean @@ -43,7 +43,7 @@ jobs: with: python-version-file: ".python-version" - name: Install uv - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 - run: sudo apt-get install pngquant - name: Build Docs run: uv run --frozen zensical build --clean From 96f4777637416c4031400eb19ff122e1e129768d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:41:27 +0000 Subject: [PATCH 35/56] Chore(deps): Bump peakoss/anti-slop from 0.2.1 to 0.3.0 (#6590) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pr-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-quality.yml b/.github/workflows/pr-quality.yml index b0a7e9de5..29eea358a 100644 --- a/.github/workflows/pr-quality.yml +++ b/.github/workflows/pr-quality.yml @@ -13,6 +13,6 @@ jobs: anti-slop: runs-on: ubuntu-latest steps: - - uses: peakoss/anti-slop@85daca1880e9e1af197fc06ea03349daf08f4202 # v0 + - uses: peakoss/anti-slop@57858eead489d08b255fab2af45a506c2ca6eab2 # v0 with: max-failures: 4 From 7ed1260f0deef9220235dd4707e6ce95e129fdaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:39:26 +0000 Subject: [PATCH 36/56] Chore(deps): Bump actions/cache from 5.0.4 to 5.0.5 (#6593) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 5314dc3b6..9861a993d 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -53,7 +53,7 @@ jobs: latest=auto - name: Next.js build cache - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: .next/cache key: nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx') }} From 44c1e8393e0fa2672caec48a86f1e24fafe29d9e Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 24 Apr 2026 10:20:15 -0700 Subject: [PATCH 37/56] Enhancement: support custom labels for cpu temp sensors (#6595) --- docs/widgets/info/glances.md | 3 +++ src/components/widgets/glances/glances.jsx | 7 ++++++- .../widgets/glances/glances.test.jsx | 20 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/widgets/info/glances.md b/docs/widgets/info/glances.md index 77c6a0ef3..fac0592e5 100644 --- a/docs/widgets/info/glances.md +++ b/docs/widgets/info/glances.md @@ -16,6 +16,7 @@ The Glances widget allows you to monitor the resources (CPU, memory, storage, te cpu: true # optional, enabled by default, disable by setting to false mem: true # optional, enabled by default, disable by setting to false cputemp: true # disabled by default + cpuSensorLabel: Package id # optional additional cputemp sensor label prefix unit: imperial # optional for temp, default is metric uptime: true # disabled by default disk: / # disabled by default, use mount point of disk(s) in glances. Can also be a list (see below) @@ -24,6 +25,8 @@ The Glances widget allows you to monitor the resources (CPU, memory, storage, te label: MyMachine # optional ``` +The built-in `cputemp` sensor matching already checks common prefixes such as `cpu_thermal`, `Core`, `Tctl`, and `Temperature`. Use `cpuSensorLabel` to add your own Glances sensor label prefix when your system reports CPU temperatures under a different name. + Multiple disks can be specified as: ```yaml diff --git a/src/components/widgets/glances/glances.jsx b/src/components/widgets/glances/glances.jsx index 567a73de1..569091e1d 100644 --- a/src/components/widgets/glances/glances.jsx +++ b/src/components/widgets/glances/glances.jsx @@ -11,12 +11,16 @@ import Resource from "../widget/resource"; import Resources from "../widget/resources"; import WidgetLabel from "../widget/widget_label"; -const cpuSensorLabels = ["cpu_thermal", "Core", "Tctl", "Temperature"]; +const defaultCpuSensorLabels = ["cpu_thermal", "Core", "Tctl", "Temperature"]; function convertToFahrenheit(t) { return (t * 9) / 5 + 32; } +function getCpuSensorLabels(options) { + return [...defaultCpuSensorLabels, options.cpuSensorLabel].filter(Boolean); +} + export default function Widget({ options }) { const { t, i18n } = useTranslation(); const { settings } = useContext(SettingsContext); @@ -56,6 +60,7 @@ export default function Widget({ options }) { const unit = options.units === "imperial" ? "fahrenheit" : "celsius"; let mainTemp = 0; let maxTemp = 80; + const cpuSensorLabels = getCpuSensorLabels(options); const cpuSensors = data.sensors?.filter( (s) => cpuSensorLabels.some((label) => s.label.startsWith(label)) && s.type === "temperature_core", ); diff --git a/src/components/widgets/glances/glances.test.jsx b/src/components/widgets/glances/glances.test.jsx index a72fff0df..8c68f9853 100644 --- a/src/components/widgets/glances/glances.test.jsx +++ b/src/components/widgets/glances/glances.test.jsx @@ -120,6 +120,26 @@ describe("components/widgets/glances", () => { expect(screen.getByRole("link")).toHaveClass("expanded"); }); + it("renders temperature for custom cpu sensor labels", () => { + useSWR.mockReturnValue({ + data: { + cpu: { total: 1 }, + load: { min15: 1 }, + mem: { available: 1, total: 1, percent: 1 }, + fs: [], + sensors: [{ label: "Package id 0", type: "temperature_core", value: 42, warning: 90 }], + }, + error: undefined, + }); + + renderWithProviders(, { + settings: { target: "_self" }, + }); + + expect(screen.getByText("42")).toBeInTheDocument(); + expect(screen.getByText("glances.temp")).toBeInTheDocument(); + }); + it("renders disk resources for an array of mount points and filters missing mounts", () => { useSWR.mockReturnValue({ data: { From 9b8e7712683580cb8140794fa9c27667f2b66269 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 18:48:21 -0700 Subject: [PATCH 38/56] Chore(deps-dev): Bump postcss from 8.5.8 to 8.5.10 in the npm_and_yarn group across 1 directory (#6596) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 01f728f17..02b7af973 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-hooks": "^5.2.0", "jsdom": "^28.1.0", - "postcss": "^8.5.8", + "postcss": "^8.5.10", "prettier": "^3.8.1", "prettier-plugin-organize-imports": "^4.3.0", "tailwind-scrollbar": "^4.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8709aaa03..5b727e58b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -154,8 +154,8 @@ importers: specifier: ^28.1.0 version: 28.1.0 postcss: - specifier: ^8.5.8 - version: 8.5.8 + specifier: ^8.5.10 + version: 8.5.10 prettier: specifier: ^3.8.1 version: 3.8.1 @@ -3048,8 +3048,8 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -4689,7 +4689,7 @@ snapshots: '@alloc/quick-lru': 5.2.0 '@tailwindcss/node': 4.1.18 '@tailwindcss/oxide': 4.1.18 - postcss: 8.5.8 + postcss: 8.5.10 tailwindcss: 4.1.18 '@tanstack/react-virtual@3.13.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -6808,7 +6808,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.8: + postcss@8.5.10: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -7608,7 +7608,7 @@ snapshots: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.8 + postcss: 8.5.10 rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: From c3b4fc17c45f93069b5e460efd138a708cb66a37 Mon Sep 17 00:00:00 2001 From: Jim Strang Date: Sun, 26 Apr 2026 23:38:14 -0400 Subject: [PATCH 39/56] Feature: ntfy widget (#6601) Co-authored-by: Jim Strang Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/ntfy.md | 36 +++ mkdocs.yml | 1 + public/locales/en/common.json | 13 ++ src/utils/proxy/handlers/credentialed.js | 6 + src/utils/proxy/handlers/credentialed.test.js | 46 ++++ src/widgets/components.js | 1 + src/widgets/ntfy/component.jsx | 63 +++++ src/widgets/ntfy/component.test.jsx | 216 ++++++++++++++++++ src/widgets/ntfy/widget.js | 14 ++ src/widgets/ntfy/widget.test.js | 11 + src/widgets/widgets.js | 2 + 11 files changed, 409 insertions(+) create mode 100644 docs/widgets/services/ntfy.md create mode 100644 src/widgets/ntfy/component.jsx create mode 100644 src/widgets/ntfy/component.test.jsx create mode 100644 src/widgets/ntfy/widget.js create mode 100644 src/widgets/ntfy/widget.test.js diff --git a/docs/widgets/services/ntfy.md b/docs/widgets/services/ntfy.md new file mode 100644 index 000000000..e8d243705 --- /dev/null +++ b/docs/widgets/services/ntfy.md @@ -0,0 +1,36 @@ +--- +title: ntfy +description: ntfy Widget Configuration +--- + +Learn more about [ntfy](https://github.com/binwiederhier/ntfy). + +This widget shows the latest notification for a ntfy topic, including the title or body, priority level, and when it was received. Works with both self-hosted ntfy instances and the public [ntfy.sh](https://ntfy.sh) service. + +Allowed fields: `["title", "message", "priority", "lastReceived", "tags"]`. + +Default fields: `["title", "message", "priority", "lastReceived"]`. + +If more than 4 fields are provided, only the first 4 are displayed. + +## Authentication + +ntfy supports both public and private topics. For private instances or access-controlled topics, you can authenticate using either a **Bearer token** (ntfy access token) or **Basic auth** (username/password). + +| Auth Method | Config Fields | Notes | +| ------------ | ------------------------------ | --------------------------------- | +| None | _(omit key/username/password)_ | For public topics | +| Bearer token | `key` | ntfy access tokens (`tk_` prefix) | +| Basic auth | `username` + `password` | Username/password credentials | + +See the [ntfy documentation](https://docs.ntfy.sh/config/#access-control) for details on access control. + +```yaml +widget: + type: ntfy + url: http://ntfy.host.or.ip:port # required + topic: mytopic # required + # key: tk_accesstoken # optional — for token auth + # username: user # optional — for basic auth + # password: pass # optional — for basic auth +``` diff --git a/mkdocs.yml b/mkdocs.yml index 1933825c5..e954e0219 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -116,6 +116,7 @@ nav: - widgets/services/nextcloud.md - widgets/services/nextdns.md - widgets/services/nginx-proxy-manager.md + - widgets/services/ntfy.md - widgets/services/nzbget.md - widgets/services/octoprint.md - widgets/services/omada.md diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 6d2204774..8908133b8 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -936,6 +936,19 @@ "warnings": "Warnings", "criticals": "Criticals" }, + "ntfy": { + "title": "Title", + "priority": "Priority", + "lastReceived": "Last Received", + "message": "Message", + "tags": "Tags", + "none": "None", + "min": "Min", + "low": "Low", + "default": "Default", + "high": "High", + "urgent": "Urgent" + }, "plantit": { "events": "Events", "plants": "Plants", diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index 27f02f3e5..afe53457d 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -77,6 +77,12 @@ export default async function credentialedProxyHandler(req, res, map) { } else { headers.Authorization = basicAuthHeader(widget); } + } else if (widget.type === "ntfy") { + if (widget.key) { + headers.Authorization = `Bearer ${widget.key}`; + } else if (widget.username && widget.password) { + headers.Authorization = basicAuthHeader(widget); + } } else if (widget.type === "proxmox") { headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`; } else if (widget.type === "proxmoxbackupserver") { diff --git a/src/utils/proxy/handlers/credentialed.test.js b/src/utils/proxy/handlers/credentialed.test.js index 72e7b5e3d..ef720669a 100644 --- a/src/utils/proxy/handlers/credentialed.test.js +++ b/src/utils/proxy/handlers/credentialed.test.js @@ -34,6 +34,7 @@ vi.mock("widgets/widgets", () => ({ paperlessngx: { api: "{url}/api/{endpoint}" }, proxmox: { api: "{url}/api2/json/{endpoint}" }, truenas: { api: "{url}/api/v2.0/{endpoint}" }, + ntfy: { api: "{url}/{endpoint}" }, proxmoxbackupserver: { api: "{url}/api2/json/{endpoint}" }, checkmk: { api: "{url}/{endpoint}" }, stocks: { api: "{url}/{endpoint}" }, @@ -185,6 +186,51 @@ describe("utils/proxy/handlers/credentialed", () => { expect(params.headers.Authorization).toBe("Bearer k"); }); + it("uses Bearer auth for ntfy when key is provided", async () => { + getServiceWidget.mockResolvedValue({ type: "ntfy", url: "http://ntfy", topic: "alerts", key: "tk_test" }); + httpProxy.mockResolvedValue([200, "application/json", { ok: true }]); + + const req = { method: "GET", query: { group: "g", service: "s", endpoint: "alerts/json", index: 0 } }; + const res = createMockRes(); + + await credentialedProxyHandler(req, res); + + const [, params] = httpProxy.mock.calls.at(-1); + expect(params.headers.Authorization).toBe("Bearer tk_test"); + }); + + it("uses Basic auth for ntfy when username/password are provided", async () => { + getServiceWidget.mockResolvedValue({ + type: "ntfy", + url: "http://ntfy", + topic: "alerts", + username: "u", + password: "p", + }); + httpProxy.mockResolvedValue([200, "application/json", { ok: true }]); + + const req = { method: "GET", query: { group: "g", service: "s", endpoint: "alerts/json", index: 0 } }; + const res = createMockRes(); + + await credentialedProxyHandler(req, res); + + const [, params] = httpProxy.mock.calls.at(-1); + expect(params.headers.Authorization).toMatch(/^Basic /); + }); + + it("sends no auth header for ntfy when no credentials are configured", async () => { + getServiceWidget.mockResolvedValue({ type: "ntfy", url: "http://ntfy", topic: "alerts" }); + httpProxy.mockResolvedValue([200, "application/json", { ok: true }]); + + const req = { method: "GET", query: { group: "g", service: "s", endpoint: "alerts/json", index: 0 } }; + const res = createMockRes(); + + await credentialedProxyHandler(req, res); + + const [, params] = httpProxy.mock.calls.at(-1); + expect(params.headers.Authorization).toBeUndefined(); + }); + it.each([ [{ type: "paperlessngx", url: "http://x", key: "k" }, { Authorization: "Token k" }], [ diff --git a/src/widgets/components.js b/src/widgets/components.js index c5f144e39..fbc34d3a2 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -91,6 +91,7 @@ const components = { nextcloud: dynamic(() => import("./nextcloud/component")), nextdns: dynamic(() => import("./nextdns/component")), npm: dynamic(() => import("./npm/component")), + ntfy: dynamic(() => import("./ntfy/component")), nzbget: dynamic(() => import("./nzbget/component")), octoprint: dynamic(() => import("./octoprint/component")), omada: dynamic(() => import("./omada/component")), diff --git a/src/widgets/ntfy/component.jsx b/src/widgets/ntfy/component.jsx new file mode 100644 index 000000000..e4f2b191a --- /dev/null +++ b/src/widgets/ntfy/component.jsx @@ -0,0 +1,63 @@ +import Block from "components/services/widget/block"; +import Container from "components/services/widget/container"; +import { useTranslation } from "next-i18next"; + +import useWidgetAPI from "utils/proxy/use-widget-api"; + +const priorityLabels = { + 1: "min", + 2: "low", + 3: "default", + 4: "high", + 5: "urgent", +}; + +function Truncated({ text }) { + return ( + + {text} + + ); +} + +export default function Component({ service }) { + const { t } = useTranslation(); + const { widget } = service; + + const { data: messagesData, error: messagesError } = useWidgetAPI(widget, "messages"); + + if (messagesError) { + return ; + } + + if (!widget.fields || widget.fields.length === 0) { + widget.fields = ["title", "message", "priority", "lastReceived"]; + } else if (widget.fields?.length > 4) { + widget.fields = widget.fields.slice(0, 4); + } + + if (!messagesData) { + return ( + + + + + + + + ); + } + + return ( + + } /> + } /> + + + 0 ? messagesData.tags.join(", ") : t("ntfy.none")} /> + + ); +} diff --git a/src/widgets/ntfy/component.test.jsx b/src/widgets/ntfy/component.test.jsx new file mode 100644 index 000000000..1132d459a --- /dev/null +++ b/src/widgets/ntfy/component.test.jsx @@ -0,0 +1,216 @@ +// @vitest-environment jsdom + +import { screen } from "@testing-library/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { renderWithProviders } from "test-utils/render-with-providers"; +import { expectBlockValue } from "test-utils/widget-assertions"; + +const { useWidgetAPI } = vi.hoisted(() => ({ useWidgetAPI: vi.fn() })); + +vi.mock("utils/proxy/use-widget-api", () => ({ + default: useWidgetAPI, +})); + +import Component from "./component"; + +describe("widgets/ntfy/component", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders placeholders while loading", () => { + useWidgetAPI.mockImplementation(() => ({ data: undefined, error: undefined })); + + const { container } = renderWithProviders(, { + settings: { hideErrors: false }, + }); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expect(screen.getByText("ntfy.title")).toBeInTheDocument(); + expect(screen.getByText("ntfy.message")).toBeInTheDocument(); + expect(screen.getByText("ntfy.priority")).toBeInTheDocument(); + expect(screen.getByText("ntfy.lastReceived")).toBeInTheDocument(); + }); + + it("renders message data with default fields", () => { + useWidgetAPI.mockImplementation(() => ({ + data: { + title: "Disk Alert", + message: "Disk usage at 90%", + priority: 4, + time: 1700000000, + tags: ["warning"], + }, + error: undefined, + })); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + expectBlockValue(container, "ntfy.title", "Disk Alert"); + expectBlockValue(container, "ntfy.message", "Disk usage at 90%"); + expectBlockValue(container, "ntfy.priority", "ntfy.high"); + }); + + it("shows placeholder for title when message has no title set", () => { + useWidgetAPI.mockImplementation(() => ({ + data: { + title: null, + message: "Simple notification", + priority: 3, + time: 1700000000, + tags: [], + }, + error: undefined, + })); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expectBlockValue(container, "ntfy.title", "ntfy.none"); + expectBlockValue(container, "ntfy.message", "Simple notification"); + expectBlockValue(container, "ntfy.priority", "ntfy.default"); + }); + + it("renders no messages state", () => { + useWidgetAPI.mockImplementation(() => ({ + data: { + title: null, + message: null, + priority: 3, + time: null, + tags: [], + }, + error: undefined, + })); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expectBlockValue(container, "ntfy.title", "ntfy.none"); + expectBlockValue(container, "ntfy.message", "ntfy.none"); + expectBlockValue(container, "ntfy.lastReceived", "ntfy.none"); + }); + + it("renders error when API fails", () => { + useWidgetAPI.mockImplementation(() => ({ + data: undefined, + error: { message: "Request failed" }, + })); + + renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expect(screen.getByText("Request failed")).toBeInTheDocument(); + }); + + it("renders optional tags field when included", () => { + useWidgetAPI.mockImplementation(() => ({ + data: { + title: "Alert", + message: "Test", + priority: 5, + time: 1700000000, + tags: ["warning", "skull"], + }, + error: undefined, + })); + + const service = { + widget: { + type: "ntfy", + url: "https://ntfy.example.com", + topic: "alerts", + fields: ["title", "priority", "lastReceived", "tags"], + }, + }; + + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expectBlockValue(container, "ntfy.tags", "warning, skull"); + expectBlockValue(container, "ntfy.priority", "ntfy.urgent"); + }); + + it("caps visible blocks at 4 when more than 4 fields are configured", () => { + useWidgetAPI.mockImplementation(() => ({ + data: { + title: "Alert", + message: "Body", + priority: 3, + time: 1700000000, + tags: ["a"], + }, + error: undefined, + })); + + const service = { + widget: { + type: "ntfy", + url: "https://ntfy.example.com", + topic: "alerts", + fields: ["title", "message", "priority", "lastReceived", "tags"], + }, + }; + + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expect(container.querySelectorAll(".service-block")).toHaveLength(4); + }); + + it("falls back to default priority label when priority is out of range", () => { + useWidgetAPI.mockImplementation(() => ({ + data: { + title: "Alert", + message: "Body", + priority: 99, + time: 1700000000, + tags: [], + }, + error: undefined, + })); + + const { container } = renderWithProviders( + , + { settings: { hideErrors: false } }, + ); + + expectBlockValue(container, "ntfy.priority", "ntfy.default"); + }); + + it("renders optional message field when included", () => { + useWidgetAPI.mockImplementation(() => ({ + data: { + title: "Disk Alert", + message: "Disk usage at 90%", + priority: 4, + time: 1700000000, + tags: [], + }, + error: undefined, + })); + + const service = { + widget: { + type: "ntfy", + url: "https://ntfy.example.com", + topic: "alerts", + fields: ["title", "priority", "message"], + }, + }; + + const { container } = renderWithProviders(, { settings: { hideErrors: false } }); + + expectBlockValue(container, "ntfy.title", "Disk Alert"); + expectBlockValue(container, "ntfy.message", "Disk usage at 90%"); + }); +}); diff --git a/src/widgets/ntfy/widget.js b/src/widgets/ntfy/widget.js new file mode 100644 index 000000000..577e124a7 --- /dev/null +++ b/src/widgets/ntfy/widget.js @@ -0,0 +1,14 @@ +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; + +const widget = { + api: "{url}/{endpoint}", + proxyHandler: credentialedProxyHandler, + + mappings: { + messages: { + endpoint: "{topic}/json?poll=1&since=latest", + }, + }, +}; + +export default widget; diff --git a/src/widgets/ntfy/widget.test.js b/src/widgets/ntfy/widget.test.js new file mode 100644 index 000000000..4827c60b2 --- /dev/null +++ b/src/widgets/ntfy/widget.test.js @@ -0,0 +1,11 @@ +import { describe, it } from "vitest"; + +import { expectWidgetConfigShape } from "test-utils/widget-config"; + +import widget from "./widget"; + +describe("ntfy widget config", () => { + it("exports a valid widget config", () => { + expectWidgetConfigShape(widget); + }); +}); diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index be7f685e4..7f18efad3 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -82,6 +82,7 @@ import netdata from "./netdata/widget"; import nextcloud from "./nextcloud/widget"; import nextdns from "./nextdns/widget"; import npm from "./npm/widget"; +import ntfy from "./ntfy/widget"; import nzbget from "./nzbget/widget"; import octoprint from "./octoprint/widget"; import omada from "./omada/widget"; @@ -239,6 +240,7 @@ const widgets = { nextcloud, nextdns, npm, + ntfy, nzbget, octoprint, omada, From 77c9ac4a2c08d697204f32cf134923bfd8b31dda Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:52:32 -0700 Subject: [PATCH 40/56] Fix: add missing backdrop blur classes to safelist (#6617) --- src/pages/_app.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx index 8e88f6b28..dd2086d0a 100644 --- a/src/pages/_app.jsx +++ b/src/pages/_app.jsx @@ -19,7 +19,10 @@ const tailwindSafelist = [ "backdrop-blur-xs", "backdrop-blur-sm", "backdrop-blur-md", + "backdrop-blur-lg", "backdrop-blur-xl", + "backdrop-blur-2xl", + "backdrop-blur-3xl", "backdrop-saturate-0", "backdrop-saturate-50", "backdrop-saturate-100", From 977be863c7e2325175f3598fdbcda27fbd681672 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 22:48:57 +0000 Subject: [PATCH 41/56] Chore(deps): Bump actions/setup-node from 6.3.0 to 6.4.0 (#6613) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-publish.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 9861a993d..6e158243f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -67,7 +67,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 24 cache: 'pnpm' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index af3b40626..9181ae45f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,7 +29,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 24 cache: 'pnpm' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3b7d43609..2d7401747 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: with: version: 9 - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 20 cache: pnpm From 081b9ec8c33dc87bb92315b7c365ce645d93a992 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 22:53:03 +0000 Subject: [PATCH 42/56] Chore(deps): Bump crowdin/github-action from 2.16.0 to 2.16.2 (#6615) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 68271247d..136e70bc3 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -19,7 +19,7 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: crowdin action - uses: crowdin/github-action@7ca9c452bfe9197d3bb7fa83a4d7e2b0c9ae835d # v2 + uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2 with: upload_translations: false download_translations: true From b2a52ff2a9df1b7e7bc612178f66539606311b84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 22:57:08 +0000 Subject: [PATCH 43/56] Chore(deps): Bump pnpm/action-setup from 5.0.0 to 6.0.3 (#6614) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-publish.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 6e158243f..e10e4cb44 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -61,7 +61,7 @@ jobs: nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Install pnpm - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 + uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 with: version: 10 run_install: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9181ae45f..ab5c8a7bc 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -23,7 +23,7 @@ jobs: uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 - name: Install pnpm - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 + uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 with: version: 10 run_install: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2d7401747..95b72adcd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5 + - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 with: version: 9 From 3dffc38462060f6fbd746931d79b017d09370393 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 May 2026 21:03:46 -0700 Subject: [PATCH 44/56] Chore(deps): Bump @headlessui/react from 2.2.9 to 2.2.10 (#6620) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 215 ++++++++++++++++++++++++++----------------------- 2 files changed, 116 insertions(+), 101 deletions(-) diff --git a/package.json b/package.json index 02b7af973..f0e2e003c 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "telemetry": "next telemetry disable" }, "dependencies": { - "@headlessui/react": "^2.2.9", + "@headlessui/react": "^2.2.10", "@kubernetes/client-node": "^1.0.0", "classnames": "^2.5.1", "compare-versions": "^6.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b727e58b..bb94d56de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@headlessui/react': - specifier: ^2.2.9 - version: 2.2.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^2.2.10 + version: 2.2.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@kubernetes/client-node': specifier: ^1.0.0 version: 1.0.0 @@ -516,14 +516,14 @@ packages: '@noble/hashes': optional: true - '@floating-ui/core@1.7.3': - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - '@floating-ui/dom@1.7.4': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - '@floating-ui/react-dom@2.1.6': - resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' @@ -534,8 +534,8 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} '@grpc/grpc-js@1.14.3': resolution: {integrity: sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==} @@ -551,8 +551,8 @@ packages: engines: {node: '>=6'} hasBin: true - '@headlessui/react@2.2.9': - resolution: {integrity: sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==} + '@headlessui/react@2.2.10': + resolution: {integrity: sha512-5pVLNK9wlpxTUTy9GpgbX/SdcRh+HBnPktjM2wbiLTH4p+2EPHBO1aoSryUCuKUIItdDWO9ITlhUL8UnUN/oIA==} engines: {node: '>=10'} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc @@ -715,6 +715,15 @@ packages: cpu: [x64] os: [win32] + '@internationalized/date@3.12.1': + resolution: {integrity: sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==} + + '@internationalized/number@3.6.6': + resolution: {integrity: sha512-iFgmQaXHE0vytNfpLZWOC2mEJCBRzcUxt53Xf/yCXG93lRvqas237i3r7X4RKMwO3txiyZD4mQjKAByFv6UGSQ==} + + '@internationalized/string@3.2.8': + resolution: {integrity: sha512-NdbMQUSfXLYIQol5VyMtinm9pZDciiMfN7RtmSuSB78io1hqwJ0naYfxyW6vgxWBkzWymQa/3uLDlbfmshtCaA==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -872,40 +881,20 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@react-aria/focus@3.21.2': - resolution: {integrity: sha512-JWaCR7wJVggj+ldmM/cb/DXFg47CXR55lznJhZBh4XVqJjMKwaOOqpT5vNN7kpC1wUpXicGNuDnJDN1S/+6dhQ==} + '@react-aria/focus@3.22.0': + resolution: {integrity: sha512-ZfDOVuVhqDsM9mkNji3QUZ/d40JhlVgXrDkrfXylM1035QCrcTHN7m2DpbE95sU2A8EQb4wikvt5jM6K/73BPg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/interactions@3.25.6': - resolution: {integrity: sha512-5UgwZmohpixwNMVkMvn9K1ceJe6TzlRlAfuYoQDUuOkk62/JVJNDLAPKIf5YMRc7d2B0rmfgaZLMtbREb0Zvkw==} + '@react-aria/interactions@3.28.0': + resolution: {integrity: sha512-OXwdU1EWFdMxmr/K1CXNGJzmNlCClByb+PuCaqUyzBymHPCGVhawirLIon/CrIN5psh3AiWpHSh4H0WeJdVpng==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/ssr@3.9.10': - resolution: {integrity: sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==} - engines: {node: '>= 12'} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - - '@react-aria/utils@3.31.0': - resolution: {integrity: sha512-ABOzCsZrWzf78ysswmguJbx3McQUja7yeGj6/vZo4JVsZNlxAN+E9rs381ExBRI0KzVo6iBTeX5De8eMZPJXig==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - - '@react-stately/flags@3.1.2': - resolution: {integrity: sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==} - - '@react-stately/utils@3.10.8': - resolution: {integrity: sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - - '@react-types/shared@3.32.1': - resolution: {integrity: sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w==} + '@react-types/shared@3.34.0': + resolution: {integrity: sha512-gp6xo/s2lX54AlTjOiqwDnxA7UW79BNvI9dB9pr3LZTzRKCd1ZA+ZbgKw/ReIiWuvvVw/8QFJpnqeeFyLocMcQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -1167,14 +1156,14 @@ packages: '@tailwindcss/postcss@4.1.18': resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} - '@tanstack/react-virtual@3.13.12': - resolution: {integrity: sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==} + '@tanstack/react-virtual@3.13.24': + resolution: {integrity: sha512-aIJvz5OSkhNIhZIpYivrxrPTKYsjW9Uzy+sP/mx0S3sev2HyvPb7xmjbYvokzEpfgYHy/HjzJ2zFAETuUfgCpg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/virtual-core@3.13.12': - resolution: {integrity: sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==} + '@tanstack/virtual-core@3.14.0': + resolution: {integrity: sha512-JLANqGy/D6k4Ujmh8Tr25lGimuOXNiaVyXaCAZS0W+1390sADdGnyUdSWNIfd49gebtIxGMij4IktRVzrdr12Q==} '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -1494,6 +1483,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -3116,6 +3109,12 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + react-aria@3.48.0: + resolution: {integrity: sha512-jQjd4rBEIMqecBaAKYJbVGK6EqIHLa5znVQ7jwFyK5vCyljoj6KhgtiahmcIPsG5vG5vEDLw+ba+bEWn6A2P4w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: @@ -3163,6 +3162,11 @@ packages: redux: optional: true + react-stately@3.46.0: + resolution: {integrity: sha512-OdxhWvHgs2L4OJGIs7hnuTr5WjjMM6enhNEAMRqiekhF8+ITvA2LRwNftOZwcogaoCslGYq5S2VQTQwnm0GbCA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} @@ -3501,8 +3505,8 @@ packages: os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true - tabbable@6.3.0: - resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} tailwind-scrollbar@4.0.2: resolution: {integrity: sha512-wAQiIxAPqk0MNTPptVe/xoyWi27y+NRGnTwvn4PQnbvB9kp8QUBiGl/wsfoVBHnQxTmhXJSNt9NHTmcz9EivFA==} @@ -3686,6 +3690,7 @@ packages: uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true varint@6.0.0: @@ -4143,30 +4148,30 @@ snapshots: '@exodus/bytes@1.15.0': {} - '@floating-ui/core@1.7.3': + '@floating-ui/core@1.7.5': dependencies: - '@floating-ui/utils': 0.2.10 + '@floating-ui/utils': 0.2.11 - '@floating-ui/dom@1.7.4': + '@floating-ui/dom@1.7.6': dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 - '@floating-ui/react-dom@2.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@floating-ui/dom': 1.7.4 + '@floating-ui/dom': 1.7.6 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) '@floating-ui/react@0.26.28(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@floating-ui/utils': 0.2.10 + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/utils': 0.2.11 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - tabbable: 6.3.0 + tabbable: 6.4.0 - '@floating-ui/utils@0.2.10': {} + '@floating-ui/utils@0.2.11': {} '@grpc/grpc-js@1.14.3': dependencies: @@ -4187,12 +4192,12 @@ snapshots: protobufjs: 7.5.5 yargs: 17.7.2 - '@headlessui/react@2.2.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@headlessui/react@2.2.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@floating-ui/react': 0.26.28(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@react-aria/focus': 3.21.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@react-aria/interactions': 3.25.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-virtual': 3.13.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/focus': 3.22.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.28.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-virtual': 3.13.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) @@ -4307,6 +4312,18 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@internationalized/date@3.12.1': + dependencies: + '@swc/helpers': 0.5.21 + + '@internationalized/number@3.6.6': + dependencies: + '@swc/helpers': 0.5.21 + + '@internationalized/string@3.2.8': + dependencies: + '@swc/helpers': 0.5.21 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -4455,52 +4472,22 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@react-aria/focus@3.21.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@react-aria/focus@3.22.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@react-aria/utils': 3.31.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@react-types/shared': 3.32.1(react@19.2.4) '@swc/helpers': 0.5.21 - clsx: 2.1.1 react: 19.2.4 + react-aria: 3.48.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-dom: 19.2.4(react@19.2.4) - '@react-aria/interactions@3.25.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@react-aria/interactions@3.28.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.4) - '@react-aria/utils': 3.31.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@react-stately/flags': 3.1.2 - '@react-types/shared': 3.32.1(react@19.2.4) + '@react-types/shared': 3.34.0(react@19.2.4) '@swc/helpers': 0.5.21 react: 19.2.4 + react-aria: 3.48.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-dom: 19.2.4(react@19.2.4) - '@react-aria/ssr@3.9.10(react@19.2.4)': - dependencies: - '@swc/helpers': 0.5.21 - react: 19.2.4 - - '@react-aria/utils@3.31.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.4) - '@react-stately/flags': 3.1.2 - '@react-stately/utils': 3.10.8(react@19.2.4) - '@react-types/shared': 3.32.1(react@19.2.4) - '@swc/helpers': 0.5.21 - clsx: 2.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - - '@react-stately/flags@3.1.2': - dependencies: - '@swc/helpers': 0.5.21 - - '@react-stately/utils@3.10.8(react@19.2.4)': - dependencies: - '@swc/helpers': 0.5.21 - react: 19.2.4 - - '@react-types/shared@3.32.1(react@19.2.4)': + '@react-types/shared@3.34.0(react@19.2.4)': dependencies: react: 19.2.4 @@ -4692,13 +4679,13 @@ snapshots: postcss: 8.5.10 tailwindcss: 4.1.18 - '@tanstack/react-virtual@3.13.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-virtual@3.13.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/virtual-core': 3.13.12 + '@tanstack/virtual-core': 3.14.0 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@tanstack/virtual-core@3.13.12': {} + '@tanstack/virtual-core@3.14.0': {} '@testing-library/dom@10.4.1': dependencies: @@ -5036,6 +5023,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -6882,6 +6873,20 @@ snapshots: iconv-lite: 0.7.0 unpipe: 1.0.0 + react-aria@3.48.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@internationalized/date': 3.12.1 + '@internationalized/number': 3.6.6 + '@internationalized/string': 3.2.8 + '@react-types/shared': 3.34.0(react@19.2.4) + '@swc/helpers': 0.5.21 + aria-hidden: 1.2.6 + clsx: 2.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-stately: 3.46.0(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 @@ -6911,11 +6916,21 @@ snapshots: dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.4 - use-sync-external-store: 1.5.0(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) optionalDependencies: '@types/react': 19.0.10 redux: 5.0.1 + react-stately@3.46.0(react@19.2.4): + dependencies: + '@internationalized/date': 3.12.1 + '@internationalized/number': 3.6.6 + '@internationalized/string': 3.2.8 + '@react-types/shared': 3.34.0(react@19.2.4) + '@swc/helpers': 0.5.21 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + react@19.2.4: {} readable-stream@1.0.34: @@ -7355,7 +7370,7 @@ snapshots: systeminformation@5.30.8: {} - tabbable@6.3.0: {} + tabbable@6.4.0: {} tailwind-scrollbar@4.0.2(react@19.2.4)(tailwindcss@4.1.18): dependencies: From 93364b6a27df4ac873a0b39bdec2febf2a4dbaf6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 04:08:43 +0000 Subject: [PATCH 45/56] Chore(deps): Bump json-rpc-2.0 from 1.7.0 to 1.7.1 (#6624) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f0e2e003c..98c2a810b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "i18next": "^25.10.9", "ical.js": "^2.2.1", "js-yaml": "^4.1.1", - "json-rpc-2.0": "^1.7.0", + "json-rpc-2.0": "^1.7.1", "luxon": "^3.6.1", "memory-cache": "^0.2.0", "minecraftstatuspinger": "^1.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb94d56de..a795df078 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,8 +39,8 @@ importers: specifier: ^4.1.1 version: 4.1.1 json-rpc-2.0: - specifier: ^1.7.0 - version: 1.7.0 + specifier: ^1.7.1 + version: 1.7.1 luxon: specifier: ^3.6.1 version: 3.6.1 @@ -2624,8 +2624,8 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-rpc-2.0@1.7.0: - resolution: {integrity: sha512-asnLgC1qD5ytP+fvBP8uL0rvj+l8P6iYICbzZ8dVxCpESffVjzA7KkYkbKCIbavs7cllwH1ZUaNtJwphdeRqpg==} + json-rpc-2.0@1.7.1: + resolution: {integrity: sha512-JqZjhjAanbpkXIzFE7u8mE/iFblawwlXtONaCvRqI+pyABVz7B4M1EUNpyVW+dZjqgQ2L5HFmZCmOCgUKm00hg==} json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -6432,7 +6432,7 @@ snapshots: json-buffer@3.0.1: {} - json-rpc-2.0@1.7.0: {} + json-rpc-2.0@1.7.1: {} json-schema-traverse@0.4.1: {} From 4e621aee8f541e2c11a7d4a12d1d3d91ae8ebd0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 04:15:05 +0000 Subject: [PATCH 46/56] Chore(deps-dev): Bump @eslint/js from 9.39.2 to 9.39.4 (#6623) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 98c2a810b..dc57dc6a4 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "devDependencies": { "@eslint/compat": "^2.0.3", "@eslint/eslintrc": "^3.3.3", - "@eslint/js": "^9.39.2", + "@eslint/js": "^9.39.4", "@tailwindcss/forms": "^0.5.11", "@tailwindcss/postcss": "^4.1.18", "@testing-library/jest-dom": "^6.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a795df078..025a65746 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -109,8 +109,8 @@ importers: specifier: ^3.3.3 version: 3.3.3 '@eslint/js': - specifier: ^9.39.2 - version: 9.39.2 + specifier: ^9.39.4 + version: 9.39.4 '@tailwindcss/forms': specifier: ^0.5.11 version: 0.5.11(tailwindcss@4.1.18) @@ -495,8 +495,8 @@ packages: resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.2': - resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': @@ -4137,7 +4137,7 @@ snapshots: '@eslint/js@9.25.1': {} - '@eslint/js@9.39.2': {} + '@eslint/js@9.39.4': {} '@eslint/object-schema@2.1.6': {} From cd6e708af292d3fa19cfeb95ea74b5c0da4c8ecb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 May 2026 21:15:50 -0700 Subject: [PATCH 47/56] Chore(deps): Bump react from 19.2.4 to 19.2.5 (#6621) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- package.json | 4 +- pnpm-lock.yaml | 202 ++++++++++++++++++++++++------------------------- 2 files changed, 103 insertions(+), 103 deletions(-) diff --git a/package.json b/package.json index dc57dc6a4..7f946d508 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ "ping": "^0.4.4", "pretty-bytes": "^7.1.0", "raw-body": "^3.0.2", - "react": "^19.2.4", - "react-dom": "^19.2.4", + "react": "^19.2.5", + "react-dom": "^19.2.5", "react-i18next": "^15.5.3", "react-icons": "^5.6.0", "recharts": "^3.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 025a65746..f33832625 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@headlessui/react': specifier: ^2.2.10 - version: 2.2.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.2.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@kubernetes/client-node': specifier: ^1.0.0 version: 1.0.0 @@ -52,10 +52,10 @@ importers: version: 1.2.2 next: specifier: ^16.2.3 - version: 16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next-i18next: specifier: ^15.4.3 - version: 15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4) + version: 15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3))(react@19.2.5) ping: specifier: ^0.4.4 version: 0.4.4 @@ -66,23 +66,23 @@ importers: specifier: ^3.0.2 version: 3.0.2 react: - specifier: ^19.2.4 - version: 19.2.4 + specifier: ^19.2.5 + version: 19.2.5 react-dom: - specifier: ^19.2.4 - version: 19.2.4(react@19.2.4) + specifier: ^19.2.5 + version: 19.2.5(react@19.2.5) react-i18next: specifier: ^15.5.3 - version: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) + version: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3) react-icons: specifier: ^5.6.0 - version: 5.6.0(react@19.2.4) + version: 5.6.0(react@19.2.5) recharts: specifier: ^3.1.2 - version: 3.1.2(@types/react@19.0.10)(react-dom@19.2.4(react@19.2.4))(react-is@18.3.1)(react@19.2.4)(redux@5.0.1) + version: 3.1.2(@types/react@19.0.10)(react-dom@19.2.5(react@19.2.5))(react-is@18.3.1)(react@19.2.5)(redux@5.0.1) swr: specifier: ^2.4.1 - version: 2.4.1(react@19.2.4) + version: 2.4.1(react@19.2.5) systeminformation: specifier: ^5.30.8 version: 5.30.8 @@ -122,7 +122,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.3.0 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react@19.0.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react@19.0.10)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@vitest/coverage-v8': specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)) @@ -164,7 +164,7 @@ importers: version: 4.3.0(prettier@3.8.1)(typescript@5.7.3) tailwind-scrollbar: specifier: ^4.0.2 - version: 4.0.2(react@19.2.4)(tailwindcss@4.1.18) + version: 4.0.2(react@19.2.5)(tailwindcss@4.1.18) tailwindcss: specifier: ^4.1.18 version: 4.1.18 @@ -3115,10 +3115,10 @@ packages: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: - react: ^19.2.4 + react: ^19.2.5 react-i18next@15.5.3: resolution: {integrity: sha512-ypYmOKOnjqPEJZO4m1BI0kS8kWqkBNsKYyhVUfij0gvjy9xJNoG/VcGkxq5dRlVwzmrmY1BQMAmpbbUBLwC4Kw==} @@ -3167,8 +3167,8 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} readable-stream@1.0.34: @@ -4157,18 +4157,18 @@ snapshots: '@floating-ui/core': 1.7.5 '@floating-ui/utils': 0.2.11 - '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@floating-ui/dom': 1.7.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@floating-ui/react@0.26.28(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@floating-ui/react@0.26.28(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@floating-ui/utils': 0.2.11 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) tabbable: 6.4.0 '@floating-ui/utils@0.2.11': {} @@ -4192,15 +4192,15 @@ snapshots: protobufjs: 7.5.5 yargs: 17.7.2 - '@headlessui/react@2.2.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@headlessui/react@2.2.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@floating-ui/react': 0.26.28(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@react-aria/focus': 3.22.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@react-aria/interactions': 3.28.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-virtual': 3.13.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - use-sync-external-store: 1.6.0(react@19.2.4) + '@floating-ui/react': 0.26.28(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@react-aria/focus': 3.22.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@react-aria/interactions': 3.28.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@tanstack/react-virtual': 3.13.24(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + use-sync-external-store: 1.6.0(react@19.2.5) '@humanfs/core@0.19.1': {} @@ -4472,26 +4472,26 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@react-aria/focus@3.22.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@react-aria/focus@3.22.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@swc/helpers': 0.5.21 - react: 19.2.4 - react-aria: 3.48.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-aria: 3.48.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-dom: 19.2.5(react@19.2.5) - '@react-aria/interactions@3.28.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@react-aria/interactions@3.28.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@react-types/shared': 3.34.0(react@19.2.4) + '@react-types/shared': 3.34.0(react@19.2.5) '@swc/helpers': 0.5.21 - react: 19.2.4 - react-aria: 3.48.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-aria: 3.48.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-dom: 19.2.5(react@19.2.5) - '@react-types/shared@3.34.0(react@19.2.4)': + '@react-types/shared@3.34.0(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 - '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.0.10)(react@19.2.4)(redux@5.0.1))(react@19.2.4)': + '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.0.10)(react@19.2.5)(redux@5.0.1))(react@19.2.5)': dependencies: '@standard-schema/spec': 1.0.0 '@standard-schema/utils': 0.3.0 @@ -4500,8 +4500,8 @@ snapshots: redux-thunk: 3.1.0(redux@5.0.1) reselect: 5.1.1 optionalDependencies: - react: 19.2.4 - react-redux: 9.2.0(@types/react@19.0.10)(react@19.2.4)(redux@5.0.1) + react: 19.2.5 + react-redux: 9.2.0(@types/react@19.0.10)(react@19.2.5)(redux@5.0.1) '@rollup/rollup-android-arm-eabi@4.59.0': optional: true @@ -4679,11 +4679,11 @@ snapshots: postcss: 8.5.10 tailwindcss: 4.1.18 - '@tanstack/react-virtual@3.13.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-virtual@3.13.24(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@tanstack/virtual-core': 3.14.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) '@tanstack/virtual-core@3.14.0': {} @@ -4707,12 +4707,12 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react@19.0.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react@19.0.10)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@testing-library/dom': 10.4.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.0.10 @@ -6630,7 +6630,7 @@ snapshots: net@1.0.2: {} - next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3))(react@19.2.4): + next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3))(react@19.2.5): dependencies: '@babel/runtime': 7.28.6 '@types/hoist-non-react-statics': 3.3.7(@types/react@19.0.10) @@ -6638,22 +6638,22 @@ snapshots: hoist-non-react-statics: 3.3.2 i18next: 25.10.9(typescript@5.7.3) i18next-fs-backend: 2.6.4 - next: 16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-i18next: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3) + next: 16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-i18next: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3) transitivePeerDependencies: - '@types/react' - next@16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@next/env': 16.2.3 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.17 caniuse-lite: 1.0.30001787 postcss: 8.4.31 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - styled-jsx: 5.1.6(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + styled-jsx: 5.1.6(react@19.2.5) optionalDependencies: '@next/swc-darwin-arm64': 16.2.3 '@next/swc-darwin-x64': 16.2.3 @@ -6826,11 +6826,11 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - prism-react-renderer@2.4.1(react@19.2.4): + prism-react-renderer@2.4.1(react@19.2.5): dependencies: '@types/prismjs': 1.26.5 clsx: 2.1.1 - react: 19.2.4 + react: 19.2.5 process-nextick-args@2.0.1: {} @@ -6873,38 +6873,38 @@ snapshots: iconv-lite: 0.7.0 unpipe: 1.0.0 - react-aria@3.48.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-aria@3.48.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@internationalized/date': 3.12.1 '@internationalized/number': 3.6.6 '@internationalized/string': 3.2.8 - '@react-types/shared': 3.34.0(react@19.2.4) + '@react-types/shared': 3.34.0(react@19.2.5) '@swc/helpers': 0.5.21 aria-hidden: 1.2.6 clsx: 2.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-stately: 3.46.0(react@19.2.4) - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-stately: 3.46.0(react@19.2.5) + use-sync-external-store: 1.6.0(react@19.2.5) - react-dom@19.2.4(react@19.2.4): + react-dom@19.2.5(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 scheduler: 0.27.0 - react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.7.3): + react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3): dependencies: '@babel/runtime': 7.27.6 html-parse-stringify: 3.0.1 i18next: 25.10.9(typescript@5.7.3) - react: 19.2.4 + react: 19.2.5 optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) typescript: 5.7.3 - react-icons@5.6.0(react@19.2.4): + react-icons@5.6.0(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 react-is@16.13.1: {} @@ -6912,26 +6912,26 @@ snapshots: react-is@18.3.1: {} - react-redux@9.2.0(@types/react@19.0.10)(react@19.2.4)(redux@5.0.1): + react-redux@9.2.0(@types/react@19.0.10)(react@19.2.5)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: '@types/react': 19.0.10 redux: 5.0.1 - react-stately@3.46.0(react@19.2.4): + react-stately@3.46.0(react@19.2.5): dependencies: '@internationalized/date': 3.12.1 '@internationalized/number': 3.6.6 '@internationalized/string': 3.2.8 - '@react-types/shared': 3.34.0(react@19.2.4) + '@react-types/shared': 3.34.0(react@19.2.5) '@swc/helpers': 0.5.21 - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) - react@19.2.4: {} + react@19.2.5: {} readable-stream@1.0.34: dependencies: @@ -6956,21 +6956,21 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - recharts@3.1.2(@types/react@19.0.10)(react-dom@19.2.4(react@19.2.4))(react-is@18.3.1)(react@19.2.4)(redux@5.0.1): + recharts@3.1.2(@types/react@19.0.10)(react-dom@19.2.5(react@19.2.5))(react-is@18.3.1)(react@19.2.5)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.0.10)(react@19.2.4)(redux@5.0.1))(react@19.2.4) + '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.0.10)(react@19.2.5)(redux@5.0.1))(react@19.2.5) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.39.10 eventemitter3: 5.0.1 immer: 10.1.3 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) react-is: 18.3.1 - react-redux: 9.2.0(@types/react@19.0.10)(react@19.2.4)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.0.10)(react@19.2.5)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 - use-sync-external-store: 1.5.0(react@19.2.4) + use-sync-external-store: 1.5.0(react@19.2.5) victory-vendor: 37.3.6 transitivePeerDependencies: - '@types/react' @@ -7345,10 +7345,10 @@ snapshots: strnum@2.1.1: {} - styled-jsx@5.1.6(react@19.2.4): + styled-jsx@5.1.6(react@19.2.5): dependencies: client-only: 0.0.1 - react: 19.2.4 + react: 19.2.5 supports-color@7.2.0: dependencies: @@ -7356,11 +7356,11 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - swr@2.4.1(react@19.2.4): + swr@2.4.1(react@19.2.5): dependencies: dequal: 2.0.3 - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) symbol-tree@3.2.4: {} @@ -7372,9 +7372,9 @@ snapshots: tabbable@6.4.0: {} - tailwind-scrollbar@4.0.2(react@19.2.4)(tailwindcss@4.1.18): + tailwind-scrollbar@4.0.2(react@19.2.5)(tailwindcss@4.1.18): dependencies: - prism-react-renderer: 2.4.1(react@19.2.4) + prism-react-renderer: 2.4.1(react@19.2.5) tailwindcss: 4.1.18 transitivePeerDependencies: - react @@ -7566,13 +7566,13 @@ snapshots: dependencies: punycode: 2.3.1 - use-sync-external-store@1.5.0(react@19.2.4): + use-sync-external-store@1.5.0(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 - use-sync-external-store@1.6.0(react@19.2.4): + use-sync-external-store@1.6.0(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 util-deprecate@1.0.2: {} From ffb264cead1521cfda91baed913cdac26ff8eac8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 04:20:22 +0000 Subject: [PATCH 48/56] Chore(deps): Bump next from 16.2.3 to 16.2.4 (#6622) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 123 ++++++++++++++++++++++++++----------------------- 2 files changed, 66 insertions(+), 59 deletions(-) diff --git a/package.json b/package.json index 7f946d508..1933a3133 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "luxon": "^3.6.1", "memory-cache": "^0.2.0", "minecraftstatuspinger": "^1.2.2", - "next": "^16.2.3", + "next": "^16.2.4", "next-i18next": "^15.4.3", "ping": "^0.4.4", "pretty-bytes": "^7.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f33832625..dfb654e21 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,11 +51,11 @@ importers: specifier: ^1.2.2 version: 1.2.2 next: - specifier: ^16.2.3 - version: 16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: ^16.2.4 + version: 16.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next-i18next: specifier: ^15.4.3 - version: 15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3))(react@19.2.5) + version: 15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3))(react@19.2.5) ping: specifier: ^0.4.4 version: 0.4.4 @@ -290,8 +290,8 @@ packages: '@emnapi/core@1.4.0': resolution: {integrity: sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==} - '@emnapi/runtime@1.9.2': - resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} '@emnapi/wasi-threads@1.0.1': resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} @@ -773,56 +773,56 @@ packages: '@napi-rs/wasm-runtime@0.2.8': resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==} - '@next/env@16.2.3': - resolution: {integrity: sha512-ZWXyj4uNu4GCWQw9cjRxWlbD+33mcDszIo9iQxFnBX3Wmgq9ulaSJcl6VhuWx5pCWqqD+9W6Wfz7N0lM5lYPMA==} + '@next/env@16.2.4': + resolution: {integrity: sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw==} '@next/eslint-plugin-next@15.5.11': resolution: {integrity: sha512-tS/HYQOjIoX9ZNDQitba/baS8sTvo3ekY6Vgdx5lmhN4jov082bdApIChXr94qhMZHvEciz9DZglFFnhguQp/A==} - '@next/swc-darwin-arm64@16.2.3': - resolution: {integrity: sha512-u37KDKTKQ+OQLvY+z7SNXixwo4Q2/IAJFDzU1fYe66IbCE51aDSAzkNDkWmLN0yjTUh4BKBd+hb69jYn6qqqSg==} + '@next/swc-darwin-arm64@16.2.4': + resolution: {integrity: sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.2.3': - resolution: {integrity: sha512-gHjL/qy6Q6CG3176FWbAKyKh9IfntKZTB3RY/YOJdDFpHGsUDXVH38U4mMNpHVGXmeYW4wj22dMp1lTfmu/bTQ==} + '@next/swc-darwin-x64@16.2.4': + resolution: {integrity: sha512-XhpVnUfmYWvD3YrXu55XdcAkQtOnvaI6wtQa8fuF5fGoKoxIUZ0kWPtcOfqJEWngFF/lOS9l3+O9CcownhiQxQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.2.3': - resolution: {integrity: sha512-U6vtblPtU/P14Y/b/n9ZY0GOxbbIhTFuaFR7F4/uMBidCi2nSdaOFhA0Go81L61Zd6527+yvuX44T4ksnf8T+Q==} + '@next/swc-linux-arm64-gnu@16.2.4': + resolution: {integrity: sha512-Mx/tjlNA3G8kg14QvuGAJ4xBwPk1tUHq56JxZ8CXnZwz1Etz714soCEzGQQzVMz4bEnGPowzkV6Xrp6wAkEWOQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.2.3': - resolution: {integrity: sha512-/YV0LgjHUmfhQpn9bVoGc4x4nan64pkhWR5wyEV8yCOfwwrH630KpvRg86olQHTwHIn1z59uh6JwKvHq1h4QEw==} + '@next/swc-linux-arm64-musl@16.2.4': + resolution: {integrity: sha512-iVMMp14514u7Nup2umQS03nT/bN9HurK8ufylC3FZNykrwjtx7V1A7+4kvhbDSCeonTVqV3Txnv0Lu+m2oDXNg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@16.2.3': - resolution: {integrity: sha512-/HiWEcp+WMZ7VajuiMEFGZ6cg0+aYZPqCJD3YJEfpVWQsKYSjXQG06vJP6F1rdA03COD9Fef4aODs3YxKx+RDQ==} + '@next/swc-linux-x64-gnu@16.2.4': + resolution: {integrity: sha512-EZOvm1aQWgnI/N/xcWOlnS3RQBk0VtVav5Zo7n4p0A7UKyTDx047k8opDbXgBpHl4CulRqRfbw3QrX2w5UOXMQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.2.3': - resolution: {integrity: sha512-Kt44hGJfZSefebhk/7nIdivoDr3Ugp5+oNz9VvF3GUtfxutucUIHfIO0ZYO8QlOPDQloUVQn4NVC/9JvHRk9hw==} + '@next/swc-linux-x64-musl@16.2.4': + resolution: {integrity: sha512-h9FxsngCm9cTBf71AR4fGznDEDx1hS7+kSEiIRjq5kO1oXWm07DxVGZjCvk0SGx7TSjlUqhI8oOyz7NfwAdPoA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@16.2.3': - resolution: {integrity: sha512-O2NZ9ie3Tq6xj5Z5CSwBT3+aWAMW2PIZ4egUi9MaWLkwaehgtB7YZjPm+UpcNpKOme0IQuqDcor7BsW6QBiQBw==} + '@next/swc-win32-arm64-msvc@16.2.4': + resolution: {integrity: sha512-3NdJV5OXMSOeJYijX+bjaLge3mJBlh4ybydbT4GFoB/2hAojWHtMhl3CYlYoMrjPuodp0nzFVi4Tj2+WaMg+Ow==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.2.3': - resolution: {integrity: sha512-Ibm29/GgB/ab5n7XKqlStkm54qqZE8v2FnijUPBgrd67FWrac45o/RsNlaOWjme/B5UqeWt/8KM4aWBwA1D2Kw==} + '@next/swc-win32-x64-msvc@16.2.4': + resolution: {integrity: sha512-kMVGgsqhO5YTYODD9IPGGhA6iprWidQckK3LmPeW08PIFENRmgfb4MjXHO+p//d+ts2rpjvK5gXWzXSMrPl9cw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1577,8 +1577,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.17: - resolution: {integrity: sha512-HdrkN8eVG2CXxeifv/VdJ4A4RSra1DTW8dc/hdxzhGHN8QePs6gKaWM9pHPcpCoxYZJuOZ8drHmbdpLHjCYjLA==} + baseline-browser-mapping@2.10.27: + resolution: {integrity: sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==} engines: {node: '>=6.0.0'} hasBin: true @@ -1644,8 +1644,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001787: - resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==} + caniuse-lite@1.0.30001791: + resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==} chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} @@ -2868,6 +2868,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -2883,8 +2888,8 @@ packages: react: '>= 17.0.2' react-i18next: '>= 13.5.0' - next@16.2.3: - resolution: {integrity: sha512-9V3zV4oZFza3PVev5/poB9g0dEafVcgNyQ8eTRop8GvxZjV2G15FC5ARuG1eFD42QgeYkzJBJzHghNP8Ad9xtA==} + next@16.2.4: + resolution: {integrity: sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -4002,7 +4007,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.2': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true @@ -4300,7 +4305,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.9.2 + '@emnapi/runtime': 1.10.0 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -4396,38 +4401,38 @@ snapshots: '@napi-rs/wasm-runtime@0.2.8': dependencies: '@emnapi/core': 1.4.0 - '@emnapi/runtime': 1.9.2 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.9.0 optional: true - '@next/env@16.2.3': {} + '@next/env@16.2.4': {} '@next/eslint-plugin-next@15.5.11': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@16.2.3': + '@next/swc-darwin-arm64@16.2.4': optional: true - '@next/swc-darwin-x64@16.2.3': + '@next/swc-darwin-x64@16.2.4': optional: true - '@next/swc-linux-arm64-gnu@16.2.3': + '@next/swc-linux-arm64-gnu@16.2.4': optional: true - '@next/swc-linux-arm64-musl@16.2.3': + '@next/swc-linux-arm64-musl@16.2.4': optional: true - '@next/swc-linux-x64-gnu@16.2.3': + '@next/swc-linux-x64-gnu@16.2.4': optional: true - '@next/swc-linux-x64-musl@16.2.3': + '@next/swc-linux-x64-musl@16.2.4': optional: true - '@next/swc-win32-arm64-msvc@16.2.3': + '@next/swc-win32-arm64-msvc@16.2.4': optional: true - '@next/swc-win32-x64-msvc@16.2.3': + '@next/swc-win32-x64-msvc@16.2.4': optional: true '@nodelib/fs.scandir@2.1.5': @@ -5149,7 +5154,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.17: {} + baseline-browser-mapping@2.10.27: {} bcrypt-pbkdf@1.0.2: dependencies: @@ -5226,7 +5231,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001787: {} + caniuse-lite@1.0.30001791: {} chai@5.3.3: dependencies: @@ -6626,11 +6631,13 @@ snapshots: nanoid@3.3.11: {} + nanoid@3.3.12: {} + natural-compare@1.4.0: {} net@1.0.2: {} - next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3))(react@19.2.5): + next-i18next@15.4.3(@types/react@19.0.10)(i18next@25.10.9(typescript@5.7.3))(next@16.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-i18next@15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3))(react@19.2.5): dependencies: '@babel/runtime': 7.28.6 '@types/hoist-non-react-statics': 3.3.7(@types/react@19.0.10) @@ -6638,31 +6645,31 @@ snapshots: hoist-non-react-statics: 3.3.2 i18next: 25.10.9(typescript@5.7.3) i18next-fs-backend: 2.6.4 - next: 16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 16.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-i18next: 15.5.3(i18next@25.10.9(typescript@5.7.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.7.3) transitivePeerDependencies: - '@types/react' - next@16.2.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + next@16.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: - '@next/env': 16.2.3 + '@next/env': 16.2.4 '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.17 - caniuse-lite: 1.0.30001787 + baseline-browser-mapping: 2.10.27 + caniuse-lite: 1.0.30001791 postcss: 8.4.31 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) styled-jsx: 5.1.6(react@19.2.5) optionalDependencies: - '@next/swc-darwin-arm64': 16.2.3 - '@next/swc-darwin-x64': 16.2.3 - '@next/swc-linux-arm64-gnu': 16.2.3 - '@next/swc-linux-arm64-musl': 16.2.3 - '@next/swc-linux-x64-gnu': 16.2.3 - '@next/swc-linux-x64-musl': 16.2.3 - '@next/swc-win32-arm64-msvc': 16.2.3 - '@next/swc-win32-x64-msvc': 16.2.3 + '@next/swc-darwin-arm64': 16.2.4 + '@next/swc-darwin-x64': 16.2.4 + '@next/swc-linux-arm64-gnu': 16.2.4 + '@next/swc-linux-arm64-musl': 16.2.4 + '@next/swc-linux-x64-gnu': 16.2.4 + '@next/swc-linux-x64-musl': 16.2.4 + '@next/swc-win32-arm64-msvc': 16.2.4 + '@next/swc-win32-x64-msvc': 16.2.4 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' @@ -6795,7 +6802,7 @@ snapshots: postcss@8.4.31: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 From 72b0e493d0e91e1a4c68ad3fe9d2cf7063ca8053 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 5 May 2026 13:30:12 -0700 Subject: [PATCH 49/56] Enhancement: Normalize non-200 proxy responses to error JSON (#6630) --- src/utils/proxy/handlers/credentialed.js | 8 ++++++++ src/utils/proxy/handlers/credentialed.test.js | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index afe53457d..e97bf97d9 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -158,6 +158,14 @@ export default async function credentialedProxyHandler(req, res, map) { if (status >= 400) { logger.error("HTTP Error %d calling %s", status, url.toString()); + return res.status(status).json({ + error: { + message: resultData?.error?.message ?? "HTTP Error", + url: sanitizeErrorURL(url), + ...(resultData?.error?.rawError ? { rawError: resultData.error.rawError } : {}), + data: Buffer.isBuffer(resultData) ? Buffer.from(resultData).toString() : resultData, + }, + }); } if (status === 200) { diff --git a/src/utils/proxy/handlers/credentialed.test.js b/src/utils/proxy/handlers/credentialed.test.js index ef720669a..663191ca9 100644 --- a/src/utils/proxy/handlers/credentialed.test.js +++ b/src/utils/proxy/handlers/credentialed.test.js @@ -250,6 +250,25 @@ describe("utils/proxy/handlers/credentialed", () => { expect(params.headers).toEqual(expect.objectContaining(expected)); }); + it("normalizes non-200 JSON responses into widget error payloads", async () => { + getServiceWidget.mockResolvedValue({ type: "paperlessngx", url: "http://x", key: "k" }); + httpProxy.mockResolvedValue([401, "application/json", { detail: "Invalid token." }]); + + const req = { method: "GET", query: { group: "g", service: "s", endpoint: "statistics", index: 0 } }; + const res = createMockRes(); + + await credentialedProxyHandler(req, res); + + expect(res.statusCode).toBe(401); + expect(res.body).toEqual({ + error: { + message: "HTTP Error", + url: "http://x/api/statistics", + data: { detail: "Invalid token." }, + }, + }); + }); + it("uses basic auth for esphome when username/password are provided", async () => { getServiceWidget.mockResolvedValue({ type: "esphome", url: "http://x", username: "u", password: "p" }); httpProxy.mockResolvedValue([200, "application/json", { ok: true }]); From ce8f020b7bebd3376558d224b211590087077943 Mon Sep 17 00:00:00 2001 From: Rob van Oostenrijk Date: Thu, 7 May 2026 10:58:48 +0400 Subject: [PATCH 50/56] Enhancement: Add node parameter to Technitium DNS Widget (#6638) --- docs/widgets/services/technitium.md | 5 +++++ src/utils/config/service-helpers.js | 1 + src/widgets/technitium/component.jsx | 1 + src/widgets/technitium/widget.js | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/widgets/services/technitium.md b/docs/widgets/services/technitium.md index 70f5e48f5..5ef8ead23 100644 --- a/docs/widgets/services/technitium.md +++ b/docs/widgets/services/technitium.md @@ -14,6 +14,7 @@ widget: type: technitium url: key: biglongapitoken + node: # optional, defaults to current node range: LastDay # optional, defaults to LastHour ``` @@ -21,6 +22,10 @@ widget: This can be generated via the Technitium DNS Dashboard, and should be generated from a special API specific user. +#### Node + +`node` value determines which Technitium cluster node the statistics are returned for. Specifying a value of `cluster` returns aggregrate stats for all nodes in the cluster. Specify a node domain name to return specific node stats, no value returns stats for the node against which the API is executed. + #### Range `range` value determines how far back of statistics to pull data for. The value comes directly from Technitium API documentation found [here](https://github.com/TechnitiumSoftware/DnsServer/blob/master/APIDOCS.md#dashboard-api-calls), defined as `"type"`. The value can be one of: `LastHour`, `LastDay`, `LastWeek`, `LastMonth`, `LastYear`. diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index f68916f74..6a87f8423 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -665,6 +665,7 @@ export function cleanServiceGroups(groups) { if (enableRecentEvents !== undefined) widget.enableRecentEvents = enableRecentEvents; } if (type === "technitium") { + if (node !== undefined) widget.node = node; if (range !== undefined) widget.range = range; } if (type === "lubelogger") { diff --git a/src/widgets/technitium/component.jsx b/src/widgets/technitium/component.jsx index fa221025b..07911c7c2 100644 --- a/src/widgets/technitium/component.jsx +++ b/src/widgets/technitium/component.jsx @@ -14,6 +14,7 @@ export default function Component({ service }) { const { widget } = service; const params = { + node: widget.node ?? "", type: widget.range ?? "LastHour", }; diff --git a/src/widgets/technitium/widget.js b/src/widgets/technitium/widget.js index fc4577bef..8755d8e6a 100644 --- a/src/widgets/technitium/widget.js +++ b/src/widgets/technitium/widget.js @@ -8,7 +8,7 @@ const widget = { stats: { endpoint: "dashboard/stats/get", validate: ["response", "status"], - params: ["type"], + params: ["node", "type"], map: (data) => asJson(data).response?.stats, }, }, From 23e66a265d3eb716f8b57fcafe05b7fa57eb49d8 Mon Sep 17 00:00:00 2001 From: Thielquis Date: Thu, 7 May 2026 16:15:25 +0200 Subject: [PATCH 51/56] Fix: Make calendar hover event toggle explicit (#6639) Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- src/widgets/calendar/event.jsx | 6 ++-- src/widgets/calendar/event.test.jsx | 50 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/widgets/calendar/event.jsx b/src/widgets/calendar/event.jsx index ff06b32be..66abf2f6f 100644 --- a/src/widgets/calendar/event.jsx +++ b/src/widgets/calendar/event.jsx @@ -39,8 +39,8 @@ export default function Event({ event, colorVariants, showDate = false, showTime return event.url ? ( setHover(!hover)} - onMouseLeave={() => setHover(!hover)} + onMouseEnter={() => setHover(true)} + onMouseLeave={() => setHover(false)} key={key} href={event.url} target="_blank" @@ -49,7 +49,7 @@ export default function Event({ event, colorVariants, showDate = false, showTime {children} ) : ( -
setHover(!hover)} onMouseLeave={() => setHover(!hover)} key={key}> +
setHover(true)} onMouseLeave={() => setHover(false)} key={key}> {children}
); diff --git a/src/widgets/calendar/event.test.jsx b/src/widgets/calendar/event.test.jsx index 56b37b159..048bf4372 100644 --- a/src/widgets/calendar/event.test.jsx +++ b/src/widgets/calendar/event.test.jsx @@ -48,6 +48,56 @@ describe("widgets/calendar/event", () => { expect(link.querySelector("svg")).toBeTruthy(); }); + it("keeps additional text visible after repeated mouse enter events", () => { + const date = DateTime.fromISO("2099-01-01T13:00:00.000Z").setZone("utc"); + + render( + , + ); + + const link = screen.getByRole("link", { name: /primary/i }); + + fireEvent.mouseEnter(link); + fireEvent.mouseEnter(link); + expect(screen.getByText("More info")).toBeInTheDocument(); + expect(screen.queryByText("Primary")).toBeNull(); + }); + + it("keeps title visible after repeated mouse leave events", () => { + const date = DateTime.fromISO("2099-01-01T13:00:00.000Z").setZone("utc"); + + render( + , + ); + + const event = screen.getByText("Primary").closest("div.flex"); + + fireEvent.mouseEnter(event); + expect(screen.getByText("More info")).toBeInTheDocument(); + + fireEvent.mouseLeave(event); + fireEvent.mouseLeave(event); + expect(screen.getByText("Primary")).toBeInTheDocument(); + expect(screen.queryByText("More info")).toBeNull(); + }); + it("compareDateTimezone matches dates by day", () => { const day = DateTime.fromISO("2099-01-01T00:00:00.000Z").setZone("utc"); expect(compareDateTimezone(day, { date: DateTime.fromISO("2099-01-01T23:59:00.000Z").setZone("utc") })).toBe(true); From 9a983a5be1fcede03eb9dd5436814b61359be61a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 09:50:03 -0700 Subject: [PATCH 52/56] Chore(deps): Bump pnpm/action-setup from 6.0.3 to 6.0.4 (#6642) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-publish.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index e10e4cb44..f6ed99303 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -61,7 +61,7 @@ jobs: nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Install pnpm - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 + uses: pnpm/action-setup@26f6d4f2c533a43e6b5da0b4a5dd983f98f7b49a # v6.0.4 with: version: 10 run_install: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ab5c8a7bc..f1643bc62 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -23,7 +23,7 @@ jobs: uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 - name: Install pnpm - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 + uses: pnpm/action-setup@26f6d4f2c533a43e6b5da0b4a5dd983f98f7b49a # v6.0.4 with: version: 10 run_install: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 95b72adcd..d27f26e9c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 + - uses: pnpm/action-setup@26f6d4f2c533a43e6b5da0b4a5dd983f98f7b49a # v6.0.4 with: version: 9 From 4603e0ee579eec5dff911dfe290a6c5841974540 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 16:54:39 +0000 Subject: [PATCH 53/56] Chore(deps): Bump release-drafter/release-drafter from 7.2.0 to 7.2.1 (#6641) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-drafter.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 083c04af4..558b72354 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -26,14 +26,14 @@ jobs: runs-on: ubuntu-latest steps: - if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' - uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7 + uses: release-drafter/release-drafter@563bf132657a13ded0b01fcb723c5a58cdd824e2 # v7 with: config-name: release-drafter.yml version: ${{ github.event.inputs.version }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == '' - uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7 + uses: release-drafter/release-drafter@563bf132657a13ded0b01fcb723c5a58cdd824e2 # v7 with: config-name: release-drafter.yml env: @@ -47,7 +47,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter/autolabeler@5de93583980a40bd78603b6dfdcda5b4df377b32 + - uses: release-drafter/release-drafter/autolabeler@563bf132657a13ded0b01fcb723c5a58cdd824e2 with: config-name: release-drafter.yml env: From 6d1e56bca084fd317a59fc9163677ffc028ccd1c Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 8 May 2026 13:36:24 -0700 Subject: [PATCH 54/56] Update bug report template for issue closure notice --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b799d3e43..5f0301c20 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -15,7 +15,7 @@ body: options: - label: I confirm this was discussed, and the maintainers asked that I open an issue. required: true - - label: I am aware that if I create this issue without a discussion, it will be removed without a response. + - label: I am aware that if I create this issue without a discussion, it will be closed without a response. required: true - type: input id: discussion From aab4f5125b892e3a09d31870b501cb15b6cd4f9f Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 8 May 2026 15:09:17 -0700 Subject: [PATCH 55/56] Chore: add pnpm workspace allowBuilds config (#6645) --- package.json | 7 ------- pnpm-workspace.yaml | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 pnpm-workspace.yaml diff --git a/package.json b/package.json index 1933a3133..a36a9df8c 100644 --- a/package.json +++ b/package.json @@ -74,12 +74,5 @@ }, "optionalDependencies": { "osx-temperature-sensor": "^1.0.8" - }, - "pnpm": { - "onlyBuiltDependencies": [ - "@tailwindcss/oxide", - "osx-temperature-sensor", - "sharp" - ] } } diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 000000000..13e025040 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,18 @@ +packages: + - . + +allowBuilds: + '@tailwindcss/oxide': true + core-js: false + cpu-features: false + esbuild: false + osx-temperature-sensor: true + protobufjs: false + sharp: true + ssh2: false + +onlyBuiltDependencies: + - '@tailwindcss/oxide' + - osx-temperature-sensor + - protobufjs + - sharp From bb765a6747aaacf3b489cc4fbe2c94347a6521b4 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 8 May 2026 15:53:50 -0700 Subject: [PATCH 56/56] 1.13.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a36a9df8c..3bbc8c04b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homepage", - "version": "1.12.3", + "version": "1.13.0", "private": true, "scripts": { "preinstall": "npx only-allow pnpm",