diff --git a/README.md b/README.md index 8c2caa03..5149a4f7 100644 --- a/README.md +++ b/README.md @@ -685,6 +685,69 @@ For bulk-written tables (game-data JSON, imports) a containerized **`mariadb-tur The CMS caches through `cached()` / `cachedQuery()` (`src/lib/cache.ts`): an in-memory fast path with a Redis (Valkey-compatible) fallback and single-flight protection against cache stampedes. Public API routes (home, leaderboard, online count, radio, photos, …) fill Redis keys per route; verify with `redis-cli DBSIZE`. With Cloudflare in front, static and `/imaging/*` responses are additionally cached edge-side (`cf-cache-status`), cutting origin load further. +#### nginx micro-cache (edge of the origin) + +A short-lived nginx cache sits in front of the origin for an explicit whitelist of +public API reads. It is configured in `/etc/nginx/sites-enabled/cms.conf` and its +backends come from `/etc/nginx/snippets/cms_upstream_servers.conf`. + +Why nginx and not the app: Next.js emits +`private, no-cache, no-store, max-age=0, must-revalidate` for dynamic route +handlers, and its response helper then drops the `Cache-Control` set by +`publicCacheControl()`. Every one of the whitelisted routes was verified to be +free of `auth()`, `cookies()`, `headers()` and request data, so the edge may +cache them on their behalf. + +| Class | Endpoints | TTL | +| --- | --- | --- | +| 1 | `/api/online`, `/api/online/count` | 10s | +| 2 | `/api/photos`, `/api/leaderboard`, `/api/radio/current-dj`, `/api/radio/points/leaderboard` | 60s | +| 3 | `/api/staff`, `/api/teams`, `/api/guilds`, `/api/shop`, `/api/shop/categories`, `/api/values`, `/api/values/categories`, `/api/values/[0-9]+` | 300s | + +`/api/radio/shouts` is intentionally excluded: it is live chat. + +Three details are easy to get wrong and are worth keeping intact: + +- **`proxy_ignore_headers "Cache-Control" "Vary";` is what makes the cache work.** + `proxy_hide_header` only strips the header from the response to the client; the + cache module has already read the upstream's `no-store` by then and stores + nothing. Ignore the upstream directive and let nginx emit a single + `Cache-Control` of its own. +- **`$upstream_status` is empty on a cache HIT** — it is only populated on a MISS. + The header map therefore matches both `|2` and the empty-status form, so HITs + get the same class as the MISS that stored them. A status-gated map alone sends + every HIT down the `default` branch and quietly returns `private`. +- **A session must never be advertised as `public`.** With a session cookie nginx + already refuses to store the response (`proxy_no_cache`), but without the skip + flag in the header map the response would still claim `public, s-maxage=...` and + Cloudflare could share it. The map keys on + `"$cms_cc_class|$cms_skip_cache|$upstream_status"`. + +HTML is deliberately **not** cached: `src/app/(site)/page.tsx` performs `auth()` +with a redirect to `/me` and reads `headers()` for a per-request CSP nonce. + +### Files changed for stability and caching + +| File | Change | +| --- | --- | +| `/etc/nginx/nginx.conf` | `worker_connections 4096`, `multi_accept on`, TLS 1.2/1.3 only, `proxy_cache_path` for the micro-cache | +| `/etc/nginx/sites-enabled/cms.conf` | single correct `Cache-Control` per path, micro-cache on the whitelist, session/Authorization bypass, SSE block with buffering off, `upstream cms_app` + `proxy_next_upstream` | +| `/etc/nginx/snippets/cms_upstream_servers.conf` | backend list, rewritten by `ci-deploy.sh` during a cutover | +| `src/app/api/online/count/stream/route.ts` | `X-Accel-Buffering: no` | +| `src/app/api/radio/stream/route.ts` | `X-Accel-Buffering: no` | +| `src/app/api/admin/import/{audit,furni/route,furni/batch,furni/batch-regen,furni/repair-icons}/route.ts` | `X-Accel-Buffering: no` | +| `src/app/api/admin/studio/nitro-cleanup{,/rebuild}/route.ts` | `X-Accel-Buffering: no` | +| `scripts/ci-deploy.sh` | resource limits, blue/green cutover, `switch_upstream`, rollback split by cutover state | +| `deploy.sh` | reduced to a wrapper around `ci-deploy.sh` | +| `docker-compose.yml` | two replica services from a shared anchor, resource limits, port-aware healthcheck, dead `mariadb-turbo` removed | +| `src/lib/services/cache-warmup.ts` | corrected a comment that described delays the code never had | +| `src/lib/ci-deploy.test.ts`, `src/test/ci-deploy-harness.sh` | blue/green coverage; nginx paths are injectable so the in-place path stays tested | +| `ecosystem.config.cjs` | removed (PM2 supervised no process, and nothing referenced it) | + +> The nginx files live on the host only, not in this repository. Rebuilding the +> host loses the cache configuration — keep a copy under version control if that +> becomes a real risk. + --- ## Cloudflare & Anti-DDoS Protection @@ -902,23 +965,98 @@ expire. --- -## Production Deployment (PM2) +## Production Deployment (blue/green) -```bash -pnpm build -pm2 start pnpm --name "next" -- start -pm2 save +PM2 is **not** used in production. It is neither started nor supervised here; the +CMS runs as a single Docker container per replica, started by +`scripts/ci-deploy.sh`. + +``` +git push main + └─ Gitea Actions "deploy" job + └─ bash scripts/ci-deploy.sh + ├─ build image epicnext-cms: + ├─ pnpm db:migrate + ├─ start candidate on the idle port (live replica keeps serving) + ├─ health gate + release-hash check + Playwright e2e + ├─ switch the nginx upstream, reload (cutover) + └─ stop and retire the previous replica ``` -Restart after updates: +### Why host ports instead of `--scale` -```bash -git pull -pnpm install -pnpm build -pm2 restart next +The containers run with `network_mode: host`, so every replica binds a **host** +port rather than sharing a published docker port. `docker compose up --scale +cms=2` therefore cannot work here: the replicas would collide on 3002. Instead +there are two fixed slots, and each release lands in the idle one: + +| Slot | Host port | Container name | +| --- | --- | --- | +| A | 3002 | `epicnext-cms-app` | +| B | 3003 | `epicnext-cms-green` | + +`docker-compose.yml` defines both services (`cms`, and `cms-green` behind the +`green` profile) from one shared YAML anchor so they cannot drift apart. Note +that the CI deploy path deliberately uses `docker run` rather than compose, so +the resource limits are declared in **both** places — limits that only existed +in compose would never apply to a real release. + +### The nginx upstream is the switch + +nginx does not know about container names; it reads a plain list of backends from +`/etc/nginx/snippets/cms_upstream_servers.conf`, which `ci-deploy.sh` rewrites +during the cutover: + +```nginx +upstream cms_app { + least_conn; + keepalive 32; + include /etc/nginx/snippets/cms_upstream_servers.conf; +} ``` +``` +server 127.0.0.1:3002 max_fails=2 fail_timeout=10s; +``` + +`switch_upstream()` writes the new backend, runs `nginx -t`, and only then +reloads. If the test fails the previous file is restored untouched, so a typo can +never take the site down. + +### Failover between replicas + +`max_fails`/`fail_timeout` mark a dead replica as unavailable, but only +`proxy_next_upstream` actually retries the other one: + +```nginx +proxy_next_upstream error timeout invalid_header http_502 http_503 http_504; +proxy_next_upstream_tries 2; +proxy_next_upstream_timeout 10s; +``` + +`non_idempotent` is deliberately **absent**, so `POST` is never replayed against +the second replica — a retried import or write would otherwise apply twice. A +stream that already emitted events is likewise not resumed elsewhere. + +### Resource limits + +`--memory=4g --memory-swap=5g --cpus=2 --pids-limit=512` per replica. The limits +were previously removed ("Next may run unrestricted"); on a shared host that +means a single leak can starve MariaDB, nginx and Traefik. + +> **Watch this on the first heavy import.** The 4 GiB ceiling is not yet +> exercised by a real bulk import. If the container is OOM-killed during a large +> furniture import, raise `mem_limit` in `docker-compose.yml` *and* `mem_limit` / +> `mem_swap_limit` in `scripts/ci-deploy.sh` together. + +### Manual deploys + +`./deploy.sh` is a thin wrapper around `scripts/ci-deploy.sh`, so a manual +release and a CI release follow exactly the same path. The previous version +killed whatever held port 3002 with `fuser -k` and ran `docker compose down` +before anything new existed — guaranteed downtime on every failed build. The +branch guard inside `ci-deploy.sh` only accepts `main`/`master`. + --- ## Scripts diff --git a/deploy.sh b/deploy.sh index 66714c1c..afff9735 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,29 +1,31 @@ -#!/bin/bash -# Forcefully free port 3002 and redeploy the CMS -PORT=3002 +#!/usr/bin/env bash +# Handmatige release uitvoeren. +# +# Dit script is bewust een dunne wrapper. Het echte werk zit in +# `scripts/ci-deploy.sh`, want dat is wat Gitea Actions ook draait. Eén deploypad +# betekent dat een handmatige release niet anders kan werken dan een release uit +# CI, dus er is geen tweede, slechter onderhouden pad meer. +# +# Waarom dit niet meer zelf doet wat het deed: +# - `fuser -k 3002/tcp` sloopte de live release bij elke mislukte build; +# - `docker compose down` haalde de site omlaag vóórdat er iets nieuws stond; +# - de container draait via `docker run` uit ci-deploy.sh, niet via compose, dus +# compose beheerde hier nooit de release die er echt draaide. +# +# `scripts/ci-deploy.sh` start nu blue/green: de nieuwe release komt op de vrije +# poort terwijl de live release door blijft draaien, en nginx gaat pas om nadat +# de kandidaat gezond is en de e2e-test heeft gewonnen. +set -Eeuo pipefail -echo "--- Preparing for deployment ---" +deploy_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$deploy_dir" -# Check if fuser is installed, if not, warn the user -if ! command -v fuser &> /dev/null; then - echo "Error: 'fuser' command not found. Please install psmisc (e.g., sudo apt install psmisc)." - exit 1 -fi - -echo "Forcefully freeing port $PORT..." -# -k kills processes, -n tcp specifies tcp socket -fuser -k $PORT/tcp || echo "No process found on port $PORT or already free." - -echo "Stopping containers..." -docker compose down - -echo "Starting deployment..." -if docker compose up -d --build; then - ./scripts/alert.sh "Deployment successful for EpicNext-Cms" - echo "--- Deployment successful ---" -else - ./scripts/alert.sh "Deployment FAILED for EpicNext-Cms" - echo "--- Deployment FAILED ---" - exit 1 +if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then + sed -n '2,20p' "$deploy_dir/deploy.sh" | sed 's/^# \{0,1\}//' + exit 0 fi +# De branch-guard in ci-deploy.sh accepteert alleen main/master, en controleert +# daarna of de HEAD-commit nog de nieuwste op de remote is. Deployen vanuit een +# feature-branch kan dus niet per ongeluk; dat was eerder wél mogelijk. +exec bash "$deploy_dir/scripts/ci-deploy.sh" "$@" diff --git a/docker-compose.yml b/docker-compose.yml index c998b03a..5cb11908 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,36 +1,80 @@ +# ───────────────────────────────────────────────────────────────────────────── +# Next.js CMS — blue/green +# +# De app draait met `network_mode: host`, dus een replica neemt een host-poort in +# plaats van een gedeelde docker-poort. Daarom twee expliciete services in plaats +# van `docker compose up --scale cms=2`: die zou op poort 3002 botsen. +# +# `deploy.sh` start een release op de vrije poort, wacht op /api/health, schrijft +# daarna /etc/nginx/snippets/cms_upstream_servers.conf en herlaadt nginx. Pas dan +# wordt de oude replica gestopt. De hele release is dus zero-downtime: faalt de +# nieuwe replica, dan blijft de oude gewoon draaien. +# +# De YAML-anchor houdt beide replicas identiek. Wil je ze bewust uit elkaar +# halen (bv. één release canary-en), verwijder dan `<<: *cms` en vul de +# afwijkende velden opnieuw in. +# ───────────────────────────────────────────────────────────────────────────── +x-cms: &cms + image: epicnext-cms:${CMS_RELEASE:-local} + build: + context: . + dockerfile: Dockerfile + args: + NEXT_DEPLOYMENT_ID: ${CMS_RELEASE:-unknown} + network: host + network_mode: host + # 15s: Next moet een lopend request nog netjes kunnen afronden voordat SIGKILL + # volgt. Met 10s werden streams en imports afgekapt. + stop_grace_period: 15s + restart: unless-stopped + env_file: + - .env + volumes: + - ./public/nitro-assets:/app/public/nitro-assets + - ./public/swf:/app/public/swf + - ./storage:/app/storage + - /var/www/Gamedata:/var/www/Gamedata + + # ── Resource limits ── + # De limieten waren eerder weggehaald ("Next mag onbeperkt presteren"). Op een + # gedeelde host is juist dat gevaarlijk: één geheugenlek vult dan de hele + # machine en MariaDB + nginx + Traefik gaan er allemaal onderuit. 4 GiB met + # 1 GiB swap geeft de V8-heap ruimte om zich te organiseren voor hij hard wordt + # afgesneden, maar houdt de schade begrensd. 2 CPU laat drie keer zoveel + # achtergrondwerk toe als de cores, zodat de 6 cores van deze host niet + # volledig door twee replicas worden opgeëist. + mem_limit: 4g + memswap_limit: 5g + cpus: 2.0 + pids_limit: 512 + + # Leest de poort uit de eigen omgeving, dus dezelfde healthcheck werkt voor + # 3002 én 3003 zonder dat deze tweemaal in de compose hoeft te staan. + healthcheck: + test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||'3002')+'/api/health').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))"] + interval: 15s + timeout: 5s + retries: 3 + start_period: 40s + services: + # Blauwe replica: host-poort 3002. cms: - image: epicnext-cms:${CMS_RELEASE:-local} - build: - context: . - dockerfile: Dockerfile - args: - NEXT_DEPLOYMENT_ID: ${CMS_RELEASE:-unknown} - network: host + <<: *cms container_name: epicnext-cms - stop_grace_period: 10s - network_mode: host - restart: unless-stopped - env_file: - - .env environment: - HOSTNAME=0.0.0.0 - volumes: - - ./public/nitro-assets:/app/public/nitro-assets - - ./public/swf:/app/public/swf - - ./storage:/app/storage - - /var/www/Gamedata:/var/www/Gamedata + - PORT=3002 - # ── Resource limits aangepast voor 24 GB RAM ── - # Verwijderd: mem_limit, memswap_limit en cpus. Next.js mag onbeperkt presteren. - pids_limit: 1024 # Verhoogd van 512 zodat Node.js/Next.js oneindig veel async requests aankan - - healthcheck: - test: ["CMD", "node", "-e", "fetch('http://localhost:3002/api/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s + # Groene replica: host-poort 3003. Meestal uitgeschakeld; alleen tijdens een + # release gestart, totdat nginx hem in de upstream-lijst heeft overgenomen. + cms-green: + <<: *cms + container_name: epicnext-cms-green + profiles: ["green"] + environment: + - HOSTNAME=0.0.0.0 + - PORT=3003 # ── Byparr (Cloudflare bypass for clone sources) ── byparr: @@ -52,59 +96,7 @@ services: retries: 3 start_period: 30s - # ── MariaDB "Turbo" (heavy JSON / bulk-loads) ── - mariadb-turbo: - image: mariadb:11 - container_name: mariadb-turbo - profiles: ["db"] - network_mode: host - restart: unless-stopped - environment: - - MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD:-root} - - MARIADB_DATABASE=${MARIADB_DATABASE:-habbo} - - MARIADB_USER=${MARIADB_USER:-cms} - - MARIADB_PASSWORD=${MARIADB_PASSWORD:-cms} - - MARIADB_AUTO_UPGRADE=1 - command: [ - "--character-set-server=utf8mb4", - "--collation-server=utf8mb4_unicode_ci", - "--max-allowed-packet=512M", - "--net-buffer-length=1M", - "--connect-timeout=30", - "--wait-timeout=3600", - "--interactive-timeout=3600", - "--net-read-timeout=600", - "--net-write-timeout=600", - "--innodb-flush-log-at-trx-commit=2", - "--innodb-buffer-pool-size=2G", # Perfect ingesteld voor een 24 GB server! - "--innodb-buffer-pool-instances=4", - "--innodb-log-file-size=1G", - "--innodb-log-buffer-size=64M", - "--innodb-flush-method=O_DIRECT", - "--innodb-autoextend-increment=512", - "--innodb-max-dirty-pages-pct=90", - "--bulk-insert-buffer-size=512M", - "--innodb-doublewrite=0", - "--innodb-use-native-aio=0", - "--tmp-table-size=256M", - "--max-heap-table-size=256M", - "--read-buffer-size=4M", - "--read-rnd-buffer-size=16M", - "--performance-schema=OFF", - "--skip-name-resolve", - ] - volumes: - - mariadb-turbo-data:/var/lib/mysql - healthcheck: - test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized || mariadb-admin ping --silent"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - - # Geoptimaliseerd: We verhogen de limiet naar 6 GB of halen hem volledig weg, - # zodat de InnoDB buffer pool en zware JSON imports nooit Out Of Memory gaan. - -volumes: - mariadb-turbo-data: - driver: local \ No newline at end of file +# De database draait niet meer in Docker. `mariadb-turbo` is verwijderd: de +# service is nooit gestart, de volume bestond niet, en de echte MariaDB draait +# al als host-proces op 127.0.0.1:3306. De optimalisatie-vlaggen daar stonden +# dus al langer niets meer in beheer. \ No newline at end of file diff --git a/package.json b/package.json index da2640ef..0fb48de8 100644 --- a/package.json +++ b/package.json @@ -1,111 +1,111 @@ { - "name": "atomcms-next", - "private": true, - "type": "module", - "engines": { - "node": ">=26.10.0 <27" - }, - "packageManager": "pnpm@11.25.0+sha512.5cde925b4f075f725eb71fbae18a42ffe784524789f19b61c731cb8721ec28aaee160e01a8d5af4fedb2a42cdbf300efe23db356b0d4a17b4d63e11f8ab7c956", - "scripts": { - "dev": "pnpm assets:editor && next dev", - "build": "pnpm assets:editor && next build", - "start": "next start", - "toolchain:check": "node scripts/check-node-toolchain.mjs", - "lint": "biome check .", - "biome:lint": "biome check .", - "format": "biome format --write .", - "diag:permissions": "tsx scripts/diagnose-permission-page.ts", - "jobs:worker": "node --conditions=react-server --import tsx scripts/jobs-worker.ts", - "test": "vitest run --coverage.enabled=false", - "test:coverage": "vitest run", - "typecheck": "tsc --noEmit", - "db:generate": "drizzle-kit generate", - "db:introspect": "drizzle-kit introspect", - "db:bulk": "tsx scripts/bulk-import-json.ts", - "db:up": "docker compose --profile db up -d mariadb-turbo", - "db:down": "docker compose --profile db stop mariadb-turbo", - "db:schema:generate": "node scripts/generate-drizzle-schema.mjs", - "db:migrate": "tsx scripts/apply-migrations.ts", - "db:migrate:status": "tsx scripts/apply-migrations.ts --status", - "db:studio": "drizzle-kit studio", - "gamedata:compress": "node scripts/compress-gamedata.mjs", - "hk:matrix:check": "tsx scripts/verify-housekeeping-matrix.ts", - "test:housekeeping": "vitest run --coverage.enabled=false src/features/housekeeping src/lib/admin-theme-source-audit.test.ts src/lib/admin/authorization-contract.test.ts", - "assets:editor": "node scripts/copy-editor-assets.mjs", - "deps:audit": "pnpm audit --audit-level=high", - "analyze": "next experimental-analyze", - "i18n:check": "node scripts/audit-cms-translations.mjs --check", - "i18n:audit": "node scripts/audit-cms-translations.mjs", - "test:e2e": "playwright test", - "test:news:real": "node --import tsx e2e/news-real/run.ts", - "test:ui": "playwright test --config playwright.ui.config.ts", - "test:ui:update": "playwright test --config playwright.ui.config.ts --update-snapshots", - "performance:report": "node scripts/performance-report.mjs", - "test:integration": "vitest run --config vitest.integration.config.ts" - }, - "dependencies": { - "@base-ui/react": "1.8.0", - "@dnd-kit/core": "6.3.1", - "@dnd-kit/sortable": "10.0.0", - "@dnd-kit/utilities": "3.2.2", - "@formatjs/icu-messageformat-parser": "3.5.19", - "@hookform/resolvers": "5.9.1", - "@tanstack/react-query": "5.103.1", - "@tanstack/react-virtual": "3.14.13", - "class-variance-authority": "0.7.1", - "clsx": "2.1.1", - "cmdk": "1.1.1", - "croner": "10.0.1", - "drizzle-orm": "0.45.2", - "hash-wasm": "4.12.0", - "ioredis": "6.0.0", - "isomorphic-dompurify": "^4.3.0", - "jpeg-js": "0.4.4", - "jsonc-parser": "3.3.1", - "jszip": "3.10.2", - "lucide-react": "1.47.0", - "lzma-wasm": "1.0.7", - "motion": "13.4.0", - "music-metadata": "11.15.0", - "mysql2": "3.24.4", - "next": "16.3.6", - "next-auth": "5.0.0-beta.32", - "next-intl": "4.14.5", - "otplib": "13.5.0", - "pino": "10.3.1", - "react": "19.3.0", - "react-dom": "19.3.0", - "react-hook-form": "7.88.0", - "resend": "6.28.1", - "server-only": "0.0.1", - "sharp": "^0.35.4", - "sonner": "2.0.8", - "tailwind-merge": "3.7.0", - "tinymce": "8.9.1", - "zod": "4.6.5" - }, - "devDependencies": { - "@axe-core/playwright": "4.13.0", - "@babel/parser": "7.29.9", - "@biomejs/biome": "2.5.14", - "@playwright/test": "1.63.0", - "@tailwindcss/forms": "0.5.11", - "@tailwindcss/postcss": "4.3.3", - "@tailwindcss/typography": "0.5.20", - "@types/node": "26.6.2", - "@types/react": "19.2.18", - "@types/react-dom": "19.2.7", - "@vitest/coverage-v8": "5.0.2", - "drizzle-kit": "0.31.10", - "esbuild": "0.28.2", - "msw": "2.15.0", - "pino-pretty": "13.1.3", - "postcss": "8.5.28", - "tailwindcss": "4.3.3", - "testcontainers": "12.1.0", - "tsx": "4.23.13", - "typescript": "7.0.2", - "vite": "8.3.0", - "vitest": "5.0.2" - } + "name": "atomcms-next", + "private": true, + "type": "module", + "engines": { + "node": ">=26.10.0 <27" + }, + "packageManager": "pnpm@12.6.0+sha512.3ef68f951cb111ac204b4a5a16f0b2ddf0da56a96e0413e81d855d9f0b55ef926714709028e1cd00c405c2c5fb7b9e8ec4dc46777c805d0373c2f2ff00fd20ec", + "scripts": { + "dev": "pnpm assets:editor && next dev", + "build": "pnpm assets:editor && next build", + "start": "next start", + "toolchain:check": "node scripts/check-node-toolchain.mjs", + "lint": "biome check .", + "biome:lint": "biome check .", + "format": "biome format --write .", + "diag:permissions": "tsx scripts/diagnose-permission-page.ts", + "jobs:worker": "node --conditions=react-server --import tsx scripts/jobs-worker.ts", + "test": "vitest run --coverage.enabled=false", + "test:coverage": "vitest run", + "typecheck": "tsc --noEmit", + "db:generate": "drizzle-kit generate", + "db:introspect": "drizzle-kit introspect", + "db:bulk": "tsx scripts/bulk-import-json.ts", + "db:up": "docker compose --profile db up -d mariadb-turbo", + "db:down": "docker compose --profile db stop mariadb-turbo", + "db:schema:generate": "node scripts/generate-drizzle-schema.mjs", + "db:migrate": "tsx scripts/apply-migrations.ts", + "db:migrate:status": "tsx scripts/apply-migrations.ts --status", + "db:studio": "drizzle-kit studio", + "gamedata:compress": "node scripts/compress-gamedata.mjs", + "hk:matrix:check": "tsx scripts/verify-housekeeping-matrix.ts", + "test:housekeeping": "vitest run --coverage.enabled=false src/features/housekeeping src/lib/admin-theme-source-audit.test.ts src/lib/admin/authorization-contract.test.ts", + "assets:editor": "node scripts/copy-editor-assets.mjs", + "deps:audit": "pnpm audit --audit-level=high", + "analyze": "next experimental-analyze", + "i18n:check": "node scripts/audit-cms-translations.mjs --check", + "i18n:audit": "node scripts/audit-cms-translations.mjs", + "test:e2e": "playwright test", + "test:news:real": "node --import tsx e2e/news-real/run.ts", + "test:ui": "playwright test --config playwright.ui.config.ts", + "test:ui:update": "playwright test --config playwright.ui.config.ts --update-snapshots", + "performance:report": "node scripts/performance-report.mjs", + "test:integration": "vitest run --config vitest.integration.config.ts" + }, + "dependencies": { + "@base-ui/react": "1.8.0", + "@dnd-kit/core": "6.3.1", + "@dnd-kit/sortable": "10.0.0", + "@dnd-kit/utilities": "3.2.2", + "@formatjs/icu-messageformat-parser": "3.5.20", + "@hookform/resolvers": "5.9.1", + "@tanstack/react-query": "5.104.0", + "@tanstack/react-virtual": "3.14.13", + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "cmdk": "1.1.1", + "croner": "10.0.1", + "drizzle-orm": "0.45.3", + "hash-wasm": "4.12.0", + "ioredis": "6.0.0", + "isomorphic-dompurify": "^4.4.0", + "jpeg-js": "0.4.4", + "jsonc-parser": "3.3.1", + "jszip": "3.10.2", + "lucide-react": "1.48.0", + "lzma-wasm": "1.0.7", + "motion": "13.4.4", + "music-metadata": "11.16.1", + "mysql2": "3.24.4", + "next": "16.3.6", + "next-auth": "5.0.0-beta.32", + "next-intl": "4.14.7", + "otplib": "13.5.0", + "pino": "10.3.1", + "react": "19.3.0", + "react-dom": "19.3.0", + "react-hook-form": "7.89.0", + "resend": "6.30.0", + "server-only": "0.0.1", + "sharp": "^0.35.5", + "sonner": "2.0.8", + "tailwind-merge": "3.7.0", + "tinymce": "8.9.2", + "zod": "4.6.5" + }, + "devDependencies": { + "@axe-core/playwright": "4.13.0", + "@babel/parser": "7.29.9", + "@biomejs/biome": "2.5.14", + "@playwright/test": "1.63.0", + "@tailwindcss/forms": "0.5.11", + "@tailwindcss/postcss": "4.3.3", + "@tailwindcss/typography": "0.5.20", + "@types/node": "26.6.3", + "@types/react": "19.3.0", + "@types/react-dom": "19.3.0", + "@vitest/coverage-v8": "5.0.2", + "drizzle-kit": "0.31.11", + "esbuild": "0.28.2", + "msw": "2.15.0", + "pino-pretty": "13.1.3", + "postcss": "8.5.28", + "tailwindcss": "4.3.3", + "testcontainers": "12.1.0", + "tsx": "4.23.15", + "typescript": "7.0.2", + "vite": "8.3.1", + "vitest": "5.0.2" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f859898..a64db704 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,3 +1,161 @@ +--- +lockfileVersion: '9.0' + +importers: + + .: + configDependencies: {} + packageManagerDependencies: + pnpm: + specifier: 12.6.0 + version: 12.6.0 + +packages: + + '@pnpm/exe.android-arm64@12.6.0': + resolution: {integrity: sha512-kviIHft9h02q+7N2In7tSL9T/HRUSGwYmU74YPtsWU5ee7vgqPyC0JT6RRX6miW+NxX1CvHgQxg69qq1qTLJYQ==} + cpu: [arm64] + os: [android] + + '@pnpm/exe.android-x64@12.6.0': + resolution: {integrity: sha512-CT8aJKLq2mtZFE71pr4E5Z2xHL8uGnRGr+NclDqsXlVF4SVcQ2QAs14mWi0C8gjT4hbmi+Q0lJRRIkMAWfjjng==} + cpu: [x64] + os: [android] + + '@pnpm/exe.darwin-arm64@12.6.0': + resolution: {integrity: sha512-rafpVkjzugKBMxSvGQd5wK1x5eOTkD/+lcJIFHeQhvd+BJ8kDisOOvwhQDrpGd4vd2Fx+hhW0P2Ptt638OlhFg==} + cpu: [arm64] + os: [darwin] + + '@pnpm/exe.darwin-x64@12.6.0': + resolution: {integrity: sha512-72Jpuv1m24gI8zUNcaylYpBWEhBzz1VPhnDIU2GYM2eRP+KsOqVLwV78i+JrihI39zY2NNXmaN4eAKX1inpaDQ==} + cpu: [x64] + os: [darwin] + + '@pnpm/exe.freebsd-x64@12.6.0': + resolution: {integrity: sha512-LON4QgNy1w/XF4uySZIyC/5hEB0oGdelXsY9tSKqstER+2j2X2oHz67skD11RRd/HWFRtMr64shQZ4I9ZoZ0zg==} + cpu: [x64] + os: [freebsd] + + '@pnpm/exe.linux-arm64-musl@12.6.0': + resolution: {integrity: sha512-BdDpX+DeaMUc5x6WNcE6FkmFy36NwrBbBvwsZU737Zt3u1fTY+iKFPchjEQNCM4rT6q6xvF2oN3ZwExGsJCkxQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-arm64@12.6.0': + resolution: {integrity: sha512-8h2sNoIhHDpHDYqZZCh9PXr6krqW10btb0GHVGuw710muDHlFAHMtUG2ogmaHge6zJG1xgY4Y7mwX5g/LWvrYg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-ppc64@12.6.0': + resolution: {integrity: sha512-ld6xgcEhFCFrsVsJhbmdmR714PnsEspO/Ij8w0/D7OSiz2hYGu3fZd5tKRxOI5m6H6Gl0/RRFAPncTHbsgXVjQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-riscv64@12.6.0': + resolution: {integrity: sha512-HIbImydoC3J8NFt+8MXfhTCf5rO6NjCMyinSAHac0VmV8uCHw+kbQkyAzxV84rzz9ZOzmBOnj0b1N461UIYGsw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-s390x@12.6.0': + resolution: {integrity: sha512-DjSqT7+BZ/lWcDHwNMuzsRVfyxUimh+D54Xw4tSWbdVVQhtWtNMUyI93LVnwCmsoEpar2gC3SFeAgywx37svKQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-x64-musl@12.6.0': + resolution: {integrity: sha512-31lKeGPmRE6xfV6I3VjaEGVFRei14pl/zgoFDK4w+UkbJqOuNl2Ht3O1GuqNIg3Gl14qTEb4kZRAYFHXifDx9A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-x64@12.6.0': + resolution: {integrity: sha512-qFWBneHJAJ73W4whtbaFOL1M/7DBC6ILHXuxc7ZPtEhfPuT1zeZiGrmKHoMAfJA+mcm6xhOFljqVTUS+00Jabw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.win32-arm64@12.6.0': + resolution: {integrity: sha512-OhfefXEEykZlslSUhR8PPRe6MVPV3Oink/dVfIecE5velpc7j80cZYsHlaDrtRDcm3TPwQHkaRW1SJ1efX9oFg==} + cpu: [arm64] + os: [win32] + + '@pnpm/exe.win32-x64@12.6.0': + resolution: {integrity: sha512-L2tuyrD2+Imgxs3VK/ST/2L3xD6vDP0ktJQxM0TaGw7TbAQEMq+RMc8iK6Ew7Id579uzjJe8jSfJID2ZGsOHCA==} + cpu: [x64] + os: [win32] + + pnpm@12.6.0: + resolution: {integrity: sha512-PvaPlRyxEawgS0paFvCy3fDaVqluBBPoHYVdnwtV75JnFHCQKOHNAMQFwsX7e56OxNxGd3yAXQNzwvL/AP0g7A==} + engines: {node: '>=18.*'} + hasBin: true + +snapshots: + + '@pnpm/exe.android-arm64@12.6.0': + optional: true + + '@pnpm/exe.android-x64@12.6.0': + optional: true + + '@pnpm/exe.darwin-arm64@12.6.0': + optional: true + + '@pnpm/exe.darwin-x64@12.6.0': + optional: true + + '@pnpm/exe.freebsd-x64@12.6.0': + optional: true + + '@pnpm/exe.linux-arm64-musl@12.6.0': + optional: true + + '@pnpm/exe.linux-arm64@12.6.0': + optional: true + + '@pnpm/exe.linux-ppc64@12.6.0': + optional: true + + '@pnpm/exe.linux-riscv64@12.6.0': + optional: true + + '@pnpm/exe.linux-s390x@12.6.0': + optional: true + + '@pnpm/exe.linux-x64-musl@12.6.0': + optional: true + + '@pnpm/exe.linux-x64@12.6.0': + optional: true + + '@pnpm/exe.win32-arm64@12.6.0': + optional: true + + '@pnpm/exe.win32-x64@12.6.0': + optional: true + + pnpm@12.6.0: + optionalDependencies: + '@pnpm/exe.android-arm64': 12.6.0 + '@pnpm/exe.android-x64': 12.6.0 + '@pnpm/exe.darwin-arm64': 12.6.0 + '@pnpm/exe.darwin-x64': 12.6.0 + '@pnpm/exe.freebsd-x64': 12.6.0 + '@pnpm/exe.linux-arm64': 12.6.0 + '@pnpm/exe.linux-arm64-musl': 12.6.0 + '@pnpm/exe.linux-ppc64': 12.6.0 + '@pnpm/exe.linux-riscv64': 12.6.0 + '@pnpm/exe.linux-s390x': 12.6.0 + '@pnpm/exe.linux-x64': 12.6.0 + '@pnpm/exe.linux-x64-musl': 12.6.0 + '@pnpm/exe.win32-arm64': 12.6.0 + '@pnpm/exe.win32-x64': 12.6.0 + +--- lockfileVersion: '9.0' settings: @@ -5,9 +163,9 @@ settings: excludeLinksFromLockfile: false overrides: - '@esbuild-kit/core-utils>esbuild': ^0.25.9 - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7 + glob: ^11.0.0 + '@esbuild-kit/core-utils': npm:tsx@^4.23.15 + '@esbuild-kit/esm-loader': npm:tsx@^4.23.15 importers: @@ -15,7 +173,7 @@ importers: dependencies: '@base-ui/react': specifier: 1.8.0 - version: 1.8.0(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + version: 1.8.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@dnd-kit/core': specifier: 6.3.1 version: 6.3.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) @@ -26,14 +184,14 @@ importers: specifier: 3.2.2 version: 3.2.2(react@19.3.0) '@formatjs/icu-messageformat-parser': - specifier: 3.5.19 - version: 3.5.19 + specifier: 3.5.20 + version: 3.5.20 '@hookform/resolvers': specifier: 5.9.1 - version: 5.9.1(react-hook-form@7.88.0(react@19.3.0))(zod@4.6.5) + version: 5.9.1(react-hook-form@7.89.0(@types/react@19.3.0)(react@19.3.0))(zod@4.6.5) '@tanstack/react-query': - specifier: 5.103.1 - version: 5.103.1(react@19.3.0) + specifier: 5.104.0 + version: 5.104.0(react@19.3.0) '@tanstack/react-virtual': specifier: 3.14.13 version: 3.14.13(react-dom@19.3.0(react@19.3.0))(react@19.3.0) @@ -45,13 +203,13 @@ importers: version: 2.1.1 cmdk: specifier: 1.1.1 - version: 1.1.1(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + version: 1.1.1(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) croner: specifier: 10.0.1 version: 10.0.1 drizzle-orm: - specifier: 0.45.2 - version: 0.45.2(mysql2@3.24.4(@types/node@26.6.2)) + specifier: 0.45.3 + version: 0.45.3(mysql2@3.24.4(@types/node@26.6.3)) hash-wasm: specifier: 4.12.0 version: 4.12.0 @@ -59,8 +217,8 @@ importers: specifier: 6.0.0 version: 6.0.0 isomorphic-dompurify: - specifier: ^4.3.0 - version: 4.3.0(@noble/hashes@2.4.0) + specifier: ^4.4.0 + version: 4.4.0(@noble/hashes@2.4.0) jpeg-js: specifier: 0.4.4 version: 0.4.4 @@ -71,29 +229,29 @@ importers: specifier: 3.10.2 version: 3.10.2 lucide-react: - specifier: 1.47.0 - version: 1.47.0(react@19.3.0) + specifier: 1.48.0 + version: 1.48.0(react@19.3.0) lzma-wasm: specifier: 1.0.7 version: 1.0.7 motion: - specifier: 13.4.0 - version: 13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + specifier: 13.4.4 + version: 13.4.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0) music-metadata: - specifier: 11.15.0 - version: 11.15.0 + specifier: 11.16.1 + version: 11.16.1 mysql2: specifier: 3.24.4 - version: 3.24.4(@types/node@26.6.2) + version: 3.24.4(@types/node@26.6.3) next: specifier: 16.3.6 - version: 16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + version: 16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) next-auth: specifier: 5.0.0-beta.32 - version: 5.0.0-beta.32(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0) + version: 5.0.0-beta.32(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0) next-intl: - specifier: 4.14.5 - version: 4.14.5(@swc/helpers@0.5.23)(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0) + specifier: 4.14.7 + version: 4.14.7(@swc/helpers@0.5.23)(@types/react@19.3.0)(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0) otplib: specifier: 13.5.0 version: 13.5.0 @@ -107,26 +265,26 @@ importers: specifier: 19.3.0 version: 19.3.0(react@19.3.0) react-hook-form: - specifier: 7.88.0 - version: 7.88.0(react@19.3.0) + specifier: 7.89.0 + version: 7.89.0(@types/react@19.3.0)(react@19.3.0) resend: - specifier: 6.28.1 - version: 6.28.1 + specifier: 6.30.0 + version: 6.30.0 server-only: specifier: 0.0.1 version: 0.0.1 sharp: - specifier: ^0.35.4 - version: 0.35.4(@types/node@26.6.2) + specifier: ^0.35.5 + version: 0.35.5(@types/node@26.6.3) sonner: specifier: 2.0.8 - version: 2.0.8(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + version: 2.0.8(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) tailwind-merge: specifier: 3.7.0 version: 3.7.0 tinymce: - specifier: 8.9.1 - version: 8.9.1 + specifier: 8.9.2 + version: 8.9.2 zod: specifier: 4.6.5 version: 4.6.5 @@ -153,26 +311,26 @@ importers: specifier: 0.5.20 version: 0.5.20(tailwindcss@4.3.3) '@types/node': - specifier: 26.6.2 - version: 26.6.2 + specifier: 26.6.3 + version: 26.6.3 '@types/react': - specifier: 19.2.18 - version: 19.2.18 + specifier: 19.3.0 + version: 19.3.0 '@types/react-dom': - specifier: 19.2.7 - version: 19.2.7(@types/react@19.2.18) + specifier: 19.3.0 + version: 19.3.0(@types/react@19.3.0) '@vitest/coverage-v8': specifier: 5.0.2 version: 5.0.2(vitest@5.0.2) drizzle-kit: - specifier: 0.31.10 - version: 0.31.10 + specifier: 0.31.11 + version: 0.31.11 esbuild: specifier: 0.28.2 version: 0.28.2 msw: specifier: 2.15.0 - version: 2.15.0(@types/node@26.6.2)(typescript@7.0.2) + version: 2.15.0(@types/node@26.6.3)(typescript@7.0.2) pino-pretty: specifier: 13.1.3 version: 13.1.3 @@ -186,17 +344,17 @@ importers: specifier: 12.1.0 version: 12.1.0 tsx: - specifier: 4.23.13 - version: 4.23.13 + specifier: 4.23.15 + version: 4.23.15 typescript: specifier: 7.0.2 version: 7.0.2 vite: - specifier: 8.3.0 - version: 8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0) + specifier: 8.3.1 + version: 8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) vitest: specifier: 5.0.2 - version: 5.0.2(@types/node@26.6.2)(@vitest/coverage-v8@5.0.2)(jsdom@30.0.1(@noble/hashes@2.4.0))(msw@2.15.0(@types/node@26.6.2)(typescript@7.0.2))(vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0)) + version: 5.0.2(@types/node@26.6.3)(@vitest/coverage-v8@5.0.2)(jsdom@30.1.1(@noble/hashes@2.4.0))(msw@2.15.0(@types/node@26.6.3)(typescript@7.0.2))(vite@8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) packages: @@ -204,13 +362,13 @@ packages: resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} engines: {node: '>=10'} - '@asamuzakjp/css-color@6.0.7': - resolution: {integrity: sha512-vC/bk1Lz7Tn/EfU9/apOTBk80/8dyGyWMowPoV1tJ52muDGsDqt2HPT2klrFUiY60MQmQv9q8yIht15JnBgDGw==} - engines: {node: ^22.13.0 || >=24.0.0} + '@asamuzakjp/css-color@7.1.2': + resolution: {integrity: sha512-99DHAnXDB5z6EEK+9GMpVI7Mw4oxj97dY5bpOzMnjADQWxI8rN6TvTduuFLUhUMlS7/CfVZ06tcZsus6cltnNw==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} - '@asamuzakjp/dom-selector@8.3.2': - resolution: {integrity: sha512-93Z1N+BQNXysodoicpOIyNh2drHfz/CTf9nnT0FEx72GJcIiwgydD7tGAr78j41LsYn3hlRn+LdGPuBLn1Bl8Q==} - engines: {node: ^22.13.0 || >=24.0.0} + '@asamuzakjp/dom-selector@9.2.2': + resolution: {integrity: sha512-lSWTBMjAcmu2xn5yEDU7jh6QDV+C8GEKtdJ4pIQhXh26RkKQ7S3FuQlt+zZkUbTdJ4d3XyV1kPI/G0zWXxqaqw==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} '@auth/core@0.41.3': resolution: {integrity: sha512-sJ3JMHHkXMD3aOjopv7mOBTO1Ocw4b0fAEXJBz6k7YHLpYQI6C40jCUPc5fNvUKxXRXNE1/sRISA15UrwWJBTw==} @@ -260,7 +418,7 @@ packages: engines: {node: '>=14.0.0'} peerDependencies: '@date-fns/tz': ^1.2.0 - '@types/react': 19.2.18 + '@types/react': ^17 || ^18 || ^19 date-fns: ^4.0.0 react: ^17 || ^18 || ^19 react-dom: ^17 || ^18 || ^19 @@ -275,7 +433,7 @@ packages: '@base-ui/utils@0.4.0': resolution: {integrity: sha512-bO9fz25kKtPf+aZVyfQrC0PDmJdmVni31W2hCS5/Owb+inwdIL3XU26pCPRPlt4LSxZrBgLwubXQXQlKaFEZzw==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': ^17 || ^18 || ^19 react: ^17 || ^18 || ^19 react-dom: ^17 || ^18 || ^19 peerDependenciesMeta: @@ -350,40 +508,40 @@ packages: resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true - '@csstools/color-helpers@6.1.1': - resolution: {integrity: sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==} + '@csstools/color-helpers@6.1.2': + resolution: {integrity: sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==} engines: {node: '>=20.19.0'} - '@csstools/css-calc@3.3.0': - resolution: {integrity: sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==} + '@csstools/css-calc@3.4.1': + resolution: {integrity: sha512-EtC7SoN1j6J4E4DCwg5QgbO5TGxgxIA1RXqe+W+qUM+BUcezx9wT+/tiQ/WO2yCX4i5X+Cuf9ciJ22aP4UEwWw==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms': ^4.0.1 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-color-parser@4.2.2': - resolution: {integrity: sha512-3QKjR/vxyjcSXBLgb6lP0S3MGdvwbmqSsvLPbYdVORqPDc8FX1HAJ0Spk38bxaRXgvENTA47tlhhbb5Z2e8hEg==} + '@csstools/css-color-parser@4.2.4': + resolution: {integrity: sha512-DyefytAZ735mX4Dq/WcDAXFtXhaEFvme0ZS9tVEBAc2whxUthXr0R0L2rmEPm59SrMBkGrFzQviBXMs/UtnABQ==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms': ^4.0.1 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + '@csstools/css-parser-algorithms@4.0.1': + resolution: {integrity: sha512-ShL8BqPfbKJrJiKFH0xBbN0i7Nrh9HXYRuF+pzyj93R/BL2YAsUxJeqANErzqM+0JGl7vjHp+3OIgd/DL69YIA==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-syntax-patches-for-csstree@1.1.12': - resolution: {integrity: sha512-3vLQK+dXxhBMR2Wx99PTCifE+vHtW2ndZWyla8yK813ev6oGhyn8Lja8jCyGAWTJ+LEYZK7EVtJxrDj8ztevJw==} + '@csstools/css-syntax-patches-for-csstree@1.1.14': + resolution: {integrity: sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==} peerDependencies: css-tree: ^3.2.1 peerDependenciesMeta: css-tree: optional: true - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + '@csstools/css-tokenizer@4.0.2': + resolution: {integrity: sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==} engines: {node: '>=20.19.0'} '@dnd-kit/accessibility@3.1.1': @@ -423,14 +581,6 @@ packages: '@emnapi/runtime@1.11.3': resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@esbuild-kit/core-utils@3.3.2': - resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} - deprecated: 'Merged into tsx: https://tsx.hirok.io' - - '@esbuild-kit/esm-loader@2.6.5': - resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} - deprecated: 'Merged into tsx: https://tsx.hirok.io' - '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} @@ -743,8 +893,8 @@ packages: cpu: [x64] os: [win32] - '@exodus/bytes@1.15.1': - resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + '@exodus/bytes@1.16.0': + resolution: {integrity: sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: '@noble/hashes': ^1.8.0 || ^2.0.0 @@ -773,8 +923,8 @@ packages: '@formatjs/icu-messageformat-parser@3.5.18': resolution: {integrity: sha512-wX1efcL8d7K5QapOTRsP/OLTA/kpwe4LwqWyNxDNg5iRs8i9jJbCyxB5P8jc4KOW5oiLzz2DJr+BRY5xMV9+bA==} - '@formatjs/icu-messageformat-parser@3.5.19': - resolution: {integrity: sha512-a5PAqgd3QPUge635SxrjPLIlTErcGwm3AMyTdmZXl0IqWXTdCx9AnuioEmvEZAV2HpeFdynLPXMvHv7dXGEWWw==} + '@formatjs/icu-messageformat-parser@3.5.20': + resolution: {integrity: sha512-DUzCb2iskGDKvLU7P+nz/rjpmN59luoTRbWHFFNYNnZTxWCKvwPI94rNll99TGZaI6XoTbDF0QGegk21GFrQZQ==} '@formatjs/icu-skeleton-parser@2.1.11': resolution: {integrity: sha512-j8cUmOJzVgkHuS0QiQ6ga76UIoLOFSAMWhs7aZJztH3aAdCOAE6vpC8KVvFB4cU10ON0y2/5oOVmPJ43s2lTwA==} @@ -785,8 +935,8 @@ packages: '@formatjs/intl-localematcher@0.8.14': resolution: {integrity: sha512-8O7V38QmbB11+ryJ3KM/znrzXtiqgpXzqNoqDsndHZZ5/zDKTTL+cf5F0mzXkQEwhx8IlWnqYvEovf2S5EwLTw==} - '@grpc/grpc-js@1.14.4': - resolution: {integrity: sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==} + '@grpc/grpc-js@1.14.5': + resolution: {integrity: sha512-7VZM+SVdEcUUqSQeNI3zM8Qs/BhQKZndPo2h5VkYkAM8Iz0wJIa8mKV5ekQGqG8UUsnkQ0NMxIxwkIHYvj0qOw==} engines: {node: '>=12.10.0'} '@grpc/proto-loader@0.7.15': @@ -881,160 +1031,160 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.35.4': - resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==} + '@img/sharp-darwin-arm64@0.35.5': + resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.35.4': - resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==} + '@img/sharp-darwin-x64@0.35.5': + resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-freebsd-wasm32@0.35.4': - resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==} + '@img/sharp-freebsd-wasm32@0.35.5': + resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} engines: {node: '>=20.9.0'} os: [freebsd] - '@img/sharp-libvips-darwin-arm64@1.3.3': - resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==} + '@img/sharp-libvips-darwin-arm64@1.3.4': + resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.3.3': - resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==} + '@img/sharp-libvips-darwin-x64@1.3.4': + resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.3.3': - resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==} + '@img/sharp-libvips-linux-arm64@1.3.4': + resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.3.3': - resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==} + '@img/sharp-libvips-linux-arm@1.3.4': + resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.3.3': - resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==} + '@img/sharp-libvips-linux-ppc64@1.3.4': + resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.3.3': - resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==} + '@img/sharp-libvips-linux-riscv64@1.3.4': + resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.3.3': - resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==} + '@img/sharp-libvips-linux-s390x@1.3.4': + resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.3.3': - resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==} + '@img/sharp-libvips-linux-x64@1.3.4': + resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.3.3': - resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.3.3': - resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==} + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.35.4': - resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==} + '@img/sharp-linux-arm64@0.35.5': + resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.35.4': - resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==} + '@img/sharp-linux-arm@0.35.5': + resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.35.4': - resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==} + '@img/sharp-linux-ppc64@0.35.5': + resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.35.4': - resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==} + '@img/sharp-linux-riscv64@0.35.5': + resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.35.4': - resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==} + '@img/sharp-linux-s390x@0.35.5': + resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.35.4': - resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==} + '@img/sharp-linux-x64@0.35.5': + resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.35.4': - resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==} + '@img/sharp-linuxmusl-arm64@0.35.5': + resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.35.4': - resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==} + '@img/sharp-linuxmusl-x64@0.35.5': + resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.35.4': - resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==} + '@img/sharp-wasm32@0.35.5': + resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} engines: {node: '>=20.9.0'} - '@img/sharp-webcontainers-wasm32@0.35.4': - resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==} + '@img/sharp-webcontainers-wasm32@0.35.5': + resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.35.4': - resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==} + '@img/sharp-win32-arm64@0.35.5': + resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.35.4': - resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==} + '@img/sharp-win32-ia32@0.35.5': + resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.35.4': - resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==} + '@img/sharp-win32-x64@0.35.5': + resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -1077,9 +1227,9 @@ packages: '@ioredis/commands@2.0.0': resolution: {integrity: sha512-vrx0AE/T0h7cRZwfo1M39Cr+ZhZrkf0V8mQN75wucKCxCLD9l/VX6no3gFvrLqD1IlG/1LtzWovqEw3t0Vr9zg==} - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1196,8 +1346,8 @@ packages: '@otplib/uri@13.5.0': resolution: {integrity: sha512-LsL1hqTEgJHY40U2eb/Qp6OR1tKkNGwHQTrqqjIuJj0cawGWkLEmeUFK1MHzWBQ4bgy5IdeB5Et7gIDSAH/CRw==} - '@oxc-project/types@0.148.0': - resolution: {integrity: sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==} + '@oxc-project/types@0.151.0': + resolution: {integrity: sha512-J1yXrIlNDZVzE3ada310xeAw7nH8yCAyLPuUIsjKatFPmfn5bS1oW+cM+QsGOtVWd5nhSpbwZWx/rue+r5Z+PA==} '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} @@ -1287,10 +1437,6 @@ packages: '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - '@playwright/test@1.63.0': resolution: {integrity: sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==} engines: {node: '>=20'} @@ -1329,7 +1475,7 @@ packages: '@radix-ui/react-compose-refs@1.1.5': resolution: {integrity: sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1338,7 +1484,7 @@ packages: '@radix-ui/react-context@1.2.2': resolution: {integrity: sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1347,8 +1493,8 @@ packages: '@radix-ui/react-dialog@1.1.23': resolution: {integrity: sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==} peerDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -1360,8 +1506,8 @@ packages: '@radix-ui/react-dismissable-layer@1.1.19': resolution: {integrity: sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==} peerDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -1373,7 +1519,7 @@ packages: '@radix-ui/react-focus-guards@1.1.6': resolution: {integrity: sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1382,8 +1528,8 @@ packages: '@radix-ui/react-focus-scope@1.1.16': resolution: {integrity: sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==} peerDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -1395,7 +1541,7 @@ packages: '@radix-ui/react-id@1.1.4': resolution: {integrity: sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1404,8 +1550,8 @@ packages: '@radix-ui/react-portal@1.1.17': resolution: {integrity: sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==} peerDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -1417,8 +1563,8 @@ packages: '@radix-ui/react-presence@1.1.10': resolution: {integrity: sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==} peerDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -1430,8 +1576,8 @@ packages: '@radix-ui/react-primitive@2.1.10': resolution: {integrity: sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==} peerDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -1443,7 +1589,7 @@ packages: '@radix-ui/react-slot@1.3.3': resolution: {integrity: sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1452,7 +1598,7 @@ packages: '@radix-ui/react-use-callback-ref@1.1.4': resolution: {integrity: sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1461,7 +1607,7 @@ packages: '@radix-ui/react-use-controllable-state@1.2.6': resolution: {integrity: sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1470,7 +1616,7 @@ packages: '@radix-ui/react-use-effect-event@0.0.5': resolution: {integrity: sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -1479,104 +1625,104 @@ packages: '@radix-ui/react-use-layout-effect@1.1.4': resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - '@rolldown/binding-android-arm-eabi@1.2.7': - resolution: {integrity: sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==} + '@rolldown/binding-android-arm-eabi@1.2.11': + resolution: {integrity: sha512-A5kXfGKvKWWZE0TtPrfsvT+q4Y5d1QG8gGUzpYjGydM+fARM9MuX90PrXYXe0XbsDVgyxxNzHo6giCj90bsFNw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@rolldown/binding-android-arm64@1.2.7': - resolution: {integrity: sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==} + '@rolldown/binding-android-arm64@1.2.11': + resolution: {integrity: sha512-z6cTycz+iJ4PVkuL4HHW4DfTfoeU/2nqYYuSOrTmH7yHK5Y0LCOnA03V4ZNxavyVaU1oOqUgIg2klN/s+USGOA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.2.7': - resolution: {integrity: sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==} + '@rolldown/binding-darwin-arm64@1.2.11': + resolution: {integrity: sha512-jShvqNtP6vDC6/A5JOAzbVV+DkgHqhl/ScVCJEbt+TUY6QYz7YnXcrg3sLtFBniro0f/Ld50ZwCWA6f7KYD1nQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.2.7': - resolution: {integrity: sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==} + '@rolldown/binding-darwin-x64@1.2.11': + resolution: {integrity: sha512-f2i2xiNWq1Z1l2++q2fuhZRdLAT3aqxD6vRNm1RAxpUoBcdqNB3C0s1Bt+K+PbEx2F5F4gQp6hqKkphCY/xF9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.2.7': - resolution: {integrity: sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==} + '@rolldown/binding-freebsd-x64@1.2.11': + resolution: {integrity: sha512-4Ir5FSOKIAMr4r0kExpt1s3bMgzJU3rA45AYOHtQpls0oNeqcYBKrWMlckrYH4KCfGLfkfn1tN1dmZPMVsdXow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.2.7': - resolution: {integrity: sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.11': + resolution: {integrity: sha512-/gnRDM+39BROzAN/k1OZjDPnDMcZxB/0EUxKjONO5yVkNEvlsoMDrxGNKgZi/ttFriS2gwlDNzB65pvNbFOXIQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.2.7': - resolution: {integrity: sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==} + '@rolldown/binding-linux-arm64-gnu@1.2.11': + resolution: {integrity: sha512-PFaK8HwvAHbaKbBcDNQihjMKYvFnA5hiENx/l5tphTDz1E0WFp32l0A7aq7lyUwGsRw/xSrNIy/gIK4thrSCrw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.2.7': - resolution: {integrity: sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==} + '@rolldown/binding-linux-arm64-musl@1.2.11': + resolution: {integrity: sha512-AskzJUIKRLPxkruR1wLKewGbOw+EYfU/9lOrBFj4AFrEA8hPpKFnODWNu2WLaNs0QNkEb9QIJufmVZZIL/bJlg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.2.7': - resolution: {integrity: sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==} + '@rolldown/binding-linux-ppc64-gnu@1.2.11': + resolution: {integrity: sha512-qlUGAheh2yh8afH7QBgx0PrRHN85hKnNd78x8MeMhXivuevgd8vgf6/CstOzmNKY/lLTHvNTrPy98cLnAugzJw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.2.7': - resolution: {integrity: sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==} + '@rolldown/binding-linux-s390x-gnu@1.2.11': + resolution: {integrity: sha512-secpEad+0vCbSfn8upFySkDskv+bGPk3THSDS9Y89yc4rb4kzqHp8Dmyd9BkQW4SnhNXBZCl/6CrO//hZahNJQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.2.7': - resolution: {integrity: sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==} + '@rolldown/binding-linux-x64-gnu@1.2.11': + resolution: {integrity: sha512-mOVBT3dPpkWm8XBWPmU4bf+U6dYDLeMo/9ojUmis4N0L5uu10qra5vOyngZ7/PSdoE4G9KvRt4bloRxNjLas7A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.2.7': - resolution: {integrity: sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==} + '@rolldown/binding-linux-x64-musl@1.2.11': + resolution: {integrity: sha512-Is78i9A8Ui4SqcxUwFJ9uMmjDn58IbVTjFWYdQestFEgeuEmHMLGNriXnVJKkwG2YiZjw8cP0zCTyDMdDGtOOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.2.7': - resolution: {integrity: sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==} + '@rolldown/binding-openharmony-arm64@1.2.11': + resolution: {integrity: sha512-dUCXneZ87INUMyQ0D+C0HrEBNUPNXHaPmU5GTjyKTJEiussw9Kaj5Ln8UztPe4epV/ffvgNBEadksdYhmW6xJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-win32-arm64-msvc@1.2.7': - resolution: {integrity: sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==} + '@rolldown/binding-win32-arm64-msvc@1.2.11': + resolution: {integrity: sha512-jByxb6qfd+bH1xUd0qnfFnb17i9sWBPY2tOavJ0l3tdr3OTu+Kvtm8cd/JV5nFt657b1VqGltxg9olOEfofXWw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.2.7': - resolution: {integrity: sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==} + '@rolldown/binding-win32-x64-msvc@1.2.11': + resolution: {integrity: sha512-/PzKqzAJ03i19oy2ItPvyvaVjOjBCNnfaJs8yvUdGBKmiESgnrJSQ2awd81QzFbbnAmu7YO9ZnJrDCb9VSJPRA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1794,11 +1940,11 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || >=4.0.0 || insiders' - '@tanstack/query-core@5.103.1': - resolution: {integrity: sha512-rms8HqTGp6zA00dM+cUQ2eBcgzNJefuu5CAMB37i/6MiGT1zulPOytCFu2a0qjLqVR2n1jENPj9woqFQNuCzWA==} + '@tanstack/query-core@5.104.0': + resolution: {integrity: sha512-JrC2r/JQlXt7khBSdUpsgxNvybzOg+aITa+ARRMlP2AFo93Y8vIqz077rp+e61mJetSZ0T6AJbwW1JHer1vrPQ==} - '@tanstack/react-query@5.103.1': - resolution: {integrity: sha512-rmAPPApNEK17VXRJhtE1rja53n23VV5w30C0saCgJhhX+EpdUnVqMGV/s5nnzV43X75KTHKzuoiuxSzGTBIkag==} + '@tanstack/react-query@5.104.0': + resolution: {integrity: sha512-e1TZmDCQnWIfiDVryIHeA6Idj+Lfx1hORLOhXS/l5wcgvtVD4yYqbTDl378sGQKIi2cSgb0TEMC9cKK8GGoJEw==} peerDependencies: react: ^18 || ^19 @@ -1836,16 +1982,16 @@ packages: '@types/node@18.19.130': resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} - '@types/node@26.6.2': - resolution: {integrity: sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==} + '@types/node@26.6.3': + resolution: {integrity: sha512-dsqMQQoeTLqu9wynDD00q573mNzso3IdQOAfHRJqLCcmCFPoGo9A1bDpUcv/9tnKpErQWv9uKeGfl37EIS02Yg==} - '@types/react-dom@19.2.7': - resolution: {integrity: sha512-I8bPpDLcHBv1qiIiXDCy71Rt8eQDKJP0sMSWJphDdAcdqiJ1sGpZamavoEIRZmYzjia9LuEb2HlYdDpmoENpvQ==} + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': ^19.3.0 - '@types/react@19.2.18': - resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} '@types/set-cookie-parser@2.4.10': resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==} @@ -1994,12 +2140,12 @@ packages: '@vitest/browser': optional: true - '@vitest/istanbul-lib-coverage@1.0.1': - resolution: {integrity: sha512-k3DJZ8LhMBK9NS4SclF1ASD3OgXEWDorbIcPTRDK0/Zae6fRvu+fJRxtFdLfHsa9Y24beCdPnoNZ4LviTNstfA==} + '@vitest/istanbul-lib-coverage@1.0.2': + resolution: {integrity: sha512-9J/JMwOf9AoJhAywhrn7ScKTL38hsWQP/qPG60OtaAFcQ5OXPwKsxZFlbnuCKmZ61m8/lGgHYnFpdyQZUvG/iA==} engines: {node: '>=22'} - '@vitest/istanbul-lib-report@1.0.1': - resolution: {integrity: sha512-1EOLRfsTMnyAr3+kEAsP4o9dhaDlGPpD7H5iLBBeq//YpNB1VIahkPhB+eRp9N2Dkfw8oySROjE3yf9XDeaIkQ==} + '@vitest/istanbul-lib-report@1.0.2': + resolution: {integrity: sha512-gUsfXZJbzPamoIY5TvHFiMMoXESBrUMo+xqaj+rYrWI69+EnvRlYBlP96ZnHPY4vX8kyUpgAnFUCg5wZG/HkDQ==} engines: {node: '>=22'} '@vitest/mocker@5.0.2': @@ -2024,18 +2170,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.3.0: - resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} - engines: {node: '>=12'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - archiver-utils@5.0.2: resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} engines: {node: '>= 14'} @@ -2055,8 +2193,8 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-v8-to-istanbul@1.0.6: - resolution: {integrity: sha512-fvpl29helSO2w/z7utIbrkNXILdrLwDwAMH2I/zPKlGf5244+gf+B4cyS1sANcrPY2h+hWCGSgC8N61s/+AF9A==} + ast-v8-to-istanbul@1.0.7: + resolution: {integrity: sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==} async-lock@1.4.1: resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} @@ -2076,8 +2214,8 @@ packages: resolution: {integrity: sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==} engines: {node: '>=4'} - b4a@1.8.1: - resolution: {integrity: sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==} + b4a@1.9.0: + resolution: {integrity: sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ==} peerDependencies: react-native-b4a: '*' peerDependenciesMeta: @@ -2087,6 +2225,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + bare-events@2.9.2: resolution: {integrity: sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==} peerDependencies: @@ -2095,8 +2237,8 @@ packages: bare-abort-controller: optional: true - bare-fs@4.8.1: - resolution: {integrity: sha512-N1nnXdHZAOSstz0XiHikGS4HGMH4CnSwhqWdGQQMqqdvp4Jybm9sE3R1WVnpWVd4SFkc8ryPDBLViNLwiEqECg==} + bare-fs@4.8.2: + resolution: {integrity: sha512-+ZI68KHMUvosXfKbg/UOHK0tbCdRnegbvPEdEcZ3Nd6TetieQsJPRXBRXPdLyy8+3VSEbPXtsumTpEtt78xv9w==} engines: {bare: '>=1.28.0'} peerDependencies: bare-buffer: '*' @@ -2127,8 +2269,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.11.21: - resolution: {integrity: sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==} + baseline-browser-mapping@2.11.26: + resolution: {integrity: sha512-GLQdD3y6UF8iVuMJl5fHgE4jdn/ua7n+toKfLgNlg3BqQtOZjpy68T8Tup8/wGWZCDlm7KMg7tPb4MPn7oN0TQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -2141,16 +2283,17 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - brace-expansion@2.1.4: - resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} + brace-expansion@2.1.7: + resolution: {integrity: sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==} + + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -2165,8 +2308,8 @@ packages: resolution: {integrity: sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==} engines: {node: '>=0.10.0'} - caniuse-lite@1.0.30001810: - resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} + caniuse-lite@1.0.30001812: + resolution: {integrity: sha512-qN+QNNBr93TCmFrmte0bBCjSDMuRvt78VlHT99qIGPszm4QsqCX8lnyWUFkHi8B7ZBAPq8SH+UqyXNy/odMdng==} chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} @@ -2291,8 +2434,8 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - docker-compose@1.4.2: - resolution: {integrity: sha512-rPHigTKGaEHpkUmfd69QgaOp+Os5vGJwG/Ry8lcr8W/382AmI+z/D7qoa9BybKIkqNppaIbs8RYeHSevdQjWww==} + docker-compose@1.5.0: + resolution: {integrity: sha512-O+eD6c63+BJORUWddXA7uAlI6H1KLDPd/aS14k73nXYpFliM48C3xrrKB3sXsR1Fp/rHUZQe7+fJ+QA7+jepyw==} engines: {node: '>= 6.0.0'} docker-modem@5.0.7: @@ -2303,15 +2446,15 @@ packages: resolution: {integrity: sha512-avsq/xk4YPIrn0CgleX5bjT9Y8IT1p9PxrNQ++RBQ2WEyFfHCTDsT9kmyxz+H/axnjAwg8wJWEIuPGOUuNupiA==} engines: {node: '>= 14.17'} - dompurify@3.4.15: - resolution: {integrity: sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==} + dompurify@3.4.16: + resolution: {integrity: sha512-sqo+pNp3qRhCIpbgRi1y8Tgk27Bo2Ry7w0dC1NBeNTdZChWjz9Xb/KOoZbRP/R6pQZ80Qw8YhXw13hWWBbMRnQ==} - drizzle-kit@0.31.10: - resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} + drizzle-kit@0.31.11: + resolution: {integrity: sha512-YCYqxTLIB2OCqf6w9/Vef13baBVbwQIPcbT4Y56AfO6B9ajZhDhD8Jkveg/hJvT/iuMloKD/IYYkyMMNhr7Kqg==} hasBin: true - drizzle-orm@0.45.2: - resolution: {integrity: sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==} + drizzle-orm@0.45.3: + resolution: {integrity: sha512-CAloER21cDdcgZ1OmjrZX82EeRNsdP+y0onX/eyoYDaYzki/adrAa91lzM5jWh7zZPK4qUbw/6LGv9J+A+uizA==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=4' @@ -2319,6 +2462,7 @@ packages: '@libsql/client': '>=0.10.0' '@libsql/client-wasm': '>=0.10.0' '@neondatabase/serverless': '>=0.10.0' + '@netlify/db': '>=0.4.0' '@op-engineering/op-sqlite': '>=2' '@opentelemetry/api': ^1.4.1 '@planetscale/database': '>=1.13' @@ -2355,6 +2499,8 @@ packages: optional: true '@neondatabase/serverless': optional: true + '@netlify/db': + optional: true '@op-engineering/op-sqlite': optional: true '@opentelemetry/api': @@ -2402,24 +2548,18 @@ packages: sqlite3: optional: true - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.24.5: - resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} + enhanced-resolve@5.25.1: + resolution: {integrity: sha512-nGXts5znJzmWPu+mIE9izCOzdg63oJca2mDzGWWTth7sr4aCToKcoyFVBQwN75Ij5Pf6p510EwkTqViTRzDV+w==} engines: {node: '>=10.13.0'} - entities@8.0.0: - resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + entities@8.1.0: + resolution: {integrity: sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==} engines: {node: '>=20.19.0'} es-module-lexer@2.3.2: @@ -2495,8 +2635,8 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - framer-motion@13.4.0: - resolution: {integrity: sha512-HCpqKM9BTu6UYKtj0u6J1QNxojnnirNcghcSDZ+SkpiL3myxvtsgXPS3ZGEELC2eSma7YiA937rAEXtRyydSXQ==} + framer-motion@13.4.4: + resolution: {integrity: sha512-lbsZO95NGbulo6apz70zEt6Vxf/anoRwQI2ECEc/EQYWO5CGbITtl7plDW8P/VXgXw6e8wrbhH4a9i+ygke0Mg==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 @@ -2529,11 +2669,9 @@ packages: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} - get-tsconfig@4.14.3: - resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} - - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} + engines: {node: 20 || >=22} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true @@ -2553,16 +2691,16 @@ packages: help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-encoding-sniffer@7.0.0: + resolution: {integrity: sha512-UikN5yr7xsCDAq87Or5or0PAlD3HJJOKVzM05az588WnpDJ4Ux7a2A53Qi6gofGg2/EtvF/H4hCi/TXfCW4Y6w==} + engines: {node: ^22.13.0 || >=24.0.0} iconv-lite@0.7.3: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} - icu-minify@4.14.5: - resolution: {integrity: sha512-5RQ5fP5inR+VZRTR4KwYBzy217ua4E9lxBT+zFHZcJv0dTOtRs9xXECSIWMQHAfmd0Hq2RXSSP2Gmyw/oQQY6A==} + icu-minify@4.14.7: + resolution: {integrity: sha512-cbBAiLGee7kzysqaoQLLaIXAYaKEhNRYo05ye9rLj8+MLq/VurqLBHv6vqhTVeyQ7jcvuTujkxmiR1Au4ku8nw==} ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2611,12 +2749,13 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isomorphic-dompurify@4.3.0: - resolution: {integrity: sha512-prq6x6sxb/da0HP4S81hiK2Hc444CIvNeZ+gj7A9oDE0r6tqUmQ90ylb9BwhP44ZSCxwUAcTPNoQY0mmjpRHcA==} + isomorphic-dompurify@4.4.0: + resolution: {integrity: sha512-8F6m5CqcxtY3TLBOKibiPMmSIDa6bMAiiLKZ0ksQad1liA8ZtOnBhjoLFGkBB3noVwj5NeCR9p8vD3uXuudF+Q==} engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} @@ -2635,8 +2774,8 @@ packages: js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - jsdom@30.0.1: - resolution: {integrity: sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==} + jsdom@30.1.1: + resolution: {integrity: sha512-FahmoPK5vbPc+jxV1iErMHmAZypCZ942NHF4+qqaWAuvaKKTBZxawnmAtrbGWLU7MtlxfqIP0qw6aSI+aWGtLg==} engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} peerDependencies: canvas: ^3.2.3 @@ -2814,19 +2953,16 @@ packages: long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@11.5.2: - resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} engines: {node: 20 || >=22} lru.min@1.1.5: resolution: {integrity: sha512-5J9ysMYUpYIg9RF2vJpy9SinEmSviFSe0GyPpCQ4L5QSkLAgeLXlTAOu2ZwWUU5m+0SBl6gUU1R1ZQB3aKypfA==} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - lucide-react@1.47.0: - resolution: {integrity: sha512-o8C23aXpNQypRY73W7fW02EyvWJinEMXgKeGjFoKym0zj3Q73hD97A1IQps1g8C14HTGsOpZL0Am+xjfgFZAbg==} + lucide-react@1.48.0: + resolution: {integrity: sha512-R0CIKY/fXiC6y9xRBADgsK+VW2p/pcTJOMhLZf1T+uG+vJUvyUR02nGOgmIIC7MPkiNK4Ox8QDnbqF8rJYWPZQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -2837,8 +2973,8 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magic-string@1.4.1: - resolution: {integrity: sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==} + magic-string@1.4.2: + resolution: {integrity: sha512-vG+rjFRj1PqdIBozIxAGMjPlOhaVe+GXpbttY/iSK7rGcJRMlwNJO7dcUwmUqkymsFLJiNGI06t4D7Fr7yRC9g==} magicast@0.5.5: resolution: {integrity: sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==} @@ -2854,14 +2990,14 @@ packages: resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} hasBin: true + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + minimatch@5.1.9: resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2877,14 +3013,14 @@ packages: engines: {node: '>=10'} hasBin: true - motion-dom@13.3.0: - resolution: {integrity: sha512-AmAnB6pHdZ1vHGzWzuzteG6Q3j1lHKeX/lbST6jGlgm0cjvLUgaCk1xhOuPMOy5SgovN6wnnUdwFrkcsus7Ftg==} + motion-dom@13.4.4: + resolution: {integrity: sha512-z2qN3RUABSci4G7cr5aHTFhqPNCWJsEMMfRlzxqtANQsSCIbVJmHvMV288m5x7doEQBTYbRTWbKdztmquCn4Sw==} motion-utils@13.3.0: resolution: {integrity: sha512-sgSschQp7EseHInIlR7hBbMuvet3RA0bs28KPZAXJcGKGdxHGvh1ogpYDilY3bOMtl73EqPNmp75sAKHYPU5sg==} - motion@13.4.0: - resolution: {integrity: sha512-aiNSA29N+vgV5p5cJSB5cFzx8KTuuxB99z8zGtxsaqlwKtBK6sq8YgPRpkVQLkbJMOcLDU0q/ShdT95qpBy/0g==} + motion@13.4.4: + resolution: {integrity: sha512-lyX5kpAum2MmigecKWrFdIj3Sjn7pHek2EUrXY0WGZbOjJ1f5NfX0g4KQAb2Bp2EqL0a6dUzse11s1n7OYr5jg==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 @@ -2907,8 +3043,8 @@ packages: typescript: optional: true - music-metadata@11.15.0: - resolution: {integrity: sha512-TN+kO1/oOc8UzDW5N3vSDncBcv9WyNnQQe/NFMcFWq6G1+zVeYUkGvkYpQ/S8wb8vKtUD7i78dIaY0cv+cmPRA==} + music-metadata@11.16.1: + resolution: {integrity: sha512-uR/mHK6eyfl8h3jVCobF5b38Mfg1IDJMiBxIVbmm5F+G1OXEFcUpQHveO84tJBAqvY93GCRY2R4kDyx7s06Rug==} engines: {node: '>=18'} mute-stream@3.0.0: @@ -2925,11 +3061,11 @@ packages: resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} engines: {node: '>=8.0.0'} - nan@2.28.0: - resolution: {integrity: sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==} + nan@2.29.0: + resolution: {integrity: sha512-GlGk3HIvitbvs+LT3g6XUP1kpirKNvmDFwF/bmo6XNWSb/eYEs/O4bfgIEIXCZ+lIOTS5xNwDvSGMw6FJdAhtA==} - nanoid@3.3.18: - resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + nanoid@3.3.19: + resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2953,14 +3089,18 @@ packages: nodemailer: optional: true - next-intl-swc-plugin-extractor@4.14.5: - resolution: {integrity: sha512-dbpsjHmwbqn795z7eDI7HHL+jxyvZ5CNF40sbGx+nkjM4pCs7HdTzGQnQ84mjF/WWZa/w9pJ6M74prh+3vnbGQ==} + next-intl-swc-plugin-extractor@4.14.7: + resolution: {integrity: sha512-0KUc8helXuJfyXVUQDolz0wnRnaW+dkJf6ozX6A+O9x1dd1+cb4PpZqj6FfcDdJagMuIxtnDmeRT7yUhllMYKA==} - next-intl@4.14.5: - resolution: {integrity: sha512-9sPJh5ITJbP28HZ5obuFAMC4RwW/mhEvHiGVHXPWL0uRbF2RrjHWz8PcUmLaH2oca79ak2ayQz+uRSALZN9xSw==} + next-intl@4.14.7: + resolution: {integrity: sha512-VQJu34ga2pG8EO7aQO7mzinoso/XpvQdMPfifBZIeWAoyGlKU3//nt7QVwWBZuOMBne4g6onsEFk+IA5ueF61g==} peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true next@16.3.6: resolution: {integrity: sha512-L+otWM/aQbYTx98aZhgEoMb4bZAXx1YVW4UMA/vuCyCoWG5HJyZUili8QAkqzrcC+5///tsz3s0M+SlyB5bLMw==} @@ -3023,9 +3163,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} @@ -3123,17 +3263,21 @@ packages: peerDependencies: react: ^19.3.0 - react-hook-form@7.88.0: - resolution: {integrity: sha512-QRaLOWhX93YCnMiRfnOFRSwWXZNt8qhm2JTZwypoDvKpSffTJHmpzMXt8U6PV5UThvL3IiiLDUWe2nHMtz6Mmw==} + react-hook-form@7.89.0: + resolution: {integrity: sha512-vKcoCfy8RKZDrhSdqsRFp0uEOdS1AhLjOL6hR7Wmfzg1akNxEhaPf5WORx8SgEQPVXakdDyDkqQp+KNxVnnPHg==} engines: {node: '>=18.0.0'} peerDependencies: + '@types/react': '*' react: ^16.8.0 || ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': @@ -3143,7 +3287,7 @@ packages: resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} engines: {node: '>=10'} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -3153,7 +3297,7 @@ packages: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -3199,8 +3343,8 @@ packages: reselect@5.3.0: resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==} - resend@6.28.1: - resolution: {integrity: sha512-5VWOcDiWKBt0NWYKXwzY9WJ+LbpQLYw9M6j1DDJYPk7TloHfWOJyaY4EFKoR/KPL0N4m5yO3o96iDoYOX7v+GA==} + resend@6.30.0: + resolution: {integrity: sha512-rED9rVw8N6cUvjmpYQwfZKBzd/cgWT+jURekVxtjFV2+YyK2/Tu2JOnE68sgqXlMBSYRoWgI6R0xlx3ANc/xeA==} engines: {node: '>=20'} peerDependencies: '@react-email/render': '*' @@ -3208,18 +3352,15 @@ packages: '@react-email/render': optional: true - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} - rettime@0.11.11: - resolution: {integrity: sha512-ILJRqVWBCTlg9r42fFgwVZx1gnFAcQF8mRoMkbgQfIrjEDf9nbBFDFx00oloOa+Q869FUtaYDXZvEfnecQSCoQ==} + rettime@0.11.12: + resolution: {integrity: sha512-5ExtR1ppiDBQkVoPw5NAqdbfH4Iq2VOmQKHMtUoaFxA9bo2krzFYBtyq6K40xxbYp+2w/YOr6D+1ToF6tTN53A==} - rolldown@1.2.7: - resolution: {integrity: sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==} + rolldown@1.2.11: + resolution: {integrity: sha512-qpSwIyz0jHQq5qXBTNxFmE6664rJ7O+4TvPFOiOaBSrz8IOHc1koKKSqTM2H6u1UG1+TveuC6vaDHKXFOvb1Kw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3260,8 +3401,8 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - sharp@0.35.4: - resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==} + sharp@0.35.5: + resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} engines: {node: '>=20.9.0'} peerDependencies: '@types/node': '*' @@ -3290,7 +3431,7 @@ packages: sonner@2.0.8: resolution: {integrity: sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==} peerDependencies: - '@types/react': 19.2.18 + '@types/react': ^18.0.0 || ^19.0.0 react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: @@ -3301,13 +3442,6 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} @@ -3349,10 +3483,6 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -3363,10 +3493,6 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - strip-json-comments@5.0.3: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} @@ -3388,9 +3514,6 @@ packages: babel-plugin-macros: optional: true - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -3432,30 +3555,30 @@ packages: resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} engines: {node: '>=20'} - tinybench@6.1.4: - resolution: {integrity: sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==} + tinybench@6.2.0: + resolution: {integrity: sha512-78U2TlB2CnVenajOFzf3BKSm0J6oz5L0NV7g32LCPccvYc0lbWvys4d3uUUCS2B1N8PAf2+aekR8i1KbC3HO7Q==} engines: {node: '>=20.0.0'} - tinyexec@1.3.0: - resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} engines: {node: '>=18'} tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinymce@8.9.1: - resolution: {integrity: sha512-5KrFiuKri2sPQW3ERWodsx3R0RZiw0cJJDr61qaMQiXO1ir3ZYaf6gVVaao+T29spZ9L9waaeE/co8Ov2Rn3vQ==} + tinymce@8.9.2: + resolution: {integrity: sha512-Qh6ADSC0x1F/KsrupfResNJFAaINJQBtfVjx5zxxWJ0ZrGtaKldtAXDMI6uEA57s2n+0rEtXmtbitiU4zV7+0Q==} tinyrainbow@3.1.1: resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} - tldts-core@7.4.12: - resolution: {integrity: sha512-nYNzS2WRf4QJmjzFFgAxLOBjyBxAGRbCy9PVBPaglcYyYajh40VBn+v5Ngr96ZMc7oM0+aCJdtQnNejvdBnXMQ==} + tldts-core@7.4.16: + resolution: {integrity: sha512-MDolfaSJtlSK5Y0A1xl3277ekubZwobpBjugknDizI9O5Rm60a1m8k4ICK+MRsCDzPygT81mp3BBf5RKDlFRfA==} - tldts@7.4.12: - resolution: {integrity: sha512-WylhSDKVeYnWXL3a+vKTaOxjnOeEGw938hImY8zoRWJjRRK/Jp1K+IihBzIONpUmW4e3WmXT6q5FW6vlESVZCA==} + tldts@7.4.16: + resolution: {integrity: sha512-QwBER5KMR86IIjpIiO7H/Z3IMJPsZ1A6RKPAqzTTgOyUQUSt9FdnKcqhTaJmkY6HVrgouZHZR0ncK5QxvmnQeg==} hasBin: true tmp@0.2.7: @@ -3477,16 +3600,16 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.23.13: - resolution: {integrity: sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==} + tsx@4.23.15: + resolution: {integrity: sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==} engines: {node: '>=18.0.0'} hasBin: true tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - type-fest@5.9.0: - resolution: {integrity: sha512-yANm3Jr3GiJ1qgJlxGAVxTOIcEOk1rhQHamlXtnrCK7EHP4HeM9OGxtMg/W7HFdrVzw/ZWJKGVIJusVH85sLtw==} + type-fest@5.10.0: + resolution: {integrity: sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==} engines: {node: '>=20'} typescript@7.0.2: @@ -3494,8 +3617,8 @@ packages: engines: {node: '>=16.20.0'} hasBin: true - uint8array-extras@1.5.0: - resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + uint8array-extras@1.6.0: + resolution: {integrity: sha512-8iAasVS4wUx0gPLjH8Xtz2PeDzTSiy8QiLGu2DT3X5GU+egFEQhpnbtkehbAwjvDcxIERmCYcysiODFmE3Ud0Q==} engines: {node: '>=18'} undici-types@5.26.5: @@ -3504,8 +3627,8 @@ packages: undici-types@8.9.0: resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} - undici@8.10.2: - resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} + undici@8.11.2: + resolution: {integrity: sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==} engines: {node: '>=22.19.0'} until-async@3.0.2: @@ -3515,37 +3638,41 @@ packages: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - use-intl@4.14.5: - resolution: {integrity: sha512-NNGSInks18BAasPgnMrnahNkEZSkWpbWE70IcEDWPUZwS39tVuDB/Vo6J3FaDnYwwKioR33JfWFOzEFnhuJcJw==} + use-intl@4.14.7: + resolution: {integrity: sha512-L7l2mo3KE8OetLkyIOdKZfN0J05+e9gB7cxgrVthkjIGu1nCW9KOBgZkVcK7w0tbc3WLfnEMgX3J+vSXMCZA/A==} peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true use-sidecar@1.1.3: resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} engines: {node: '>=10'} peerDependencies: - '@types/react': 19.2.18 + '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + use-sync-external-store@1.7.0: + resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - vite@8.3.0: - resolution: {integrity: sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==} + vite@8.3.1: + resolution: {integrity: sha512-/bvH9E9tmCXRGp2uXY3WbOldqpTwFkbha/8ANaEQ6VkxhH60KyqLwgZq6lG2y+4uT55x9+9eUHMpQ7uGnOCKjA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -3628,9 +3755,9 @@ packages: jsdom: optional: true - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} + w3c-xmlserializer@6.0.0: + resolution: {integrity: sha512-4Nsy8K5Tr6SPDH9jhKJOHf7ChDrc1zufZTVSF7x72hwuEXBqxqk9G6cK+K2NRUtB3iELRJqjXb4JPDMBjMTl2Q==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} webidl-conversions@8.0.1: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} @@ -3644,8 +3771,8 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - whatwg-url@17.1.0: - resolution: {integrity: sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==} + whatwg-url@17.1.2: + resolution: {integrity: sha512-TEZA+Zqxin7Jjsm2cjRohCmen5awh+hT6Zi3VZdqZlNRk7zvOI/9WpBFg/DWlA56bWnzwm6DuB8NS0EsxQH9uQ==} engines: {node: ^22.14.0 || >=24.0.0} which@2.0.2: @@ -3665,10 +3792,6 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -3683,8 +3806,8 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} engines: {node: '>= 14.6'} hasBin: true @@ -3707,20 +3830,20 @@ snapshots: '@alloc/quick-lru@5.3.0': {} - '@asamuzakjp/css-color@6.0.7': + '@asamuzakjp/css-color@7.1.2': dependencies: - '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.2.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - lru-cache: 11.5.2 + '@csstools/css-calc': 3.4.1(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-color-parser': 4.2.4(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-parser-algorithms': 4.0.1(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 + lru-cache: 11.5.3 - '@asamuzakjp/dom-selector@8.3.2': + '@asamuzakjp/dom-selector@9.2.2': dependencies: bidi-js: 1.1.0 css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.5.2 + lru-cache: 11.5.3 '@auth/core@0.41.3': dependencies: @@ -3752,28 +3875,28 @@ snapshots: '@balena/dockerignore@1.0.2': {} - '@base-ui/react@1.8.0(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@base-ui/react@1.8.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: '@babel/runtime': 7.29.7 - '@base-ui/utils': 0.4.0(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@base-ui/utils': 0.4.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@floating-ui/react-dom': 2.1.9(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@floating-ui/utils': 0.2.12 react: 19.3.0 react-dom: 19.3.0(react@19.3.0) - use-sync-external-store: 1.6.0(react@19.3.0) + use-sync-external-store: 1.7.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@base-ui/utils@0.4.0(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@base-ui/utils@0.4.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: '@babel/runtime': 7.29.7 '@floating-ui/utils': 0.2.12 react: 19.3.0 react-dom: 19.3.0(react@19.3.0) reselect: 5.3.0 - use-sync-external-store: 1.6.0(react@19.3.0) + use-sync-external-store: 1.7.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 '@bcoe/v8-coverage@1.0.2': {} @@ -3818,29 +3941,29 @@ snapshots: dependencies: css-tree: 3.2.1 - '@csstools/color-helpers@6.1.1': {} + '@csstools/color-helpers@6.1.2': {} - '@csstools/css-calc@3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-calc@3.4.1(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-parser-algorithms': 4.0.1(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-color-parser@4.2.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-color-parser@4.2.4(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/color-helpers': 6.1.1 - '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 + '@csstools/color-helpers': 6.1.2 + '@csstools/css-calc': 3.4.1(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-parser-algorithms': 4.0.1(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-syntax-patches-for-csstree@1.1.12(css-tree@3.2.1)': + '@csstools/css-syntax-patches-for-csstree@1.1.14(css-tree@3.2.1)': optionalDependencies: css-tree: 3.2.1 - '@csstools/css-tokenizer@4.0.0': {} + '@csstools/css-tokenizer@4.0.2': {} '@dnd-kit/accessibility@3.1.1(react@19.3.0)': dependencies: @@ -3885,16 +4008,6 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild-kit/core-utils@3.3.2': - dependencies: - esbuild: 0.25.12 - source-map-support: 0.5.21 - - '@esbuild-kit/esm-loader@2.6.5': - dependencies: - '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.14.3 - '@esbuild/aix-ppc64@0.25.12': optional: true @@ -4051,7 +4164,7 @@ snapshots: '@esbuild/win32-x64@0.28.2': optional: true - '@exodus/bytes@1.15.1(@noble/hashes@2.4.0)': + '@exodus/bytes@1.16.0(@noble/hashes@2.4.0)': optionalDependencies: '@noble/hashes': 2.4.0 @@ -4078,7 +4191,7 @@ snapshots: dependencies: '@formatjs/icu-skeleton-parser': 2.1.11 - '@formatjs/icu-messageformat-parser@3.5.19': + '@formatjs/icu-messageformat-parser@3.5.20': dependencies: '@formatjs/icu-skeleton-parser': 2.1.12 @@ -4090,7 +4203,7 @@ snapshots: dependencies: '@formatjs/fast-memoize': 3.1.7 - '@grpc/grpc-js@1.14.4': + '@grpc/grpc-js@1.14.5': dependencies: '@grpc/proto-loader': 0.8.1 '@js-sdsl/ordered-map': 4.4.2 @@ -4109,156 +4222,149 @@ snapshots: protobufjs: 7.6.6 yargs: 17.7.3 - '@hookform/resolvers@5.9.1(react-hook-form@7.88.0(react@19.3.0))(zod@4.6.5)': + '@hookform/resolvers@5.9.1(react-hook-form@7.89.0(@types/react@19.3.0)(react@19.3.0))(zod@4.6.5)': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.88.0(react@19.3.0) + react-hook-form: 7.89.0(@types/react@19.3.0)(react@19.3.0) optionalDependencies: zod: 4.6.5 '@img/colour@1.1.0': {} - '@img/sharp-darwin-arm64@0.35.4': + '@img/sharp-darwin-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.3.3 + '@img/sharp-libvips-darwin-arm64': 1.3.4 optional: true - '@img/sharp-darwin-x64@0.35.4': + '@img/sharp-darwin-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.3.3 + '@img/sharp-libvips-darwin-x64': 1.3.4 optional: true - '@img/sharp-freebsd-wasm32@0.35.4': + '@img/sharp-freebsd-wasm32@0.35.5': dependencies: - '@img/sharp-wasm32': 0.35.4 + '@img/sharp-wasm32': 0.35.5 optional: true - '@img/sharp-libvips-darwin-arm64@1.3.3': + '@img/sharp-libvips-darwin-arm64@1.3.4': optional: true - '@img/sharp-libvips-darwin-x64@1.3.3': + '@img/sharp-libvips-darwin-x64@1.3.4': optional: true - '@img/sharp-libvips-linux-arm64@1.3.3': + '@img/sharp-libvips-linux-arm64@1.3.4': optional: true - '@img/sharp-libvips-linux-arm@1.3.3': + '@img/sharp-libvips-linux-arm@1.3.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.3.3': + '@img/sharp-libvips-linux-ppc64@1.3.4': optional: true - '@img/sharp-libvips-linux-riscv64@1.3.3': + '@img/sharp-libvips-linux-riscv64@1.3.4': optional: true - '@img/sharp-libvips-linux-s390x@1.3.3': + '@img/sharp-libvips-linux-s390x@1.3.4': optional: true - '@img/sharp-libvips-linux-x64@1.3.3': + '@img/sharp-libvips-linux-x64@1.3.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.3.3': + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.3.3': + '@img/sharp-libvips-linuxmusl-x64@1.3.4': optional: true - '@img/sharp-linux-arm64@0.35.4': + '@img/sharp-linux-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.3.3 + '@img/sharp-libvips-linux-arm64': 1.3.4 optional: true - '@img/sharp-linux-arm@0.35.4': + '@img/sharp-linux-arm@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.3.3 + '@img/sharp-libvips-linux-arm': 1.3.4 optional: true - '@img/sharp-linux-ppc64@0.35.4': + '@img/sharp-linux-ppc64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.3.3 + '@img/sharp-libvips-linux-ppc64': 1.3.4 optional: true - '@img/sharp-linux-riscv64@0.35.4': + '@img/sharp-linux-riscv64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.3.3 + '@img/sharp-libvips-linux-riscv64': 1.3.4 optional: true - '@img/sharp-linux-s390x@0.35.4': + '@img/sharp-linux-s390x@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.3.3 + '@img/sharp-libvips-linux-s390x': 1.3.4 optional: true - '@img/sharp-linux-x64@0.35.4': + '@img/sharp-linux-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.3.3 + '@img/sharp-libvips-linux-x64': 1.3.4 optional: true - '@img/sharp-linuxmusl-arm64@0.35.4': + '@img/sharp-linuxmusl-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 optional: true - '@img/sharp-linuxmusl-x64@0.35.4': + '@img/sharp-linuxmusl-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.3.3 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 optional: true - '@img/sharp-wasm32@0.35.4': + '@img/sharp-wasm32@0.35.5': dependencies: '@emnapi/runtime': 1.11.3 optional: true - '@img/sharp-webcontainers-wasm32@0.35.4': + '@img/sharp-webcontainers-wasm32@0.35.5': dependencies: - '@img/sharp-wasm32': 0.35.4 + '@img/sharp-wasm32': 0.35.5 optional: true - '@img/sharp-win32-arm64@0.35.4': + '@img/sharp-win32-arm64@0.35.5': optional: true - '@img/sharp-win32-ia32@0.35.4': + '@img/sharp-win32-ia32@0.35.5': optional: true - '@img/sharp-win32-x64@0.35.4': + '@img/sharp-win32-x64@0.35.5': optional: true '@inquirer/ansi@2.0.8': {} - '@inquirer/confirm@6.3.2(@types/node@26.6.2)': + '@inquirer/confirm@6.3.2(@types/node@26.6.3)': dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.2) - '@inquirer/type': 4.1.1(@types/node@26.6.2) + '@inquirer/core': 12.0.3(@types/node@26.6.3) + '@inquirer/type': 4.1.1(@types/node@26.6.3) optionalDependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 - '@inquirer/core@12.0.3(@types/node@26.6.2)': + '@inquirer/core@12.0.3(@types/node@26.6.3)': dependencies: '@inquirer/ansi': 2.0.8 '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.1.1(@types/node@26.6.2) + '@inquirer/type': 4.1.1(@types/node@26.6.3) cli-width: 4.1.0 fast-wrap-ansi: 0.2.2 mute-stream: 3.0.0 signal-exit: 4.1.0 optionalDependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@inquirer/figures@2.0.9': {} - '@inquirer/type@4.1.1(@types/node@26.6.2)': + '@inquirer/type@4.1.1(@types/node@26.6.3)': optionalDependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@ioredis/commands@2.0.0': {} - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.2.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/cliui@9.0.0': {} '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -4362,7 +4468,7 @@ snapshots: dependencies: '@otplib/core': 13.5.0 - '@oxc-project/types@0.148.0': {} + '@oxc-project/types@0.151.0': {} '@panva/hkdf@1.2.1': {} @@ -4424,9 +4530,6 @@ snapshots: '@pinojs/redact@0.4.0': {} - '@pkgjs/parseargs@0.11.0': - optional: true - '@playwright/test@1.63.0': dependencies: playwright: 1.63.0 @@ -4453,184 +4556,184 @@ snapshots: '@radix-ui/primitive@1.1.7': {} - '@radix-ui/react-compose-refs@1.1.5(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-compose-refs@1.1.5(@types/react@19.3.0)(react@19.3.0)': dependencies: react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-context@1.2.2(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-context@1.2.2(@types/react@19.3.0)(react@19.3.0)': dependencies: react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-dialog@1.1.23(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@radix-ui/react-dialog@1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) aria-hidden: 1.2.6 react: 19.3.0 react-dom: 19.3.0(react@19.3.0) - react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.3.0) + react-remove-scroll: 2.7.2(@types/react@19.3.0)(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7(@types/react@19.2.18) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7(@types/react@19.2.18) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-focus-guards@1.1.6(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-focus-guards@1.1.6(@types/react@19.3.0)(react@19.3.0)': dependencies: react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7(@types/react@19.2.18) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-id@1.1.4(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-id@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-portal@1.1.17(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@radix-ui/react-portal@1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7(@types/react@19.2.18) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-presence@1.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@radix-ui/react-presence@1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7(@types/react@19.2.18) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 - '@types/react-dom': 19.2.7(@types/react@19.2.18) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-slot@1.3.3(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-slot@1.3.3(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-use-callback-ref@1.1.4(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-use-callback-ref@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-use-controllable-state@1.2.6(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-use-controllable-state@1.2.6(@types/react@19.3.0)(react@19.3.0)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.2.18)(react@19.3.0)': + '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: react: 19.3.0 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@rolldown/binding-android-arm-eabi@1.2.7': + '@rolldown/binding-android-arm-eabi@1.2.11': optional: true - '@rolldown/binding-android-arm64@1.2.7': + '@rolldown/binding-android-arm64@1.2.11': optional: true - '@rolldown/binding-darwin-arm64@1.2.7': + '@rolldown/binding-darwin-arm64@1.2.11': optional: true - '@rolldown/binding-darwin-x64@1.2.7': + '@rolldown/binding-darwin-x64@1.2.11': optional: true - '@rolldown/binding-freebsd-x64@1.2.7': + '@rolldown/binding-freebsd-x64@1.2.11': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.2.7': + '@rolldown/binding-linux-arm-gnueabihf@1.2.11': optional: true - '@rolldown/binding-linux-arm64-gnu@1.2.7': + '@rolldown/binding-linux-arm64-gnu@1.2.11': optional: true - '@rolldown/binding-linux-arm64-musl@1.2.7': + '@rolldown/binding-linux-arm64-musl@1.2.11': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.2.7': + '@rolldown/binding-linux-ppc64-gnu@1.2.11': optional: true - '@rolldown/binding-linux-s390x-gnu@1.2.7': + '@rolldown/binding-linux-s390x-gnu@1.2.11': optional: true - '@rolldown/binding-linux-x64-gnu@1.2.7': + '@rolldown/binding-linux-x64-gnu@1.2.11': optional: true - '@rolldown/binding-linux-x64-musl@1.2.7': + '@rolldown/binding-linux-x64-musl@1.2.11': optional: true - '@rolldown/binding-openharmony-arm64@1.2.7': + '@rolldown/binding-openharmony-arm64@1.2.11': optional: true - '@rolldown/binding-win32-arm64-msvc@1.2.7': + '@rolldown/binding-win32-arm64-msvc@1.2.11': optional: true - '@rolldown/binding-win32-x64-msvc@1.2.7': + '@rolldown/binding-win32-x64-msvc@1.2.11': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -4716,7 +4819,7 @@ snapshots: '@tailwindcss/node@4.3.3': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.24.5 + enhanced-resolve: 5.25.1 jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 @@ -4787,11 +4890,11 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.3.3 - '@tanstack/query-core@5.103.1': {} + '@tanstack/query-core@5.104.0': {} - '@tanstack/react-query@5.103.1(react@19.3.0)': + '@tanstack/react-query@5.104.0(react@19.3.0)': dependencies: - '@tanstack/query-core': 5.103.1 + '@tanstack/query-core': 5.104.0 react: 19.3.0 '@tanstack/react-virtual@3.14.13(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': @@ -4820,13 +4923,13 @@ snapshots: '@types/docker-modem@3.0.6': dependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@types/ssh2': 1.15.6 '@types/dockerode@4.0.1': dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@types/ssh2': 1.15.6 '@types/estree@1.0.9': {} @@ -4835,29 +4938,29 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@26.6.2': + '@types/node@26.6.3': dependencies: undici-types: 8.9.0 - '@types/react-dom@19.2.7(@types/react@19.2.18)': + '@types/react-dom@19.3.0(@types/react@19.3.0)': dependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - '@types/react@19.2.18': + '@types/react@19.3.0': dependencies: csstype: 3.2.3 '@types/set-cookie-parser@2.4.10': dependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@types/ssh2-streams@0.1.13': dependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@types/ssh2@0.5.52': dependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@types/ssh2-streams': 0.1.13 '@types/ssh2@1.15.6': @@ -4932,30 +5035,30 @@ snapshots: '@vitest/coverage-v8@5.0.2(vitest@5.0.2)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/istanbul-lib-coverage': 1.0.1 - '@vitest/istanbul-lib-report': 1.0.1 - ast-v8-to-istanbul: 1.0.6 + '@vitest/istanbul-lib-coverage': 1.0.2 + '@vitest/istanbul-lib-report': 1.0.2 + ast-v8-to-istanbul: 1.0.7 magicast: 0.5.5 obug: 2.2.1 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 5.0.2(@types/node@26.6.2)(@vitest/coverage-v8@5.0.2)(jsdom@30.0.1(@noble/hashes@2.4.0))(msw@2.15.0(@types/node@26.6.2)(typescript@7.0.2))(vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0)) + vitest: 5.0.2(@types/node@26.6.3)(@vitest/coverage-v8@5.0.2)(jsdom@30.1.1(@noble/hashes@2.4.0))(msw@2.15.0(@types/node@26.6.3)(typescript@7.0.2))(vite@8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) - '@vitest/istanbul-lib-coverage@1.0.1': {} + '@vitest/istanbul-lib-coverage@1.0.2': {} - '@vitest/istanbul-lib-report@1.0.1': + '@vitest/istanbul-lib-report@1.0.2': dependencies: - '@vitest/istanbul-lib-coverage': 1.0.1 + '@vitest/istanbul-lib-coverage': 1.0.2 - '@vitest/mocker@5.0.2(msw@2.15.0(@types/node@26.6.2)(typescript@7.0.2))(vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0))': + '@vitest/mocker@5.0.2(msw@2.15.0(@types/node@26.6.3)(typescript@7.0.2))(vite@8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.2 estree-walker: 3.0.3 - magic-string: 1.4.1 + magic-string: 1.4.2 optionalDependencies: - msw: 2.15.0(@types/node@26.6.2)(typescript@7.0.2) - vite: 8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0) + msw: 2.15.0(@types/node@26.6.3)(typescript@7.0.2) + vite: 8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) '@vitest/spy@5.0.2': {} @@ -4965,17 +5068,13 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.3.0: {} - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - ansi-styles@6.2.3: {} - archiver-utils@5.0.2: dependencies: - glob: 10.5.0 + glob: 11.1.0 graceful-fs: 4.2.11 is-stream: 2.0.1 lazystream: 1.0.1 @@ -5007,7 +5106,7 @@ snapshots: assertion-error@2.0.1: {} - ast-v8-to-istanbul@1.0.6: + ast-v8-to-istanbul@1.0.7: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -5023,13 +5122,15 @@ snapshots: axe-core@4.13.0: {} - b4a@1.8.1: {} + b4a@1.9.0: {} balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + bare-events@2.9.2: {} - bare-fs@4.8.1: + bare-fs@4.8.2: dependencies: bare-events: 2.9.2 bare-path: 3.1.2 @@ -5044,7 +5145,7 @@ snapshots: bare-stream@2.13.4(bare-events@2.9.2): dependencies: - b4a: 1.8.1 + b4a: 1.9.0 streamx: 2.28.1 teex: 1.0.1 optionalDependencies: @@ -5058,7 +5159,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.11.21: {} + baseline-browser-mapping@2.11.26: {} bcrypt-pbkdf@1.0.2: dependencies: @@ -5074,13 +5175,15 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - brace-expansion@2.1.4: + brace-expansion@2.1.7: dependencies: balanced-match: 1.0.2 - buffer-crc32@1.0.0: {} + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 - buffer-from@1.1.2: {} + buffer-crc32@1.0.0: {} buffer@5.7.1: dependencies: @@ -5097,7 +5200,7 @@ snapshots: byline@5.0.0: {} - caniuse-lite@1.0.30001810: {} + caniuse-lite@1.0.30001812: {} chai@6.2.2: {} @@ -5121,12 +5224,12 @@ snapshots: cluster-key-slot@1.1.1: {} - cmdk@1.1.1(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + cmdk@1.1.1(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.3.0) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) react: 19.3.0 react-dom: 19.3.0(react@19.3.0) transitivePeerDependencies: @@ -5158,7 +5261,7 @@ snapshots: cpu-features@0.0.10: dependencies: buildcheck: 0.0.7 - nan: 2.28.0 + nan: 2.29.0 optional: true crc-32@1.2.2: {} @@ -5206,9 +5309,9 @@ snapshots: detect-node-es@1.1.0: {} - docker-compose@1.4.2: + docker-compose@1.5.0: dependencies: - yaml: 2.9.0 + yaml: 2.9.1 docker-modem@5.0.7: dependencies: @@ -5222,7 +5325,7 @@ snapshots: dockerode@5.0.1: dependencies: '@balena/dockerignore': 1.0.2 - '@grpc/grpc-js': 1.14.4 + '@grpc/grpc-js': 1.14.5 '@grpc/proto-loader': 0.7.15 docker-modem: 5.0.7 protobufjs: 7.6.6 @@ -5230,37 +5333,33 @@ snapshots: transitivePeerDependencies: - supports-color - dompurify@3.4.15: + dompurify@3.4.16: optionalDependencies: '@types/trusted-types': 2.0.7 - drizzle-kit@0.31.10: + drizzle-kit@0.31.11: dependencies: '@drizzle-team/brocli': 0.10.2 - '@esbuild-kit/esm-loader': 2.6.5 + '@esbuild-kit/esm-loader': tsx@4.23.15 esbuild: 0.25.12 - tsx: 4.23.13 + tsx: 4.23.15 - drizzle-orm@0.45.2(mysql2@3.24.4(@types/node@26.6.2)): + drizzle-orm@0.45.3(mysql2@3.24.4(@types/node@26.6.3)): optionalDependencies: - mysql2: 3.24.4(@types/node@26.6.2) - - eastasianwidth@0.2.0: {} + mysql2: 3.24.4(@types/node@26.6.3) emoji-regex@8.0.0: {} - emoji-regex@9.2.2: {} - end-of-stream@1.4.5: dependencies: once: 1.4.0 - enhanced-resolve@5.24.5: + enhanced-resolve@5.25.1: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 - entities@8.0.0: {} + entities@8.1.0: {} es-module-lexer@2.3.2: {} @@ -5367,7 +5466,7 @@ snapshots: '@tokenizer/inflate': 0.4.1 strtok3: 10.3.5 token-types: 6.1.2 - uint8array-extras: 1.5.0 + uint8array-extras: 1.6.0 transitivePeerDependencies: - supports-color @@ -5376,9 +5475,9 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - framer-motion@13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + framer-motion@13.4.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - motion-dom: 13.3.0 + motion-dom: 13.4.4 motion-utils: 13.3.0 tslib: 2.8.1 optionalDependencies: @@ -5400,18 +5499,14 @@ snapshots: get-port@5.1.1: {} - get-tsconfig@4.14.3: - dependencies: - resolve-pkg-maps: 1.0.0 - - glob@10.5.0: + glob@11.1.0: dependencies: foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 + jackspeak: 4.2.3 + minimatch: 10.2.6 minipass: 7.1.3 package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 + path-scurry: 2.0.2 graceful-fs@4.2.11: {} @@ -5426,9 +5521,9 @@ snapshots: help-me@5.0.0: {} - html-encoding-sniffer@6.0.0(@noble/hashes@2.4.0): + html-encoding-sniffer@7.0.0(@noble/hashes@2.4.0): dependencies: - '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + '@exodus/bytes': 1.16.0(@noble/hashes@2.4.0) transitivePeerDependencies: - '@noble/hashes' @@ -5436,9 +5531,9 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icu-minify@4.14.5: + icu-minify@4.14.7: dependencies: - '@formatjs/icu-messageformat-parser': 3.5.19 + '@formatjs/icu-messageformat-parser': 3.5.20 ieee754@1.2.1: {} @@ -5482,19 +5577,17 @@ snapshots: isexe@2.0.0: {} - isomorphic-dompurify@4.3.0(@noble/hashes@2.4.0): + isomorphic-dompurify@4.4.0(@noble/hashes@2.4.0): dependencies: - dompurify: 3.4.15 - jsdom: 30.0.1(@noble/hashes@2.4.0) + dompurify: 3.4.16 + jsdom: 30.1.1(@noble/hashes@2.4.0) transitivePeerDependencies: - '@noble/hashes' - canvas - jackspeak@3.4.3: + jackspeak@4.2.3: dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + '@isaacs/cliui': 9.0.0 jiti@2.7.0: {} @@ -5506,28 +5599,27 @@ snapshots: js-tokens@10.0.0: {} - jsdom@30.0.1(@noble/hashes@2.4.0): + jsdom@30.1.1(@noble/hashes@2.4.0): dependencies: - '@asamuzakjp/css-color': 6.0.7 - '@asamuzakjp/dom-selector': 8.3.2 + '@asamuzakjp/css-color': 7.1.2 + '@asamuzakjp/dom-selector': 9.2.2 '@bramus/specificity': 2.4.2 - '@csstools/css-syntax-patches-for-csstree': 1.1.12(css-tree@3.2.1) - '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + '@csstools/css-syntax-patches-for-csstree': 1.1.14(css-tree@3.2.1) + '@exodus/bytes': 1.16.0(@noble/hashes@2.4.0) css-tree: 3.2.1 data-urls: 7.0.0(@noble/hashes@2.4.0) decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0(@noble/hashes@2.4.0) + html-encoding-sniffer: 7.0.0(@noble/hashes@2.4.0) is-potential-custom-element-name: 1.0.1 - lru-cache: 11.5.2 + lru-cache: 11.5.3 parse5: 8.0.1 saxes: 6.0.0 - symbol-tree: 3.2.4 tough-cookie: 6.0.2 - undici: 8.10.2 - w3c-xmlserializer: 5.0.0 + undici: 8.11.2 + w3c-xmlserializer: 6.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 - whatwg-url: 17.1.0(@noble/hashes@2.4.0) + whatwg-url: 17.1.2(@noble/hashes@2.4.0) xml-name-validator: 5.0.0 transitivePeerDependencies: - '@noble/hashes' @@ -5653,13 +5745,11 @@ snapshots: long@5.3.2: {} - lru-cache@10.4.3: {} - - lru-cache@11.5.2: {} + lru-cache@11.5.3: {} lru.min@1.1.5: {} - lucide-react@1.47.0(react@19.3.0): + lucide-react@1.48.0(react@19.3.0): dependencies: react: 19.3.0 @@ -5669,7 +5759,7 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 - magic-string@1.4.1: + magic-string@1.4.2: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 @@ -5685,13 +5775,13 @@ snapshots: mini-svg-data-uri@1.4.4: {} + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + minimatch@5.1.9: dependencies: - brace-expansion: 2.1.4 - - minimatch@9.0.9: - dependencies: - brace-expansion: 2.1.4 + brace-expansion: 2.1.7 minimist@1.2.8: {} @@ -5701,15 +5791,15 @@ snapshots: mkdirp@3.0.1: {} - motion-dom@13.3.0: + motion-dom@13.4.4: dependencies: motion-utils: 13.3.0 motion-utils@13.3.0: {} - motion@13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + motion@13.4.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - framer-motion: 13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + framer-motion: 13.4.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0) tslib: 2.8.1 optionalDependencies: react: 19.3.0 @@ -5717,9 +5807,9 @@ snapshots: ms@2.1.3: {} - msw@2.15.0(@types/node@26.6.2)(typescript@7.0.2): + msw@2.15.0(@types/node@26.6.3)(typescript@7.0.2): dependencies: - '@inquirer/confirm': 6.3.2(@types/node@26.6.2) + '@inquirer/confirm': 6.3.2(@types/node@26.6.3) '@mswjs/interceptors': 0.41.9 '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 @@ -5730,11 +5820,11 @@ snapshots: outvariant: 1.4.3 path-to-regexp: 6.3.0 picocolors: 1.1.1 - rettime: 0.11.11 + rettime: 0.11.12 statuses: 2.0.2 strict-event-emitter: 0.5.1 tough-cookie: 6.0.2 - type-fest: 5.9.0 + type-fest: 5.10.0 until-async: 3.0.2 yargs: 17.7.3 optionalDependencies: @@ -5742,7 +5832,7 @@ snapshots: transitivePeerDependencies: - '@types/node' - music-metadata@11.15.0: + music-metadata@11.16.1: dependencies: '@borewit/text-codec': 0.2.2 '@tokenizer/token': 0.3.0 @@ -5752,16 +5842,16 @@ snapshots: media-typer: 2.0.0 strtok3: 10.3.5 token-types: 6.1.2 - uint8array-extras: 1.5.0 + uint8array-extras: 1.6.0 win-guid: 0.2.1 transitivePeerDependencies: - supports-color mute-stream@3.0.0: {} - mysql2@3.24.4(@types/node@26.6.2): + mysql2@3.24.4(@types/node@26.6.3): dependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 aws-ssl-profiles: 1.1.2 generate-function: 2.3.1 iconv-lite: 0.7.3 @@ -5774,24 +5864,24 @@ snapshots: dependencies: lru.min: 1.1.5 - nan@2.28.0: + nan@2.29.0: optional: true - nanoid@3.3.18: {} + nanoid@3.3.19: {} negotiator@1.1.0: dependencies: content-type: 2.1.0 - next-auth@5.0.0-beta.32(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0): + next-auth@5.0.0-beta.32(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0): dependencies: '@auth/core': 0.41.3 - next: 16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + next: 16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) react: 19.3.0 - next-intl-swc-plugin-extractor@4.14.5: {} + next-intl-swc-plugin-extractor@4.14.7: {} - next-intl@4.14.5(@swc/helpers@0.5.23)(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0): + next-intl@4.14.7(@swc/helpers@0.5.23)(@types/react@19.3.0)(next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0): dependencies: '@eloqnt/config': 0.1.0 '@eloqnt/format-json': 0.1.0 @@ -5799,21 +5889,23 @@ snapshots: '@formatjs/intl-localematcher': 0.8.14 '@parcel/watcher': 2.6.0 '@swc/core': 1.16.2(@swc/helpers@0.5.23) - icu-minify: 4.14.5 + icu-minify: 4.14.7 negotiator: 1.1.0 - next: 16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - next-intl-swc-plugin-extractor: 4.14.5 + next: 16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + next-intl-swc-plugin-extractor: 4.14.7 react: 19.3.0 - use-intl: 4.14.5(react@19.3.0) + use-intl: 4.14.7(@types/react@19.3.0)(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 transitivePeerDependencies: - '@swc/helpers' - next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + next@16.3.6(@playwright/test@1.63.0)(@types/node@26.6.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: '@next/env': 16.3.6 '@swc/helpers': 0.5.23 - baseline-browser-mapping: 2.11.21 - caniuse-lite: 1.0.30001810 + baseline-browser-mapping: 2.11.26 + caniuse-lite: 1.0.30001812 postcss: 8.5.23 react: 19.3.0 react-dom: 19.3.0(react@19.3.0) @@ -5828,7 +5920,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 16.3.6 '@next/swc-win32-x64-msvc': 16.3.6 '@playwright/test': 1.63.0 - sharp: 0.35.4(@types/node@26.6.2) + sharp: 0.35.5(@types/node@26.6.3) transitivePeerDependencies: - '@babel/core' - '@types/node' @@ -5865,13 +5957,13 @@ snapshots: parse5@8.0.1: dependencies: - entities: 8.0.0 + entities: 8.1.0 path-key@3.1.1: {} - path-scurry@1.11.1: + path-scurry@2.0.2: dependencies: - lru-cache: 10.4.3 + lru-cache: 11.5.3 minipass: 7.1.3 path-to-regexp@6.3.0: {} @@ -5933,13 +6025,13 @@ snapshots: postcss@8.5.23: dependencies: - nanoid: 3.3.18 + nanoid: 3.3.19 picocolors: 1.1.1 source-map-js: 1.2.1 postcss@8.5.28: dependencies: - nanoid: 3.3.18 + nanoid: 3.3.19 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -5979,7 +6071,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.2 - '@types/node': 26.6.2 + '@types/node': 26.6.3 long: 5.3.2 pump@3.0.4: @@ -5996,36 +6088,38 @@ snapshots: react: 19.3.0 scheduler: 0.28.0 - react-hook-form@7.88.0(react@19.3.0): + react-hook-form@7.89.0(@types/react@19.3.0)(react@19.3.0): dependencies: react: 19.3.0 + optionalDependencies: + '@types/react': 19.3.0 - react-remove-scroll-bar@2.3.8(@types/react@19.2.18)(react@19.3.0): + react-remove-scroll-bar@2.3.8(@types/react@19.3.0)(react@19.3.0): dependencies: react: 19.3.0 - react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.3.0) + react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.0) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - react-remove-scroll@2.7.2(@types/react@19.2.18)(react@19.3.0): + react-remove-scroll@2.7.2(@types/react@19.3.0)(react@19.3.0): dependencies: react: 19.3.0 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.18)(react@19.3.0) - react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.3.0) + react-remove-scroll-bar: 2.3.8(@types/react@19.3.0)(react@19.3.0) + react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.0) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.18)(react@19.3.0) - use-sidecar: 1.1.3(@types/react@19.2.18)(react@19.3.0) + use-callback-ref: 1.3.3(@types/react@19.3.0)(react@19.3.0) + use-sidecar: 1.1.3(@types/react@19.3.0)(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - react-style-singleton@2.2.3(@types/react@19.2.18)(react@19.3.0): + react-style-singleton@2.2.3(@types/react@19.3.0)(react@19.3.0): dependencies: get-nonce: 1.0.1 react: 19.3.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 react@19.3.0: {} @@ -6042,7 +6136,7 @@ snapshots: readable-stream@3.6.2: dependencies: inherits: 2.0.4 - string_decoder: 1.1.1 + string_decoder: 1.3.0 util-deprecate: 1.0.2 readable-stream@4.7.0: @@ -6069,37 +6163,35 @@ snapshots: reselect@5.3.0: {} - resend@6.28.1: + resend@6.30.0: dependencies: postal-mime: 2.7.6 standardwebhooks: 1.1.1 - resolve-pkg-maps@1.0.0: {} - retry@0.12.0: {} - rettime@0.11.11: {} + rettime@0.11.12: {} - rolldown@1.2.7: + rolldown@1.2.11: dependencies: - '@oxc-project/types': 0.148.0 + '@oxc-project/types': 0.151.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm-eabi': 1.2.7 - '@rolldown/binding-android-arm64': 1.2.7 - '@rolldown/binding-darwin-arm64': 1.2.7 - '@rolldown/binding-darwin-x64': 1.2.7 - '@rolldown/binding-freebsd-x64': 1.2.7 - '@rolldown/binding-linux-arm-gnueabihf': 1.2.7 - '@rolldown/binding-linux-arm64-gnu': 1.2.7 - '@rolldown/binding-linux-arm64-musl': 1.2.7 - '@rolldown/binding-linux-ppc64-gnu': 1.2.7 - '@rolldown/binding-linux-s390x-gnu': 1.2.7 - '@rolldown/binding-linux-x64-gnu': 1.2.7 - '@rolldown/binding-linux-x64-musl': 1.2.7 - '@rolldown/binding-openharmony-arm64': 1.2.7 - '@rolldown/binding-win32-arm64-msvc': 1.2.7 - '@rolldown/binding-win32-x64-msvc': 1.2.7 + '@rolldown/binding-android-arm-eabi': 1.2.11 + '@rolldown/binding-android-arm64': 1.2.11 + '@rolldown/binding-darwin-arm64': 1.2.11 + '@rolldown/binding-darwin-x64': 1.2.11 + '@rolldown/binding-freebsd-x64': 1.2.11 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.11 + '@rolldown/binding-linux-arm64-gnu': 1.2.11 + '@rolldown/binding-linux-arm64-musl': 1.2.11 + '@rolldown/binding-linux-ppc64-gnu': 1.2.11 + '@rolldown/binding-linux-s390x-gnu': 1.2.11 + '@rolldown/binding-linux-x64-gnu': 1.2.11 + '@rolldown/binding-linux-x64-musl': 1.2.11 + '@rolldown/binding-openharmony-arm64': 1.2.11 + '@rolldown/binding-win32-arm64-msvc': 1.2.11 + '@rolldown/binding-win32-x64-msvc': 1.2.11 safe-buffer@5.1.2: {} @@ -6125,38 +6217,38 @@ snapshots: setimmediate@1.0.5: {} - sharp@0.35.4(@types/node@26.6.2): + sharp@0.35.5(@types/node@26.6.3): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.35.4 - '@img/sharp-darwin-x64': 0.35.4 - '@img/sharp-freebsd-wasm32': 0.35.4 - '@img/sharp-libvips-darwin-arm64': 1.3.3 - '@img/sharp-libvips-darwin-x64': 1.3.3 - '@img/sharp-libvips-linux-arm': 1.3.3 - '@img/sharp-libvips-linux-arm64': 1.3.3 - '@img/sharp-libvips-linux-ppc64': 1.3.3 - '@img/sharp-libvips-linux-riscv64': 1.3.3 - '@img/sharp-libvips-linux-s390x': 1.3.3 - '@img/sharp-libvips-linux-x64': 1.3.3 - '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 - '@img/sharp-libvips-linuxmusl-x64': 1.3.3 - '@img/sharp-linux-arm': 0.35.4 - '@img/sharp-linux-arm64': 0.35.4 - '@img/sharp-linux-ppc64': 0.35.4 - '@img/sharp-linux-riscv64': 0.35.4 - '@img/sharp-linux-s390x': 0.35.4 - '@img/sharp-linux-x64': 0.35.4 - '@img/sharp-linuxmusl-arm64': 0.35.4 - '@img/sharp-linuxmusl-x64': 0.35.4 - '@img/sharp-webcontainers-wasm32': 0.35.4 - '@img/sharp-win32-arm64': 0.35.4 - '@img/sharp-win32-ia32': 0.35.4 - '@img/sharp-win32-x64': 0.35.4 - '@types/node': 26.6.2 + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + '@types/node': 26.6.3 shebang-command@2.0.0: dependencies: @@ -6172,22 +6264,15 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@2.0.8(@types/react@19.2.18)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + sonner@2.0.8(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: react: 19.3.0 react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 source-map-js@1.2.1: {} - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - split-ca@1.0.1: {} split2@4.2.0: {} @@ -6205,7 +6290,7 @@ snapshots: bcrypt-pbkdf: 1.0.2 optionalDependencies: cpu-features: 0.0.10 - nan: 2.28.0 + nan: 2.29.0 standard-as-callback@2.1.0: {} @@ -6235,12 +6320,6 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.2.0 - string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -6253,10 +6332,6 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.3.0 - strip-json-comments@5.0.3: {} strtok3@10.3.5: @@ -6268,8 +6343,6 @@ snapshots: client-only: 0.0.1 react: 19.3.0 - symbol-tree@3.2.4: {} - tagged-tag@1.0.0: {} tailwind-merge@3.7.0: {} @@ -6290,7 +6363,7 @@ snapshots: pump: 3.0.4 tar-stream: 3.2.1 optionalDependencies: - bare-fs: 4.8.1 + bare-fs: 4.8.2 bare-path: 3.1.2 transitivePeerDependencies: - bare-abort-controller @@ -6307,8 +6380,8 @@ snapshots: tar-stream@3.2.1: dependencies: - b4a: 1.8.1 - bare-fs: 4.8.1 + b4a: 1.9.0 + bare-fs: 4.8.2 fast-fifo: 1.3.2 streamx: 2.28.1 transitivePeerDependencies: @@ -6331,7 +6404,7 @@ snapshots: async-lock: 1.4.1 byline: 5.0.0 debug: 4.4.3 - docker-compose: 1.4.2 + docker-compose: 1.5.0 dockerode: 5.0.1 get-port: 5.1.1 proper-lockfile: 4.1.2 @@ -6339,7 +6412,7 @@ snapshots: ssh-remote-port-forward: 1.0.4 tar-fs: 3.1.3 tmp: 0.2.7 - undici: 8.10.2 + undici: 8.11.2 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -6348,7 +6421,7 @@ snapshots: text-decoder@1.2.7: dependencies: - b4a: 1.8.1 + b4a: 1.9.0 transitivePeerDependencies: - react-native-b4a @@ -6356,24 +6429,24 @@ snapshots: dependencies: real-require: 1.0.0 - tinybench@6.1.4: {} + tinybench@6.2.0: {} - tinyexec@1.3.0: {} + tinyexec@1.3.1: {} tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.7) picomatch: 4.0.7 - tinymce@8.9.1: {} + tinymce@8.9.2: {} tinyrainbow@3.1.1: {} - tldts-core@7.4.12: {} + tldts-core@7.4.16: {} - tldts@7.4.12: + tldts@7.4.16: dependencies: - tldts-core: 7.4.12 + tldts-core: 7.4.16 tmp@0.2.7: {} @@ -6385,7 +6458,7 @@ snapshots: tough-cookie@6.0.2: dependencies: - tldts: 7.4.12 + tldts: 7.4.16 tr46@6.0.0: dependencies: @@ -6393,7 +6466,7 @@ snapshots: tslib@2.8.1: {} - tsx@4.23.13: + tsx@4.23.15: dependencies: esbuild: 0.28.2 optionalDependencies: @@ -6401,7 +6474,7 @@ snapshots: tweetnacl@0.14.5: {} - type-fest@5.9.0: + type-fest@5.10.0: dependencies: tagged-tag: 1.0.0 @@ -6428,84 +6501,86 @@ snapshots: '@typescript/typescript-win32-arm64': 7.0.2 '@typescript/typescript-win32-x64': 7.0.2 - uint8array-extras@1.5.0: {} + uint8array-extras@1.6.0: {} undici-types@5.26.5: {} undici-types@8.9.0: {} - undici@8.10.2: {} + undici@8.11.2: {} until-async@3.0.2: {} - use-callback-ref@1.3.3(@types/react@19.2.18)(react@19.3.0): + use-callback-ref@1.3.3(@types/react@19.3.0)(react@19.3.0): dependencies: react: 19.3.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - use-intl@4.14.5(react@19.3.0): + use-intl@4.14.7(@types/react@19.3.0)(react@19.3.0): dependencies: '@formatjs/fast-memoize': 3.1.7 '@schummar/icu-type-parser': 1.21.5 - icu-minify: 4.14.5 + icu-minify: 4.14.7 intl-messageformat: 11.2.15 react: 19.3.0 + optionalDependencies: + '@types/react': 19.3.0 - use-sidecar@1.1.3(@types/react@19.2.18)(react@19.3.0): + use-sidecar@1.1.3(@types/react@19.3.0)(react@19.3.0): dependencies: detect-node-es: 1.1.0 react: 19.3.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.18 + '@types/react': 19.3.0 - use-sync-external-store@1.6.0(react@19.3.0): + use-sync-external-store@1.7.0(react@19.3.0): dependencies: react: 19.3.0 util-deprecate@1.0.2: {} - vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0): + vite@8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 postcss: 8.5.28 - rolldown: 1.2.7 + rolldown: 1.2.11 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 esbuild: 0.28.2 fsevents: 2.3.3 jiti: 2.7.0 - tsx: 4.23.13 - yaml: 2.9.0 + tsx: 4.23.15 + yaml: 2.9.1 - vitest@5.0.2(@types/node@26.6.2)(@vitest/coverage-v8@5.0.2)(jsdom@30.0.1(@noble/hashes@2.4.0))(msw@2.15.0(@types/node@26.6.2)(typescript@7.0.2))(vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0)): + vitest@5.0.2(@types/node@26.6.3)(@vitest/coverage-v8@5.0.2)(jsdom@30.1.1(@noble/hashes@2.4.0))(msw@2.15.0(@types/node@26.6.3)(typescript@7.0.2))(vite@8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.2(msw@2.15.0(@types/node@26.6.2)(typescript@7.0.2))(vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0)) + '@vitest/mocker': 5.0.2(msw@2.15.0(@types/node@26.6.3)(typescript@7.0.2))(vite@8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 - magic-string: 1.4.1 + magic-string: 1.4.2 obug: 2.2.1 picomatch: 4.0.7 std-env: 4.2.0 - tinybench: 6.1.4 - tinyexec: 1.3.0 + tinybench: 6.2.0 + tinyexec: 1.3.1 tinyglobby: 0.2.17 - vite: 8.3.0(@types/node@26.6.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0) + vite: 8.3.1(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) why-is-node-running: 3.2.2 optionalDependencies: - '@types/node': 26.6.2 + '@types/node': 26.6.3 '@vitest/coverage-v8': 5.0.2(vitest@5.0.2) - jsdom: 30.0.1(@noble/hashes@2.4.0) + jsdom: 30.1.1(@noble/hashes@2.4.0) transitivePeerDependencies: - msw - w3c-xmlserializer@5.0.0: + w3c-xmlserializer@6.0.0: dependencies: xml-name-validator: 5.0.0 @@ -6515,15 +6590,15 @@ snapshots: whatwg-url@16.0.1(@noble/hashes@2.4.0): dependencies: - '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + '@exodus/bytes': 1.16.0(@noble/hashes@2.4.0) tr46: 6.0.0 webidl-conversions: 8.0.1 transitivePeerDependencies: - '@noble/hashes' - whatwg-url@17.1.0(@noble/hashes@2.4.0): + whatwg-url@17.1.2(@noble/hashes@2.4.0): dependencies: - '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + '@exodus/bytes': 1.16.0(@noble/hashes@2.4.0) tr46: 6.0.0 webidl-conversions: 8.0.1 transitivePeerDependencies: @@ -6543,12 +6618,6 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.2.0 - wrappy@1.0.2: {} xml-name-validator@5.0.0: {} @@ -6557,7 +6626,7 @@ snapshots: y18n@5.0.8: {} - yaml@2.9.0: {} + yaml@2.9.1: {} yargs-parser@21.1.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7cedc895..7a3fb3f6 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,17 +1,18 @@ +packages: + - '.' + allowBuilds: + '@parcel/watcher': true + '@swc/core': true + cpu-features: true esbuild: true - sharp: true - "@parcel/watcher": true - "@swc/core": true - msw: false - cpu-features: false - protobufjs: false - ssh2: false + msw: true + protobufjs: true + ssh2: true minimumReleaseAge: 60 overrides: - # drizzle-kit still uses an obsolete development-server dependency. - "@esbuild-kit/core-utils>esbuild": "^0.25.9" - "@types/react": "19.2.18" - "@types/react-dom": "19.2.7" + glob: '^11.0.0' + '@esbuild-kit/core-utils': 'npm:tsx@^4.23.15' + '@esbuild-kit/esm-loader': 'npm:tsx@^4.23.15' diff --git a/scripts/ci-deploy.sh b/scripts/ci-deploy.sh index 9bf6973b..f96a97be 100644 --- a/scripts/ci-deploy.sh +++ b/scripts/ci-deploy.sh @@ -21,6 +21,35 @@ cutover_started=0 candidate_attempted=0 backup_created=0 +# ── Blue/green ── +# De app draait met `--net=host`, dus elke replica neemt een eigen host-poort in +# plaats van een gedeelde docker-poort. Daardoor zijn er twee vaste slots en kan +# een release naast de live release opstarten. De nginx-upstream wijst pas naar +# de nieuwe release nadat die gezond is én de browsersmoke-test heeft gewonnen. +slot_a_port=3002 +slot_b_port=3003 +slot_a_container="epicnext-cms-app" +slot_b_container="epicnext-cms-green" +# Overridable zodat de simulatietests een pad kunnen opgeven dat niet bestaat en +# zo het in-place pad kunnen testen, en zodat een host met een andere +# nginx-indeling niet stilvalt op een release. +upstream_file="${CMS_UPSTREAM_FILE:-/etc/nginx/snippets/cms_upstream_servers.conf}" +nginx_site="${CMS_NGINX_SITE:-/etc/nginx/sites-enabled/cms.conf}" +active_port="" +old_port="" +new_port="" +old_container="" +new_container="" +blue_green=0 + +# Resource limits voor de container. Zonder deze limieten kan één geheugenlek de +# hele host vullen, met MariaDB, nginx en Traefik als slachtoffer. 2 CPU laat +# achtergrondwerk toe zonder de hele kernel aan één release te geven. +mem_limit="4g" +mem_swap_limit="5g" +cpu_limit="2" +pids_limit="512" + is_current() { local head head="$(git ls-remote --exit-code origin "refs/heads/$branch")" || return 2 @@ -38,18 +67,131 @@ check_current() { } healthy() { + local port="${1:-$slot_a_port}" local attempt for attempt in $(seq 1 30); do - if curl -sf --max-time 5 http://127.0.0.1:3002/api/health | grep -q '"database":true'; then return 0; fi + if curl -sf --max-time 5 "http://127.0.0.1:$port/api/health" | grep -q '"database":true'; then return 0; fi sleep 3 done return 1 } +# Staat er een blue/green-upstream? Zonder die bestanden blijft dit script op de +# oude, in-place cutover vallen, zodat een host met een andere nginx-indeling +# niet stilvalt op een upgrade. +detect_blue_green() { + [ -r "$upstream_file" ] || return 1 + grep -qs 'cms_app' "$nginx_site" || return 1 + return 0 +} + +# Op welke poort verwerkt nginx nu verkeer? Onbekend (of geen bestand) betekent +# slot A, zodat de allereerste release op 3002 terechtkomt. +read_active_port() { + local port="" + port="$(grep -oE '127\.0\.0\.1:[0-9]+' "$upstream_file" 2>/dev/null | head -1 | cut -d: -f2 || true)" + case "$port" in + "$slot_b_port") printf '%s' "$slot_b_port" ;; + *) printf '%s' "$slot_a_port" ;; + esac +} + +# Zet de nginx-upstream op de nieuwe poort en herlaadt graceful. +# +# De nieuwe inhoud wordt eerst echt weggeschreven en dán getest: `nginx -t` leest +# het include-bestand van schijf, dus alleen achteraf testen zou de oude, werkende +# configuratie blijven valideren. Faalt de test, dan gaat het origineel onmiddellijk +# terug en raakt de live release niets. +switch_upstream() { + local port="$1" + local backup="${upstream_file}.deploy.bak" + if ! cp "$upstream_file" "$backup" 2>/dev/null; then + echo "Cannot back up $upstream_file; refusing to cut over" >&2 + return 1 + fi + { + echo "# Geschreven door scripts/ci-deploy.sh op $(date -u +%FT%TZ) voor release $sha." + echo "# Niet met de hand bewerken: de volgende deploy overschrijft dit bestand." + echo "server 127.0.0.1:${port} max_fails=2 fail_timeout=10s;" + } >"$upstream_file" + if ! nginx -t >/dev/null 2>&1; then + echo "nginx rejected the new upstream; restoring the previous one" >&2 + mv "$backup" "$upstream_file" + return 1 + fi + if ! nginx -s reload; then + echo "nginx reload failed; restoring the previous upstream" >&2 + mv "$backup" "$upstream_file" + nginx -s reload || true + return 1 + fi + rm -f "$backup" + # Even de tijd voor de graceful reload om de nieuwe worker te laten starten. + sleep 1 + return 0 +} + +# Start de kandidaat op een eigen host-poort. +# +# De resource limits staan hier bewust bij de `docker run` en niet alleen in +# docker-compose.yml: een release wordt hier gestart en gebruikt compose helemaal +# niet, dus limieten die alleen in de compose stonden zouden in productie nooit +# gelden. +start_candidate() { + local port="$1" name="$2" + ( + set -a + # shellcheck disable=SC1091 + . "$deploy_dir/.env" + set +a + ENV_ARGS=() + while IFS='=' read -r key _; do + case "$key" in ''|'#'*|*[!A-Za-z0-9_]* ) continue ;; esac + ENV_ARGS+=(-e "$key") + done < "$deploy_dir/.env" + docker run -d --name "$name" --restart always --net=host \ + --memory="$mem_limit" --memory-swap="$mem_swap_limit" \ + --cpus="$cpu_limit" --pids-limit="$pids_limit" \ + "${ENV_ARGS[@]}" -e "PORT=$port" -e HOSTNAME=0.0.0.0 \ + -v "$deploy_dir/public/nitro-assets:/app/public/nitro-assets" \ + -v "$deploy_dir/public/swf:/app/public/swf" \ + -v "$deploy_dir/storage:/app/storage" \ + -v /var/www/Gamedata:/var/www/Gamedata \ + "$image" + ) +} + finish() { local status=$? trap - EXIT - if [ "$status" -ne 0 ] && [ "$cutover_started" -eq 1 ]; then + if [ "$status" -ne 0 ] && [ "$blue_green" -eq 1 ]; then + # Er zijn twee soorten falen, en het verschil bepaalt hoeveel werk terug moet. + if [ "$cutover_started" -eq 0 ]; then + # De live release draait nog ongestoord; alleen de kandidaat opruimen. + echo "Deployment failed before cutover; the live release was never stopped" >&2 + if [ "$candidate_attempted" -eq 1 ] && [ -n "$new_container" ]; then + docker logs "$new_container" --tail 50 >&2 || true + docker rm -f "$new_container" || true + fi + else + # nginx wijst nu naar de kandidaat. Eerst het verkeer terug, dan pas de + # kandidaat weghalen, anders zou de site 502-en terwijl we terugdraaien. + echo "Deployment failed after cutover; rolling back to port $old_port" >&2 + if [ -n "$new_container" ]; then docker logs "$new_container" --tail 50 >&2 || true; fi + if [ -n "$old_port" ]; then switch_upstream "$old_port" || true; fi + if [ -n "$new_container" ]; then docker rm -f "$new_container" || true; fi + if [ -n "$old_container" ] && docker start "$old_container" >/dev/null 2>&1; then + if healthy "$old_port"; then + echo "Rollback verified on port $old_port" + else + echo "ERROR: previous container did not return to a healthy state" >&2 + fi + else + echo "ERROR: no previous container to roll back to" >&2 + fi + fi + elif [ "$status" -ne 0 ] && [ "$cutover_started" -eq 1 ]; then + # In-place pad (geen blue/green-upstream): het oude scriptgedrag. echo "Deployment failed; restoring previous container" >&2 docker logs epicnext-cms-app --tail 50 >&2 || true if command -v ss >/dev/null 2>&1; then ss -ltnp 'sport = :3002' >&2 || true; fi @@ -133,31 +275,55 @@ check_current pnpm db:migrate check_current -# Prefer the active CI container, or the active legacy compose container. -for name in epicnext-cms epicnext-cms-app; do - if [ "$(docker inspect --format '{{.State.Running}}' "$name" 2>/dev/null || true)" = true ]; then - if [ -z "$previous_name" ]; then previous_name="$name"; else secondary_name="$name"; fi +# ── Blue/green: bepaal wie live is en waar de kandidaat mag starten ── +if detect_blue_green; then + blue_green=1 + active_port="$(read_active_port)" + if [ "$active_port" = "$slot_b_port" ]; then + old_port=$slot_b_port; new_port=$slot_a_port + old_container=$slot_b_container; new_container=$slot_a_container + else + old_port=$slot_a_port; new_port=$slot_b_port + old_container=$slot_a_container; new_container=$slot_b_container fi -done -if [ -z "$previous_name" ]; then - for name in epicnext-cms-app epicnext-cms; do - if docker inspect "$name" >/dev/null 2>&1; then previous_name="$name"; break; fi + echo "Live release keeps serving port $old_port; candidate starts on port $new_port" + # Rollback-evidence vastleggen voordat er iets wordt veranderd. + if docker inspect "$old_container" >/dev/null 2>&1; then + previous_name="$old_container" + previous_image="$(docker inspect --format '{{.Image}}' "$old_container")" + docker tag "$previous_image" epicnext-cms:previous + else + # Eerste release op een verse blue/green-opstelling: er is nog niets live. + previous_name="" + old_container="" + fi +else + blue_green=0 + # Prefer the active CI container, or the active legacy compose container. + for name in epicnext-cms epicnext-cms-app; do + if [ "$(docker inspect --format '{{.State.Running}}' "$name" 2>/dev/null || true)" = true ]; then + if [ -z "$previous_name" ]; then previous_name="$name"; else secondary_name="$name"; fi + fi done + if [ -z "$previous_name" ]; then + for name in epicnext-cms-app epicnext-cms; do + if docker inspect "$name" >/dev/null 2>&1; then previous_name="$name"; break; fi + done + fi + if [ -n "$previous_name" ]; then + previous_image="$(docker inspect --format '{{.Image}}' "$previous_name")" + docker tag "$previous_image" epicnext-cms:previous + fi + # Remove a stopped leftover CI container when the compose container is active. + if [ "$previous_name" != epicnext-cms-app ] && [ "$secondary_name" != epicnext-cms-app ] && docker inspect epicnext-cms-app >/dev/null 2>&1; then + docker rm epicnext-cms-app + fi fi if docker inspect "$backup_name" >/dev/null 2>&1; then echo "Unresolved rollback container exists; refusing to overwrite it" >&2 exit 1 fi -if [ -n "$previous_name" ]; then - previous_image="$(docker inspect --format '{{.Image}}' "$previous_name")" - docker tag "$previous_image" epicnext-cms:previous -fi -# Remove a stopped leftover CI container when the compose container is active. -if [ "$previous_name" != epicnext-cms-app ] && [ "$secondary_name" != epicnext-cms-app ] && docker inspect epicnext-cms-app >/dev/null 2>&1; then - docker rm epicnext-cms-app -fi -cutover_started=1 # The avatar/badge disk cache lives on the host bind and is written by uid 33 # inside the container. Root-owned directories make every cache write fail # silently, which turns each avatar into a fresh live render. @@ -167,48 +333,68 @@ for cache_dir in avatars badges; do fi done chown -R 33:33 "$deploy_dir/storage/imaging" 2>/dev/null || true -# Both legacy Compose and CI containers can exist after earlier failed updates. -# Preserve each before releasing the shared host port; never kill an arbitrary PID. -if [ -n "$secondary_name" ]; then - docker stop "$secondary_name" - docker rename "$secondary_name" "$secondary_backup" - secondary_backup_created=1 + +if [ "$blue_green" -eq 1 ]; then + # 1. Maak de doel-poort vrij. Alles wat daar draait is per definitie niet live, + # want nginx wijst nog naar old_port. Een restje van een mislukte eerdere + # deploy mag de nieuwe release niet blokkeren. + if docker inspect "$new_container" >/dev/null 2>&1; then + docker rm -f "$new_container" + fi + + # 2. Start de kandidaat ernaast. De live release draait ononderbroken door. + candidate_attempted=1 + start_candidate "$new_port" "$new_container" + + # 3. Gezond? Release-hash klopt? Browsersmoke-test? Pas dan hoeft het oude + # release het veld te ruimen — anders zou een mislukte e2e-test pas ná de + # cutover de productie breken in plaats van ervoor. + healthy "$new_port" + node scripts/verify-deployed-release.mjs "http://127.0.0.1:$new_port/api/health" "$sha" + PLAYWRIGHT_BASE_URL="http://127.0.0.1:$new_port" pnpm test:e2e + + # 4. Het enige onomkeerbare moment: vanaf hier wijst nginx naar de kandidaat. + cutover_started=1 + switch_upstream "$new_port" + echo "Cut over to port $new_port; retiring port $old_port" + + # 5. Nu mag de oude release weg. Pas ná de swap, zodat er nooit een moment is + # waarop er geen enkele container draait. + if [ -n "$old_container" ] && docker inspect "$old_container" >/dev/null 2>&1; then + docker stop "$old_container" + docker rename "$old_container" "$backup_name" + backup_created=1 + fi + verified_image="$(docker inspect --format '{{.Image}}' "$new_container")" +else + # In-place pad, alleen voor hosts zonder blue/green-upstream. + cutover_started=1 + # Both legacy Compose and CI containers can exist after earlier failed updates. + # Preserve each before releasing the shared host port; never kill an arbitrary PID. + if [ -n "$secondary_name" ]; then + docker stop "$secondary_name" + docker rename "$secondary_name" "$secondary_backup" + secondary_backup_created=1 + fi + if [ -n "$previous_name" ]; then + docker stop "$previous_name" + docker rename "$previous_name" "$backup_name" + backup_created=1 + fi + candidate_attempted=1 + start_candidate 3002 epicnext-cms-app + healthy 3002 + node scripts/verify-deployed-release.mjs http://127.0.0.1:3002/api/health "$sha" + PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 pnpm test:e2e + verified_image="$(docker inspect --format '{{.Image}}' epicnext-cms-app)" fi -if [ -n "$previous_name" ]; then - docker stop "$previous_name" - docker rename "$previous_name" "$backup_name" - backup_created=1 -fi -candidate_attempted=1 -( - set -a - # shellcheck disable=SC1091 - . "$deploy_dir/.env" - set +a - ENV_ARGS=() - while IFS='=' read -r key _; do - case "$key" in ''|'#'*|*[!A-Za-z0-9_]* ) continue ;; esac - ENV_ARGS+=(-e "$key") - done < "$deploy_dir/.env" - docker run -d --name epicnext-cms-app --restart always --net=host \ - "${ENV_ARGS[@]}" -e PORT=3002 -e HOSTNAME=0.0.0.0 \ - -v "$deploy_dir/public/nitro-assets:/app/public/nitro-assets" \ - -v "$deploy_dir/public/swf:/app/public/swf" \ - -v "$deploy_dir/storage:/app/storage" \ - -v /var/www/Gamedata:/var/www/Gamedata \ - "$image" -) -healthy -node scripts/verify-deployed-release.mjs http://127.0.0.1:3002/api/health "$sha" -PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 pnpm test:e2e -# Publish the latest alias only after HTTP and browser checks pass. -verified_image="$(docker inspect --format '{{.Image}}' epicnext-cms-app)" docker tag "$verified_image" "epicnext-cms:verified-$sha" docker tag "$verified_image" epicnext-cms:latest cutover_started=0 if [ "$backup_created" -eq 1 ]; then docker rm "$backup_name" || true; fi if [ "$secondary_backup_created" -eq 1 ]; then docker rm "$secondary_backup" || true; fi + echo "Deployment verified: $sha" # Retain the current and previous releases; do not remove arbitrary named tags. while IFS= read -r tag; do diff --git a/src/app/api/admin/import/audit/route.ts b/src/app/api/admin/import/audit/route.ts index 9ba04a6b..aceeecdb 100644 --- a/src/app/api/admin/import/audit/route.ts +++ b/src/app/api/admin/import/audit/route.ts @@ -79,6 +79,7 @@ export const POST = withAdmin( headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", + "X-Accel-Buffering": "no", Connection: "keep-alive", }, }); diff --git a/src/app/api/admin/import/furni/batch-regen/route.ts b/src/app/api/admin/import/furni/batch-regen/route.ts index c6c1b1e0..36c8c37b 100644 --- a/src/app/api/admin/import/furni/batch-regen/route.ts +++ b/src/app/api/admin/import/furni/batch-regen/route.ts @@ -343,6 +343,7 @@ export const POST = withAdmin( headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", + "X-Accel-Buffering": "no", Connection: "keep-alive", }, }); diff --git a/src/app/api/admin/import/furni/batch/route.ts b/src/app/api/admin/import/furni/batch/route.ts index 9a603fc6..5296d466 100644 --- a/src/app/api/admin/import/furni/batch/route.ts +++ b/src/app/api/admin/import/furni/batch/route.ts @@ -529,6 +529,7 @@ export const POST = withAdmin( headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", + "X-Accel-Buffering": "no", Connection: "keep-alive", }, }); diff --git a/src/app/api/admin/import/furni/repair-icons/route.ts b/src/app/api/admin/import/furni/repair-icons/route.ts index c12d65c3..0b3517df 100644 --- a/src/app/api/admin/import/furni/repair-icons/route.ts +++ b/src/app/api/admin/import/furni/repair-icons/route.ts @@ -40,6 +40,7 @@ export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async () => { headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", + "X-Accel-Buffering": "no", Connection: "keep-alive", }, }); diff --git a/src/app/api/admin/studio/nitro-cleanup/rebuild/route.ts b/src/app/api/admin/studio/nitro-cleanup/rebuild/route.ts index cde021fd..45242f09 100644 --- a/src/app/api/admin/studio/nitro-cleanup/rebuild/route.ts +++ b/src/app/api/admin/studio/nitro-cleanup/rebuild/route.ts @@ -124,6 +124,7 @@ export const POST = withAdmin( headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", + "X-Accel-Buffering": "no", Connection: "keep-alive", }, }); diff --git a/src/app/api/admin/studio/nitro-cleanup/route.ts b/src/app/api/admin/studio/nitro-cleanup/route.ts index cb72d6a5..7bd88d5f 100644 --- a/src/app/api/admin/studio/nitro-cleanup/route.ts +++ b/src/app/api/admin/studio/nitro-cleanup/route.ts @@ -125,6 +125,7 @@ export const GET = withAdmin( headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", + "X-Accel-Buffering": "no", Connection: "keep-alive", }, }); diff --git a/src/app/api/online/count/stream/route.ts b/src/app/api/online/count/stream/route.ts index eddd9ef4..0f931030 100644 --- a/src/app/api/online/count/stream/route.ts +++ b/src/app/api/online/count/stream/route.ts @@ -103,6 +103,7 @@ export async function GET(req: Request) { headers: { "content-type": "text/event-stream; charset=utf-8", "cache-control": "no-store, no-transform", + "x-accel-buffering": "no", connection: "keep-alive", }, }); diff --git a/src/app/api/radio/stream/route.ts b/src/app/api/radio/stream/route.ts index c7b40a56..e27f5d29 100644 --- a/src/app/api/radio/stream/route.ts +++ b/src/app/api/radio/stream/route.ts @@ -61,6 +61,7 @@ export async function GET(req: Request) { headers: { "content-type": "text/event-stream; charset=utf-8", "cache-control": "no-store, no-transform", + "x-accel-buffering": "no", connection: "keep-alive", }, }); diff --git a/src/lib/ci-deploy.test.ts b/src/lib/ci-deploy.test.ts index 0eb76b15..8aa1b582 100644 --- a/src/lib/ci-deploy.test.ts +++ b/src/lib/ci-deploy.test.ts @@ -50,6 +50,11 @@ function simulate( BASH_ENV: resolve(root, "src/test/ci-deploy-harness.sh"), TEST_DIR: dir.replaceAll("\\", "/"), CMS_DEPLOY_DIR: join(dir, "production").replaceAll("\\", "/"), + // Deze scenario's testen het in-place pad. Door een pad op te geven + // dat niet bestaat ziet het script geen blue/green-upstream, ook niet + // wanneer de test op de productiehost zelf draait. + CMS_UPSTREAM_FILE: join(dir, "no-such-upstream.conf"), + CMS_NGINX_SITE: join(dir, "no-such-nginx-site.conf"), TEST_SHA: sha, SCENARIO: scenario, DEPLOY_BRANCH: "main", @@ -191,3 +196,148 @@ describe("legacy and CI container coexistence", () => { expect(r.calls).toContain("docker start epicnext-cms"); }); }); + +// Blue/green: nginx wijst pas naar de nieuwe release nadat die gezond is én de +// e2e-test heeft gewonnen. De hele winst zit in de volgorde, dus daar asserten +// we dan ook op. +function simulateBlueGreen(scenario: string, livePort = 3002) { + const dir = mkdtempSync(join(tmpdir(), "cms-deploy-bg-")); + try { + mkdirSync(join(dir, "production")); + // Een werkende deploymap heeft een DATABASE_URL; die gebruikt + // scripts/ci-deploy.sh voor de migraties op de host. + writeFileSync( + join(dir, "production", ".env"), + 'HOTEL_NAME="Test Hotel"\nDATABASE_URL="mysql://test:test@127.0.0.1:3306/test"\n', + ); + // De live release draait op `livePort`; nginx wijst ernaar. + writeFileSync( + join(dir, "upstream.conf"), + `server 127.0.0.1:${livePort} max_fails=2 fail_timeout=10s;\n`, + ); + writeFileSync(join(dir, "nginx-site.conf"), "upstream cms_app { }\n"); + // Het live container-bestand, zodat `docker inspect` hem als draaiend ziet. + writeFileSync(join(dir, "epicnext-cms-app"), "old\n"); + const result = spawnSync(bash, [resolve(root, "scripts/ci-deploy.sh")], { + cwd: dir, + encoding: "utf8", + timeout: 25000, + env: { + ...process.env, + BASH_ENV: resolve(root, "src/test/ci-deploy-harness.sh"), + TEST_DIR: dir.replaceAll("\\", "/"), + CMS_DEPLOY_DIR: join(dir, "production").replaceAll("\\", "/"), + CMS_UPSTREAM_FILE: join(dir, "upstream.conf"), + CMS_NGINX_SITE: join(dir, "nginx-site.conf"), + TEST_SHA: sha, + SCENARIO: scenario, + DEPLOY_BRANCH: "main", + }, + }); + if (result.error) throw result.error; + return { + status: result.status, + output: result.stdout + result.stderr, + calls: existsSync(join(dir, "calls")) + ? readFileSync(join(dir, "calls"), "utf8") + : "", + upstream: existsSync(join(dir, "upstream.conf")) + ? readFileSync(join(dir, "upstream.conf"), "utf8") + : "", + green: existsSync(join(dir, "epicnext-cms-green")) + ? readFileSync(join(dir, "epicnext-cms-green"), "utf8").trim() + : null, + app: existsSync(join(dir, "epicnext-cms-app")) + ? readFileSync(join(dir, "epicnext-cms-app"), "utf8").trim() + : null, + }; + } finally { + rmSync(dir, { recursive: true, force: true }); + } +} + +describe("blue/green cutover", () => { + it("starts the candidate on the idle port and keeps the live one serving", () => { + const r = simulateBlueGreen("success"); + expect(r.status, r.output).toBe(0); + // De kandidaat draait naast de live release, niet ervoor. + expect(r.calls).toContain("docker run -d --name epicnext-cms-green"); + expect(r.calls).toContain("PORT=3003"); + expect(r.calls.indexOf("docker run")).toBeLessThan( + r.calls.indexOf("docker stop epicnext-cms-app"), + ); + // De release-hash en de e2e-test draaien tegen de kandidaat, vóór de swap. + expect(r.calls).toContain("http://127.0.0.1:3003/api/health"); + expect(r.calls).toContain("PLAYWRIGHT_BASE_URL=http://127.0.0.1:3003"); + expect(r.calls.indexOf("pnpm test:e2e")).toBeLessThan( + r.calls.indexOf("nginx -s reload"), + ); + }); + + it("switches nginx over before retiring the live container", () => { + const r = simulateBlueGreen("success"); + expect(r.status, r.output).toBe(0); + // nginx test vóór de reload, en de swap gaat vóór het stoppen: anders + // zou er een moment zijn waarop niets draait. + expect(r.calls).toContain("nginx -t"); + expect(r.calls.indexOf("nginx -t")).toBeLessThan( + r.calls.indexOf("nginx -s reload"), + ); + expect(r.calls.indexOf("nginx -s reload")).toBeLessThan( + r.calls.indexOf("docker stop epicnext-cms-app"), + ); + expect(r.upstream).toContain("127.0.0.1:3003"); + expect(r.upstream).not.toContain("127.0.0.1:3002"); + }); + + it("alternates slots on the next release", () => { + const r = simulateBlueGreen("success", 3003); + expect(r.status, r.output).toBe(0); + // Live op 3003 → de kandidaat gaat naar 3002. + expect(r.calls).toContain("docker run -d --name epicnext-cms-app"); + expect(r.upstream).toContain("127.0.0.1:3002"); + expect(r.upstream).not.toContain("127.0.0.1:3003"); + }); + + it.each([ + "run-failure", + "health-failure", + "smoke-failure", + "release-failure", + ])( + "never stops the live release when the candidate fails on %s", + (scenario) => { + const r = simulateBlueGreen(scenario); + expect(r.status, r.output).not.toBe(0); + // Dit is de hele belofte: een mislukte release kost tijd, geen downtime. + expect(r.calls).not.toContain("docker stop epicnext-cms-app"); + expect(r.calls).not.toContain("nginx -s reload"); + expect(r.upstream).toContain("127.0.0.1:3002"); + expect(r.green).toBeNull(); + expect(r.output).toContain("the live release was never stopped"); + }, + 30000, + ); + + it("leaves the live release alone when migrations fail", () => { + // Migraties draaien vóórdat de blue/green-detectie, dus er is op dat + // moment simpelweg nog niets om terug te draaien. + const r = simulateBlueGreen("migration-failure"); + expect(r.status, r.output).not.toBe(0); + expect(r.calls).not.toContain("docker stop"); + expect(r.calls).not.toContain("docker run"); + expect(r.calls).not.toContain("nginx -s reload"); + expect(r.upstream).toContain("127.0.0.1:3002"); + expect(r.app).toBe("old"); + }); + + it("keeps the live release serving when nginx rejects the new upstream", () => { + const r = simulateBlueGreen("nginx-reject"); + expect(r.status, r.output).not.toBe(0); + expect(r.calls).not.toContain("docker stop epicnext-cms-app"); + expect(r.calls).not.toContain("nginx -s reload"); + // De upstream is teruggezet op wat er stond. + expect(r.upstream).toContain("127.0.0.1:3002"); + expect(r.output).toContain("restoring the previous one"); + }); +}); diff --git a/src/lib/services/cache-warmup.ts b/src/lib/services/cache-warmup.ts index 12e467cb..4b64e6d3 100644 --- a/src/lib/services/cache-warmup.ts +++ b/src/lib/services/cache-warmup.ts @@ -43,8 +43,10 @@ async function warm(name: string, load: () => Promise): Promise { } export async function warmPublicCaches(): Promise { - // Small delays between groups: a boot-time burst of COUNT(*) queries against - // a database that is still opening connections helps nobody. + // Elke `warm` wordt afgewacht voordat de volgende begint, dus de COUNT(*) + // queries gaan één voor één in plaats van als een burst op een database die + // nog aan het opstarten is. Dat is goed genoeg; kunstmatige sleeps zouden + // de warme start alleen maar vertragen zonder iets te winnen. await warm("online_count", () => cached("online_count", ONLINE_TTL_MS, countOnline, { staleMs: 15_000 }), ); diff --git a/src/test/ci-deploy-harness.sh b/src/test/ci-deploy-harness.sh index bca38251..e7ccb682 100644 --- a/src/test/ci-deploy-harness.sh +++ b/src/test/ci-deploy-harness.sh @@ -11,13 +11,30 @@ git() { } flock() { echo "lock" >> "$TEST_DIR/calls"; [ "$SCENARIO" != lock-failure ]; } pnpm() { - echo "pnpm $*" >> "$TEST_DIR/calls" + # De env-prefix (bv. PLAYWRIGHT_BASE_URL) hoort bij het deploypad dat getest + # wordt, dus die loggen we mee: zo blijft zichtbaar dat de e2e-test tegen de + # juiste poort draait. + echo "${PLAYWRIGHT_BASE_URL:+PLAYWRIGHT_BASE_URL=$PLAYWRIGHT_BASE_URL }pnpm $*" >> "$TEST_DIR/calls" if [ "$1" = db:migrate ] && [ "$SCENARIO" = migration-failure ]; then return 1; fi - if [ "$1" = test:e2e ] && [ "$SCENARIO" = smoke-failure ] && [ "$(cat "$TEST_DIR/epicnext-cms-app" 2>/dev/null)" = new ]; then return 1; fi + if [ "$1" = test:e2e ] && [ "$SCENARIO" = smoke-failure ] && candidate_is_new; then return 1; fi + return 0 +} +# De kandidaat is het container dat het script zojuist heeft gestart. Bij +# blue/green is dat niet per se `epicnext-cms-app`. +candidate_is_new() { + for f in epicnext-cms-app epicnext-cms-green; do + if [ "$(cat "$TEST_DIR/$f" 2>/dev/null)" = new ]; then return 0; fi + done + return 1 +} +nginx() { + echo "nginx $*" >> "$TEST_DIR/calls" + if [ "$SCENARIO" = nginx-reject ] && [ "$1" = "-t" ]; then return 1; fi + if [ "$SCENARIO" = nginx-reload-fail ] && [ "$1" = "-s" ]; then return 1; fi return 0 } curl() { - if [ "$SCENARIO" = health-failure ] && [ "$(cat "$TEST_DIR/epicnext-cms-app" 2>/dev/null)" = new ]; then return 1; fi + if [ "$SCENARIO" = health-failure ] && candidate_is_new; then return 1; fi echo '{"database":true}' } sleep() { :; } @@ -40,14 +57,20 @@ docker() { stop) return 0 ;; rename) mv "$TEST_DIR/$2" "$TEST_DIR/$3" ;; run) - echo new > "$TEST_DIR/epicnext-cms-app" + run_name=epicnext-cms-app + prev="" + for arg in "$@"; do + if [ "$prev" = "--name" ]; then run_name="$arg"; fi + prev="$arg" + done + echo new > "$TEST_DIR/$run_name" [ "$SCENARIO" != run-failure ] ;; start) [ -f "$TEST_DIR/$2" ] ;; rm) rm -f "$TEST_DIR/$name" ;; *) return 0 ;; esac } -export -f git flock pnpm curl sleep docker +export -f git flock pnpm curl sleep docker nginx candidate_is_new node() { echo "node $*" >> "$TEST_DIR/calls"