From d50ade17cf5ae3ffdbb9b5dc833db2b12af42a9b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Jun 2026 02:21:10 +0000 Subject: [PATCH 1/3] chore: add an unused-dependency CI check (knip) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing caught dependencies declared but imported nowhere (this let @tanstack/react-query sit unused until #49). Add knip as a CI guardrail. - knip + knip.json, configured for the vinxi/TanStack Start entrypoints so there are zero false positives; tailwindcss allowlisted (used via the CSS @import + @tailwindcss/vite, which knip can't trace); drizzle plugin off so knip needn't execute drizzle.config.ts - `pnpm knip` script + an "Unused dependency check" CI step in ci.yml - Removed @testing-library/user-event — knip flagged it as genuinely unused - Scaffold now drops @hono/zod-validator (only the removed example route used it) so the propagated check passes out-of-box in a fresh instance - Documented in docs/agents/dependencies.md Verified: knip clean in the template and in a scaffolded instance; preflight green; instance preflight green. Closes #42. --- .github/workflows/ci.yml | 3 + changelog.d/42-unused-deps.added.md | 1 + changelog.d/42-user-event.removed.md | 1 + docs/agents/dependencies.md | 23 + knip.json | 15 + package.json | 9 +- pnpm-lock.yaml | 649 ++++++++++++++++++++++++--- scripts/scaffold.mjs | 6 + 8 files changed, 653 insertions(+), 54 deletions(-) create mode 100644 changelog.d/42-unused-deps.added.md create mode 100644 changelog.d/42-user-event.removed.md create mode 100644 knip.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc021db..5288c77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,9 @@ jobs: - name: Type check run: pnpm typecheck + - name: Unused dependency check + run: pnpm knip + - name: Unit tests run: pnpm exec vitest run diff --git a/changelog.d/42-unused-deps.added.md b/changelog.d/42-unused-deps.added.md new file mode 100644 index 0000000..a66bc1a --- /dev/null +++ b/changelog.d/42-unused-deps.added.md @@ -0,0 +1 @@ +- `[propagate]` Added an unused-dependency CI check (`pnpm knip`, configured in `knip.json`) that fails when a declared dependency is imported nowhere — the guardrail that would have caught the previously-unused `@tanstack/react-query`. Documented in `docs/agents/dependencies.md`. diff --git a/changelog.d/42-user-event.removed.md b/changelog.d/42-user-event.removed.md new file mode 100644 index 0000000..ce18b30 --- /dev/null +++ b/changelog.d/42-user-event.removed.md @@ -0,0 +1 @@ +- `[propagate]` Removed `@testing-library/user-event`, which the new unused-dependency check flagged as declared but imported nowhere. diff --git a/docs/agents/dependencies.md b/docs/agents/dependencies.md index 45b8590..0d77c08 100644 --- a/docs/agents/dependencies.md +++ b/docs/agents/dependencies.md @@ -95,3 +95,26 @@ Before adding a package: 5. **Dev dependencies stay dev.** Test utilities, type packages, and build tools go in `devDependencies`. The hard rule from `AGENTS.md` applies: **no new dependencies without checking if the existing stack already covers the need.** + +## Unused Dependency Check + +CI runs [`knip`](https://knip.dev) via `pnpm knip` to fail the build when a +declared dependency is imported nowhere (or an import has no corresponding +dependency). This is the guardrail that would have caught `@tanstack/react-query` +sitting in the stack unused before it was wired up. + +Config lives in `knip.json`. Three repo-specific settings keep false positives at zero: + +- **Entry points** list the vinxi / TanStack Start entries (`app/client.tsx`, + `app/ssr.tsx`, `app/router.tsx`, `app/routes/**`, `app/server/index.ts`) and the + standalone scripts — knip can't infer the framework's entrypoints on its own. +- **`tailwindcss` is in `ignoreDependencies`** — it's consumed via + `@import "tailwindcss"` in `app/styles/app.css` and the `@tailwindcss/vite` + plugin, neither of which knip traces, so it would otherwise be a false "unused". +- **The drizzle plugin is disabled** (`"drizzle": false`) so knip doesn't execute + `drizzle.config.ts` (which throws without `DATABASE_URL`). `drizzle-kit` is still + detected via the `db:*` scripts. + +Run it locally with `pnpm knip`. If knip flags a dependency you intend to keep +unused, add it to `ignoreDependencies` in `knip.json` and note why in this +section — don't silence the whole check. diff --git a/knip.json b/knip.json new file mode 100644 index 0000000..1179233 --- /dev/null +++ b/knip.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://unpkg.com/knip@6/schema.json", + "entry": [ + "app/client.tsx", + "app/ssr.tsx", + "app/router.tsx", + "app/routes/**/*.tsx", + "app/server/index.ts", + "app.config.ts", + "scripts/labels.mjs" + ], + "project": ["app/**/*.{ts,tsx}", "db/**/*.ts", "scripts/*.mjs"], + "ignoreDependencies": ["tailwindcss"], + "drizzle": false +} diff --git a/package.json b/package.json index d168421..00941a3 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "changelog:check": "node scripts/changelog.mjs check", "changelog:release": "node scripts/changelog.mjs release", "typecheck": "tsc --noEmit", + "knip": "knip --include dependencies,unlisted", "test": "vitest", "test:coverage": "vitest run --coverage", "test:ui": "vitest --ui", @@ -47,23 +48,23 @@ "zod": "^3.24.0" }, "devDependencies": { - "drizzle-kit": "^0.30.0", "@biomejs/biome": "^1.9.0", "@playwright/test": "^1.50.0", "@tailwindcss/vite": "^4.0.0", + "@tanstack/router-cli": "~1.114.3", "@testing-library/jest-dom": "^6.6.0", "@testing-library/react": "^16.2.0", - "@testing-library/user-event": "^14.5.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^4.3.0", "@vitest/coverage-v8": "^2.1.0", + "drizzle-kit": "^0.30.0", "jsdom": "^26.0.0", + "knip": "^6.20.0", + "lefthook": "^1.11.0", "tailwindcss": "^4.0.0", "typescript": "^5.7.0", "vite-tsconfig-paths": "^5.1.0", - "@tanstack/router-cli": "~1.114.3", - "lefthook": "^1.11.0", "vitest": "^2.1.0" }, "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a40009..70d80ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,7 +52,7 @@ importers: version: 1.114.35(@tanstack/react-query@5.99.0(react@19.2.5))(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@tanstack/router-core@1.114.35)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/react-start': specifier: 1.114.34 - version: 1.114.34(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1)) + version: 1.114.34(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1))(yaml@2.9.0) drizzle-orm: specifier: ^0.40.0 version: 0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0) @@ -67,7 +67,7 @@ importers: version: 19.2.5(react@19.2.5) vinxi: specifier: ^0.5.1 - version: 0.5.11(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + version: 0.5.11(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) zod: specifier: ^3.24.0 version: 3.25.76 @@ -90,9 +90,6 @@ importers: '@testing-library/react': specifier: ^16.2.0 version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@testing-library/user-event': - specifier: ^14.5.0 - version: 14.6.1(@testing-library/dom@10.4.1) '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -111,6 +108,9 @@ importers: jsdom: specifier: ^26.0.0 version: 26.1.0 + knip: + specifier: ^6.20.0 + version: 6.20.0 lefthook: specifier: ^1.11.0 version: 1.13.6 @@ -339,6 +339,21 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@emnapi/core@1.11.0': + resolution: {integrity: sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==} + + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/runtime@1.11.0': + resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' @@ -1400,6 +1415,12 @@ packages: engines: {node: '>=18'} hasBin: true + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@neondatabase/serverless@0.10.4': resolution: {integrity: sha512-2nZuh3VUO9voBauuh+IGYRhGU/MskWHt1IuZvHcJw6GLjDgtqj/KViKo7SIrLdGLdot7vFbiRRw+BgEy3wT9HA==} @@ -1415,6 +1436,223 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@oxc-parser/binding-android-arm-eabi@0.137.0': + resolution: {integrity: sha512-KDs+0VPdEmasOkpuJHW9V5WCF+cvYdMQv2Jd+aJXt+cxIx12NToRQRbXaRwUEDsZw+/jMk81Ve8ZFbjUkJTOwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-parser/binding-android-arm64@0.137.0': + resolution: {integrity: sha512-WhALNzfy3x/RfC6bsqX+csavuUY0yHHE7XfgPE5M542uhoBZUUoGTPG+nkMbGoG4+gcfss5s7urMyn5QBHu0sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-parser/binding-darwin-arm64@0.137.0': + resolution: {integrity: sha512-bFPr5hgmNMOMoyPTGtdsK4Ug21RovIPojRMgDDhSp1LtCnc/DkLwGONKjgRjszg677RlGnkYSviQ8hHaUPOVYA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.137.0': + resolution: {integrity: sha512-CL5dMm1asqXIDZHg14FLxj3Mc36w8PI7xCWh1uA4is6z8g2XrIILoTcQYOxDbwzuk34RDPX5IAGUxZr6LA9KAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-freebsd-x64@0.137.0': + resolution: {integrity: sha512-79h8rYGnSlKPGWo7mHr2ixO6ea7aW8B0CT965SZ8SLbNnCOH5aOYBTeVXUY6eMvEaiLyWr8Skuiugr5pDYgLGw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.137.0': + resolution: {integrity: sha512-ASgmlSimhGyr0lksgVIo6hibz1obnDq4qJbiMX/AzltfgPnanRrzG1Q+23g8ljOHOjv6dsznkUuCYL3gg0sY1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.137.0': + resolution: {integrity: sha512-AU2J9aa22Sx32wRGnDjybOU9TQXXQUud5sdUi+ZB0XxwM8aToWLweV+yA0wlQm0yIUVqljquqoHCYEq9II8gJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.137.0': + resolution: {integrity: sha512-GdEtiG89yMr7XkUGxifgodXEEm2f+xW2f9CpDjlgAnBOwhTmrpQMvhOGobLVKUyzf/qHBXW16smk5zbF3nZU6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-arm64-musl@0.137.0': + resolution: {integrity: sha512-EGJ+Bs8iXx8KBH8DQ5BLoEm5lnHaYjlh4/8j8vFhrr/6z4tqONy5BZDzLpKmmNWlN6Hlc5r8YOuBVHqZ9vRFEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-ppc64-gnu@0.137.0': + resolution: {integrity: sha512-vzFUQENy/fnbSe5DZWovq6tIBc1uhuMztanSW6rz1e9WdQE4gHwYuD7ZII6JnrJifd1R3RSoqiZbgRFlVL2tYQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-gnu@0.137.0': + resolution: {integrity: sha512-SfVI14HBQs9gtLcUD5hTt5hsNbdrqSUNg9S8muN+LhVQ5nf1WwH3hAoK6B9NKgdYgWAQSXFXGiiBedQ4r/BKuw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-musl@0.137.0': + resolution: {integrity: sha512-e7Ppy4FCIFNQxT/ikSeIWFoQ0l+N9vgtRBtLcyZXeolTzApyVoPqEXsYPrcdM/9i0Bwk8knvYd37vaEMxHyi6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-s390x-gnu@0.137.0': + resolution: {integrity: sha512-Bho5qFwdhqsIFR7gipYEUlqvi3SRrY8sugxXig380MIaakBB1PyU9+7dBiBVScfImTNWhijUxdBwqrprGdq5WA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@oxc-parser/binding-linux-x64-gnu@0.137.0': + resolution: {integrity: sha512-36mGWtg7PyFzjJwGDkH6/F4o2nIDEoKXLPr/X/lwqklkomQwJJt1I5GJVmGhovUEmgPK5WAeAZMqlFCehwiy9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-linux-x64-musl@0.137.0': + resolution: {integrity: sha512-/Jqx6+N7A44n2BdvUr7pXhVr2vFjs6WGH3unZRczwrfiH0H1zY0QwKQMG/dtRiTlKGDKGukznPT8lx84/oEsZg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-openharmony-arm64@0.137.0': + resolution: {integrity: sha512-9Uj0qHNNl+OgT1UTGwF7ixIXU6T1u2SbMidmgPy/h1h/fl2gRS6YpAxxY1gwHofcWjoTwkoMFd8xs5Vuj6GOFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-parser/binding-wasm32-wasi@0.137.0': + resolution: {integrity: sha512-gW2vfkytNGgMVADiuzdvOfw0mWG9za20F/1fCJsif5aBMAvWJTSbpIXbIe0XkOe0VENk+PadpQ7cZgUy2sUJcA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@oxc-parser/binding-win32-arm64-msvc@0.137.0': + resolution: {integrity: sha512-x+pFANF0yL5uK/6T7lu6SlR5qid6sp//eZXKLq5iNsIE+EQg6EaS8/wsW7E91nXXjpnPhSoMOHXShSVhGRdn8w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-ia32-msvc@0.137.0': + resolution: {integrity: sha512-sQUqym80PFi6McRsIqfJrSu2JrSClEZIXXD+/FjAFoULEKzOPsldIdFBG96xdX8aVMzCNQ9792FPx3MfkEIrFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.137.0': + resolution: {integrity: sha512-2AsevxlvNN4WKxpEn3RtqD5zbqMaXF+T7JXblsP4gVuY+vC9dXS4ED/PwfRCliFqoeisYS3Iro4DHzxr0TEvVA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-project/types@0.137.0': + resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==} + + '@oxc-resolver/binding-android-arm-eabi@11.21.3': + resolution: {integrity: sha512-eNU11A2WNizh04v3uyaJCootrHIaS0B9aHYXvAvVnPNk4xYSjMUjHnhQ6dewPN2MRYDskV85d1N0Aw0WNWhcyg==} + cpu: [arm] + os: [android] + + '@oxc-resolver/binding-android-arm64@11.21.3': + resolution: {integrity: sha512-8Q+ZjTLvn2dIcWsrmhdrEihm7q+ag/k+mkry7Z+t0QbbHaVxXQfvH9AewyVMh/WrpEKhQ3DDgx9fYbqeCpeOEw==} + cpu: [arm64] + os: [android] + + '@oxc-resolver/binding-darwin-arm64@11.21.3': + resolution: {integrity: sha512-wkh0qKZGHXVUDxFw3oA1TXnU2BDYY/r775oJflGeIr8uDPPoN2pk8gijQIzYRT6hoql/lg3+Tx/SaTn9e2/aGg==} + cpu: [arm64] + os: [darwin] + + '@oxc-resolver/binding-darwin-x64@11.21.3': + resolution: {integrity: sha512-HbNc23FAQYbuyDV2vBWMez4u4mrsm5RAkniGZAWqr6lYZ3N4beeqIb776jzwRl8qL2zRhHVXpUj97X0QgogVzg==} + cpu: [x64] + os: [darwin] + + '@oxc-resolver/binding-freebsd-x64@11.21.3': + resolution: {integrity: sha512-K6xNsTUPEUdfrn0+kbMq5nOUB5w1C5pavPQngt4TM2FpN91lP0PBe2srSpamb4d69O7h86oAi/qWX/kZNRSjkw==} + cpu: [x64] + os: [freebsd] + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.21.3': + resolution: {integrity: sha512-VcFmOpcpWX1zoEy8M58tR2M9YxM+Z9RuQhqAx5q0CTmrruaP7Gveejg75hzd/5sg5nk9G3aLALEa3hE2FsmmTQ==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm-musleabihf@11.21.3': + resolution: {integrity: sha512-quVoxFLBy43hWaQbbDtQNRwAX5vX76mv7n64icAtQcJ3eNgVeblqmkupF/hAneNthdqSlnd1sTjb3aQSaDPaCQ==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-gnu@11.21.3': + resolution: {integrity: sha512-X0AqNZgcD07Q4V3RDK18/vYOj/HQT/FnmEFGYS2jTWqY7JO13ryE3TEs3eAIgUJhBnNkpEaiXqz3VK8M7qQhWQ==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-musl@11.21.3': + resolution: {integrity: sha512-YkaQnaKYdbuaXvRt5Qd0GpbihzVnyfR6z1SpYfIUC6RTu4NF7lDKPjVkYb+jRI2gedVO2rVpN35Y6akG6ud4Lw==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-ppc64-gnu@11.21.3': + resolution: {integrity: sha512-gB9HwhrPiFqUzDeEq+y/CgAijz1YdI6BnXz5GaH2Pa9cWdutchlkGFAiAuGb/PjVQpiK6NFKzFuztxrweoit7A==} + cpu: [ppc64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-gnu@11.21.3': + resolution: {integrity: sha512-zjDWBlYk8QGv0H8dsPUWqkfjYIIjG2TvspGkzXL0eImbgxtZorA/klKeHyolevoT3Kvbi+1iMr9Lhrh7jf54Og==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-musl@11.21.3': + resolution: {integrity: sha512-4UfsQvacV388y1zpXL7C1x1FNYaV52JtuNRiuzrfQA2z1z6ElVrsidkGsrvQ5EgeSq1Pj7kaKqrgGkvFuxJ/tw==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-s390x-gnu@11.21.3': + resolution: {integrity: sha512-b5uH+HKH0MP5mNBYaK75SKsJbw52URqrx2LavYdq6wb0l3ExAG5niYRP9DWUNHdKilpaBVM2bXk9HNWrH3ew7Q==} + cpu: [s390x] + os: [linux] + + '@oxc-resolver/binding-linux-x64-gnu@11.21.3': + resolution: {integrity: sha512-PjYlmilBpNRh2ntXNYAK3Am5w/nPfEpnU/96iNx7CI8EzAn12J4JRiec63wHJTH31nLoCNxBg/829pN+3CfG3Q==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-linux-x64-musl@11.21.3': + resolution: {integrity: sha512-QTBAb7JuHlZ7JUEyM8UiQi2f7m/L4swBhP2TNpYIDc9Wp/wRw1G/8sl6i13aIzQAXH7LKIm294LeOHd0lQR8zA==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-openharmony-arm64@11.21.3': + resolution: {integrity: sha512-4j1DFwjwv36ec9kds0jU/ucQ5Ha4ERO/H95BxR5JFf0kqUUAJ1kwII7XhTc1vZrkdJkvLGC9Q2MbpObpum8RBg==} + cpu: [arm64] + os: [openharmony] + + '@oxc-resolver/binding-wasm32-wasi@11.21.3': + resolution: {integrity: sha512-i8oluoel5kru/j1WNrjmQSiA3GQ7wvIYVR1IwIoZtKogAhya2iub+ZKIeSIkcJOrnzQ18Tzl/F+kL3fYOxZLvA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-resolver/binding-win32-arm64-msvc@11.21.3': + resolution: {integrity: sha512-M/8dw8dD6aOs+NlPJax401CZB9I7Aut84isQLgALGGwke4Afvw+/7yYhZb94yXf6t2sPLhQLmSmtSV+2FhsOWg==} + cpu: [arm64] + os: [win32] + + '@oxc-resolver/binding-win32-x64-msvc@11.21.3': + resolution: {integrity: sha512-H7BCt/VnS9hnmMp42eGhZ99izSCRvlnWwy/N71K1/J8QoExwY4262Z8QiEkMDtduRJrztayDxETTckmUuAVL9Q==} + cpu: [x64] + os: [win32] + '@parcel/watcher-android-arm64@2.5.6': resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} engines: {node: '>= 10.0.0'} @@ -2017,11 +2255,8 @@ packages: '@types/react-dom': optional: true - '@testing-library/user-event@14.6.1': - resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} - engines: {node: '>=12', npm: '>=6'} - peerDependencies: - '@testing-library/dom': '>=7.21.4' + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -2822,6 +3057,9 @@ packages: fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fd-package-json@2.0.0: + resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2851,6 +3089,11 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + formatly@0.3.0: + resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} + engines: {node: '>=18.3.0'} + hasBin: true + fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -3124,6 +3367,10 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3157,6 +3404,11 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} + knip@6.20.0: + resolution: {integrity: sha512-q+HYrS7FOERk32GM7g43IdTG7TurN7+YMLZrNpCxubZPYZyQwliBgd18yH4oYQL7YgGtOxP2fCqess3K2XaK2Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + knitwork@1.3.0: resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} @@ -3490,6 +3742,13 @@ packages: resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} engines: {node: '>=20'} + oxc-parser@0.137.0: + resolution: {integrity: sha512-yFImD+WLElJpLKy8llG1qe4DCmMsL18peRp8XP1JKfig/gISbJkglnpDtX2aTmAn10kZF7164HbN2H8QPsXxGg==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-resolver@11.21.3: + resolution: {integrity: sha512-2Mx3fKQz7+xgrBONjsxOgCGtMHOn38/HxMzW1I5efwXB5a4lRN0Vp40gYUJFBWJslcrvwoofTrqoTnLbwTd3pA==} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -3826,6 +4085,10 @@ packages: resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==} engines: {node: '>=20.0.0'} + smol-toml@1.7.0: + resolution: {integrity: sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==} + engines: {node: '>= 18'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3894,6 +4157,10 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} @@ -3969,6 +4236,10 @@ packages: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -4017,6 +4288,9 @@ packages: typescript: optional: true + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} @@ -4045,6 +4319,10 @@ packages: ultrahtml@1.6.0: resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + unbash@4.0.1: + resolution: {integrity: sha512-1ajSo3813sDoVIHx4inJdUS4l5L2ic5cFiddemPiyjb/PZEoBAhFwHtbaEdRDFxbAKy7FCG7s5ww3/uCFawuIA==} + engines: {node: '>=14'} + uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} @@ -4334,6 +4612,10 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -4429,6 +4711,11 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -4676,6 +4963,33 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} + '@emnapi/core@1.11.0': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -5249,6 +5563,20 @@ snapshots: - encoding - supports-color + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)': + dependencies: + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + '@neondatabase/serverless@0.10.4': dependencies: '@types/pg': 8.11.6 @@ -5265,6 +5593,133 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@oxc-parser/binding-android-arm-eabi@0.137.0': + optional: true + + '@oxc-parser/binding-android-arm64@0.137.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.137.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.137.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.137.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.137.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.137.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.137.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.137.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.137.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.137.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.137.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.137.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.137.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.137.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.137.0': + optional: true + + '@oxc-parser/binding-wasm32-wasi@0.137.0': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.137.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.137.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.137.0': + optional: true + + '@oxc-project/types@0.137.0': {} + + '@oxc-resolver/binding-android-arm-eabi@11.21.3': + optional: true + + '@oxc-resolver/binding-android-arm64@11.21.3': + optional: true + + '@oxc-resolver/binding-darwin-arm64@11.21.3': + optional: true + + '@oxc-resolver/binding-darwin-x64@11.21.3': + optional: true + + '@oxc-resolver/binding-freebsd-x64@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-arm-musleabihf@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-arm64-gnu@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-arm64-musl@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-ppc64-gnu@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-riscv64-gnu@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-riscv64-musl@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-s390x-gnu@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@11.21.3': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@11.21.3': + optional: true + + '@oxc-resolver/binding-openharmony-arm64@11.21.3': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@11.21.3': + dependencies: + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0) + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@11.21.3': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@11.21.3': + optional: true + '@parcel/watcher-android-arm64@2.5.6': optional: true @@ -5570,7 +6025,7 @@ snapshots: tailwindcss: 4.2.2 vite: 5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1) - '@tanstack/directive-functions-plugin@1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/directive-functions-plugin@1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: '@babel/code-frame': 7.26.2 '@babel/core': 7.29.0 @@ -5583,7 +6038,7 @@ snapshots: babel-dead-code-elimination: 1.0.12 dedent: 1.7.2 tiny-invariant: 1.3.3 - vite: 6.1.4(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vite: 6.1.4(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -5627,7 +6082,7 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/react-start-client@1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/react-start-client@1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: '@tanstack/react-router': 1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/router-core': 1.114.35 @@ -5638,7 +6093,7 @@ snapshots: react-dom: 19.2.5(react@19.2.5) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - vinxi: 0.5.11(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vinxi: 0.5.11(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -5685,13 +6140,13 @@ snapshots: - xml2js - yaml - '@tanstack/react-start-config@1.114.35(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1))': + '@tanstack/react-start-config@1.114.35(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1))(yaml@2.9.0)': dependencies: - '@tanstack/react-start-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/react-start-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) '@tanstack/router-core': 1.114.35 '@tanstack/router-generator': 1.114.35(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@tanstack/router-plugin': 1.114.35(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1)) - '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) '@tanstack/start-server-functions-handler': 1.114.35 '@vitejs/plugin-react': 4.7.0(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1)) import-meta-resolve: 4.2.0 @@ -5699,7 +6154,7 @@ snapshots: ofetch: 1.5.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - vinxi: 0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vinxi: 0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) vite: 5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1) zod: 3.25.76 transitivePeerDependencies: @@ -5753,7 +6208,7 @@ snapshots: - xml2js - yaml - '@tanstack/react-start-plugin@1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/react-start-plugin@1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: '@babel/code-frame': 7.26.2 '@babel/core': 7.29.0 @@ -5765,7 +6220,7 @@ snapshots: '@tanstack/router-utils': 1.114.29 babel-dead-code-elimination: 1.0.12 tiny-invariant: 1.3.3 - vite: 6.1.4(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vite: 6.1.4(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - jiti @@ -5780,11 +6235,11 @@ snapshots: - tsx - yaml - '@tanstack/react-start-router-manifest@1.114.33(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/react-start-router-manifest@1.114.33(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: '@tanstack/router-core': 1.114.35 tiny-invariant: 1.3.3 - vinxi: 0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vinxi: 0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -5846,17 +6301,17 @@ snapshots: tiny-warning: 1.0.3 unctx: 2.5.0 - '@tanstack/react-start@1.114.34(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1))': + '@tanstack/react-start@1.114.34(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1))(yaml@2.9.0)': dependencies: - '@tanstack/react-start-client': 1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0) - '@tanstack/react-start-config': 1.114.35(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1)) - '@tanstack/react-start-router-manifest': 1.114.33(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/react-start-client': 1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) + '@tanstack/react-start-config': 1.114.35(@tanstack/react-router@1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(terser@5.46.1)(tsx@4.21.0)(vite@5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1))(yaml@2.9.0) + '@tanstack/react-start-router-manifest': 1.114.33(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) '@tanstack/react-start-server': 1.114.35(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@tanstack/start-api-routes': 1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) - '@tanstack/start-server-functions-client': 1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/start-api-routes': 1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) + '@tanstack/start-server-functions-client': 1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) '@tanstack/start-server-functions-handler': 1.114.35 - '@tanstack/start-server-functions-server': 1.114.32(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) - '@tanstack/start-server-functions-ssr': 1.114.33(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/start-server-functions-server': 1.114.32(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) + '@tanstack/start-server-functions-ssr': 1.114.33(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) vite: 5.4.21(@types/node@25.6.0)(lightningcss@1.32.0)(terser@5.46.1) @@ -5973,7 +6428,7 @@ snapshots: ansis: 3.17.0 diff: 7.0.0 - '@tanstack/server-functions-plugin@1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/server-functions-plugin@1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: '@babel/code-frame': 7.26.2 '@babel/core': 7.29.0 @@ -5982,7 +6437,7 @@ snapshots: '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 - '@tanstack/directive-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/directive-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) babel-dead-code-elimination: 1.0.12 dedent: 1.7.2 tiny-invariant: 1.3.3 @@ -6001,11 +6456,11 @@ snapshots: - tsx - yaml - '@tanstack/start-api-routes@1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/start-api-routes@1.114.35(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: '@tanstack/router-core': 1.114.35 '@tanstack/start-server-core': 1.114.35 - vinxi: 0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vinxi: 0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -6070,9 +6525,9 @@ snapshots: tiny-warning: 1.0.3 unctx: 2.5.0 - '@tanstack/start-server-functions-client@1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/start-server-functions-client@1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: - '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) '@tanstack/start-server-functions-fetcher': 1.114.35 transitivePeerDependencies: - '@types/node' @@ -6101,9 +6556,9 @@ snapshots: '@tanstack/start-server-core': 1.114.35 tiny-invariant: 1.3.3 - '@tanstack/start-server-functions-server@1.114.32(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/start-server-functions-server@1.114.32(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: - '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) tiny-invariant: 1.3.3 transitivePeerDependencies: - '@types/node' @@ -6120,9 +6575,9 @@ snapshots: - tsx - yaml - '@tanstack/start-server-functions-ssr@1.114.33(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)': + '@tanstack/start-server-functions-ssr@1.114.33(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)': dependencies: - '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + '@tanstack/server-functions-plugin': 1.114.35(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) '@tanstack/start-client-core': 1.114.35 '@tanstack/start-server-core': 1.114.35 '@tanstack/start-server-functions-fetcher': 1.114.35 @@ -6176,9 +6631,10 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + '@tybys/wasm-util@0.10.3': dependencies: - '@testing-library/dom': 10.4.1 + tslib: 2.8.1 + optional: true '@types/aria-query@5.0.4': {} @@ -7045,6 +7501,10 @@ snapshots: dependencies: reusify: 1.1.0 + fd-package-json@2.0.0: + dependencies: + walk-up-path: 4.0.0 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -7062,6 +7522,10 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + formatly@0.3.0: + dependencies: + fd-package-json: 2.0.0 + fresh@0.5.2: {} fresh@2.0.0: {} @@ -7343,6 +7807,8 @@ snapshots: jiti@2.6.1: {} + jiti@2.7.0: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -7382,6 +7848,22 @@ snapshots: klona@2.0.6: {} + knip@6.20.0: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + formatly: 0.3.0 + get-tsconfig: 4.14.0 + jiti: 2.7.0 + oxc-parser: 0.137.0 + oxc-resolver: 11.21.3 + picomatch: 4.0.4 + smol-toml: 1.7.0 + strip-json-comments: 5.0.3 + tinyglobby: 0.2.17 + unbash: 4.0.1 + yaml: 2.9.0 + zod: 4.3.6 + knitwork@1.3.0: {} lazystream@1.0.1: @@ -7761,6 +8243,53 @@ snapshots: powershell-utils: 0.1.0 wsl-utils: 0.3.1 + oxc-parser@0.137.0: + dependencies: + '@oxc-project/types': 0.137.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.137.0 + '@oxc-parser/binding-android-arm64': 0.137.0 + '@oxc-parser/binding-darwin-arm64': 0.137.0 + '@oxc-parser/binding-darwin-x64': 0.137.0 + '@oxc-parser/binding-freebsd-x64': 0.137.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.137.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.137.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.137.0 + '@oxc-parser/binding-linux-arm64-musl': 0.137.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.137.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.137.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.137.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.137.0 + '@oxc-parser/binding-linux-x64-gnu': 0.137.0 + '@oxc-parser/binding-linux-x64-musl': 0.137.0 + '@oxc-parser/binding-openharmony-arm64': 0.137.0 + '@oxc-parser/binding-wasm32-wasi': 0.137.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.137.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.137.0 + '@oxc-parser/binding-win32-x64-msvc': 0.137.0 + + oxc-resolver@11.21.3: + optionalDependencies: + '@oxc-resolver/binding-android-arm-eabi': 11.21.3 + '@oxc-resolver/binding-android-arm64': 11.21.3 + '@oxc-resolver/binding-darwin-arm64': 11.21.3 + '@oxc-resolver/binding-darwin-x64': 11.21.3 + '@oxc-resolver/binding-freebsd-x64': 11.21.3 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.21.3 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.21.3 + '@oxc-resolver/binding-linux-arm64-gnu': 11.21.3 + '@oxc-resolver/binding-linux-arm64-musl': 11.21.3 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.21.3 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.21.3 + '@oxc-resolver/binding-linux-riscv64-musl': 11.21.3 + '@oxc-resolver/binding-linux-s390x-gnu': 11.21.3 + '@oxc-resolver/binding-linux-x64-gnu': 11.21.3 + '@oxc-resolver/binding-linux-x64-musl': 11.21.3 + '@oxc-resolver/binding-openharmony-arm64': 11.21.3 + '@oxc-resolver/binding-wasm32-wasi': 11.21.3 + '@oxc-resolver/binding-win32-arm64-msvc': 11.21.3 + '@oxc-resolver/binding-win32-x64-msvc': 11.21.3 + package-json-from-dist@1.0.1: {} parse5@7.3.0: @@ -8097,6 +8626,8 @@ snapshots: smob@1.6.1: {} + smol-toml@1.7.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -8167,6 +8698,8 @@ snapshots: dependencies: min-indent: 1.0.1 + strip-json-comments@5.0.3: {} + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 @@ -8249,6 +8782,11 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tinypool@1.1.1: {} tinyrainbow@1.2.0: {} @@ -8281,6 +8819,9 @@ snapshots: optionalDependencies: typescript: 5.9.3 + tslib@2.8.1: + optional: true + tsx@4.21.0: dependencies: esbuild: 0.27.7 @@ -8302,6 +8843,8 @@ snapshots: ultrahtml@1.6.0: {} + unbash@4.0.1: {} + uncrypto@0.1.3: {} unctx@2.5.0: @@ -8415,7 +8958,7 @@ snapshots: util-deprecate@1.0.2: {} - vinxi@0.5.11(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0): + vinxi@0.5.11(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: '@babel/core': 7.29.0 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) @@ -8449,7 +8992,7 @@ snapshots: unctx: 2.5.0 unenv: 1.10.0 unstorage: 1.17.5(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(ioredis@5.10.1) - vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vite: 6.4.2(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) zod: 4.3.6 transitivePeerDependencies: - '@azure/app-configuration' @@ -8497,7 +9040,7 @@ snapshots: - xml2js - yaml - vinxi@0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0): + vinxi@0.5.3(@types/node@25.6.0)(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0))(ioredis@5.10.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: '@babel/core': 7.29.0 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) @@ -8531,7 +9074,7 @@ snapshots: unctx: 2.5.0 unenv: 1.10.0 unstorage: 1.17.5(db0@0.3.4(drizzle-orm@0.40.1(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(gel@2.2.0)))(ioredis@5.10.1) - vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vite: 6.4.2(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) zod: 3.25.76 transitivePeerDependencies: - '@azure/app-configuration' @@ -8619,7 +9162,7 @@ snapshots: lightningcss: 1.32.0 terser: 5.46.1 - vite@6.1.4(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0): + vite@6.1.4(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: esbuild: 0.24.2 postcss: 8.5.10 @@ -8627,12 +9170,13 @@ snapshots: optionalDependencies: '@types/node': 25.6.0 fsevents: 2.3.3 - jiti: 2.6.1 + jiti: 2.7.0 lightningcss: 1.32.0 terser: 5.46.1 tsx: 4.21.0 + yaml: 2.9.0 - vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0): + vite@6.4.2(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.4) @@ -8643,10 +9187,11 @@ snapshots: optionalDependencies: '@types/node': 25.6.0 fsevents: 2.3.3 - jiti: 2.6.1 + jiti: 2.7.0 lightningcss: 1.32.0 terser: 5.46.1 tsx: 4.21.0 + yaml: 2.9.0 vitest@2.1.9(@types/node@25.6.0)(jsdom@26.1.0)(lightningcss@1.32.0)(terser@5.46.1): dependencies: @@ -8688,6 +9233,8 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + walk-up-path@4.0.0: {} + webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {} @@ -8766,6 +9313,8 @@ snapshots: yallist@5.0.0: {} + yaml@2.9.0: {} + yargs-parser@21.1.1: {} yargs-parser@22.0.0: {} diff --git a/scripts/scaffold.mjs b/scripts/scaffold.mjs index f438861..0bb63e0 100644 --- a/scripts/scaffold.mjs +++ b/scripts/scaffold.mjs @@ -169,6 +169,12 @@ pkg.version = "0.1.0"; pkg.scripts = Object.fromEntries( Object.entries(pkg.scripts).filter(([name]) => name !== "scaffold") ); +// The example Hono route (removed in step 7) is the only consumer of +// @hono/zod-validator, so drop it too — otherwise the unused-dependency check +// (knip) fails in the fresh instance. Re-add it when you build a validated route. +pkg.dependencies = Object.fromEntries( + Object.entries(pkg.dependencies).filter(([name]) => name !== "@hono/zod-validator") +); writeJSON(path.join(ROOT, "package.json"), pkg); console.log("✓ package.json updated"); From e300ad9e84b4c0340ddc1aad8c9d12510bf5efa4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Jun 2026 03:18:27 +0000 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20useful=20example=20routes=20?= =?UTF-8?q?=E2=80=94=20health=20check=20+=20removable=20validation=20examp?= =?UTF-8?q?le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reworks the example-route story so the unused-dependency check stays honest without scaffold quietly dropping a dependency. - Add `GET /api/health` (app/server/routes/health.ts), a dependency-free liveness route kept in scaffolded projects - Keep the request-validation example mounted by default (so @hono/zod-validator stays a *used* dependency); split its tests into example.test.ts - Add `scripts/remove-example.mjs` — opt-out that deletes the example route + test, unmounts it, and drops @hono/zod-validator (documented in api.md) - Scaffold no longer strips the server example or drops the dependency Verified end-to-end: template preflight + knip green; a scaffolded instance is knip-green with the example kept; running remove-example.mjs leaves a knip-green, preflight-green instance with only the health route. --- app/server/index.test.ts | 15 ++---- app/server/index.ts | 8 ++- app/server/routes/example.test.ts | 21 ++++++++ app/server/routes/health.ts | 5 ++ changelog.d/42-example-routes.added.md | 1 + docs/agents/api.md | 5 ++ knip.json | 3 +- scripts/remove-example.mjs | 71 ++++++++++++++++++++++++++ scripts/scaffold.mjs | 43 ++-------------- 9 files changed, 119 insertions(+), 53 deletions(-) create mode 100644 app/server/routes/example.test.ts create mode 100644 app/server/routes/health.ts create mode 100644 changelog.d/42-example-routes.added.md create mode 100644 scripts/remove-example.mjs diff --git a/app/server/index.test.ts b/app/server/index.test.ts index e3406eb..ca01716 100644 --- a/app/server/index.test.ts +++ b/app/server/index.test.ts @@ -2,10 +2,10 @@ import { describe, expect, it } from "vitest"; import app from "./index"; describe("api app", () => { - it("serves a mounted route", async () => { - const res = await app.request("/api/example"); + it("serves the health check", async () => { + const res = await app.request("/api/health"); expect(res.status).toBe(200); - expect(await res.json()).toEqual({ message: "Hello from Hono" }); + expect(await res.json()).toEqual({ status: "ok" }); }); it("returns a JSON 404 for unknown routes", async () => { @@ -14,13 +14,4 @@ describe("api app", () => { expect(res.headers.get("content-type")).toContain("application/json"); expect(await res.json()).toEqual({ error: "Not Found" }); }); - - it("validates request bodies (400 on missing field)", async () => { - const res = await app.request("/api/example", { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({}), - }); - expect(res.status).toBe(400); - }); }); diff --git a/app/server/index.ts b/app/server/index.ts index fc67649..4397368 100644 --- a/app/server/index.ts +++ b/app/server/index.ts @@ -1,12 +1,18 @@ import { Hono } from "hono"; import { HTTPException } from "hono/http-exception"; import { exampleRoutes } from "./routes/example"; +import { healthRoutes } from "./routes/health"; // All API routes are mounted under /api // This app is handed off from TanStack Start's catch-all API route const app = new Hono().basePath("/api"); -// Mount route groups here +// Health check — a useful liveness probe. Keep it. +app.route("/health", healthRoutes); + +// Example route demonstrating request validation with @hono/zod-validator. +// Don't need it? Run `node scripts/remove-example.mjs` to delete the route and +// drop the dependency (see docs/agents/api.md). app.route("/example", exampleRoutes); // Consistent JSON for unmatched routes instead of Hono's default text 404. diff --git a/app/server/routes/example.test.ts b/app/server/routes/example.test.ts new file mode 100644 index 0000000..576247c --- /dev/null +++ b/app/server/routes/example.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from "vitest"; +import app from "../index"; + +// Tests for the optional example route. `node scripts/remove-example.mjs` +// deletes this file along with the route it covers. +describe("example route", () => { + it("responds on GET /api/example", async () => { + const res = await app.request("/api/example"); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ message: "Hello from Hono" }); + }); + + it("validates request bodies (400 on missing field)", async () => { + const res = await app.request("/api/example", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({}), + }); + expect(res.status).toBe(400); + }); +}); diff --git a/app/server/routes/health.ts b/app/server/routes/health.ts new file mode 100644 index 0000000..3865c85 --- /dev/null +++ b/app/server/routes/health.ts @@ -0,0 +1,5 @@ +import { Hono } from "hono"; + +// Liveness probe — useful for uptime checks, load balancers, and deploy smoke +// tests. No dependencies and no DB access; always returns 200. +export const healthRoutes = new Hono().get("/", (c) => c.json({ status: "ok" })); diff --git a/changelog.d/42-example-routes.added.md b/changelog.d/42-example-routes.added.md new file mode 100644 index 0000000..9825a6c --- /dev/null +++ b/changelog.d/42-example-routes.added.md @@ -0,0 +1 @@ +- `[propagate]` Added a `GET /api/health` liveness route (kept in scaffolded projects) and made the request-validation example route optional: scaffold no longer strips it, and `node scripts/remove-example.mjs` deletes it plus drops `@hono/zod-validator` for projects that don't want it. diff --git a/docs/agents/api.md b/docs/agents/api.md index 33b1a97..3ab2ac2 100644 --- a/docs/agents/api.md +++ b/docs/agents/api.md @@ -100,6 +100,11 @@ For portable endpoints: webhooks, CRUD, anything consumable outside this fronten `app/server/routes/example.ts` contains a working Hono route group (`exampleRoutes`). Refer to it as the canonical pattern. +The app also mounts a `GET /api/health` liveness route +(`app/server/routes/health.ts`), kept by default. If you don't need the +validation example, run `node scripts/remove-example.mjs` to delete it and drop +`@hono/zod-validator`. + ### Adding a new Hono route group 1. Create `app/server/routes/your-resource.ts` diff --git a/knip.json b/knip.json index 1179233..83acf30 100644 --- a/knip.json +++ b/knip.json @@ -7,7 +7,8 @@ "app/routes/**/*.tsx", "app/server/index.ts", "app.config.ts", - "scripts/labels.mjs" + "scripts/labels.mjs", + "scripts/remove-example.mjs" ], "project": ["app/**/*.{ts,tsx}", "db/**/*.ts", "scripts/*.mjs"], "ignoreDependencies": ["tailwindcss"], diff --git a/scripts/remove-example.mjs b/scripts/remove-example.mjs new file mode 100644 index 0000000..3672d88 --- /dev/null +++ b/scripts/remove-example.mjs @@ -0,0 +1,71 @@ +#!/usr/bin/env node + +/** + * Remove the example Hono route and its dependency. + * + * The template ships a request-validation example at + * `app/server/routes/example.ts` (using `@hono/zod-validator`), mounted at + * `/api/example`, plus a `GET /api/health` route that stays. If your project + * doesn't need the validation example, run this once: + * + * node scripts/remove-example.mjs + * + * It deletes the route and its test, unmounts it from `app/server/index.ts`, + * and drops `@hono/zod-validator` from package.json. Run `pnpm install` after. + */ + +import * as fs from "node:fs"; +import * as path from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(__dirname, ".."); + +const IMPORT_LINE = 'import { exampleRoutes } from "./routes/example";\n'; +const MOUNT_BLOCK = `// Example route demonstrating request validation with @hono/zod-validator. +// Don't need it? Run \`node scripts/remove-example.mjs\` to delete the route and +// drop the dependency (see docs/agents/api.md). +app.route("/example", exampleRoutes);`; + +/** + * Delete the example route + test, unmount it from the server index, and drop + * the `@hono/zod-validator` dependency. Safe to run more than once. + * @returns {string[]} the paths that were removed + */ +export function removeExample() { + const removed = []; + for (const rel of ["app/server/routes/example.ts", "app/server/routes/example.test.ts"]) { + const p = path.join(ROOT, rel); + if (fs.existsSync(p)) { + fs.unlinkSync(p); + removed.push(rel); + } + } + + const indexPath = path.join(ROOT, "app/server/index.ts"); + if (fs.existsSync(indexPath)) { + const index = fs + .readFileSync(indexPath, "utf-8") + .replace(IMPORT_LINE, "") + .replace(MOUNT_BLOCK, "") + .replace(/\n{3,}/g, "\n\n"); + fs.writeFileSync(indexPath, index); + } + + const pkgPath = path.join(ROOT, "package.json"); + const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")); + pkg.dependencies = Object.fromEntries( + Object.entries(pkg.dependencies).filter(([name]) => name !== "@hono/zod-validator") + ); + fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`); + + return removed; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + removeExample(); + console.log( + "✓ Removed the example route and dropped @hono/zod-validator.\n" + + " Run `pnpm install` to update the lockfile." + ); +} diff --git a/scripts/scaffold.mjs b/scripts/scaffold.mjs index 0bb63e0..9a28f2f 100644 --- a/scripts/scaffold.mjs +++ b/scripts/scaffold.mjs @@ -169,12 +169,6 @@ pkg.version = "0.1.0"; pkg.scripts = Object.fromEntries( Object.entries(pkg.scripts).filter(([name]) => name !== "scaffold") ); -// The example Hono route (removed in step 7) is the only consumer of -// @hono/zod-validator, so drop it too — otherwise the unused-dependency check -// (knip) fails in the fresh instance. Re-add it when you build a validated route. -pkg.dependencies = Object.fromEntries( - Object.entries(pkg.dependencies).filter(([name]) => name !== "@hono/zod-validator") -); writeJSON(path.join(ROOT, "package.json"), pkg); console.log("✓ package.json updated"); @@ -252,39 +246,10 @@ console.log("✓ .construct metadata written"); removeFile(path.join(ROOT, "TEMPLATE.md")); console.log("✓ TEMPLATE.md removed"); -// 7. Remove example Hono route (and its test) and clean up server index. -// Keep the handler block below in sync with app/server/index.ts. -removeFile(path.join(ROOT, "app/server/routes/example.ts")); -removeFile(path.join(ROOT, "app/server/index.test.ts")); -const serverIndex = `import { Hono } from "hono"; -import { HTTPException } from "hono/http-exception"; - -// Mount your route groups here -// import { yourRoutes } from "./routes/your-resource"; - -const app = new Hono().basePath("/api"); - -// app.route("/your-resource", yourRoutes); - -// Consistent JSON for unmatched routes instead of Hono's default text 404. -app.notFound((c) => c.json({ error: "Not Found" }, 404)); - -// Centralized error handling. Honor intentional HTTPExceptions; otherwise log -// and return a generic 500 without leaking internals (e.g. stack traces). -app.onError((err, c) => { - if (err instanceof HTTPException) { - return err.getResponse(); - } - console.error(err); - return c.json({ error: "Internal Server Error" }, 500); -}); - -export type AppType = typeof app; - -export default app; -`; -writeFile(path.join(ROOT, "app/server/index.ts"), serverIndex); -console.log("✓ Example routes cleaned up"); +// 7. Server example routes are intentionally kept. The instance ships with a +// useful GET /api/health route plus a request-validation example. Users who +// don't want the validation example (and its @hono/zod-validator dependency) +// can run `node scripts/remove-example.mjs` (see docs/agents/api.md). // 8. Substitute project name into AGENTS.md const agentsPath = path.join(ROOT, "AGENTS.md"); From f4eb1f429c37f7c4def60ad18e6fc07b272cb47b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Jun 2026 03:41:11 +0000 Subject: [PATCH 3/3] test: use user-event via a Counter example; jest-dom/vitest entry Instead of dropping @testing-library/user-event for being unused, demonstrate it so it's a genuinely-used dependency. - Add an interactive `Counter` example component + `Counter.test.tsx` that simulates a real click with @testing-library/user-event - Switch tests/setup.ts to the Vitest-specific jest-dom entry (`@testing-library/jest-dom/vitest`) - Restores @testing-library/user-event to devDependencies Verified: knip green (user-event now used), preflight green (44 tests incl. the Counter click test); scaffolded instance keeps Counter + user-event, knip green. --- app/components/Counter.test.tsx | 15 +++++++++++++++ app/components/Counter.tsx | 13 +++++++++++++ changelog.d/42-testing-example.added.md | 1 + changelog.d/42-user-event.removed.md | 1 - package.json | 1 + pnpm-lock.yaml | 13 +++++++++++++ tests/setup.ts | 2 +- 7 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 app/components/Counter.test.tsx create mode 100644 app/components/Counter.tsx create mode 100644 changelog.d/42-testing-example.added.md delete mode 100644 changelog.d/42-user-event.removed.md diff --git a/app/components/Counter.test.tsx b/app/components/Counter.test.tsx new file mode 100644 index 0000000..91f851a --- /dev/null +++ b/app/components/Counter.test.tsx @@ -0,0 +1,15 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it } from "vitest"; +import { Counter } from "./Counter"; + +describe("Counter", () => { + it("increments when the button is clicked", async () => { + const user = userEvent.setup(); + render(); + + expect(screen.getByRole("button", { name: /count: 0/i })).toBeInTheDocument(); + await user.click(screen.getByRole("button")); + expect(screen.getByRole("button", { name: /count: 1/i })).toBeInTheDocument(); + }); +}); diff --git a/app/components/Counter.tsx b/app/components/Counter.tsx new file mode 100644 index 0000000..6577e05 --- /dev/null +++ b/app/components/Counter.tsx @@ -0,0 +1,13 @@ +import { useState } from "react"; + +// Example interactive component — demonstrates local state and a click handler. +// Its test (Counter.test.tsx) is the canonical `@testing-library/user-event` +// example: simulate a real click and assert the result. +export function Counter() { + const [count, setCount] = useState(0); + return ( + + ); +} diff --git a/changelog.d/42-testing-example.added.md b/changelog.d/42-testing-example.added.md new file mode 100644 index 0000000..82820cd --- /dev/null +++ b/changelog.d/42-testing-example.added.md @@ -0,0 +1 @@ +- `[propagate]` Added an interactive `Counter` example component with a `@testing-library/user-event` test, demonstrating the full Testing Library + Vitest flow (render → real click → assert). Switched the jest-dom setup import to the Vitest-specific entry (`@testing-library/jest-dom/vitest`). diff --git a/changelog.d/42-user-event.removed.md b/changelog.d/42-user-event.removed.md deleted file mode 100644 index ce18b30..0000000 --- a/changelog.d/42-user-event.removed.md +++ /dev/null @@ -1 +0,0 @@ -- `[propagate]` Removed `@testing-library/user-event`, which the new unused-dependency check flagged as declared but imported nowhere. diff --git a/package.json b/package.json index 00941a3..52f7d0e 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "@tanstack/router-cli": "~1.114.3", "@testing-library/jest-dom": "^6.6.0", "@testing-library/react": "^16.2.0", + "@testing-library/user-event": "^14.6.1", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^4.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70d80ad..a0aa4c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,6 +90,9 @@ importers: '@testing-library/react': specifier: ^16.2.0 version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@testing-library/user-event': + specifier: ^14.6.1 + version: 14.6.1(@testing-library/dom@10.4.1) '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -2255,6 +2258,12 @@ packages: '@types/react-dom': optional: true + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -6631,6 +6640,10 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + dependencies: + '@testing-library/dom': 10.4.1 + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 diff --git a/tests/setup.ts b/tests/setup.ts index d0de870..f149f27 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -1 +1 @@ -import "@testing-library/jest-dom"; +import "@testing-library/jest-dom/vitest";