mirror of
https://github.com/gethomepage/homepage.git
synced 2026-04-14 06:01:20 -07:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb245cf104 | ||
|
|
a7bab17f97 | ||
|
|
1accddf29a | ||
|
|
636d62106c | ||
|
|
d048888d99 | ||
|
|
24804f39fc | ||
|
|
70f8c67d3c | ||
|
|
038f5c3b9f | ||
|
|
ade4c733c7 | ||
|
|
bdbd2e6ff0 | ||
|
|
5f4b0b4e33 | ||
|
|
a56a05b553 | ||
|
|
11d1ceb755 | ||
|
|
6df1cfdeba | ||
|
|
d64fbae776 | ||
|
|
5f7e5430c4 | ||
|
|
3cc3986ec3 | ||
|
|
5af0ab1686 | ||
|
|
f0f5c3c15c | ||
|
|
2ed1da4411 | ||
|
|
e1023466b1 | ||
|
|
9fe5ad62f1 | ||
|
|
173883000f |
7
.github/workflows/docker-publish.yml
vendored
7
.github/workflows/docker-publish.yml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- feature/**
|
- feature/**
|
||||||
|
- fix/**
|
||||||
- dev
|
- dev
|
||||||
tags: [ 'v*.*.*' ]
|
tags: [ 'v*.*.*' ]
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -60,7 +61,7 @@ jobs:
|
|||||||
nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
run_install: false
|
run_install: false
|
||||||
@@ -83,7 +84,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Log into registry ${{ env.REGISTRY }}
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -91,7 +92,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|||||||
8
.github/workflows/docs-publish.yml
vendored
8
.github/workflows/docs-publish.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version-file: ".python-version"
|
python-version-file: ".python-version"
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7
|
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
|
||||||
- run: sudo apt-get install pngquant
|
- run: sudo apt-get install pngquant
|
||||||
- name: Test Docs Build
|
- name: Test Docs Build
|
||||||
run: uv run --frozen zensical build --clean
|
run: uv run --frozen zensical build --clean
|
||||||
@@ -37,18 +37,18 @@ jobs:
|
|||||||
name: github-pages
|
name: github-pages
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
|
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
||||||
with:
|
with:
|
||||||
python-version-file: ".python-version"
|
python-version-file: ".python-version"
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7
|
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
|
||||||
- run: sudo apt-get install pngquant
|
- run: sudo apt-get install pngquant
|
||||||
- name: Build Docs
|
- name: Build Docs
|
||||||
run: uv run --frozen zensical build --clean
|
run: uv run --frozen zensical build --clean
|
||||||
- uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
|
- uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
|
||||||
with:
|
with:
|
||||||
path: site
|
path: site
|
||||||
- uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
|
- uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
||||||
id: deployment
|
id: deployment
|
||||||
|
|||||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|||||||
2
.github/workflows/pr-quality.yml
vendored
2
.github/workflows/pr-quality.yml
vendored
@@ -13,6 +13,6 @@ jobs:
|
|||||||
anti-slop:
|
anti-slop:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: peakoss/anti-slop@a5a4b2440c9de6f65b64f0718a0136a1fdb04f6f # v0
|
- uses: peakoss/anti-slop@85daca1880e9e1af197fc06ea03349daf08f4202 # v0
|
||||||
with:
|
with:
|
||||||
max-failures: 4
|
max-failures: 4
|
||||||
|
|||||||
6
.github/workflows/release-drafter.yml
vendored
6
.github/workflows/release-drafter.yml
vendored
@@ -26,14 +26,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
- 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:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
version: ${{ github.event.inputs.version }}
|
version: ${{ github.event.inputs.version }}
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == ''
|
- 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:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
env:
|
env:
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: release-drafter/release-drafter/autolabeler@ebb69bb56f1b0ebd19897745035726b19bef973e
|
- uses: release-drafter/release-drafter/autolabeler@139054aeaa9adc52ab36ddf67437541f039b88e2
|
||||||
with:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
env:
|
env:
|
||||||
|
|||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
- uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5
|
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||||
with:
|
with:
|
||||||
version: 9
|
version: 9
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
# Run Vitest directly so `--shard` is parsed as an option
|
# Run Vitest directly so `--shard` is parsed as an option
|
||||||
- run: pnpm -s exec vitest run --coverage --shard ${{ matrix.shard }}/4 --pool forks
|
- run: pnpm -s exec vitest run --coverage --shard ${{ matrix.shard }}/4 --pool forks
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5
|
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./coverage/lcov.info
|
files: ./coverage/lcov.info
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ Use the `gethomepage.dev/pod-selector` selector to specify the pod used for the
|
|||||||
|
|
||||||
### Traefik IngressRoute support
|
### 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
|
```yaml
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ widget:
|
|||||||
url: http://pyload.host.or.ip:port
|
url: http://pyload.host.or.ip:port
|
||||||
username: username
|
username: username
|
||||||
password: password # only needed if set
|
password: password # only needed if set
|
||||||
|
key: pyloadapikey # only needed if set, takes precedence over username/password
|
||||||
```
|
```
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -18,17 +18,17 @@
|
|||||||
"@kubernetes/client-node": "^1.0.0",
|
"@kubernetes/client-node": "^1.0.0",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"compare-versions": "^6.1.1",
|
"compare-versions": "^6.1.1",
|
||||||
"dockerode": "^4.0.7",
|
"dockerode": "^4.0.10",
|
||||||
"follow-redirects": "^1.15.11",
|
"follow-redirects": "^1.15.11",
|
||||||
"gamedig": "^5.3.2",
|
"gamedig": "^5.3.2",
|
||||||
"i18next": "^25.8.0",
|
"i18next": "^25.10.9",
|
||||||
"ical.js": "^2.2.1",
|
"ical.js": "^2.2.1",
|
||||||
"js-yaml": "^4.1.1",
|
"js-yaml": "^4.1.1",
|
||||||
"json-rpc-2.0": "^1.7.0",
|
"json-rpc-2.0": "^1.7.0",
|
||||||
"luxon": "^3.6.1",
|
"luxon": "^3.6.1",
|
||||||
"memory-cache": "^0.2.0",
|
"memory-cache": "^0.2.0",
|
||||||
"minecraftstatuspinger": "^1.2.2",
|
"minecraftstatuspinger": "^1.2.2",
|
||||||
"next": "^16.1.7",
|
"next": "^16.2.3",
|
||||||
"next-i18next": "^15.4.3",
|
"next-i18next": "^15.4.3",
|
||||||
"ping": "^0.4.4",
|
"ping": "^0.4.4",
|
||||||
"pretty-bytes": "^7.1.0",
|
"pretty-bytes": "^7.1.0",
|
||||||
@@ -47,10 +47,10 @@
|
|||||||
"xml-js": "^1.6.11"
|
"xml-js": "^1.6.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/compat": "^2.0.2",
|
"@eslint/compat": "^2.0.3",
|
||||||
"@eslint/eslintrc": "^3.3.3",
|
"@eslint/eslintrc": "^3.3.3",
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^9.39.2",
|
||||||
"@tailwindcss/forms": "^0.5.10",
|
"@tailwindcss/forms": "^0.5.11",
|
||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.1.18",
|
||||||
"@testing-library/jest-dom": "^6.8.0",
|
"@testing-library/jest-dom": "^6.8.0",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
"eslint-plugin-react": "^7.37.4",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"jsdom": "^28.1.0",
|
"jsdom": "^28.1.0",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.8",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-organize-imports": "^4.3.0",
|
"prettier-plugin-organize-imports": "^4.3.0",
|
||||||
"tailwind-scrollbar": "^4.0.2",
|
"tailwind-scrollbar": "^4.0.2",
|
||||||
|
|||||||
344
pnpm-lock.yaml
generated
344
pnpm-lock.yaml
generated
@@ -21,8 +21,8 @@ importers:
|
|||||||
specifier: ^6.1.1
|
specifier: ^6.1.1
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
dockerode:
|
dockerode:
|
||||||
specifier: ^4.0.7
|
specifier: ^4.0.10
|
||||||
version: 4.0.7
|
version: 4.0.10
|
||||||
follow-redirects:
|
follow-redirects:
|
||||||
specifier: ^1.15.11
|
specifier: ^1.15.11
|
||||||
version: 1.15.11
|
version: 1.15.11
|
||||||
@@ -30,8 +30,8 @@ importers:
|
|||||||
specifier: ^5.3.2
|
specifier: ^5.3.2
|
||||||
version: 5.3.2
|
version: 5.3.2
|
||||||
i18next:
|
i18next:
|
||||||
specifier: ^25.8.0
|
specifier: ^25.10.9
|
||||||
version: 25.8.0(typescript@5.7.3)
|
version: 25.10.9(typescript@5.7.3)
|
||||||
ical.js:
|
ical.js:
|
||||||
specifier: ^2.2.1
|
specifier: ^2.2.1
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
@@ -51,11 +51,11 @@ importers:
|
|||||||
specifier: ^1.2.2
|
specifier: ^1.2.2
|
||||||
version: 1.2.2
|
version: 1.2.2
|
||||||
next:
|
next:
|
||||||
specifier: ^16.1.7
|
specifier: ^16.2.3
|
||||||
version: 16.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
version: 16.2.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
next-i18next:
|
next-i18next:
|
||||||
specifier: ^15.4.3
|
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.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:
|
ping:
|
||||||
specifier: ^0.4.4
|
specifier: ^0.4.4
|
||||||
version: 0.4.4
|
version: 0.4.4
|
||||||
@@ -73,7 +73,7 @@ importers:
|
|||||||
version: 19.2.4(react@19.2.4)
|
version: 19.2.4(react@19.2.4)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: ^15.5.3
|
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:
|
react-icons:
|
||||||
specifier: ^5.6.0
|
specifier: ^5.6.0
|
||||||
version: 5.6.0(react@19.2.4)
|
version: 5.6.0(react@19.2.4)
|
||||||
@@ -103,8 +103,8 @@ importers:
|
|||||||
version: 1.6.11
|
version: 1.6.11
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@eslint/compat':
|
'@eslint/compat':
|
||||||
specifier: ^2.0.2
|
specifier: ^2.0.3
|
||||||
version: 2.0.2(eslint@9.25.1(jiti@2.6.1))
|
version: 2.0.3(eslint@9.25.1(jiti@2.6.1))
|
||||||
'@eslint/eslintrc':
|
'@eslint/eslintrc':
|
||||||
specifier: ^3.3.3
|
specifier: ^3.3.3
|
||||||
version: 3.3.3
|
version: 3.3.3
|
||||||
@@ -112,8 +112,8 @@ importers:
|
|||||||
specifier: ^9.39.2
|
specifier: ^9.39.2
|
||||||
version: 9.39.2
|
version: 9.39.2
|
||||||
'@tailwindcss/forms':
|
'@tailwindcss/forms':
|
||||||
specifier: ^0.5.10
|
specifier: ^0.5.11
|
||||||
version: 0.5.10(tailwindcss@4.1.18)
|
version: 0.5.11(tailwindcss@4.1.18)
|
||||||
'@tailwindcss/postcss':
|
'@tailwindcss/postcss':
|
||||||
specifier: ^4.1.18
|
specifier: ^4.1.18
|
||||||
version: 4.1.18
|
version: 4.1.18
|
||||||
@@ -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)
|
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':
|
'@vitest/coverage-v8':
|
||||||
specifier: ^3.2.4
|
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:
|
eslint:
|
||||||
specifier: ^9.25.1
|
specifier: ^9.25.1
|
||||||
version: 9.25.1(jiti@2.6.1)
|
version: 9.25.1(jiti@2.6.1)
|
||||||
@@ -154,8 +154,8 @@ importers:
|
|||||||
specifier: ^28.1.0
|
specifier: ^28.1.0
|
||||||
version: 28.1.0
|
version: 28.1.0
|
||||||
postcss:
|
postcss:
|
||||||
specifier: ^8.5.6
|
specifier: ^8.5.8
|
||||||
version: 8.5.6
|
version: 8.5.8
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.8.1
|
specifier: ^3.8.1
|
||||||
version: 3.8.1
|
version: 3.8.1
|
||||||
@@ -173,7 +173,7 @@ importers:
|
|||||||
version: 5.7.3
|
version: 5.7.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^3.2.4
|
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:
|
optionalDependencies:
|
||||||
osx-temperature-sensor:
|
osx-temperature-sensor:
|
||||||
specifier: ^1.0.8
|
specifier: ^1.0.8
|
||||||
@@ -290,8 +290,8 @@ packages:
|
|||||||
'@emnapi/core@1.4.0':
|
'@emnapi/core@1.4.0':
|
||||||
resolution: {integrity: sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==}
|
resolution: {integrity: sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==}
|
||||||
|
|
||||||
'@emnapi/runtime@1.9.0':
|
'@emnapi/runtime@1.9.2':
|
||||||
resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==}
|
resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==}
|
||||||
|
|
||||||
'@emnapi/wasi-threads@1.0.1':
|
'@emnapi/wasi-threads@1.0.1':
|
||||||
resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==}
|
resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==}
|
||||||
@@ -462,8 +462,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
|
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
|
||||||
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||||
|
|
||||||
'@eslint/compat@2.0.2':
|
'@eslint/compat@2.0.3':
|
||||||
resolution: {integrity: sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==}
|
resolution: {integrity: sha512-SjIJhGigp8hmd1YGIBwh7Ovri7Kisl42GYFjrOyHhtfYGGoLW6teYi/5p8W50KSsawUPpuLOSmsq1bD0NGQLBw==}
|
||||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.40 || 9 || 10
|
eslint: ^8.40 || 9 || 10
|
||||||
@@ -483,8 +483,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==}
|
resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@eslint/core@1.1.0':
|
'@eslint/core@1.1.1':
|
||||||
resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==}
|
resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==}
|
||||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
'@eslint/eslintrc@3.3.3':
|
'@eslint/eslintrc@3.3.3':
|
||||||
@@ -537,8 +537,8 @@ packages:
|
|||||||
'@floating-ui/utils@0.2.10':
|
'@floating-ui/utils@0.2.10':
|
||||||
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
|
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
|
||||||
|
|
||||||
'@grpc/grpc-js@1.13.4':
|
'@grpc/grpc-js@1.14.3':
|
||||||
resolution: {integrity: sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg==}
|
resolution: {integrity: sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==}
|
||||||
engines: {node: '>=12.10.0'}
|
engines: {node: '>=12.10.0'}
|
||||||
|
|
||||||
'@grpc/proto-loader@0.7.15':
|
'@grpc/proto-loader@0.7.15':
|
||||||
@@ -546,6 +546,11 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
'@grpc/proto-loader@0.8.0':
|
||||||
|
resolution: {integrity: sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
'@headlessui/react@2.2.9':
|
'@headlessui/react@2.2.9':
|
||||||
resolution: {integrity: sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==}
|
resolution: {integrity: sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -759,56 +764,56 @@ packages:
|
|||||||
'@napi-rs/wasm-runtime@0.2.8':
|
'@napi-rs/wasm-runtime@0.2.8':
|
||||||
resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==}
|
resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==}
|
||||||
|
|
||||||
'@next/env@16.1.7':
|
'@next/env@16.2.3':
|
||||||
resolution: {integrity: sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==}
|
resolution: {integrity: sha512-ZWXyj4uNu4GCWQw9cjRxWlbD+33mcDszIo9iQxFnBX3Wmgq9ulaSJcl6VhuWx5pCWqqD+9W6Wfz7N0lM5lYPMA==}
|
||||||
|
|
||||||
'@next/eslint-plugin-next@15.5.11':
|
'@next/eslint-plugin-next@15.5.11':
|
||||||
resolution: {integrity: sha512-tS/HYQOjIoX9ZNDQitba/baS8sTvo3ekY6Vgdx5lmhN4jov082bdApIChXr94qhMZHvEciz9DZglFFnhguQp/A==}
|
resolution: {integrity: sha512-tS/HYQOjIoX9ZNDQitba/baS8sTvo3ekY6Vgdx5lmhN4jov082bdApIChXr94qhMZHvEciz9DZglFFnhguQp/A==}
|
||||||
|
|
||||||
'@next/swc-darwin-arm64@16.1.7':
|
'@next/swc-darwin-arm64@16.2.3':
|
||||||
resolution: {integrity: sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==}
|
resolution: {integrity: sha512-u37KDKTKQ+OQLvY+z7SNXixwo4Q2/IAJFDzU1fYe66IbCE51aDSAzkNDkWmLN0yjTUh4BKBd+hb69jYn6qqqSg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@next/swc-darwin-x64@16.1.7':
|
'@next/swc-darwin-x64@16.2.3':
|
||||||
resolution: {integrity: sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==}
|
resolution: {integrity: sha512-gHjL/qy6Q6CG3176FWbAKyKh9IfntKZTB3RY/YOJdDFpHGsUDXVH38U4mMNpHVGXmeYW4wj22dMp1lTfmu/bTQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-gnu@16.1.7':
|
'@next/swc-linux-arm64-gnu@16.2.3':
|
||||||
resolution: {integrity: sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==}
|
resolution: {integrity: sha512-U6vtblPtU/P14Y/b/n9ZY0GOxbbIhTFuaFR7F4/uMBidCi2nSdaOFhA0Go81L61Zd6527+yvuX44T4ksnf8T+Q==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-musl@16.1.7':
|
'@next/swc-linux-arm64-musl@16.2.3':
|
||||||
resolution: {integrity: sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==}
|
resolution: {integrity: sha512-/YV0LgjHUmfhQpn9bVoGc4x4nan64pkhWR5wyEV8yCOfwwrH630KpvRg86olQHTwHIn1z59uh6JwKvHq1h4QEw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-linux-x64-gnu@16.1.7':
|
'@next/swc-linux-x64-gnu@16.2.3':
|
||||||
resolution: {integrity: sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==}
|
resolution: {integrity: sha512-/HiWEcp+WMZ7VajuiMEFGZ6cg0+aYZPqCJD3YJEfpVWQsKYSjXQG06vJP6F1rdA03COD9Fef4aODs3YxKx+RDQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-linux-x64-musl@16.1.7':
|
'@next/swc-linux-x64-musl@16.2.3':
|
||||||
resolution: {integrity: sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==}
|
resolution: {integrity: sha512-Kt44hGJfZSefebhk/7nIdivoDr3Ugp5+oNz9VvF3GUtfxutucUIHfIO0ZYO8QlOPDQloUVQn4NVC/9JvHRk9hw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-win32-arm64-msvc@16.1.7':
|
'@next/swc-win32-arm64-msvc@16.2.3':
|
||||||
resolution: {integrity: sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==}
|
resolution: {integrity: sha512-O2NZ9ie3Tq6xj5Z5CSwBT3+aWAMW2PIZ4egUi9MaWLkwaehgtB7YZjPm+UpcNpKOme0IQuqDcor7BsW6QBiQBw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@next/swc-win32-x64-msvc@16.1.7':
|
'@next/swc-win32-x64-msvc@16.2.3':
|
||||||
resolution: {integrity: sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==}
|
resolution: {integrity: sha512-Ibm29/GgB/ab5n7XKqlStkm54qqZE8v2FnijUPBgrd67FWrac45o/RsNlaOWjme/B5UqeWt/8KM4aWBwA1D2Kw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@@ -1062,15 +1067,15 @@ packages:
|
|||||||
'@swc/helpers@0.5.15':
|
'@swc/helpers@0.5.15':
|
||||||
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
|
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
|
||||||
|
|
||||||
'@swc/helpers@0.5.19':
|
'@swc/helpers@0.5.21':
|
||||||
resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==}
|
resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==}
|
||||||
|
|
||||||
'@szmarczak/http-timer@5.0.1':
|
'@szmarczak/http-timer@5.0.1':
|
||||||
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
|
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
|
||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
|
|
||||||
'@tailwindcss/forms@0.5.10':
|
'@tailwindcss/forms@0.5.11':
|
||||||
resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==}
|
resolution: {integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
|
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
|
||||||
|
|
||||||
@@ -1262,8 +1267,8 @@ packages:
|
|||||||
'@types/node@22.13.4':
|
'@types/node@22.13.4':
|
||||||
resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==}
|
resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==}
|
||||||
|
|
||||||
'@types/node@24.1.0':
|
'@types/node@25.5.0':
|
||||||
resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==}
|
resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==}
|
||||||
|
|
||||||
'@types/prismjs@1.26.5':
|
'@types/prismjs@1.26.5':
|
||||||
resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==}
|
resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==}
|
||||||
@@ -1579,8 +1584,8 @@ packages:
|
|||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
baseline-browser-mapping@2.10.8:
|
baseline-browser-mapping@2.10.17:
|
||||||
resolution: {integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==}
|
resolution: {integrity: sha512-HdrkN8eVG2CXxeifv/VdJ4A4RSra1DTW8dc/hdxzhGHN8QePs6gKaWM9pHPcpCoxYZJuOZ8drHmbdpLHjCYjLA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -1606,8 +1611,8 @@ packages:
|
|||||||
buffer@5.7.1:
|
buffer@5.7.1:
|
||||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||||
|
|
||||||
buildcheck@0.0.6:
|
buildcheck@0.0.7:
|
||||||
resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==}
|
resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
bytes@3.1.2:
|
bytes@3.1.2:
|
||||||
@@ -1646,8 +1651,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001780:
|
caniuse-lite@1.0.30001787:
|
||||||
resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==}
|
resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==}
|
||||||
|
|
||||||
chai@5.3.3:
|
chai@5.3.3:
|
||||||
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
|
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
|
||||||
@@ -1890,12 +1895,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
docker-modem@5.0.6:
|
docker-modem@5.0.7:
|
||||||
resolution: {integrity: sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ==}
|
resolution: {integrity: sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==}
|
||||||
engines: {node: '>= 8.0'}
|
engines: {node: '>= 8.0'}
|
||||||
|
|
||||||
dockerode@4.0.7:
|
dockerode@4.0.10:
|
||||||
resolution: {integrity: sha512-R+rgrSRTRdU5mH14PZTCPZtW/zw3HDWNTS/1ZAQpL/5Upe/ye5K9WQkIysu4wBoiMwKynsz0a8qWuGsHgEvSAA==}
|
resolution: {integrity: sha512-8L/P9JynLBiG7/coiA4FlQXegHltRqS0a+KqI44P1zgQh8QLHTg7FKOwhkBgSJwZTeHsq30WRoVFLuwkfK0YFg==}
|
||||||
engines: {node: '>= 8.0'}
|
engines: {node: '>= 8.0'}
|
||||||
|
|
||||||
doctrine@2.1.0:
|
doctrine@2.1.0:
|
||||||
@@ -2388,10 +2393,10 @@ packages:
|
|||||||
i18next-fs-backend@2.6.1:
|
i18next-fs-backend@2.6.1:
|
||||||
resolution: {integrity: sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ==}
|
resolution: {integrity: sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ==}
|
||||||
|
|
||||||
i18next@25.8.0:
|
i18next@25.10.9:
|
||||||
resolution: {integrity: sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==}
|
resolution: {integrity: sha512-hQY9/bFoQKGlSKMlaCuLR8w1h5JjieqrsnZvEmj1Ja6Ec7fbyc4cTrCsY9mb9Sd8YQ/swsrKz1S9M8AcvVI70w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: ^5
|
typescript: ^5 || ^6
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
@@ -2862,8 +2867,8 @@ packages:
|
|||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
nan@2.23.0:
|
nan@2.26.2:
|
||||||
resolution: {integrity: sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==}
|
resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==}
|
||||||
|
|
||||||
nanoid@3.3.11:
|
nanoid@3.3.11:
|
||||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||||
@@ -2885,8 +2890,8 @@ packages:
|
|||||||
react: '>= 17.0.2'
|
react: '>= 17.0.2'
|
||||||
react-i18next: '>= 13.5.0'
|
react-i18next: '>= 13.5.0'
|
||||||
|
|
||||||
next@16.1.7:
|
next@16.2.3:
|
||||||
resolution: {integrity: sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==}
|
resolution: {integrity: sha512-9V3zV4oZFza3PVev5/poB9g0dEafVcgNyQ8eTRop8GvxZjV2G15FC5ARuG1eFD42QgeYkzJBJzHghNP8Ad9xtA==}
|
||||||
engines: {node: '>=20.9.0'}
|
engines: {node: '>=20.9.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3043,8 +3048,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
|
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
postcss@8.5.6:
|
postcss@8.5.8:
|
||||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
prelude-ls@1.2.1:
|
prelude-ls@1.2.1:
|
||||||
@@ -3089,12 +3094,12 @@ packages:
|
|||||||
prop-types@15.8.1:
|
prop-types@15.8.1:
|
||||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
|
|
||||||
protobufjs@7.5.3:
|
protobufjs@7.5.4:
|
||||||
resolution: {integrity: sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==}
|
resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
pump@3.0.3:
|
pump@3.0.4:
|
||||||
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
|
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==}
|
||||||
|
|
||||||
punycode@2.3.1:
|
punycode@2.3.1:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
@@ -3357,8 +3362,8 @@ packages:
|
|||||||
split-ca@1.0.1:
|
split-ca@1.0.1:
|
||||||
resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==}
|
resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==}
|
||||||
|
|
||||||
ssh2@1.16.0:
|
ssh2@1.17.0:
|
||||||
resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==}
|
resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==}
|
||||||
engines: {node: '>=10.16.0'}
|
engines: {node: '>=10.16.0'}
|
||||||
|
|
||||||
stable-hash@0.0.5:
|
stable-hash@0.0.5:
|
||||||
@@ -3512,8 +3517,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
tar-fs@2.1.3:
|
tar-fs@2.1.4:
|
||||||
resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==}
|
resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==}
|
||||||
|
|
||||||
tar-stream@2.2.0:
|
tar-stream@2.2.0:
|
||||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||||
@@ -3646,8 +3651,8 @@ packages:
|
|||||||
undici-types@6.20.0:
|
undici-types@6.20.0:
|
||||||
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
|
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
|
||||||
|
|
||||||
undici-types@7.8.0:
|
undici-types@7.18.2:
|
||||||
resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
|
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
|
||||||
|
|
||||||
undici@7.24.4:
|
undici@7.24.4:
|
||||||
resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==}
|
resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==}
|
||||||
@@ -3694,8 +3699,8 @@ packages:
|
|||||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
vite@7.3.1:
|
vite@7.3.2:
|
||||||
resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
|
resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3992,7 +3997,7 @@ snapshots:
|
|||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@emnapi/runtime@1.9.0':
|
'@emnapi/runtime@1.9.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
@@ -4087,9 +4092,9 @@ snapshots:
|
|||||||
|
|
||||||
'@eslint-community/regexpp@4.12.1': {}
|
'@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:
|
dependencies:
|
||||||
'@eslint/core': 1.1.0
|
'@eslint/core': 1.1.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint: 9.25.1(jiti@2.6.1)
|
eslint: 9.25.1(jiti@2.6.1)
|
||||||
|
|
||||||
@@ -4107,7 +4112,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/json-schema': 7.0.15
|
'@types/json-schema': 7.0.15
|
||||||
|
|
||||||
'@eslint/core@1.1.0':
|
'@eslint/core@1.1.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/json-schema': 7.0.15
|
'@types/json-schema': 7.0.15
|
||||||
|
|
||||||
@@ -4163,16 +4168,23 @@ snapshots:
|
|||||||
|
|
||||||
'@floating-ui/utils@0.2.10': {}
|
'@floating-ui/utils@0.2.10': {}
|
||||||
|
|
||||||
'@grpc/grpc-js@1.13.4':
|
'@grpc/grpc-js@1.14.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@grpc/proto-loader': 0.7.15
|
'@grpc/proto-loader': 0.8.0
|
||||||
'@js-sdsl/ordered-map': 4.4.2
|
'@js-sdsl/ordered-map': 4.4.2
|
||||||
|
|
||||||
'@grpc/proto-loader@0.7.15':
|
'@grpc/proto-loader@0.7.15':
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash.camelcase: 4.3.0
|
lodash.camelcase: 4.3.0
|
||||||
long: 5.3.2
|
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
|
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.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||||
@@ -4283,7 +4295,7 @@ snapshots:
|
|||||||
|
|
||||||
'@img/sharp-wasm32@0.34.5':
|
'@img/sharp-wasm32@0.34.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emnapi/runtime': 1.9.0
|
'@emnapi/runtime': 1.9.2
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@img/sharp-win32-arm64@0.34.5':
|
'@img/sharp-win32-arm64@0.34.5':
|
||||||
@@ -4367,38 +4379,38 @@ snapshots:
|
|||||||
'@napi-rs/wasm-runtime@0.2.8':
|
'@napi-rs/wasm-runtime@0.2.8':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emnapi/core': 1.4.0
|
'@emnapi/core': 1.4.0
|
||||||
'@emnapi/runtime': 1.9.0
|
'@emnapi/runtime': 1.9.2
|
||||||
'@tybys/wasm-util': 0.9.0
|
'@tybys/wasm-util': 0.9.0
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/env@16.1.7': {}
|
'@next/env@16.2.3': {}
|
||||||
|
|
||||||
'@next/eslint-plugin-next@15.5.11':
|
'@next/eslint-plugin-next@15.5.11':
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-glob: 3.3.1
|
fast-glob: 3.3.1
|
||||||
|
|
||||||
'@next/swc-darwin-arm64@16.1.7':
|
'@next/swc-darwin-arm64@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-darwin-x64@16.1.7':
|
'@next/swc-darwin-x64@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-arm64-gnu@16.1.7':
|
'@next/swc-linux-arm64-gnu@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-arm64-musl@16.1.7':
|
'@next/swc-linux-arm64-musl@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-x64-gnu@16.1.7':
|
'@next/swc-linux-x64-gnu@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-x64-musl@16.1.7':
|
'@next/swc-linux-x64-musl@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-win32-arm64-msvc@16.1.7':
|
'@next/swc-win32-arm64-msvc@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-win32-x64-msvc@16.1.7':
|
'@next/swc-win32-x64-msvc@16.2.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
@@ -4448,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/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-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)
|
'@react-types/shared': 3.32.1(react@19.2.4)
|
||||||
'@swc/helpers': 0.5.19
|
'@swc/helpers': 0.5.21
|
||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
react-dom: 19.2.4(react@19.2.4)
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
@@ -4459,13 +4471,13 @@ snapshots:
|
|||||||
'@react-aria/utils': 3.31.0(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-stately/flags': 3.1.2
|
'@react-stately/flags': 3.1.2
|
||||||
'@react-types/shared': 3.32.1(react@19.2.4)
|
'@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: 19.2.4
|
||||||
react-dom: 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)':
|
'@react-aria/ssr@3.9.10(react@19.2.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/helpers': 0.5.19
|
'@swc/helpers': 0.5.21
|
||||||
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-aria/utils@3.31.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||||
@@ -4474,18 +4486,18 @@ snapshots:
|
|||||||
'@react-stately/flags': 3.1.2
|
'@react-stately/flags': 3.1.2
|
||||||
'@react-stately/utils': 3.10.8(react@19.2.4)
|
'@react-stately/utils': 3.10.8(react@19.2.4)
|
||||||
'@react-types/shared': 3.32.1(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
|
clsx: 2.1.1
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
react-dom: 19.2.4(react@19.2.4)
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
|
|
||||||
'@react-stately/flags@3.1.2':
|
'@react-stately/flags@3.1.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/helpers': 0.5.19
|
'@swc/helpers': 0.5.21
|
||||||
|
|
||||||
'@react-stately/utils@3.10.8(react@19.2.4)':
|
'@react-stately/utils@3.10.8(react@19.2.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/helpers': 0.5.19
|
'@swc/helpers': 0.5.21
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
|
|
||||||
'@react-types/shared@3.32.1(react@19.2.4)':
|
'@react-types/shared@3.32.1(react@19.2.4)':
|
||||||
@@ -4598,7 +4610,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@swc/helpers@0.5.19':
|
'@swc/helpers@0.5.21':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
@@ -4606,7 +4618,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
defer-to-connect: 2.0.1
|
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:
|
dependencies:
|
||||||
mini-svg-data-uri: 1.4.4
|
mini-svg-data-uri: 1.4.4
|
||||||
tailwindcss: 4.1.18
|
tailwindcss: 4.1.18
|
||||||
@@ -4677,7 +4689,7 @@ snapshots:
|
|||||||
'@alloc/quick-lru': 5.2.0
|
'@alloc/quick-lru': 5.2.0
|
||||||
'@tailwindcss/node': 4.1.18
|
'@tailwindcss/node': 4.1.18
|
||||||
'@tailwindcss/oxide': 4.1.18
|
'@tailwindcss/oxide': 4.1.18
|
||||||
postcss: 8.5.6
|
postcss: 8.5.8
|
||||||
tailwindcss: 4.1.18
|
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.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||||
@@ -4781,9 +4793,9 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.20.0
|
undici-types: 6.20.0
|
||||||
|
|
||||||
'@types/node@24.1.0':
|
'@types/node@25.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.8.0
|
undici-types: 7.18.2
|
||||||
|
|
||||||
'@types/prismjs@1.26.5': {}
|
'@types/prismjs@1.26.5': {}
|
||||||
|
|
||||||
@@ -4859,7 +4871,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.29.0
|
'@typescript-eslint/types': 8.29.0
|
||||||
'@typescript-eslint/visitor-keys': 8.29.0
|
'@typescript-eslint/visitor-keys': 8.29.0
|
||||||
debug: 4.4.3
|
debug: 4.4.1
|
||||||
fast-glob: 3.3.3
|
fast-glob: 3.3.3
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
minimatch: 9.0.5
|
minimatch: 9.0.5
|
||||||
@@ -4932,7 +4944,7 @@ snapshots:
|
|||||||
'@unrs/resolver-binding-win32-x64-msvc@1.3.3':
|
'@unrs/resolver-binding-win32-x64-msvc@1.3.3':
|
||||||
optional: true
|
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:
|
dependencies:
|
||||||
'@ampproject/remapping': 2.3.0
|
'@ampproject/remapping': 2.3.0
|
||||||
'@bcoe/v8-coverage': 1.0.2
|
'@bcoe/v8-coverage': 1.0.2
|
||||||
@@ -4947,7 +4959,7 @@ snapshots:
|
|||||||
std-env: 3.10.0
|
std-env: 3.10.0
|
||||||
test-exclude: 7.0.1
|
test-exclude: 7.0.1
|
||||||
tinyrainbow: 2.0.0
|
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:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -4959,13 +4971,13 @@ snapshots:
|
|||||||
chai: 5.3.3
|
chai: 5.3.3
|
||||||
tinyrainbow: 2.0.0
|
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.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 3.2.4
|
'@vitest/spy': 3.2.4
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.3.1(@types/node@24.1.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':
|
'@vitest/pretty-format@3.2.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5146,7 +5158,7 @@ snapshots:
|
|||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
baseline-browser-mapping@2.10.8: {}
|
baseline-browser-mapping@2.10.17: {}
|
||||||
|
|
||||||
bcrypt-pbkdf@1.0.2:
|
bcrypt-pbkdf@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5180,7 +5192,7 @@ snapshots:
|
|||||||
base64-js: 1.5.1
|
base64-js: 1.5.1
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
|
|
||||||
buildcheck@0.0.6:
|
buildcheck@0.0.7:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
bytes@3.1.2: {}
|
bytes@3.1.2: {}
|
||||||
@@ -5223,7 +5235,7 @@ snapshots:
|
|||||||
|
|
||||||
callsites@3.1.0: {}
|
callsites@3.1.0: {}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001780: {}
|
caniuse-lite@1.0.30001787: {}
|
||||||
|
|
||||||
chai@5.3.3:
|
chai@5.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5293,8 +5305,8 @@ snapshots:
|
|||||||
|
|
||||||
cpu-features@0.0.10:
|
cpu-features@0.0.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
buildcheck: 0.0.6
|
buildcheck: 0.0.7
|
||||||
nan: 2.23.0
|
nan: 2.26.2
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
@@ -5434,23 +5446,23 @@ snapshots:
|
|||||||
|
|
||||||
detect-libc@2.1.2: {}
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
docker-modem@5.0.6:
|
docker-modem@5.0.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.1
|
debug: 4.4.3
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
split-ca: 1.0.1
|
split-ca: 1.0.1
|
||||||
ssh2: 1.16.0
|
ssh2: 1.17.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
dockerode@4.0.7:
|
dockerode@4.0.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@balena/dockerignore': 1.0.2
|
'@balena/dockerignore': 1.0.2
|
||||||
'@grpc/grpc-js': 1.13.4
|
'@grpc/grpc-js': 1.14.3
|
||||||
'@grpc/proto-loader': 0.7.15
|
'@grpc/proto-loader': 0.7.15
|
||||||
docker-modem: 5.0.6
|
docker-modem: 5.0.7
|
||||||
protobufjs: 7.5.3
|
protobufjs: 7.5.4
|
||||||
tar-fs: 2.1.3
|
tar-fs: 2.1.4
|
||||||
uuid: 10.0.0
|
uuid: 10.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -6182,9 +6194,9 @@ snapshots:
|
|||||||
|
|
||||||
i18next-fs-backend@2.6.1: {}
|
i18next-fs-backend@2.6.1: {}
|
||||||
|
|
||||||
i18next@25.8.0(typescript@5.7.3):
|
i18next@25.10.9(typescript@5.7.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.6
|
'@babel/runtime': 7.29.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.7.3
|
typescript: 5.7.3
|
||||||
|
|
||||||
@@ -6618,7 +6630,7 @@ snapshots:
|
|||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
nan@2.23.0:
|
nan@2.26.2:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
nanoid@3.3.11: {}
|
nanoid@3.3.11: {}
|
||||||
@@ -6627,39 +6639,39 @@ snapshots:
|
|||||||
|
|
||||||
net@1.0.2: {}
|
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.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:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.6
|
'@babel/runtime': 7.28.6
|
||||||
'@types/hoist-non-react-statics': 3.3.7(@types/react@19.0.10)
|
'@types/hoist-non-react-statics': 3.3.7(@types/react@19.0.10)
|
||||||
core-js: 3.48.0
|
core-js: 3.48.0
|
||||||
hoist-non-react-statics: 3.3.2
|
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
|
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: 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:
|
transitivePeerDependencies:
|
||||||
- '@types/react'
|
- '@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:
|
dependencies:
|
||||||
'@next/env': 16.1.7
|
'@next/env': 16.2.3
|
||||||
'@swc/helpers': 0.5.15
|
'@swc/helpers': 0.5.15
|
||||||
baseline-browser-mapping: 2.10.8
|
baseline-browser-mapping: 2.10.17
|
||||||
caniuse-lite: 1.0.30001780
|
caniuse-lite: 1.0.30001787
|
||||||
postcss: 8.4.31
|
postcss: 8.4.31
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
react-dom: 19.2.4(react@19.2.4)
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
styled-jsx: 5.1.6(react@19.2.4)
|
styled-jsx: 5.1.6(react@19.2.4)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@next/swc-darwin-arm64': 16.1.7
|
'@next/swc-darwin-arm64': 16.2.3
|
||||||
'@next/swc-darwin-x64': 16.1.7
|
'@next/swc-darwin-x64': 16.2.3
|
||||||
'@next/swc-linux-arm64-gnu': 16.1.7
|
'@next/swc-linux-arm64-gnu': 16.2.3
|
||||||
'@next/swc-linux-arm64-musl': 16.1.7
|
'@next/swc-linux-arm64-musl': 16.2.3
|
||||||
'@next/swc-linux-x64-gnu': 16.1.7
|
'@next/swc-linux-x64-gnu': 16.2.3
|
||||||
'@next/swc-linux-x64-musl': 16.1.7
|
'@next/swc-linux-x64-musl': 16.2.3
|
||||||
'@next/swc-win32-arm64-msvc': 16.1.7
|
'@next/swc-win32-arm64-msvc': 16.2.3
|
||||||
'@next/swc-win32-x64-msvc': 16.1.7
|
'@next/swc-win32-x64-msvc': 16.2.3
|
||||||
sharp: 0.34.5
|
sharp: 0.34.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
@@ -6796,7 +6808,7 @@ snapshots:
|
|||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
postcss@8.5.6:
|
postcss@8.5.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.11
|
nanoid: 3.3.11
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
@@ -6837,7 +6849,7 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
react-is: 16.13.1
|
react-is: 16.13.1
|
||||||
|
|
||||||
protobufjs@7.5.3:
|
protobufjs@7.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@protobufjs/aspromise': 1.1.2
|
'@protobufjs/aspromise': 1.1.2
|
||||||
'@protobufjs/base64': 1.1.2
|
'@protobufjs/base64': 1.1.2
|
||||||
@@ -6849,10 +6861,10 @@ snapshots:
|
|||||||
'@protobufjs/path': 1.1.2
|
'@protobufjs/path': 1.1.2
|
||||||
'@protobufjs/pool': 1.1.0
|
'@protobufjs/pool': 1.1.0
|
||||||
'@protobufjs/utf8': 1.1.0
|
'@protobufjs/utf8': 1.1.0
|
||||||
'@types/node': 24.1.0
|
'@types/node': 25.5.0
|
||||||
long: 5.3.2
|
long: 5.3.2
|
||||||
|
|
||||||
pump@3.0.3:
|
pump@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
end-of-stream: 1.4.5
|
end-of-stream: 1.4.5
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
@@ -6875,11 +6887,11 @@ snapshots:
|
|||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
scheduler: 0.27.0
|
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:
|
dependencies:
|
||||||
'@babel/runtime': 7.27.6
|
'@babel/runtime': 7.27.6
|
||||||
html-parse-stringify: 3.0.1
|
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
|
react: 19.2.4
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
react-dom: 19.2.4(react@19.2.4)
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
@@ -7190,13 +7202,13 @@ snapshots:
|
|||||||
|
|
||||||
split-ca@1.0.1: {}
|
split-ca@1.0.1: {}
|
||||||
|
|
||||||
ssh2@1.16.0:
|
ssh2@1.17.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
asn1: 0.2.6
|
asn1: 0.2.6
|
||||||
bcrypt-pbkdf: 1.0.2
|
bcrypt-pbkdf: 1.0.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
cpu-features: 0.0.10
|
cpu-features: 0.0.10
|
||||||
nan: 2.23.0
|
nan: 2.26.2
|
||||||
|
|
||||||
stable-hash@0.0.5: {}
|
stable-hash@0.0.5: {}
|
||||||
|
|
||||||
@@ -7356,11 +7368,11 @@ snapshots:
|
|||||||
|
|
||||||
tapable@2.3.0: {}
|
tapable@2.3.0: {}
|
||||||
|
|
||||||
tar-fs@2.1.3:
|
tar-fs@2.1.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
chownr: 1.1.4
|
chownr: 1.1.4
|
||||||
mkdirp-classic: 0.5.3
|
mkdirp-classic: 0.5.3
|
||||||
pump: 3.0.3
|
pump: 3.0.4
|
||||||
tar-stream: 2.2.0
|
tar-stream: 2.2.0
|
||||||
|
|
||||||
tar-stream@2.2.0:
|
tar-stream@2.2.0:
|
||||||
@@ -7507,7 +7519,7 @@ snapshots:
|
|||||||
|
|
||||||
undici-types@6.20.0: {}
|
undici-types@6.20.0: {}
|
||||||
|
|
||||||
undici-types@7.8.0: {}
|
undici-types@7.18.2: {}
|
||||||
|
|
||||||
undici@7.24.4: {}
|
undici@7.24.4: {}
|
||||||
|
|
||||||
@@ -7570,13 +7582,13 @@ snapshots:
|
|||||||
d3-time: 3.1.0
|
d3-time: 3.1.0
|
||||||
d3-timer: 3.0.1
|
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:
|
dependencies:
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
es-module-lexer: 1.7.0
|
es-module-lexer: 1.7.0
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
vite: 7.3.1(@types/node@24.1.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:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- jiti
|
- jiti
|
||||||
@@ -7591,25 +7603,25 @@ snapshots:
|
|||||||
- tsx
|
- tsx
|
||||||
- yaml
|
- yaml
|
||||||
|
|
||||||
vite@7.3.1(@types/node@24.1.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:
|
dependencies:
|
||||||
esbuild: 0.27.2
|
esbuild: 0.27.2
|
||||||
fdir: 6.5.0(picomatch@4.0.4)
|
fdir: 6.5.0(picomatch@4.0.4)
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
postcss: 8.5.6
|
postcss: 8.5.8
|
||||||
rollup: 4.59.0
|
rollup: 4.59.0
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 24.1.0
|
'@types/node': 25.5.0
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
jiti: 2.6.1
|
jiti: 2.6.1
|
||||||
lightningcss: 1.30.2
|
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:
|
dependencies:
|
||||||
'@types/chai': 5.2.3
|
'@types/chai': 5.2.3
|
||||||
'@vitest/expect': 3.2.4
|
'@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.2(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||||
'@vitest/pretty-format': 3.2.4
|
'@vitest/pretty-format': 3.2.4
|
||||||
'@vitest/runner': 3.2.4
|
'@vitest/runner': 3.2.4
|
||||||
'@vitest/snapshot': 3.2.4
|
'@vitest/snapshot': 3.2.4
|
||||||
@@ -7627,11 +7639,11 @@ snapshots:
|
|||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
tinypool: 1.1.1
|
tinypool: 1.1.1
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
vite: 7.3.1(@types/node@24.1.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@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)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 24.1.0
|
'@types/node': 25.5.0
|
||||||
jsdom: 28.1.0
|
jsdom: 28.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- jiti
|
- jiti
|
||||||
|
|||||||
@@ -67,9 +67,9 @@
|
|||||||
"empty_data": "Substelsel status onbekend"
|
"empty_data": "Substelsel status onbekend"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "Gesond",
|
||||||
"degraded": "Degraded",
|
"degraded": "Gedegradeer",
|
||||||
"no_data": "No storage data available"
|
"no_data": "Geen bergingsdata beskikbaar nie"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "RX",
|
"rx": "RX",
|
||||||
|
|||||||
@@ -67,9 +67,9 @@
|
|||||||
"empty_data": "Statut du sous-système inconnu"
|
"empty_data": "Statut du sous-système inconnu"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "Sain",
|
||||||
"degraded": "Degraded",
|
"degraded": "Dégradé",
|
||||||
"no_data": "No storage data available"
|
"no_data": "Aucune données de stockage disponible"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "Rx",
|
"rx": "Rx",
|
||||||
@@ -115,12 +115,12 @@
|
|||||||
"jellyfin": {
|
"jellyfin": {
|
||||||
"playing": "En cours",
|
"playing": "En cours",
|
||||||
"transcoding": "En cours d'encodage",
|
"transcoding": "En cours d'encodage",
|
||||||
"bitrate": "Bitrate",
|
"bitrate": "Débit",
|
||||||
"no_active": "No Active Streams",
|
"no_active": "Aucune lecture en cours",
|
||||||
"movies": "Movies",
|
"movies": "Films",
|
||||||
"series": "Series",
|
"series": "Séries",
|
||||||
"episodes": "Episodes",
|
"episodes": "Épisodes",
|
||||||
"songs": "Songs"
|
"songs": "Chansons"
|
||||||
},
|
},
|
||||||
"esphome": {
|
"esphome": {
|
||||||
"offline": "Hors ligne",
|
"offline": "Hors ligne",
|
||||||
@@ -190,11 +190,11 @@
|
|||||||
"plex_connection_error": "Vérifier la connexion à Plex"
|
"plex_connection_error": "Vérifier la connexion à Plex"
|
||||||
},
|
},
|
||||||
"tracearr": {
|
"tracearr": {
|
||||||
"no_active": "No Active Streams",
|
"no_active": "Aucune lecture en cours",
|
||||||
"streams": "Streams",
|
"streams": "Lectures",
|
||||||
"transcodes": "Transcodes",
|
"transcodes": "Transcodages",
|
||||||
"directplay": "Direct Play",
|
"directplay": "Lectures directes",
|
||||||
"bitrate": "Bitrate"
|
"bitrate": "Débit"
|
||||||
},
|
},
|
||||||
"omada": {
|
"omada": {
|
||||||
"connectedAp": "APs connectées",
|
"connectedAp": "APs connectées",
|
||||||
@@ -295,12 +295,12 @@
|
|||||||
"available": "Disponible"
|
"available": "Disponible"
|
||||||
},
|
},
|
||||||
"seerr": {
|
"seerr": {
|
||||||
"pending": "Pending",
|
"pending": "En attente",
|
||||||
"approved": "Approved",
|
"approved": "Validées",
|
||||||
"available": "Available",
|
"available": "Disponibles",
|
||||||
"completed": "Completed",
|
"completed": "Complétées",
|
||||||
"processing": "Processing",
|
"processing": "En traitement",
|
||||||
"issues": "Open Issues"
|
"issues": "Problèmes non résolus"
|
||||||
},
|
},
|
||||||
"netalertx": {
|
"netalertx": {
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
@@ -619,13 +619,13 @@
|
|||||||
"total": "Total"
|
"total": "Total"
|
||||||
},
|
},
|
||||||
"pangolin": {
|
"pangolin": {
|
||||||
"orgs": "Orgs",
|
"orgs": "Organisations",
|
||||||
"sites": "Sites",
|
"sites": "Sites",
|
||||||
"resources": "Ressources",
|
"resources": "Ressources",
|
||||||
"targets": "Cibles",
|
"targets": "Cibles",
|
||||||
"traffic": "Trafique",
|
"traffic": "Trafique",
|
||||||
"in": "In",
|
"in": "Entrant",
|
||||||
"out": "Out"
|
"out": "Sortant"
|
||||||
},
|
},
|
||||||
"peanut": {
|
"peanut": {
|
||||||
"battery_charge": "Charge de la batterie",
|
"battery_charge": "Charge de la batterie",
|
||||||
@@ -724,8 +724,8 @@
|
|||||||
"volumeAvailable": "Disponible"
|
"volumeAvailable": "Disponible"
|
||||||
},
|
},
|
||||||
"dispatcharr": {
|
"dispatcharr": {
|
||||||
"channels": "Channels",
|
"channels": "Chaînes",
|
||||||
"streams": "Streams"
|
"streams": "Lectures"
|
||||||
},
|
},
|
||||||
"mylar": {
|
"mylar": {
|
||||||
"series": "Séries",
|
"series": "Séries",
|
||||||
@@ -816,10 +816,10 @@
|
|||||||
"series": "Séries"
|
"series": "Séries"
|
||||||
},
|
},
|
||||||
"booklore": {
|
"booklore": {
|
||||||
"libraries": "Libraries",
|
"libraries": "Bibliothèques",
|
||||||
"books": "Books",
|
"books": "Livres",
|
||||||
"reading": "Reading",
|
"reading": "En cours de lecture",
|
||||||
"finished": "Finished"
|
"finished": "Terminés"
|
||||||
},
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "File d'attente",
|
"downloadCount": "File d'attente",
|
||||||
@@ -1160,30 +1160,30 @@
|
|||||||
"artists": "Artistes"
|
"artists": "Artistes"
|
||||||
},
|
},
|
||||||
"arcane": {
|
"arcane": {
|
||||||
"containers": "Containers",
|
"containers": "Conteneurs",
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
"image_updates": "Image Updates",
|
"image_updates": "Mises à jour d'images",
|
||||||
"images_unused": "Unused",
|
"images_unused": "Inutilisées",
|
||||||
"environment_required": "Environment ID Required"
|
"environment_required": "ID d'environnement requis"
|
||||||
},
|
},
|
||||||
"dockhand": {
|
"dockhand": {
|
||||||
"running": "Running",
|
"running": "En cours d'exécution",
|
||||||
"stopped": "Stopped",
|
"stopped": "Arrêtés",
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Memory",
|
"memory": "Mémoire",
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
"volumes": "Volumes",
|
"volumes": "Volumes",
|
||||||
"events_today": "Events Today",
|
"events_today": "Événements aujourd'hui",
|
||||||
"pending_updates": "Pending Updates",
|
"pending_updates": "Mises à jour en attente",
|
||||||
"stacks": "Stacks",
|
"stacks": "Stacks",
|
||||||
"paused": "Paused",
|
"paused": "En pause",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"environment_not_found": "Environment Not Found"
|
"environment_not_found": "Environnement introuvable"
|
||||||
},
|
},
|
||||||
"sparkyfitness": {
|
"sparkyfitness": {
|
||||||
"eaten": "Eaten",
|
"eaten": "Mangé",
|
||||||
"burned": "Burned",
|
"burned": "Brûlé",
|
||||||
"remaining": "Remaining",
|
"remaining": "Restant",
|
||||||
"steps": "Steps"
|
"steps": "Pas"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,9 +67,9 @@
|
|||||||
"empty_data": "Stanje podsustava nepoznato"
|
"empty_data": "Stanje podsustava nepoznato"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "Zdrav",
|
||||||
"degraded": "Degraded",
|
"degraded": "Degradirano",
|
||||||
"no_data": "No storage data available"
|
"no_data": "Nema dostupnih podataka spremišta"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "RX",
|
"rx": "RX",
|
||||||
@@ -624,8 +624,8 @@
|
|||||||
"resources": "Resursi",
|
"resources": "Resursi",
|
||||||
"targets": "Ciljevi",
|
"targets": "Ciljevi",
|
||||||
"traffic": "Promet",
|
"traffic": "Promet",
|
||||||
"in": "In",
|
"in": "Ulaz",
|
||||||
"out": "Out"
|
"out": "Izlaz"
|
||||||
},
|
},
|
||||||
"peanut": {
|
"peanut": {
|
||||||
"battery_charge": "Napunjenost baterije",
|
"battery_charge": "Napunjenost baterije",
|
||||||
|
|||||||
@@ -61,15 +61,15 @@
|
|||||||
"wlan_devices": "Dispositivi WLAN",
|
"wlan_devices": "Dispositivi WLAN",
|
||||||
"lan_users": "Utenti LAN",
|
"lan_users": "Utenti LAN",
|
||||||
"wlan_users": "Utenti WLAN",
|
"wlan_users": "Utenti WLAN",
|
||||||
"up": "UP",
|
"up": "SU",
|
||||||
"down": "DOWN",
|
"down": "DOWN",
|
||||||
"wait": "Please wait",
|
"wait": "Attendere prego",
|
||||||
"empty_data": "Stato del sottosistema sconosciuto"
|
"empty_data": "Stato del sottosistema sconosciuto"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "Sano",
|
||||||
"degraded": "Degraded",
|
"degraded": "Degradato",
|
||||||
"no_data": "No storage data available"
|
"no_data": "Nessun dato di archiviazione disponibile"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "RX",
|
"rx": "RX",
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
"partial": "Parziale"
|
"partial": "Parziale"
|
||||||
},
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
"error": "Error",
|
"error": "Errore",
|
||||||
"ping": "Ping",
|
"ping": "Ping",
|
||||||
"down": "Down",
|
"down": "Down",
|
||||||
"up": "Up",
|
"up": "Up",
|
||||||
@@ -96,11 +96,11 @@
|
|||||||
},
|
},
|
||||||
"siteMonitor": {
|
"siteMonitor": {
|
||||||
"http_status": "Stato HTTP",
|
"http_status": "Stato HTTP",
|
||||||
"error": "Error",
|
"error": "Errore",
|
||||||
"response": "Risposta",
|
"response": "Risposta",
|
||||||
"down": "Down",
|
"down": "Giù",
|
||||||
"up": "Up",
|
"up": "Su",
|
||||||
"not_available": "Not Available"
|
"not_available": "Non disponibile"
|
||||||
},
|
},
|
||||||
"emby": {
|
"emby": {
|
||||||
"playing": "In riproduzione",
|
"playing": "In riproduzione",
|
||||||
@@ -113,21 +113,21 @@
|
|||||||
"songs": "Canzoni"
|
"songs": "Canzoni"
|
||||||
},
|
},
|
||||||
"jellyfin": {
|
"jellyfin": {
|
||||||
"playing": "Playing",
|
"playing": "In riproduzione",
|
||||||
"transcoding": "Transcoding",
|
"transcoding": "Transcodifica",
|
||||||
"bitrate": "Bitrate",
|
"bitrate": "Velocità in bit",
|
||||||
"no_active": "No Active Streams",
|
"no_active": "Nessuna Trasmissione Attiva",
|
||||||
"movies": "Movies",
|
"movies": "Film",
|
||||||
"series": "Serie",
|
"series": "Serie",
|
||||||
"episodes": "Episodes",
|
"episodes": "Episodi",
|
||||||
"songs": "Songs"
|
"songs": "Canzoni"
|
||||||
},
|
},
|
||||||
"esphome": {
|
"esphome": {
|
||||||
"offline": "Offline",
|
"offline": "Disconnesso",
|
||||||
"offline_alt": "Offline",
|
"offline_alt": "Disconnesso",
|
||||||
"online": "Online",
|
"online": "Online",
|
||||||
"total": "Total",
|
"total": "Totale",
|
||||||
"unknown": "Unknown"
|
"unknown": "Sconosciuto"
|
||||||
},
|
},
|
||||||
"evcc": {
|
"evcc": {
|
||||||
"pv_power": "Produzione",
|
"pv_power": "Produzione",
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
"unread": "Non letto"
|
"unread": "Non letto"
|
||||||
},
|
},
|
||||||
"fritzbox": {
|
"fritzbox": {
|
||||||
"connectionStatus": "Status",
|
"connectionStatus": "Stato",
|
||||||
"connectionStatusUnconfigured": "Non configurato",
|
"connectionStatusUnconfigured": "Non configurato",
|
||||||
"connectionStatusConnecting": "Connessione in corso",
|
"connectionStatusConnecting": "Connessione in corso",
|
||||||
"connectionStatusAuthenticating": "In fase di autenticazione",
|
"connectionStatusAuthenticating": "In fase di autenticazione",
|
||||||
@@ -156,11 +156,11 @@
|
|||||||
"connectionStatusDisconnecting": "Disconnessione in corso",
|
"connectionStatusDisconnecting": "Disconnessione in corso",
|
||||||
"connectionStatusDisconnected": "Disconnesso",
|
"connectionStatusDisconnected": "Disconnesso",
|
||||||
"connectionStatusConnected": "Connesso",
|
"connectionStatusConnected": "Connesso",
|
||||||
"uptime": "Uptime",
|
"uptime": "Tempo di funzionamento",
|
||||||
"maxDown": "Max. Down",
|
"maxDown": "Max. Down",
|
||||||
"maxUp": "Max. Up",
|
"maxUp": "Max. Up",
|
||||||
"down": "Down",
|
"down": "Giù",
|
||||||
"up": "Up",
|
"up": "Su",
|
||||||
"received": "Ricevuti",
|
"received": "Ricevuti",
|
||||||
"sent": "Inviati",
|
"sent": "Inviati",
|
||||||
"externalIPAddress": "IP Esterno",
|
"externalIPAddress": "IP Esterno",
|
||||||
@@ -184,17 +184,17 @@
|
|||||||
},
|
},
|
||||||
"tautulli": {
|
"tautulli": {
|
||||||
"playing": "In riproduzione",
|
"playing": "In riproduzione",
|
||||||
"transcoding": "Transcoding",
|
"transcoding": "Transcodifica",
|
||||||
"bitrate": "Bitrate",
|
"bitrate": "Velocità in bit",
|
||||||
"no_active": "No Active Streams",
|
"no_active": "Nessuna Trasmissione Attiva",
|
||||||
"plex_connection_error": "Controllare la connessione a Plex"
|
"plex_connection_error": "Controllare la connessione a Plex"
|
||||||
},
|
},
|
||||||
"tracearr": {
|
"tracearr": {
|
||||||
"no_active": "No Active Streams",
|
"no_active": "Nessuna Trasmissione Attiva",
|
||||||
"streams": "Streams",
|
"streams": "Flussi",
|
||||||
"transcodes": "Transcodes",
|
"transcodes": "Transcodifiche",
|
||||||
"directplay": "Direct Play",
|
"directplay": "Riproduzione diretta",
|
||||||
"bitrate": "Bitrate"
|
"bitrate": "Velocità in bit"
|
||||||
},
|
},
|
||||||
"omada": {
|
"omada": {
|
||||||
"connectedAp": "AP Connessi",
|
"connectedAp": "AP Connessi",
|
||||||
@@ -211,11 +211,11 @@
|
|||||||
"plex": {
|
"plex": {
|
||||||
"streams": "Trasmissioni attive",
|
"streams": "Trasmissioni attive",
|
||||||
"albums": "Album",
|
"albums": "Album",
|
||||||
"movies": "Movies",
|
"movies": "Film",
|
||||||
"tv": "Programmi televisivi"
|
"tv": "Programmi televisivi"
|
||||||
},
|
},
|
||||||
"sabnzbd": {
|
"sabnzbd": {
|
||||||
"rate": "Rate",
|
"rate": "Rapporto",
|
||||||
"queue": "Coda",
|
"queue": "Coda",
|
||||||
"timeleft": "Tempo Rimanente"
|
"timeleft": "Tempo Rimanente"
|
||||||
},
|
},
|
||||||
@@ -227,13 +227,13 @@
|
|||||||
"transmission": {
|
"transmission": {
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"leech": "Leech",
|
"leech": "In download",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
"qbittorrent": {
|
"qbittorrent": {
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"leech": "Leech",
|
"leech": "In download",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
@@ -430,21 +430,21 @@
|
|||||||
"medusa": {
|
"medusa": {
|
||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"series": "Series"
|
"series": "Serie"
|
||||||
},
|
},
|
||||||
"minecraft": {
|
"minecraft": {
|
||||||
"players": "Giocatori",
|
"players": "Giocatori",
|
||||||
"version": "Versione",
|
"version": "Versione",
|
||||||
"status": "Status",
|
"status": "Stato",
|
||||||
"up": "Online",
|
"up": "Online",
|
||||||
"down": "Offline"
|
"down": "Disconnesso"
|
||||||
},
|
},
|
||||||
"miniflux": {
|
"miniflux": {
|
||||||
"read": "Letti",
|
"read": "Letti",
|
||||||
"unread": "Unread"
|
"unread": "Non letto"
|
||||||
},
|
},
|
||||||
"authentik": {
|
"authentik": {
|
||||||
"users": "Users",
|
"users": "Utenti",
|
||||||
"loginsLast24H": "Accessi (24h)",
|
"loginsLast24H": "Accessi (24h)",
|
||||||
"failedLoginsLast24H": "Accessi Falliti (24h)"
|
"failedLoginsLast24H": "Accessi Falliti (24h)"
|
||||||
},
|
},
|
||||||
@@ -456,19 +456,19 @@
|
|||||||
},
|
},
|
||||||
"glances": {
|
"glances": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"load": "Load",
|
"load": "Carico",
|
||||||
"wait": "Please wait",
|
"wait": "Attendere prego",
|
||||||
"temp": "TEMP",
|
"temp": "TEMP",
|
||||||
"_temp": "Temp.",
|
"_temp": "Temp.",
|
||||||
"warn": "Avviso",
|
"warn": "Avviso",
|
||||||
"uptime": "UP",
|
"uptime": "SU",
|
||||||
"total": "Total",
|
"total": "Totale",
|
||||||
"free": "Free",
|
"free": "Libero",
|
||||||
"used": "Used",
|
"used": "Utilizzato",
|
||||||
"days": "d",
|
"days": "g",
|
||||||
"hours": "h",
|
"hours": "o",
|
||||||
"crit": "Critico",
|
"crit": "Critico",
|
||||||
"read": "Read",
|
"read": "Letti",
|
||||||
"write": "Scrittura",
|
"write": "Scrittura",
|
||||||
"gpu": "GPU",
|
"gpu": "GPU",
|
||||||
"mem": "Mem.",
|
"mem": "Mem.",
|
||||||
@@ -489,57 +489,57 @@
|
|||||||
"1-day": "Prevalentemente Soleggiato",
|
"1-day": "Prevalentemente Soleggiato",
|
||||||
"1-night": "Prevalentemente Sereno",
|
"1-night": "Prevalentemente Sereno",
|
||||||
"2-day": "Parzialmente Nuvoloso",
|
"2-day": "Parzialmente Nuvoloso",
|
||||||
"2-night": "Partly Cloudy",
|
"2-night": "Parzialmente Nuvoloso",
|
||||||
"3-day": "Nuvoloso",
|
"3-day": "Nuvoloso",
|
||||||
"3-night": "Cloudy",
|
"3-night": "Nuvoloso",
|
||||||
"45-day": "Nebbioso",
|
"45-day": "Nebbioso",
|
||||||
"45-night": "Foggy",
|
"45-night": "Nebbioso",
|
||||||
"48-day": "Foggy",
|
"48-day": "Nebbioso",
|
||||||
"48-night": "Foggy",
|
"48-night": "Nebbioso",
|
||||||
"51-day": "Pioggerella Leggera",
|
"51-day": "Pioggerella Leggera",
|
||||||
"51-night": "Light Drizzle",
|
"51-night": "Pioggerella Leggera",
|
||||||
"53-day": "Pioggerella",
|
"53-day": "Pioggerella",
|
||||||
"53-night": "Drizzle",
|
"53-night": "Pioggerella",
|
||||||
"55-day": "Pioggerella Pesante",
|
"55-day": "Pioggerella Pesante",
|
||||||
"55-night": "Heavy Drizzle",
|
"55-night": "Pioggerella Pesante",
|
||||||
"56-day": "Leggera Pioggia Gelata",
|
"56-day": "Leggera Pioggia Gelata",
|
||||||
"56-night": "Light Freezing Drizzle",
|
"56-night": "Leggera Pioggia Gelata",
|
||||||
"57-day": "Pioggerella Gelata",
|
"57-day": "Pioggerella Gelata",
|
||||||
"57-night": "Freezing Drizzle",
|
"57-night": "Pioggerella Gelata",
|
||||||
"61-day": "Pioggia Leggera",
|
"61-day": "Pioggia Leggera",
|
||||||
"61-night": "Light Rain",
|
"61-night": "Pioggia Leggera",
|
||||||
"63-day": "Pioggia",
|
"63-day": "Pioggia",
|
||||||
"63-night": "Rain",
|
"63-night": "Pioggia",
|
||||||
"65-day": "Pioggia Intensa",
|
"65-day": "Pioggia Intensa",
|
||||||
"65-night": "Heavy Rain",
|
"65-night": "Pioggia Intensa",
|
||||||
"66-day": "Grandine",
|
"66-day": "Grandine",
|
||||||
"66-night": "Freezing Rain",
|
"66-night": "Grandine",
|
||||||
"67-day": "Freezing Rain",
|
"67-day": "Grandine",
|
||||||
"67-night": "Freezing Rain",
|
"67-night": "Grandine",
|
||||||
"71-day": "Leggera Nevicata",
|
"71-day": "Leggera Nevicata",
|
||||||
"71-night": "Light Snow",
|
"71-night": "Leggera Nevicata",
|
||||||
"73-day": "Neve",
|
"73-day": "Neve",
|
||||||
"73-night": "Snow",
|
"73-night": "Neve",
|
||||||
"75-day": "Nevicata Intensa",
|
"75-day": "Nevicata Intensa",
|
||||||
"75-night": "Heavy Snow",
|
"75-night": "Nevicata Intensa",
|
||||||
"77-day": "Fiocchi di Neve",
|
"77-day": "Fiocchi di Neve",
|
||||||
"77-night": "Snow Grains",
|
"77-night": "Fiocchi di Neve",
|
||||||
"80-day": "Leggeri Rovesci",
|
"80-day": "Leggeri Rovesci",
|
||||||
"80-night": "Light Showers",
|
"80-night": "Leggeri Rovesci",
|
||||||
"81-day": "Rovesci",
|
"81-day": "Rovesci",
|
||||||
"81-night": "Showers",
|
"81-night": "Rovesci",
|
||||||
"82-day": "Intensi Rovesci",
|
"82-day": "Intensi Rovesci",
|
||||||
"82-night": "Heavy Showers",
|
"82-night": "Intensi Rovesci",
|
||||||
"85-day": "Rovesci di Neve",
|
"85-day": "Rovesci di Neve",
|
||||||
"85-night": "Snow Showers",
|
"85-night": "Rovesci di Neve",
|
||||||
"86-day": "Snow Showers",
|
"86-day": "Rovesci di Neve",
|
||||||
"86-night": "Snow Showers",
|
"86-night": "Rovesci di Neve",
|
||||||
"95-day": "Temporale",
|
"95-day": "Temporale",
|
||||||
"95-night": "Thunderstorm",
|
"95-night": "Temporale",
|
||||||
"96-day": "Temporale con grandine",
|
"96-day": "Temporale con grandine",
|
||||||
"96-night": "Thunderstorm With Hail",
|
"96-night": "Temporale con grandine",
|
||||||
"99-day": "Thunderstorm With Hail",
|
"99-day": "Temporale con grandine",
|
||||||
"99-night": "Thunderstorm With Hail"
|
"99-night": "Temporale con grandine"
|
||||||
},
|
},
|
||||||
"homebridge": {
|
"homebridge": {
|
||||||
"available_update": "Sistema",
|
"available_update": "Sistema",
|
||||||
|
|||||||
@@ -67,9 +67,9 @@
|
|||||||
"empty_data": "서브시스템 상태 알 수 없음"
|
"empty_data": "서브시스템 상태 알 수 없음"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "정상",
|
||||||
"degraded": "Degraded",
|
"degraded": "성능 저하",
|
||||||
"no_data": "No storage data available"
|
"no_data": "저장소 데이터 없음"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "수신",
|
"rx": "수신",
|
||||||
|
|||||||
@@ -67,9 +67,9 @@
|
|||||||
"empty_data": "Status podsystemu nieznany"
|
"empty_data": "Status podsystemu nieznany"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "Zdrowy",
|
||||||
"degraded": "Degraded",
|
"degraded": "Zdegradowany",
|
||||||
"no_data": "No storage data available"
|
"no_data": "Brak danych o miejscu przechowywania"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "Rx",
|
"rx": "Rx",
|
||||||
|
|||||||
@@ -67,9 +67,9 @@
|
|||||||
"empty_data": "Status do Subsistema desconhecido"
|
"empty_data": "Status do Subsistema desconhecido"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "Saudável",
|
||||||
"degraded": "Degraded",
|
"degraded": "Degradado",
|
||||||
"no_data": "No storage data available"
|
"no_data": "Sem dados de armazenamento disponíveis"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "RX",
|
"rx": "RX",
|
||||||
@@ -114,9 +114,9 @@
|
|||||||
},
|
},
|
||||||
"jellyfin": {
|
"jellyfin": {
|
||||||
"playing": "Jogando",
|
"playing": "Jogando",
|
||||||
"transcoding": "Transcoding",
|
"transcoding": "Transcodificando",
|
||||||
"bitrate": "Bitrate",
|
"bitrate": "Bitrate",
|
||||||
"no_active": "No Active Streams",
|
"no_active": "Sem Transmissões Ativas",
|
||||||
"movies": "Filmes",
|
"movies": "Filmes",
|
||||||
"series": "Séries",
|
"series": "Séries",
|
||||||
"episodes": "Episódios",
|
"episodes": "Episódios",
|
||||||
@@ -190,10 +190,10 @@
|
|||||||
"plex_connection_error": "Verifique a conexão do Plex"
|
"plex_connection_error": "Verifique a conexão do Plex"
|
||||||
},
|
},
|
||||||
"tracearr": {
|
"tracearr": {
|
||||||
"no_active": "No Active Streams",
|
"no_active": "Sem Transmissões Ativas",
|
||||||
"streams": "Streams",
|
"streams": "Transmissões",
|
||||||
"transcodes": "Transcodes",
|
"transcodes": "Transcodificações",
|
||||||
"directplay": "Direct Play",
|
"directplay": "Reprodução direta",
|
||||||
"bitrate": "Bitrate"
|
"bitrate": "Bitrate"
|
||||||
},
|
},
|
||||||
"omada": {
|
"omada": {
|
||||||
@@ -619,13 +619,13 @@
|
|||||||
"total": "Total"
|
"total": "Total"
|
||||||
},
|
},
|
||||||
"pangolin": {
|
"pangolin": {
|
||||||
"orgs": "Orgs",
|
"orgs": "Organizações",
|
||||||
"sites": "Sites",
|
"sites": "Sites",
|
||||||
"resources": "Recursos",
|
"resources": "Recursos",
|
||||||
"targets": "Targets",
|
"targets": "Alvos",
|
||||||
"traffic": "Traffic",
|
"traffic": "Tráfego",
|
||||||
"in": "In",
|
"in": "Em",
|
||||||
"out": "Out"
|
"out": "Saída"
|
||||||
},
|
},
|
||||||
"peanut": {
|
"peanut": {
|
||||||
"battery_charge": "Carga da bateria",
|
"battery_charge": "Carga da bateria",
|
||||||
@@ -1164,11 +1164,11 @@
|
|||||||
"images": "Imagens",
|
"images": "Imagens",
|
||||||
"image_updates": "Atualizações de Imagem",
|
"image_updates": "Atualizações de Imagem",
|
||||||
"images_unused": "Não utilizado",
|
"images_unused": "Não utilizado",
|
||||||
"environment_required": "Environment ID Required"
|
"environment_required": "ID do ambiente necessário"
|
||||||
},
|
},
|
||||||
"dockhand": {
|
"dockhand": {
|
||||||
"running": "Executando",
|
"running": "Executando",
|
||||||
"stopped": "Stopped",
|
"stopped": "Parado",
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Memória",
|
"memory": "Memória",
|
||||||
"images": "Imagens",
|
"images": "Imagens",
|
||||||
@@ -1178,12 +1178,12 @@
|
|||||||
"stacks": "Pilhas",
|
"stacks": "Pilhas",
|
||||||
"paused": "Pausado",
|
"paused": "Pausado",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"environment_not_found": "Environment Not Found"
|
"environment_not_found": "Ambiente não encontrado"
|
||||||
},
|
},
|
||||||
"sparkyfitness": {
|
"sparkyfitness": {
|
||||||
"eaten": "Eaten",
|
"eaten": "Comido",
|
||||||
"burned": "Burned",
|
"burned": "Queimado",
|
||||||
"remaining": "Remaining",
|
"remaining": "Restante",
|
||||||
"steps": "Steps"
|
"steps": "Passos"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -458,7 +458,7 @@
|
|||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"load": "负载",
|
"load": "负载",
|
||||||
"wait": "请稍候",
|
"wait": "请稍候",
|
||||||
"temp": "转速",
|
"temp": "温度",
|
||||||
"_temp": "Temp",
|
"_temp": "Temp",
|
||||||
"warn": "Warn",
|
"warn": "Warn",
|
||||||
"uptime": "运行时间",
|
"uptime": "运行时间",
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ export function setCookieHeader(url, params) {
|
|||||||
const existingCookie = cookieJar.getCookieStringSync(url.toString());
|
const existingCookie = cookieJar.getCookieStringSync(url.toString());
|
||||||
if (existingCookie) {
|
if (existingCookie) {
|
||||||
params.headers = params.headers ?? {};
|
params.headers = params.headers ?? {};
|
||||||
params.headers[params.cookieHeader ?? "Cookie"] = existingCookie;
|
const cookieHeader = params.cookieHeader ?? "Cookie";
|
||||||
|
if (!params.headers[cookieHeader]) {
|
||||||
|
params.headers[cookieHeader] = existingCookie;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,4 +42,16 @@ describe("utils/proxy/cookie-jar", () => {
|
|||||||
|
|
||||||
expect(params.headers.Cookie).toContain("c=d");
|
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");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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 = {}) {
|
export async function httpProxy(url, params = {}) {
|
||||||
const constructedUrl = new URL(url);
|
const constructedUrl = new URL(url);
|
||||||
const disableIpv6 = process.env.HOMEPAGE_PROXY_DISABLE_IPV6 === "true";
|
const disableIpv6 = process.env.HOMEPAGE_PROXY_DISABLE_IPV6 === "true";
|
||||||
const agentOptions = {
|
|
||||||
...(disableIpv6 ? { family: 4, autoSelectFamily: false } : { autoSelectFamilyAttemptTimeout: 500 }),
|
|
||||||
lookup: homepageDNSLookupFn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let request = null;
|
let request = null;
|
||||||
if (constructedUrl.protocol === "https:") {
|
if (constructedUrl.protocol === "https:") {
|
||||||
request = httpsRequest(constructedUrl, {
|
request = httpsRequest(constructedUrl, {
|
||||||
agent: new https.Agent({ ...agentOptions, rejectUnauthorized: false }),
|
agent: getAgent(constructedUrl.protocol, disableIpv6),
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
request = httpRequest(constructedUrl, {
|
request = httpRequest(constructedUrl, {
|
||||||
agent: new http.Agent(agentOptions),
|
agent: getAgent(constructedUrl.protocol, disableIpv6),
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const { state, cache, logger, dns, net, cookieJar } = vi.hoisted(() => ({
|
|||||||
body: Buffer.from(""),
|
body: Buffer.from(""),
|
||||||
},
|
},
|
||||||
error: null,
|
error: null,
|
||||||
|
lastAgent: null,
|
||||||
lastAgentOptions: null,
|
lastAgentOptions: null,
|
||||||
lastRequestParams: null,
|
lastRequestParams: null,
|
||||||
lastWrittenBody: null,
|
lastWrittenBody: null,
|
||||||
@@ -59,6 +60,7 @@ vi.mock("follow-redirects", async () => {
|
|||||||
state.lastWrittenBody = chunk;
|
state.lastWrittenBody = chunk;
|
||||||
});
|
});
|
||||||
req.end = vi.fn(() => {
|
req.end = vi.fn(() => {
|
||||||
|
state.lastAgent = params?.agent ?? null;
|
||||||
state.lastAgentOptions = params?.agent?.opts ?? null;
|
state.lastAgentOptions = params?.agent?.opts ?? null;
|
||||||
if (state.error) {
|
if (state.error) {
|
||||||
req.emit("error", state.error);
|
req.emit("error", state.error);
|
||||||
@@ -104,6 +106,7 @@ describe("utils/proxy/http cachedRequest", () => {
|
|||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
body: Buffer.from(""),
|
body: Buffer.from(""),
|
||||||
};
|
};
|
||||||
|
state.lastAgent = null;
|
||||||
state.lastAgentOptions = null;
|
state.lastAgentOptions = null;
|
||||||
state.lastRequestParams = null;
|
state.lastRequestParams = null;
|
||||||
state.lastWrittenBody = null;
|
state.lastWrittenBody = null;
|
||||||
@@ -307,6 +310,7 @@ describe("utils/proxy/http httpProxy", () => {
|
|||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
body: Buffer.from("ok"),
|
body: Buffer.from("ok"),
|
||||||
};
|
};
|
||||||
|
state.lastAgent = null;
|
||||||
state.lastAgentOptions = null;
|
state.lastAgentOptions = null;
|
||||||
state.lastRequestParams = null;
|
state.lastRequestParams = null;
|
||||||
state.lastWrittenBody = null;
|
state.lastWrittenBody = null;
|
||||||
@@ -397,6 +401,7 @@ describe("utils/proxy/http httpProxy", () => {
|
|||||||
|
|
||||||
await httpMod.httpProxy("http://example.com");
|
await httpMod.httpProxy("http://example.com");
|
||||||
|
|
||||||
|
expect(state.lastAgentOptions.keepAlive).toBe(true);
|
||||||
expect(state.lastAgentOptions.family).toBe(4);
|
expect(state.lastAgentOptions.family).toBe(4);
|
||||||
expect(state.lastAgentOptions.autoSelectFamily).toBe(false);
|
expect(state.lastAgentOptions.autoSelectFamily).toBe(false);
|
||||||
});
|
});
|
||||||
@@ -409,6 +414,17 @@ describe("utils/proxy/http httpProxy", () => {
|
|||||||
expect(state.lastAgentOptions.rejectUnauthorized).toBe(false);
|
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 () => {
|
it("returns a sanitized error response when the request fails", async () => {
|
||||||
state.error = Object.assign(new Error("boom"), { code: "EHOSTUNREACH" });
|
state.error = Object.assign(new Error("boom"), { code: "EHOSTUNREACH" });
|
||||||
const httpMod = await import("./http");
|
const httpMod = await import("./http");
|
||||||
|
|||||||
@@ -1,12 +1,40 @@
|
|||||||
|
import cache from "memory-cache";
|
||||||
|
|
||||||
import getServiceWidget from "utils/config/service-helpers";
|
import getServiceWidget from "utils/config/service-helpers";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
import { httpProxy } from "utils/proxy/http";
|
import { httpProxy } from "utils/proxy/http";
|
||||||
|
|
||||||
const proxyName = "omadaProxyHandler";
|
const proxyName = "omadaProxyHandler";
|
||||||
|
const sessionCacheKey = `${proxyName}__session`;
|
||||||
|
|
||||||
const logger = createLogger(proxyName);
|
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 = {
|
const params = {
|
||||||
username,
|
username,
|
||||||
password,
|
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",
|
method: "POST",
|
||||||
body: JSON.stringify(params),
|
body: JSON.stringify(params),
|
||||||
headers: {
|
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) {
|
export default async function omadaProxyHandler(req, res) {
|
||||||
@@ -86,25 +127,40 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sessionCacheId = getSessionCacheId(group, service, index);
|
||||||
|
let session = cache.get(sessionCacheId);
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
||||||
|
try {
|
||||||
|
const usedCachedSession = Boolean(session);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
const [loginStatus, loginResponseData] = await login(
|
const [loginStatus, loginResponseData] = await login(
|
||||||
loginUrl,
|
loginUrl,
|
||||||
widget.username,
|
widget.username,
|
||||||
widget.password,
|
widget.password,
|
||||||
controllerVersionMajor,
|
controllerVersionMajor,
|
||||||
|
sessionCacheId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (loginStatus !== 200 || loginResponseData.errorCode > 0) {
|
if (loginStatus !== 200 || loginResponseData.errorCode > 0) {
|
||||||
return res
|
return res.status(loginStatus).json({
|
||||||
.status(loginStatus)
|
error: { message: "Error logging in to Omada controller", url: loginUrl, data: loginResponseData },
|
||||||
.json({ error: { message: "Error logging in to Omada controller", url: loginUrl, data: loginResponseData } });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { token } = loginResponseData.result;
|
session = cache.get(sessionCacheId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { token, cookieHeader } = session;
|
||||||
|
|
||||||
let sitesUrl;
|
let sitesUrl;
|
||||||
let body = {};
|
let body = {};
|
||||||
let params = { token };
|
let params = { token };
|
||||||
let headers = { "Csrf-Token": token };
|
let headers = { "Csrf-Token": token };
|
||||||
|
if (cookieHeader) {
|
||||||
|
headers.Cookie = cookieHeader;
|
||||||
|
}
|
||||||
let method = "GET";
|
let method = "GET";
|
||||||
|
|
||||||
switch (controllerVersionMajor) {
|
switch (controllerVersionMajor) {
|
||||||
@@ -116,6 +172,10 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
userName: widget.username,
|
userName: widget.username,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
headers = { "Content-Type": "application/json" };
|
||||||
|
if (cookieHeader) {
|
||||||
|
headers.Cookie = cookieHeader;
|
||||||
|
}
|
||||||
method = "POST";
|
method = "POST";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
@@ -133,13 +193,18 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
headers,
|
headers: { ...headers },
|
||||||
});
|
});
|
||||||
|
|
||||||
const sitesResponseData = JSON.parse(data);
|
const sitesResponseData = JSON.parse(data);
|
||||||
|
|
||||||
if (status !== 200 || sitesResponseData.errorCode > 0) {
|
if (status !== 200 || sitesResponseData.errorCode > 0) {
|
||||||
logger.debug(`HTTP ${status} getting sites list: ${sitesResponseData.msg}`);
|
logger.debug(`HTTP ${status} getting sites list: ${sitesResponseData.msg}`);
|
||||||
|
if (shouldRetryWithFreshSession(status, sitesResponseData, attempt, usedCachedSession)) {
|
||||||
|
cache.del(sessionCacheId);
|
||||||
|
session = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
.status(status)
|
.status(status)
|
||||||
.json({ error: { message: "Error getting sites list", url, data: sitesResponseData } });
|
.json({ error: { message: "Error getting sites list", url, data: sitesResponseData } });
|
||||||
@@ -151,7 +216,9 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
: sitesResponseData.result.data.find((s) => s.name === widget.site);
|
: sitesResponseData.result.data.find((s) => s.name === widget.site);
|
||||||
|
|
||||||
if (!site) {
|
if (!site) {
|
||||||
return res.status(status).json({ error: { message: `Site ${widget.site} is not found`, url: sitesUrl, data } });
|
return res
|
||||||
|
.status(status)
|
||||||
|
.json({ error: { message: `Site ${widget.site} is not found`, url: sitesUrl, data } });
|
||||||
}
|
}
|
||||||
|
|
||||||
let siteResponseData;
|
let siteResponseData;
|
||||||
@@ -174,18 +241,26 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
headers = { "Content-Type": "application/json" };
|
headers = { "Content-Type": "application/json" };
|
||||||
|
if (cookieHeader) {
|
||||||
|
headers.Cookie = cookieHeader;
|
||||||
|
}
|
||||||
params = { token };
|
params = { token };
|
||||||
|
|
||||||
[status, contentType, data] = await httpProxy(switchUrl, {
|
[status, contentType, data] = await httpProxy(switchUrl, {
|
||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
headers,
|
headers: { ...headers },
|
||||||
});
|
});
|
||||||
|
|
||||||
const switchResponseData = JSON.parse(data);
|
const switchResponseData = JSON.parse(data);
|
||||||
if (status !== 200 || switchResponseData.errorCode > 0) {
|
if (status !== 200 || switchResponseData.errorCode > 0) {
|
||||||
logger.error(`HTTP ${status} getting sites list: ${data}`);
|
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 } });
|
return res.status(status).json({ error: { message: "Error switching site", url: switchUrl, data } });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,12 +271,17 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
method: "getGlobalStat",
|
method: "getGlobalStat",
|
||||||
}),
|
}),
|
||||||
headers,
|
headers: { ...headers },
|
||||||
});
|
});
|
||||||
|
|
||||||
siteResponseData = JSON.parse(data);
|
siteResponseData = JSON.parse(data);
|
||||||
|
|
||||||
if (status !== 200 || siteResponseData.errorCode > 0) {
|
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 } });
|
return res.status(status).json({ error: { message: "Error getting stats", url: statsUrl, data } });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,15 +296,18 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
: `${url}/${cId}/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, {
|
[status, contentType, data] = await httpProxy(siteStatsUrl, {
|
||||||
headers: {
|
headers: { ...headers },
|
||||||
"Csrf-Token": token,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
siteResponseData = JSON.parse(data);
|
siteResponseData = JSON.parse(data);
|
||||||
|
|
||||||
if (status !== 200 || siteResponseData.errorCode > 0) {
|
if (status !== 200 || siteResponseData.errorCode > 0) {
|
||||||
logger.debug(`HTTP ${status} getting stats for site ${widget.site} with message ${siteResponseData.msg}`);
|
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({
|
return res.status(status === 200 ? 500 : status).json({
|
||||||
error: {
|
error: {
|
||||||
message: "Error getting stats",
|
message: "Error getting stats",
|
||||||
@@ -240,12 +323,25 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
: `${url}/${cId}/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, {
|
[status, contentType, data] = await httpProxy(alertUrl, {
|
||||||
headers: {
|
headers: { ...headers },
|
||||||
"Csrf-Token": token,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const alertResponseData = JSON.parse(data);
|
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;
|
activeUser = siteResponseData.result.totalClientNum;
|
||||||
connectedAp = siteResponseData.result.connectedApNum;
|
connectedAp = siteResponseData.result.connectedApNum;
|
||||||
connectedGateways = siteResponseData.result.connectedGatewayNum;
|
connectedGateways = siteResponseData.result.connectedGatewayNum;
|
||||||
@@ -262,6 +358,16 @@ export default async function omadaProxyHandler(req, res) {
|
|||||||
connectedSwitches,
|
connectedSwitches,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof SyntaxError && attempt === 0) {
|
||||||
|
cache.del(sessionCacheId);
|
||||||
|
session = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,24 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
|
|
||||||
import createMockRes from "test-utils/create-mock-res";
|
import createMockRes from "test-utils/create-mock-res";
|
||||||
|
|
||||||
const { httpProxy, getServiceWidget, logger } = vi.hoisted(() => ({
|
const { httpProxy, getServiceWidget, cache, logger } = vi.hoisted(() => {
|
||||||
|
const store = new Map();
|
||||||
|
|
||||||
|
return {
|
||||||
httpProxy: vi.fn(),
|
httpProxy: vi.fn(),
|
||||||
getServiceWidget: 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: {
|
logger: {
|
||||||
debug: vi.fn(),
|
debug: vi.fn(),
|
||||||
error: vi.fn(),
|
error: vi.fn(),
|
||||||
},
|
},
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
|
||||||
vi.mock("utils/logger", () => ({
|
vi.mock("utils/logger", () => ({
|
||||||
default: () => logger,
|
default: () => logger,
|
||||||
@@ -20,15 +30,19 @@ vi.mock("utils/config/service-helpers", () => ({
|
|||||||
vi.mock("utils/proxy/http", () => ({
|
vi.mock("utils/proxy/http", () => ({
|
||||||
httpProxy,
|
httpProxy,
|
||||||
}));
|
}));
|
||||||
|
vi.mock("memory-cache", () => ({
|
||||||
|
default: cache,
|
||||||
|
...cache,
|
||||||
|
}));
|
||||||
|
|
||||||
import omadaProxyHandler from "./proxy";
|
import omadaProxyHandler from "./proxy";
|
||||||
|
|
||||||
describe("widgets/omada/proxy", () => {
|
describe("widgets/omada/proxy", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
// Clear one-off implementations between tests (some branches return early).
|
|
||||||
httpProxy.mockReset();
|
httpProxy.mockReset();
|
||||||
getServiceWidget.mockReset();
|
getServiceWidget.mockReset();
|
||||||
|
cache._reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fetches controller info, logs in, selects site, and returns overview stats (v4)", async () => {
|
it("fetches controller info, logs in, selects site, and returns overview stats (v4)", async () => {
|
||||||
@@ -51,6 +65,7 @@ describe("widgets/omada/proxy", () => {
|
|||||||
200,
|
200,
|
||||||
"application/json",
|
"application/json",
|
||||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
||||||
|
{ "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] },
|
||||||
])
|
])
|
||||||
// sites list
|
// sites list
|
||||||
.mockResolvedValueOnce([
|
.mockResolvedValueOnce([
|
||||||
@@ -91,6 +106,12 @@ describe("widgets/omada/proxy", () => {
|
|||||||
connectedSwitches: 3,
|
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 () => {
|
it("returns an error when controller info cannot be retrieved", async () => {
|
||||||
@@ -169,6 +190,7 @@ describe("widgets/omada/proxy", () => {
|
|||||||
200,
|
200,
|
||||||
"application/json",
|
"application/json",
|
||||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
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" })]);
|
.mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 2, msg: "bad" })]);
|
||||||
|
|
||||||
@@ -195,6 +217,7 @@ describe("widgets/omada/proxy", () => {
|
|||||||
200,
|
200,
|
||||||
"application/json",
|
"application/json",
|
||||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
||||||
|
{ "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] },
|
||||||
])
|
])
|
||||||
.mockResolvedValueOnce([
|
.mockResolvedValueOnce([
|
||||||
200,
|
200,
|
||||||
@@ -222,6 +245,7 @@ describe("widgets/omada/proxy", () => {
|
|||||||
200,
|
200,
|
||||||
"application/json",
|
"application/json",
|
||||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
||||||
|
{ "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] },
|
||||||
])
|
])
|
||||||
// getUserSites
|
// getUserSites
|
||||||
.mockResolvedValueOnce([
|
.mockResolvedValueOnce([
|
||||||
@@ -271,6 +295,7 @@ describe("widgets/omada/proxy", () => {
|
|||||||
200,
|
200,
|
||||||
"application/json",
|
"application/json",
|
||||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
||||||
|
{ "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] },
|
||||||
])
|
])
|
||||||
.mockResolvedValueOnce([
|
.mockResolvedValueOnce([
|
||||||
200,
|
200,
|
||||||
@@ -301,6 +326,7 @@ describe("widgets/omada/proxy", () => {
|
|||||||
200,
|
200,
|
||||||
"application/json",
|
"application/json",
|
||||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
||||||
|
{ "set-cookie": ["TPOMADA_SESSIONID=sid; Path=/; HttpOnly"] },
|
||||||
])
|
])
|
||||||
.mockResolvedValueOnce([
|
.mockResolvedValueOnce([
|
||||||
200,
|
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("<!DOCTYPE html>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,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const widget = {
|
|||||||
endpoint: "org/{org}/sites",
|
endpoint: "org/{org}/sites",
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
endpoint: "org/{org}/resources",
|
endpoint: "org/{org}/resources?pageSize=200",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,17 +45,20 @@ async function fetchFromPyloadAPI(url, sessionId, params, service) {
|
|||||||
return [status, returnData, responseHeaders];
|
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 parsedUrl = new URL(url);
|
||||||
const isGetRequest = !params || Object.keys(params).length === 0;
|
const isGetRequest = !params || Object.keys(params).length === 0;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
method: isGetRequest ? "GET" : "POST",
|
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 (isGetRequest) {
|
||||||
if (params) {
|
if (params) {
|
||||||
Object.keys(params).forEach((key) => parsedUrl.searchParams.append(key, params[key]));
|
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 url = new URL(formatApiCall(apiTemplate, { endpoint, ...widget }));
|
||||||
const ngUrl = ngEndpoint ? new URL(formatApiCall(apiTemplate, { endpoint: ngEndpoint, ...widget })) : url;
|
const ngUrl = ngEndpoint ? new URL(formatApiCall(apiTemplate, { endpoint: ngEndpoint, ...widget })) : url;
|
||||||
const loginUrl = `${widget.url}/api/login`;
|
const loginUrl = `${widget.url}/api/login`;
|
||||||
const hasCredentials = widget.username && widget.password;
|
const hasCredentials = widget.key || (widget.username && widget.password);
|
||||||
|
|
||||||
if (hasCredentials) {
|
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) {
|
if (status === 200 && !data?.error) {
|
||||||
cache.put(`${isNgCacheKey}.${service}`, true);
|
cache.put(`${isNgCacheKey}.${service}`, true);
|
||||||
@@ -117,9 +126,7 @@ export default async function pyloadProxyHandler(req, res, map = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status === 401) {
|
if (status === 401) {
|
||||||
return res
|
return res.status(status).send({ error: "Invalid credentials communicating with Pyload API", data });
|
||||||
.status(status)
|
|
||||||
.send({ error: { message: "Invalid credentials communicating with Pyload API", data } });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,46 @@ describe("widgets/pyload/proxy", () => {
|
|||||||
expect(res.body).toEqual({ ok: true });
|
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 () => {
|
it("retries after 403 by clearing session and logging in again", async () => {
|
||||||
getServiceWidget.mockResolvedValue({
|
getServiceWidget.mockResolvedValue({
|
||||||
type: "pyload",
|
type: "pyload",
|
||||||
|
|||||||
Reference in New Issue
Block a user