deps: bump Tier-A patches + react-day-picker 10 + esbuild 0.28

Successfully bumped:
- bullmq 5.76.6 → 5.76.8
- @tanstack/react-query 5.100.9 → 5.100.10
- @tanstack/react-query-devtools 5.100.9 → 5.100.10
- better-auth 1.6.9 → 1.6.10
- @playwright/test 1.59.1 → 1.60.0
- libphonenumber-js 1.12.43 → 1.13.1
- tailwind-merge 3.5.0 → 3.6.0
- vitest 4.1.5 → 4.1.6
- @vitest/coverage-v8 4.1.5 → 4.1.6
- lint-staged 17.0.3 → 17.0.4
- esbuild 0.27.7 → 0.28.0
- react-grab 0.1.33 → 0.1.34
- react-day-picker 9.14.0 → 10.0.0

react-day-picker 10 verified safe: probed v10 release notes against
src/components/ui/calendar.tsx — we use only v9-canonical APIs that
v10 preserves. Removed the `table` className entry from the wrapper
(v10 dropped it since the renderer is now CSS-grid, not table-based).

Tried + rolled back:
- @hookform/resolvers 3 → 5: stricter input/output inference broke
  every form using <{schema}, any, {schema}> implicit shape. Needs
  per-form refactor; parked.

Verified clean: pnpm audit (prod + dev) = 0 vulnerabilities;
pnpm exec tsc --noEmit clean; vitest 1293/1293 pass.

Remaining outdated (deliberately deferred — see docs/AUDIT-2026-05-12.md §34):
- next/eslint-config-next 15 → 16 (2-4 wk wait)
- zod 3 → 4 (couple with @hookform/resolvers 5; codemod-needed)
- tailwindcss 3 → 4 (focused-afternoon project)
- @types/node ^20.19 stays pinned to match runtime (audit decision)
- archiver 7 stays (no @types/archiver@8 published)
- eslint 9 stays (locked to eslint-config-next 15)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 17:33:24 +02:00
parent a7d0dd95e2
commit 82049eea92
5 changed files with 365 additions and 382 deletions

View File

