From dbf55badf661b52ff5c25083b137cb4d2759f173 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 27 Oct 2025 09:49:16 -0500 Subject: [PATCH] Optimize Next.js 16 behavior (#349) * Remove unused desktop redirect component * Tweak useEffect/setState interactions * Address more next.js 16 linting * Tweak secret loading * Finish linting setstate/useeffect interactions * Disable ref lint warnings --- eslint.config.mjs | 2 - package.json | 21 +- pnpm-lock.yaml | 724 +++++++++--------- middleware.ts => proxy.ts | 2 +- src/admin/AdminNavClient.tsx | 5 +- src/admin/config/AdminAppConfiguration.tsx | 5 +- .../config/AdminAppConfigurationClient.tsx | 5 +- .../config/AdminAppConfigurationServer.tsx | 4 + src/admin/select/SelectPhotosProvider.tsx | 16 +- src/app/AppState.ts | 2 +- src/app/AppStateProvider.tsx | 10 +- src/app/SecretGenerator.tsx | 14 +- src/app/ThemeSwitcher.tsx | 20 +- src/components/AnimateItems.tsx | 7 +- src/components/RedirectOnDesktop.tsx | 33 - src/components/ResponsiveDate.tsx | 10 +- src/components/SelectMenu.tsx | 1 + src/components/TagInput.tsx | 1 + src/components/image/ImageWithFallback.tsx | 1 + src/components/og/OGLoaderImage.tsx | 1 + .../primitives/PathLoaderButton.tsx | 1 + src/components/switcher/SwitcherItem.tsx | 4 +- src/photo/ai/useTitleCaptionAiImageQuery.ts | 1 + src/photo/cache.ts | 20 +- .../form/ApplyRecipesGloballyCheckbox.tsx | 1 + src/photo/form/PhotoForm.tsx | 3 +- src/place/PlaceInput.tsx | 1 + src/utility/useClientSearchParams.ts | 6 +- src/utility/useHash.ts | 5 +- src/utility/useIsDesktop.ts | 20 - src/utility/useSupportsHover.ts | 12 +- tsconfig.json | 2 +- 32 files changed, 465 insertions(+), 495 deletions(-) rename middleware.ts => proxy.ts (95%) delete mode 100644 src/components/RedirectOnDesktop.tsx delete mode 100644 src/utility/useIsDesktop.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index 73d03b69..ced8685e 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -18,9 +18,7 @@ const eslintConfig = defineConfig([ '@stylistic': stylistic, }, rules: { - // Temporarily disable during Next.js 16 migration 'react-hooks/refs': 'off', - 'react-hooks/set-state-in-effect': 'warn', '@next/next/no-img-element': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-require-imports': 'off', diff --git a/package.json b/package.json index 6b227288..52099e69 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "exif-photo-blog", "scripts": { - "dev": "next dev --turbopack", + "dev": "next dev", "build": "next build", "start": "next start", "lint": "eslint .", @@ -10,8 +10,8 @@ }, "packageManager": "pnpm@10.19.0", "dependencies": { - "@ai-sdk/openai": "^2.0.53", - "@ai-sdk/rsc": "^1.0.79", + "@ai-sdk/openai": "^2.0.54", + "@ai-sdk/rsc": "^1.0.81", "@aws-sdk/client-s3": "3.917.0", "@aws-sdk/s3-request-presigner": "3.917.0", "@radix-ui/react-dialog": "^1.1.15", @@ -24,7 +24,7 @@ "@vercel/analytics": "^1.5.0", "@vercel/blob": "^2.0.0", "@vercel/speed-insights": "^1.2.0", - "ai": "^5.0.79", + "ai": "^5.0.81", "camelcase-keys": "^10.0.0", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -37,14 +37,14 @@ "fast-deep-equal": "^3.1.3", "framer-motion": "^12.23.24", "nanoid": "^5.1.6", - "next": "15.5.5", + "next": "16.0.0", "next-auth": "5.0.0-beta.29", "next-themes": "^0.4.6", "ol": "^10.6.1", "pg": "^8.16.3", "piexifjs": "^1.0.6", - "react": "19.1.1", - "react-dom": "19.1.1", + "react": "19.2.0", + "react-dom": "19.2.0", "react-icons": "^5.5.0", "react-openlayers": "^10.5.1", "sanitize-html": "^2.17.0", @@ -58,8 +58,8 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.3.1", - "@next/bundle-analyzer": "15.5.5", - "@next/eslint-plugin-next": "15.5.5", + "@next/bundle-analyzer": "16.0.0", + "@next/eslint-plugin-next": "16.0.0", "@stylistic/eslint-plugin": "^5.5.0", "@tailwindcss/postcss": "^4.1.16", "@testing-library/dom": "^10.4.1", @@ -74,8 +74,7 @@ "@types/sanitize-html": "^2.16.0", "cross-fetch": "^4.1.0", "eslint": "9.38.0", - "eslint-config-next": "15.5.5", - "eslint-plugin-react-hooks": "^7.0.1", + "eslint-config-next": "16.0.0", "jest": "^30.2.0", "jest-environment-jsdom": "^30.2.0", "postcss": "8.5.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f98a6e2..ae90efcc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: dependencies: '@ai-sdk/openai': - specifier: ^2.0.53 - version: 2.0.53(zod@4.1.12) + specifier: ^2.0.54 + version: 2.0.54(zod@4.1.12) '@ai-sdk/rsc': - specifier: ^1.0.79 - version: 1.0.79(react@19.1.1)(zod@4.1.12) + specifier: ^1.0.81 + version: 1.0.81(react@19.2.0)(zod@4.1.12) '@aws-sdk/client-s3': specifier: 3.917.0 version: 3.917.0 @@ -22,16 +22,16 @@ importers: version: 3.917.0 '@radix-ui/react-dialog': specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 - version: 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-tooltip': specifier: ^1.2.8 - version: 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-visually-hidden': specifier: ^1.2.3 - version: 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/piexifjs': specifier: ^1.0.0 version: 1.0.0 @@ -43,16 +43,16 @@ importers: version: 1.35.6 '@vercel/analytics': specifier: ^1.5.0 - version: 1.5.0(next@15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) + version: 1.5.0(next@16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) '@vercel/blob': specifier: ^2.0.0 version: 2.0.0 '@vercel/speed-insights': specifier: ^1.2.0 - version: 1.2.0(next@15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) + version: 1.2.0(next@16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) ai: - specifier: ^5.0.79 - version: 5.0.79(zod@4.1.12) + specifier: ^5.0.81 + version: 5.0.81(zod@4.1.12) camelcase-keys: specifier: ^10.0.0 version: 10.0.0 @@ -61,7 +61,7 @@ importers: version: 2.1.1 cmdk: specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 1.1.1(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) culori: specifier: ^4.0.2 version: 4.0.2 @@ -85,19 +85,19 @@ importers: version: 3.1.3 framer-motion: specifier: ^12.23.24 - version: 12.23.24(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) nanoid: specifier: ^5.1.6 version: 5.1.6 next: - specifier: 15.5.5 - version: 15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + specifier: 16.0.0 + version: 16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) next-auth: specifier: 5.0.0-beta.29 - version: 5.0.0-beta.29(next@15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) + version: 5.0.0-beta.29(next@16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) next-themes: specifier: ^0.4.6 - version: 0.4.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) ol: specifier: ^10.6.1 version: 10.6.1 @@ -108,17 +108,17 @@ importers: specifier: ^1.0.6 version: 1.0.6 react: - specifier: 19.1.1 - version: 19.1.1 + specifier: 19.2.0 + version: 19.2.0 react-dom: - specifier: 19.1.1 - version: 19.1.1(react@19.1.1) + specifier: 19.2.0 + version: 19.2.0(react@19.2.0) react-icons: specifier: ^5.5.0 - version: 5.5.0(react@19.1.1) + version: 5.5.0(react@19.2.0) react-openlayers: specifier: ^10.5.1 - version: 10.5.1(ol@10.6.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 10.5.1(ol@10.6.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) sanitize-html: specifier: ^2.17.0 version: 2.17.0 @@ -127,16 +127,16 @@ importers: version: 0.34.4 sonner: specifier: ^2.0.7 - version: 2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) swr: specifier: ^2.3.6 - version: 2.3.6(react@19.1.1) + version: 2.3.6(react@19.2.0) ts-exif-parser: specifier: ^0.2.2 version: 0.2.2 use-debounce: specifier: ^10.0.6 - version: 10.0.6(react@19.1.1) + version: 10.0.6(react@19.2.0) viewerjs: specifier: ^1.11.7 version: 1.11.7 @@ -148,11 +148,11 @@ importers: specifier: ^3.3.1 version: 3.3.1 '@next/bundle-analyzer': - specifier: 15.5.5 - version: 15.5.5 + specifier: 16.0.0 + version: 16.0.0 '@next/eslint-plugin-next': - specifier: 15.5.5 - version: 15.5.5 + specifier: 16.0.0 + version: 16.0.0 '@stylistic/eslint-plugin': specifier: ^5.5.0 version: 5.5.0(eslint@9.38.0(jiti@2.6.1)) @@ -167,7 +167,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.3.0 - version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/culori': specifier: ^4.0.1 version: 4.0.1 @@ -196,11 +196,8 @@ importers: specifier: 9.38.0 version: 9.38.0(jiti@2.6.1) eslint-config-next: - specifier: 15.5.5 - version: 15.5.5(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-hooks: - specifier: ^7.0.1 - version: 7.0.1(eslint@9.38.0(jiti@2.6.1)) + specifier: 16.0.0 + version: 16.0.0(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) jest: specifier: ^30.2.0 version: 30.2.0(@types/node@24.9.1)(ts-node@10.9.2(@types/node@24.9.1)(typescript@5.9.3)) @@ -225,20 +222,20 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@ai-sdk/gateway@2.0.1': - resolution: {integrity: sha512-vPVIbnP35ZnayS937XLo85vynR85fpBQWHCdUweq7apzqFOTU2YkUd4V3msebEHbQ2Zro60ZShDDy9SMiyWTqA==} + '@ai-sdk/gateway@2.0.2': + resolution: {integrity: sha512-25F1qPqZxOw9IcV9OQCL29hV4HAFLw5bFWlzQLBi5aDhEZsTMT2rMi3umSqNaUxrrw+dLRtjOL7RbHC+WjbA/A==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@2.0.53': - resolution: {integrity: sha512-GIkR3+Fyif516ftXv+YPSPstnAHhcZxNoR2s8uSHhQ1yBT7I7aQYTVwpjAuYoT3GR+TeP50q7onj2/nDRbT2FQ==} + '@ai-sdk/openai@2.0.54': + resolution: {integrity: sha512-MH4wCCtCz5R1y2T0ZzjYIt5pHN4WqDYsWLuzl5MBcmCRm4oqth/JAKcAmQc5DVogJ3ybja4segmjdN6g1RBdLQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@3.0.12': - resolution: {integrity: sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==} + '@ai-sdk/provider-utils@3.0.13': + resolution: {integrity: sha512-aXFLBLRPTUYA853MJliItefSXeJPl+mg0KSjbToP41kJ+banBmHO8ZPGLJhNqGlCU82o11TYN7G05EREKX8CkA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -247,8 +244,8 @@ packages: resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} engines: {node: '>=18'} - '@ai-sdk/rsc@1.0.79': - resolution: {integrity: sha512-FiEK7DVN7l4RJ2zu/7k9nX9XjIukiak7PKcanvIE5wTvOIG3PeYWlY9AftxF5MKiFyYqyrucUUQ5HI8/VL4dXw==} + '@ai-sdk/rsc@1.0.81': + resolution: {integrity: sha512-Vk4C1EpE2kygl4q3Wl4Ds6tEhO0MmuwTk+JsE8MUP3jmnIwvJBTueVjRVZyXKqGSxg8XIKFYi9CErPerCSpx6A==} engines: {node: '>=18'} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc @@ -980,59 +977,59 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@next/bundle-analyzer@15.5.5': - resolution: {integrity: sha512-X9tOAWrgF6rPuI++vs2xfjYPd/+XdsdJzu0rQtjFmOV5qa02uzqGutAAr+qCd0vsB5J3VmnMFfzn2/9xxmM23w==} + '@next/bundle-analyzer@16.0.0': + resolution: {integrity: sha512-OYufQoNm/Im2fYQBdXu9fqUrXaP3lPuPnryW0XNGG7kJiGxH/VWS8zc2/x4aW2LQGn+opqIJYNRXy7k5qV/09g==} - '@next/env@15.5.5': - resolution: {integrity: sha512-2Zhvss36s/yL+YSxD5ZL5dz5pI6ki1OLxYlh6O77VJ68sBnlUrl5YqhBgCy7FkdMsp9RBeGFwpuDCdpJOqdKeQ==} + '@next/env@16.0.0': + resolution: {integrity: sha512-s5j2iFGp38QsG1LWRQaE2iUY3h1jc014/melHFfLdrsMJPqxqDQwWNwyQTcNoUSGZlCVZuM7t7JDMmSyRilsnA==} - '@next/eslint-plugin-next@15.5.5': - resolution: {integrity: sha512-FMzm412l9oFB8zdRD+K6HQ1VzlS+sNNsdg0MfvTg0i8lfCyTgP/RFxiu/pGJqZ/IQnzn9xSiLkjOVI7Iv4nbdQ==} + '@next/eslint-plugin-next@16.0.0': + resolution: {integrity: sha512-IB7RzmmtrPOrpAgEBR1PIQPD0yea5lggh5cq54m51jHjjljU80Ia+czfxJYMlSDl1DPvpzb8S9TalCc0VMo9Hw==} - '@next/swc-darwin-arm64@15.5.5': - resolution: {integrity: sha512-lYExGHuFIHeOxf40mRLWoA84iY2sLELB23BV5FIDHhdJkN1LpRTPc1MDOawgTo5ifbM5dvAwnGuHyNm60G1+jw==} + '@next/swc-darwin-arm64@16.0.0': + resolution: {integrity: sha512-/CntqDCnk5w2qIwMiF0a9r6+9qunZzFmU0cBX4T82LOflE72zzH6gnOjCwUXYKOBlQi8OpP/rMj8cBIr18x4TA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.5.5': - resolution: {integrity: sha512-cacs/WQqa96IhqUm+7CY+z/0j9sW6X80KE07v3IAJuv+z0UNvJtKSlT/T1w1SpaQRa9l0wCYYZlRZUhUOvEVmg==} + '@next/swc-darwin-x64@16.0.0': + resolution: {integrity: sha512-hB4GZnJGKa8m4efvTGNyii6qs76vTNl+3dKHTCAUaksN6KjYy4iEO3Q5ira405NW2PKb3EcqWiRaL9DrYJfMHg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.5.5': - resolution: {integrity: sha512-tLd90SvkRFik6LSfuYjcJEmwqcNEnVYVOyKTacSazya/SLlSwy/VYKsDE4GIzOBd+h3gW+FXqShc2XBavccHCg==} + '@next/swc-linux-arm64-gnu@16.0.0': + resolution: {integrity: sha512-E2IHMdE+C1k+nUgndM13/BY/iJY9KGCphCftMh7SXWcaQqExq/pJU/1Hgn8n/tFwSoLoYC/yUghOv97tAsIxqg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.5.5': - resolution: {integrity: sha512-ekV76G2R/l3nkvylkfy9jBSYHeB4QcJ7LdDseT6INnn1p51bmDS1eGoSoq+RxfQ7B1wt+Qa0pIl5aqcx0GLpbw==} + '@next/swc-linux-arm64-musl@16.0.0': + resolution: {integrity: sha512-xzgl7c7BVk4+7PDWldU+On2nlwnGgFqJ1siWp3/8S0KBBLCjonB6zwJYPtl4MUY7YZJrzzumdUpUoquu5zk8vg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.5.5': - resolution: {integrity: sha512-tI+sBu+3FmWtqlqD4xKJcj3KJtqbniLombKTE7/UWyyoHmOyAo3aZ7QcEHIOgInXOG1nt0rwh0KGmNbvSB0Djg==} + '@next/swc-linux-x64-gnu@16.0.0': + resolution: {integrity: sha512-sdyOg4cbiCw7YUr0F/7ya42oiVBXLD21EYkSwN+PhE4csJH4MSXUsYyslliiiBwkM+KsuQH/y9wuxVz6s7Nstg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.5.5': - resolution: {integrity: sha512-kDRh+epN/ulroNJLr+toDjN+/JClY5L+OAWjOrrKCI0qcKvTw9GBx7CU/rdA2bgi4WpZN3l0rf/3+b8rduEwrQ==} + '@next/swc-linux-x64-musl@16.0.0': + resolution: {integrity: sha512-IAXv3OBYqVaNOgyd3kxR4L3msuhmSy1bcchPHxDOjypG33i2yDWvGBwFD94OuuTjjTt/7cuIKtAmoOOml6kfbg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.5.5': - resolution: {integrity: sha512-GDgdNPFFqiKjTrmfw01sMMRWhVN5wOCmFzPloxa7ksDfX6TZt62tAK986f0ZYqWpvDFqeBCLAzmgTURvtQBdgw==} + '@next/swc-win32-arm64-msvc@16.0.0': + resolution: {integrity: sha512-bmo3ncIJKUS9PWK1JD9pEVv0yuvp1KPuOsyJTHXTv8KDrEmgV/K+U0C75rl9rhIaODcS7JEb6/7eJhdwXI0XmA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.5.5': - resolution: {integrity: sha512-5kE3oRJxc7M8RmcTANP8RGoJkaYlwIiDD92gSwCjJY0+j8w8Sl1lvxgQ3bxfHY2KkHFai9tpy/Qx1saWV8eaJQ==} + '@next/swc-win32-x64-msvc@16.0.0': + resolution: {integrity: sha512-O1cJbT+lZp+cTjYyZGiDwsOjO3UHHzSqobkPNipdlnnuPb1swfcuY6r3p8dsKU4hAIEO4cO67ZCfVVH/M1ETXA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1382,9 +1379,6 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@rushstack/eslint-patch@1.14.1': - resolution: {integrity: sha512-jGTk8UD/RdjsNZW8qq10r0RBvxL8OWtoT+kImlzPDFilmozzM+9QmIJsmze9UiSBrFU45ZxhTYBypn9q9z/VfQ==} - '@sinclair/typebox@0.34.41': resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} @@ -2072,8 +2066,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ai@5.0.79: - resolution: {integrity: sha512-Zhtn9Kj/RMjuUlnI64qP0IRFfFegEsO7OzYY4peqVvagWaXj3/iIzt8OQl3VzDgaahf85nTbyV3j/TUL322EMQ==} + ai@5.0.81: + resolution: {integrity: sha512-SB7oMC9QSpIu1VLswFTZuhhpfQfrGtFBUbWLtHBkhjWZIQskjtcdEhB+N4yO9hscdc2wYtjw/tacgoxX93QWFw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -2561,10 +2555,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-config-next@15.5.5: - resolution: {integrity: sha512-f8lRSSelp6cqrYjxEMjJ5En3WV913gTu/w9goYShnIujwDSQlKt4x9MwSDiduE9R5mmFETK44+qlQDxeSA0rUA==} + eslint-config-next@16.0.0: + resolution: {integrity: sha512-DWKT1YAO9ex2rK0/EeiPpKU++ghTiG59z6m08/ReLRECOYIaEv17maSCYT8zmFQLwIrY5lhJ+iaJPQdT4sJd4g==} peerDependencies: - eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + eslint: '>=9.0.0' typescript: '>=3.3.1' peerDependenciesMeta: typescript: @@ -2623,12 +2617,6 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - eslint-plugin-react-hooks@5.2.0: - resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react-hooks@7.0.1: resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} engines: {node: '>=18'} @@ -2876,6 +2864,10 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -3582,9 +3574,9 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@15.5.5: - resolution: {integrity: sha512-OQVdBPtpBfq7HxFN0kOVb7rXXOSIkt5lTzDJDGRBcOyVvNRIWFauMqi1gIHd1pszq1542vMOGY0HP4CaiALfkA==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + next@16.0.0: + resolution: {integrity: sha512-nYohiNdxGu4OmBzggxy9rczmjIGI+TpR5vbKTsE1HqYwNm1B+YSiugSrFguX6omMOKnDHAmBPY4+8TNJk0Idyg==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -3886,10 +3878,10 @@ packages: rbush@4.0.1: resolution: {integrity: sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==} - react-dom@19.1.1: - resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: - react: ^19.1.1 + react: ^19.2.0 react-icons@5.5.0: resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==} @@ -3942,8 +3934,8 @@ packages: '@types/react': optional: true - react@19.1.1: - resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} redent@3.0.0: @@ -4028,8 +4020,8 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} @@ -4342,6 +4334,13 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typescript-eslint@8.46.2: + resolution: {integrity: sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -4568,20 +4567,20 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@ai-sdk/gateway@2.0.1(zod@4.1.12)': + '@ai-sdk/gateway@2.0.2(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.13(zod@4.1.12) '@vercel/oidc': 3.0.3 zod: 4.1.12 - '@ai-sdk/openai@2.0.53(zod@4.1.12)': + '@ai-sdk/openai@2.0.54(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.13(zod@4.1.12) zod: 4.1.12 - '@ai-sdk/provider-utils@3.0.12(zod@4.1.12)': + '@ai-sdk/provider-utils@3.0.13(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 '@standard-schema/spec': 1.0.0 @@ -4592,13 +4591,13 @@ snapshots: dependencies: json-schema: 0.4.0 - '@ai-sdk/rsc@1.0.79(react@19.1.1)(zod@4.1.12)': + '@ai-sdk/rsc@1.0.81(react@19.2.0)(zod@4.1.12)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) - ai: 5.0.79(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.13(zod@4.1.12) + ai: 5.0.81(zod@4.1.12) jsondiffpatch: 0.6.0 - react: 19.1.1 + react: 19.2.0 optionalDependencies: zod: 4.1.12 @@ -5394,11 +5393,11 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@floating-ui/dom': 1.7.4 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) '@floating-ui/utils@0.2.10': {} @@ -5741,41 +5740,41 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@next/bundle-analyzer@15.5.5': + '@next/bundle-analyzer@16.0.0': dependencies: webpack-bundle-analyzer: 4.10.1 transitivePeerDependencies: - bufferutil - utf-8-validate - '@next/env@15.5.5': {} + '@next/env@16.0.0': {} - '@next/eslint-plugin-next@15.5.5': + '@next/eslint-plugin-next@16.0.0': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.5.5': + '@next/swc-darwin-arm64@16.0.0': optional: true - '@next/swc-darwin-x64@15.5.5': + '@next/swc-darwin-x64@16.0.0': optional: true - '@next/swc-linux-arm64-gnu@15.5.5': + '@next/swc-linux-arm64-gnu@16.0.0': optional: true - '@next/swc-linux-arm64-musl@15.5.5': + '@next/swc-linux-arm64-musl@16.0.0': optional: true - '@next/swc-linux-x64-gnu@15.5.5': + '@next/swc-linux-x64-gnu@16.0.0': optional: true - '@next/swc-linux-x64-musl@15.5.5': + '@next/swc-linux-x64-musl@16.0.0': optional: true - '@next/swc-win32-arm64-msvc@15.5.5': + '@next/swc-win32-arm64-msvc@16.0.0': optional: true - '@next/swc-win32-x64-msvc@15.5.5': + '@next/swc-win32-x64-msvc@16.0.0': optional: true '@nodelib/fs.scandir@2.1.5': @@ -5807,289 +5806,289 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.2.0)': dependencies: - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.2.0)': dependencies: - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) aria-hidden: 1.2.6 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.2.0)': dependencies: - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.2)(react@19.2.0)': dependencies: - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.2.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.1.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) aria-hidden: 1.2.6 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.1.1) + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) '@radix-ui/rect': 1.1.1 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.2.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.2)(react@19.2.0)': dependencies: - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.2.0)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.2.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.2)(react@19.2.0)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.2.0)': dependencies: - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.2)(react@19.2.0)': dependencies: '@radix-ui/rect': 1.1.1 - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.2)(react@19.1.1)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.2)(react@19.2.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1) - react: 19.1.1 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) @@ -6098,8 +6097,6 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@rushstack/eslint-patch@1.14.1': {} - '@sinclair/typebox@0.34.41': {} '@sinonjs/commons@3.0.1': @@ -6553,12 +6550,12 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 '@testing-library/dom': 10.4.1 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.2(@types/react@19.2.2) @@ -6833,10 +6830,10 @@ snapshots: dependencies: uncrypto: 0.1.3 - '@vercel/analytics@1.5.0(next@15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)': + '@vercel/analytics@1.5.0(next@16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': optionalDependencies: - next: 15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 + next: 16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 '@vercel/blob@2.0.0': dependencies: @@ -6848,10 +6845,10 @@ snapshots: '@vercel/oidc@3.0.3': {} - '@vercel/speed-insights@1.2.0(next@15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)': + '@vercel/speed-insights@1.2.0(next@16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': optionalDependencies: - next: 15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 + next: 16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 acorn-jsx@5.3.2(acorn@8.15.0): dependencies: @@ -6865,11 +6862,11 @@ snapshots: agent-base@7.1.4: {} - ai@5.0.79(zod@4.1.12): + ai@5.0.81(zod@4.1.12): dependencies: - '@ai-sdk/gateway': 2.0.1(zod@4.1.12) + '@ai-sdk/gateway': 2.0.2(zod@4.1.12) '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.12(zod@4.1.12) + '@ai-sdk/provider-utils': 3.0.13(zod@4.1.12) '@opentelemetry/api': 1.9.0 zod: 4.1.12 @@ -7144,14 +7141,14 @@ snapshots: clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + cmdk@1.1.1(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -7436,22 +7433,22 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-next@15.5.5(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): + eslint-config-next@16.0.0(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@next/eslint-plugin-next': 15.5.5 - '@rushstack/eslint-patch': 1.14.1 - '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@next/eslint-plugin-next': 16.0.0 eslint: 9.38.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0(jiti@2.6.1)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.38.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.38.0(jiti@2.6.1)) + eslint-plugin-react-hooks: 7.0.1(eslint@9.38.0(jiti@2.6.1)) + globals: 16.4.0 + typescript-eslint: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: + - '@typescript-eslint/parser' - eslint-import-resolver-webpack - eslint-plugin-import-x - supports-color @@ -7538,10 +7535,6 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.38.0(jiti@2.6.1)): - dependencies: - eslint: 9.38.0(jiti@2.6.1) - eslint-plugin-react-hooks@7.0.1(eslint@9.38.0(jiti@2.6.1)): dependencies: '@babel/core': 7.28.5 @@ -7748,14 +7741,14 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - framer-motion@12.23.24(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: motion-dom: 12.23.23 motion-utils: 12.23.6 tslib: 2.8.1 optionalDependencies: - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) fs.realpath@1.0.0: {} @@ -7854,6 +7847,8 @@ snapshots: globals@14.0.0: {} + globals@16.4.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -8689,35 +8684,35 @@ snapshots: natural-compare@1.4.0: {} - next-auth@5.0.0-beta.29(next@15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1): + next-auth@5.0.0-beta.29(next@16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0): dependencies: '@auth/core': 0.40.0 - next: 15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 + next: 16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 - next-themes@0.4.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + next-themes@0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) - next@15.5.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + next@16.0.0(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: - '@next/env': 15.5.5 + '@next/env': 16.0.0 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001751 postcss: 8.4.31 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.2.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.5 - '@next/swc-darwin-x64': 15.5.5 - '@next/swc-linux-arm64-gnu': 15.5.5 - '@next/swc-linux-arm64-musl': 15.5.5 - '@next/swc-linux-x64-gnu': 15.5.5 - '@next/swc-linux-x64-musl': 15.5.5 - '@next/swc-win32-arm64-msvc': 15.5.5 - '@next/swc-win32-x64-msvc': 15.5.5 + '@next/swc-darwin-arm64': 16.0.0 + '@next/swc-darwin-x64': 16.0.0 + '@next/swc-linux-arm64-gnu': 16.0.0 + '@next/swc-linux-arm64-musl': 16.0.0 + '@next/swc-linux-x64-gnu': 16.0.0 + '@next/swc-linux-x64-musl': 16.0.0 + '@next/swc-win32-arm64-msvc': 16.0.0 + '@next/swc-win32-x64-msvc': 16.0.0 '@opentelemetry/api': 1.9.0 sharp: 0.34.4 transitivePeerDependencies: @@ -8992,14 +8987,14 @@ snapshots: dependencies: quickselect: 3.0.0 - react-dom@19.1.1(react@19.1.1): + react-dom@19.2.0(react@19.2.0): dependencies: - react: 19.1.1 - scheduler: 0.26.0 + react: 19.2.0 + scheduler: 0.27.0 - react-icons@5.5.0(react@19.1.1): + react-icons@5.5.0(react@19.2.0): dependencies: - react: 19.1.1 + react: 19.2.0 react-is@16.13.1: {} @@ -9007,40 +9002,40 @@ snapshots: react-is@18.3.1: {} - react-openlayers@10.5.1(ol@10.6.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + react-openlayers@10.5.1(ol@10.6.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: ol: 10.6.1 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) - react-remove-scroll-bar@2.3.8(@types/react@19.2.2)(react@19.1.1): + react-remove-scroll-bar@2.3.8(@types/react@19.2.2)(react@19.2.0): dependencies: - react: 19.1.1 - react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.1.1) + react: 19.2.0 + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0) tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 - react-remove-scroll@2.7.1(@types/react@19.2.2)(react@19.1.1): + react-remove-scroll@2.7.1(@types/react@19.2.2)(react@19.2.0): dependencies: - react: 19.1.1 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.2)(react@19.1.1) - react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.1.1) + react: 19.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.2)(react@19.2.0) + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.2)(react@19.1.1) - use-sidecar: 1.1.3(@types/react@19.2.2)(react@19.1.1) + use-callback-ref: 1.3.3(@types/react@19.2.2)(react@19.2.0) + use-sidecar: 1.1.3(@types/react@19.2.2)(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 - react-style-singleton@2.2.3(@types/react@19.2.2)(react@19.1.1): + react-style-singleton@2.2.3(@types/react@19.2.2)(react@19.2.0): dependencies: get-nonce: 1.0.1 - react: 19.1.1 + react: 19.2.0 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 - react@19.1.1: {} + react@19.2.0: {} redent@3.0.0: dependencies: @@ -9141,7 +9136,7 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.26.0: {} + scheduler@0.27.0: {} semver@6.3.1: {} @@ -9244,10 +9239,10 @@ snapshots: slash@3.0.0: {} - sonner@2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) source-map-js@1.2.1: {} @@ -9362,10 +9357,10 @@ snapshots: strnum@2.1.1: {} - styled-jsx@5.1.6(@babel/core@7.28.5)(react@19.1.1): + styled-jsx@5.1.6(@babel/core@7.28.5)(react@19.2.0): dependencies: client-only: 0.0.1 - react: 19.1.1 + react: 19.2.0 optionalDependencies: '@babel/core': 7.28.5 @@ -9379,11 +9374,11 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - swr@2.3.6(react@19.1.1): + swr@2.3.6(react@19.2.0): dependencies: dequal: 2.0.3 - react: 19.1.1 - use-sync-external-store: 1.6.0(react@19.1.1) + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) symbol-tree@3.2.4: {} @@ -9510,6 +9505,17 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typescript-eslint@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.38.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript@5.9.3: {} unbox-primitive@1.1.0: @@ -9561,28 +9567,28 @@ snapshots: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.1.1): + use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.2.0): dependencies: - react: 19.1.1 + react: 19.2.0 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 - use-debounce@10.0.6(react@19.1.1): + use-debounce@10.0.6(react@19.2.0): dependencies: - react: 19.1.1 + react: 19.2.0 - use-sidecar@1.1.3(@types/react@19.2.2)(react@19.1.1): + use-sidecar@1.1.3(@types/react@19.2.2)(react@19.2.0): dependencies: detect-node-es: 1.1.0 - react: 19.1.1 + react: 19.2.0 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 - use-sync-external-store@1.6.0(react@19.1.1): + use-sync-external-store@1.6.0(react@19.2.0): dependencies: - react: 19.1.1 + react: 19.2.0 v8-compile-cache-lib@3.0.1: {} diff --git a/middleware.ts b/proxy.ts similarity index 95% rename from middleware.ts rename to proxy.ts index 61e22b46..337c614e 100644 --- a/middleware.ts +++ b/proxy.ts @@ -10,7 +10,7 @@ import { PREFIX_TAG, } from './src/app/path'; -export default function middleware(req: NextRequest, res:NextResponse) { +export function proxy(req: NextRequest, res:NextResponse) { const pathname = req.nextUrl.pathname; if (pathname === PATH_ADMIN) { diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index c1e4b3d6..984e2975 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -53,11 +53,10 @@ export default function AdminNavClient({ useState(areTimesRecent(updateTimes)); useEffect(() => { - // Check every 5 seconds if update times are recent - setHasRecentUpdates(areTimesRecent(updateTimes)); + // Check every 1 second if update times are recent const interval = setInterval(() => setHasRecentUpdates(areTimesRecent(updateTimes)) - , 5_000); + , 1_000); return () => clearInterval(interval); }, [updateTimes]); diff --git a/src/admin/config/AdminAppConfiguration.tsx b/src/admin/config/AdminAppConfiguration.tsx index 319ce79b..d1510354 100644 --- a/src/admin/config/AdminAppConfiguration.tsx +++ b/src/admin/config/AdminAppConfiguration.tsx @@ -2,16 +2,19 @@ import { Suspense } from 'react'; import { APP_CONFIGURATION } from '@/app/config'; import AdminAppConfigurationClient from './AdminAppConfigurationClient'; import AdminAppConfigurationServer from './AdminAppConfigurationServer'; +import { generateAuthSecret } from '@/auth'; -export default function AdminAppConfiguration({ +export default async function AdminAppConfiguration({ simplifiedView, }: { simplifiedView?: boolean }) { + const secret = await generateAuthSecret(); return ( }> diff --git a/src/admin/config/AdminAppConfigurationClient.tsx b/src/admin/config/AdminAppConfigurationClient.tsx index 71e99436..ef9f4eb2 100644 --- a/src/admin/config/AdminAppConfigurationClient.tsx +++ b/src/admin/config/AdminAppConfigurationClient.tsx @@ -137,6 +137,8 @@ export default function AdminAppConfigurationClient({ areInternalToolsEnabled, areAdminDebugToolsEnabled, isAdminSqlDebugEnabled, + // Auth + secret, // Connection status databaseError, storageError, @@ -147,6 +149,7 @@ export default function AdminAppConfigurationClient({ simplifiedView, isAnalyzingConfiguration, }: AppConfiguration & + { secret: string } & Partial>> & { simplifiedView?: boolean isAnalyzingConfiguration?: boolean @@ -373,7 +376,7 @@ export default function AdminAppConfigurationClient({ Store auth secret in environment variable: {!hasAuthSecret &&
- +
} {renderEnvVars(['AUTH_SECRET'])} diff --git a/src/admin/config/AdminAppConfigurationServer.tsx b/src/admin/config/AdminAppConfigurationServer.tsx index 0e817be1..eb8cb4d9 100644 --- a/src/admin/config/AdminAppConfigurationServer.tsx +++ b/src/admin/config/AdminAppConfigurationServer.tsx @@ -1,6 +1,7 @@ import AdminAppConfigurationClient from './AdminAppConfigurationClient'; import { APP_CONFIGURATION } from '@/app/config'; import { testConnectionsAction } from '@/admin/actions'; +import { generateAuthSecret } from '@/auth'; export default async function AdminAppConfigurationServer({ simplifiedView, @@ -9,10 +10,13 @@ export default async function AdminAppConfigurationServer({ }) { const connectionErrors = await testConnectionsAction().catch(() => ({})); + const secret = await generateAuthSecret(); + return ( ); diff --git a/src/admin/select/SelectPhotosProvider.tsx b/src/admin/select/SelectPhotosProvider.tsx index cbea400e..8452d330 100644 --- a/src/admin/select/SelectPhotosProvider.tsx +++ b/src/admin/select/SelectPhotosProvider.tsx @@ -22,7 +22,11 @@ export default function SelectPhotosProvider({ const { isUserSignedIn } = useAppState(); - const searchParamsSelect = useClientSearchParams(PARAM_SELECT); + const searchParamsSelect = useClientSearchParams( + PARAM_SELECT, + // Only scan urls when admin is signed in + isUserSignedIn, + ); const [canCurrentPageSelectPhotos, setCanCurrentPageSelectPhotos] = useState(false); @@ -36,9 +40,12 @@ export default function SelectPhotosProvider({ , []); useEffect(() => { - const doesPageHavePhotoGrids = getPhotoGridElements().length > 0; - setCanCurrentPageSelectPhotos(doesPageHavePhotoGrids); - }, [pathname, getPhotoGridElements]); + if (isUserSignedIn) { + const doesPageHavePhotoGrids = getPhotoGridElements().length > 0; + // eslint-disable-next-line react-hooks/set-state-in-effect + setCanCurrentPageSelectPhotos(doesPageHavePhotoGrids); + } + }, [pathname, isUserSignedIn, getPhotoGridElements]); const isSelectingPhotos = useMemo(() => isUserSignedIn && @@ -66,6 +73,7 @@ export default function SelectPhotosProvider({ photoGrids[0]?.scrollIntoView({ behavior: 'smooth' }); } } else { + // eslint-disable-next-line react-hooks/set-state-in-effect setSelectedPhotoIds([]); } }, [isSelectingPhotos, getPhotoGridElements]); diff --git a/src/app/AppState.ts b/src/app/AppState.ts index a42f01cb..264fa9cb 100644 --- a/src/app/AppState.ts +++ b/src/app/AppState.ts @@ -18,7 +18,6 @@ import { SWRKey } from '@/swr'; export type AppStateContextType = { // CORE - hasLoaded?: boolean hasLoadedWithAnimations?: boolean invalidateSwr?: (key?: SWRKey, revalidate?: boolean) => void nextPhotoAnimation?: AnimationConfig @@ -31,6 +30,7 @@ export type AppStateContextType = { typeof getCountsForCategoriesCachedAction >> // ENVIRONMENT + timezone?: string supportsHover?: boolean // MODAL isCommandKOpen?: boolean diff --git a/src/app/AppStateProvider.tsx b/src/app/AppStateProvider.tsx index 012c9310..a4bb85bd 100644 --- a/src/app/AppStateProvider.tsx +++ b/src/app/AppStateProvider.tsx @@ -54,8 +54,6 @@ export default function AppStateProvider({ const pathname = usePathname(); // CORE - const [hasLoaded, setHasLoaded] = - useState(false); const [hasLoadedWithAnimations, setHasLoadedWithAnimations] = useState(false); const [nextPhotoAnimation, _setNextPhotoAnimation] = @@ -80,6 +78,7 @@ export default function AppStateProvider({ const [shouldRespondToKeyboardCommands, setShouldRespondToKeyboardCommands] = useState(true); // ENVIRONMENT + const [timezone, setTimezone] = useState(); const supportsHover = useSupportsHover(); // MODAL const [isCommandKOpen, setIsCommandKOpen] = @@ -118,9 +117,11 @@ export default function AppStateProvider({ useState(false); useEffect(() => { - setHasLoaded(true); storeTimezoneCookie(); + // eslint-disable-next-line react-hooks/set-state-in-effect setUserEmailEager(getAuthEmailCookie()); + // Capture backup timezone on client + setTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone); if (IS_PRODUCTION) { warmRedisAction(); } const timeout = setTimeout(() => { setHasLoadedWithAnimations(true); @@ -152,6 +153,7 @@ export default function AppStateProvider({ } = useSWR(SWR_KEYS.GET_AUTH, getAuthAction); useEffect(() => { if (auth === null || authError) { + // eslint-disable-next-line react-hooks/set-state-in-effect setUserEmail(undefined); setUserEmailEager(undefined); clearAuthEmailCookie(); @@ -222,7 +224,6 @@ export default function AppStateProvider({ { setIsLoading(true); @@ -19,10 +23,6 @@ export default function SecretGenerator() { .finally(() => setIsLoading(false)); }, []); - useEffect(() => { - getSecret(); - }, [getSecret]); - return (
diff --git a/src/app/ThemeSwitcher.tsx b/src/app/ThemeSwitcher.tsx index b1869b62..9e019dd6 100644 --- a/src/app/ThemeSwitcher.tsx +++ b/src/app/ThemeSwitcher.tsx @@ -1,27 +1,19 @@ 'use client'; -import { useState, useEffect } from 'react'; import { useTheme } from 'next-themes'; import Switcher from '@/components/switcher/Switcher'; import SwitcherItem from '@/components/switcher/SwitcherItem'; import { BiDesktop, BiMoon, BiSun } from 'react-icons/bi'; import { useAppText } from '@/i18n/state/client'; +import { useAppState } from './AppState'; export default function ThemeSwitcher () { + const { hasLoadedWithAnimations } = useAppState(); + const appText = useAppText(); - const [mounted, setMounted] = useState(false); const { theme, setTheme } = useTheme(); - // useEffect only runs on the client, so now we can safely show the UI - useEffect(() => { - setMounted(true); - }, []); - - if (!mounted) { - return null; - } - return ( } onClick={() => setTheme('system')} - active={theme === 'system'} + active={hasLoadedWithAnimations && theme === 'system'} tooltip={{ content: appText.theme.system }} /> } onClick={() => setTheme('light')} - active={theme === 'light'} + active={hasLoadedWithAnimations && theme === 'light'} tooltip={{ content: appText.theme.light }} /> } onClick={() => setTheme('dark')} - active={theme === 'dark'} + active={hasLoadedWithAnimations && theme === 'dark'} tooltip={{ content: appText.theme.dark }} /> diff --git a/src/components/AnimateItems.tsx b/src/components/AnimateItems.tsx index 07466e6c..c55dfbee 100644 --- a/src/components/AnimateItems.tsx +++ b/src/components/AnimateItems.tsx @@ -46,7 +46,7 @@ function AnimateItems({ onAnimationComplete, }: Props) { const { - hasLoaded, + hasLoadedWithAnimations, nextPhotoAnimation, getNextPhotoAnimationId, clearNextPhotoAnimation, @@ -56,14 +56,13 @@ function AnimateItems({ const prefersReducedMotion = usePrefersReducedMotion(); - const hasLoadedInitial = useRef(hasLoaded); const nextPhotoAnimationInitial = useRef(nextPhotoAnimation); const shouldAnimate = type !== 'none' && !prefersReducedMotion && - !(animateOnFirstLoadOnly && hasLoadedInitial.current); + !(animateOnFirstLoadOnly && hasLoadedWithAnimations); const shouldStagger = - !(staggerOnFirstLoadOnly && hasLoadedInitial.current); + !(staggerOnFirstLoadOnly && hasLoadedWithAnimations); const typeResolved = animateFromAppState ? (nextPhotoAnimationInitial.current?.type ?? type) diff --git a/src/components/RedirectOnDesktop.tsx b/src/components/RedirectOnDesktop.tsx deleted file mode 100644 index 42704c7d..00000000 --- a/src/components/RedirectOnDesktop.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client'; - -import useIsDesktop from '@/utility/useIsDesktop'; -import { usePathname, useRouter } from 'next/navigation'; -import { useEffect } from 'react'; - -export default function RedirectOnDesktop({ - redirectPath, - shouldPrefetchRedirect = true, -}: { - redirectPath: string - shouldPrefetchRedirect?: boolean -}) { - const router = useRouter(); - - const pathname = usePathname(); - - const isDesktop = useIsDesktop(); - - useEffect(() => { - if (shouldPrefetchRedirect) { - router.prefetch(redirectPath); - } - }, [router, shouldPrefetchRedirect, redirectPath]); - - useEffect(() => { - if (isDesktop && pathname !== redirectPath) { - router.push(redirectPath); - } - }, [router, isDesktop, pathname, redirectPath]); - - return null; -} diff --git a/src/components/ResponsiveDate.tsx b/src/components/ResponsiveDate.tsx index 371ac467..1e44d4db 100644 --- a/src/components/ResponsiveDate.tsx +++ b/src/components/ResponsiveDate.tsx @@ -1,8 +1,8 @@ 'use client'; +import { useAppState } from '@/app/AppState'; import { formatDate } from '@/utility/date'; import { clsx } from 'clsx/lite'; -import { useEffect, useState } from 'react'; export default function ResponsiveDate({ date, @@ -15,13 +15,9 @@ export default function ResponsiveDate({ className?: string titleLabel?: string } & Parameters[0]) { - const [timezone, setTimezone] = useState(timezoneFromProps); + const { timezone: timezoneFromState } = useAppState(); - useEffect(() => { - if (!timezoneFromProps) { - setTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone); - } - }, [timezoneFromProps]); + const timezone = timezoneFromProps ?? timezoneFromState; const showPlaceholder = timezone === undefined; diff --git a/src/components/SelectMenu.tsx b/src/components/SelectMenu.tsx index 863d7fcd..c4172f66 100644 --- a/src/components/SelectMenu.tsx +++ b/src/components/SelectMenu.tsx @@ -50,6 +50,7 @@ export default function SelectMenu({ useEffect(() => { if (readOnly) { + // eslint-disable-next-line react-hooks/set-state-in-effect setIsOpen(false); } }, [readOnly]); diff --git a/src/components/TagInput.tsx b/src/components/TagInput.tsx index 4e0ecfce..05a87e42 100644 --- a/src/components/TagInput.tsx +++ b/src/components/TagInput.tsx @@ -193,6 +193,7 @@ export default function TagInput({ useEffect(() => { if (inputText) { if (inputText.includes(',')) { + // eslint-disable-next-line react-hooks/set-state-in-effect addOptions(inputText.split(',')); } else { setShouldShowMenu(true); diff --git a/src/components/image/ImageWithFallback.tsx b/src/components/image/ImageWithFallback.tsx index ec02fadf..d1936cf6 100644 --- a/src/components/image/ImageWithFallback.tsx +++ b/src/components/image/ImageWithFallback.tsx @@ -37,6 +37,7 @@ export default function ImageWithFallback({ !ref.current?.complete || (ref.current?.naturalWidth ?? 0) === 0 ) { + // eslint-disable-next-line react-hooks/set-state-in-effect setFadeFallbackTransition(true); } }, []); diff --git a/src/components/og/OGLoaderImage.tsx b/src/components/og/OGLoaderImage.tsx index 9412325b..d4c1d238 100644 --- a/src/components/og/OGLoaderImage.tsx +++ b/src/components/og/OGLoaderImage.tsx @@ -29,6 +29,7 @@ export default function OGLoaderImage({ useEffect(() => { if (!ref.current?.complete) { + // eslint-disable-next-line react-hooks/set-state-in-effect setLoadingState('loading'); } }, [path]); diff --git a/src/components/primitives/PathLoaderButton.tsx b/src/components/primitives/PathLoaderButton.tsx index 0851d3e0..29735158 100644 --- a/src/components/primitives/PathLoaderButton.tsx +++ b/src/components/primitives/PathLoaderButton.tsx @@ -34,6 +34,7 @@ export default function PathLoaderButton({ }, loaderDelay); return () => clearTimeout(timeout); } else { + // eslint-disable-next-line react-hooks/set-state-in-effect setShouldShowLoader(false); } }, [isPending, loaderDelay]); diff --git a/src/components/switcher/SwitcherItem.tsx b/src/components/switcher/SwitcherItem.tsx index 92c94aa0..13b8cd65 100644 --- a/src/components/switcher/SwitcherItem.tsx +++ b/src/components/switcher/SwitcherItem.tsx @@ -5,8 +5,8 @@ import Spinner from '../Spinner'; import LinkWithIconLoader from '../LinkWithIconLoader'; import Tooltip from '../Tooltip'; -const WIDTH_CLASS = 'w-[42px]'; -const WIDTH_CLASS_NARROW = 'w-[36px]'; +const WIDTH_CLASS = 'w-[42px]'; +const WIDTH_CLASS_NARROW = 'w-[36px]'; export default function SwitcherItem({ icon, diff --git a/src/photo/ai/useTitleCaptionAiImageQuery.ts b/src/photo/ai/useTitleCaptionAiImageQuery.ts index f99483ec..3f77582e 100644 --- a/src/photo/ai/useTitleCaptionAiImageQuery.ts +++ b/src/photo/ai/useTitleCaptionAiImageQuery.ts @@ -17,6 +17,7 @@ export default function useTitleCaptionAiImageQuery( const [caption, setCaption] = useState(''); useEffect(() => { const { title, caption } = parseTitleAndCaption(text); + // eslint-disable-next-line react-hooks/set-state-in-effect setTitle(title); setCaption(caption); }, [text]); diff --git a/src/photo/cache.ts b/src/photo/cache.ts index a459c86f..1222ff4a 100644 --- a/src/photo/cache.ts +++ b/src/photo/cache.ts @@ -102,31 +102,31 @@ const getPhotosCacheKeys = (options: PhotoQueryOptions = {}) => { }; export const revalidatePhotosKey = () => - revalidateTag(KEY_PHOTOS); + revalidateTag(KEY_PHOTOS, 'max'); export const revalidateAlbumsKey = () => - revalidateTag(KEY_ALBUMS); + revalidateTag(KEY_ALBUMS, 'max'); export const revalidateTagsKey = () => - revalidateTag(KEY_TAGS); + revalidateTag(KEY_TAGS, 'max'); export const revalidateRecipesKey = () => - revalidateTag(KEY_RECIPES); + revalidateTag(KEY_RECIPES, 'max'); export const revalidateCamerasKey = () => - revalidateTag(KEY_CAMERAS); + revalidateTag(KEY_CAMERAS, 'max'); export const revalidateLensesKey = () => - revalidateTag(KEY_LENSES); + revalidateTag(KEY_LENSES, 'max'); export const revalidateFilmsKey = () => - revalidateTag(KEY_FILMS); + revalidateTag(KEY_FILMS, 'max'); export const revalidateFocalLengthsKey = () => - revalidateTag(KEY_FOCAL_LENGTHS); + revalidateTag(KEY_FOCAL_LENGTHS, 'max'); export const revalidateYearsKey = () => - revalidateTag(KEY_YEARS); + revalidateTag(KEY_YEARS, 'max'); export const revalidateAllKeys = () => { revalidatePhotosKey(); @@ -151,7 +151,7 @@ export const revalidateAllKeysAndPaths = () => { export const revalidatePhoto = (photoId: string) => { // Tags - revalidateTag(photoId); + revalidateTag(photoId, 'max'); revalidateYearsKey(); revalidateCamerasKey(); revalidateLensesKey(); diff --git a/src/photo/form/ApplyRecipesGloballyCheckbox.tsx b/src/photo/form/ApplyRecipesGloballyCheckbox.tsx index 93f44e22..1a683a6c 100644 --- a/src/photo/form/ApplyRecipesGloballyCheckbox.tsx +++ b/src/photo/form/ApplyRecipesGloballyCheckbox.tsx @@ -24,6 +24,7 @@ export default function ApplyRecipeTitleGloballyCheckbox({ useEffect(() => { if (recipeTitle && hasRecipeTitleChanged && recipeData && film) { + // eslint-disable-next-line react-hooks/set-state-in-effect setMatchingPhotosCount(undefined); getPhotosNeedingRecipeTitleCountAction(recipeData, film, photoId) .then(setMatchingPhotosCount); diff --git a/src/photo/form/PhotoForm.tsx b/src/photo/form/PhotoForm.tsx index 2af6846b..29bbbcb6 100644 --- a/src/photo/form/PhotoForm.tsx +++ b/src/photo/form/PhotoForm.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/set-state-in-effect */ 'use client'; import { @@ -371,7 +372,7 @@ export default function PhotoForm({ blurCompatibilityLevel="none" width={thumbnailDimensions.width} height={thumbnailDimensions.height} - priority + preload />; return ( diff --git a/src/place/PlaceInput.tsx b/src/place/PlaceInput.tsx index cf451a7b..8acc4686 100644 --- a/src/place/PlaceInput.tsx +++ b/src/place/PlaceInput.tsx @@ -31,6 +31,7 @@ export default function PlaceInput({ useEffect(() => { if (inputTextDebounced) { + // eslint-disable-next-line react-hooks/set-state-in-effect setIsLoadingPlaces(true); getPlaceAutoCompleteAction(inputTextDebounced) .then(options => { diff --git a/src/utility/useClientSearchParams.ts b/src/utility/useClientSearchParams.ts index b08474da..c112aebd 100644 --- a/src/utility/useClientSearchParams.ts +++ b/src/utility/useClientSearchParams.ts @@ -3,6 +3,7 @@ import { useCallback, useEffect, useState } from 'react'; export default function useClientSearchParams( paramKey: string, + enableScanning = true, ): string | undefined { const pathname = usePathname(); @@ -23,7 +24,10 @@ export default function useClientSearchParams( }; }, [captureParam]); - useEffect(captureParam, [captureParam, pathname]); + useEffect(() => { + // eslint-disable-next-line react-hooks/set-state-in-effect + if (enableScanning) { captureParam(); } + }, [pathname, captureParam, enableScanning]); return paramValue; }; diff --git a/src/utility/useHash.ts b/src/utility/useHash.ts index 07558889..cabc263d 100644 --- a/src/utility/useHash.ts +++ b/src/utility/useHash.ts @@ -17,9 +17,8 @@ export default function useHash() { // Needed to capture non-request-initiated hash changes const params = useSearchParams(); - useEffect(() => { - storeHash(); - }, [params, storeHash]); + // eslint-disable-next-line react-hooks/set-state-in-effect + useEffect(storeHash, [params, storeHash]); const updateWindowHash = useCallback((hash: string) => { window.history.replaceState(null, '', `#${hash}`); diff --git a/src/utility/useIsDesktop.ts b/src/utility/useIsDesktop.ts deleted file mode 100644 index 2e58ba89..00000000 --- a/src/utility/useIsDesktop.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useEffect, useState } from 'react'; - -export default function useIsDesktop() { - const [isDesktop, setIsDesktop] = useState(); - - useEffect(() => { - const breakpointMd = getComputedStyle(document.body) - .getPropertyValue('--breakpoint-md'); - const mql = window.matchMedia(`(min-width: ${breakpointMd})`); - setIsDesktop(mql.matches); - - const eventHandler = (event: MediaQueryListEvent) => - setIsDesktop(event.matches); - - mql.addEventListener('change', eventHandler); - return () => mql.removeEventListener('change', eventHandler); - }, []); - - return isDesktop; -}; diff --git a/src/utility/useSupportsHover.ts b/src/utility/useSupportsHover.ts index 0454e178..e777c891 100644 --- a/src/utility/useSupportsHover.ts +++ b/src/utility/useSupportsHover.ts @@ -5,14 +5,16 @@ export default function useSupportsHover() { ? window.matchMedia('(hover: hover)') : undefined); - const [supportsHover, setSupportsHover] = - useState(mqlRef.current?.matches ?? false); + const [supportsHover, setSupportsHover] = useState(false); useEffect(() => { - const listener = (e: MediaQueryListEvent) => setSupportsHover(e.matches); const mql = mqlRef.current; - mql?.addEventListener('change', listener); - return () => mql?.removeEventListener('change', listener); + if (mql) { + setSupportsHover(mql.matches); + const listener = (e: MediaQueryListEvent) => setSupportsHover(e.matches); + mql.addEventListener('change', listener); + return () => mql?.removeEventListener('change', listener); + } }, []); return supportsHover; diff --git a/tsconfig.json b/tsconfig.json index fcfb38cf..56206137 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ {