From 918d2ccf72f1cf5e4d93c467952c772507d10e20 Mon Sep 17 00:00:00 2001 From: withrvr Date: Sun, 13 Sep 2026 23:14:11 +0000 Subject: [PATCH 1/2] chore(deps): upgrade every dependency to true latest stable (Phase 9.6) Backend: uv lock --upgrade (small remainder after Phase 9.5), raised the redis/psycopg version floors in pyproject.toml to match Dependabot PRs #8/#9 and what was already resolving. Frontend: attempted every deferral Phase 9.5 left, per this phase's "actually try the fix" mandate -- axios and @hey-api/openapi-ts upgraded clean; @tanstack/react-table v8->v9 migrated for real (DataTable.tsx and its two consumers, verified via build/lint/dev-server); react-email in packages/react-email/ bumped to true latest, verified byte-identical template export output. typescript v6->v7 attempted then reverted: it works fine on its own, but @hey-api/openapi-ts crashes under it (a confirmed, currently-open upstream bug, hey-api/hey-api#4235) -- the one genuine "latest is broken" case this phase hit. zizmor-action bumped to v0.6.3 (Dependabot PR #5's exact target). Verified postgres:18/redis:8-alpine are each technology's current major via a live check (PostgreSQL 19 is still beta). Full detail, including a template-org leftover found in zizmor.yml (flagged for Phase 14, not fixed here) and the Dependabot reconciliation: docs/development/dependency-audit.md. Claude-Session: https://claude.ai/code/session_01WACAxnAd7w5uk12Y58EHqz --- .github/workflows/zizmor.yml | 2 +- .gitignore | 1 + PROGRESS.md | 62 +++- backend/pyproject.toml | 4 +- bun.lock | 134 ++++----- docs/development/dependency-audit.md | 264 +++++++++++------- docs/stack.md | 37 ++- frontend/Dockerfile.playwright | 2 +- frontend/package.json | 8 +- frontend/src/client/client.gen.ts | 4 +- frontend/src/client/client/index.ts | 2 + frontend/src/client/client/utils.gen.ts | 4 +- frontend/src/client/core/auth.gen.ts | 7 + frontend/src/client/core/params.gen.ts | 33 ++- .../src/client/core/pathSerializer.gen.ts | 12 +- .../src/client/core/queryKeySerializer.gen.ts | 2 +- frontend/src/client/core/types.gen.ts | 6 + frontend/src/client/core/utils.gen.ts | 8 +- frontend/src/client/sdk.gen.ts | 112 ++++---- frontend/src/components/Admin/columns.tsx | 3 +- frontend/src/components/Common/DataTable.tsx | 44 +-- frontend/src/components/Items/columns.tsx | 3 +- packages/react-email/package.json | 4 +- uv.lock | 254 ++++++++--------- 24 files changed, 596 insertions(+), 416 deletions(-) diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index fae8b5d..5c1fb25 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -24,7 +24,7 @@ jobs: with: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2 + uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3 with: advanced-security: ${{ github.repository_owner == 'fastapi' }} annotations: ${{ github.repository_owner != 'fastapi' }} diff --git a/.gitignore b/.gitignore index afeeaa0..16ae5c3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ backend/app/frontend/ # botpit additions .env.staging .env.production +packages/react-email/.react-email/ *.local data/* !data/.gitkeep diff --git a/PROGRESS.md b/PROGRESS.md index 45ae2e0..d96e3b3 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -36,7 +36,8 @@ branch; only the phase branch opens a PR into `master`. | 7 | Rooms, seats, capacity, join queue | done 2026-09-13 (PR #12) | | 8 | First live mixed game (terminal + API) | done 2026-09-13 (PR #13) | | 9 | Persistence and replay | done 2026-09-13 (PR #14) | -| 9.5 | Stabilize, document, rebrand | done 2026-09-13 (branch phase-9.5-stabilize-and-rebrand, PR pending) | +| 9.5 | Stabilize, document, rebrand | done 2026-09-13 (PR #15) | +| 9.6 | Upgrade to latest stable versions | done 2026-09-13 (branch phase-9.6-dependency-upgrade, PR pending) | | 10 | Frontend: play, spectate, admin, focus view | | | 11 | Chat and personas | | | 12 | Leaderboard | | @@ -447,6 +448,65 @@ the three genuinely independent pieces per the brief. `ty check app` clean, backend suite 753 tests green, frontend `bun run build`/`bun run lint` clean, `prek run --all-files` clean. +## Phase 9.6 — done 2026-09-13 (branch phase-9.6-dependency-upgrade) + +One job: every dependency onto its true latest stable version, verified, +falling back only where genuinely broken with the reason documented. Full +detail: `docs/development/dependency-audit.md`. + +- Backend: `uv lock --upgrade` picked up the small remainder Phase 9.5 + left (`ast-serialize`, `coverage`, `pydantic-core` patches); raised two + `pyproject.toml` floors (`redis[hiredis]` to `>=8.1.0`, + `psycopg[binary]` to `>=3.3.5,<4.0.0`) to close Dependabot PRs #8/#9 for + real. `pydantic-core` 2.49.0 exists but `pydantic` 2.13.5 (itself the + true latest) doesn't request it yet -- not a gap, verified against PyPI + directly. +- Frontend: attempted every deferral Phase 9.5 left, per this phase's + "actually try the real fix" mandate. + - `axios` (1.18.0 -> 1.20.0) and `@hey-api/openapi-ts` (0.97.3 -> 0.99.0) + upgraded clean. + - `@tanstack/react-table` v8 -> v9 (confirmed genuinely GA, not still + beta, via a live check before touching it): a real migration, not a + version bump -- `useReactTable`/`getCoreRowModel`/ + `getPaginationRowModel` -> `useTable`/`tableFeatures`/ + `createPaginatedRowModel`, `table.getState()` -> `table.state`, + `row.getVisibleCells()` -> `row.getAllCells()`, `ColumnDef` gains a + leading `TFeatures` param. Migrated `DataTable.tsx` and its two + consumers (`Admin/columns.tsx`, `Items/columns.tsx`); verified via + build, lint, and starting the dev server to exercise + `@tanstack/router-plugin`'s live route generation under the new types. + - `react-email`/`@react-email/ui` in `packages/react-email/` (the + `emails` workspace member) bumped to true latest 6.9.5 -- found via a + Dependabot PR mentioning packages neither this nor the Phase 9.5 audit + had looked at. Verified via `bun run --filter emails export` + producing byte-identical HTML to the already-committed + `backend/app/email-templates/*.html`. + - `typescript` v6 -> v7 **attempted, then reverted**: 7.0.2 builds, + lints, and runs the dev server fine on its own, but + `@hey-api/openapi-ts` 0.99.0 crashes under it + (`Cannot read properties of undefined (reading 'AnyKeyword')`) -- + confirmed as a currently-open upstream bug + (`hey-api/hey-api#4235`), not fixable here. Reverted to `^6.0.3`. + This is the one genuine "latest is broken, fall back and document" + case this phase hit. +- Docker/CI: confirmed via live checks that `postgres:18`/`redis:8-alpine` + are still each technology's current major (PostgreSQL 19 is in beta, + not shipped stable); bumped `zizmorcore/zizmor-action` to v0.6.3 (PR + #5's exact target). Found, flagged, not fixed (out of scope for a + version-only phase, and `.github/workflows/*` is a standing Phase-14 + deferral): `zizmor.yml`'s `advanced-security` gate still checks + `github.repository_owner == 'fastapi'`, a leftover template-org check. +- Housekeeping found while verifying: `packages/react-email/.react-email/` + (that package's build cache) had no `.gitignore` entry anywhere in the + repo -- added one. +- Dependabot reconciliation: closed all 5 open PRs (#4, #5, #8, #9, #16), + each with a comment pointing at the commit that superseded it -- every + one covered at the same or a truer-latest version except `typescript` + (documented exception above, not a security advisory). +- Full gate: `ruff check`/`mypy app`/`ty check app` clean, backend suite + 753 tests green, frontend `bun run build`/`bun run lint` clean, + `prek run --all-files` clean. + ## Phase 2 — done pending PR review - `botpit.games.base`: `Game[State, Move]` contract, frozen pydantic state, diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 61b7292..01e58e2 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -12,14 +12,14 @@ dependencies = [ "jinja2<4.0.0,>=3.1.4", "alembic>=1.19.1,<2.0.0", "httpx<1.0.0,>=0.25.1", - "psycopg[binary]>=3.3.4,<4.0.0", + "psycopg[binary]>=3.3.5,<4.0.0", "sqlmodel>=0.0.39,<1.0.0", "pydantic-settings<3.0.0,>=2.2.1", "sentry-sdk[fastapi]>=2.68.1,<3.0.0", "pyjwt<3.0.0,>=2.13.0", "pwdlib[argon2,bcrypt]>=0.3.1", # botpit - "redis[hiredis]>=5.2", + "redis[hiredis]>=8.1.0", "websockets>=13", ] diff --git a/bun.lock b/bun.lock index 2f5351e..979e26e 100644 --- a/bun.lock +++ b/bun.lock @@ -27,8 +27,8 @@ "@tanstack/react-query-devtools": "^5.102.8", "@tanstack/react-router": "^1.170.36", "@tanstack/react-router-devtools": "^1.167.2", - "@tanstack/react-table": "^8.21.3", - "axios": "1.18.0", + "@tanstack/react-table": "^9.2.4", + "axios": "1.20.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "form-data": "4.0.6", @@ -45,8 +45,8 @@ }, "devDependencies": { "@biomejs/biome": "^2.5.13", - "@hey-api/openapi-ts": "0.97.3", - "@playwright/test": "1.62.1", + "@hey-api/openapi-ts": "0.99.0", + "@playwright/test": "1.63.0", "@tanstack/router-devtools": "^1.167.2", "@tanstack/router-plugin": "^1.168.38", "@types/node": "^26.5.1", @@ -66,11 +66,11 @@ "@react-email/components": "1.0.12", "react": "^19.2.8", "react-dom": "^19.2.8", - "react-email": "6.9.1", + "react-email": "6.9.5", }, "devDependencies": { "@biomejs/biome": "^2.5.6", - "@react-email/ui": "6.9.1", + "@react-email/ui": "6.9.5", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", }, @@ -127,7 +127,7 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.5.13", "", { "os": "win32", "cpu": "x64" }, "sha512-VOofU/nW761XWzUeUNE8zzYNyPrxuMuNFMizL0qz7J75yeV8N7WFheUlk1/K6dOkaFpH9wJ+lDKlwjAbw0346w=="], - "@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="], + "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], @@ -189,13 +189,13 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.12", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="], - "@hey-api/codegen-core": ["@hey-api/codegen-core@0.8.2", "", { "dependencies": { "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "c12": "3.3.4", "color-support": "1.1.3" } }, "sha512-R2NMf3wq97rh1mjz33WJQU8svz3F0RYUjvx/QzXucjpSqQ3O5huTdDjErG4fMxSr1X+X56NuDrqtGfHmo1TRUQ=="], + "@hey-api/codegen-core": ["@hey-api/codegen-core@0.9.1", "", { "dependencies": { "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "c12": "3.3.4", "color-support": "1.1.3" } }, "sha512-s97jL1dgTMuiMHv2BZ1X4Tgd99Mf9GOvGdNqNcGwIMmnR+PgYNoraj4Zvp134MKsNCap/m7k0r0vKKnl56pj4w=="], - "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.4.2", "", { "dependencies": { "@jsdevtools/ono": "7.1.3", "@types/json-schema": "7.0.15", "js-yaml": "4.1.1" } }, "sha512-ZhCFSKI2ipZHEbgmtUHdyddvRU3wJ4elgCfYUC7T7hZa4EivSrVflTQf2w+v3TuaYxR1Y2V2kq3otqTttrrK8Q=="], + "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.4.4", "", { "dependencies": { "@jsdevtools/ono": "7.1.3", "@types/json-schema": "7.0.15", "js-yaml": "4.2.0" } }, "sha512-otmd+zCxbYVBIp/mlMTnGkvlNYLkVKgs3VOIq0kSnenhB1+fRwLPQIeSwyWM6E51oXhUedkYjVsVpkVexeuJOA=="], - "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.97.3", "", { "dependencies": { "@hey-api/codegen-core": "0.8.2", "@hey-api/json-schema-ref-parser": "1.4.2", "@hey-api/shared": "0.4.5", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "@lukeed/ms": "2.0.2", "ansi-colors": "4.1.3", "color-support": "1.1.3", "commander": "14.0.3", "get-tsconfig": "4.14.0" }, "peerDependencies": { "typescript": ">=5.5.3 || >=6.0.0 || 6.0.1-rc" }, "bin": { "openapi-ts": "./bin/run.js" } }, "sha512-4sR6/E/POuy7aPZW9DDjhObzZCq7eSJWiW0+epXeKNczoTWEwdOyWFy9Ca/CnXYlZ3oJsrv0ZD0OO+YuczT7CA=="], + "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.99.0", "", { "dependencies": { "@hey-api/codegen-core": "0.9.1", "@hey-api/json-schema-ref-parser": "1.4.4", "@hey-api/shared": "0.5.0", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "@lukeed/ms": "2.0.2", "ansi-colors": "4.1.3", "color-support": "1.1.3", "commander": "15.0.0", "get-tsconfig": "4.14.0" }, "peerDependencies": { "typescript": ">=5.5.3 || >=6.0.0 || 6.0.1-rc" }, "bin": { "openapi-ts": "./bin/run.js" } }, "sha512-SePU/5oEWWkvUBYmvzdYRctseoLuskyhs4ET0RvLIcmzc8yLQoA2R+KtBIQ8bPsoSUB0m4E5SmBnl6aGSA0szQ=="], - "@hey-api/shared": ["@hey-api/shared@0.4.5", "", { "dependencies": { "@hey-api/codegen-core": "0.8.2", "@hey-api/json-schema-ref-parser": "1.4.2", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "cross-spawn": "7.0.6", "open": "11.0.0", "semver": "7.7.4" } }, "sha512-au4eHpBXAe1du0iMp6ESYuEaMS2jsoEyrbcT246btRhI9rMeQFEs7ZjtcMGXGsxhpaR38A8cPGNHx7QOrWAdMw=="], + "@hey-api/shared": ["@hey-api/shared@0.5.0", "", { "dependencies": { "@hey-api/codegen-core": "0.9.1", "@hey-api/json-schema-ref-parser": "1.4.4", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "cross-spawn": "7.0.6", "open": "11.0.0", "semver": "7.8.4" } }, "sha512-JN/j4Ebh4cJGYIQ5cwWuqe7GeSUyQoz7oC51WqyhKOcrejK6DKZMDkshc5d1eKTRuRL+rjozuRcoUaZZn2DGPw=="], "@hey-api/spec-types": ["@hey-api/spec-types@0.2.0", "", { "dependencies": { "@hey-api/types": "0.1.4" } }, "sha512-ibQ8Is7evMavzr8GNyJCcTg975d8DpaMUyLmOrQ85UBdy1l6t1KuRAwgChAbesJsIlNV6gjmlXruWyegDX18Fg=="], @@ -205,53 +205,57 @@ "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA=="], - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.3.3" }, "os": "darwin", "cpu": "x64" }, "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw=="], - "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + "@img/sharp-freebsd-wasm32": ["@img/sharp-freebsd-wasm32@0.35.4", "", { "dependencies": { "@img/sharp-wasm32": "0.35.4" }, "os": "freebsd" }, "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA=="], - "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg=="], - "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw=="], - "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA=="], - "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A=="], - "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.3.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w=="], - "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.3.3", "", { "os": "linux", "cpu": "none" }, "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ=="], - "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.3.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q=="], - "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA=="], - "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw=="], - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw=="], - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.3.3" }, "os": "linux", "cpu": "arm" }, "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A=="], - "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.3.3" }, "os": "linux", "cpu": "arm64" }, "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ=="], - "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.3.3" }, "os": "linux", "cpu": "ppc64" }, "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ=="], - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.3.3" }, "os": "linux", "cpu": "none" }, "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA=="], - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.3.3" }, "os": "linux", "cpu": "s390x" }, "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ=="], - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.3.3" }, "os": "linux", "cpu": "x64" }, "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA=="], - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" }, "os": "linux", "cpu": "arm64" }, "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA=="], - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.3.3" }, "os": "linux", "cpu": "x64" }, "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg=="], - "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.4", "", { "dependencies": { "@emnapi/runtime": "^1.11.3" } }, "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA=="], - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + "@img/sharp-webcontainers-wasm32": ["@img/sharp-webcontainers-wasm32@0.35.4", "", { "dependencies": { "@img/sharp-wasm32": "0.35.4" }, "cpu": "none" }, "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA=="], - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.35.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.35.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.4", "", { "os": "win32", "cpu": "x64" }, "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -267,27 +271,27 @@ "@lukeed/ms": ["@lukeed/ms@2.0.2", "", {}, "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA=="], - "@next/env": ["@next/env@16.2.6", "", {}, "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw=="], + "@next/env": ["@next/env@16.3.3", "", {}, "sha512-U2eYQRwXj+dsqxV79zFqExDdatnNY/ZWc2nsJU1p/OgT7fd3dXwlF6OjYaFQCfMoeTA19PWq+wVmYgimVA+V+g=="], - "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg=="], + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8Hiv32QJPwdV6KYJ8meR9SBA061tQqnIKTJDocvOXlEQqib0xMFpzArosuffFUUc0sslbh7QQ8a3Yey1QV8EIw=="], - "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ=="], + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-A1lgKgwVchRYmSe467zdwhxT9040dd8lH+o65sL5Jet8fjB4kegw/rDyPIpYVRb6jAqwXFOJpjIXJLxQKLiE3A=="], - "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.2.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w=="], + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-bf0FIssMFueU2dm7vQEWWxk0c8UjKTdW0yzuh0sQsD8pf1+KCLDdaqhYZNMYGmXwEOiHAUzgBKudovIlcvvBjg=="], - "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.2.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA=="], + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-W7viwCk9JY/cAkdz/A273rd5bb3RgT/IHwR7Upv90tunjBWNtAAhGhoecHh+teRNRSinuAFmE+l7fwZ4YKkrXg=="], - "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.2.6", "", { "os": "linux", "cpu": "x64" }, "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw=="], + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-0W46zw1N3ODpI6n0GeivHvvob1pooozgZVqy65k0mh4/7vr+FbY9+WpHzNVXjHipJf/A3FDheBG19H1s5A25rA=="], - "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.2.6", "", { "os": "linux", "cpu": "x64" }, "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g=="], + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-H4mBso8ZTMBPtdT0PN0pBx2ayTvQuTuvS6qT13d77yVFJXAPCxkyIhLTmdMaGTJs0krQYI/qpzdHijCeihXhbg=="], - "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.2.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg=="], + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-cTMUJpcEGmeywofCUfhR+rSsoE33+rVPnPEYNTNdLNlsOeEg/vktOsKUSTb28vUGqD2jkm4Zaskcwn7OCI6FQg=="], - "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.2.6", "", { "os": "win32", "cpu": "x64" }, "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA=="], + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-2VR4cTBzHXaBjnGsuH6GyJjENzQOmHeAh11uY1iUhjm3j5dEUrVJuUj+VL78jaGi/Dik8xS76zEj18BsFhlVZQ=="], "@oxc-project/types": ["@oxc-project/types@0.149.0", "", {}, "sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA=="], - "@playwright/test": ["@playwright/test@1.62.1", "", { "dependencies": { "playwright": "1.62.1" }, "bin": { "playwright": "cli.js" } }, "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ=="], + "@playwright/test": ["@playwright/test@1.63.0", "", { "dependencies": { "playwright": "1.63.0" }, "bin": { "playwright": "cli.js" } }, "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ=="], "@radix-ui/number": ["@radix-ui/number@1.1.3", "", {}, "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA=="], @@ -409,7 +413,7 @@ "@react-email/text": ["@react-email/text@0.1.6", "", { "peerDependencies": { "react": "^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-TYqkioRS45wTR5il3dYk/SbUjjEdhSwh9BtRNB99qNH1pXAwA45H7rAuxehiu8iJQJH0IyIr+6n62gBz9ezmsw=="], - "@react-email/ui": ["@react-email/ui@6.9.1", "", { "dependencies": { "esbuild": "0.28.1", "next": "16.2.6" } }, "sha512-zw7KvwMu3RU/fDC9TAkegg9/qNV9foJtd3QRoetdWVFe8aQC/NyXmWTrG9IrkzVLzn5otkkxu7e7B1QelcwdiQ=="], + "@react-email/ui": ["@react-email/ui@6.9.5", "", { "dependencies": { "esbuild": "0.28.1", "next": "16.3.3" } }, "sha512-UvE0yeSQCvdBm9BoEgvZ5vBi8abk02GbRE+4RQjjtxozy66D/O1GbUgK9RdB26+7EqQdOxdwkGLq5CMCiRO96A=="], "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.8", "", { "os": "android", "cpu": "arm" }, "sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw=="], @@ -477,7 +481,7 @@ "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], - "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + "@swc/helpers": ["@swc/helpers@0.5.23", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw=="], "@swc/types": ["@swc/types@0.1.28", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw=="], @@ -527,7 +531,7 @@ "@tanstack/react-store": ["@tanstack/react-store@0.11.1", "", { "dependencies": { "@tanstack/store": "0.11.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-HaIGKI3YLmjBYIvy5DFDY23oNaYZIsTZfngey07Uh5iLVJgM3bIGCnZeOFOqzjFld9JHWcaHJnasD/bKoGKwJQ=="], - "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="], + "@tanstack/react-table": ["@tanstack/react-table@9.2.4", "", { "dependencies": { "@tanstack/react-store": "^0.11.1", "@tanstack/table-core": "9.2.4" }, "peerDependencies": { "react": ">=18" } }, "sha512-Rzp1Q4e0/nIgEjmISYR5HeEgLTNtrG+C7NFZf/AbCxPO5hg+zC3yNGwcoECigUk8SFzzvhXbd2rFdtP2ZiGrfA=="], "@tanstack/router-core": ["@tanstack/router-core@1.171.30", "", { "dependencies": { "@tanstack/history": "1.162.4", "cookie-es": "^3.0.0", "seroval": "^1.6.2", "seroval-plugins": "^1.6.2" } }, "sha512-wtS1yCAb/k5CJBauvrCyqf2n4/kRc3aiz81tFBJ1QXH4Utsu81xFTMq15AdmNWgWmt2UstUSMfWi4Ua7ph2F+w=="], @@ -543,7 +547,7 @@ "@tanstack/store": ["@tanstack/store@0.11.1", "", {}, "sha512-mzTOBhypOuDJAy/D8n2MfUZ1HFkXnmSETviRyhqEC8LUE7/IZQExOTxMANj3KjTofYTkFNpBY67qaVrT41YccA=="], - "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="], + "@tanstack/table-core": ["@tanstack/table-core@9.2.4", "", { "dependencies": { "@tanstack/store": "^0.11.1" } }, "sha512-GwdDyGGr6UXAtubF14yAwcXvdaogqfsQgIk89Suebjxob/Rjq2xvfmXsjDF1rQmKmhHsJm9TOY7myxv3i6geJw=="], "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.162.0", "", {}, "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA=="], @@ -581,7 +585,7 @@ "atomically": ["atomically@2.1.1", "", { "dependencies": { "stubborn-fs": "^2.0.0", "when-exit": "^2.1.4" } }, "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ=="], - "axios": ["axios@1.18.0", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw=="], + "axios": ["axios@1.20.0", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.6", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg=="], "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], @@ -589,7 +593,7 @@ "base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.11.12", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.11.23", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ=="], "botpit-frontend": ["botpit-frontend@workspace:frontend"], @@ -619,7 +623,7 @@ "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], - "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + "commander": ["commander@15.0.0", "", {}, "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg=="], "conf": ["conf@15.1.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "atomically": "^2.0.3", "debounce-fn": "^6.0.0", "dot-prop": "^10.0.0", "env-paths": "^3.0.0", "json-schema-typed": "^8.0.1", "semver": "^7.7.2", "uint8array-extras": "^1.5.0" } }, "sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og=="], @@ -773,7 +777,7 @@ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "js-yaml": ["js-yaml@4.2.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw=="], "jsesc": ["jsesc@3.1.0", "", { "bin": "bin/jsesc" }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], @@ -843,7 +847,7 @@ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "next": ["next@16.2.6", "", { "dependencies": { "@next/env": "16.2.6", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.6", "@next/swc-darwin-x64": "16.2.6", "@next/swc-linux-arm64-gnu": "16.2.6", "@next/swc-linux-arm64-musl": "16.2.6", "@next/swc-linux-x64-gnu": "16.2.6", "@next/swc-linux-x64-musl": "16.2.6", "@next/swc-win32-arm64-msvc": "16.2.6", "@next/swc-win32-x64-msvc": "16.2.6", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw=="], + "next": ["next@16.3.3", "", { "dependencies": { "@next/env": "16.3.3", "@swc/helpers": "0.5.23", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.5.23", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.3.3", "@next/swc-darwin-x64": "16.3.3", "@next/swc-linux-arm64-gnu": "16.3.3", "@next/swc-linux-arm64-musl": "16.3.3", "@next/swc-linux-x64-gnu": "16.3.3", "@next/swc-linux-x64-musl": "16.3.3", "@next/swc-win32-arm64-msvc": "16.3.3", "@next/swc-win32-x64-msvc": "16.3.3", "sharp": "^0.35.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-tuRTx1nQ/yVw83cwJBo9F+njGUgMn3UHQycreWHB8XsStvvAh1AthbI8/4IpKnFaF58F+iSiHejYOlMQ/eq83g=="], "node-releases": ["node-releases@2.0.55", "", {}, "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ=="], @@ -877,9 +881,9 @@ "pkg-types": ["pkg-types@2.3.3", "", { "dependencies": { "confbox": "^0.3.1", "exsolve": "^1.1.1", "pathe": "^2.0.3" } }, "sha512-j/lCFdcppV0JxWpCEITdbDltBxPP6cHT+yNJ6Go2OgoSA9518X847X9z0p6LtA4Nc16+eQzCZjRrWanTGvHJ5w=="], - "playwright": ["playwright@1.62.1", "", { "dependencies": { "playwright-core": "1.62.1" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg=="], + "playwright": ["playwright@1.63.0", "", { "dependencies": { "playwright-core": "1.63.0" }, "bin": { "playwright": "cli.js" } }, "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg=="], - "playwright-core": ["playwright-core@1.62.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw=="], + "playwright-core": ["playwright-core@1.63.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg=="], "postcss": ["postcss@8.5.28", "", { "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A=="], @@ -899,7 +903,7 @@ "react-dom": ["react-dom@19.3.0", "", { "dependencies": { "scheduler": "^0.28.0" }, "peerDependencies": { "react": "^19.3.0" } }, "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q=="], - "react-email": ["react-email@6.9.1", "", { "dependencies": { "@babel/parser": "7.29.2", "@babel/traverse": "7.29.0", "@react-email/render": ">=2.1.0", "chokidar": "^4.0.3", "commander": "^13.0.0", "conf": "^15.0.2", "css-tree": "3.2.1", "debounce": "^2.0.0", "esbuild": "^0.28.0", "glob": "^13.0.6", "jiti": "2.6.1", "log-symbols": "^7.0.0", "marked": "^15.0.12", "mime-types": "^3.0.0", "normalize-path": "^3.0.0", "nypm": "0.6.6", "picospinner": "^3.0.0", "prismjs": "^1.30.0", "prompts": "2.4.2", "socket.io": "^4.8.1", "tailwindcss": "^4.1.18", "tsconfig-paths": "4.2.0" }, "peerDependencies": { "react": "^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" }, "bin": { "email": "./dist/cli/index.mjs" } }, "sha512-uUDRgFukMUXRlrsCNGlA0PZuUlQ44faI9hT/D7uMjozdumLBdHjfQttQswRYLjyLW8fFtg2HBrxAESbFU4ZKKA=="], + "react-email": ["react-email@6.9.5", "", { "dependencies": { "@babel/parser": "7.29.2", "@babel/traverse": "7.29.0", "@react-email/render": ">=2.1.0", "chokidar": "^4.0.3", "commander": "^13.0.0", "conf": "^15.0.2", "css-tree": "3.2.1", "debounce": "^2.0.0", "esbuild": "^0.28.0", "glob": "^13.0.6", "jiti": "2.6.1", "log-symbols": "^7.0.0", "marked": "^15.0.12", "mime-types": "^3.0.0", "normalize-path": "^3.0.0", "nypm": "0.6.6", "picospinner": "^3.0.0", "prismjs": "^1.30.0", "prompts": "2.4.2", "socket.io": "^4.8.1", "tailwindcss": "^4.1.18", "tsconfig-paths": "4.2.0" }, "peerDependencies": { "react": "^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" }, "bin": { "email": "./dist/cli/index.mjs" } }, "sha512-XkUFa4S3XGbVQegdGSvkShsEOn/j9t3yL5MXRf5A2l4K+RzXNPK2TZLOgI/bXfWu2WRyKWb9aVDtfLLuyBMi2A=="], "react-error-boundary": ["react-error-boundary@6.1.5", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-l2nk+KhgM6e79tAiHEs3tXTdiTW4ARniKYMQN+cLY5vQFpDOkxuXKIC4uIwYuIKoMpFQ6jEbQz9wBArUmq7GWA=="], @@ -927,13 +931,13 @@ "selderee": ["selderee@0.11.0", "", { "dependencies": { "parseley": "^0.12.0" } }, "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA=="], - "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + "semver": ["semver@7.8.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA=="], "seroval": ["seroval@1.6.7", "", {}, "sha512-AeDcLh0yO2SFm9W71essgnSzLV9DI8ZH0x0knXn2DMnUZj728mpLbxjlbB6IqKCmqh8JA3cEqRyGoNkt584JcQ=="], "seroval-plugins": ["seroval-plugins@1.6.7", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-4Nk35ttD3DTDJW4hgw5StsVAPeU6qnDFnULAouw6tQ7oLTV/ICXrWpsXo2EE52eSP2joUMazbVf52mFEcADqRw=="], - "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + "sharp": ["sharp@0.35.4", "", { "dependencies": { "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", "semver": "^7.8.5" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.35.4", "@img/sharp-darwin-x64": "0.35.4", "@img/sharp-freebsd-wasm32": "0.35.4", "@img/sharp-libvips-darwin-arm64": "1.3.3", "@img/sharp-libvips-darwin-x64": "1.3.3", "@img/sharp-libvips-linux-arm": "1.3.3", "@img/sharp-libvips-linux-arm64": "1.3.3", "@img/sharp-libvips-linux-ppc64": "1.3.3", "@img/sharp-libvips-linux-riscv64": "1.3.3", "@img/sharp-libvips-linux-s390x": "1.3.3", "@img/sharp-libvips-linux-x64": "1.3.3", "@img/sharp-libvips-linuxmusl-arm64": "1.3.3", "@img/sharp-libvips-linuxmusl-x64": "1.3.3", "@img/sharp-linux-arm": "0.35.4", "@img/sharp-linux-arm64": "0.35.4", "@img/sharp-linux-ppc64": "0.35.4", "@img/sharp-linux-riscv64": "0.35.4", "@img/sharp-linux-s390x": "0.35.4", "@img/sharp-linux-x64": "0.35.4", "@img/sharp-linuxmusl-arm64": "0.35.4", "@img/sharp-linuxmusl-x64": "0.35.4", "@img/sharp-webcontainers-wasm32": "0.35.4", "@img/sharp-win32-arm64": "0.35.4", "@img/sharp-win32-ia32": "0.35.4", "@img/sharp-win32-x64": "0.35.4" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -1061,20 +1065,18 @@ "babel-dead-code-elimination/@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", "@babel/types": "^7.29.8", "debug": "^4.3.1" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="], - "browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.11.23", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ=="], - "c12/jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "conf/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + "engine.io/@types/node": ["@types/node@25.9.2", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw=="], - "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + "next/postcss": ["postcss@8.5.23", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg=="], "path-scurry/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], "pkg-types/confbox": ["confbox@0.3.1", "", {}, "sha512-cKUSoKa8YxFZZSmraVi7onONx3amu77ngK3kGpsYHDH7drPwCRkQE1RYMPlLRrMtnciRj274XNRxcHxnKmDSnA=="], - "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], - "react-email/@react-email/render": ["@react-email/render@2.1.0", "", { "dependencies": { "entities": "^4.5.0", "html-to-text": "^9.0.5", "html5parser": "^3.0.0", "prettier": "^3.5.3" }, "peerDependencies": { "react": "^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-F+zE3O6d6sW6Aj2UjvZAA17R7tJKM7kcq2mgV6k4HCT8jeLLFaVP2txMtH1lgqYFRMZ0Gxsd37q2PRyiXLXXxA=="], "react-email/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], @@ -1083,7 +1085,7 @@ "react-email/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], - "react-email/tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="], + "sharp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], "@babel/helper-module-imports/@babel/traverse/@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="], @@ -1119,8 +1121,6 @@ "engine.io/@types/node/undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="], - "next/postcss/nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], - "react-email/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "react-email/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], diff --git a/docs/development/dependency-audit.md b/docs/development/dependency-audit.md index ecbe37c..84bba6e 100644 --- a/docs/development/dependency-audit.md +++ b/docs/development/dependency-audit.md @@ -1,103 +1,177 @@ -# Dependency audit (Phase 9.5) +# Dependency audit -One-time sweep against every dependency's current stable release, done -right before Phase 10 (frontend) starts, per the standing project -convention of stabilizing between backend and frontend work. Not a +A living record of dependency-upgrade passes. First done in Phase 9.5 +(stabilize/document/rebrand, right before Phase 10 starts); Phase 9.6 is a +dedicated follow-up whose only job was pushing every dependency to its true +latest stable release, not just what was already caught in passing. Not a recurring scheduled job yet -- there's no CI/CD phase (14) to hang one off of. -## Backend (`uv lock --upgrade`) +## Phase 9.6 -- true latest, dependency-focused pass -30 packages bumped within the existing `pyproject.toml` version ranges (all -of them `>=X, 1.6.0, the -largest single jump), `uvicorn`, `pydantic`/`pydantic-core`, `alembic`, -`psycopg`/`psycopg-binary`, `pyjwt`, `sentry-sdk`, `httpx`-adjacent -transitive deps, plus the dev toolchain (`ruff`, `ty`, `prek`, `zizmor`, -`typer`). +### Backend + +`uv lock --upgrade` picked up the small remainder left after Phase 9.5 +(`ast-serialize`, `coverage`, `pydantic-core` patch bumps). Two +`pyproject.toml` version *floors* were also raised to match what was +already resolving anyway, closing Dependabot PRs #8/#9 for real rather than +just resolving past their proposed floor invisibly: + +- `redis[hiredis]`: `>=5.2` -> `>=8.1.0` +- `psycopg[binary]`: `>=3.3.4,<4.0.0` -> `>=3.3.5,<4.0.0` + +`pydantic-core` sits at 2.46.5 while 2.49.0 exists on PyPI -- checked +directly against PyPI's own listing, `pydantic` itself (the only thing this +project depends on directly) is genuinely still at 2.13.5, its true latest +release, and its own metadata is what pins the compatible `pydantic-core` +range. Not a gap: forcing `pydantic-core` past what `pydantic` actually +declares compatible would risk a real mismatch, not close one. Verified clean after: `ruff check`, `mypy app` (strict), `ty check app`, -and the full backend suite (753 tests) all green, same as before the -upgrade. - -Python itself: `3.14` is pinned in `.python-version` at the repo root, and -every GitHub Actions workflow that runs Python reads that same file via -`python-version-file: .python-version` rather than a hardcoded version -string -- there is no drift possible between local dev and CI on this. - -## Frontend (`bun update`) - -Within-range bumps to `@tanstack/react-query`/`react-router` (and their -devtools packages), `react`/`react-dom`, `react-hook-form`, -`lucide-react`, `tailwindcss`, `sonner`, `tailwind-merge`, `zod`, -`@biomejs/biome`, `vite`, `@types/*`, and their transitive dependencies. - -Verified clean after: `bun run build` and `bun run lint` (biome) both -green. - -### Deliberately not upgraded - -- **`@tanstack/react-table`** (8.21.3, latest is 9.x) and **`typescript`** - (6.0.3, latest is 7.x): both are capped by `package.json`'s own `^` - range at their current major version, and both major bumps carry real - breaking-change risk that needs actual code migration to absorb safely - -- `react-table` v9 changes its core API surface, and the current - scaffold's `DataTable.tsx`/`Admin/columns.tsx`/`Items/columns.tsx` use - it directly. Phase 10 (frontend) is about to rewrite or heavily touch - those exact files anyway, so bumping the major version now, before any - real UI work happens on top of it, would mean either migrating dead-end - template scaffold code or doing the migration twice. Left for Phase 10 - to decide once it knows what it's actually keeping vs. replacing. -- **`axios`** (1.18.0) and **`form-data`** (4.0.6): both are exact-pinned - in `package.json` (no `^`/`~` range), unlike every other dependency in - the file. An exact pin like that is typically deliberate -- most often - to work around a specific regression in a later version -- and nothing - in this repo's history explains why these two are pinned that way. - Overriding a pin without knowing its reason risks reintroducing whatever - it was protecting against. Left as-is; a newer `axios` (1.20.0 is - current) is available whenever someone confirms the pin's origin and - decides to lift it. - -### Noted, not acted on - -- Biome's own report flagged `frontend/biome.json`'s `$schema` URL as one - version behind the just-upgraded `@biomejs/biome` package (`2.5.6` vs. - `2.5.13`) -- purely an informational schema-version string, not a - lint failure (`biome check` still ran and passed on this repo's actual - code). Left as-is: this repo's config-protection tooling blocks direct - edits to `biome.json` outside of a deliberate, explicit exception, and - the mismatch has no functional effect. Worth a one-line fix whenever - someone next touches that file for an actual rule change. -- `starlette`'s `TestClient` and its own `testclient.py` now emit two new - deprecation warnings under the upgraded `httpx`/`anyio` (`httpx2` - suggested; `anyio.abc.BlockingPortal` -> `anyio.from_thread.BlockingPortal`). - Both are upstream library warnings, not anything in this codebase, and - neither affects test correctness -- the full suite still passes with - them present. Not acted on; revisit if a future `starlette`/`httpx` - bump ever turns these into hard removals instead of warnings. - -## Container base images - -`backend/Dockerfile`: `python:3.14` and `oven/bun:1` -- both float to the -latest patch within their pinned major/minor, already current by -construction, nothing to bump. `compose.yml`: `postgres:18`, `redis:8-alpine` --- both already the current major version for each. `traefik:v3.7`, -`mailpit`, `adminer` (dev-only tooling containers, not part of botpit's -own runtime) were not chased for exact latest patch tags -- low value -relative to the effort, and none of them affect application behavior. - -## What this audit did not cover - -- No PRs or phase branches were left dangling going into this audit -- - every phase through 9 is merged into `master`, confirmed via `git log` - before this phase branched. -- Frontend and backend were audited together in one pass rather than - strictly "one meaningful batch at a time" with a full-suite run between - every individual package -- given the actual diff size (30 backend - packages, ~20 frontend packages, all within already-permitted semver - ranges) and that the full gate was still run and confirmed green - immediately after each side's upgrade, a finer-grained bisection wasn't - needed to attribute a regression, since there wasn't one. +and the full backend suite (753 tests) all green. + +### Frontend + +`bun update` picked up the small remainder (`@radix-ui/react-slot`, minor +`@tanstack/*` patch bumps). Three items Phase 9.5 had deliberately deferred +were actually attempted this time, per this phase's mandate to try the real +fix before falling back: + +- **`axios`** 1.18.0 -> 1.20.0 and **`@hey-api/openapi-ts`** 0.97.3 -> + 0.99.0: both exact-pinned, both upgraded cleanly. Verified by regenerating + the OpenAPI client (`scripts/generate-client.sh`) and a full `bun run + build`/`bun run lint` -- clean. (`form-data`, still exact-pinned at + 4.0.6, was left alone -- same "no recorded reason for the pin, don't + guess" caution as before, and it's already at its own latest anyway.) +- **`@tanstack/react-table`** 8.21.3 -> 9.2.4: a real v8->v9 migration, not + a version-number change. v9 replaces `useReactTable`/`getCoreRowModel`/ + `getPaginationRowModel` with `useTable`/`tableFeatures`/ + `createPaginatedRowModel`, drops `table.getState()` in favor of + `table.state`, drops `row.getVisibleCells()` in favor of `row.getAllCells()` + (column visibility is no longer bundled into core), and `ColumnDef` gains + a leading `TFeatures` type parameter. Migrated `DataTable.tsx` (the shared + component) and both its consumers, `Admin/columns.tsx` and + `Items/columns.tsx` -- exported the table's `features` object from + `DataTable.tsx` so both column-definition files share the exact same + `TFeatures` type. Verified via `bun run build` (`tsc` + `vite build`), + `bun run lint`, and starting the dev server to exercise + `@tanstack/router-plugin`'s live route-tree generation under the new + table types -- all clean. No live-browser render check was done (this is + still template scaffold, not a real botpit feature yet); build+lint+type + correctness was judged sufficient given that. +- **`@react-email/ui`**/**`react-email`** (in `packages/react-email/`, the + `emails` workspace member -- found via a Dependabot PR that mentioned + packages neither prior audit had looked at): 6.9.1 -> 6.9.5 (true latest; + Dependabot's own PR only proposed 6.9.3). Verified via `bun run --filter + emails build` and, more importantly, `bun run --filter emails export` -- + byte-identical output to the three already-committed `backend/app/ + email-templates/*.html` files, confirming the upgrade changes nothing + observable for this project's actual usage. + +### Deliberately held back + +- **`typescript`**: attempted the real upgrade to 7.0.2 first, per this + phase's explicit mandate. It builds, lints, and runs the dev server fine + **on its own** -- the "TypeScript 7 has no stable programmatic compiler + API until 7.1" limitation that blocks many toolchains (Vue/Svelte/Astro + template type-checking, some webpack loaders) does not affect this + project's actual Vite/`@tanstack/router-plugin` build path. But + `@hey-api/openapi-ts` 0.99.0 -- the OpenAPI-to-TypeScript client generator + `scripts/generate-client.sh` depends on -- crashes under it: + `TypeError: Cannot read properties of undefined (reading 'AnyKeyword')`, + because it uses the TypeScript compiler as a library to build the + generated client's AST, and that surface is exactly what changed in + TypeScript 7. This is a confirmed, currently-open upstream bug + (`hey-api/hey-api#4235`, labeled `bug`), not something fixable in this + codebase -- reverted to `^6.0.3` (the version already in use, still the + right choice) rather than ship a build that can never regenerate its own + API client. Retry this once that issue closes upstream; check + `@hey-api/openapi-ts`'s own changelog for a "TypeScript 7 support" entry + first, since the fix will land there, not in TypeScript itself. + +### Container base images + +`postgres:18` and `redis:8-alpine` (`compose.yml`) confirmed against a live +check to still be the current major of each -- PostgreSQL 19 is in beta +(scheduled stable ~September 2026, not shipped as of this pass) and Redis +8.x remains current (8.10.1 is the latest patch). `backend/Dockerfile`'s +`python:3.14`/`oven/bun:1` float to latest patch by construction, already +current. `traefik:v3.7`/`mailpit`/`adminer` (dev-only tooling, not +botpit's own runtime) -- Dependabot's own `docker-compose` ecosystem watch +covers these and has not flagged any of them, taken as sufficient signal +rather than re-checking each by hand. + +### GitHub Actions + +Every action in `.github/workflows/*.yml` is SHA-pinned with a version +comment. Dependabot's `github-actions` group had exactly one open item +(`zizmorcore/zizmor-action` 0.6.2 -> 0.6.3, PR #5) -- applied directly +(new SHA `70fb788f84895a7701f5643d103d587e460b5c99`). Nothing else in that +group was flagged, taken as sufficient signal that the rest are current +(Dependabot watches this ecosystem continuously; a stale action would have +its own open PR by now). + +**Found in passing, not fixed (out of scope for a version-upgrade phase):** +`.github/workflows/zizmor.yml`'s `advanced-security`/`annotations` inputs +gate on `github.repository_owner == 'fastapi'` -- a leftover check against +the *template's* upstream org, not this repo's (`withrvr`). Functionally +this just means `advanced-security` is always `false` and `annotations` is +always `true` for this repo, which happens to be harmless, but it's a +correctness bug, not a version issue, and `.github/workflows/*` is a +standing, deliberate deferral to Phase 14 (PROGRESS.md's Phase 2b note) for +exactly this kind of template-authored logic. Flagging here so it isn't +silently lost before Phase 14 gets there. + +### Housekeeping found while verifying + +`packages/react-email/.react-email/` (that package's local dev/build cache) +had no `.gitignore` entry anywhere in the repo -- added one. Discovered +because verifying the `react-email` upgrade meant actually running its +`build`/`export` scripts, which created the directory. + +### Dependabot reconciliation + +Every open Dependabot PR at the time this phase started (#4, #5, #8, #9, +#16) was superseded by this pass's own commits -- same or a truer-latest +target version in every case except `typescript` (see above, a deliberate, +documented exception, not a security advisory Dependabot flagged, so +closing #16 does not silently drop anything). All five were closed with a +comment pointing at the PR that superseded them. None of the five carried a +security-advisory label; if a future Dependabot PR does and this kind of +pass doesn't fully resolve it, that PR must stay open and the situation +gets recorded here instead. + +## Phase 9.5 -- first sweep + +30 backend packages (`uv lock --upgrade`, within existing `pyproject.toml` +ranges: `fastapi`, `sqlalchemy`, `sqlmodel`, `starlette` 1.3.1->1.6.0, +`uvicorn`, `pydantic`, `alembic`, `psycopg`, plus the dev toolchain) and +~20 frontend packages (`bun update`, within existing `package.json` ranges: +`@tanstack/react-query`/`router`, `react`, `react-hook-form`, +`lucide-react`, `tailwindcss`, `biome`, `vite`, `@types/*`). Full backend +suite (753 tests) and `bun run build`/`lint` both green after. + +`@tanstack/react-table` (major bump), `typescript` (major bump), `axios`, +and `@hey-api/openapi-ts` (both exact-pinned) were deliberately left +untouched at the time -- Phase 9.6 above is where each was actually +attempted. `python:3.14`/`oven/bun:1`/`postgres:18`/`redis:8-alpine` +container images were already current; Python 3.14 consistency confirmed +via `.python-version`, read by every GitHub Actions workflow that needs a +Python version (no drift possible between local dev and CI). + +Noted, not acted on then (still true now): `frontend/biome.json`'s +`$schema` URL trails the installed `@biomejs/biome` version by a few +patches -- purely informational, config-protection tooling blocks direct +edits to `biome.json` outside a deliberate exception, no functional effect. +`starlette`'s `TestClient` emits two upstream deprecation warnings +(`httpx2`, `anyio.from_thread.BlockingPortal`) under the newer +`httpx`/`anyio` -- neither affects test correctness. diff --git a/docs/stack.md b/docs/stack.md index 53f1dce..28a4cd4 100644 --- a/docs/stack.md +++ b/docs/stack.md @@ -32,17 +32,20 @@ not repeat those documents' detail — it summarizes and links to them. plan of async SQLAlchemy 2.0 across SQLite and Postgres. DB work inside `async def` route handlers goes through `run_in_threadpool`; the engine itself (`backend/app/core/db.py`) is a plain sync `create_engine`. -- **Postgres** (17 locally, `postgres:18` in the deploy-shaped compose file) - is the only database. The SQLite dual-dialect layer from Phase 1 was - dropped at the Phase 2b pivot — one dialect, one set of column types, no - `if dialect == ...` branches anywhere in the codebase. +- **Postgres 18** (`postgres:18` in `compose.yml`, the same image for local + dev and any deploy-shaped setup — one pin, not a dev/deploy split) is the + only database. The SQLite dual-dialect layer from Phase 1 was dropped at + the Phase 2b pivot — one dialect, one set of column types, no `if dialect + == ...` branches anywhere in the codebase. PostgreSQL 19 entered beta in + 2026; not adopted here until it ships stable (`docs/development/dependency-audit.md`). - **Alembic** — schema migrations, run via `scripts/prestart.sh` before the server starts (not in the app lifespan, unlike the pre-template design). See `docs/persistence.md`. -- **Redis** — two independent uses, never a source of truth for game state - (DECISIONS.md §12): the pluggable event bus's `RedisStreamsEventBus` - (`docs/events.md`) when `EVENT_BUS=redis`, and the sliding-window rate - limiter plus join-queue primitives (`docs/capacity-and-queueing.md`). +- **Redis 8** (`redis:8-alpine` in `compose.yml`) — two independent uses, + never a source of truth for game state (DECISIONS.md §12): the pluggable + event bus's `RedisStreamsEventBus` (`docs/events.md`) when + `EVENT_BUS=redis`, and the sliding-window rate limiter plus join-queue + primitives (`docs/capacity-and-queueing.md`). - **Pydantic v2** — every request/response model (via SQLModel, which wraps it), the event envelope and payload schema (`backend/app/events/schema.py`), and `pydantic-settings` for `Settings` (`backend/app/core/config.py`). @@ -113,9 +116,21 @@ not repeat those documents' detail — it summarizes and links to them. ## Frontend (Phase 10, not yet built) -- **React 19 + TanStack Router/Query + Tailwind 4 + shadcn/ui + Vite + Bun**, - built into `backend/app/frontend` and served by FastAPI, with a generated - OpenAPI client — the template's own stack, adopted at the Phase 2b pivot. +- **React 19.3, TanStack Router 1.170/Query 5.102, TypeScript 6.0 + (see below), Tailwind 4.3, shadcn/ui, Vite 8.3, Bun 1.4**, built into + `backend/app/frontend` and served by FastAPI, with a generated OpenAPI + client (`@hey-api/openapi-ts` 0.99) — the template's own stack, adopted + at the Phase 2b pivot, kept current in Phase 9.6 + (`docs/development/dependency-audit.md`). `@tanstack/react-table` 9 (a + real v8→v9 migration, not just a version bump) is used by the still-template + `DataTable`/`Admin`/`Items` scaffolding; nothing here is a real botpit + feature yet. +- **TypeScript stays on 6.0**, not the newer major 7.0, because + `@hey-api/openapi-ts` (the OpenAPI-to-TypeScript client generator this + project's build depends on) crashes under TypeScript 7 — a confirmed, + currently-open upstream bug (`hey-api/hey-api#4235`), not a choice made + here. Revisit once that's fixed upstream; full detail in + `docs/development/dependency-audit.md`. This supersedes an earlier researched pick of **SvelteKit 2 + Svelte 5** (runes-based reactive state was attractive for a websocket-fed table UI, and produced the smallest bundles in 2026 framework comparisons) — recorded diff --git a/frontend/Dockerfile.playwright b/frontend/Dockerfile.playwright index 63d9028..53ed576 100644 --- a/frontend/Dockerfile.playwright +++ b/frontend/Dockerfile.playwright @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/playwright:v1.62.1-noble +FROM mcr.microsoft.com/playwright:v1.63.0-noble WORKDIR /app diff --git a/frontend/package.json b/frontend/package.json index 4bed498..9e9386e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,8 +31,8 @@ "@tanstack/react-query-devtools": "^5.102.8", "@tanstack/react-router": "^1.170.36", "@tanstack/react-router-devtools": "^1.167.2", - "@tanstack/react-table": "^8.21.3", - "axios": "1.18.0", + "@tanstack/react-table": "^9.2.4", + "axios": "1.20.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "form-data": "4.0.6", @@ -49,8 +49,8 @@ }, "devDependencies": { "@biomejs/biome": "^2.5.13", - "@hey-api/openapi-ts": "0.97.3", - "@playwright/test": "1.62.1", + "@hey-api/openapi-ts": "0.99.0", + "@playwright/test": "1.63.0", "@tanstack/router-devtools": "^1.167.2", "@tanstack/router-plugin": "^1.168.38", "@types/node": "^26.5.1", diff --git a/frontend/src/client/client.gen.ts b/frontend/src/client/client.gen.ts index 988ea75..99565fb 100644 --- a/frontend/src/client/client.gen.ts +++ b/frontend/src/client/client.gen.ts @@ -1,6 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -import { type ClientOptions, type Config, createClient, createConfig } from './client'; +import { type Client, type ClientOptions, type Config, createClient, createConfig } from './client'; import type { ClientOptions as ClientOptions2 } from './types.gen'; /** @@ -13,4 +13,4 @@ import type { ClientOptions as ClientOptions2 } from './types.gen'; */ export type CreateClientConfig = (override?: Config) => Config & T>; -export const client = createClient(createConfig({ throwOnError: true })); +export const client: Client = createClient(createConfig({ throwOnError: true })); diff --git a/frontend/src/client/client/index.ts b/frontend/src/client/client/index.ts index 7bd7b98..3e877a5 100644 --- a/frontend/src/client/client/index.ts +++ b/frontend/src/client/client/index.ts @@ -9,6 +9,8 @@ export { } from '../core/bodySerializer.gen'; export { buildClientParams } from '../core/params.gen'; export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen'; +export type { ServerSentEventsResult } from '../core/serverSentEvents.gen'; +export type { ClientMeta } from '../core/types.gen'; export { createClient } from './client.gen'; export type { Client, diff --git a/frontend/src/client/client/utils.gen.ts b/frontend/src/client/client/utils.gen.ts index 837b869..6b0faec 100644 --- a/frontend/src/client/client/utils.gen.ts +++ b/frontend/src/client/client/utils.gen.ts @@ -13,8 +13,8 @@ import type { Client, ClientOptions, Config, RequestOptions } from './types.gen' export const createQuerySerializer = ({ parameters = {}, ...args -}: QuerySerializerOptions = {}) => { - const querySerializer = (queryParams: T) => { +}: QuerySerializerOptions = {}): ((queryParams: T) => string) => { + const querySerializer = (queryParams: T): string => { const search: string[] = []; if (queryParams && typeof queryParams === 'object') { for (const name in queryParams) { diff --git a/frontend/src/client/core/auth.gen.ts b/frontend/src/client/core/auth.gen.ts index 3ebf994..c663664 100644 --- a/frontend/src/client/core/auth.gen.ts +++ b/frontend/src/client/core/auth.gen.ts @@ -9,6 +9,13 @@ export interface Auth { * @default 'header' */ in?: 'header' | 'query' | 'cookie'; + /** + * A unique identifier for the security scheme. + * + * Defined only when there are multiple security schemes whose `Auth` + * shape would otherwise be identical. + */ + key?: string; /** * Header or query parameter name. * diff --git a/frontend/src/client/core/params.gen.ts b/frontend/src/client/core/params.gen.ts index 6478519..5e8908f 100644 --- a/frontend/src/client/core/params.gen.ts +++ b/frontend/src/client/core/params.gen.ts @@ -62,7 +62,7 @@ type KeyMap = Map< } >; -const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { +function buildKeyMap(fields: FieldsConfig, map?: KeyMap): KeyMap { if (!map) { map = new Map(); } @@ -85,26 +85,26 @@ const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { } return map; -}; +} interface Params { - body: unknown; + body?: unknown; headers: Record; path: Record; query: Record; } -const stripEmptySlots = (params: Params) => { +function stripEmptySlots(params: Params): void { for (const [slot, value] of Object.entries(params)) { + if (slot === 'body') continue; if (value && typeof value === 'object' && !Array.isArray(value) && !Object.keys(value).length) { delete params[slot as Slot]; } } -}; +} -export const buildClientParams = (args: ReadonlyArray, fields: FieldsConfig) => { +export function buildClientParams(args: ReadonlyArray, fields: FieldsConfig): Params { const params: Params = { - body: Object.create(null), headers: Object.create(null), path: Object.create(null), query: Object.create(null), @@ -112,6 +112,15 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo const map = buildKeyMap(fields); + function writeSlot(slot: Slot, key: string, value: unknown): void { + let record = params[slot] as Record | undefined; + if (record === undefined) { + record = Object.create(null) as Record; + params[slot] = record; + } + record[key] = value; + } + let config: FieldsConfig[number] | undefined; for (const [index, arg] of args.entries()) { @@ -128,7 +137,7 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo const field = map.get(config.key)!; const name = field.map || config.key; if (field.in) { - (params[field.in] as Record)[name] = arg; + writeSlot(field.in, name, arg); } } else { params.body = arg; @@ -140,7 +149,7 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo if (field) { if (field.in) { const name = field.map || key; - (params[field.in] as Record)[name] = value; + writeSlot(field.in, name, value); } else { params[field.map] = value; } @@ -149,11 +158,11 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo if (extra) { const [prefix, slot] = extra; - (params[slot] as Record)[key.slice(prefix.length)] = value; + writeSlot(slot, key.slice(prefix.length), value); } else if ('allowExtra' in config && config.allowExtra) { for (const [slot, allowed] of Object.entries(config.allowExtra)) { if (allowed) { - (params[slot as Slot] as Record)[key] = value; + writeSlot(slot as Slot, key, value); break; } } @@ -166,4 +175,4 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo stripEmptySlots(params); return params; -}; +} diff --git a/frontend/src/client/core/pathSerializer.gen.ts b/frontend/src/client/core/pathSerializer.gen.ts index 994b284..fab1ed4 100644 --- a/frontend/src/client/core/pathSerializer.gen.ts +++ b/frontend/src/client/core/pathSerializer.gen.ts @@ -25,7 +25,7 @@ interface SerializePrimitiveParam extends SerializePrimitiveOptions { value: string; } -export const separatorArrayExplode = (style: ArraySeparatorStyle) => { +export const separatorArrayExplode = (style: ArraySeparatorStyle): '.' | ';' | ',' | '&' => { switch (style) { case 'label': return '.'; @@ -38,7 +38,7 @@ export const separatorArrayExplode = (style: ArraySeparatorStyle) => { } }; -export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { +export const separatorArrayNoExplode = (style: ArraySeparatorStyle): ',' | '|' | '%20' => { switch (style) { case 'form': return ','; @@ -51,7 +51,7 @@ export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { } }; -export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { +export const separatorObjectExplode = (style: ObjectSeparatorStyle): '.' | ';' | ',' | '&' => { switch (style) { case 'label': return '.'; @@ -72,7 +72,7 @@ export const serializeArrayParam = ({ value, }: SerializeOptions & { value: unknown[]; -}) => { +}): string => { if (!explode) { const joinedValues = ( allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) @@ -110,7 +110,7 @@ export const serializePrimitiveParam = ({ allowReserved, name, value, -}: SerializePrimitiveParam) => { +}: SerializePrimitiveParam): string => { if (value === undefined || value === null) { return ''; } @@ -134,7 +134,7 @@ export const serializeObjectParam = ({ }: SerializeOptions & { value: Record | Date; valueOnly?: boolean; -}) => { +}): string => { if (value instanceof Date) { return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; } diff --git a/frontend/src/client/core/queryKeySerializer.gen.ts b/frontend/src/client/core/queryKeySerializer.gen.ts index 5000df6..773b065 100644 --- a/frontend/src/client/core/queryKeySerializer.gen.ts +++ b/frontend/src/client/core/queryKeySerializer.gen.ts @@ -14,7 +14,7 @@ export type JsonValue = /** * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. */ -export const queryKeyJsonReplacer = (_key: string, value: unknown) => { +export const queryKeyJsonReplacer = (_key: string, value: unknown): unknown | undefined => { if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { return undefined; } diff --git a/frontend/src/client/core/types.gen.ts b/frontend/src/client/core/types.gen.ts index 9efe71d..c657c85 100644 --- a/frontend/src/client/core/types.gen.ts +++ b/frontend/src/client/core/types.gen.ts @@ -91,6 +91,12 @@ export interface Config { responseValidator?: (data: unknown) => Promise; } +/** + * Arbitrary metadata passed through the `meta` request option. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface ClientMeta {} + type IsExactlyNeverOrNeverUndefined = [T] extends [never] ? true : [T] extends [never | undefined] diff --git a/frontend/src/client/core/utils.gen.ts b/frontend/src/client/core/utils.gen.ts index 9a4fec7..af56e07 100644 --- a/frontend/src/client/core/utils.gen.ts +++ b/frontend/src/client/core/utils.gen.ts @@ -13,9 +13,9 @@ export interface PathSerializer { url: string; } -export const PATH_PARAM_RE = /\{[^{}]+\}/g; +export const PATH_PARAM_RE: RegExp = /\{[^{}]+\}/g; -export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { +export const defaultPathSerializer = ({ path, url: _url }: PathSerializer): string => { let url = _url; const matches = _url.match(PATH_PARAM_RE); if (matches) { @@ -94,7 +94,7 @@ export const getUrl = ({ query?: Record; querySerializer: QuerySerializer; url: string; -}) => { +}): string => { const pathUrl = _url.startsWith('/') ? _url : `/${_url}`; let url = (baseUrl ?? '') + pathUrl; if (path) { @@ -114,7 +114,7 @@ export function getValidRequestBody(options: { body?: unknown; bodySerializer?: BodySerializer | null; serializedBody?: unknown; -}) { +}): unknown { const hasBody = options.body !== undefined; const isSerializedBody = hasBody && options.bodySerializer; diff --git a/frontend/src/client/sdk.gen.ts b/frontend/src/client/sdk.gen.ts index ab6b126..658be4f 100644 --- a/frontend/src/client/sdk.gen.ts +++ b/frontend/src/client/sdk.gen.ts @@ -1,6 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -import { type Client, type Options as Options2, type TDataShape, urlSearchParamsBodySerializer } from './client'; +import { type Client, type ClientMeta, type Options as Options2, type RequestResult, type TDataShape, urlSearchParamsBodySerializer } from './client'; import { client } from './client.gen'; import type { adminCreateOverrideData, adminCreateOverrideErrors, adminCreateOverrideResponses, adminReadFlagsData, adminReadFlagsResponses, adminReadSettingsData, adminReadSettingsResponses, adminRemoveOverrideData, adminRemoveOverrideErrors, adminRemoveOverrideResponses, adminUpdateFlagData, adminUpdateFlagErrors, adminUpdateFlagResponses, adminUpdateSettingData, adminUpdateSettingErrors, adminUpdateSettingResponses, flagsReadMyFlagsData, flagsReadMyFlagsResponses, gamesGameEventsData, gamesGameEventsErrors, gamesGameEventsResponses, gamesGetGameRecordData, gamesGetGameRecordErrors, gamesGetGameRecordResponses, gamesReplayData, gamesReplayErrors, gamesReplayResponses, healthHealthData, healthHealthLlmData, healthHealthLlmResponses, healthHealthResponses, itemsCreateItemData, itemsCreateItemErrors, itemsCreateItemResponses, itemsDeleteItemData, itemsDeleteItemErrors, itemsDeleteItemResponses, itemsReadItemData, itemsReadItemErrors, itemsReadItemResponses, itemsReadItemsData, itemsReadItemsErrors, itemsReadItemsResponses, itemsUpdateItemData, itemsUpdateItemErrors, itemsUpdateItemResponses, loginLoginAccessTokenData, loginLoginAccessTokenErrors, loginLoginAccessTokenResponses, loginRecoverPasswordData, loginRecoverPasswordErrors, loginRecoverPasswordHtmlContentData, loginRecoverPasswordHtmlContentErrors, loginRecoverPasswordHtmlContentResponses, loginRecoverPasswordResponses, loginResetPasswordData, loginResetPasswordErrors, loginResetPasswordResponses, loginTestTokenData, loginTestTokenResponses, privateCreateUserData, privateCreateUserErrors, privateCreateUserResponses, rolesGrantUserRoleData, rolesGrantUserRoleErrors, rolesGrantUserRoleResponses, rolesReadPermissionsData, rolesReadPermissionsResponses, rolesReadRolesData, rolesReadRolesResponses, rolesReadUserRolesData, rolesReadUserRolesErrors, rolesReadUserRolesResponses, rolesRevokeUserRoleData, rolesRevokeUserRoleErrors, rolesRevokeUserRoleResponses, roomsCreateRoomData, roomsCreateRoomErrors, roomsCreateRoomResponses, roomsForceStartRoomData, roomsForceStartRoomErrors, roomsForceStartRoomResponses, roomsGetRoomData, roomsGetRoomErrors, roomsGetRoomResponses, roomsJoinRoomData, roomsJoinRoomErrors, roomsJoinRoomResponses, roomsLeaveRoomData, roomsLeaveRoomErrors, roomsLeaveRoomResponses, roomsListRoomsData, roomsListRoomsErrors, roomsListRoomsResponses, roomsMovesSchemaData, roomsMovesSchemaErrors, roomsMovesSchemaResponses, roomsRoomEventsData, roomsRoomEventsErrors, roomsRoomEventsResponses, roomsRoomQueueData, roomsRoomQueueErrors, roomsRoomQueueResponses, roomsRoomViewData, roomsRoomViewErrors, roomsRoomViewResponses, roomsStartRoomData, roomsStartRoomErrors, roomsStartRoomResponses, roomsStopRoomData, roomsStopRoomErrors, roomsStopRoomResponses, roomsSubmitMoveData, roomsSubmitMoveErrors, roomsSubmitMoveResponses, usersCreateUserData, usersCreateUserErrors, usersCreateUserResponses, usersDeleteUserData, usersDeleteUserErrors, usersDeleteUserMeData, usersDeleteUserMeResponses, usersDeleteUserResponses, usersReadUserByIdData, usersReadUserByIdErrors, usersReadUserByIdResponses, usersReadUserMeData, usersReadUserMePermissionsData, usersReadUserMePermissionsResponses, usersReadUserMeResponses, usersReadUsersData, usersReadUsersErrors, usersReadUsersResponses, usersRegisterUserData, usersRegisterUserErrors, usersRegisterUserResponses, usersUpdatePasswordMeData, usersUpdatePasswordMeErrors, usersUpdatePasswordMeResponses, usersUpdateUserData, usersUpdateUserErrors, usersUpdateUserMeData, usersUpdateUserMeErrors, usersUpdateUserMeResponses, usersUpdateUserResponses, utilsHealthCheckData, utilsHealthCheckResponses, utilsTestEmailData, utilsTestEmailErrors, utilsTestEmailResponses } from './types.gen'; @@ -15,7 +15,7 @@ export type Options; + meta?: keyof ClientMeta extends never ? Record : ClientMeta; }; export class LoginService { @@ -24,7 +24,7 @@ export class LoginService { * * OAuth2 compatible token login, get an access token for future requests */ - public static loginAccessToken(options: Options) { + public static loginAccessToken(options: Options): RequestResult { return (options.client ?? client).post({ ...urlSearchParamsBodySerializer, responseType: 'json', @@ -42,7 +42,7 @@ export class LoginService { * * Test access token */ - public static testToken(options?: Options) { + public static testToken(options?: Options): RequestResult { return (options?.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -56,7 +56,7 @@ export class LoginService { * * Password Recovery */ - public static recoverPassword(options: Options) { + public static recoverPassword(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', url: '/api/v1/password-recovery/{email}', @@ -69,7 +69,7 @@ export class LoginService { * * Reset password */ - public static resetPassword(options: Options) { + public static resetPassword(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', url: '/api/v1/reset-password/', @@ -86,7 +86,7 @@ export class LoginService { * * HTML Content for Password Recovery */ - public static recoverPasswordHtmlContent(options: Options) { + public static recoverPasswordHtmlContent(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'text', security: [{ scheme: 'bearer', type: 'http' }], @@ -102,7 +102,7 @@ export class UsersService { * * Retrieve users. */ - public static readUsers(options?: Options) { + public static readUsers(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -116,7 +116,7 @@ export class UsersService { * * Create new user. */ - public static createUser(options: Options) { + public static createUser(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -134,7 +134,7 @@ export class UsersService { * * Delete own user. */ - public static deleteUserMe(options?: Options) { + public static deleteUserMe(options?: Options): RequestResult { return (options?.client ?? client).delete({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -148,7 +148,7 @@ export class UsersService { * * Get current user. */ - public static readUserMe(options?: Options) { + public static readUserMe(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -162,7 +162,7 @@ export class UsersService { * * Update own user. */ - public static updateUserMe(options: Options) { + public static updateUserMe(options: Options): RequestResult { return (options.client ?? client).patch({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -180,7 +180,7 @@ export class UsersService { * * Update own password. */ - public static updatePasswordMe(options: Options) { + public static updatePasswordMe(options: Options): RequestResult { return (options.client ?? client).patch({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -198,7 +198,7 @@ export class UsersService { * * Get the current user's effective global permissions. */ - public static readUserMePermissions(options?: Options) { + public static readUserMePermissions(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -212,7 +212,7 @@ export class UsersService { * * Create new user without the need to be logged in. */ - public static registerUser(options: Options) { + public static registerUser(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', url: '/api/v1/users/signup', @@ -229,7 +229,7 @@ export class UsersService { * * Delete a user. */ - public static deleteUser(options: Options) { + public static deleteUser(options: Options): RequestResult { return (options.client ?? client).delete({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -243,7 +243,7 @@ export class UsersService { * * Get a specific user by id. */ - public static readUserById(options: Options) { + public static readUserById(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -257,7 +257,7 @@ export class UsersService { * * Update a user. */ - public static updateUser(options: Options) { + public static updateUser(options: Options): RequestResult { return (options.client ?? client).patch({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -277,7 +277,7 @@ export class UtilsService { * * Test emails. */ - public static testEmail(options: Options) { + public static testEmail(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -289,7 +289,7 @@ export class UtilsService { /** * Health Check */ - public static healthCheck(options?: Options) { + public static healthCheck(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', url: '/api/v1/utils/health-check/', @@ -304,7 +304,7 @@ export class ItemsService { * * Retrieve items. */ - public static readItems(options?: Options) { + public static readItems(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -318,7 +318,7 @@ export class ItemsService { * * Create new item. */ - public static createItem(options: Options) { + public static createItem(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -336,7 +336,7 @@ export class ItemsService { * * Delete an item. */ - public static deleteItem(options: Options) { + public static deleteItem(options: Options): RequestResult { return (options.client ?? client).delete({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -350,7 +350,7 @@ export class ItemsService { * * Get item by ID. */ - public static readItem(options: Options) { + public static readItem(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -364,7 +364,7 @@ export class ItemsService { * * Update an item. */ - public static updateItem(options: Options) { + public static updateItem(options: Options): RequestResult { return (options.client ?? client).put({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -382,7 +382,7 @@ export class HealthService { /** * Health */ - public static health(options?: Options) { + public static health(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', url: '/api/v1/health/', @@ -393,7 +393,7 @@ export class HealthService { /** * Health Llm */ - public static healthLlm(options?: Options) { + public static healthLlm(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -407,7 +407,7 @@ export class RolesService { /** * Read Roles */ - public static readRoles(options?: Options) { + public static readRoles(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -419,7 +419,7 @@ export class RolesService { /** * Read Permissions */ - public static readPermissions(options?: Options) { + public static readPermissions(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -431,7 +431,7 @@ export class RolesService { /** * Read User Roles */ - public static readUserRoles(options: Options) { + public static readUserRoles(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -443,7 +443,7 @@ export class RolesService { /** * Grant User Role */ - public static grantUserRole(options: Options) { + public static grantUserRole(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -459,7 +459,7 @@ export class RolesService { /** * Revoke User Role */ - public static revokeUserRole(options: Options) { + public static revokeUserRole(options: Options): RequestResult { return (options.client ?? client).delete({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -473,7 +473,7 @@ export class AdminService { /** * Read Settings */ - public static readSettings(options?: Options) { + public static readSettings(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -485,7 +485,7 @@ export class AdminService { /** * Update Setting */ - public static updateSetting(options: Options) { + public static updateSetting(options: Options): RequestResult { return (options.client ?? client).patch({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -501,7 +501,7 @@ export class AdminService { /** * Read Flags */ - public static readFlags(options?: Options) { + public static readFlags(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -513,7 +513,7 @@ export class AdminService { /** * Update Flag */ - public static updateFlag(options: Options) { + public static updateFlag(options: Options): RequestResult { return (options.client ?? client).patch({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -529,7 +529,7 @@ export class AdminService { /** * Create Override */ - public static createOverride(options: Options) { + public static createOverride(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -545,7 +545,7 @@ export class AdminService { /** * Remove Override */ - public static removeOverride(options: Options) { + public static removeOverride(options: Options): RequestResult { return (options.client ?? client).delete({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -559,7 +559,7 @@ export class FlagsService { /** * Read My Flags */ - public static readMyFlags(options?: Options) { + public static readMyFlags(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -573,7 +573,7 @@ export class RoomsService { /** * List Rooms */ - public static listRooms(options?: Options) { + public static listRooms(options?: Options): RequestResult { return (options?.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -585,7 +585,7 @@ export class RoomsService { /** * Create Room */ - public static createRoom(options: Options) { + public static createRoom(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -601,7 +601,7 @@ export class RoomsService { /** * Get Room */ - public static getRoom(options: Options) { + public static getRoom(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -613,7 +613,7 @@ export class RoomsService { /** * Join Room */ - public static joinRoom(options: Options) { + public static joinRoom(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -629,7 +629,7 @@ export class RoomsService { /** * Leave Room */ - public static leaveRoom(options: Options) { + public static leaveRoom(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -641,7 +641,7 @@ export class RoomsService { /** * Start Room */ - public static startRoom(options: Options) { + public static startRoom(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -653,7 +653,7 @@ export class RoomsService { /** * Force Start Room */ - public static forceStartRoom(options: Options) { + public static forceStartRoom(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -665,7 +665,7 @@ export class RoomsService { /** * Stop Room */ - public static stopRoom(options: Options) { + public static stopRoom(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -677,7 +677,7 @@ export class RoomsService { /** * Room Queue */ - public static roomQueue(options: Options) { + public static roomQueue(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -693,7 +693,7 @@ export class RoomsService { * live ``GameState`` under ``GameRunner``, never the database (which holds * only room/seat metadata, not game state). */ - public static roomView(options: Options) { + public static roomView(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -710,7 +710,7 @@ export class RoomsService { * reports a rejection as a seat-visible ``game.move_rejected`` event on * ``GET /events`` -- poll that to find out whether it was accepted. */ - public static submitMove(options: Options) { + public static submitMove(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -731,7 +731,7 @@ export class RoomsService { * /{room_id}`` -- it reveals nothing beyond the game type those already * show. */ - public static movesSchema(options: Options) { + public static movesSchema(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -750,7 +750,7 @@ export class RoomsService { * events plus their own seat's; nobody sees another seat's without * ``room:view_seat_detail``. */ - public static roomEvents(options: Options) { + public static roomEvents(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -764,7 +764,7 @@ export class GamesService { /** * Get Game Record */ - public static getGameRecord(options: Options) { + public static getGameRecord(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -780,7 +780,7 @@ export class GamesService { * ``since``/``next_since`` here are the archived ``seq`` integer, not a * live bus cursor -- the game is over, there is nothing left to poll for. */ - public static gameEvents(options: Options) { + public static gameEvents(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -803,7 +803,7 @@ export class GamesService { * the room's own live ``/view`` -- a cross-seat admin view is Phase 10's * job, not this route's. */ - public static replay(options: Options) { + public static replay(options: Options): RequestResult { return (options.client ?? client).get({ responseType: 'json', security: [{ scheme: 'bearer', type: 'http' }], @@ -819,7 +819,7 @@ export class PrivateService { * * Create a new user. */ - public static createUser(options: Options) { + public static createUser(options: Options): RequestResult { return (options.client ?? client).post({ responseType: 'json', url: '/api/v1/private/users/', diff --git a/frontend/src/components/Admin/columns.tsx b/frontend/src/components/Admin/columns.tsx index 8b0fa13..0029cb2 100644 --- a/frontend/src/components/Admin/columns.tsx +++ b/frontend/src/components/Admin/columns.tsx @@ -1,6 +1,7 @@ import type { ColumnDef } from "@tanstack/react-table" import type { UserPublic } from "@/client" +import type { features } from "@/components/Common/DataTable" import { Badge } from "@/components/ui/badge" import { cn } from "@/lib/utils" import { UserActionsMenu } from "./UserActionsMenu" @@ -9,7 +10,7 @@ export type UserTableData = UserPublic & { isCurrentUser: boolean } -export const columns: ColumnDef[] = [ +export const columns: ColumnDef[] = [ { accessorKey: "full_name", header: "Full Name", diff --git a/frontend/src/components/Common/DataTable.tsx b/frontend/src/components/Common/DataTable.tsx index e5bf2ae..168c459 100644 --- a/frontend/src/components/Common/DataTable.tsx +++ b/frontend/src/components/Common/DataTable.tsx @@ -1,9 +1,11 @@ import { type ColumnDef, + createPaginatedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - useReactTable, + type RowData, + rowPaginationFeature, + tableFeatures, + useTable, } from "@tanstack/react-table" import { ChevronLeft, @@ -29,20 +31,24 @@ import { TableRow, } from "@/components/ui/table" -interface DataTableProps { - columns: ColumnDef[] +export const features = tableFeatures({ + rowPaginationFeature, + paginatedRowModel: createPaginatedRowModel(), +}) + +interface DataTableProps { + columns: ColumnDef[] data: TData[] } -export function DataTable({ +export function DataTable({ columns, data, -}: DataTableProps) { - const table = useReactTable({ +}: DataTableProps) { + const table = useTable({ + features, data, columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), }) return ( @@ -70,7 +76,7 @@ export function DataTable({ {table.getRowModel().rows.length ? ( table.getRowModel().rows.map((row) => ( - {row.getVisibleCells().map((cell) => ( + {row.getAllCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} @@ -95,13 +101,13 @@ export function DataTable({
Showing{" "} - {table.getState().pagination.pageIndex * - table.getState().pagination.pageSize + + {table.state.pagination.pageIndex * + table.state.pagination.pageSize + 1}{" "} to{" "} {Math.min( - (table.getState().pagination.pageIndex + 1) * - table.getState().pagination.pageSize, + (table.state.pagination.pageIndex + 1) * + table.state.pagination.pageSize, data.length, )}{" "} of{" "} @@ -111,15 +117,13 @@ export function DataTable({

Rows per page