@@ -6529,26 +6529,26 @@ major in?" prioritization.
## At a glance — what's outdated ## At a glance — what's outdated
| Package | Current | Latest | Bump size | | Package | Current | Latest | Bump size |
|---|---|---|---| | ----------------------- | ------- | -------- | --------------------------------- |
| `next` | 15.5.18 | 16.2.6 | major | | `next` | 15.5.18 | 16.2.6 | major |
| `eslint-config-next` | 15.5.18 | 16.2.6 | major (matches next) | | `eslint-config-next` | 15.5.18 | 16.2.6 | major (matches next) |
| `zod` | 3.25.76 | 4.4.3 | major | | `zod` | 3.25.76 | 4.4.3 | major |
| `tailwindcss` | 3.4.19 | 4.3.0 | major | | `tailwindcss` | 3.4.19 | 4.3.0 | major |
| `@hookform/resolvers` | 3.10.0 | 5.2.2 | TWO majors | | `@hookform/resolvers` | 3.10.0 | 5.2.2 | TWO majors |
| `archiver` | 7.0.1 | 8.0.0 | major | | `archiver` | 7.0.1 | 8.0.0 | major |
| `react-day-picker` | 9.14.0 | 10.0.0 | major | | `react-day-picker` | 9.14.0 | 10.0.0 | major |
| `eslint` | 9.39.4 | 10.3.0 | major | | `eslint` | 9.39.4 | 10.3.0 | major |
| `esbuild` | 0.27.7 | 0.28.0 | pre-1.0 minor (effectively major) | | `esbuild` | 0.27.7 | 0.28.0 | pre-1.0 minor (effectively major) |
| `@playwright/test` | 1.59.1 | 1.60.0 | minor | | `@playwright/test` | 1.59.1 | 1.60.0 | minor |
| `libphonenumber-js` | 1.12.43 | 1.13.1 | minor | | `libphonenumber-js` | 1.12.43 | 1.13.1 | minor |
| `tailwind-merge` | 3.5.0 | 3.6.0 | minor | | `tailwind-merge` | 3.5.0 | 3.6.0 | minor |
| `bullmq` | 5.76.6 | 5.76.8 | patch | | `bullmq` | 5.76.6 | 5.76.8 | patch |
| `@tanstack/react-query` | 5.100.9 | 5.100.10 | patch | | `@tanstack/react-query` | 5.100.9 | 5.100.10 | patch |
| `better-auth` | 1.6.9 | 1.6.10 | patch | | `better-auth` | 1.6.9 | 1.6.10 | patch |
| `vitest` | 4.1.5 | 4.1.6 | patch | | `vitest` | 4.1.5 | 4.1.6 | patch |
| `lint-staged` | 17.0.3 | 17.0.4 | patch | | `lint-staged` | 17.0.3 | 17.0.4 | patch |
| `@vitest/coverage-v8` | 4.1.5 | 4.1.6 | patch | | `@vitest/coverage-v8` | 4.1.5 | 4.1.6 | patch |
`@types/node` deliberately pinned to ^20.19 to match Node 20 runtime `@types/node` deliberately pinned to ^20.19 to match Node 20 runtime
(audit findings — was previously ^25 against a Node 20 runtime, which (audit findings — was previously ^25 against a Node 20 runtime, which
@@ -6571,7 +6571,7 @@ verify and full vitest run.
## Tier B — Per-major analysis ## Tier B — Per-major analysis
### B-1 — Next.js 15.5 → 16.2 *(touches every API route + middleware)* ### B-1 — Next.js 15.5 → 16.2 _(touches every API route + middleware)_
**Upstream summary (via Context7):** **Upstream summary (via Context7):**
@@ -6580,6 +6580,7 @@ verify and full vitest run.
- Automated codemod: `npx @next/codemod@canary upgrade latest` handles the rename + most boilerplate. - Automated codemod: `npx @next/codemod@canary upgrade latest` handles the rename + most boilerplate.
**Risk for us:** **Risk for us:**
- `src/middleware.ts` rename is a 30-second edit; no semantic change for us because we don't depend on edge runtime. - `src/middleware.ts` rename is a 30-second edit; no semantic change for us because we don't depend on edge runtime.
- The Documenso webhook + websocket server custom-server path (`src/server.ts`) needs to be retested — Next 16 changed some internals around the custom-server contract. - The Documenso webhook + websocket server custom-server path (`src/server.ts`) needs to be retested — Next 16 changed some internals around the custom-server contract.
- `eslint-config-next` must bump in lockstep (already at 15.5.18 → 16.2.6). - `eslint-config-next` must bump in lockstep (already at 15.5.18 → 16.2.6).
@@ -6589,7 +6590,7 @@ verify and full vitest run.
--- ---
### B-2 — Zod 3 → 4 *(touches every validator file)* ### B-2 — Zod 3 → 4 _(touches every validator file)_
**Upstream summary (via Context7):** **Upstream summary (via Context7):**
@@ -6600,6 +6601,7 @@ verify and full vitest run.
- TypeScript server perf improvement (generic-class-signature simplification). - TypeScript server perf improvement (generic-class-signature simplification).
**Risk for us:** **Risk for us:**
- We have ~30 validator files using `z.string().email()` / `.uuid()` style and `{ message: '...' }` style throughout. Both still work in 4.x but produce deprecation warnings on every parse — noisy in logs. - We have ~30 validator files using `z.string().email()` / `.uuid()` style and `{ message: '...' }` style throughout. Both still work in 4.x but produce deprecation warnings on every parse — noisy in logs.
- `@hookform/resolvers` v5 supports **both** Zod 3 and Zod 4 natively (auto-detects), so this couples cleanly with B-4 below. - `@hookform/resolvers` v5 supports **both** Zod 3 and Zod 4 natively (auto-detects), so this couples cleanly with B-4 below.
- We don't use `z.function()` anywhere, so the biggest breaking change is a non-issue for us. - We don't use `z.function()` anywhere, so the biggest breaking change is a non-issue for us.
@@ -6608,7 +6610,7 @@ verify and full vitest run.
--- ---
### B-3 — Tailwind CSS 3 → 4 *(touches `tailwind.config.ts`, `globals.css`, every dynamic-class site)* ### B-3 — Tailwind CSS 3 → 4 _(touches `tailwind.config.ts`, `globals.css`, every dynamic-class site)_
**Upstream summary (via Context7):** **Upstream summary (via Context7):**
@@ -6619,6 +6621,7 @@ verify and full vitest run.
- Official automated upgrade tool: `npx @tailwindcss/upgrade` (requires Node 20+, which we already use). - Official automated upgrade tool: `npx @tailwindcss/upgrade` (requires Node 20+, which we already use).
**Risk for us:** **Risk for us:**
- We have a custom `tailwind.config.ts` with brand tokens, CVA + tailwind-merge + clsx, plus the `tailwindcss-animate` plugin. The upgrade tool migrates most of this automatically; the manual review is the design-token spread across `globals.css`. - We have a custom `tailwind.config.ts` with brand tokens, CVA + tailwind-merge + clsx, plus the `tailwindcss-animate` plugin. The upgrade tool migrates most of this automatically; the manual review is the design-token spread across `globals.css`.
- shadcn/ui components (`components/ui/*`) use `cn()` + arbitrary values heavily. Some `[--variable]` syntax has changed in v4. - shadcn/ui components (`components/ui/*`) use `cn()` + arbitrary values heavily. Some `[--variable]` syntax has changed in v4.
- `tailwindcss-animate` may not yet support v4 — need to confirm or swap for `tailwindcss-animated` (the v4 successor). - `tailwindcss-animate` may not yet support v4 — need to confirm or swap for `tailwindcss-animated` (the v4 successor).
@@ -6627,7 +6630,7 @@ verify and full vitest run.
--- ---
### B-4 — `@hookform/resolvers` 3 → 5 *(touches every form file)* ### B-4 — `@hookform/resolvers` 3 → 5 _(touches every form file)_
**Upstream summary (via Context7):** **Upstream summary (via Context7):**
@@ -6636,17 +6639,19 @@ verify and full vitest run.
- v4 was a transitional version with the same external API; v5 is the stable cut. - v4 was a transitional version with the same external API; v5 is the stable cut.
**Risk for us:** **Risk for us:**
- Coupled with the Zod 4 upgrade — if we stay on Zod 3, v5 still works (the resolver detects Zod-3 schemas via shape probing). Bumping resolvers without bumping Zod is safe. - Coupled with the Zod 4 upgrade — if we stay on Zod 3, v5 still works (the resolver detects Zod-3 schemas via shape probing). Bumping resolvers without bumping Zod is safe.
**Recommended:** **GO IN LOCKSTEP with B-2 (Zod 4).** Effort: 5 min once Zod 4 is in. **Recommended:** **GO IN LOCKSTEP with B-2 (Zod 4).** Effort: 5 min once Zod 4 is in.
--- ---
### B-5 — `archiver` 7 → 8 *(touches GDPR-export bundle + backup-restore)* ### B-5 — `archiver` 7 → 8 _(touches GDPR-export bundle + backup-restore)_
**Upstream summary:** Library "/gajus/archiver" not found in Context7 — fallback to npm changelog. We previously rolled back archiver@8 to archiver@7 (in commit `04a5949` per CLAUDE.md history) because of dropped default-export changes that broke our TS types. v8 stabilised since then. **Upstream summary:** Library "/gajus/archiver" not found in Context7 — fallback to npm changelog. We previously rolled back archiver@8 to archiver@7 (in commit `04a5949` per CLAUDE.md history) because of dropped default-export changes that broke our TS types. v8 stabilised since then.
**Risk for us:** **Risk for us:**
- Last time we tried this it broke. Read the v8 changelog before retrying. - Last time we tried this it broke. Read the v8 changelog before retrying.
- Used only for GDPR export + backup-restore — narrow blast radius. A failed upgrade is non-customer-facing. - Used only for GDPR export + backup-restore — narrow blast radius. A failed upgrade is non-customer-facing.
@@ -6654,20 +6659,22 @@ verify and full vitest run.
--- ---
### B-6 — `react-day-picker` 9 → 10 *(touches every date-picker site)* ### B-6 — `react-day-picker` 9 → 10 _(touches every date-picker site)_
**Upstream summary:** v10 is a recent cut. Without Context7 returning a hit on its changelog, treat as "investigate before pulling". **Upstream summary:** v10 is a recent cut. Without Context7 returning a hit on its changelog, treat as "investigate before pulling".
**Risk for us:** **Risk for us:**
- Used in ~6 surfaces (reminder form, EOI date fields, expense date, invoice due-date, dashboard date-range picker). A breaking change to the calendar render path would affect every form. - Used in ~6 surfaces (reminder form, EOI date fields, expense date, invoice due-date, dashboard date-range picker). A breaking change to the calendar render path would affect every form.
**Recommended:** **DEFER 2-3 weeks** to let bug reports surface. Effort to actually do it: ~1h once the spec is reviewed. **Recommended:** **DEFER 2-3 weeks** to let bug reports surface. Effort to actually do it: ~1h once the spec is reviewed.
--- ---
### B-7 — `eslint` 9 → 10 + `eslint-config-next` *(touches CI)* ### B-7 — `eslint` 9 → 10 + `eslint-config-next` _(touches CI)_
**Risk for us:** **Risk for us:**
- ESLint 10 likely drops support for some legacy rule configs. - ESLint 10 likely drops support for some legacy rule configs.
- `eslint-config-next` should bump in lockstep with `next` (B-1). - `eslint-config-next` should bump in lockstep with `next` (B-1).
@@ -6675,9 +6682,10 @@ verify and full vitest run.
--- ---
### B-8 — `esbuild` 0.27 → 0.28 *(touches build pipeline)* ### B-8 — `esbuild` 0.27 → 0.28 _(touches build pipeline)_
**Risk for us:** **Risk for us:**
- We use esbuild via `pnpm.overrides` plus directly in `build:server` and `build:worker` scripts. - We use esbuild via `pnpm.overrides` plus directly in `build:server` and `build:worker` scripts.
- Pre-1.0 minors at esbuild are typically very safe (Evan Wallace ships tight changelogs), but they do occasionally drop deprecated flags. - Pre-1.0 minors at esbuild are typically very safe (Evan Wallace ships tight changelogs), but they do occasionally drop deprecated flags.

View File

@@ -56,13 +56,13 @@
"@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-tooltip": "^1.2.8",
"@socket.io/redis-adapter": "^8.3.0", "@socket.io/redis-adapter": "^8.3.0",
"@tanstack/react-query": "^5.100.9", "@tanstack/react-query": "^5.100.10",
"@tanstack/react-query-devtools": "^5.100.9", "@tanstack/react-query-devtools": "^5.100.10",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@types/pdfkit": "^0.17.6", "@types/pdfkit": "^0.17.6",
"archiver": "^7.0.1", "archiver": "^7.0.1",
"better-auth": "^1.6.9", "better-auth": "^1.6.10",
"bullmq": "^5.76.6", "bullmq": "^5.76.8",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
@@ -72,7 +72,7 @@
"ioredis": "^5.10.1", "ioredis": "^5.10.1",
"iso-3166-2": "^1.0.0", "iso-3166-2": "^1.0.0",
"jose": "^6.2.3", "jose": "^6.2.3",
"libphonenumber-js": "^1.12.43", "libphonenumber-js": "^1.13.1",
"lucide-react": "^1.14.0", "lucide-react": "^1.14.0",
"mailparser": "^3.9.8", "mailparser": "^3.9.8",
"minio": "^8.0.7", "minio": "^8.0.7",
@@ -86,7 +86,7 @@
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
"postgres": "^3.4.9", "postgres": "^3.4.9",
"react": "^19.2.6", "react": "^19.2.6",
"react-day-picker": "^9.14.0", "react-day-picker": "^10.0.0",
"react-dom": "^19.2.6", "react-dom": "^19.2.6",
"react-easy-crop": "^5.5.7", "react-easy-crop": "^5.5.7",
"react-hook-form": "^7.75.0", "react-hook-form": "^7.75.0",
@@ -95,7 +95,7 @@
"socket.io": "^4.8.3", "socket.io": "^4.8.3",
"socket.io-client": "^4.8.3", "socket.io-client": "^4.8.3",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwind-merge": "^3.5.0", "tailwind-merge": "^3.6.0",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"tesseract.js": "^7.0.0", "tesseract.js": "^7.0.0",
"vaul": "^1.1.2", "vaul": "^1.1.2",
@@ -104,7 +104,7 @@
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.3.5", "@eslint/eslintrc": "^3.3.5",
"@playwright/test": "^1.59.1", "@playwright/test": "^1.60.0",
"@types/archiver": "^7.0.0", "@types/archiver": "^7.0.0",
"@types/iso-3166-2": "^1.0.4", "@types/iso-3166-2": "^1.0.4",
"@types/mailparser": "^3.4.6", "@types/mailparser": "^3.4.6",
@@ -112,23 +112,23 @@
"@types/nodemailer": "^8.0.0", "@types/nodemailer": "^8.0.0",
"@types/react": "^19.2.14", "@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@vitest/coverage-v8": "^4.1.5", "@vitest/coverage-v8": "^4.1.6",
"autoprefixer": "^10.5.0", "autoprefixer": "^10.5.0",
"dotenv": "^17.4.2", "dotenv": "^17.4.2",
"drizzle-kit": "^0.31.10", "drizzle-kit": "^0.31.10",
"esbuild": "^0.27.7", "esbuild": "^0.28.0",
"eslint": "^9.39.4", "eslint": "^9.39.4",
"eslint-config-next": "15.5.18", "eslint-config-next": "15.5.18",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"husky": "^9.1.7", "husky": "^9.1.7",
"lint-staged": "^17.0.3", "lint-staged": "^17.0.4",
"postcss": "^8.5.14", "postcss": "^8.5.14",
"prettier": "^3.8.3", "prettier": "^3.8.3",
"react-grab": "^0.1.33", "react-grab": "^0.1.34",
"tailwindcss": "^3.4.19", "tailwindcss": "^3.4.19",
"tsx": "^4.21.0", "tsx": "^4.21.0",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"vitest": "^4.1.5" "vitest": "^4.1.6"
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {

630
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -73,7 +73,6 @@ function Calendar({
: '[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5', : '[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5',
defaultClassNames.caption_label, defaultClassNames.caption_label,
), ),
table: 'w-full border-collapse',
weekdays: cn('flex', defaultClassNames.weekdays), weekdays: cn('flex', defaultClassNames.weekdays),
weekday: cn( weekday: cn(
'text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal', 'text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal',
@@ -85,6 +84,10 @@ function Calendar({
'text-muted-foreground select-none text-[0.8rem]', 'text-muted-foreground select-none text-[0.8rem]',
defaultClassNames.week_number, defaultClassNames.week_number,
), ),
// NB: the 'table' className was removed in react-day-picker 10 —
// the renderer is now CSS-grid based, so the table-derived class
// doesn't apply. shadcn's older Calendar wrapper had it; we drop
// it on the v10 bump.
day: cn( day: cn(
'group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md', 'group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md',
defaultClassNames.day, defaultClassNames.day,

View File

@@ -1,12 +1,7 @@
import { and, asc, eq } from 'drizzle-orm'; import { and, asc, eq } from 'drizzle-orm';
import { db } from '@/lib/db'; import { db } from '@/lib/db';
import { import { documentFolders, documents, files, type DocumentFolder } from '@/lib/db/schema/documents';
documentFolders,
documents,
files,
type DocumentFolder,
} from '@/lib/db/schema/documents';
import { clients } from '@/lib/db/schema/clients'; import { clients } from '@/lib/db/schema/clients';
import { companies } from '@/lib/db/schema/companies'; import { companies } from '@/lib/db/schema/companies';
import { yachts } from '@/lib/db/schema/yachts'; import { yachts } from '@/lib/db/schema/yachts';
@@ -231,10 +226,7 @@ export async function moveFolder(
return await db.transaction(async (tx) => { return await db.transaction(async (tx) => {
if (newParentId !== null) { if (newParentId !== null) {
const newParent = await tx.query.documentFolders.findFirst({ const newParent = await tx.query.documentFolders.findFirst({
where: and( where: and(eq(documentFolders.id, newParentId), eq(documentFolders.portId, portId)),
eq(documentFolders.id, newParentId),
eq(documentFolders.portId, portId),
),
}); });
if (!newParent) throw new ValidationError('Invalid parent folder'); if (!newParent) throw new ValidationError('Invalid parent folder');
@@ -245,9 +237,7 @@ export async function moveFolder(
const seen = new Set<string>([newParent.id]); const seen = new Set<string>([newParent.id]);
while (cursor) { while (cursor) {
if (cursor === folderId) { if (cursor === folderId) {
throw new ValidationError( throw new ValidationError('Cannot move a folder under one of its descendants (cycle)');
'Cannot move a folder under one of its descendants (cycle)',
);
} }
if (seen.has(cursor)) break; // defensive — pre-existing cycle, bail if (seen.has(cursor)) break; // defensive — pre-existing cycle, bail
seen.add(cursor); seen.add(cursor);
@@ -628,7 +618,11 @@ export async function syncEntityFolderName(
entityId: folder.id, entityId: folder.id,
oldValue: { name: folder.name }, oldValue: { name: folder.name },
newValue: { name: candidate }, newValue: { name: candidate },
metadata: { type: 'folder_entity_rename_sync', entity: entityType, sourceEntityId: entityId }, metadata: {
type: 'folder_entity_rename_sync',
entity: entityType,
sourceEntityId: entityId,
},
}); });
return; return;
} }