diff --git a/.dockerignore b/.dockerignore index 265d8fd4..0e0ef78b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -34,8 +34,5 @@ public/cache public/tmp db_backup_*.sql *.log -playwright-report -test-results -blob-report .codex .agents diff --git a/.env.example b/.env.example index 6acc2981..331e866b 100644 --- a/.env.example +++ b/.env.example @@ -76,8 +76,8 @@ PAYPAL_API=https://api-m.sandbox.paypal.com # --- LOGGING --- LOG_LEVEL=error -# --- FLARESOLVERR (Cloudflare bypass for clone sources) --- -FLARESOLVERR_URL=http://localhost:8191 +# --- BYPARR (Cloudflare bypass for clone sources) --- +BYPARR_URL=http://localhost:8191 # Catalog Studio export: dedicated clean clone on Beta-3 with Git push credentials. CATALOG_GIT_CHECKOUT= diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index ac479521..1f56a937 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -53,14 +53,11 @@ jobs: BCRYPT_ROUNDS: 4 run: | if [ -x /usr/bin/time ]; then - /usr/bin/time -f 'Tests: %e seconds; peak process RSS: %M KiB' pnpm test --maxWorkers=2 + /usr/bin/time -f 'Tests: %e seconds; peak process RSS: %M KiB' pnpm test:coverage --maxWorkers=4 else - time pnpm test --maxWorkers=2 + time pnpm test:coverage --maxWorkers=4 fi - - name: Knip (unused files/exports) - run: pnpm knip - # ───────────────────────────────────────────── # Docker build & deploy # Draait op de host (self-hosted) zodat Docker diff --git a/.gitea/workflows/container.yaml b/.gitea/workflows/container.yaml index e35cbcf7..771d95e6 100644 --- a/.gitea/workflows/container.yaml +++ b/.gitea/workflows/container.yaml @@ -18,7 +18,7 @@ jobs: pnpm install --frozen-lockfile pnpm typecheck pnpm biome:lint - pnpm test + pnpm test:coverage env: SKIP_ENV_VALIDATION: 1 NODE_ENV: test diff --git a/.gitignore b/.gitignore index 6f60ed50..469d2d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -33,11 +33,6 @@ public/tmp/ # Test coverage reports coverage/ - -# Playwright test artifacts -test-results/ -playwright-report/ -blob-report/ .aider* /public/vendor/tinymce/ diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 5ee7abd8..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1 +0,0 @@ -pnpm exec lint-staged diff --git a/.husky/pre-push b/.husky/pre-push deleted file mode 100755 index 42267220..00000000 --- a/.husky/pre-push +++ /dev/null @@ -1,2 +0,0 @@ -pnpm typecheck -pnpm test diff --git a/Dockerfile b/Dockerfile index a573737e..dabed1c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,22 +4,37 @@ FROM node:26.8.1-alpine AS migrations WORKDIR /app ENV NEXT_TELEMETRY_DISABLED=1 # Keep the bootstrap aligned with package.json packageManager. -RUN apk add --no-cache git \ +# The apk cache is persisted in a BuildKit cache mount so git is not +# re-downloaded on every build. +RUN --mount=type=cache,target=/var/cache/apk \ + apk add --no-cache git \ && npm install -g pnpm@11.25.0 +# The pnpm store is kept in a BuildKit cache mount that persists across builds +# on the builder. This is what stops disk usage from growing unbounded: the +# downloaded dependency store is shared and reused instead of being copied into +# a fresh image layer on every build. Unlike an image layer it is also prunable +# independently, so a hard cap (see ci-deploy.sh) keeps it bounded. +ENV PNPM_HOME=/pnpm PNPM_STORE=/pnpm/store # pnpm-workspace.yaml + .npmrc must be present too: the lockfile records the # overrides from pnpm-workspace.yaml, and --frozen-lockfile rejects a build # where the workspace config is absent (ERR_PNPM_LOCKFILE_CONFIG_MISMATCH). COPY package.json pnpm-lock.yaml* pnpm-workspace.yaml* .npmrc* ./ -# pnpm fetch: download all deps into $PNPM_STORE first, so only the lockfile -# change (not source changes) invalidates the network-heavy download layer. -RUN pnpm fetch --ignore-scripts -RUN pnpm install --frozen-lockfile --ignore-scripts --offline +# pnpm fetch: download all deps into the shared cache-mounted store. +RUN --mount=type=cache,target=/pnpm \ + pnpm fetch --ignore-scripts +# Install offline from the cache-mounted store; the store itself stays in the +# build cache between builds. +RUN --mount=type=cache,target=/pnpm \ + pnpm install --frozen-lockfile --ignore-scripts --offline COPY . . FROM migrations AS builder ARG NEXT_DEPLOYMENT_ID="unknown" ENV NEXT_DEPLOYMENT_ID="$NEXT_DEPLOYMENT_ID" # Fixture values exist only for this build command; production secrets are runtime-only. -RUN DATABASE_URL="mysql://build:build@127.0.0.1:9/build" \ +# Cache Next.js build output and webpack caches so rebuilds only redo the +# changed parts. +RUN --mount=type=cache,target=/app/.next/cache \ + DATABASE_URL="mysql://build:build@127.0.0.1:9/build" \ HOTEL_NAME="Build fixture" APP_URL="http://localhost:3002" \ AUTH_SECRET="build-fixture-not-for-runtime-use-000000000000" \ pnpm run build @@ -32,7 +47,7 @@ ENV NODE_ENV=production \ NEXT_TELEMETRY_DISABLED=1 \ PORT=3002 \ HOSTNAME=0.0.0.0 -RUN apk add --no-cache tini \ +RUN apk add --no-cache tini curl \ && addgroup -g 33 -S nextjs && adduser -u 33 -S -G nextjs nextjs \ && mkdir -p /app/storage /app/public/nitro-assets /app/public/swf /var/www/Gamedata \ && chown -R 33:33 /app/storage /app/public /var/www/Gamedata diff --git a/README.md b/README.md index 7f987750..dc3a12f5 100644 --- a/README.md +++ b/README.md @@ -812,16 +812,16 @@ pnpm jobs:worker # or: npm run jobs:worker / yarn jobs:worker Optional OpenAI-powered moderation for comments and guestbook posts. Set `OPENAI_API_KEY`. -### FlareSolverr (Cloudflare Bypass) +### Byparr (Cloudflare Bypass) -Some clone sources are protected by Cloudflare. FlareSolverr solves these challenges automatically. +Some clone sources are protected by Cloudflare. Byparr (a FlareSolverr successor) solves these challenges automatically. ```bash -docker compose up -d flaresolverr +docker compose up -d byparr ``` ```dotenv -FLARESOLVERR_URL=http://localhost:8191 +BYPARR_URL=http://localhost:8191 ``` ### Furniture Import with Auto-Translation diff --git a/biome.json b/biome.json index 51fa8719..b90c07c8 100644 --- a/biome.json +++ b/biome.json @@ -7,7 +7,7 @@ }, "files": { "ignoreUnknown": false, - "includes": ["**", "!setup", "!*.cjs", "!coverage"] + "includes": ["**", "!setup", "!*.cjs", "!coverage", "!drizzle/drafts/meta"] }, "formatter": { "enabled": true, diff --git a/docker-compose.yml b/docker-compose.yml index 17f71ad4..f628f4e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,19 +58,18 @@ services: start_period: 40s mem_limit: 2g - # ── FlareSolverr (Cloudflare bypass for clone sources) ── + # ── Byparr (Cloudflare bypass for clone sources) ── # Solves Cloudflare/TLS-fingerprint blocks via a headless Chrome browser. - # The CMS calls this on http://localhost:8191 for sources that block Node's - # TLS fingerprint (e.g. Leet.city). Used by src/lib/services/flare-solver.ts. - flaresolverr: - image: ghcr.io/flaresolverr/flaresolverr:latest - container_name: flaresolverr + # Drop-in successor to FlareSolverr. The CMS calls this on + # http://localhost:8191 for sources that block Node's TLS fingerprint + # (e.g. Leet.city). Used by src/lib/services/byparr.ts. + byparr: + image: ghcr.io/thephaseless/byparr:latest + container_name: byparr network_mode: host restart: unless-stopped environment: - - LOG_LEVEL=info - - BROWSER_TIMEOUT=60000 - - BROWSER_WORKERS=1 + - LOG_LEVEL=INFO mem_limit: 2g healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8191/health"] diff --git a/docs/operations/cms-error-center.md b/docs/operations/cms-error-center.md index 71d086d2..6b3458aa 100644 --- a/docs/operations/cms-error-center.md +++ b/docs/operations/cms-error-center.md @@ -44,7 +44,7 @@ stack is diagnostic evidence, not an automatic root-cause determination. ## Dependencies `pnpm install --frozen-lockfile`, `pnpm deps:audit`, `pnpm typecheck`, `pnpm test`, -`pnpm knip`, `pnpm biome:lint`, and `pnpm build` are the verification sequence. +`pnpm biome:lint`, and `pnpm build` are the verification sequence. `pnpm analyze --output` writes a Next.js bundle analysis (not an application build). TinyMCE 8.9 is pinned in pnpm. `pnpm assets:editor` copies its runtime files and diff --git a/e2e/smoke.spec.ts b/e2e/smoke.spec.ts deleted file mode 100644 index 60b9f1a8..00000000 --- a/e2e/smoke.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { expect, test } from "@playwright/test"; - -test("health endpoint is reachable", async ({ request }) => { - const res = await request.get("/api/health"); - expect(res.ok()).toBeTruthy(); - const body = await res.json(); - expect(body).toHaveProperty("status"); -}); - -test("homepage renders", async ({ page }) => { - await page.goto("/"); - await expect(page).toHaveTitle(/.+/); -}); diff --git a/knip.json b/knip.json deleted file mode 100644 index 2b614c66..00000000 --- a/knip.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://unpkg.com/knip@6/schema.json", - "entry": [ - "src/app/**/page.{ts,tsx}", - "src/app/**/layout.{ts,tsx}", - "src/app/**/route.{ts,tsx}", - "src/app/**/{error,not-found,loading,template,default,global-error}.{ts,tsx}", - "scripts/migrate-aes-cbc-to-gcm.ts", - "scripts/build-languages-full.ts", - "scripts/translate-furnidata-full.ts", - "scripts/align-db-ids-with-furnidata.ts", - "scripts/furni-diagnose-now.ts" - ], - "project": ["src/**/*.{ts,tsx,css}", "scripts/**/*.{ts,js}"], - "ignoreDependencies": ["pino-pretty"], - "ignoreBinaries": ["sendmail"] -} diff --git a/package.json b/package.json index 5945e733..5515aea6 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,10 @@ "lint": "biome check .", "biome:lint": "biome check .", "format": "biome format --write .", - "knip": "knip --include files,dependencies,devDependencies,unlisted,binaries", "diag:permissions": "tsx scripts/diagnose-permission-page.ts", "jobs:worker": "node --conditions=react-server --import tsx scripts/jobs-worker.ts", - "test": "vitest run", - "test:e2e": "playwright test", + "test": "vitest run --coverage.enabled=false", + "test:coverage": "vitest run", "typecheck": "tsc --noEmit", "db:generate": "drizzle-kit generate", "db:introspect": "drizzle-kit introspect", @@ -32,17 +31,12 @@ "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", - "prepare": "node scripts/prepare-hooks.mjs", "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" }, - "lint-staged": { - "*.{js,ts,jsx,tsx,json}": "biome check --write --no-errors-on-unmatched", - "*.{ts,tsx}": "node scripts/check-admin-colors.mjs" - }, "dependencies": { "@base-ui/react": "1.8.0", "@dnd-kit/core": "6.3.1", @@ -86,7 +80,6 @@ "devDependencies": { "@babel/parser": "7.29.8", "@biomejs/biome": "2.5.12", - "@playwright/test": "^1.62.1", "@tailwindcss/forms": "0.5.11", "@tailwindcss/postcss": "4.3.3", "@tailwindcss/typography": "0.5.20", @@ -95,9 +88,6 @@ "@types/react-dom": "19.2.7", "@vitest/coverage-v8": "5.0.0", "drizzle-kit": "0.31.10", - "husky": "9.1.7", - "knip": "6.34.0", - "lint-staged": "17.4.1", "pino-pretty": "13.1.3", "postcss": "8.5.28", "tailwindcss": "4.3.3", diff --git a/playwright.config.ts b/playwright.config.ts deleted file mode 100644 index c14dd960..00000000 --- a/playwright.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineConfig, devices } from "@playwright/test"; - -const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? "http://127.0.0.1:3000"; - -export default defineConfig({ - testDir: "./e2e", - fullyParallel: true, - retries: process.env.CI ? 2 : 0, - reporter: process.env.CI ? "github" : "list", - use: { baseURL, trace: "on-first-retry" }, - webServer: process.env.PLAYWRIGHT_BASE_URL - ? undefined - : { - command: "pnpm dev --port 3000", - url: "http://127.0.0.1:3000/api/health", - reuseExistingServer: !process.env.CI, - timeout: 120_000, - }, - projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }], -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bed4d714..b16e52e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,7 +30,7 @@ importers: version: 3.5.17 '@hookform/resolvers': specifier: 5.9.1 - version: 5.9.1(@standard-schema/spec@1.1.0)(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4) + version: 5.9.1(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4) '@tanstack/react-virtual': specifier: 3.14.10 version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -54,7 +54,7 @@ importers: version: 4.12.0 ioredis: specifier: 6.0.0 - version: 6.0.0(supports-color@7.2.0) + version: 6.0.0 isomorphic-dompurify: specifier: ^4.1.0 version: 4.1.0(@noble/hashes@2.4.0) @@ -78,19 +78,19 @@ importers: version: 13.2.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) music-metadata: specifier: 11.15.0 - version: 11.15.0(supports-color@7.2.0) + version: 11.15.0 mysql2: specifier: 3.24.3 version: 3.24.3(@types/node@26.4.1) next: specifier: 16.3.4 - version: 16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) next-auth: specifier: 5.0.0-beta.32 - version: 5.0.0-beta.32(next@16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) + version: 5.0.0-beta.32(next@16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) next-intl: specifier: 4.14.2 - version: 4.14.2(@swc/helpers@0.5.23)(next@16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) + version: 4.14.2(@swc/helpers@0.5.23)(next@16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) otplib: specifier: 13.5.0 version: 13.5.0 @@ -134,9 +134,6 @@ importers: '@biomejs/biome': specifier: 2.5.12 version: 2.5.12 - '@playwright/test': - specifier: ^1.62.1 - version: 1.62.1 '@tailwindcss/forms': specifier: 0.5.11 version: 0.5.11(tailwindcss@4.3.3) @@ -161,15 +158,6 @@ importers: drizzle-kit: specifier: 0.31.10 version: 0.31.10 - husky: - specifier: 9.1.7 - version: 9.1.7 - knip: - specifier: 6.34.0 - version: 6.34.0 - lint-staged: - specifier: 17.4.1 - version: 17.4.1 pino-pretty: specifier: 13.1.3 version: 13.1.3 @@ -191,8 +179,8 @@ importers: packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + '@alloc/quick-lru@5.3.0': + resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} engines: {node: '>=10'} '@asamuzakjp/css-color@6.0.7': @@ -403,18 +391,9 @@ packages: '@eloqnt/format-po@0.1.0': resolution: {integrity: sha512-odgtuICWs67GdkNqY51/d2vaIukuOdlGalKASUGkI5c4cyWOmv/WIVyk5gZyn3xr614RzwWp57s9WB40lRLlBw==} - '@emnapi/core@1.11.2': - resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} - - '@emnapi/runtime@1.11.2': - resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} - '@emnapi/runtime@1.11.3': resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@emnapi/wasi-threads@1.2.2': - resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.hirok.io' @@ -1030,13 +1009,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@napi-rs/wasm-runtime@1.2.3': - resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} - engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} - peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 - '@next/env@16.3.4': resolution: {integrity: sha512-cjWZnUUa6jZq2kFaNe/ZyJdZonOZ/QoN0Zka2nz/FLOrfx14pQuM9c5RaSVkWMqgdt4ksgPAMWPyHSs/CyV48Q==} @@ -1114,236 +1086,8 @@ packages: '@otplib/uri@13.5.0': resolution: {integrity: sha512-LsL1hqTEgJHY40U2eb/Qp6OR1tKkNGwHQTrqqjIuJj0cawGWkLEmeUFK1MHzWBQ4bgy5IdeB5Et7gIDSAH/CRw==} - '@oxc-parser/binding-android-arm-eabi@0.147.0': - resolution: {integrity: sha512-fOtoGvIoirkvxQVw9J1WJPxz571XPgLsPf9uhRD+PJteUnvrJHMDmK9pw2yZEGGyismtRoEsp+JcXUdF/JDMDw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxc-parser/binding-android-arm64@0.147.0': - resolution: {integrity: sha512-emjQHOYJaomo4ykaXQ1EItunr/I94Nk01oqBmU4dSkKSTupIDx6OysVDf2e8Eytm77rb+4ZxzgElyWP7rcEX7A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@oxc-parser/binding-darwin-arm64@0.147.0': - resolution: {integrity: sha512-kXvBPJL7RmDPJ2mze/vXPPVQimCDtFr9OFLjf7dyhV5Dx64cgcXh9KKrA1sMWvCObvJll9CZZUO0FBlFwD0l6A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@oxc-parser/binding-darwin-x64@0.147.0': - resolution: {integrity: sha512-mgFF8pLU6R64LbT27lSrtVRspVC/3IcZ0qyIikzmi78Y3Ik2OPnlAHHI0UEBRcC3qmNgtjaef7zkFt7/uPxIcw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@oxc-parser/binding-freebsd-x64@0.147.0': - resolution: {integrity: sha512-v38aiF11qufOTBcCAKL4skgQf0zJ4NEvRlivq7B5kHrlyvjCLjvNrMtNWDTz1SDUL6/xVsJRmLDxv2e+Cp4oWw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@oxc-parser/binding-linux-arm-gnueabihf@0.147.0': - resolution: {integrity: sha512-AeIiBbwUaP0H1+4/qGW9l5qHecS/+XA5iMuieVcGb1T+tyc2dVGspFW13BWk/XrLsiGP/CiDJTJqAPLLCzZHkw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-parser/binding-linux-arm-musleabihf@0.147.0': - resolution: {integrity: sha512-/41MKPW4RgPY4DJco0NCF0RYX3IMZaVlRNMNzvhaxRavc7tN3Txm+qllZbh0aMRs0VHdgUlbI8TcAOiTai4TKg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-parser/binding-linux-arm64-gnu@0.147.0': - resolution: {integrity: sha512-bmpw/RPhVXgZbtb3xBDuwW5s8+LvZYdqcDSX/sP2ltL77aTio3DP/B5ZTwwgoJ6Mr9vJs4RrmgEKW9XkLNUU1g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-arm64-musl@0.147.0': - resolution: {integrity: sha512-gd7VX/FDVOw6mjQcu45iIcp4QkgybgJwh3a0OFG2NxmPCj628mQWD96QGu1kK8+mZF9qK4b/gIEyC63vQoB7+Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@oxc-parser/binding-linux-ppc64-gnu@0.147.0': - resolution: {integrity: sha512-HnAzcfki7dSUNHf510Q2NmbJlz8Ys7rn8l9l588Pkx0tYe1BHLZnmELIgqizJ4WPhHGSwN8Ce+B/menVxS3odA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-riscv64-gnu@0.147.0': - resolution: {integrity: sha512-qlkOL6wT44U+fT5s/+sR6Shx0OdwvQF83JyIPZUxG/ovqZF5/7atOtjH+JPZ5/7ATQLbFBBSmghcy/+2NVB/ew==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-riscv64-musl@0.147.0': - resolution: {integrity: sha512-DlefD7L7sMXs/3hIBH23Egk0phj8kG0SA81dVGOQ3S1ekjOlmTLH2E+F2Thwfh1slKx6aH+lNc5fQYAw0GU7/g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@oxc-parser/binding-linux-s390x-gnu@0.147.0': - resolution: {integrity: sha512-Xqpagk/031IvZ4svrk2FF01YEqM/iN3MJV3SVZadKg/CsGlDCGoREqKHXYnoV5+8SfGe/m6RM1szXFLusTu/Uw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-x64-gnu@0.147.0': - resolution: {integrity: sha512-QioQOeUbI4ATUr0S2z88uA3Cds2R3Mm5Ge7U8XNYtlTb2GJF3rWlcj70z0AJhhOlbdm0YgVjqPBldUNbFylDIg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-x64-musl@0.147.0': - resolution: {integrity: sha512-NXy1tv/OdC+pPTwf9RiCZWPK53V/Xq/2cjSnjOSyKopajdaDqMIkgtDY+jXZemp2e8px5FeWfY2L2LwhKZQovg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@oxc-parser/binding-openharmony-arm64@0.147.0': - resolution: {integrity: sha512-GpGWZ6oKz4bjCWW9Mz5pCaGPyk2Aaze6zEoaslIQqpSLtpx5pXj/ap5gUNb5Jn2LIbqWyjkGLX9yv3NMuNcBVQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxc-parser/binding-win32-arm64-msvc@0.147.0': - resolution: {integrity: sha512-a8mlt7CC8z7LUdCfaxhff4kCd+vSjE+NEFL0cxA8ukfuSnvAto/pWTjytW4BuVLnQGcCVdHJwcRKOfs++H+tjw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxc-parser/binding-win32-ia32-msvc@0.147.0': - resolution: {integrity: sha512-M5ViVDBcFLnl2632AuuWuP35zEL5oikK1jTx8r3+902VEDeSNHxFZAB6RZyfZ7MU6Oi5QTOG8MmMkIeHsudSaw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxc-parser/binding-win32-x64-msvc@0.147.0': - resolution: {integrity: sha512-DUaE13OwnUSlHpLZNcC/nuT10ivlWqc5EZgsfgXuAmWYw0r3nDxGeLD1zlGwYwIgVk1/ZMAxoXpV+05stvbHaA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@oxc-project/types@0.146.0': - resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==} - - '@oxc-project/types@0.147.0': - resolution: {integrity: sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==} - - '@oxc-resolver/binding-android-arm-eabi@11.24.2': - resolution: {integrity: sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==} - cpu: [arm] - os: [android] - - '@oxc-resolver/binding-android-arm64@11.24.2': - resolution: {integrity: sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg==} - cpu: [arm64] - os: [android] - - '@oxc-resolver/binding-darwin-arm64@11.24.2': - resolution: {integrity: sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w==} - cpu: [arm64] - os: [darwin] - - '@oxc-resolver/binding-darwin-x64@11.24.2': - resolution: {integrity: sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q==} - cpu: [x64] - os: [darwin] - - '@oxc-resolver/binding-freebsd-x64@11.24.2': - resolution: {integrity: sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw==} - cpu: [x64] - os: [freebsd] - - '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2': - resolution: {integrity: sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg==} - cpu: [arm] - os: [linux] - - '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2': - resolution: {integrity: sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA==} - cpu: [arm] - os: [linux] - - '@oxc-resolver/binding-linux-arm64-gnu@11.24.2': - resolution: {integrity: sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@oxc-resolver/binding-linux-arm64-musl@11.24.2': - resolution: {integrity: sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2': - resolution: {integrity: sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2': - resolution: {integrity: sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@oxc-resolver/binding-linux-riscv64-musl@11.24.2': - resolution: {integrity: sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@oxc-resolver/binding-linux-s390x-gnu@11.24.2': - resolution: {integrity: sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@oxc-resolver/binding-linux-x64-gnu@11.24.2': - resolution: {integrity: sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@oxc-resolver/binding-linux-x64-musl@11.24.2': - resolution: {integrity: sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@oxc-resolver/binding-openharmony-arm64@11.24.2': - resolution: {integrity: sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg==} - cpu: [arm64] - os: [openharmony] - - '@oxc-resolver/binding-wasm32-wasi@11.24.2': - resolution: {integrity: sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': - resolution: {integrity: sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg==} - cpu: [arm64] - os: [win32] - - '@oxc-resolver/binding-win32-x64-msvc@11.24.2': - resolution: {integrity: sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw==} - cpu: [x64] - os: [win32] + '@oxc-project/types@0.148.0': + resolution: {integrity: sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==} '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} @@ -1433,11 +1177,6 @@ packages: '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@playwright/test@1.62.1': - resolution: {integrity: sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==} - engines: {node: '>=20'} - hasBin: true - '@radix-ui/primitive@1.1.7': resolution: {integrity: sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==} @@ -1600,98 +1339,98 @@ packages: '@types/react': optional: true - '@rolldown/binding-android-arm-eabi@1.2.5': - resolution: {integrity: sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==} + '@rolldown/binding-android-arm-eabi@1.2.7': + resolution: {integrity: sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@rolldown/binding-android-arm64@1.2.5': - resolution: {integrity: sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==} + '@rolldown/binding-android-arm64@1.2.7': + resolution: {integrity: sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.2.5': - resolution: {integrity: sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==} + '@rolldown/binding-darwin-arm64@1.2.7': + resolution: {integrity: sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.2.5': - resolution: {integrity: sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==} + '@rolldown/binding-darwin-x64@1.2.7': + resolution: {integrity: sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.2.5': - resolution: {integrity: sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==} + '@rolldown/binding-freebsd-x64@1.2.7': + resolution: {integrity: sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.2.5': - resolution: {integrity: sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.7': + resolution: {integrity: sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.2.5': - resolution: {integrity: sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==} + '@rolldown/binding-linux-arm64-gnu@1.2.7': + resolution: {integrity: sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.2.5': - resolution: {integrity: sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==} + '@rolldown/binding-linux-arm64-musl@1.2.7': + resolution: {integrity: sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.2.5': - resolution: {integrity: sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==} + '@rolldown/binding-linux-ppc64-gnu@1.2.7': + resolution: {integrity: sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.2.5': - resolution: {integrity: sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==} + '@rolldown/binding-linux-s390x-gnu@1.2.7': + resolution: {integrity: sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.2.5': - resolution: {integrity: sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==} + '@rolldown/binding-linux-x64-gnu@1.2.7': + resolution: {integrity: sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.2.5': - resolution: {integrity: sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==} + '@rolldown/binding-linux-x64-musl@1.2.7': + resolution: {integrity: sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.2.5': - resolution: {integrity: sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==} + '@rolldown/binding-openharmony-arm64@1.2.7': + resolution: {integrity: sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-win32-arm64-msvc@1.2.5': - resolution: {integrity: sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==} + '@rolldown/binding-win32-arm64-msvc@1.2.7': + resolution: {integrity: sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.2.5': - resolution: {integrity: sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==} + '@rolldown/binding-win32-x64-msvc@1.2.7': + resolution: {integrity: sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1708,92 +1447,89 @@ packages: '@stablelib/base64@1.0.1': resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - '@swc/core-darwin-arm64@1.16.1': - resolution: {integrity: sha512-zlJblJ8ncErD43lKdxjbUaUskJQf+LxiPXYcWXD8/8ZMV+7uuAT+CwjciLXpyZBd5Pq/S726bMpeeAwSeL1hhg==} + '@swc/core-darwin-arm64@1.16.2': + resolution: {integrity: sha512-i/j0HNbnn79qnTVPicvay92Nark8fW8NQqn1e2mGERjUXNpBV0+SwQxlRpk2zBhn6laJ8PDI6Kn1nHZhnz3LCA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.16.1': - resolution: {integrity: sha512-IN0BmPWb0YAh/17mmlWB/HDBtTw2MfuW4hulf/tQAgTQBRH17l+z499bNJLK6LizSjqs0P7V+jU38Zj+vJC1DA==} + '@swc/core-darwin-x64@1.16.2': + resolution: {integrity: sha512-HrwqHyEyHVXO3qTk8EkNK7/b6sOZSEoNh+pot6RdE5x0LbNqfo8LtJUvi3UTXr+5ja/o5HbJdW80eCXo+NjbiA==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.16.1': - resolution: {integrity: sha512-EYgrx2YOCQ2Twz2S793kqNjPkpvYVUPzzR95bIb7by+VQcyaai4lZZ2iz/tZvcFVKSNcN3/JTKwx+aBn2ZL52A==} + '@swc/core-linux-arm-gnueabihf@1.16.2': + resolution: {integrity: sha512-MdXi83Z/gGp1LIrg+h7HKxiul/z/Bty/ZJSvYAFqDl9zteC1XLSAZdScquKtXPp50rdyXqritTDCqQBhwVfZKA==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.16.1': - resolution: {integrity: sha512-moyKm0YZlHdHohzm1YwgAyesqnE853rO0REMfJLFAova51wF9BNi+3ZW2PeS7Vqvn6HeJuepLpAHbBdZctxpHA==} + '@swc/core-linux-arm64-gnu@1.16.2': + resolution: {integrity: sha512-/jcTmK6Ktz3owM3YtiKvjofV6p3VpHnYzTIrOGwDIOsDigRAAVuZ8east33wYO/7UTdKYFlyHNnJNT0WJqOA3Q==} engines: {node: '>=10'} cpu: [arm64] os: [linux] libc: [glibc] - '@swc/core-linux-arm64-musl@1.16.1': - resolution: {integrity: sha512-kKGBO9wdapiSzuf5ZzZ2fYtlu1BNSYtIIUxvH1ir/gcelTOREEHGDCLTDFx/2Knf878nU11A40z7LxwasEFxqA==} + '@swc/core-linux-arm64-musl@1.16.2': + resolution: {integrity: sha512-4gFarKaFnlJTSlJYKmMhV4u+3YE4uYfiydpBoYjmgQhCf9lAieOq+WilZaK9vVSHeqLuQpTEiGULZqAdsRX5Dw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] libc: [musl] - '@swc/core-linux-ppc64-gnu@1.16.1': - resolution: {integrity: sha512-nZ6qahtLxC3PM54cWOQZHxt4lTCF/3J4LIoWWzz6v7A+rLs8Dx54anYQf7mH3eIi8KlNpgKci/ie8ZSqFN8O7A==} + '@swc/core-linux-ppc64-gnu@1.16.2': + resolution: {integrity: sha512-syqSLGd6KlZ1PciNzs6bIUlhOuFztZufebOHaERjc4N4SqNZxyqYd4I+jj/EfOYnpe0kNjccn9HJLN1p5dz3+w==} engines: {node: '>=10'} cpu: [ppc64] os: [linux] libc: [glibc] - '@swc/core-linux-s390x-gnu@1.16.1': - resolution: {integrity: sha512-4ji5PNzhYq193Z4/4xUaSoNJza6iCkDJSzhetrbB6KOYxsr+kxtQr8ePWhMJUiMt6JUWtXaZ1PYT8FhtED+nGA==} + '@swc/core-linux-s390x-gnu@1.16.2': + resolution: {integrity: sha512-ZBBLK+ewGyXLzWeMS7wbKtWBdnif6etn7xvPY/iOfbdsjX/+bgkp1pQt2lWF2wlu2hXYZuhJ/tHZE/QR8/apzg==} engines: {node: '>=10'} cpu: [s390x] os: [linux] libc: [glibc] - '@swc/core-linux-x64-gnu@1.16.1': - resolution: {integrity: sha512-VJQxqrisHV+B394IgrOu8YsIIXZgffnf5tO+yc9Z/hoUpuZEvuQTjWwlnpZdpyD+0nx6LTD1/3k646JYm43yJA==} + '@swc/core-linux-x64-gnu@1.16.2': + resolution: {integrity: sha512-LyHJgxCA4Tje0ysBMbEb0tt/ie8kgUKoFE3JAKFhpevmTmhYEoC0H9s47WuDsqiFckF1ITUguZIXJG6K5e0dvg==} engines: {node: '>=10'} cpu: [x64] os: [linux] libc: [glibc] - '@swc/core-linux-x64-musl@1.16.1': - resolution: {integrity: sha512-r9oV1mwxxsIGcLV1IQ/tw76MW3doatKze1QFWuC+a7QqJUkhY/bKTSVk6NpKKUGm2LDsE33Va8VqSClfA7vSiQ==} + '@swc/core-linux-x64-musl@1.16.2': + resolution: {integrity: sha512-PghXJlVM1cgtLfNUR1vxFo1z+PDRAe8cWAJlZZ7spmeiN7BospGXg/MHUg7oNSgwSX7Zo//YKv9P5yD9apsFJQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] libc: [musl] - '@swc/core-win32-arm64-msvc@1.16.1': - resolution: {integrity: sha512-6huNRessoBLxWEqBm5zJXyCQ27TO7anvkdiuQ5MDO4CJni0nOXEqKtV9RllQ2TdyENKKsUMXVnIfW2hIXx/R5Q==} + '@swc/core-win32-arm64-msvc@1.16.2': + resolution: {integrity: sha512-StTOSefYBxemvNYYUI3UmO1a8y+hSPjjfHogC2TEHL+Z1PlEBim/XtLas5rS04jAzT9RrNmbtX911SZ42H9jSQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.16.1': - resolution: {integrity: sha512-OVKJFUzphrGmsh+BGtcZDesx0YryV7/Yvy5XGgTqnrZfjnyfcr5uaqYQugCckdIlupc5Vs3XtDjRAj12z4ZPlw==} + '@swc/core-win32-ia32-msvc@1.16.2': + resolution: {integrity: sha512-fycER209DYIzsibpTMC+chND05OfOjgztWL9U8OE6/uUlsOUZH3eh98isBLEnOymYUhlJLEt5++W1+KL/FOh5Q==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.16.1': - resolution: {integrity: sha512-Bt+VIhWYCGk4urklnkkteLUOeLv1VxigwTCeB/xC6rBZxY6IIKdDwCJf6on3E3SUGsIqmQS6QqtuJQc1VxF4Aw==} + '@swc/core-win32-x64-msvc@1.16.2': + resolution: {integrity: sha512-cSd1z6ivSrJPVr+moVwOHWjeKy6TpO4/Shwcv5KCrKYXCccxwh4pRy1C3fDioNx2PF1jPZWHKZjtXt+Be9VbaQ==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.16.1': - resolution: {integrity: sha512-nUaeu91O5QZKrQdaDCHd402ogUIoNOOjpkZNq0UomWK0G6gDaGmLhvddF1/3BXf5O8aLyo6ZPY/aMDWvaJQ/hg==} + '@swc/core@1.16.2': + resolution: {integrity: sha512-95I4kiSMeveI/Mhi+tE4fiWcWLUMfzfKrk0jtr8LRMqHgOgq+xHS+zExkDqoO4b5OeeuXHMWVdD5MeP3X6sULw==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -1928,9 +1664,6 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@tybys/wasm-util@0.10.3': - resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} - '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -2113,8 +1846,8 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-v8-to-istanbul@1.0.5: - resolution: {integrity: sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==} + ast-v8-to-istanbul@1.0.6: + resolution: {integrity: sha512-fvpl29helSO2w/z7utIbrkNXILdrLwDwAMH2I/zPKlGf5244+gf+B4cyS1sANcrPY2h+hWCGSgC8N61s/+AF9A==} atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} @@ -2124,13 +1857,13 @@ packages: resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} engines: {node: '>= 6.0.0'} - baseline-browser-mapping@2.11.20: - resolution: {integrity: sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==} + baseline-browser-mapping@2.11.21: + resolution: {integrity: sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==} engines: {node: '>=6.0.0'} hasBin: true - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + bidi-js@1.1.0: + resolution: {integrity: sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==} buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2218,8 +1951,8 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - dompurify@3.4.14: - resolution: {integrity: sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==} + dompurify@3.4.15: + resolution: {integrity: sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==} drizzle-kit@0.31.10: resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} @@ -2348,8 +2081,8 @@ packages: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} - fast-copy@4.1.0: - resolution: {integrity: sha512-f5oNUvGAmBPLP85im9czQ7fVWh3RfcIIIzyXrcXKmCiWoDn+CRmfsoQN3jmE5J+UEquj4Ugc1woTaxD0oa37Gg==} + fast-copy@4.1.1: + resolution: {integrity: sha512-A4QTJmuiztpGtr6AMeJts9R4hbj2ZBUwtOaKrG6rw2y7t6+IaJKjz5M3XDs8BUznxDH43FVc6A0y/gWlMl4UtA==} fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} @@ -2357,9 +2090,6 @@ packages: fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} - fd-package-json@2.0.0: - resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2373,11 +2103,6 @@ packages: resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} engines: {node: '>=20'} - formatly@0.7.0: - resolution: {integrity: sha512-7CXJtIIA0zy/u12StsYk25qVKxvdLA2ep2sTNxK3ov0mGNIIDqIvAXDSgTnAfDJFsPfWjuz0WjfYSdpvnLA5Tg==} - engines: {node: '>=18.3.0'} - hasBin: true - framer-motion@13.2.0: resolution: {integrity: sha512-9E33ebgMaO33w1nN/jEdW8z3/GO483fMi4rqbMG9rt83XgW9QLKRe4NcmJ8s+fQ3O34++UHrIQwlIWGIWTITjA==} peerDependencies: @@ -2389,11 +2114,6 @@ packages: react-dom: optional: true - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2412,10 +2132,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - hash-wasm@4.12.0: resolution: {integrity: sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==} @@ -2426,11 +2142,6 @@ packages: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - husky@9.1.7: - resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} - engines: {node: '>=18'} - hasBin: true - iconv-lite@0.7.3: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} @@ -2479,8 +2190,8 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true - jose@6.2.10: - resolution: {integrity: sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==} + jose@6.2.12: + resolution: {integrity: sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==} joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} @@ -2507,11 +2218,6 @@ packages: jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - knip@6.34.0: - resolution: {integrity: sha512-bbHIrnGspYwe4EBPjjx+lvkUor0F2qfKQc5BPzPI4SOAImYA+k2ueVpIcF7d/W1LEVT7XoJUPt6zELeGZhXBgA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -2663,11 +2369,6 @@ packages: resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} - lint-staged@17.4.1: - resolution: {integrity: sha512-FmJeudcalbSfg1du+JCfvi5vS6Qt08KgbfLWiHinbef+2JJwUZwAWVoaO1AcJVUTWPfk0t30PMQNwPAeCzYQ+Q==} - engines: {node: '>=22.22.1'} - hasBin: true - long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} @@ -2675,8 +2376,8 @@ packages: resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} - lru.min@1.1.4: - resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + 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.41.0: @@ -2803,8 +2504,8 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - oauth4webapi@3.8.7: - resolution: {integrity: sha512-4RxcKxXjuItDFZ20RRPf4YTw3kpeXJyCgJFxVzJ068A7PNJ18st2Dg90tlC1LkSDS0GecroagCLHYEIVUhCAkw==} + oauth4webapi@3.8.8: + resolution: {integrity: sha512-8N28E+a/oxfXWBgOMt+ZP/JUf/XR+IFbvkAEPP3gznXOMv9BpAAwiIj0TFNz3tGTPc0ZQ8zmWBNgN1nAys0gng==} obug@2.1.4: resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} @@ -2820,16 +2521,6 @@ packages: otplib@13.5.0: resolution: {integrity: sha512-RpcC6aq4rANX6MverMuU3pqHVLgMPO7vl6qR8ga7YzoEHlPJknJ58cSVAaf3jBYnasiQVQHXXl2mj/4pYlsVEQ==} - oxc-parser@0.147.0: - resolution: {integrity: sha512-5xaug6t7GfV3BO5Iv+xHW1rmQkDEQ3BEu3L8g3InsvWO5i8CYGc4tCZ2X985QcwWNycFJam+aOns6Nr2XAThTA==} - engines: {node: ^20.19.0 || >=22.12.0} - - oxc-resolver@11.24.2: - resolution: {integrity: sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw==} - - package-manager-detector@1.8.0: - resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} - pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -2857,16 +2548,6 @@ packages: resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} hasBin: true - playwright-core@1.62.1: - resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==} - engines: {node: '>=20'} - hasBin: true - - playwright@1.62.1: - resolution: {integrity: sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==} - engines: {node: '>=20'} - hasBin: true - po-parser@2.2.0: resolution: {integrity: sha512-NdTrKgh0oO7+y+RFX8KKhOB438x/j94UGXEFzl/7pHH0JjWSn42iJ9tgmPksIO6n1JKDHmNDcejPJfKspljB9g==} @@ -2987,8 +2668,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - rolldown@1.2.5: - resolution: {integrity: sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==} + rolldown@1.2.7: + resolution: {integrity: sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3035,10 +2716,6 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - smol-toml@1.8.0: - resolution: {integrity: sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==} - engines: {node: '>= 18'} - sonic-boom@4.2.1: resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} @@ -3083,10 +2760,6 @@ packages: std-env@4.2.0: resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} - string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} - engines: {node: '>=0.6.19'} - string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -3111,10 +2784,6 @@ packages: babel-plugin-macros: optional: true - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -3151,11 +2820,11 @@ packages: resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} - tldts-core@7.4.11: - resolution: {integrity: sha512-CW3WN2rIIE/Of21mulhgnGOwoDyEFNygyIBOONSdyAuSATgMMUCpLeUlB+E8sAwA5xRV9hYPl+kyZ9citHCaKg==} + tldts-core@7.4.12: + resolution: {integrity: sha512-nYNzS2WRf4QJmjzFFgAxLOBjyBxAGRbCy9PVBPaglcYyYajh40VBn+v5Ngr96ZMc7oM0+aCJdtQnNejvdBnXMQ==} - tldts@7.4.11: - resolution: {integrity: sha512-aBiNayCfTQxuIJBm06M+xR14cYaYlDlSXZbgsnKzKNxDKUVq7KFwTjwBSsb7m9Y5xO8WfPnBc63WaYFMTGlvqw==} + tldts@7.4.12: + resolution: {integrity: sha512-WylhSDKVeYnWXL3a+vKTaOxjnOeEGw938hImY8zoRWJjRRK/Jp1K+IihBzIONpUmW4e3WmXT6q5FW6vlESVZCA==} hasBin: true token-types@6.1.2: @@ -3187,15 +2856,11 @@ packages: resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} engines: {node: '>=18'} - unbash@4.0.10: - resolution: {integrity: sha512-b7zoBQvpWp0vuN5q2vK2RRBR2SvuruQAs50DApdDveBSn3eSYd84IaHodFqQIMlvY9K2VnyBUEXgwOBuGU9GBg==} - engines: {node: '>=14'} - undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - undici@8.10.1: - resolution: {integrity: sha512-YQ3WlbqjYMmNpdvDH64jAgLjxuAR9+649calDWhbshYaeQGO2bR4nI94ORJmwI3J9YhoKQnpyGOK+0zlWS5N5Q==} + undici@8.10.2: + resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} engines: {node: '>=22.19.0'} use-callback-ref@1.3.3: @@ -3319,10 +2984,6 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} - walk-up-path@4.0.0: - resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} - engines: {node: 20 || >=22} - webidl-conversions@8.0.1: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} @@ -3367,7 +3028,7 @@ packages: snapshots: - '@alloc/quick-lru@5.2.0': {} + '@alloc/quick-lru@5.3.0': {} '@asamuzakjp/css-color@6.0.7': dependencies: @@ -3379,7 +3040,7 @@ snapshots: '@asamuzakjp/dom-selector@8.3.2': dependencies: - bidi-js: 1.0.3 + bidi-js: 1.1.0 css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 lru-cache: 11.5.2 @@ -3387,8 +3048,8 @@ snapshots: '@auth/core@0.41.3': dependencies: '@panva/hkdf': 1.2.1 - jose: 6.2.10 - oauth4webapi: 3.8.7 + jose: 6.2.12 + oauth4webapi: 3.8.8 preact: 10.24.3 preact-render-to-string: 6.5.11(preact@10.24.3) @@ -3535,27 +3196,11 @@ snapshots: '@eloqnt/config': 0.1.0 po-parser: 2.2.0 - '@emnapi/core@1.11.2': - dependencies: - '@emnapi/wasi-threads': 1.2.2 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.11.2': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.11.3': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.2': - dependencies: - tslib: 2.8.1 - optional: true - '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.25.12 @@ -3755,12 +3400,11 @@ snapshots: dependencies: '@formatjs/fast-memoize': 3.1.7 - '@hookform/resolvers@5.9.1(@standard-schema/spec@1.1.0)(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4)': + '@hookform/resolvers@5.9.1(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4)': dependencies: '@standard-schema/utils': 0.3.0 react-hook-form: 7.87.0(react@19.2.8) optionalDependencies: - '@standard-schema/spec': 1.1.0 zod: 4.5.4 '@img/colour@1.1.0': {} @@ -3890,13 +3534,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 - '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': - dependencies: - '@emnapi/core': 1.11.2 - '@emnapi/runtime': 1.11.2 - '@tybys/wasm-util': 0.10.3 - optional: true - '@next/env@16.3.4': {} '@next/swc-darwin-arm64@16.3.4': @@ -3952,127 +3589,7 @@ snapshots: dependencies: '@otplib/core': 13.5.0 - '@oxc-parser/binding-android-arm-eabi@0.147.0': - optional: true - - '@oxc-parser/binding-android-arm64@0.147.0': - optional: true - - '@oxc-parser/binding-darwin-arm64@0.147.0': - optional: true - - '@oxc-parser/binding-darwin-x64@0.147.0': - optional: true - - '@oxc-parser/binding-freebsd-x64@0.147.0': - optional: true - - '@oxc-parser/binding-linux-arm-gnueabihf@0.147.0': - optional: true - - '@oxc-parser/binding-linux-arm-musleabihf@0.147.0': - optional: true - - '@oxc-parser/binding-linux-arm64-gnu@0.147.0': - optional: true - - '@oxc-parser/binding-linux-arm64-musl@0.147.0': - optional: true - - '@oxc-parser/binding-linux-ppc64-gnu@0.147.0': - optional: true - - '@oxc-parser/binding-linux-riscv64-gnu@0.147.0': - optional: true - - '@oxc-parser/binding-linux-riscv64-musl@0.147.0': - optional: true - - '@oxc-parser/binding-linux-s390x-gnu@0.147.0': - optional: true - - '@oxc-parser/binding-linux-x64-gnu@0.147.0': - optional: true - - '@oxc-parser/binding-linux-x64-musl@0.147.0': - optional: true - - '@oxc-parser/binding-openharmony-arm64@0.147.0': - optional: true - - '@oxc-parser/binding-win32-arm64-msvc@0.147.0': - optional: true - - '@oxc-parser/binding-win32-ia32-msvc@0.147.0': - optional: true - - '@oxc-parser/binding-win32-x64-msvc@0.147.0': - optional: true - - '@oxc-project/types@0.146.0': {} - - '@oxc-project/types@0.147.0': {} - - '@oxc-resolver/binding-android-arm-eabi@11.24.2': - optional: true - - '@oxc-resolver/binding-android-arm64@11.24.2': - optional: true - - '@oxc-resolver/binding-darwin-arm64@11.24.2': - optional: true - - '@oxc-resolver/binding-darwin-x64@11.24.2': - optional: true - - '@oxc-resolver/binding-freebsd-x64@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-arm64-gnu@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-arm64-musl@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-riscv64-musl@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-s390x-gnu@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-x64-gnu@11.24.2': - optional: true - - '@oxc-resolver/binding-linux-x64-musl@11.24.2': - optional: true - - '@oxc-resolver/binding-openharmony-arm64@11.24.2': - optional: true - - '@oxc-resolver/binding-wasm32-wasi@11.24.2': - dependencies: - '@emnapi/core': 1.11.2 - '@emnapi/runtime': 1.11.2 - '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) - optional: true - - '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': - optional: true - - '@oxc-resolver/binding-win32-x64-msvc@11.24.2': - optional: true + '@oxc-project/types@0.148.0': {} '@panva/hkdf@1.2.1': {} @@ -4134,10 +3651,6 @@ snapshots: '@pinojs/redact@0.4.0': {} - '@playwright/test@1.62.1': - dependencies: - playwright: 1.62.1 - '@radix-ui/primitive@1.1.7': {} '@radix-ui/react-compose-refs@1.1.5(@types/react@19.2.18)(react@19.2.8)': @@ -4275,49 +3788,49 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@rolldown/binding-android-arm-eabi@1.2.5': + '@rolldown/binding-android-arm-eabi@1.2.7': optional: true - '@rolldown/binding-android-arm64@1.2.5': + '@rolldown/binding-android-arm64@1.2.7': optional: true - '@rolldown/binding-darwin-arm64@1.2.5': + '@rolldown/binding-darwin-arm64@1.2.7': optional: true - '@rolldown/binding-darwin-x64@1.2.5': + '@rolldown/binding-darwin-x64@1.2.7': optional: true - '@rolldown/binding-freebsd-x64@1.2.5': + '@rolldown/binding-freebsd-x64@1.2.7': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.2.5': + '@rolldown/binding-linux-arm-gnueabihf@1.2.7': optional: true - '@rolldown/binding-linux-arm64-gnu@1.2.5': + '@rolldown/binding-linux-arm64-gnu@1.2.7': optional: true - '@rolldown/binding-linux-arm64-musl@1.2.5': + '@rolldown/binding-linux-arm64-musl@1.2.7': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.2.5': + '@rolldown/binding-linux-ppc64-gnu@1.2.7': optional: true - '@rolldown/binding-linux-s390x-gnu@1.2.5': + '@rolldown/binding-linux-s390x-gnu@1.2.7': optional: true - '@rolldown/binding-linux-x64-gnu@1.2.5': + '@rolldown/binding-linux-x64-gnu@1.2.7': optional: true - '@rolldown/binding-linux-x64-musl@1.2.5': + '@rolldown/binding-linux-x64-musl@1.2.7': optional: true - '@rolldown/binding-openharmony-arm64@1.2.5': + '@rolldown/binding-openharmony-arm64@1.2.7': optional: true - '@rolldown/binding-win32-arm64-msvc@1.2.5': + '@rolldown/binding-win32-arm64-msvc@1.2.7': optional: true - '@rolldown/binding-win32-x64-msvc@1.2.5': + '@rolldown/binding-win32-x64-msvc@1.2.7': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -4328,64 +3841,61 @@ snapshots: '@stablelib/base64@1.0.1': {} - '@standard-schema/spec@1.1.0': - optional: true - '@standard-schema/utils@0.3.0': {} - '@swc/core-darwin-arm64@1.16.1': + '@swc/core-darwin-arm64@1.16.2': optional: true - '@swc/core-darwin-x64@1.16.1': + '@swc/core-darwin-x64@1.16.2': optional: true - '@swc/core-linux-arm-gnueabihf@1.16.1': + '@swc/core-linux-arm-gnueabihf@1.16.2': optional: true - '@swc/core-linux-arm64-gnu@1.16.1': + '@swc/core-linux-arm64-gnu@1.16.2': optional: true - '@swc/core-linux-arm64-musl@1.16.1': + '@swc/core-linux-arm64-musl@1.16.2': optional: true - '@swc/core-linux-ppc64-gnu@1.16.1': + '@swc/core-linux-ppc64-gnu@1.16.2': optional: true - '@swc/core-linux-s390x-gnu@1.16.1': + '@swc/core-linux-s390x-gnu@1.16.2': optional: true - '@swc/core-linux-x64-gnu@1.16.1': + '@swc/core-linux-x64-gnu@1.16.2': optional: true - '@swc/core-linux-x64-musl@1.16.1': + '@swc/core-linux-x64-musl@1.16.2': optional: true - '@swc/core-win32-arm64-msvc@1.16.1': + '@swc/core-win32-arm64-msvc@1.16.2': optional: true - '@swc/core-win32-ia32-msvc@1.16.1': + '@swc/core-win32-ia32-msvc@1.16.2': optional: true - '@swc/core-win32-x64-msvc@1.16.1': + '@swc/core-win32-x64-msvc@1.16.2': optional: true - '@swc/core@1.16.1(@swc/helpers@0.5.23)': + '@swc/core@1.16.2(@swc/helpers@0.5.23)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.28 optionalDependencies: - '@swc/core-darwin-arm64': 1.16.1 - '@swc/core-darwin-x64': 1.16.1 - '@swc/core-linux-arm-gnueabihf': 1.16.1 - '@swc/core-linux-arm64-gnu': 1.16.1 - '@swc/core-linux-arm64-musl': 1.16.1 - '@swc/core-linux-ppc64-gnu': 1.16.1 - '@swc/core-linux-s390x-gnu': 1.16.1 - '@swc/core-linux-x64-gnu': 1.16.1 - '@swc/core-linux-x64-musl': 1.16.1 - '@swc/core-win32-arm64-msvc': 1.16.1 - '@swc/core-win32-ia32-msvc': 1.16.1 - '@swc/core-win32-x64-msvc': 1.16.1 + '@swc/core-darwin-arm64': 1.16.2 + '@swc/core-darwin-x64': 1.16.2 + '@swc/core-linux-arm-gnueabihf': 1.16.2 + '@swc/core-linux-arm64-gnu': 1.16.2 + '@swc/core-linux-arm64-musl': 1.16.2 + '@swc/core-linux-ppc64-gnu': 1.16.2 + '@swc/core-linux-s390x-gnu': 1.16.2 + '@swc/core-linux-x64-gnu': 1.16.2 + '@swc/core-linux-x64-musl': 1.16.2 + '@swc/core-win32-arm64-msvc': 1.16.2 + '@swc/core-win32-ia32-msvc': 1.16.2 + '@swc/core-win32-x64-msvc': 1.16.2 '@swc/helpers': 0.5.23 '@swc/counter@0.1.3': {} @@ -4466,7 +3976,7 @@ snapshots: '@tailwindcss/postcss@4.3.3': dependencies: - '@alloc/quick-lru': 5.2.0 + '@alloc/quick-lru': 5.3.0 '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 postcss: 8.5.28 @@ -4485,20 +3995,15 @@ snapshots: '@tanstack/virtual-core@3.17.8': {} - '@tokenizer/inflate@0.4.1(supports-color@7.2.0)': + '@tokenizer/inflate@0.4.1': dependencies: - debug: 4.4.3(supports-color@7.2.0) + debug: 4.4.3 token-types: 6.1.2 transitivePeerDependencies: - supports-color '@tokenizer/token@0.3.0': {} - '@tybys/wasm-util@0.10.3': - dependencies: - tslib: 2.8.1 - optional: true - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -4588,7 +4093,7 @@ snapshots: '@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.5 + ast-v8-to-istanbul: 1.0.6 magicast: 0.5.4 obug: 2.1.4 std-env: 4.2.0 @@ -4618,7 +4123,7 @@ snapshots: assertion-error@2.0.1: {} - ast-v8-to-istanbul@1.0.5: + ast-v8-to-istanbul@1.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -4628,9 +4133,9 @@ snapshots: aws-ssl-profiles@1.1.2: {} - baseline-browser-mapping@2.11.20: {} + baseline-browser-mapping@2.11.21: {} - bidi-js@1.0.3: + bidi-js@1.1.0: dependencies: require-from-string: 2.0.2 @@ -4688,11 +4193,9 @@ snapshots: dateformat@4.6.3: {} - debug@4.4.3(supports-color@7.2.0): + debug@4.4.3: dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 7.2.0 decimal.js@10.6.0: {} @@ -4702,7 +4205,7 @@ snapshots: detect-node-es@1.1.0: {} - dompurify@3.4.14: + dompurify@3.4.15: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -4794,34 +4297,25 @@ snapshots: expect-type@1.4.0: {} - fast-copy@4.1.0: {} + fast-copy@4.1.1: {} fast-safe-stringify@2.1.1: {} fast-sha256@1.3.0: {} - fd-package-json@2.0.0: - dependencies: - walk-up-path: 4.0.0 - fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 - file-type@21.3.4(supports-color@7.2.0): + file-type@21.3.4: dependencies: - '@tokenizer/inflate': 0.4.1(supports-color@7.2.0) + '@tokenizer/inflate': 0.4.1 strtok3: 10.3.5 token-types: 6.1.2 uint8array-extras: 1.5.0 transitivePeerDependencies: - supports-color - formatly@0.7.0: - dependencies: - fd-package-json: 2.0.0 - package-manager-detector: 1.8.0 - framer-motion@13.2.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: motion-dom: 13.2.0 @@ -4831,9 +4325,6 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - fsevents@2.3.2: - optional: true - fsevents@2.3.3: optional: true @@ -4849,9 +4340,6 @@ snapshots: graceful-fs@4.2.11: {} - has-flag@4.0.0: - optional: true - hash-wasm@4.12.0: {} help-me@5.0.0: {} @@ -4862,8 +4350,6 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - husky@9.1.7: {} - iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 @@ -4883,11 +4369,11 @@ snapshots: '@formatjs/fast-memoize': 3.1.7 '@formatjs/icu-messageformat-parser': 3.5.17 - ioredis@6.0.0(supports-color@7.2.0): + ioredis@6.0.0: dependencies: '@ioredis/commands': 2.0.0 cluster-key-slot: 1.1.1 - debug: 4.4.3(supports-color@7.2.0) + debug: 4.4.3 denque: 2.1.0 redis-errors: 1.2.0 standard-as-callback: 2.1.0 @@ -4908,7 +4394,7 @@ snapshots: isomorphic-dompurify@4.1.0(@noble/hashes@2.4.0): dependencies: - dompurify: 3.4.14 + dompurify: 3.4.15 jsdom: 30.0.1(@noble/hashes@2.4.0) transitivePeerDependencies: - '@noble/hashes' @@ -4916,7 +4402,7 @@ snapshots: jiti@2.7.0: {} - jose@6.2.10: {} + jose@6.2.12: {} joycon@3.1.1: {} @@ -4941,7 +4427,7 @@ snapshots: saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 6.0.2 - undici: 8.10.1 + undici: 8.10.2 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 @@ -4959,22 +4445,6 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 - knip@6.34.0: - dependencies: - fdir: 6.5.0(picomatch@4.0.7) - formatly: 0.7.0 - get-tsconfig: 4.14.3 - jiti: 2.7.0 - oxc-parser: 0.147.0 - oxc-resolver: 11.24.2 - picomatch: 4.0.7 - smol-toml: 1.8.0 - strip-json-comments: 5.0.3 - tinyglobby: 0.2.17 - unbash: 4.0.10 - yaml: 2.9.0 - zod: 4.5.4 - lie@3.3.0: dependencies: immediate: 3.0.6 @@ -5077,19 +4547,11 @@ snapshots: lightningcss-win32-arm64-msvc: 1.33.0 lightningcss-win32-x64-msvc: 1.33.0 - lint-staged@17.4.1: - dependencies: - picomatch: 4.0.7 - string-argv: 0.3.2 - tinyexec: 1.3.0 - optionalDependencies: - yaml: 2.9.0 - long@5.3.2: {} lru-cache@11.5.2: {} - lru.min@1.1.4: {} + lru.min@1.1.5: {} lucide-react@1.41.0(react@19.2.8): dependencies: @@ -5135,13 +4597,13 @@ snapshots: ms@2.1.3: {} - music-metadata@11.15.0(supports-color@7.2.0): + music-metadata@11.15.0: dependencies: '@borewit/text-codec': 0.2.2 '@tokenizer/token': 0.3.0 content-type: 2.1.0 - debug: 4.4.3(supports-color@7.2.0) - file-type: 21.3.4(supports-color@7.2.0) + debug: 4.4.3 + file-type: 21.3.4 media-typer: 2.0.0 strtok3: 10.3.5 token-types: 6.1.2 @@ -5157,13 +4619,13 @@ snapshots: generate-function: 2.3.1 iconv-lite: 0.7.3 long: 5.3.2 - lru.min: 1.1.4 + lru.min: 1.1.5 named-placeholders: 1.1.6 sql-escaper: 1.5.1 named-placeholders@1.1.6: dependencies: - lru.min: 1.1.4 + lru.min: 1.1.5 nanoid@3.3.18: {} @@ -5171,36 +4633,36 @@ snapshots: dependencies: content-type: 2.1.0 - next-auth@5.0.0-beta.32(next@16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): + next-auth@5.0.0-beta.32(next@16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): dependencies: '@auth/core': 0.41.3 - next: 16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + next: 16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 next-intl-swc-plugin-extractor@4.14.2: {} - next-intl@4.14.2(@swc/helpers@0.5.23)(next@16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): + next-intl@4.14.2(@swc/helpers@0.5.23)(next@16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): dependencies: '@eloqnt/config': 0.1.0 '@eloqnt/format-json': 0.1.0 '@eloqnt/format-po': 0.1.0 '@formatjs/intl-localematcher': 0.8.13 '@parcel/watcher': 2.6.0 - '@swc/core': 1.16.1(@swc/helpers@0.5.23) + '@swc/core': 1.16.2(@swc/helpers@0.5.23) icu-minify: 4.14.2 negotiator: 1.1.0 - next: 16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + next: 16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) next-intl-swc-plugin-extractor: 4.14.2 react: 19.2.8 use-intl: 4.14.2(react@19.2.8) transitivePeerDependencies: - '@swc/helpers' - next@16.3.4(@playwright/test@1.62.1)(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + next@16.3.4(@types/node@26.4.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@next/env': 16.3.4 '@swc/helpers': 0.5.23 - baseline-browser-mapping: 2.11.20 + baseline-browser-mapping: 2.11.21 caniuse-lite: 1.0.30001810 postcss: 8.5.23 react: 19.2.8 @@ -5215,7 +4677,6 @@ snapshots: '@next/swc-linux-x64-musl': 16.3.4 '@next/swc-win32-arm64-msvc': 16.3.4 '@next/swc-win32-x64-msvc': 16.3.4 - '@playwright/test': 1.62.1 sharp: 0.35.4(@types/node@26.4.1) transitivePeerDependencies: - '@babel/core' @@ -5224,7 +4685,7 @@ snapshots: node-addon-api@7.1.1: {} - oauth4webapi@3.8.7: {} + oauth4webapi@3.8.8: {} obug@2.1.4: {} @@ -5243,54 +4704,6 @@ snapshots: '@otplib/totp': 13.5.0 '@otplib/uri': 13.5.0 - oxc-parser@0.147.0: - dependencies: - '@oxc-project/types': 0.147.0 - optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.147.0 - '@oxc-parser/binding-android-arm64': 0.147.0 - '@oxc-parser/binding-darwin-arm64': 0.147.0 - '@oxc-parser/binding-darwin-x64': 0.147.0 - '@oxc-parser/binding-freebsd-x64': 0.147.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.147.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.147.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.147.0 - '@oxc-parser/binding-linux-arm64-musl': 0.147.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.147.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.147.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.147.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.147.0 - '@oxc-parser/binding-linux-x64-gnu': 0.147.0 - '@oxc-parser/binding-linux-x64-musl': 0.147.0 - '@oxc-parser/binding-openharmony-arm64': 0.147.0 - '@oxc-parser/binding-win32-arm64-msvc': 0.147.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.147.0 - '@oxc-parser/binding-win32-x64-msvc': 0.147.0 - - oxc-resolver@11.24.2: - optionalDependencies: - '@oxc-resolver/binding-android-arm-eabi': 11.24.2 - '@oxc-resolver/binding-android-arm64': 11.24.2 - '@oxc-resolver/binding-darwin-arm64': 11.24.2 - '@oxc-resolver/binding-darwin-x64': 11.24.2 - '@oxc-resolver/binding-freebsd-x64': 11.24.2 - '@oxc-resolver/binding-linux-arm-gnueabihf': 11.24.2 - '@oxc-resolver/binding-linux-arm-musleabihf': 11.24.2 - '@oxc-resolver/binding-linux-arm64-gnu': 11.24.2 - '@oxc-resolver/binding-linux-arm64-musl': 11.24.2 - '@oxc-resolver/binding-linux-ppc64-gnu': 11.24.2 - '@oxc-resolver/binding-linux-riscv64-gnu': 11.24.2 - '@oxc-resolver/binding-linux-riscv64-musl': 11.24.2 - '@oxc-resolver/binding-linux-s390x-gnu': 11.24.2 - '@oxc-resolver/binding-linux-x64-gnu': 11.24.2 - '@oxc-resolver/binding-linux-x64-musl': 11.24.2 - '@oxc-resolver/binding-openharmony-arm64': 11.24.2 - '@oxc-resolver/binding-wasm32-wasi': 11.24.2 - '@oxc-resolver/binding-win32-arm64-msvc': 11.24.2 - '@oxc-resolver/binding-win32-x64-msvc': 11.24.2 - - package-manager-detector@1.8.0: {} - pako@1.0.11: {} parse5@8.0.1: @@ -5309,7 +4722,7 @@ snapshots: dependencies: colorette: 2.0.20 dateformat: 4.6.3 - fast-copy: 4.1.0 + fast-copy: 4.1.1 fast-safe-stringify: 2.1.1 help-me: 5.0.0 joycon: 3.1.1 @@ -5337,14 +4750,6 @@ snapshots: sonic-boom: 4.2.1 thread-stream: 4.2.0 - playwright-core@1.62.1: {} - - playwright@1.62.1: - dependencies: - playwright-core: 1.62.1 - optionalDependencies: - fsevents: 2.3.2 - po-parser@2.2.0: {} postal-mime@2.7.5: {} @@ -5450,26 +4855,26 @@ snapshots: resolve-pkg-maps@1.0.0: {} - rolldown@1.2.5: + rolldown@1.2.7: dependencies: - '@oxc-project/types': 0.146.0 + '@oxc-project/types': 0.148.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm-eabi': 1.2.5 - '@rolldown/binding-android-arm64': 1.2.5 - '@rolldown/binding-darwin-arm64': 1.2.5 - '@rolldown/binding-darwin-x64': 1.2.5 - '@rolldown/binding-freebsd-x64': 1.2.5 - '@rolldown/binding-linux-arm-gnueabihf': 1.2.5 - '@rolldown/binding-linux-arm64-gnu': 1.2.5 - '@rolldown/binding-linux-arm64-musl': 1.2.5 - '@rolldown/binding-linux-ppc64-gnu': 1.2.5 - '@rolldown/binding-linux-s390x-gnu': 1.2.5 - '@rolldown/binding-linux-x64-gnu': 1.2.5 - '@rolldown/binding-linux-x64-musl': 1.2.5 - '@rolldown/binding-openharmony-arm64': 1.2.5 - '@rolldown/binding-win32-arm64-msvc': 1.2.5 - '@rolldown/binding-win32-x64-msvc': 1.2.5 + '@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 safe-buffer@5.1.2: {} @@ -5526,8 +4931,6 @@ snapshots: siginfo@2.0.0: {} - smol-toml@1.8.0: {} - sonic-boom@4.2.1: dependencies: atomic-sleep: 1.0.0 @@ -5563,8 +4966,6 @@ snapshots: std-env@4.2.0: {} - string-argv@0.3.2: {} - string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -5580,11 +4981,6 @@ snapshots: client-only: 0.0.1 react: 19.2.8 - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - optional: true - symbol-tree@3.2.4: {} tailwind-merge@3.6.0: {} @@ -5610,11 +5006,11 @@ snapshots: tinyrainbow@3.1.1: {} - tldts-core@7.4.11: {} + tldts-core@7.4.12: {} - tldts@7.4.11: + tldts@7.4.12: dependencies: - tldts-core: 7.4.11 + tldts-core: 7.4.12 token-types@6.1.2: dependencies: @@ -5624,7 +5020,7 @@ snapshots: tough-cookie@6.0.2: dependencies: - tldts: 7.4.11 + tldts: 7.4.12 tr46@6.0.0: dependencies: @@ -5663,11 +5059,9 @@ snapshots: uint8array-extras@1.5.0: {} - unbash@4.0.10: {} - undici-types@8.3.0: {} - undici@8.10.1: {} + undici@8.10.2: {} use-callback-ref@1.3.3(@types/react@19.2.18)(react@19.2.8): dependencies: @@ -5703,7 +5097,7 @@ snapshots: lightningcss: 1.33.0 picomatch: 4.0.7 postcss: 8.5.28 - rolldown: 1.2.5 + rolldown: 1.2.7 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.4.1 @@ -5740,8 +5134,6 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - walk-up-path@4.0.0: {} - webidl-conversions@8.0.1: {} whatwg-mimetype@5.0.0: {} @@ -5775,6 +5167,7 @@ snapshots: xmlchars@2.2.0: {} - yaml@2.9.0: {} + yaml@2.9.0: + optional: true zod@4.5.4: {} diff --git a/scripts/ci-deploy.sh b/scripts/ci-deploy.sh index 01b2d5fe..c5b9753e 100644 --- a/scripts/ci-deploy.sh +++ b/scripts/ci-deploy.sh @@ -93,8 +93,6 @@ for managed_name in epicnext-cms epicnext-cms-app; do done cp "$deploy_dir/.env" .env pnpm install --frozen-lockfile -# Prepare browser before cutover so installation failures cannot interrupt the site. -pnpm exec playwright install chromium echo "Building $image" DOCKER_BUILDKIT=1 docker build --network=host --progress=plain --cache-from epicnext-cms:latest \ @@ -161,8 +159,7 @@ candidate_attempted=1 ) 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 health and browser checks pass. +# Publish the latest alias only after health and release checks pass. docker tag "$image" epicnext-cms:latest cutover_started=0 if [ "$backup_created" -eq 1 ]; then docker rm "$backup_name" || true; fi @@ -176,5 +173,5 @@ while IFS= read -r tag; do if [ -n "$tagged_image" ] && [ "$tagged_image" != "$previous_image" ]; then docker image rm "$tag" || true; fi fi done < <(docker image ls --format '{{.Repository}}:{{.Tag}}' epicnext-cms) -docker builder prune -af --filter "until=72h" --keep-storage=2g || true +docker builder prune -af --filter "until=72h" --max-used-space=4g || true docker image prune -f --filter "until=168h" || true diff --git a/scripts/health-check.sh b/scripts/health-check.sh index b8bcb2bc..5b3c4535 100755 --- a/scripts/health-check.sh +++ b/scripts/health-check.sh @@ -1,20 +1,20 @@ #!/usr/bin/env bash set -euo pipefail -URL="${FLARESOLVERR_URL:-http://localhost:8191}" -MAX_RETRIES="${FLARESOLVERR_MAX_RETRIES:-30}" -RETRY_INTERVAL="${FLARESOLVERR_RETRY_INTERVAL:-2}" +URL="${BYPARR_URL:-${FLARESOLVERR_URL:-http://localhost:8191}}" +MAX_RETRIES="${BYPARR_MAX_RETRIES:-30}" +RETRY_INTERVAL="${BYPARR_RETRY_INTERVAL:-2}" -echo "Waiting for FlareSolverr at ${URL}..." +echo "Waiting for Byparr at ${URL}..." for i in $(seq 1 "$MAX_RETRIES"); do if curl -sf "${URL}/health" >/dev/null 2>&1; then - echo "FlareSolverr is healthy." + echo "Byparr is healthy." exit 0 fi - echo "Attempt ${i}/${MAX_RETRIES} - FlareSolverr not ready, retrying in ${RETRY_INTERVAL}s..." + echo "Attempt ${i}/${MAX_RETRIES} - Byparr not ready, retrying in ${RETRY_INTERVAL}s..." sleep "$RETRY_INTERVAL" done -echo "ERROR: FlareSolverr did not become healthy after ${MAX_RETRIES} attempts." +echo "ERROR: Byparr did not become healthy after ${MAX_RETRIES} attempts." exit 1 \ No newline at end of file diff --git a/scripts/prepare-hooks.mjs b/scripts/prepare-hooks.mjs deleted file mode 100644 index 8a7856c5..00000000 --- a/scripts/prepare-hooks.mjs +++ /dev/null @@ -1,5 +0,0 @@ -// Production builds and CI do not need Git hooks or dev-only executables. -if (process.env.NODE_ENV !== "production" && !process.env.CI) { - const { default: husky } = await import("husky"); - husky(); -} diff --git a/src/components/admin/article-form.tsx b/src/components/admin/article-form.tsx index 949b977a..44b03645 100644 --- a/src/components/admin/article-form.tsx +++ b/src/components/admin/article-form.tsx @@ -14,7 +14,7 @@ export function ArticleForm({ action, defaultValues, }: { - action: (formData: FormData) => Promise; + action: (formData: FormData) => Promise; edit?: boolean; defaultValues?: { title?: string; diff --git a/src/lib/admin-search-permissions.test.ts b/src/lib/admin-search-permissions.test.ts index 4bd53700..52b16131 100644 --- a/src/lib/admin-search-permissions.test.ts +++ b/src/lib/admin-search-permissions.test.ts @@ -5,11 +5,13 @@ const state = vi.hoisted(() => ({ queried: [] as unknown[], })); vi.mock("@/lib/api-handler", () => ({ - withAdmin: (_: unknown, handler: Function) => (request: unknown) => - handler(request, { - session: { user: { id: 1, rank: 7 } }, - permissions: { isSuperAdmin: false }, - }), + withAdmin: + (_: unknown, handler: (...args: unknown[]) => unknown) => + (request: unknown) => + handler(request, { + session: { user: { id: 1, rank: 7 } }, + permissions: { isSuperAdmin: false }, + }), })); vi.mock("@/lib/rate-limit", () => ({ rateLimit: async () => ({ ok: true }) })); vi.mock("@/lib/permissions", async () => ({ diff --git a/src/lib/ci-deploy.test.ts b/src/lib/ci-deploy.test.ts index 60ee35f2..8339ea3e 100644 --- a/src/lib/ci-deploy.test.ts +++ b/src/lib/ci-deploy.test.ts @@ -77,7 +77,7 @@ describe("deployment transaction", () => { expect(result.calls.indexOf("pnpm db:migrate")).toBeLessThan( result.calls.indexOf("docker stop"), ); - expect(result.calls.indexOf("pnpm test:e2e")).toBeLessThan( + expect(result.calls.indexOf("verify-deployed-release.mjs")).toBeLessThan( result.calls.indexOf( `docker tag epicnext-cms:${sha} epicnext-cms:latest`, ), diff --git a/src/lib/ci-workflow-contract.test.ts b/src/lib/ci-workflow-contract.test.ts index 6d000c9f..bd6b6c40 100644 --- a/src/lib/ci-workflow-contract.test.ts +++ b/src/lib/ci-workflow-contract.test.ts @@ -25,7 +25,7 @@ describe("CI workflow", () => { it("check runs lint, typecheck, and test", () => { expect(workflow).toContain("pnpm biome:lint"); expect(workflow).toContain("pnpm typecheck"); - expect(workflow).toContain("pnpm test"); + expect(workflow).toContain("pnpm test:coverage"); }); it("check job runs on self-hosted runner", () => { @@ -61,7 +61,8 @@ describe("CI workflow", () => { it("smoke-tests the deployed app within the deployment transaction", () => { expect(workflow).toContain("bash scripts/ci-deploy.sh"); const deploy = readFileSync("scripts/ci-deploy.sh", "utf8"); - expect(deploy).toContain("pnpm test:e2e"); - expect(deploy).toContain("PLAYWRIGHT_BASE_URL"); + expect(deploy).toContain( + "node scripts/verify-deployed-release.mjs http://127.0.0.1:3002/api/health", + ); }); }); diff --git a/src/lib/deploy-workflow-contract.test.ts b/src/lib/deploy-workflow-contract.test.ts index 4de0cb74..838f2a17 100644 --- a/src/lib/deploy-workflow-contract.test.ts +++ b/src/lib/deploy-workflow-contract.test.ts @@ -4,11 +4,11 @@ import { expect, it } from "vitest"; const workflow = readFileSync(".gitea/workflows/ci.yaml", "utf8"); const deploy = readFileSync("scripts/ci-deploy.sh", "utf8"); it("uses two test workers and runs smoke checks in the deployment transaction", () => { - expect(workflow).toContain("pnpm test --maxWorkers=2"); + expect(workflow).toContain("pnpm test:coverage --maxWorkers=4"); expect(workflow).not.toContain("\n e2e:"); expect(workflow).toContain("bash scripts/ci-deploy.sh"); expect(deploy).toContain( - "PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 pnpm test:e2e", + "node scripts/verify-deployed-release.mjs http://127.0.0.1:3002/api/health", ); }); it("locks CI and scheduled deployments using the same production lock", () => { @@ -27,7 +27,7 @@ it("preserves production runtime configuration and recent cache", () => { expect(deploy).toContain("/app/storage"); expect(deploy).not.toContain("--env-file"); expect(deploy).toContain( - 'docker builder prune -af --filter "until=72h" --keep-storage=2g', + 'docker builder prune -af --filter "until=72h" --max-used-space=4g', ); expect(deploy).not.toContain("docker volume prune"); }); diff --git a/src/lib/error-monitor.ts b/src/lib/error-monitor.ts index 6a4dc7c2..e35f2da4 100644 --- a/src/lib/error-monitor.ts +++ b/src/lib/error-monitor.ts @@ -115,12 +115,12 @@ export class ErrorStore { name.slice(0, 10) < cutoff ) await unlink(path.join(this.directory, name)).catch(() => {}); - const file = path.join(this.directory, record.at.slice(0, 10) + ".jsonl"); + const file = path.join(this.directory, `${record.at.slice(0, 10)}.jsonl`); const size = await stat(file) .then((s) => s.size) .catch(() => 0); if (size >= DAY_LIMIT) throw new Error("Daily error storage limit reached"); - await appendFile(file, JSON.stringify(record) + "\n", { mode: 0o600 }); + await appendFile(file, `${JSON.stringify(record)}\n`, { mode: 0o600 }); } async resolve(fingerprint: string) { if (!/^[a-f0-9]{16}$/.test(fingerprint)) diff --git a/src/lib/services/byparr.ts b/src/lib/services/byparr.ts new file mode 100644 index 00000000..660c1910 --- /dev/null +++ b/src/lib/services/byparr.ts @@ -0,0 +1,90 @@ +const BYPARR_URL = + process.env.BYPARR_URL ?? + process.env.FLARESOLVERR_URL ?? // legacy env fallback + "http://localhost:8191"; + +const BYPARR_API = `${BYPARR_URL}/v1`; + +type ByparrCookie = { + name: string; + value: string; + domain?: string; + path?: string; +}; + +type ByparrSolution = { + response: string; + status: number; + cookies: ByparrCookie[]; +}; + +type ByparrResult = { + status?: "ok" | "error"; + message?: string; + solution?: ByparrSolution; + error?: string; +}; + +async function byparrRequest( + url: string, + timeout = 30000, +): Promise { + const res = await fetch(BYPARR_API, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + cmd: "request.get", + url, + maxTimeout: timeout, + }), + signal: AbortSignal.timeout(timeout + 5000), + }); + + if (!res.ok) { + throw new Error(`Byparr request failed: ${res.status} ${res.statusText}`); + } + + const data = (await res.json()) as ByparrResult; + + if (data.error) { + throw new Error(`Byparr error: ${data.error}`); + } + + // Byparr returns HTTP 200 with `status: "error"` for invalid requests + // (FlareSolverr used a top-level `error` field instead). + if (data.status && data.status !== "ok") { + throw new Error(`Byparr error: ${data.message ?? "request failed"}`); + } + + if (!data.solution) { + throw new Error("Byparr: no solution in response"); + } + + return data.solution; +} + +export async function fetchWithByparr( + url: string, + timeout = 30000, +): Promise { + const solution = await byparrRequest(url, timeout); + return solution.response; +} + +/** + * Solve a Cloudflare challenge for the given URL and return the clearance + * cookies as a `-b "name=value; ..."` argument string suitable for curl. + * Returns null if Byparr is unavailable or no cookies were set. + */ +export async function getByparrCookies( + url: string, + timeout = 30000, +): Promise { + try { + const solution = await byparrRequest(url, timeout); + if (!solution.cookies?.length) return null; + return solution.cookies.map((c) => `${c.name}=${c.value}`).join("; "); + } catch { + return null; + } +} diff --git a/src/lib/services/clone-import.test.ts b/src/lib/services/clone-import.test.ts index b059e177..a2f52623 100644 --- a/src/lib/services/clone-import.test.ts +++ b/src/lib/services/clone-import.test.ts @@ -12,7 +12,7 @@ const { selectLimit, fsUnlink, fsReadFile, - fetchWithFlareSolver, + fetchWithByparr, curlFetchText, curlDownload, } = vi.hoisted(() => ({ @@ -23,7 +23,7 @@ const { selectLimit: vi.fn(async () => []), fsUnlink: vi.fn(async () => {}), fsReadFile: vi.fn(async () => Buffer.from("NITRO")), - fetchWithFlareSolver: vi.fn(async () => ""), + fetchWithByparr: vi.fn(async () => ""), curlFetchText: vi.fn(async () => ""), curlDownload: vi.fn(async () => ({ ok: true, size: 200 })), })); @@ -33,7 +33,7 @@ vi.mock("@/lib/services/import/core/curl-fetch", () => ({ curlDownload, curlFetchText, })); -vi.mock("@/lib/services/flare-solver", () => ({ fetchWithFlareSolver })); +vi.mock("@/lib/services/byparr", () => ({ fetchWithByparr })); vi.mock("@/lib/services/furni-data", () => ({ appendFurniEntry })); vi.mock("@/lib/services/furni-import", () => ({ ensureDirectories: vi.fn(async () => {}), @@ -217,8 +217,8 @@ describe("fetchSourceFurnidata", () => { const HTML_WRAPPED = `
${JSON_BODY}
`; beforeEach(() => { - fetchWithFlareSolver.mockReset(); - fetchWithFlareSolver.mockResolvedValue(""); + fetchWithByparr.mockReset(); + fetchWithByparr.mockResolvedValue(""); vi.unstubAllGlobals(); }); @@ -235,10 +235,10 @@ describe("fetchSourceFurnidata", () => { ); const list = await fetchSourceFurnidata("https://a.test/fd.json", 1); expect(list.map((e) => e.classname)).toEqual(["bc_sofa", "wall_x"]); - expect(fetchWithFlareSolver).not.toHaveBeenCalled(); + expect(fetchWithByparr).not.toHaveBeenCalled(); }); - it("extracts JSON from an HTML-wrapped furnidata (e.g. Leet via FlareSolverr)", async () => { + it("extracts JSON from an HTML-wrapped furnidata (e.g. Leet via Byparr)", async () => { vi.stubGlobal( "fetch", vi.fn( @@ -249,13 +249,13 @@ describe("fetchSourceFurnidata", () => { }), ), ); - fetchWithFlareSolver.mockResolvedValue(HTML_WRAPPED); + fetchWithByparr.mockResolvedValue(HTML_WRAPPED); const list = await fetchSourceFurnidata("https://b.test/fd.json", 1); expect(list.map((e) => e.classname)).toEqual(["bc_sofa", "wall_x"]); - expect(fetchWithFlareSolver).toHaveBeenCalledWith("https://b.test/fd.json"); + expect(fetchWithByparr).toHaveBeenCalledWith("https://b.test/fd.json"); }); - it("falls back to FlareSolverr on HTML body even when status is 200", async () => { + it("falls back to Byparr on HTML body even when status is 200", async () => { vi.stubGlobal( "fetch", vi.fn( @@ -266,7 +266,7 @@ describe("fetchSourceFurnidata", () => { }), ), ); - fetchWithFlareSolver.mockResolvedValue(HTML_WRAPPED); + fetchWithByparr.mockResolvedValue(HTML_WRAPPED); const list = await fetchSourceFurnidata("https://c.test/fd.json", 1); expect(list.map((e) => e.classname)).toEqual(["bc_sofa", "wall_x"]); }); @@ -284,7 +284,7 @@ describe("fetchSourceFurnidata", () => { ); const list = await fetchSourceFurnidata("https://g.test/fd.json", 1); expect(list.map((e) => e.classname)).toEqual(["bc_sofa", "wall_x"]); - expect(fetchWithFlareSolver).not.toHaveBeenCalled(); + expect(fetchWithByparr).not.toHaveBeenCalled(); }); it("throws when HTML has no embedded JSON payload", async () => { @@ -298,7 +298,7 @@ describe("fetchSourceFurnidata", () => { }), ), ); - fetchWithFlareSolver.mockResolvedValue("still a challenge"); + fetchWithByparr.mockResolvedValue("still a challenge"); await expect( fetchSourceFurnidata("https://d.test/fd.json", 1), ).rejects.toThrow(/Cloudflare challenge/); diff --git a/src/lib/services/clone-import.ts b/src/lib/services/clone-import.ts index a133fae3..4f8ba421 100644 --- a/src/lib/services/clone-import.ts +++ b/src/lib/services/clone-import.ts @@ -5,9 +5,9 @@ import { autoDetectInteraction } from "@/lib/furni/auto-interaction"; import { normalizeClassname } from "@/lib/furni/classname"; import { HABBO_GAMEDATA_HOTEL_SETTING_KEY } from "@/lib/habbo-gamedata-hotel"; import { logger } from "@/lib/logger"; +import { fetchWithByparr } from "@/lib/services/byparr"; import { extractFurniIconPng } from "@/lib/services/clone-icon"; import type { CloneSource } from "@/lib/services/clone-sources"; -import { fetchWithFlareSolver } from "@/lib/services/flare-solver"; import { getFurniAssetDirs } from "@/lib/services/furni-asset-dirs"; import { appendFurniEntry } from "@/lib/services/furni-data"; import { @@ -101,7 +101,7 @@ const TTL = 5 * 60 * 1000; /** * Some sources serve their furnidata wrapped in an HTML document (e.g. Leet's * JSON is embedded in a `
` block inside the page, often surfaced by the
- * FlareSolverr fallback). Extract the JSON payload before giving up.
+ * Byparr fallback). Extract the JSON payload before giving up.
  */
 function extractJsonFromHtml(body: string): string | null {
 	const pre = body.match(/]*>([\s\S]*?)<\/pre>/);
@@ -117,20 +117,20 @@ function extractJsonFromHtml(body: string): string | null {
 }
 
 /**
- * Fetch a source's furnidata via FlareSolverr, falling back to a curl
+ * Fetch a source's furnidata via Byparr, falling back to a curl
  * subprocess. Some CDNs (e.g. Leet.city) block Node's TLS fingerprint while
  * the same request succeeds from curl — so curl is a useful second fallback
- * when FlareSolverr is unavailable.
+ * when Byparr is unavailable.
  */
 async function fetchWithFallback(url: string): Promise {
 	try {
-		return await fetchWithFlareSolver(url);
+		return await fetchWithByparr(url);
 	} catch {
 		try {
 			return await curlFetchText(url);
 		} catch (err) {
 			throw new Error(
-				`FlareSolverr + curl fallback failed for ${url}: ${(err as Error).message}`,
+				`Byparr + curl fallback failed for ${url}: ${(err as Error).message}`,
 			);
 		}
 	}
@@ -150,8 +150,8 @@ export async function fetchSourceFurnidata(
 		});
 		if (res.ok) {
 			// Some sources (e.g. GitHub raw) serve JSON with a text/plain
-			// content-type — only route to FlareSolverr when the body is
-			// actually HTML, otherwise parse the JSON directly.
+			// content-type — only route to Byparr when the body is actually
+			// HTML, otherwise parse the JSON directly.
 			const text = await res.text();
 			if (
 				text.trimStart().startsWith("{") ||
@@ -171,7 +171,7 @@ export async function fetchSourceFurnidata(
 		const extracted = extractJsonFromHtml(body);
 		if (!extracted) {
 			throw new Error(
-				`Source ${url} is behind a Cloudflare challenge that could not be bypassed. Start FlareSolverr and check its logs.`,
+				`Source ${url} is behind a Cloudflare challenge that could not be bypassed. Start Byparr and check its logs.`,
 			);
 		}
 		body = extracted;
diff --git a/src/lib/services/clone-sources.ts b/src/lib/services/clone-sources.ts
index db8d41f2..551382e2 100644
--- a/src/lib/services/clone-sources.ts
+++ b/src/lib/services/clone-sources.ts
@@ -142,12 +142,20 @@ export const DEFAULT_SOURCES: CloneSource[] = [
 	{
 		id: "default-virtualcity",
 		name: "VirtualCity",
-		furnidataUrl: "https://virtualc.nl/gamedata/furnidata_json/1",
+		furnidataUrl: "https://virtualc.nl/gamedata/FurnitureData.json",
 		nitroBaseUrl: "https://virtualc.nl/nitro/bundled/furniture",
 		iconBaseUrl: "https://virtualc.nl/nitro/icons",
 		hotel: "com",
 		sourceSwfBaseUrl: "https://virtualc.nl/dcr",
 	},
+	{
+		id: "default-sodastudios",
+		name: "SodaStudios",
+		furnidataUrl: "https://assets.sodaho.tel/gamedata/FurnitureData.json",
+		nitroBaseUrl: "https://assets.sodaho.tel/bundled/furniture",
+		iconBaseUrl: "https://assets.sodaho.tel/dcr/hof_furni/icons",
+		hotel: "com",
+	},
 	{
 		id: "default-habboon",
 		name: "Habboon",
diff --git a/src/lib/services/flare-solver.ts b/src/lib/services/flare-solver.ts
deleted file mode 100644
index 7f011879..00000000
--- a/src/lib/services/flare-solver.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-const FLARESOLVERR_URL =
-	process.env.FLARESOLVERR_URL ?? "http://localhost:8191";
-
-const FLARESOLVERR_API = `${FLARESOLVERR_URL}/v1`;
-
-type FlareCookie = {
-	name: string;
-	value: string;
-	domain: string;
-	path: string;
-};
-
-type FlareSolution = {
-	response: string;
-	status: number;
-	cookies: FlareCookie[];
-};
-
-type FlareResult = {
-	solution?: FlareSolution;
-	error?: string;
-};
-
-async function flareRequest(
-	url: string,
-	timeout = 30000,
-): Promise {
-	const res = await fetch(FLARESOLVERR_API, {
-		method: "POST",
-		headers: { "Content-Type": "application/json" },
-		body: JSON.stringify({
-			cmd: "request.get",
-			url,
-			maxTimeout: timeout,
-		}),
-		signal: AbortSignal.timeout(timeout + 5000),
-	});
-
-	if (!res.ok) {
-		throw new Error(
-			`FlareSolverr request failed: ${res.status} ${res.statusText}`,
-		);
-	}
-
-	const data = (await res.json()) as FlareResult;
-
-	if (data.error) {
-		throw new Error(`FlareSolverr error: ${data.error}`);
-	}
-
-	if (!data.solution) {
-		throw new Error("FlareSolverr: no solution in response");
-	}
-
-	return data.solution;
-}
-
-export async function fetchWithFlareSolver(
-	url: string,
-	timeout = 30000,
-): Promise {
-	const solution = await flareRequest(url, timeout);
-	return solution.response;
-}
-
-/**
- * Solve a Cloudflare challenge for the given URL and return the clearance
- * cookies as a `-b "name=value; ..."` argument string suitable for curl.
- * Returns null if FlareSolverr is unavailable or no cookies were set.
- */
-export async function getFlareSolverrCookies(
-	url: string,
-	timeout = 30000,
-): Promise {
-	try {
-		const solution = await flareRequest(url, timeout);
-		if (!solution.cookies?.length) return null;
-		return solution.cookies.map((c) => `${c.name}=${c.value}`).join("; ");
-	} catch {
-		return null;
-	}
-}
diff --git a/src/lib/services/import/core/download.ts b/src/lib/services/import/core/download.ts
index 8286711d..b8110714 100644
--- a/src/lib/services/import/core/download.ts
+++ b/src/lib/services/import/core/download.ts
@@ -1,5 +1,5 @@
 import { promises as fs } from "node:fs";
-import { getFlareSolverrCookies } from "@/lib/services/flare-solver";
+import { getByparrCookies } from "@/lib/services/byparr";
 import { parseNitroBundle } from "../../swf/nitro-builder";
 import { browserHeaders } from "./browser-headers";
 import { curlDownload } from "./curl-fetch";
@@ -62,7 +62,7 @@ export async function downloadFile(
 	const curlFallback = async (): Promise => {
 		let curlRes = await curlDownload(url, destPath);
 		if (!curlRes.ok) {
-			const cookieHeader = await getFlareSolverrCookies(url);
+			const cookieHeader = await getByparrCookies(url);
 			curlRes = await curlDownload(
 				url,
 				destPath,
@@ -108,7 +108,7 @@ export async function downloadFile(
 					res.status === 404 || res.status === 410 || res.status === 403;
 				if (deterministic || attempt === maxRetries) {
 					// HTTP 403 is often a TLS-fingerprint / Cloudflare challenge
-					// block (e.g. Leet.city) — retry via curl, with FlareSolverr
+					// block (e.g. Leet.city) — retry via curl, with Byparr
 					// clearance cookies if the plain curl is also challenged.
 					if (res.status === 403 && (await curlFallback())) {
 						const stat = await fs.stat(destPath);
@@ -148,7 +148,7 @@ export async function downloadFile(
 			return { ok: true, size: buffer.length };
 		} catch (err) {
 			if (attempt === maxRetries || stage === "write") {
-				// TLS fingerprint aborts land here too — try curl/FlareSolverr
+				// TLS fingerprint aborts land here too — try curl/Byparr
 				// before reporting the network failure.
 				if (stage === "download" && (await curlFallback())) {
 					const stat = await fs.stat(destPath);
diff --git a/src/test/ci-deploy-harness.sh b/src/test/ci-deploy-harness.sh
index 61bdaae5..3ec66ee0 100644
--- a/src/test/ci-deploy-harness.sh
+++ b/src/test/ci-deploy-harness.sh
@@ -13,7 +13,6 @@ flock() { echo "lock" >> "$TEST_DIR/calls"; [ "$SCENARIO" != lock-failure ]; }
 pnpm() {
   echo "pnpm $*" >> "$TEST_DIR/calls"
   if [ "$1" = db:migrate ] && [ "$SCENARIO" = migration-failure ]; then return 1; fi
-  if [ "$1" = test:e2e ] && [ "$SCENARIO" = smoke-failure ]; then return 1; fi
   return 0
 }
 curl() {
@@ -43,5 +42,12 @@ docker() {
 }
 export -f git flock pnpm curl sleep docker
 
-node() { echo "node $*" >> "$TEST_DIR/calls"; [ "$SCENARIO" != release-failure ]; }
+node() {
+  echo "node $*" >> "$TEST_DIR/calls"
+  case "$SCENARIO" in
+    release-failure) return 1 ;;
+    smoke-failure) case "$*" in *verify-deployed-release.mjs*) return 1 ;; esac ;;
+  esac
+  return 0
+}
 export -f node
diff --git a/tsconfig.json b/tsconfig.json
index 5dc971ca..4f65630c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -34,5 +34,5 @@
 		".next-staging/types/**/*.ts",
 		".next-staging/dev/types/**/*.ts"
 	],
-	"exclude": ["node_modules", "e2e", "playwright.config.ts", "src/generated"]
+	"exclude": ["node_modules", "src/generated"]
 }
diff --git a/update-Nitrov3.sh b/update-Nitrov3.sh
index cb773d3e..12d4c125 100755
--- a/update-Nitrov3.sh
+++ b/update-Nitrov3.sh
@@ -1282,7 +1282,7 @@ with open(out, "w", encoding="utf-8") as f:
 
 # Sanity-check a .env file for the failure modes that actually break a deploy:
 # duplicate keys, and a value concatenated onto another key (missing newline),
-# e.g. FLARESOLVERR_URL=http://localhost:8191AUTH_TRUST_HOST="..."
+# e.g. BYPARR_URL=http://localhost:8191AUTH_TRUST_HOST="..."
 validate_env_file() {
     local base_dir="${1:-$SCRIPT_DIR}"
     local en="$base_dir/.env"