8 Commits
Author SHA1 Message Date
sharang ac28e2256f fix(ci): docker:27-cli image job; clear postcss and sharp HIGHs (#24)
ci / test (push) Successful in 10m17s
ci / e2e (push) Blocked by required conditions
ci / shared (push) Successful in 14s
ci / image (push) Successful in 50s
2026-08-31 15:51:39 +00:00
sharang 63fde7993c fix(deps): next-auth beta.32 — the advisory targets next-auth itself (#23)
ci / e2e (push) Blocked by required conditions
ci / shared (push) Failing after 12s
ci / test (push) Successful in 10m14s
ci / image (push) Skipped
2026-08-31 08:40:14 +00:00
sharang ba483cae97 fix(ci): make main deployable again — coverage, CVEs, and the image job (#22)
ci / e2e (push) Blocked by required conditions
ci / shared (push) Failing after 12s
ci / test (push) Successful in 10m17s
ci / image (push) Skipped
2026-08-30 21:33:08 +00:00
sharang f2f9ab74c8 RBAC: send a client_credentials service token to tenant-registry (#21)
ci / shared (push) Failing after 12s
ci / test (push) Failing after 5m3s
ci / e2e (push) Skipped
ci / image (push) Skipped
2026-08-25 09:15:47 +00:00
sharang 7e62c0162f Repoint registry.breakpilot.com -> repo.breakpilot.com (Harbor) (#20)
ci / shared (push) Failing after 11s
ci / test (push) Successful in 10m16s
ci / image (push) Skipped
ci / e2e (push) Canceled after 0s
2026-08-09 21:22:10 +00:00
sharang 329cc0e57a chore(ci): repoint registry/git/cargo meghsakha.com -> breakpilot.com (#19)
ci / test (push) Successful in 10m16s
ci / image (push) Skipped
ci / e2e (push) Canceled after 0s
ci / shared (push) Failing after 12s
2026-08-06 09:49:52 +00:00
sharang da6b8f70c5 Merge pull request 'ci: fix cosign signing (install fallback, env-style login, portal sign step)' (#18) from ci/cosign-fixes into main
ci / shared (push) Failing after 12s
ci / test (push) Successful in 10m14s
ci / image (push) Skipped
ci / e2e (push) Canceled after 0s
2026-07-22 07:46:02 +00:00
sharang a3c1bb075c ci: fix cosign install (curl->wget fallback), env-style registry login, portal sign step
ci / test (pull_request) Successful in 10m20s
ci / shared (pull_request) Failing after 5s
ci / image (pull_request) Skipped
ci / e2e (pull_request) Canceled after 0s
2026-07-22 07:44:16 +00:00
7 changed files with 632 additions and 314 deletions
+43 -22
View File
@@ -114,37 +114,58 @@ jobs:
image: image:
# Builds the portal image and ships it through the same path every # Builds the portal image and ships it through the same path every
# other service in orca-infra uses: push :latest + :sha-<sha> to # other service in orca-infra uses: push :latest + :sha-<sha> to
# repo.meghsakha.com, then POST a github-style payload to the # repo.breakpilot.com, then POST a github-style payload to the
# orca webhook so the master pulls and redeploys breakpilot-portal. # orca webhook so the master pulls and redeploys the portal services.
#
# Webhook target (registered once on the master via
# orca webhooks add --repo platform/portal \
# --service breakpilot-portal --branch main
# ) accepts unsigned payloads — orca matches on repo + branch.
needs: [shared, test] needs: [shared, test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && hashFiles('Dockerfile') != '' # NOTE: no hashFiles() here — at job level it evaluates BEFORE checkout
# against an empty workspace, so the old condition was always false and
# this job silently never ran (deployment sat on a June-10 image).
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: docker runs-on: docker
# The runner's default job container has no docker CLI, so
# docker/login-action + docker/build-push-action die with "Unable to
# locate executable file: docker" (proven by tenant-registry run 5441).
# Same pattern as the proven breakpilot-compliance build-push-deploy.yml:
# run in docker:27-cli and use plain docker commands.
container: docker:27-cli
steps: steps:
- uses: actions/checkout@v4 - name: Checkout
- uses: docker/login-action@v3 run: |
with: apk add --no-cache git curl openssl
registry: repo.meghsakha.com git clone --depth 1 --branch ${GITHUB_REF_NAME} $(echo ${GITHUB_SERVER_URL} | sed -E "s#^(https?://)#\1ci:${{ secrets.GITHUB_TOKEN }}@#")/${GITHUB_REPOSITORY}.git .
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }} - name: Login
- uses: docker/build-push-action@v6 env:
with: REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
push: true REGISTRY_PASS: ${{ secrets.REGISTRY_PASS }}
tags: | run: echo "$REGISTRY_PASS" | docker login repo.breakpilot.com -u "$REGISTRY_USER" --password-stdin
repo.meghsakha.com/breakpilot/portal:latest
repo.meghsakha.com/breakpilot/portal:sha-${{ github.sha }} - name: Build + push
run: |
set -eu
docker build \
-t repo.breakpilot.com/breakpilot/portal:latest \
-t repo.breakpilot.com/breakpilot/portal:sha-${GITHUB_SHA} \
.
docker push repo.breakpilot.com/breakpilot/portal:latest
docker push repo.breakpilot.com/breakpilot/portal:sha-${GITHUB_SHA}
- name: sign image (cosign)
run: |
{ command -v cosign >/dev/null 2>&1 || curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 || wget -qO /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64; } || echo "::warning::cosign fetch failed"
chmod +x /usr/local/bin/cosign 2>/dev/null || true
cosign sign --yes --key env://COSIGN_KEY repo.breakpilot.com/breakpilot/portal:latest || echo "::warning::cosign failed"
- name: trigger orca redeploy - name: trigger orca redeploy
# Signs the POST with HMAC-SHA256 over the JSON body using the # Signs the POST with HMAC-SHA256 over the JSON body using the
# secret orca generated when the webhook was registered. Orca's # secret orca generated when the webhook was registered. Orca's
# endpoint is publicly reachable on the master, so the signature # endpoint is publicly reachable on the master, so the signature
# gates who can fire a deploy. # gates who can fire a deploy. Plain http like the proven
# compliance trigger-orca job (the endpoint does not serve TLS).
env: env:
ORCA_WEBHOOK_SECRET: ${{ secrets.ORCA_WEBHOOK_SECRET }} ORCA_WEBHOOK_SECRET: ${{ secrets.ORCA_WEBHOOK_SECRET }}
run: | run: |
set -eu
BODY='{"repository":{"full_name":"platform/portal"},"ref":"refs/heads/main"}' BODY='{"repository":{"full_name":"platform/portal"},"ref":"refs/heads/main"}'
SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$ORCA_WEBHOOK_SECRET" -hex | awk '{print $NF}')" SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$ORCA_WEBHOOK_SECRET" -hex | awk '{print $NF}')"
curl -ksSf -X POST \ curl -ksSf -X POST \
@@ -152,4 +173,4 @@ jobs:
-H "X-GitHub-Event: push" \ -H "X-GitHub-Event: push" \
-H "X-Hub-Signature-256: $SIG" \ -H "X-Hub-Signature-256: $SIG" \
-d "$BODY" \ -d "$BODY" \
https://46.225.100.82:6880/api/v1/webhooks/github http://46.225.100.82:6880/api/v1/webhooks/github
+4 -4
View File
@@ -22,7 +22,7 @@ jobs:
- name: verify stage soak (>= 24h on this image) - name: verify stage soak (>= 24h on this image)
run: | run: |
IMG=registry.breakpilot.com/${{ github.event.repository.name }}:env-stage IMG=repo.breakpilot.com/breakpilot/${{ github.event.repository.name }}:env-stage
SOAK_SECONDS=$(orca image-age --env=stage --image $IMG) SOAK_SECONDS=$(orca image-age --env=stage --image $IMG)
if [ "$SOAK_SECONDS" -lt 86400 ]; then if [ "$SOAK_SECONDS" -lt 86400 ]; then
echo "Stage soak only $SOAK_SECONDS s, < 24h. Aborting." echo "Stage soak only $SOAK_SECONDS s, < 24h. Aborting."
@@ -34,12 +34,12 @@ jobs:
- name: re-tag image as semver + env-prod - name: re-tag image as semver + env-prod
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: registry.breakpilot.com registry: repo.breakpilot.com
username: ${{ secrets.REGISTRY_USER }} username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }} password: ${{ secrets.REGISTRY_PASS }}
- run: | - run: |
IMG=registry.breakpilot.com/${{ github.event.repository.name }} IMG=repo.breakpilot.com/breakpilot/${{ github.event.repository.name }}
docker pull $IMG:env-stage docker pull $IMG:env-stage
docker tag $IMG:env-stage $IMG:v${{ steps.v.outputs.version }} docker tag $IMG:env-stage $IMG:v${{ steps.v.outputs.version }}
docker tag $IMG:env-stage $IMG:env-prod docker tag $IMG:env-stage $IMG:env-prod
@@ -67,7 +67,7 @@ jobs:
curl -X POST -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ curl -X POST -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$(jq -Rs '{tag_name:"v${{ steps.v.outputs.version }}", name:"v${{ steps.v.outputs.version }}", body:.}' < RELEASE_NOTES.md)" \ -d "$(jq -Rs '{tag_name:"v${{ steps.v.outputs.version }}", name:"v${{ steps.v.outputs.version }}", body:.}' < RELEASE_NOTES.md)" \
https://gitea.meghsakha.com/api/v1/repos/${{ github.repository }}/releases https://git.breakpilot.com/api/v1/repos/${{ github.repository }}/releases
rollback-on-failure: rollback-on-failure:
needs: promote needs: promote
+10 -2
View File
@@ -23,8 +23,8 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"geist": "^1.7.2", "geist": "^1.7.2",
"lucide-react": "^1.17.0", "lucide-react": "^1.17.0",
"next": "16.2.6", "next": "16.2.11",
"next-auth": "5.0.0-beta.25", "next-auth": "5.0.0-beta.32",
"react": "19.0.0", "react": "19.0.0",
"react-dom": "19.0.0", "react-dom": "19.0.0",
"tailwind-merge": "^3.6.0" "tailwind-merge": "^3.6.0"
@@ -48,5 +48,13 @@
"workerDirectory": [ "workerDirectory": [
"public" "public"
] ]
},
"pnpm": {
"overrides": {
"nanoid@<3.3.18": ">=3.3.18",
"postcss@<8.5.18": ">=8.5.18",
"@auth/core@<0.41.3": ">=0.41.3",
"sharp@<0.35.0": ">=0.35.0"
}
} }
} }
+304 -284
View File
@@ -4,6 +4,12 @@ settings:
autoInstallPeers: true autoInstallPeers: true
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
overrides:
nanoid@<3.3.18: '>=3.3.18'
postcss@<8.5.18: '>=8.5.18'
'@auth/core@<0.41.3': '>=0.41.3'
sharp@<0.35.0: '>=0.35.0'
importers: importers:
.: .:
@@ -16,16 +22,16 @@ importers:
version: 2.1.1 version: 2.1.1
geist: geist:
specifier: ^1.7.2 specifier: ^1.7.2
version: 1.7.2(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) version: 1.7.2(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
lucide-react: lucide-react:
specifier: ^1.17.0 specifier: ^1.17.0
version: 1.17.0(react@19.0.0) version: 1.17.0(react@19.0.0)
next: next:
specifier: 16.2.6 specifier: 16.2.11
version: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) version: 16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
next-auth: next-auth:
specifier: 5.0.0-beta.25 specifier: 5.0.0-beta.32
version: 5.0.0-beta.25(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) version: 5.0.0-beta.32(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
react: react:
specifier: 19.0.0 specifier: 19.0.0
version: 19.0.0 version: 19.0.0
@@ -64,8 +70,8 @@ importers:
specifier: ^2.14.6 specifier: ^2.14.6
version: 2.14.6(@types/node@20.16.10)(typescript@5.7.2) version: 2.14.6(@types/node@20.16.10)(typescript@5.7.2)
postcss: postcss:
specifier: ^8.5.15 specifier: '>=8.5.18'
version: 8.5.15 version: 8.5.26
tailwindcss: tailwindcss:
specifier: ^4.3.0 specifier: ^4.3.0
version: 4.3.0 version: 4.3.0
@@ -86,12 +92,12 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
'@auth/core@0.37.2': '@auth/core@0.41.3':
resolution: {integrity: sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==} resolution: {integrity: sha512-sJ3JMHHkXMD3aOjopv7mOBTO1Ocw4b0fAEXJBz6k7YHLpYQI6C40jCUPc5fNvUKxXRXNE1/sRISA15UrwWJBTw==}
peerDependencies: peerDependencies:
'@simplewebauthn/browser': ^9.0.1 '@simplewebauthn/browser': ^9.0.1
'@simplewebauthn/server': ^9.0.2 '@simplewebauthn/server': ^9.0.2
nodemailer: ^6.8.0 nodemailer: ^7.0.7 || ^8.0.5
peerDependenciesMeta: peerDependenciesMeta:
'@simplewebauthn/browser': '@simplewebauthn/browser':
optional: true optional: true
@@ -176,6 +182,9 @@ packages:
'@emnapi/runtime@1.10.0': '@emnapi/runtime@1.10.0':
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
'@emnapi/runtime@1.11.3':
resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
'@emnapi/wasi-threads@1.2.1': '@emnapi/wasi-threads@1.2.1':
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
@@ -379,136 +388,145 @@ packages:
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@img/sharp-darwin-arm64@0.34.5': '@img/sharp-darwin-arm64@0.35.4':
resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@img/sharp-darwin-x64@0.34.5': '@img/sharp-darwin-x64@0.35.4':
resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@img/sharp-libvips-darwin-arm64@1.2.4': '@img/sharp-freebsd-wasm32@0.35.4':
resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==}
engines: {node: '>=20.9.0'}
os: [freebsd]
'@img/sharp-libvips-darwin-arm64@1.3.3':
resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@img/sharp-libvips-darwin-x64@1.2.4': '@img/sharp-libvips-darwin-x64@1.3.3':
resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@img/sharp-libvips-linux-arm64@1.2.4': '@img/sharp-libvips-linux-arm64@1.3.3':
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@img/sharp-libvips-linux-arm@1.2.4': '@img/sharp-libvips-linux-arm@1.3.3':
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@img/sharp-libvips-linux-ppc64@1.2.4': '@img/sharp-libvips-linux-ppc64@1.3.3':
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@img/sharp-libvips-linux-riscv64@1.2.4': '@img/sharp-libvips-linux-riscv64@1.3.3':
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@img/sharp-libvips-linux-s390x@1.2.4': '@img/sharp-libvips-linux-s390x@1.3.3':
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@img/sharp-libvips-linux-x64@1.2.4': '@img/sharp-libvips-linux-x64@1.3.3':
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@img/sharp-libvips-linuxmusl-arm64@1.2.4': '@img/sharp-libvips-linuxmusl-arm64@1.3.3':
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@img/sharp-libvips-linuxmusl-x64@1.2.4': '@img/sharp-libvips-linuxmusl-x64@1.3.3':
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@img/sharp-linux-arm64@0.34.5': '@img/sharp-linux-arm64@0.35.4':
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@img/sharp-linux-arm@0.34.5': '@img/sharp-linux-arm@0.35.4':
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@img/sharp-linux-ppc64@0.34.5': '@img/sharp-linux-ppc64@0.35.4':
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@img/sharp-linux-riscv64@0.34.5': '@img/sharp-linux-riscv64@0.35.4':
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@img/sharp-linux-s390x@0.34.5': '@img/sharp-linux-s390x@0.35.4':
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@img/sharp-linux-x64@0.34.5': '@img/sharp-linux-x64@0.35.4':
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@img/sharp-linuxmusl-arm64@0.34.5': '@img/sharp-linuxmusl-arm64@0.35.4':
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@img/sharp-linuxmusl-x64@0.34.5': '@img/sharp-linuxmusl-x64@0.35.4':
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@img/sharp-wasm32@0.34.5': '@img/sharp-wasm32@0.35.4':
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
'@img/sharp-webcontainers-wasm32@0.35.4':
resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==}
engines: {node: '>=20.9.0'}
cpu: [wasm32] cpu: [wasm32]
'@img/sharp-win32-arm64@0.34.5': '@img/sharp-win32-arm64@0.35.4':
resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@img/sharp-win32-ia32@0.34.5': '@img/sharp-win32-ia32@0.35.4':
resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^20.9.0}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@img/sharp-win32-x64@0.34.5': '@img/sharp-win32-x64@0.35.4':
resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -581,56 +599,56 @@ packages:
'@emnapi/core': ^1.7.1 '@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1 '@emnapi/runtime': ^1.7.1
'@next/env@16.2.6': '@next/env@16.2.11':
resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} resolution: {integrity: sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==}
'@next/eslint-plugin-next@16.2.6': '@next/eslint-plugin-next@16.2.6':
resolution: {integrity: sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==} resolution: {integrity: sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==}
'@next/swc-darwin-arm64@16.2.6': '@next/swc-darwin-arm64@16.2.11':
resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==} resolution: {integrity: sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@next/swc-darwin-x64@16.2.6': '@next/swc-darwin-x64@16.2.11':
resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==} resolution: {integrity: sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@next/swc-linux-arm64-gnu@16.2.6': '@next/swc-linux-arm64-gnu@16.2.11':
resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==} resolution: {integrity: sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-arm64-musl@16.2.6': '@next/swc-linux-arm64-musl@16.2.11':
resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==} resolution: {integrity: sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-x64-gnu@16.2.6': '@next/swc-linux-x64-gnu@16.2.11':
resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==} resolution: {integrity: sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-linux-x64-musl@16.2.6': '@next/swc-linux-x64-musl@16.2.11':
resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==} resolution: {integrity: sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-win32-arm64-msvc@16.2.6': '@next/swc-win32-arm64-msvc@16.2.11':
resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==} resolution: {integrity: sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@next/swc-win32-x64-msvc@16.2.6': '@next/swc-win32-x64-msvc@16.2.11':
resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==} resolution: {integrity: sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -897,9 +915,6 @@ packages:
'@tybys/wasm-util@0.10.2': '@tybys/wasm-util@0.10.2':
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
'@types/estree@1.0.8': '@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -1315,10 +1330,6 @@ packages:
convert-source-map@2.0.0: convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
cookie@0.7.1:
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
engines: {node: '>= 0.6'}
cookie@1.1.1: cookie@1.1.1:
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -1931,8 +1942,8 @@ packages:
resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
hasBin: true hasBin: true
jose@5.10.0: jose@6.2.10:
resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} resolution: {integrity: sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==}
js-tokens@4.0.0: js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -2134,9 +2145,9 @@ packages:
resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==}
engines: {node: ^20.17.0 || >=22.9.0} engines: {node: ^20.17.0 || >=22.9.0}
nanoid@3.3.12: nanoid@6.0.1:
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} resolution: {integrity: sha512-3wVS3i51pE2pi1k5FFL/95BGfVS0kSsvDVuGXHOtxox/TywUmtgq+3qiTOTbs9J7KfHaXPiN171k/A6dBnaXFw==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^22 || ^24 || >=26}
hasBin: true hasBin: true
napi-postinstall@0.3.4: napi-postinstall@0.3.4:
@@ -2147,14 +2158,14 @@ packages:
natural-compare@1.4.0: natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
next-auth@5.0.0-beta.25: next-auth@5.0.0-beta.32:
resolution: {integrity: sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog==} resolution: {integrity: sha512-CGlChIEWZ6LltNVxrE5yiySMID+Idpmry47JYA5lLwgD8Sx02a8M65VL0TWVz9nbnOioS/tCW/rP/0+mE7Qp4Q==}
peerDependencies: peerDependencies:
'@simplewebauthn/browser': ^9.0.1 '@simplewebauthn/browser': ^9.0.1
'@simplewebauthn/server': ^9.0.2 '@simplewebauthn/server': ^9.0.2
next: ^14.0.0-0 || ^15.0.0-0 next: ^14.0.0-0 || ^15.0.0 || ^16.0.0
nodemailer: ^6.6.5 nodemailer: ^7.0.7 || ^8.0.5
react: ^18.2.0 || ^19.0.0-0 react: ^18.2.0 || ^19.0.0
peerDependenciesMeta: peerDependenciesMeta:
'@simplewebauthn/browser': '@simplewebauthn/browser':
optional: true optional: true
@@ -2163,8 +2174,8 @@ packages:
nodemailer: nodemailer:
optional: true optional: true
next@16.2.6: next@16.2.11:
resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} resolution: {integrity: sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==}
engines: {node: '>=20.9.0'} engines: {node: '>=20.9.0'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -2302,29 +2313,22 @@ packages:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
postcss@8.4.31: postcss@8.5.26:
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
postcss@8.5.15: preact-render-to-string@6.5.11:
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==}
engines: {node: ^10 || ^12 || >=14}
preact-render-to-string@5.2.3:
resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==}
peerDependencies: peerDependencies:
preact: '>=10' preact: '>=10'
preact@10.11.3: preact@10.24.3:
resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==} resolution: {integrity: sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==}
prelude-ls@1.2.1: prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
pretty-format@3.8.0:
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
prop-types@15.8.1: prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -2410,6 +2414,11 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
hasBin: true hasBin: true
semver@7.8.5:
resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
engines: {node: '>=10'}
hasBin: true
set-cookie-parser@3.1.0: set-cookie-parser@3.1.0:
resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==}
@@ -2425,9 +2434,14 @@ packages:
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
sharp@0.34.5: sharp@0.35.4:
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: '>=20.9.0'}
peerDependencies:
'@types/node': '*'
peerDependenciesMeta:
'@types/node':
optional: true
shebang-command@2.0.0: shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
@@ -2813,15 +2827,13 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.13 '@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31 '@jridgewell/trace-mapping': 0.3.31
'@auth/core@0.37.2': '@auth/core@0.41.3':
dependencies: dependencies:
'@panva/hkdf': 1.2.1 '@panva/hkdf': 1.2.1
'@types/cookie': 0.6.0 jose: 6.2.10
cookie: 0.7.1
jose: 5.10.0
oauth4webapi: 3.8.6 oauth4webapi: 3.8.6
preact: 10.11.3 preact: 10.24.3
preact-render-to-string: 5.2.3(preact@10.11.3) preact-render-to-string: 6.5.11(preact@10.24.3)
'@babel/code-frame@7.29.0': '@babel/code-frame@7.29.0':
dependencies: dependencies:
@@ -2936,6 +2948,11 @@ snapshots:
tslib: 2.8.1 tslib: 2.8.1
optional: true optional: true
'@emnapi/runtime@1.11.3':
dependencies:
tslib: 2.8.1
optional: true
'@emnapi/wasi-threads@1.2.1': '@emnapi/wasi-threads@1.2.1':
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
@@ -3075,98 +3092,108 @@ snapshots:
'@img/colour@1.1.0': '@img/colour@1.1.0':
optional: true optional: true
'@img/sharp-darwin-arm64@0.34.5': '@img/sharp-darwin-arm64@0.35.4':
optionalDependencies: optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.2.4 '@img/sharp-libvips-darwin-arm64': 1.3.3
optional: true optional: true
'@img/sharp-darwin-x64@0.34.5': '@img/sharp-darwin-x64@0.35.4':
optionalDependencies: optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.2.4 '@img/sharp-libvips-darwin-x64': 1.3.3
optional: true optional: true
'@img/sharp-libvips-darwin-arm64@1.2.4': '@img/sharp-freebsd-wasm32@0.35.4':
optional: true
'@img/sharp-libvips-darwin-x64@1.2.4':
optional: true
'@img/sharp-libvips-linux-arm64@1.2.4':
optional: true
'@img/sharp-libvips-linux-arm@1.2.4':
optional: true
'@img/sharp-libvips-linux-ppc64@1.2.4':
optional: true
'@img/sharp-libvips-linux-riscv64@1.2.4':
optional: true
'@img/sharp-libvips-linux-s390x@1.2.4':
optional: true
'@img/sharp-libvips-linux-x64@1.2.4':
optional: true
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
optional: true
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
optional: true
'@img/sharp-linux-arm64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.2.4
optional: true
'@img/sharp-linux-arm@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.2.4
optional: true
'@img/sharp-linux-ppc64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-ppc64': 1.2.4
optional: true
'@img/sharp-linux-riscv64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-riscv64': 1.2.4
optional: true
'@img/sharp-linux-s390x@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.2.4
optional: true
'@img/sharp-linux-x64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.2.4
optional: true
'@img/sharp-linuxmusl-arm64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
optional: true
'@img/sharp-linuxmusl-x64@0.34.5':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
optional: true
'@img/sharp-wasm32@0.34.5':
dependencies: dependencies:
'@emnapi/runtime': 1.10.0 '@img/sharp-wasm32': 0.35.4
optional: true optional: true
'@img/sharp-win32-arm64@0.34.5': '@img/sharp-libvips-darwin-arm64@1.3.3':
optional: true optional: true
'@img/sharp-win32-ia32@0.34.5': '@img/sharp-libvips-darwin-x64@1.3.3':
optional: true optional: true
'@img/sharp-win32-x64@0.34.5': '@img/sharp-libvips-linux-arm64@1.3.3':
optional: true
'@img/sharp-libvips-linux-arm@1.3.3':
optional: true
'@img/sharp-libvips-linux-ppc64@1.3.3':
optional: true
'@img/sharp-libvips-linux-riscv64@1.3.3':
optional: true
'@img/sharp-libvips-linux-s390x@1.3.3':
optional: true
'@img/sharp-libvips-linux-x64@1.3.3':
optional: true
'@img/sharp-libvips-linuxmusl-arm64@1.3.3':
optional: true
'@img/sharp-libvips-linuxmusl-x64@1.3.3':
optional: true
'@img/sharp-linux-arm64@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.3.3
optional: true
'@img/sharp-linux-arm@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.3.3
optional: true
'@img/sharp-linux-ppc64@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linux-ppc64': 1.3.3
optional: true
'@img/sharp-linux-riscv64@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linux-riscv64': 1.3.3
optional: true
'@img/sharp-linux-s390x@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.3.3
optional: true
'@img/sharp-linux-x64@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.3.3
optional: true
'@img/sharp-linuxmusl-arm64@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.3.3
optional: true
'@img/sharp-linuxmusl-x64@0.35.4':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.3.3
optional: true
'@img/sharp-wasm32@0.35.4':
dependencies:
'@emnapi/runtime': 1.11.3
optional: true
'@img/sharp-webcontainers-wasm32@0.35.4':
dependencies:
'@img/sharp-wasm32': 0.35.4
optional: true
'@img/sharp-win32-arm64@0.35.4':
optional: true
'@img/sharp-win32-ia32@0.35.4':
optional: true
'@img/sharp-win32-x64@0.35.4':
optional: true optional: true
'@inquirer/ansi@2.0.7': {} '@inquirer/ansi@2.0.7': {}
@@ -3242,34 +3269,34 @@ snapshots:
'@tybys/wasm-util': 0.10.2 '@tybys/wasm-util': 0.10.2
optional: true optional: true
'@next/env@16.2.6': {} '@next/env@16.2.11': {}
'@next/eslint-plugin-next@16.2.6': '@next/eslint-plugin-next@16.2.6':
dependencies: dependencies:
fast-glob: 3.3.1 fast-glob: 3.3.1
'@next/swc-darwin-arm64@16.2.6': '@next/swc-darwin-arm64@16.2.11':
optional: true optional: true
'@next/swc-darwin-x64@16.2.6': '@next/swc-darwin-x64@16.2.11':
optional: true optional: true
'@next/swc-linux-arm64-gnu@16.2.6': '@next/swc-linux-arm64-gnu@16.2.11':
optional: true optional: true
'@next/swc-linux-arm64-musl@16.2.6': '@next/swc-linux-arm64-musl@16.2.11':
optional: true optional: true
'@next/swc-linux-x64-gnu@16.2.6': '@next/swc-linux-x64-gnu@16.2.11':
optional: true optional: true
'@next/swc-linux-x64-musl@16.2.6': '@next/swc-linux-x64-musl@16.2.11':
optional: true optional: true
'@next/swc-win32-arm64-msvc@16.2.6': '@next/swc-win32-arm64-msvc@16.2.11':
optional: true optional: true
'@next/swc-win32-x64-msvc@16.2.6': '@next/swc-win32-x64-msvc@16.2.11':
optional: true optional: true
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
@@ -3453,7 +3480,7 @@ snapshots:
'@alloc/quick-lru': 5.2.0 '@alloc/quick-lru': 5.2.0
'@tailwindcss/node': 4.3.0 '@tailwindcss/node': 4.3.0
'@tailwindcss/oxide': 4.3.0 '@tailwindcss/oxide': 4.3.0
postcss: 8.5.15 postcss: 8.5.26
tailwindcss: 4.3.0 tailwindcss: 4.3.0
'@tybys/wasm-util@0.10.2': '@tybys/wasm-util@0.10.2':
@@ -3461,8 +3488,6 @@ snapshots:
tslib: 2.8.1 tslib: 2.8.1
optional: true optional: true
'@types/cookie@0.6.0': {}
'@types/estree@1.0.8': {} '@types/estree@1.0.8': {}
'@types/estree@1.0.9': {} '@types/estree@1.0.9': {}
@@ -3910,8 +3935,6 @@ snapshots:
convert-source-map@2.0.0: {} convert-source-map@2.0.0: {}
cookie@0.7.1: {}
cookie@1.1.1: {} cookie@1.1.1: {}
cross-spawn@7.0.6: cross-spawn@7.0.6:
@@ -4415,9 +4438,9 @@ snapshots:
functions-have-names@1.2.3: {} functions-have-names@1.2.3: {}
geist@1.7.2(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)): geist@1.7.2(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)):
dependencies: dependencies:
next: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: 16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
generator-function@2.0.1: {} generator-function@2.0.1: {}
@@ -4695,7 +4718,7 @@ snapshots:
jiti@2.7.0: {} jiti@2.7.0: {}
jose@5.10.0: {} jose@6.2.10: {}
js-tokens@4.0.0: {} js-tokens@4.0.0: {}
@@ -4878,41 +4901,42 @@ snapshots:
mute-stream@3.0.0: {} mute-stream@3.0.0: {}
nanoid@3.3.12: {} nanoid@6.0.1: {}
napi-postinstall@0.3.4: {} napi-postinstall@0.3.4: {}
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
next-auth@5.0.0-beta.25(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0): next-auth@5.0.0-beta.32(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0):
dependencies: dependencies:
'@auth/core': 0.37.2 '@auth/core': 0.41.3
next: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: 16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0 react: 19.0.0
next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(@types/node@20.16.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies: dependencies:
'@next/env': 16.2.6 '@next/env': 16.2.11
'@swc/helpers': 0.5.15 '@swc/helpers': 0.5.15
baseline-browser-mapping: 2.10.31 baseline-browser-mapping: 2.10.31
caniuse-lite: 1.0.30001793 caniuse-lite: 1.0.30001793
postcss: 8.4.31 postcss: 8.5.26
react: 19.0.0 react: 19.0.0
react-dom: 19.0.0(react@19.0.0) react-dom: 19.0.0(react@19.0.0)
styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.0.0) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.0.0)
optionalDependencies: optionalDependencies:
'@next/swc-darwin-arm64': 16.2.6 '@next/swc-darwin-arm64': 16.2.11
'@next/swc-darwin-x64': 16.2.6 '@next/swc-darwin-x64': 16.2.11
'@next/swc-linux-arm64-gnu': 16.2.6 '@next/swc-linux-arm64-gnu': 16.2.11
'@next/swc-linux-arm64-musl': 16.2.6 '@next/swc-linux-arm64-musl': 16.2.11
'@next/swc-linux-x64-gnu': 16.2.6 '@next/swc-linux-x64-gnu': 16.2.11
'@next/swc-linux-x64-musl': 16.2.6 '@next/swc-linux-x64-musl': 16.2.11
'@next/swc-win32-arm64-msvc': 16.2.6 '@next/swc-win32-arm64-msvc': 16.2.11
'@next/swc-win32-x64-msvc': 16.2.6 '@next/swc-win32-x64-msvc': 16.2.11
'@playwright/test': 1.60.0 '@playwright/test': 1.60.0
sharp: 0.34.5 sharp: 0.35.4(@types/node@20.16.10)
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'
- '@types/node'
- babel-plugin-macros - babel-plugin-macros
node-exports-info@1.6.0: node-exports-info@1.6.0:
@@ -5032,29 +5056,20 @@ snapshots:
possible-typed-array-names@1.1.0: {} possible-typed-array-names@1.1.0: {}
postcss@8.4.31: postcss@8.5.26:
dependencies: dependencies:
nanoid: 3.3.12 nanoid: 6.0.1
picocolors: 1.1.1 picocolors: 1.1.1
source-map-js: 1.2.1 source-map-js: 1.2.1
postcss@8.5.15: preact-render-to-string@6.5.11(preact@10.24.3):
dependencies: dependencies:
nanoid: 3.3.12 preact: 10.24.3
picocolors: 1.1.1
source-map-js: 1.2.1
preact-render-to-string@5.2.3(preact@10.11.3): preact@10.24.3: {}
dependencies:
preact: 10.11.3
pretty-format: 3.8.0
preact@10.11.3: {}
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
pretty-format@3.8.0: {}
prop-types@15.8.1: prop-types@15.8.1:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
@@ -5173,6 +5188,9 @@ snapshots:
semver@7.8.0: {} semver@7.8.0: {}
semver@7.8.5:
optional: true
set-cookie-parser@3.1.0: {} set-cookie-parser@3.1.0: {}
set-function-length@1.2.2: set-function-length@1.2.2:
@@ -5197,36 +5215,38 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
sharp@0.34.5: sharp@0.35.4(@types/node@20.16.10):
dependencies: dependencies:
'@img/colour': 1.1.0 '@img/colour': 1.1.0
detect-libc: 2.1.2 detect-libc: 2.1.2
semver: 7.8.0 semver: 7.8.5
optionalDependencies: optionalDependencies:
'@img/sharp-darwin-arm64': 0.34.5 '@img/sharp-darwin-arm64': 0.35.4
'@img/sharp-darwin-x64': 0.34.5 '@img/sharp-darwin-x64': 0.35.4
'@img/sharp-libvips-darwin-arm64': 1.2.4 '@img/sharp-freebsd-wasm32': 0.35.4
'@img/sharp-libvips-darwin-x64': 1.2.4 '@img/sharp-libvips-darwin-arm64': 1.3.3
'@img/sharp-libvips-linux-arm': 1.2.4 '@img/sharp-libvips-darwin-x64': 1.3.3
'@img/sharp-libvips-linux-arm64': 1.2.4 '@img/sharp-libvips-linux-arm': 1.3.3
'@img/sharp-libvips-linux-ppc64': 1.2.4 '@img/sharp-libvips-linux-arm64': 1.3.3
'@img/sharp-libvips-linux-riscv64': 1.2.4 '@img/sharp-libvips-linux-ppc64': 1.3.3
'@img/sharp-libvips-linux-s390x': 1.2.4 '@img/sharp-libvips-linux-riscv64': 1.3.3
'@img/sharp-libvips-linux-x64': 1.2.4 '@img/sharp-libvips-linux-s390x': 1.3.3
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4 '@img/sharp-libvips-linux-x64': 1.3.3
'@img/sharp-libvips-linuxmusl-x64': 1.2.4 '@img/sharp-libvips-linuxmusl-arm64': 1.3.3
'@img/sharp-linux-arm': 0.34.5 '@img/sharp-libvips-linuxmusl-x64': 1.3.3
'@img/sharp-linux-arm64': 0.34.5 '@img/sharp-linux-arm': 0.35.4
'@img/sharp-linux-ppc64': 0.34.5 '@img/sharp-linux-arm64': 0.35.4
'@img/sharp-linux-riscv64': 0.34.5 '@img/sharp-linux-ppc64': 0.35.4
'@img/sharp-linux-s390x': 0.34.5 '@img/sharp-linux-riscv64': 0.35.4
'@img/sharp-linux-x64': 0.34.5 '@img/sharp-linux-s390x': 0.35.4
'@img/sharp-linuxmusl-arm64': 0.34.5 '@img/sharp-linux-x64': 0.35.4
'@img/sharp-linuxmusl-x64': 0.34.5 '@img/sharp-linuxmusl-arm64': 0.35.4
'@img/sharp-wasm32': 0.34.5 '@img/sharp-linuxmusl-x64': 0.35.4
'@img/sharp-win32-arm64': 0.34.5 '@img/sharp-webcontainers-wasm32': 0.35.4
'@img/sharp-win32-ia32': 0.34.5 '@img/sharp-win32-arm64': 0.35.4
'@img/sharp-win32-x64': 0.34.5 '@img/sharp-win32-ia32': 0.35.4
'@img/sharp-win32-x64': 0.35.4
'@types/node': 20.16.10
optional: true optional: true
shebang-command@2.0.0: shebang-command@2.0.0:
@@ -5548,7 +5568,7 @@ snapshots:
vite@5.4.21(@types/node@20.16.10)(lightningcss@1.32.0): vite@5.4.21(@types/node@20.16.10)(lightningcss@1.32.0):
dependencies: dependencies:
esbuild: 0.21.5 esbuild: 0.21.5
postcss: 8.5.15 postcss: 8.5.26
rollup: 4.60.4 rollup: 4.60.4
optionalDependencies: optionalDependencies:
'@types/node': 20.16.10 '@types/node': 20.16.10
+168
View File
@@ -0,0 +1,168 @@
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import {
resetServiceTokenCache,
serviceAuthHeader,
serviceToken,
} from "./service-token";
const ISSUER = "https://auth.breakpilot.com/realms/breakpilot-dev";
function tokenResponse(value: string, expiresIn = 300) {
return {
ok: true,
status: 200,
json: async () => ({ access_token: value, expires_in: expiresIn }),
} as Response;
}
function configure() {
process.env.KEYCLOAK_ISSUER = ISSUER;
process.env.PORTAL_SVC_CLIENT_ID = "portal-svc";
process.env.PORTAL_SVC_CLIENT_SECRET = "shh";
}
beforeEach(() => {
resetServiceTokenCache();
delete process.env.PORTAL_SVC_CLIENT_ID;
delete process.env.PORTAL_SVC_CLIENT_SECRET;
delete process.env.KEYCLOAK_ISSUER;
});
afterEach(() => {
vi.restoreAllMocks();
vi.useRealTimers();
});
describe("serviceToken", () => {
test("returns null and makes no request when unconfigured", async () => {
const fetchSpy = vi.spyOn(globalThis, "fetch");
expect(await serviceToken()).toBeNull();
expect(await serviceAuthHeader()).toEqual({});
expect(fetchSpy).not.toHaveBeenCalled();
});
test("requests a client_credentials token against the realm", async () => {
configure();
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockResolvedValue(tokenResponse("tok-1"));
expect(await serviceToken()).toBe("tok-1");
const [url, init] = fetchSpy.mock.calls[0] as [string, RequestInit];
expect(url).toBe(`${ISSUER}/protocol/openid-connect/token`);
expect(init.method).toBe("POST");
const body = new URLSearchParams(init.body as string);
expect(body.get("grant_type")).toBe("client_credentials");
expect(body.get("client_id")).toBe("portal-svc");
expect(body.get("client_secret")).toBe("shh");
});
test("caches the token across calls", async () => {
configure();
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockResolvedValue(tokenResponse("tok-1"));
await serviceToken();
await serviceToken();
await serviceToken();
expect(fetchSpy).toHaveBeenCalledTimes(1);
});
test("de-dupes concurrent fetches into one request", async () => {
configure();
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockResolvedValue(tokenResponse("tok-1"));
const results = await Promise.all([
serviceToken(),
serviceToken(),
serviceToken(),
]);
expect(results).toEqual(["tok-1", "tok-1", "tok-1"]);
expect(fetchSpy).toHaveBeenCalledTimes(1);
});
test("refreshes shortly before expiry", async () => {
configure();
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-08-25T10:00:00Z"));
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockResolvedValueOnce(tokenResponse("tok-1", 300))
.mockResolvedValueOnce(tokenResponse("tok-2", 300));
expect(await serviceToken()).toBe("tok-1");
// 4 minutes in: still inside the window
vi.setSystemTime(new Date("2026-08-25T10:04:00Z"));
expect(await serviceToken()).toBe("tok-1");
// 4:40 — inside the 30s refresh margin
vi.setSystemTime(new Date("2026-08-25T10:04:40Z"));
expect(await serviceToken()).toBe("tok-2");
expect(fetchSpy).toHaveBeenCalledTimes(2);
});
test("surfaces a rejected token request instead of calling unauthenticated", async () => {
configure();
// no json() on the mock: fetchToken throws on !ok before reading the body
vi.spyOn(globalThis, "fetch").mockResolvedValue({
ok: false,
status: 401,
} as Response);
await expect(serviceToken()).rejects.toThrow("service token request failed: 401");
});
test("surfaces a malformed token response", async () => {
configure();
vi.spyOn(globalThis, "fetch").mockResolvedValue({
ok: true,
status: 200,
json: async () => ({}),
} as Response);
await expect(serviceToken()).rejects.toThrow("no access_token");
});
test("a failed fetch does not poison the cache", async () => {
configure();
vi.spyOn(globalThis, "fetch")
.mockResolvedValueOnce({ ok: false, status: 503 } as Response)
.mockResolvedValueOnce(tokenResponse("tok-ok"));
await expect(serviceToken()).rejects.toThrow();
expect(await serviceToken()).toBe("tok-ok");
});
test("a response without expires_in gets the 300s default lifetime", async () => {
configure();
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-08-30T10:00:00Z"));
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockResolvedValueOnce({
ok: true,
status: 200,
json: async () => ({ access_token: "tok-default" }),
} as Response)
.mockResolvedValueOnce(tokenResponse("tok-next"));
expect(await serviceToken()).toBe("tok-default");
// 4 minutes in: still inside the defaulted 300s window
vi.setSystemTime(new Date("2026-08-30T10:04:00Z"));
expect(await serviceToken()).toBe("tok-default");
// past the default expiry
vi.setSystemTime(new Date("2026-08-30T10:05:01Z"));
expect(await serviceToken()).toBe("tok-next");
expect(fetchSpy).toHaveBeenCalledTimes(2);
});
test("serviceAuthHeader carries the bearer token when configured", async () => {
configure();
vi.spyOn(globalThis, "fetch").mockResolvedValue(tokenResponse("tok-1"));
expect(await serviceAuthHeader()).toEqual({ authorization: "Bearer tok-1" });
});
});
+96
View File
@@ -0,0 +1,96 @@
// Client-credentials service token for portal → tenant-registry calls.
//
// tenant-registry's API is INTERNAL_SERVICE_ONLY: once its AUTH_ENABLED
// flips, every route except /healthz and /readyz needs a Keycloak token
// whose audience contains `tenant-registry`. The portal is a service
// principal here — this is machine-to-machine, unrelated to the visitor's
// SSO session (that one authenticates a human against `dev-portal`).
//
// Inert until configured: with no PORTAL_SVC_CLIENT_ID / _SECRET the
// helper returns null and callers send no Authorization header, which is
// exactly today's behaviour against a tenant-registry that is not yet
// enforcing. Configure both to switch the portal over.
//
// Server-only: the client secret must never reach the browser. Every
// caller (src/lib/tenant-registry.ts) already runs server-side.
const REFRESH_MARGIN_SECONDS = 30;
type CachedToken = { value: string; expiresAt: number };
let cached: CachedToken | null = null;
// de-dupes concurrent fetches: many parallel renders share one request
let inFlight: Promise<CachedToken> | null = null;
function config(): { issuer: string; clientId: string; secret: string } | null {
const clientId = process.env.PORTAL_SVC_CLIENT_ID;
const secret = process.env.PORTAL_SVC_CLIENT_SECRET;
const issuer = process.env.KEYCLOAK_ISSUER;
if (!clientId || !secret || !issuer) return null;
return { issuer, clientId, secret };
}
async function fetchToken(cfg: {
issuer: string;
clientId: string;
secret: string;
}): Promise<CachedToken> {
const res = await fetch(`${cfg.issuer}/protocol/openid-connect/token`, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: cfg.clientId,
client_secret: cfg.secret,
}),
cache: "no-store",
});
if (!res.ok) {
throw new Error(`service token request failed: ${res.status}`);
}
const body = (await res.json()) as {
access_token?: string;
expires_in?: number;
};
if (!body.access_token) {
throw new Error("service token response carried no access_token");
}
return {
value: body.access_token,
expiresAt: Date.now() / 1000 + (body.expires_in ?? 300),
};
}
/**
* A valid service token, or null when the portal is not configured to
* send one. Cached in memory and refreshed shortly before expiry (realm
* tokens live 5 minutes).
*/
export async function serviceToken(): Promise<string | null> {
const cfg = config();
if (!cfg) return null;
const now = Date.now() / 1000;
if (cached && now < cached.expiresAt - REFRESH_MARGIN_SECONDS) {
return cached.value;
}
if (!inFlight) {
inFlight = fetchToken(cfg).finally(() => {
inFlight = null;
});
}
cached = await inFlight;
return cached.value;
}
/** Authorization header for an outbound call, or {} when unconfigured. */
export async function serviceAuthHeader(): Promise<Record<string, string>> {
const token = await serviceToken();
return token ? { authorization: `Bearer ${token}` } : {};
}
/** Test seam: drop the cached token. */
export function resetServiceTokenCache(): void {
cached = null;
inFlight = null;
}
+6 -1
View File
@@ -1,6 +1,8 @@
// Tenant Registry client — covers everything the portal needs to call // Tenant Registry client — covers everything the portal needs to call
// from server components and server actions. // from server components and server actions.
import { serviceAuthHeader } from "./service-token";
export type Tenant = { export type Tenant = {
id: string; id: string;
slug: string; slug: string;
@@ -74,9 +76,12 @@ async function req<T>(
path: string, path: string,
body?: unknown, body?: unknown,
): Promise<{ status: number; data: T | null }> { ): Promise<{ status: number; data: T | null }> {
// tenant-registry is INTERNAL_SERVICE_ONLY — the portal calls it as a
// service principal. Unconfigured ⇒ {} ⇒ unchanged, header-less calls.
const auth = await serviceAuthHeader();
const init: RequestInit = { const init: RequestInit = {
method, method,
headers: { accept: "application/json" }, headers: { accept: "application/json", ...auth },
cache: "no-store", cache: "no-store",
}; };
if (body !== undefined) { if (body !== undefined) {