From a63f2c3fe35f3582a5775d0b046c58b4e36f0eb1 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Thu, 12 Feb 2026 22:28:37 -0600 Subject: [PATCH] Select All Photos (1 of 2) (#372) * Add 'select all photos' to app state * Create general purpose bulk photo action * Fix infinite scroll pagination, temporarily hide "select all" * Refine batch edit behavior * Add admin endpoints to check storage * Add missing storage count * Refine missing file presentation * Finalize storage status page * Store image-dependent photo fields when reuploading * Move storage checks behind flag --- app/admin/storage/page.tsx | 19 + app/sitemap.ts | 4 +- package.json | 16 +- pnpm-lock.yaml | 909 +++++++++--------- src/admin/DeletePhotosButton.tsx | 7 +- .../config/AdminAppConfigurationClient.tsx | 10 + .../select/AdminBatchEditPanelClient.tsx | 48 +- src/admin/select/SelectPhotosProvider.tsx | 23 +- src/admin/select/SelectPhotosState.ts | 6 +- src/admin/storage/AdminPhotoStorageCheck.tsx | 36 + src/admin/storage/AdminStorageTable.tsx | 58 ++ src/album/actions.ts | 13 +- src/app/config.ts | 3 + src/app/static.ts | 4 +- src/components/EnvVar.tsx | 2 + src/db/index.ts | 6 + src/photo/InfinitePhotoScroll.tsx | 6 + src/photo/PhotoDetailPage.tsx | 7 +- src/photo/PhotoFullPage.tsx | 5 +- src/photo/PhotoGrid.tsx | 17 +- src/photo/PhotoLarge.tsx | 5 + src/photo/PhotosLarge.tsx | 3 + src/photo/PhotosLargeInfinite.tsx | 11 +- src/photo/actions.ts | 110 ++- src/photo/query.ts | 120 ++- 25 files changed, 885 insertions(+), 563 deletions(-) create mode 100644 app/admin/storage/page.tsx create mode 100644 src/admin/storage/AdminPhotoStorageCheck.tsx create mode 100644 src/admin/storage/AdminStorageTable.tsx diff --git a/app/admin/storage/page.tsx b/app/admin/storage/page.tsx new file mode 100644 index 00000000..5f34e0ef --- /dev/null +++ b/app/admin/storage/page.tsx @@ -0,0 +1,19 @@ +import AdminInfoPage from '@/admin/AdminInfoPage'; +import AdminStorageTable from '@/admin/storage/AdminStorageTable'; +import { ADMIN_STORAGE_DEBUG_ENABLED } from '@/app/config'; +import EnvVar from '@/components/EnvVar'; + +export default function AdminStoragePage() { + return + {ADMIN_STORAGE_DEBUG_ENABLED + ? + :
+ Set + {' '} + + {' '} + to {'"1"'} to enable + storage checks +
} +
; +} diff --git a/app/sitemap.ts b/app/sitemap.ts index 036cabda..ef0a45c2 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -16,7 +16,7 @@ import { } from '@/app/path'; import { isTagFavs } from '@/tag'; import { BASE_URL, GRID_HOMEPAGE_ENABLED } from '@/app/config'; -import { getPhotoIdsAndUpdatedAt } from '@/photo/query'; +import { getAllPhotoIdsWithUpdatedAt } from '@/photo/query'; // Cache for 24 hours export const revalidate = 86_400; @@ -53,7 +53,7 @@ export default async function sitemap(): Promise { films: [], focalLengths: [], })), - getPhotoIdsAndUpdatedAt().catch(() => []), + getAllPhotoIdsWithUpdatedAt().catch(() => []), ]); const lastModifiedSite = [ diff --git a/package.json b/package.json index c5e850c4..f2aa7527 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,12 @@ "test": "jest --watch --transformIgnorePatterns 'node_modules/(?!my-library-dir)/'", "analyze": "ANALYZE=true next build --webpack" }, - "packageManager": "pnpm@10.29.2", + "packageManager": "pnpm@10.29.3", "dependencies": { - "@ai-sdk/openai": "^3.0.26", - "@ai-sdk/rsc": "^2.0.78", - "@aws-sdk/client-s3": "3.987.0", - "@aws-sdk/s3-request-presigner": "3.987.0", + "@ai-sdk/openai": "^3.0.28", + "@ai-sdk/rsc": "^2.0.85", + "@aws-sdk/client-s3": "3.989.0", + "@aws-sdk/s3-request-presigner": "3.989.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-tooltip": "^1.2.8", @@ -23,7 +23,7 @@ "@vercel/analytics": "^1.6.1", "@vercel/blob": "^2.2.0", "@vercel/speed-insights": "^1.3.1", - "ai": "^6.0.78", + "ai": "^6.0.85", "camelcase-keys": "^10.0.2", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -39,7 +39,7 @@ "next": "16.1.6", "next-auth": "5.0.0-beta.30", "next-themes": "^0.4.6", - "ol": "^10.7.0", + "ol": "^10.8.0", "pg": "^8.18.0", "piexifjs": "^1.0.6", "react": "19.2.4", @@ -69,7 +69,7 @@ "@types/node": "^25.2.3", "@types/pg": "^8.16.0", "@types/piexifjs": "^1.0.0", - "@types/react": "19.2.13", + "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@types/sanitize-html": "^2.16.0", "baseline-browser-mapping": "^2.9.19", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea7f29fe..e3519fc0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,29 +9,29 @@ importers: .: dependencies: '@ai-sdk/openai': - specifier: ^3.0.26 - version: 3.0.26(zod@4.3.6) + specifier: ^3.0.28 + version: 3.0.28(zod@4.3.6) '@ai-sdk/rsc': - specifier: ^2.0.78 - version: 2.0.78(react@19.2.4)(zod@4.3.6) + specifier: ^2.0.85 + version: 2.0.85(react@19.2.4)(zod@4.3.6) '@aws-sdk/client-s3': - specifier: 3.987.0 - version: 3.987.0 + specifier: 3.989.0 + version: 3.989.0 '@aws-sdk/s3-request-presigner': - specifier: 3.987.0 - version: 3.987.0 + specifier: 3.989.0 + version: 3.989.0 '@radix-ui/react-dialog': specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 - version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-tooltip': specifier: ^1.2.8 - version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-visually-hidden': specifier: ^1.2.4 - version: 1.2.4(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@upstash/ratelimit': specifier: ^2.0.8 version: 2.0.8(@upstash/redis@1.36.2) @@ -48,8 +48,8 @@ importers: specifier: ^1.3.1 version: 1.3.1(next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) ai: - specifier: ^6.0.78 - version: 6.0.78(zod@4.3.6) + specifier: ^6.0.85 + version: 6.0.85(zod@4.3.6) camelcase-keys: specifier: ^10.0.2 version: 10.0.2 @@ -58,7 +58,7 @@ importers: version: 2.1.1 cmdk: specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) culori: specifier: ^4.0.2 version: 4.0.2 @@ -96,8 +96,8 @@ importers: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ol: - specifier: ^10.7.0 - version: 10.7.0 + specifier: ^10.8.0 + version: 10.8.0 pg: specifier: ^8.18.0 version: 8.18.0 @@ -115,7 +115,7 @@ importers: version: 5.5.0(react@19.2.4) react-openlayers: specifier: ^10.5.1 - version: 10.5.1(ol@10.7.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 10.5.1(ol@10.8.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) sanitize-html: specifier: ^2.17.0 version: 2.17.0 @@ -164,7 +164,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/culori': specifier: ^4.0.1 version: 4.0.1 @@ -181,11 +181,11 @@ importers: specifier: ^1.0.0 version: 1.0.0 '@types/react': - specifier: 19.2.13 - version: 19.2.13 + specifier: 19.2.14 + version: 19.2.14 '@types/react-dom': specifier: 19.2.3 - version: 19.2.3(@types/react@19.2.13) + version: 19.2.3(@types/react@19.2.14) '@types/sanitize-html': specifier: ^2.16.0 version: 2.16.0 @@ -225,20 +225,20 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@ai-sdk/gateway@3.0.39': - resolution: {integrity: sha512-SeCZBAdDNbWpVUXiYgOAqis22p5MEYfrjRw0hiBa5hM+7sDGYQpMinUjkM8kbPXMkY+AhKLrHleBl+SuqpzlgA==} + '@ai-sdk/gateway@3.0.45': + resolution: {integrity: sha512-ZB6kHV+D8mLCRnkpWotLCV/rZK4NiODxx4Kv7JdT9QmQknbG/scbE4iyoT4JLFdULA8Y/IVbMvyE0Nwq3Dceqw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@3.0.26': - resolution: {integrity: sha512-W/hiwxIfG29IO0Fob1HwWpFssMsNrxWoX8A7DwNGOtKArDBmJNuGzQeU/k0Fnh8WyvZEnfxkjO4oXkSXfVBayg==} + '@ai-sdk/openai@3.0.28': + resolution: {integrity: sha512-m2Dm6fwUzMksqnPrd5f/WZ4cZ9GTZHpzsVO6jxKQwwc84gFHzAFZmUCG0C5mV7XlPOw4mwaiYV3HfLiEfphvvA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.14': - resolution: {integrity: sha512-7bzKd9lgiDeXM7O4U4nQ8iTxguAOkg8LZGD9AfDVZYjO5cKYRwBPwVjboFcVrxncRHu0tYxZtXZtiLKpG4pEng==} + '@ai-sdk/provider-utils@4.0.15': + resolution: {integrity: sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -247,8 +247,8 @@ packages: resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} engines: {node: '>=18'} - '@ai-sdk/rsc@2.0.78': - resolution: {integrity: sha512-nSNj2RgVPgLVWbTvDIprmYAdV5YeL9MeNBk7eKEFhwSbI79qGTRAPnFjIEik7r1mxcdcjHGmud8ayB4hWQVNQw==} + '@ai-sdk/rsc@2.0.85': + resolution: {integrity: sha512-SsUMx1Bdtbe3/ZtZk++cVD2zN0Cm9KZvGiVtBTk8xr2Ccn2IYuU2/fW93HLPcL7/TR21ZnRzBI50d9ZBPeRvWA==} engines: {node: '>=18'} peerDependencies: react: ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1 @@ -301,52 +301,52 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.987.0': - resolution: {integrity: sha512-9nLbDIjqdiDkJk8hrAW8jP51bRXjD0+2J3lnCAy+N2G4BDoQuN09+iQF2chF/9BJ/hTk5Ldm2beaO8G2PM1cyw==} + '@aws-sdk/client-s3@3.989.0': + resolution: {integrity: sha512-ccz2miIetWAgrJYmKCpSnRjF8jew7DPstl54nufhfPMtM1MLxD2z55eSk1eJj3Umhu4CioNN1aY1ILT7fwlSiw==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-sso@3.985.0': - resolution: {integrity: sha512-81J8iE8MuXhdbMfIz4sWFj64Pe41bFi/uqqmqOC5SlGv+kwoyLsyKS/rH2tW2t5buih4vTUxskRjxlqikTD4oQ==} + '@aws-sdk/client-sso@3.989.0': + resolution: {integrity: sha512-3sC+J1ru5VFXLgt9KZmXto0M7mnV5RkS6FNGwRMK3XrojSjHso9DLOWjbnXhbNv4motH8vu53L1HK2VC1+Nj5w==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.973.7': - resolution: {integrity: sha512-wNZZQQNlJ+hzD49cKdo+PY6rsTDElO8yDImnrI69p2PLBa7QomeUKAJWYp9xnaR38nlHqWhMHZuYLCQ3oSX+xg==} + '@aws-sdk/core@3.973.9': + resolution: {integrity: sha512-cyUOfJSizn8da7XrBEFBf4UMI4A6JQNX6ZFcKtYmh/CrwfzsDcabv3k/z0bNwQ3pX5aeq5sg/8Bs/ASiL0bJaA==} engines: {node: '>=20.0.0'} '@aws-sdk/crc64-nvme@3.972.0': resolution: {integrity: sha512-ThlLhTqX68jvoIVv+pryOdb5coP1cX1/MaTbB9xkGDCbWbsqQcLqzPxuSoW1DCnAAIacmXCWpzUNOB9pv+xXQw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-env@3.972.5': - resolution: {integrity: sha512-LxJ9PEO4gKPXzkufvIESUysykPIdrV7+Ocb9yAhbhJLE4TiAYqbCVUE+VuKP1leGR1bBfjWjYgSV5MxprlX3mQ==} + '@aws-sdk/credential-provider-env@3.972.7': + resolution: {integrity: sha512-r8kBtglvLjGxBT87l6Lqkh9fL8yJJ6O4CYQPjKlj3AkCuL4/4784x3rxxXWw9LTKXOo114VB6mjxAuy5pI7XIg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.7': - resolution: {integrity: sha512-L2uOGtvp2x3bTcxFTpSM+GkwFIPd8pHfGWO1764icMbo7e5xJh0nfhx1UwkXLnwvocTNEf8A7jISZLYjUSNaTg==} + '@aws-sdk/credential-provider-http@3.972.9': + resolution: {integrity: sha512-40caFblEg/TPrp9EpvyMxp4xlJ5TuTI+A8H6g8FhHn2hfH2PObFAPLF9d5AljK/G69E1YtTklkuQeAwPlV3w8Q==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.972.5': - resolution: {integrity: sha512-SdDTYE6jkARzOeL7+kudMIM4DaFnP5dZVeatzw849k4bSXDdErDS188bgeNzc/RA2WGrlEpsqHUKP6G7sVXhZg==} + '@aws-sdk/credential-provider-ini@3.972.7': + resolution: {integrity: sha512-zeYKrMwM5bCkHFho/x3+1OL0vcZQ0OhTR7k35tLq74+GP5ieV3juHXTZfa2LVE0Bg75cHIIerpX0gomVOhzo/w==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.5': - resolution: {integrity: sha512-uYq1ILyTSI6ZDCMY5+vUsRM0SOCVI7kaW4wBrehVVkhAxC6y+e9rvGtnoZqCOWL1gKjTMouvsf4Ilhc5NCg1Aw==} + '@aws-sdk/credential-provider-login@3.972.7': + resolution: {integrity: sha512-Q103cLU6OjAllYjX7+V+PKQw654jjvZUkD+lbUUiFbqut6gR5zwl1DrelvJPM5hnzIty7BCaxaRB3KMuz3M/ug==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-node@3.972.6': - resolution: {integrity: sha512-DZ3CnAAtSVtVz+G+ogqecaErMLgzph4JH5nYbHoBMgBkwTUV+SUcjsjOJwdBJTHu3Dm6l5LBYekZoU2nDqQk2A==} + '@aws-sdk/credential-provider-node@3.972.8': + resolution: {integrity: sha512-AaDVOT7iNJyLjc3j91VlucPZ4J8Bw+eu9sllRDugJqhHWYyR3Iyp2huBUW8A3+DfHoh70sxGkY92cThAicSzlQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.5': - resolution: {integrity: sha512-HDKF3mVbLnuqGg6dMnzBf1VUOywE12/N286msI9YaK9mEIzdsGCtLTvrDhe3Up0R9/hGFbB+9l21/TwF5L1C6g==} + '@aws-sdk/credential-provider-process@3.972.7': + resolution: {integrity: sha512-hxMo1V3ujWWrQSONxQJAElnjredkRpB6p8SDjnvRq70IwYY38R/CZSys0IbhRPxdgWZ5j12yDRk2OXhxw4Gj3g==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.972.5': - resolution: {integrity: sha512-8urj3AoeNeQisjMmMBhFeiY2gxt6/7wQQbEGun0YV/OaOOiXrIudTIEYF8ZfD+NQI6X1FY5AkRsx6O/CaGiybA==} + '@aws-sdk/credential-provider-sso@3.972.7': + resolution: {integrity: sha512-ZGKBOHEj8Ap15jhG2XMncQmKLTqA++2DVU2eZfLu3T/pkwDyhCp5eZv5c/acFxbZcA/6mtxke+vzO/n+aeHs4A==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.5': - resolution: {integrity: sha512-OK3cULuJl6c+RcDZfPpaK5o3deTOnKZbxm7pzhFNGA3fI2hF9yDih17fGRazJzGGWaDVlR9ejZrpDef4DJCEsw==} + '@aws-sdk/credential-provider-web-identity@3.972.7': + resolution: {integrity: sha512-AbYupBIoSJoVMlbMqBhNvPhqj+CdGtzW7Uk4ZIMBm2br18pc3rkG1VaKVFV85H87QCvLHEnni1idJjaX1wOmIw==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-bucket-endpoint@3.972.3': @@ -357,8 +357,8 @@ packages: resolution: {integrity: sha512-4msC33RZsXQpUKR5QR4HnvBSNCPLGHmB55oDiROqqgyOc+TOfVu2xgi5goA7ms6MdZLeEh2905UfWMnMMF4mRg==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.972.5': - resolution: {integrity: sha512-SF/1MYWx67OyCrLA4icIpWUfCkdlOi8Y1KecQ9xYxkL10GMjVdPTGPnYhAg0dw5U43Y9PVUWhAV2ezOaG+0BLg==} + '@aws-sdk/middleware-flexible-checksums@3.972.7': + resolution: {integrity: sha512-YU/5rpz8k2mwFGi2M0px9ChOQZY7Bbow5knB2WLRVPqDM/cG8T5zj55UaWS1qcaFpE7vCX9a9/kvYBlKGcD+KA==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-host-header@3.972.3': @@ -377,36 +377,36 @@ packages: resolution: {integrity: sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-sdk-s3@3.972.7': - resolution: {integrity: sha512-VtZ7tMIw18VzjG+I6D6rh2eLkJfTtByiFoCIauGDtTTPBEUMQUiGaJ/zZrPlCY6BsvLLeFKz3+E5mntgiOWmIg==} + '@aws-sdk/middleware-sdk-s3@3.972.9': + resolution: {integrity: sha512-F4Ak2HM7te/o3izFTqg/jUTBLjavpaJ5iynKM6aLMwNddXbwAZQ1VbIG8RFUHBo7fBHj2eeN2FNLtIFT4ejWYQ==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-ssec@3.972.3': resolution: {integrity: sha512-dU6kDuULN3o3jEHcjm0c4zWJlY1zWVkjG9NPe9qxYLLpcbdj5kRYBS2DdWYD+1B9f910DezRuws7xDEqKkHQIg==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.972.7': - resolution: {integrity: sha512-HUD+geASjXSCyL/DHPQc/Ua7JhldTcIglVAoCV8kiVm99IaFSlAbTvEnyhZwdE6bdFyTL+uIaWLaCFSRsglZBQ==} + '@aws-sdk/middleware-user-agent@3.972.9': + resolution: {integrity: sha512-1g1B7yf7KzessB0mKNiV9gAHEwbM662xgU+VE4LxyGe6kVGZ8LqYsngjhE+Stna09CJ7Pxkjr6Uq1OtbGwJJJg==} engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.985.0': - resolution: {integrity: sha512-TsWwKzb/2WHafAY0CE7uXgLj0FmnkBTgfioG9HO+7z/zCPcl1+YU+i7dW4o0y+aFxFgxTMG+ExBQpqT/k2ao8g==} + '@aws-sdk/nested-clients@3.989.0': + resolution: {integrity: sha512-Dbk2HMPU3mb6RrSRzgf0WCaWSbgtZG258maCpuN2/ONcAQNpOTw99V5fU5CA1qVK6Vkm4Fwj2cnOnw7wbGVlOw==} engines: {node: '>=20.0.0'} '@aws-sdk/region-config-resolver@3.972.3': resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==} engines: {node: '>=20.0.0'} - '@aws-sdk/s3-request-presigner@3.987.0': - resolution: {integrity: sha512-XHf9ZQOgsdzBhfFhMM+wFITnd1M3OqMVUEdIrciSS8aFOg+WtQEcR2GcMs+Sj5whmO4XOrUMFuDdCgAwvdq0tg==} + '@aws-sdk/s3-request-presigner@3.989.0': + resolution: {integrity: sha512-cn5e6DODSDulkyGvVCM7E66kGNdyYkMEiSTwTVKWrrc+Vv19AZaytt2n+GARjGOzTsGy48BLW/jyp5iexfdB6g==} engines: {node: '>=20.0.0'} - '@aws-sdk/signature-v4-multi-region@3.987.0': - resolution: {integrity: sha512-5kVC6x6+2NO+/NIXWJwN68+8cvqREsoE+tFOMyZWj2fg3EWzCnTGVIFd7hSJZJT2WiP5LqcrdEoFyXtfDta1hg==} + '@aws-sdk/signature-v4-multi-region@3.989.0': + resolution: {integrity: sha512-rVhR/BUZdnru7tLlxWD+uzoKB1LAs2L0pcoh6rYgIYuCtQflnsC6Ud0SpfqIsOapBSBKXdoW73IITFf+XFMdCQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.985.0': - resolution: {integrity: sha512-+hwpHZyEq8k+9JL2PkE60V93v2kNhUIv7STFt+EAez1UJsJOQDhc5LpzEX66pNjclI5OTwBROs/DhJjC/BtMjQ==} + '@aws-sdk/token-providers@3.989.0': + resolution: {integrity: sha512-OdBByMv+OjOZoekrk4THPFpLuND5aIQbDHCGh3n2rvifAbm31+6e0OLhxSeCF1UMPm+nKq12bXYYEoCIx5SQBg==} engines: {node: '>=20.0.0'} '@aws-sdk/types@3.973.1': @@ -417,12 +417,8 @@ packages: resolution: {integrity: sha512-VkykWbqMjlSgBFDyrY3nOSqupMc6ivXuGmvci6Q3NnLq5kC+mKQe2QBZ4nrWRE/jqOxeFP2uYzLtwncYYcvQDg==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-endpoints@3.985.0': - resolution: {integrity: sha512-vth7UfGSUR3ljvaq8V4Rc62FsM7GUTH/myxPWkaEgOrprz1/Pc72EgTXxj+cPPPDAfHFIpjhkB7T7Td0RJx+BA==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/util-endpoints@3.987.0': - resolution: {integrity: sha512-rZnZwDq7Pn+TnL0nyS6ryAhpqTZtLtHbJaqfxuHlDX3v/bq0M7Ch/V3qF9dZWaGgsJ2H9xn7/vFOxlnL4fBMcQ==} + '@aws-sdk/util-endpoints@3.989.0': + resolution: {integrity: sha512-eKmAOeQM4Qusq0jtcbZPiNWky8XaojByKC/n+THbJ8vJf7t4ys8LlcZ4PrBSHZISe9cC484mQsPVOQh6iySjqw==} engines: {node: '>=20.0.0'} '@aws-sdk/util-format-url@3.972.3': @@ -436,8 +432,8 @@ packages: '@aws-sdk/util-user-agent-browser@3.972.3': resolution: {integrity: sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==} - '@aws-sdk/util-user-agent-node@3.972.5': - resolution: {integrity: sha512-GsUDF+rXyxDZkkJxUsDxnA67FG+kc5W1dnloCFLl6fWzceevsCYzJpASBzT+BPjwUgREE6FngfJYYYMQUY5fZQ==} + '@aws-sdk/util-user-agent-node@3.972.7': + resolution: {integrity: sha512-oyhv+FjrgHjP+F16cmsrJzNP4qaRJzkV1n9Lvv4uyh3kLqo3rIe9NSBSBa35f2TedczfG2dD+kaQhHBB47D6Og==} engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -1484,8 +1480,8 @@ packages: resolution: {integrity: sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==} engines: {node: '>=18.0.0'} - '@smithy/core@3.22.1': - resolution: {integrity: sha512-x3ie6Crr58MWrm4viHqqy2Du2rHYZjwu8BekasrQx4ca+Y24dzVAwq3yErdqIbc2G3I0kLQA13PQ+/rde+u65g==} + '@smithy/core@3.23.0': + resolution: {integrity: sha512-Yq4UPVoQICM9zHnByLmG8632t2M0+yap4T7ANVw482J0W7HW0pOuxwVmeOwzJqX2Q89fkXz0Vybz55Wj2Xzrsg==} engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.2.8': @@ -1548,12 +1544,12 @@ packages: resolution: {integrity: sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.4.13': - resolution: {integrity: sha512-x6vn0PjYmGdNuKh/juUJJewZh7MoQ46jYaJ2mvekF4EesMuFfrl4LaW/k97Zjf8PTCPQmPgMvwewg7eNoH9n5w==} + '@smithy/middleware-endpoint@4.4.14': + resolution: {integrity: sha512-FUFNE5KVeaY6U/GL0nzAAHkaCHzXLZcY1EhtQnsAqhD8Du13oPKtMB9/0WK4/LK6a/T5OZ24wPoSShff5iI6Ag==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.4.30': - resolution: {integrity: sha512-CBGyFvN0f8hlnqKH/jckRDz78Snrp345+PVk8Ux7pnkUCW97Iinse59lY78hBt04h1GZ6hjBN94BRwZy1xC8Bg==} + '@smithy/middleware-retry@4.4.31': + resolution: {integrity: sha512-RXBzLpMkIrxBPe4C8OmEOHvS8aH9RUuCOH++Acb5jZDEblxDjyg6un72X9IcbrGTJoiUwmI7hLypNfuDACypbg==} engines: {node: '>=18.0.0'} '@smithy/middleware-serde@4.2.9': @@ -1568,8 +1564,8 @@ packages: resolution: {integrity: sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.4.9': - resolution: {integrity: sha512-KX5Wml5mF+luxm1szW4QDz32e3NObgJ4Fyw+irhph4I/2geXwUy4jkIMUs5ZPGflRBeR6BUkC2wqIab4Llgm3w==} + '@smithy/node-http-handler@4.4.10': + resolution: {integrity: sha512-u4YeUwOWRZaHbWaebvrs3UhwQwj+2VNmcVCwXcYTvPIuVyM7Ex1ftAj+fdbG/P4AkBwLq/+SKn+ydOI4ZJE9PA==} engines: {node: '>=18.0.0'} '@smithy/property-provider@4.2.8': @@ -1600,8 +1596,8 @@ packages: resolution: {integrity: sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.11.2': - resolution: {integrity: sha512-SCkGmFak/xC1n7hKRsUr6wOnBTJ3L22Qd4e8H1fQIuKTAjntwgU8lrdMe7uHdiT2mJAOWA/60qaW9tiMu69n1A==} + '@smithy/smithy-client@4.11.3': + resolution: {integrity: sha512-Q7kY5sDau8OoE6Y9zJoRGgje8P4/UY0WzH8R2ok0PDh+iJ+ZnEKowhjEqYafVcubkbYxQVaqwm3iufktzhprGg==} engines: {node: '>=18.0.0'} '@smithy/types@4.12.0': @@ -1636,12 +1632,12 @@ packages: resolution: {integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.3.29': - resolution: {integrity: sha512-nIGy3DNRmOjaYaaKcQDzmWsro9uxlaqUOhZDHQed9MW/GmkBZPtnU70Pu1+GT9IBmUXwRdDuiyaeiy9Xtpn3+Q==} + '@smithy/util-defaults-mode-browser@4.3.30': + resolution: {integrity: sha512-cMni0uVU27zxOiU8TuC8pQLC1pYeZ/xEMxvchSK/ILwleRd1ugobOcIRr5vXtcRqKd4aBLWlpeBoDPJJ91LQng==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.2.32': - resolution: {integrity: sha512-7dtFff6pu5fsjqrVve0YMhrnzJtccCWDacNKOkiZjJ++fmjGExmmSu341x+WU6Oc1IccL7lDuaUj7SfrHpWc5Q==} + '@smithy/util-defaults-mode-node@4.2.33': + resolution: {integrity: sha512-LEb2aq5F4oZUSzWBG7S53d4UytZSkOEJPXcBq/xbG2/TmK9EW5naUZ8lKu1BEyWMzdHIzEVN16M3k8oxDq+DJA==} engines: {node: '>=18.0.0'} '@smithy/util-endpoints@3.2.8': @@ -1660,8 +1656,8 @@ packages: resolution: {integrity: sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==} engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.5.11': - resolution: {integrity: sha512-lKmZ0S/3Qj2OF5H1+VzvDLb6kRxGzZHq6f3rAsoSu5cTLGsn3v3VQBA8czkNNXlLjoFEtVu3OQT2jEeOtOE2CA==} + '@smithy/util-stream@4.5.12': + resolution: {integrity: sha512-D8tgkrmhAX/UNeCZbqbEO3uqyghUnEmmoO9YEvRuwxjlkKKUE7FOgCJnqpTlQPe9MApdWPky58mNQQHbnCzoNg==} engines: {node: '>=18.0.0'} '@smithy/util-uri-escape@4.2.0': @@ -1885,8 +1881,8 @@ packages: peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.13': - resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} '@types/sanitize-html@2.16.0': resolution: {integrity: sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==} @@ -2145,6 +2141,9 @@ packages: vue-router: optional: true + '@zarrita/storage@0.1.4': + resolution: {integrity: sha512-qURfJAQcQGRfDQ4J9HaCjGaj3jlJKc66bnRk6G/IeLUsM7WKyG7Bzsuf1EZurSXyc0I4LVcu6HaeQQ4d3kZ16g==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2163,8 +2162,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ai@6.0.78: - resolution: {integrity: sha512-eriIX/NLWfWNDeE/OJy8wmIp9fyaH7gnxTOCPT5bp0MNkvORstp1TwRUql9au8XjXzH7o2WApqbwgxJDDV0Rbw==} + ai@6.0.85: + resolution: {integrity: sha512-2bP7M+OcNQGSIH8I3jdujUadxj4tAwuHBvLhpmDSlcjRXXry3zNGEajjjRraOjObHMO/Yqa37PJWhPVHIHt2TQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -2828,6 +2827,9 @@ packages: picomatch: optional: true + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2899,8 +2901,8 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - geotiff@2.1.3: - resolution: {integrity: sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==} + geotiff@3.0.3: + resolution: {integrity: sha512-yRoDQDYxWYiB421p0cbxJvdy79OlQW+rxDI9GDbIUeWCAh6YAZ0vlTKF448EAiEuuUpBsNaegd2flavF0p+kvw==} engines: {node: '>=10.19'} get-caller-file@2.0.5: @@ -3712,6 +3714,9 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + numcodecs@0.3.2: + resolution: {integrity: sha512-6YSPnmZgg0P87jnNhi3s+FVLOcIn3y+1CTIgUulA3IdASzK9fJM87sUFkpyA+be9GibGRaST2wCgkD+6U+fWKw==} + nwsapi@2.2.22: resolution: {integrity: sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==} @@ -3750,8 +3755,8 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - ol@10.7.0: - resolution: {integrity: sha512-122U5gamPqNgLpLOkogFJhgpywvd/5en2kETIDW+Ubfi9lPnZ0G9HWRdG+CX0oP8od2d6u6ky3eewIYYlrVczw==} + ol@10.8.0: + resolution: {integrity: sha512-kLk7jIlJvKyhVMAjORTXKjzlM6YIByZ1H/d0DBx3oq8nSPCG6/gbLr5RxukzPgwbhnAqh+xHNCmrvmFKhVMvoQ==} once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -4039,6 +4044,9 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} + reference-spec-reader@0.2.0: + resolution: {integrity: sha512-q0mfCi5yZSSHXpCyxjgQeaORq3tvDsxDyzaadA/5+AbAUwRyRuuTh0aRQuE/vAOt/qzzxidJ5iDeu1cLHaNBlQ==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -4464,6 +4472,10 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + unzipit@1.4.3: + resolution: {integrity: sha512-gsq2PdJIWWGhx5kcdWStvNWit9FVdTewm4SEG7gFskWs+XCVaULt9+BwuoBtJiRE8eo3L1IPAOrbByNLtLtIlg==} + engines: {node: '>=12'} + update-browserslist-db@1.1.4: resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} hasBin: true @@ -4504,6 +4516,9 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + uzip-module@1.0.3: + resolution: {integrity: sha512-AMqwWZaknLM77G+VPYNZLEruMGWGzyigPK3/Whg99B3S6vGHuqsyl5ZrOv1UUF3paGK1U6PM0cnayioaryg/fA==} + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -4652,6 +4667,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zarrita@0.6.1: + resolution: {integrity: sha512-YOMTW8FT55Rz+vadTIZeOFZ/F2h4svKizyldvPtMYSxPgSNcRkOzkxCsWpIWlWzB1I/LmISmi0bEekOhLlI+Zw==} + zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} @@ -4661,27 +4679,27 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} - zstddec@0.1.0: - resolution: {integrity: sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==} + zstddec@0.2.0: + resolution: {integrity: sha512-oyPnDa1X5c13+Y7mA/FDMNJrn4S8UNBe0KCqtDmor40Re7ALrPN6npFwyYVRRh+PqozZQdeg23QtbcamZnG5rA==} snapshots: '@adobe/css-tools@4.4.4': {} - '@ai-sdk/gateway@3.0.39(zod@4.3.6)': + '@ai-sdk/gateway@3.0.45(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.14(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) '@vercel/oidc': 3.1.0 zod: 4.3.6 - '@ai-sdk/openai@3.0.26(zod@4.3.6)': + '@ai-sdk/openai@3.0.28(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.14(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/provider-utils@4.0.14(zod@4.3.6)': + '@ai-sdk/provider-utils@4.0.15(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@standard-schema/spec': 1.1.0 @@ -4692,11 +4710,11 @@ snapshots: dependencies: json-schema: 0.4.0 - '@ai-sdk/rsc@2.0.78(react@19.2.4)(zod@4.3.6)': + '@ai-sdk/rsc@2.0.85(react@19.2.4)(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.14(zod@4.3.6) - ai: 6.0.78(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) + ai: 6.0.85(zod@4.3.6) jsondiffpatch: 0.7.3 react: 19.2.4 optionalDependencies: @@ -4767,31 +4785,31 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.987.0': + '@aws-sdk/client-s3@3.989.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.7 - '@aws-sdk/credential-provider-node': 3.972.6 + '@aws-sdk/core': 3.973.9 + '@aws-sdk/credential-provider-node': 3.972.8 '@aws-sdk/middleware-bucket-endpoint': 3.972.3 '@aws-sdk/middleware-expect-continue': 3.972.3 - '@aws-sdk/middleware-flexible-checksums': 3.972.5 + '@aws-sdk/middleware-flexible-checksums': 3.972.7 '@aws-sdk/middleware-host-header': 3.972.3 '@aws-sdk/middleware-location-constraint': 3.972.3 '@aws-sdk/middleware-logger': 3.972.3 '@aws-sdk/middleware-recursion-detection': 3.972.3 - '@aws-sdk/middleware-sdk-s3': 3.972.7 + '@aws-sdk/middleware-sdk-s3': 3.972.9 '@aws-sdk/middleware-ssec': 3.972.3 - '@aws-sdk/middleware-user-agent': 3.972.7 + '@aws-sdk/middleware-user-agent': 3.972.9 '@aws-sdk/region-config-resolver': 3.972.3 - '@aws-sdk/signature-v4-multi-region': 3.987.0 + '@aws-sdk/signature-v4-multi-region': 3.989.0 '@aws-sdk/types': 3.973.1 - '@aws-sdk/util-endpoints': 3.987.0 + '@aws-sdk/util-endpoints': 3.989.0 '@aws-sdk/util-user-agent-browser': 3.972.3 - '@aws-sdk/util-user-agent-node': 3.972.5 + '@aws-sdk/util-user-agent-node': 3.972.7 '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/eventstream-serde-browser': 4.2.8 '@smithy/eventstream-serde-config-resolver': 4.3.8 '@smithy/eventstream-serde-node': 4.2.8 @@ -4802,66 +4820,66 @@ snapshots: '@smithy/invalid-dependency': 4.2.8 '@smithy/md5-js': 4.2.8 '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.13 - '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 '@smithy/middleware-serde': 4.2.9 '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.29 - '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 '@smithy/util-waiter': 4.2.8 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.985.0': + '@aws-sdk/client-sso@3.989.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/middleware-host-header': 3.972.3 '@aws-sdk/middleware-logger': 3.972.3 '@aws-sdk/middleware-recursion-detection': 3.972.3 - '@aws-sdk/middleware-user-agent': 3.972.7 + '@aws-sdk/middleware-user-agent': 3.972.9 '@aws-sdk/region-config-resolver': 3.972.3 '@aws-sdk/types': 3.973.1 - '@aws-sdk/util-endpoints': 3.985.0 + '@aws-sdk/util-endpoints': 3.989.0 '@aws-sdk/util-user-agent-browser': 3.972.3 - '@aws-sdk/util-user-agent-node': 3.972.5 + '@aws-sdk/util-user-agent-node': 3.972.7 '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/fetch-http-handler': 5.3.9 '@smithy/hash-node': 4.2.8 '@smithy/invalid-dependency': 4.2.8 '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.13 - '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 '@smithy/middleware-serde': 4.2.9 '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.29 - '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 @@ -4870,16 +4888,16 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.973.7': + '@aws-sdk/core@3.973.9': dependencies: '@aws-sdk/types': 3.973.1 '@aws-sdk/xml-builder': 3.972.4 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/node-config-provider': 4.3.8 '@smithy/property-provider': 4.2.8 '@smithy/protocol-http': 5.3.8 '@smithy/signature-v4': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/util-base64': 4.3.0 '@smithy/util-middleware': 4.2.8 @@ -4891,37 +4909,37 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.5': + '@aws-sdk/credential-provider-env@3.972.7': dependencies: - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.7': + '@aws-sdk/credential-provider-http@3.972.9': dependencies: - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/types': 3.973.1 '@smithy/fetch-http-handler': 5.3.9 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/property-provider': 4.2.8 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.972.5': + '@aws-sdk/credential-provider-ini@3.972.7': dependencies: - '@aws-sdk/core': 3.973.7 - '@aws-sdk/credential-provider-env': 3.972.5 - '@aws-sdk/credential-provider-http': 3.972.7 - '@aws-sdk/credential-provider-login': 3.972.5 - '@aws-sdk/credential-provider-process': 3.972.5 - '@aws-sdk/credential-provider-sso': 3.972.5 - '@aws-sdk/credential-provider-web-identity': 3.972.5 - '@aws-sdk/nested-clients': 3.985.0 + '@aws-sdk/core': 3.973.9 + '@aws-sdk/credential-provider-env': 3.972.7 + '@aws-sdk/credential-provider-http': 3.972.9 + '@aws-sdk/credential-provider-login': 3.972.7 + '@aws-sdk/credential-provider-process': 3.972.7 + '@aws-sdk/credential-provider-sso': 3.972.7 + '@aws-sdk/credential-provider-web-identity': 3.972.7 + '@aws-sdk/nested-clients': 3.989.0 '@aws-sdk/types': 3.973.1 '@smithy/credential-provider-imds': 4.2.8 '@smithy/property-provider': 4.2.8 @@ -4931,10 +4949,10 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.972.5': + '@aws-sdk/credential-provider-login@3.972.7': dependencies: - '@aws-sdk/core': 3.973.7 - '@aws-sdk/nested-clients': 3.985.0 + '@aws-sdk/core': 3.973.9 + '@aws-sdk/nested-clients': 3.989.0 '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/protocol-http': 5.3.8 @@ -4944,14 +4962,14 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.972.6': + '@aws-sdk/credential-provider-node@3.972.8': dependencies: - '@aws-sdk/credential-provider-env': 3.972.5 - '@aws-sdk/credential-provider-http': 3.972.7 - '@aws-sdk/credential-provider-ini': 3.972.5 - '@aws-sdk/credential-provider-process': 3.972.5 - '@aws-sdk/credential-provider-sso': 3.972.5 - '@aws-sdk/credential-provider-web-identity': 3.972.5 + '@aws-sdk/credential-provider-env': 3.972.7 + '@aws-sdk/credential-provider-http': 3.972.9 + '@aws-sdk/credential-provider-ini': 3.972.7 + '@aws-sdk/credential-provider-process': 3.972.7 + '@aws-sdk/credential-provider-sso': 3.972.7 + '@aws-sdk/credential-provider-web-identity': 3.972.7 '@aws-sdk/types': 3.973.1 '@smithy/credential-provider-imds': 4.2.8 '@smithy/property-provider': 4.2.8 @@ -4961,20 +4979,20 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.972.5': + '@aws-sdk/credential-provider-process@3.972.7': dependencies: - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/shared-ini-file-loader': 4.4.3 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.972.5': + '@aws-sdk/credential-provider-sso@3.972.7': dependencies: - '@aws-sdk/client-sso': 3.985.0 - '@aws-sdk/core': 3.973.7 - '@aws-sdk/token-providers': 3.985.0 + '@aws-sdk/client-sso': 3.989.0 + '@aws-sdk/core': 3.973.9 + '@aws-sdk/token-providers': 3.989.0 '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/shared-ini-file-loader': 4.4.3 @@ -4983,10 +5001,10 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.972.5': + '@aws-sdk/credential-provider-web-identity@3.972.7': dependencies: - '@aws-sdk/core': 3.973.7 - '@aws-sdk/nested-clients': 3.985.0 + '@aws-sdk/core': 3.973.9 + '@aws-sdk/nested-clients': 3.989.0 '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/shared-ini-file-loader': 4.4.3 @@ -5012,12 +5030,12 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-flexible-checksums@3.972.5': + '@aws-sdk/middleware-flexible-checksums@3.972.7': dependencies: '@aws-crypto/crc32': 5.2.0 '@aws-crypto/crc32c': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/crc64-nvme': 3.972.0 '@aws-sdk/types': 3.973.1 '@smithy/is-array-buffer': 4.2.0 @@ -5025,7 +5043,7 @@ snapshots: '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 '@smithy/util-middleware': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 @@ -5056,20 +5074,20 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.972.7': + '@aws-sdk/middleware-sdk-s3@3.972.9': dependencies: - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/types': 3.973.1 '@aws-sdk/util-arn-parser': 3.972.2 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/node-config-provider': 4.3.8 '@smithy/protocol-http': 5.3.8 '@smithy/signature-v4': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/util-config-provider': 4.2.0 '@smithy/util-middleware': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 @@ -5079,51 +5097,51 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.7': + '@aws-sdk/middleware-user-agent@3.972.9': dependencies: - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/types': 3.973.1 - '@aws-sdk/util-endpoints': 3.985.0 - '@smithy/core': 3.22.1 + '@aws-sdk/util-endpoints': 3.989.0 + '@smithy/core': 3.23.0 '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.985.0': + '@aws-sdk/nested-clients@3.989.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.7 + '@aws-sdk/core': 3.973.9 '@aws-sdk/middleware-host-header': 3.972.3 '@aws-sdk/middleware-logger': 3.972.3 '@aws-sdk/middleware-recursion-detection': 3.972.3 - '@aws-sdk/middleware-user-agent': 3.972.7 + '@aws-sdk/middleware-user-agent': 3.972.9 '@aws-sdk/region-config-resolver': 3.972.3 '@aws-sdk/types': 3.973.1 - '@aws-sdk/util-endpoints': 3.985.0 + '@aws-sdk/util-endpoints': 3.989.0 '@aws-sdk/util-user-agent-browser': 3.972.3 - '@aws-sdk/util-user-agent-node': 3.972.5 + '@aws-sdk/util-user-agent-node': 3.972.7 '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/fetch-http-handler': 5.3.9 '@smithy/hash-node': 4.2.8 '@smithy/invalid-dependency': 4.2.8 '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.13 - '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 '@smithy/middleware-serde': 4.2.9 '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.29 - '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 @@ -5140,30 +5158,30 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/s3-request-presigner@3.987.0': + '@aws-sdk/s3-request-presigner@3.989.0': dependencies: - '@aws-sdk/signature-v4-multi-region': 3.987.0 + '@aws-sdk/signature-v4-multi-region': 3.989.0 '@aws-sdk/types': 3.973.1 '@aws-sdk/util-format-url': 3.972.3 - '@smithy/middleware-endpoint': 4.4.13 + '@smithy/middleware-endpoint': 4.4.14 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.987.0': + '@aws-sdk/signature-v4-multi-region@3.989.0': dependencies: - '@aws-sdk/middleware-sdk-s3': 3.972.7 + '@aws-sdk/middleware-sdk-s3': 3.972.9 '@aws-sdk/types': 3.973.1 '@smithy/protocol-http': 5.3.8 '@smithy/signature-v4': 5.3.8 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.985.0': + '@aws-sdk/token-providers@3.989.0': dependencies: - '@aws-sdk/core': 3.973.7 - '@aws-sdk/nested-clients': 3.985.0 + '@aws-sdk/core': 3.973.9 + '@aws-sdk/nested-clients': 3.989.0 '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/shared-ini-file-loader': 4.4.3 @@ -5181,15 +5199,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.985.0': - dependencies: - '@aws-sdk/types': 3.973.1 - '@smithy/types': 4.12.0 - '@smithy/url-parser': 4.2.8 - '@smithy/util-endpoints': 3.2.8 - tslib: 2.8.1 - - '@aws-sdk/util-endpoints@3.987.0': + '@aws-sdk/util-endpoints@3.989.0': dependencies: '@aws-sdk/types': 3.973.1 '@smithy/types': 4.12.0 @@ -5215,9 +5225,9 @@ snapshots: bowser: 2.12.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.972.5': + '@aws-sdk/util-user-agent-node@3.972.7': dependencies: - '@aws-sdk/middleware-user-agent': 3.972.7 + '@aws-sdk/middleware-user-agent': 3.972.9 '@aws-sdk/types': 3.973.1 '@smithy/node-config-provider': 4.3.8 '@smithy/types': 4.12.0 @@ -5942,317 +5952,317 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': dependencies: react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-context@1.1.2(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': dependencies: react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) aria-hidden: 1.2.6 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.1(@types/react@19.2.13)(react@19.2.4) + react-remove-scroll: 2.7.1(@types/react@19.2.14)(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.4)': dependencies: react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-id@1.1.1(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) aria-hidden: 1.2.6 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.1(@types/react@19.2.13)(react@19.2.4) + react-remove-scroll: 2.7.1(@types/react@19.2.14)(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@floating-ui/react-dom': 2.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) '@radix-ui/rect': 1.1.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-slot@1.2.3(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-slot@1.2.4(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: '@radix-ui/rect': 1.1.1 react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.13)(react@19.2.4)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-visually-hidden@1.2.4(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-visually-hidden@1.2.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/rect@1.1.1': {} @@ -6291,7 +6301,7 @@ snapshots: '@smithy/util-middleware': 4.2.8 tslib: 2.8.1 - '@smithy/core@3.22.1': + '@smithy/core@3.23.0': dependencies: '@smithy/middleware-serde': 4.2.9 '@smithy/protocol-http': 5.3.8 @@ -6299,7 +6309,7 @@ snapshots: '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-middleware': 4.2.8 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 '@smithy/uuid': 1.1.0 tslib: 2.8.1 @@ -6395,9 +6405,9 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.4.13': + '@smithy/middleware-endpoint@4.4.14': dependencies: - '@smithy/core': 3.22.1 + '@smithy/core': 3.23.0 '@smithy/middleware-serde': 4.2.9 '@smithy/node-config-provider': 4.3.8 '@smithy/shared-ini-file-loader': 4.4.3 @@ -6406,12 +6416,12 @@ snapshots: '@smithy/util-middleware': 4.2.8 tslib: 2.8.1 - '@smithy/middleware-retry@4.4.30': + '@smithy/middleware-retry@4.4.31': dependencies: '@smithy/node-config-provider': 4.3.8 '@smithy/protocol-http': 5.3.8 '@smithy/service-error-classification': 4.2.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 @@ -6436,7 +6446,7 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/node-http-handler@4.4.9': + '@smithy/node-http-handler@4.4.10': dependencies: '@smithy/abort-controller': 4.2.8 '@smithy/protocol-http': 5.3.8 @@ -6485,14 +6495,14 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@smithy/smithy-client@4.11.2': + '@smithy/smithy-client@4.11.3': dependencies: - '@smithy/core': 3.22.1 - '@smithy/middleware-endpoint': 4.4.13 + '@smithy/core': 3.23.0 + '@smithy/middleware-endpoint': 4.4.14 '@smithy/middleware-stack': 4.2.8 '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 - '@smithy/util-stream': 4.5.11 + '@smithy/util-stream': 4.5.12 tslib: 2.8.1 '@smithy/types@4.12.0': @@ -6533,20 +6543,20 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.3.29': + '@smithy/util-defaults-mode-browser@4.3.30': dependencies: '@smithy/property-provider': 4.2.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.2.32': + '@smithy/util-defaults-mode-node@4.2.33': dependencies: '@smithy/config-resolver': 4.4.6 '@smithy/credential-provider-imds': 4.2.8 '@smithy/node-config-provider': 4.3.8 '@smithy/property-provider': 4.2.8 - '@smithy/smithy-client': 4.11.2 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -6571,10 +6581,10 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@smithy/util-stream@4.5.11': + '@smithy/util-stream@4.5.12': dependencies: '@smithy/fetch-http-handler': 5.3.9 - '@smithy/node-http-handler': 4.4.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/types': 4.12.0 '@smithy/util-base64': 4.3.0 '@smithy/util-buffer-from': 4.2.0 @@ -6711,15 +6721,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@babel/runtime': 7.28.4 '@testing-library/dom': 10.4.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) '@tsconfig/node10@1.0.12': {} @@ -6800,11 +6810,11 @@ snapshots: '@types/rbush@4.0.0': {} - '@types/react-dom@19.2.3(@types/react@19.2.13)': + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@types/react@19.2.13': + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -7013,6 +7023,11 @@ snapshots: next: 16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 + '@zarrita/storage@0.1.4': + dependencies: + reference-spec-reader: 0.2.0 + unzipit: 1.4.3 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -7025,11 +7040,11 @@ snapshots: agent-base@7.1.4: {} - ai@6.0.78(zod@4.3.6): + ai@6.0.85(zod@4.3.6): dependencies: - '@ai-sdk/gateway': 3.0.39(zod@4.3.6) + '@ai-sdk/gateway': 3.0.45(zod@4.3.6) '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.14(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) '@opentelemetry/api': 1.9.0 zod: 4.3.6 @@ -7302,12 +7317,12 @@ snapshots: clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: @@ -7866,6 +7881,8 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fflate@0.8.2: {} + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -7931,7 +7948,7 @@ snapshots: gensync@1.0.0-beta.2: {} - geotiff@2.1.3: + geotiff@3.0.3: dependencies: '@petamoriken/float16': 3.9.3 lerc: 3.0.0 @@ -7940,7 +7957,7 @@ snapshots: quick-lru: 6.1.2 web-worker: 1.5.0 xml-utils: 1.10.2 - zstddec: 0.1.0 + zstddec: 0.2.0 get-caller-file@2.0.5: {} @@ -8891,6 +8908,10 @@ snapshots: dependencies: path-key: 3.1.1 + numcodecs@0.3.2: + dependencies: + fflate: 0.8.2 + nwsapi@2.2.22: {} oauth4webapi@3.8.2: {} @@ -8937,13 +8958,14 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - ol@10.7.0: + ol@10.8.0: dependencies: '@types/rbush': 4.0.0 earcut: 3.0.2 - geotiff: 2.1.3 + geotiff: 3.0.3 pbf: 4.0.1 rbush: 4.0.1 + zarrita: 0.6.1 once@1.4.0: dependencies: @@ -9162,38 +9184,38 @@ snapshots: react-is@18.3.1: {} - react-openlayers@10.5.1(ol@10.7.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-openlayers@10.5.1(ol@10.8.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - ol: 10.7.0 + ol: 10.8.0 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - react-remove-scroll-bar@2.3.8(@types/react@19.2.13)(react@19.2.4): + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): dependencies: react: 19.2.4 - react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - react-remove-scroll@2.7.1(@types/react@19.2.13)(react@19.2.4): + react-remove-scroll@2.7.1(@types/react@19.2.14)(react@19.2.4): dependencies: react: 19.2.4 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.13)(react@19.2.4) - react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.4) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.13)(react@19.2.4) - use-sidecar: 1.1.3(@types/react@19.2.13)(react@19.2.4) + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.4) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.4) optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - react-style-singleton@2.2.3(@types/react@19.2.13)(react@19.2.4): + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.4): dependencies: get-nonce: 1.0.1 react: 19.2.4 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 react@19.2.4: {} @@ -9202,6 +9224,8 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 + reference-spec-reader@0.2.0: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -9721,6 +9745,10 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + unzipit@1.4.3: + dependencies: + uzip-module: 1.0.3 + update-browserslist-db@1.1.4(browserslist@4.28.0): dependencies: browserslist: 4.28.0 @@ -9731,29 +9759,31 @@ snapshots: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@19.2.13)(react@19.2.4): + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): dependencies: react: 19.2.4 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 use-debounce@10.1.0(react@19.2.4): dependencies: react: 19.2.4 - use-sidecar@1.1.3(@types/react@19.2.13)(react@19.2.4): + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): dependencies: detect-node-es: 1.1.0 react: 19.2.4 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 use-sync-external-store@1.6.0(react@19.2.4): dependencies: react: 19.2.4 + uzip-module@1.0.3: {} + v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: @@ -9911,10 +9941,15 @@ snapshots: yocto-queue@0.1.0: {} + zarrita@0.6.1: + dependencies: + '@zarrita/storage': 0.1.4 + numcodecs: 0.3.2 + zod-validation-error@4.0.2(zod@4.3.6): dependencies: zod: 4.3.6 zod@4.3.6: {} - zstddec@0.1.0: {} + zstddec@0.2.0: {} diff --git a/src/admin/DeletePhotosButton.tsx b/src/admin/DeletePhotosButton.tsx index 9e42edd4..fe5761c9 100644 --- a/src/admin/DeletePhotosButton.tsx +++ b/src/admin/DeletePhotosButton.tsx @@ -2,7 +2,7 @@ import LoaderButton from '@/components/primitives/LoaderButton'; import { photoQuantityText } from '@/photo'; -import { deletePhotosAction } from '@/photo/actions'; +import { batchPhotoAction } from '@/photo/actions'; import { useAppState } from '@/app/AppState'; import { toastSuccess, toastWarning } from '@/toast'; import { ComponentProps, useState } from 'react'; @@ -43,7 +43,10 @@ export default function DeletePhotosButton({ onClick={() => { onClick?.(); setIsLoading(true); - deletePhotosAction(photoIds) + batchPhotoAction({ + photoIds, + action: 'delete', + }) .then(() => { toastSuccess(toastText ?? `${photosText} deleted`); if (clearLocalState) { diff --git a/src/admin/config/AdminAppConfigurationClient.tsx b/src/admin/config/AdminAppConfigurationClient.tsx index 62fe922f..afd086a3 100644 --- a/src/admin/config/AdminAppConfigurationClient.tsx +++ b/src/admin/config/AdminAppConfigurationClient.tsx @@ -140,6 +140,7 @@ export default function AdminAppConfigurationClient({ areInternalToolsEnabled, areAdminDebugToolsEnabled, isAdminSqlDebugEnabled, + isAdminStorageDebugEnabled, // Auth secret, // Connection status @@ -1018,6 +1019,15 @@ export default function AdminAppConfigurationClient({ console output for all sql queries: {renderEnvVars(['ADMIN_SQL_DEBUG'])} + + Set environment variable to {'"1"'} to enable + storage debugging: + {renderEnvVars(['ADMIN_STORAGE_DEBUG'])} + ; } }; diff --git a/src/admin/select/AdminBatchEditPanelClient.tsx b/src/admin/select/AdminBatchEditPanelClient.tsx index 6fd07173..f6d48b89 100644 --- a/src/admin/select/AdminBatchEditPanelClient.tsx +++ b/src/admin/select/AdminBatchEditPanelClient.tsx @@ -6,9 +6,9 @@ import AppGrid from '@/components/AppGrid'; import { clsx } from 'clsx/lite'; import { IoCloseSharp } from 'react-icons/io5'; import { useEffect, useRef, useState } from 'react'; -import { TAG_FAVS, Tags } from '@/tag'; +import { Tags } from '@/tag'; import FieldsetTag from '@/tag/FieldsetTag'; -import { tagMultiplePhotosAction } from '@/photo/actions'; +import { batchPhotoAction } from '@/photo/actions'; import { toastSuccess } from '@/toast'; import DeletePhotosButton from '@/admin/DeletePhotosButton'; import { photoQuantityText } from '@/photo'; @@ -21,14 +21,17 @@ import { useSelectPhotosState } from './SelectPhotosState'; import { Albums } from '@/album'; import FieldsetAlbum from '@/album/FieldsetAlbum'; import IconAlbum from '@/components/icons/IconAlbum'; -import { addPhotosToAlbumsAction } from '@/album/actions'; +import FieldsetWithStatus from '@/components/FieldsetWithStatus'; +import { convertStringToArray } from '@/utility/string'; export default function AdminBatchEditPanelClient({ uniqueAlbums, uniqueTags, + showSelectAll, }: { uniqueAlbums: Albums uniqueTags: Tags + showSelectAll?: boolean }) { const refNote = useRef(null); @@ -36,6 +39,8 @@ export default function AdminBatchEditPanelClient({ canCurrentPageSelectPhotos, isSelectingPhotos, stopSelectingPhotos, + isSelectingAllPhotos, + toggleIsSelectingAllPhotos, selectedPhotoIds, isPerformingSelectEdit, setIsPerformingSelectEdit, @@ -98,20 +103,20 @@ export default function AdminBatchEditPanelClient({ onClick={() => { setIsPerformingSelectEdit?.(true); if (isInTagMode) { - tagMultiplePhotosAction( - tags, - selectedPhotoIds ?? [], - ) + batchPhotoAction({ + photoIds: selectedPhotoIds, + tags: convertStringToArray(tags, false), + }) .then(() => { toastSuccess(`${photosText} tagged`); stopSelectingPhotos?.(); }) .finally(() => setIsPerformingSelectEdit?.(false)); } else if (isInAlbumMode) { - addPhotosToAlbumsAction( - selectedPhotoIds ?? [], - albumTitles.split(','), - ) + batchPhotoAction({ + photoIds: selectedPhotoIds, + albumTitles: albumTitles.split(','), + }) .then(() => { toastSuccess(`${photosText} added`); stopSelectingPhotos?.(); @@ -146,10 +151,10 @@ export default function AdminBatchEditPanelClient({ confirmText={`Are you sure you want to favorite ${photosText}?`} onClick={() => { setIsPerformingSelectEdit?.(true); - tagMultiplePhotosAction( - TAG_FAVS, - selectedPhotoIds ?? [], - ) + batchPhotoAction({ + photoIds: selectedPhotoIds, + action: 'favorite', + }) .then(() => { toastSuccess(`${photosText} favorited`); stopSelectingPhotos?.(); @@ -230,8 +235,17 @@ export default function AdminBatchEditPanelClient({ openOnLoad hideLabel /> - :
- {renderPhotoCTA} + :
+
+ {renderPhotoCTA} +
+ {showSelectAll && + }
} {tagErrorMessage && diff --git a/src/admin/select/SelectPhotosProvider.tsx b/src/admin/select/SelectPhotosProvider.tsx index 8452d330..781855d1 100644 --- a/src/admin/select/SelectPhotosProvider.tsx +++ b/src/admin/select/SelectPhotosProvider.tsx @@ -32,6 +32,8 @@ export default function SelectPhotosProvider({ useState(false); const [selectedPhotoIds, setSelectedPhotoIds] = useState([]); + const [isSelectingAllPhotos, setIsSelectingAllPhotos] = + useState(false); const [isPerformingSelectEdit, setIsPerformingSelectEdit] = useState(false); @@ -64,6 +66,22 @@ export default function SelectPhotosProvider({ replacePathWithEvent(pathname) , [pathname]); + const togglePhotoSelection = useCallback((photoId: string) => { + if (isSelectingAllPhotos) { + setSelectedPhotoIds([photoId]); + setIsSelectingAllPhotos(false); + } else { + setSelectedPhotoIds(selectedPhotoIds.includes(photoId) + ? (selectedPhotoIds ?? []).filter(id => id !== photoId) + : (selectedPhotoIds ?? []).concat(photoId)); + } + }, [isSelectingAllPhotos, selectedPhotoIds]); + + const toggleIsSelectingAllPhotos = useCallback(() => { + setIsSelectingAllPhotos(prev => !prev); + setSelectedPhotoIds([]); + }, []); + useEffect(() => { if (isSelectingPhotos) { const photoGrids = Array.from(getPhotoGridElements()); @@ -75,6 +93,7 @@ export default function SelectPhotosProvider({ } else { // eslint-disable-next-line react-hooks/set-state-in-effect setSelectedPhotoIds([]); + setIsSelectingAllPhotos(false); } }, [isSelectingPhotos, getPhotoGridElements]); @@ -82,10 +101,12 @@ export default function SelectPhotosProvider({ diff --git a/src/admin/select/SelectPhotosState.ts b/src/admin/select/SelectPhotosState.ts index 240e8d6f..3cc9827a 100644 --- a/src/admin/select/SelectPhotosState.ts +++ b/src/admin/select/SelectPhotosState.ts @@ -2,11 +2,13 @@ import { createContext, Dispatch, SetStateAction, use } from 'react'; export type SelectPhotosState = { canCurrentPageSelectPhotos?: boolean - isSelectingPhotos?: boolean; + isSelectingPhotos?: boolean + isSelectingAllPhotos?: boolean + toggleIsSelectingAllPhotos?: () => void startSelectingPhotos?: () => void stopSelectingPhotos?: () => void selectedPhotoIds?: string[] - setSelectedPhotoIds?: (photoIds: string[]) => void + togglePhotoSelection?: (photoId: string) => void isPerformingSelectEdit?: boolean setIsPerformingSelectEdit?: Dispatch> }; diff --git a/src/admin/storage/AdminPhotoStorageCheck.tsx b/src/admin/storage/AdminPhotoStorageCheck.tsx new file mode 100644 index 00000000..8b52a822 --- /dev/null +++ b/src/admin/storage/AdminPhotoStorageCheck.tsx @@ -0,0 +1,36 @@ +'use client'; + +import { Photo } from '@/photo'; +import { getOptimizedUrlsFromPhotoUrl } from '@/photo/storage'; +import useVisibility from '@/utility/useVisibility'; +import { useCallback, useRef, useState } from 'react'; + +export default function AdminPhotoStorageCheck({ + photo, +}: { + photo: Photo +}) { + const ref = useRef(null); + + const url = getOptimizedUrlsFromPhotoUrl(photo.url)[0]; + + const [hasImage, setHasImage] = useState(); + + const onVisible = useCallback(() => { + if (hasImage === undefined) { + fetch(url) + .then(res => setHasImage(res.ok)) + .catch(() => setHasImage(false)); + } + }, [url, hasImage]); + + useVisibility({ ref, onVisible }); + + return
+ {hasImage === undefined + ? 'Checking ...' + : hasImage === false + ? '❌' + : '✅'} +
; +} diff --git a/src/admin/storage/AdminStorageTable.tsx b/src/admin/storage/AdminStorageTable.tsx new file mode 100644 index 00000000..d48bc3e8 --- /dev/null +++ b/src/admin/storage/AdminStorageTable.tsx @@ -0,0 +1,58 @@ +import { pathForPhoto } from '@/app/path'; +import LinkWithStatus from '@/components/LinkWithStatus'; +import { Photo } from '@/photo'; +import { getPhotoUrls } from '@/photo/query'; +import { getStorageUrlsForPhoto } from '@/photo/storage'; + +export default async function AdminStoragePage() { + const _urls = await getPhotoUrls({ limit: 1000, hidden: 'include' }); + + const urls = await Promise.all(_urls.map(async ({ url, ...partialPhoto }) => { + const urlSet = await getStorageUrlsForPhoto({ url } as Photo); + const status = urlSet.length === 4 + ? 'complete' + : urlSet.length === 0 + ? 'missing' + : 'partial'; + return { ...partialPhoto, status }; + })); + + const countComplete = urls + .filter(({ status }) => status === 'complete').length; + const countPartial = urls + .filter(({ status }) => status === 'partial').length; + const countMissing = urls + .filter(({ status }) => status === 'missing').length; + + return ( +
+
+ Storage ({countComplete + countPartial}/{urls.length}) +
+
+
✅ {countComplete.toString().padStart(3, '0')} Complete
+
⚠️ {countPartial.toString().padStart(3, '0')} Partial
+
❌ {countMissing.toString().padStart(3, '0')} Missing
+
+
+ {urls.map(({ id, title, hidden, status }) => ( +
+ +
+ ))} +
+
+ ); +} diff --git a/src/album/actions.ts b/src/album/actions.ts index 607b15d0..d3b16e40 100644 --- a/src/album/actions.ts +++ b/src/album/actions.ts @@ -1,13 +1,12 @@ 'use server'; import { runAuthenticatedAdminServerAction } from '@/auth/server'; -import { addPhotoAlbumIds, deleteAlbum, updateAlbum } from './query'; +import { deleteAlbum, updateAlbum } from './query'; import { revalidateAllKeysAndPaths } from '@/cache'; import { redirect } from 'next/navigation'; import { PATH_ADMIN_ALBUMS, PATH_ROOT, pathForAlbum } from '@/app/path'; import { convertFormDataToAlbum } from './form'; import { Album } from '.'; -import { createAlbumsAndGetIds } from './server'; export const updateAlbumAction = async (formData: FormData) => runAuthenticatedAdminServerAction(async () => { @@ -35,13 +34,3 @@ export const deleteAlbumAction = async ( redirect(PATH_ROOT); } }); - -export const addPhotosToAlbumsAction = async ( - photoIds: string[], - albumTitles: string[], -) => - runAuthenticatedAdminServerAction(async () => { - const albumIds = await createAlbumsAndGetIds(albumTitles); - await addPhotoAlbumIds(photoIds, albumIds); - revalidateAllKeysAndPaths(); - }); diff --git a/src/app/config.ts b/src/app/config.ts index a48860da..d690006d 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -399,6 +399,8 @@ export const ADMIN_DEBUG_TOOLS_ENABLED = process.env.ADMIN_DEBUG_TOOLS === '1'; export const ADMIN_SQL_DEBUG_ENABLED = process.env.ADMIN_SQL_DEBUG === '1' && !IS_BUILDING; +export const ADMIN_STORAGE_DEBUG_ENABLED = + process.env.ADMIN_STORAGE_DEBUG === '1'; export const APP_CONFIGURATION = { // Storage @@ -527,6 +529,7 @@ export const APP_CONFIGURATION = { ), areAdminDebugToolsEnabled: ADMIN_DEBUG_TOOLS_ENABLED, isAdminSqlDebugEnabled: ADMIN_SQL_DEBUG_ENABLED, + isAdminStorageDebugEnabled: ADMIN_STORAGE_DEBUG_ENABLED, // Misc nextVersion: dependencies.next, reactVersion: dependencies.react, diff --git a/src/app/static.ts b/src/app/static.ts index 85bf2f0f..be50d1a1 100644 --- a/src/app/static.ts +++ b/src/app/static.ts @@ -8,7 +8,7 @@ import { STATICALLY_OPTIMIZED_PHOTOS, } from '@/app/config'; import { GENERATE_STATIC_PARAMS_LIMIT } from '@/db'; -import { getPublicPhotoIds } from '@/photo/query'; +import { getAllPublicPhotoIds } from '@/photo/query'; import { depluralize, pluralize } from '@/utility/string'; type StaticOutput = 'page' | 'image'; @@ -25,7 +25,7 @@ export const staticallyGeneratePhotosIfConfigured = (type: StaticOutput) => ( (type === 'image' && STATICALLY_OPTIMIZED_PHOTO_OG_IMAGES) ) ? async () => { - const photoIds = await getPublicPhotoIds({ + const photoIds = await getAllPublicPhotoIds({ limit: GENERATE_STATIC_PARAMS_LIMIT, }) .catch(e => { diff --git a/src/components/EnvVar.tsx b/src/components/EnvVar.tsx index 1f360b6b..2bd429f5 100644 --- a/src/components/EnvVar.tsx +++ b/src/components/EnvVar.tsx @@ -1,3 +1,5 @@ +'use client'; + import clsx from 'clsx/lite'; import { ReactNode } from 'react'; import CopyButton from './CopyButton'; diff --git a/src/db/index.ts b/src/db/index.ts index abf5e00b..c69edbb6 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -37,6 +37,7 @@ export type PhotoQueryOptions = { camera?: Partial lens?: Partial album?: Album + photoIds?: string[] }; export const areOptionsSensitive = (options: PhotoQueryOptions) => @@ -68,6 +69,7 @@ export const getWheresFromOptions = ( film, recipe, focal, + photoIds, } = options; const wheres = [] as string[]; @@ -157,6 +159,10 @@ export const getWheresFromOptions = ( wheres.push(`focal_length=$${valuesIndex++}`); wheresValues.push(focal); } + if (photoIds && photoIds.length > 0) { + wheres.push(`id=ANY($${valuesIndex++})`); + wheresValues.push(convertArrayToPostgresString(photoIds) ?? ''); + } return { wheres: wheres.length > 0 diff --git a/src/photo/InfinitePhotoScroll.tsx b/src/photo/InfinitePhotoScroll.tsx index e57c03e4..e1063487 100644 --- a/src/photo/InfinitePhotoScroll.tsx +++ b/src/photo/InfinitePhotoScroll.tsx @@ -30,6 +30,8 @@ export default function InfinitePhotoScroll({ sortBy, sortWithPriority, excludeFromFeeds, + recent, + year, camera, lens, tag, @@ -79,6 +81,8 @@ export default function InfinitePhotoScroll({ excludeFromFeeds, limit: itemsPerPage, hidden: includeHiddenPhotos ? 'include' : 'exclude', + recent, + year, camera, lens, tag, @@ -94,6 +98,8 @@ export default function InfinitePhotoScroll({ initialOffset, itemsPerPage, includeHiddenPhotos, + recent, + year, camera, lens, tag, diff --git a/src/photo/PhotoDetailPage.tsx b/src/photo/PhotoDetailPage.tsx index e63009e2..4503b701 100644 --- a/src/photo/PhotoDetailPage.tsx +++ b/src/photo/PhotoDetailPage.tsx @@ -14,7 +14,10 @@ import PhotoHeader from './PhotoHeader'; import RecipeHeader from '@/recipe/RecipeHeader'; import { ReactNode } from 'react'; import LensHeader from '@/lens/LensHeader'; -import { AI_CONTENT_GENERATION_ENABLED } from '@/app/config'; +import { + ADMIN_STORAGE_DEBUG_ENABLED, + AI_CONTENT_GENERATION_ENABLED, +} from '@/app/config'; import YearHeader from '@/year/YearHeader'; import RecentsHeader from '@/recents/RecentsHeader'; import AlbumHeader from '@/album/AlbumHeader'; @@ -180,13 +183,13 @@ export default function PhotoDetailPage({ shouldShareFocalLength={focal !== undefined} includeFavoriteInAdminMenu={includeFavoriteInAdminMenu} showAdminKeyCommands + showStorageCheck={ADMIN_STORAGE_DEBUG_ENABLED} />, ]} /> - + {photosCount > photos.length && }
); diff --git a/src/photo/PhotoGrid.tsx b/src/photo/PhotoGrid.tsx index 53cba1dc..8a882e4c 100644 --- a/src/photo/PhotoGrid.tsx +++ b/src/photo/PhotoGrid.tsx @@ -15,7 +15,6 @@ import { DATA_KEY_PHOTO_GRID } from '@/admin/select/SelectPhotosProvider'; export default function PhotoGrid({ photos, - selectedPhoto, prioritizeInitialPhotos, className, classNamePhoto, @@ -31,7 +30,6 @@ export default function PhotoGrid({ ...categories }: { photos: Photo[] - selectedPhoto?: Photo prioritizeInitialPhotos?: boolean className?: string classNamePhoto?: string @@ -51,8 +49,9 @@ export default function PhotoGrid({ const { isSelectingPhotos, + isSelectingAllPhotos, selectedPhotoIds, - setSelectedPhotoIds, + togglePhotoSelection, } = useSelectPhotosState(); return ( @@ -79,7 +78,10 @@ export default function PhotoGrid({ staggerOnFirstLoadOnly={staggerOnFirstLoadOnly} onAnimationComplete={onAnimationComplete} items={photos.map((photo, index) => { - const isSelected = selectedPhotoIds?.includes(photo.id) ?? false; + const isSelected = ( + selectedPhotoIds?.includes(photo.id) || + isSelectingAllPhotos + ) ?? false; return
setSelectedPhotoIds?.(isSelected - ? (selectedPhotoIds ?? []).filter(id => id !== photo.id) - : (selectedPhotoIds ?? []).concat(photo.id), - )} + onSelectChange={() => togglePhotoSelection?.(photo.id)} />}
; }).concat(additionalTile ? <>{additionalTile} : [])} diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index 55fc05b2..d89971c4 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -50,6 +50,7 @@ import { lensFromPhoto } from '@/lens'; import MaskedScroll from '@/components/MaskedScroll'; import { useAppText } from '@/i18n/state/client'; import { Album } from '@/album'; +import AdminPhotoStorageCheck from '@/admin/storage/AdminPhotoStorageCheck'; export default function PhotoLarge({ photo, @@ -83,6 +84,7 @@ export default function PhotoLarge({ includeFavoriteInAdminMenu, onVisible, showAdminKeyCommands, + showStorageCheck, }: { photo: Photo className?: string @@ -115,6 +117,7 @@ export default function PhotoLarge({ includeFavoriteInAdminMenu?: boolean onVisible?: () => void showAdminKeyCommands?: boolean + showStorageCheck?: boolean }) { const ref = useRef(null); const refZoomControls = useRef(null); @@ -481,6 +484,8 @@ export default function PhotoLarge({ photo={photo} />} + {showStorageCheck && + } diff --git a/src/photo/PhotosLarge.tsx b/src/photo/PhotosLarge.tsx index 9da562c9..23f3b5d1 100644 --- a/src/photo/PhotosLarge.tsx +++ b/src/photo/PhotosLarge.tsx @@ -9,12 +9,14 @@ export default function PhotosLarge({ prefetchFirstPhotoLinks, onLastPhotoVisible, revalidatePhoto, + showStorageCheck, }: { photos: Photo[] animate?: boolean prefetchFirstPhotoLinks?: boolean onLastPhotoVisible?: () => void revalidatePhoto?: RevalidatePhoto + showStorageCheck?: boolean }) { return ( )} itemKeys={photos.map(photo => photo.id)} /> diff --git a/src/photo/PhotosLargeInfinite.tsx b/src/photo/PhotosLargeInfinite.tsx index abab71fe..c34d4953 100644 --- a/src/photo/PhotosLargeInfinite.tsx +++ b/src/photo/PhotosLargeInfinite.tsx @@ -10,12 +10,14 @@ export default function PhotosLargeInfinite({ itemsPerPage, sortBy, excludeFromFeeds, + showStorageCheck, }: { initialOffset: number itemsPerPage: number sortBy: SortBy sortWithPriority: boolean excludeFromFeeds?: boolean + showStorageCheck?: boolean }) { return ( } ); diff --git a/src/photo/actions.ts b/src/photo/actions.ts index 8f80dade..94711caf 100644 --- a/src/photo/actions.ts +++ b/src/photo/actions.ts @@ -14,11 +14,13 @@ import { getPhotosNeedingRecipeTitleCount, updateColorDataForPhoto, getColorDataForPhotos, + getPhotoIds, } from '@/photo/query'; import { PhotoQueryOptions, areOptionsSensitive } from '@/db'; import { FIELDS_TO_NOT_OVERWRITE_WITH_NULL_DATA_ON_SYNC, PhotoFormData, + convertFormDataToPhotoDbInsert, convertPhotoToFormData, } from './form'; import { redirect } from 'next/navigation'; @@ -50,7 +52,7 @@ import { propagateRecipeTitleIfNecessary, } from './server'; import { TAG_FAVS, Tags, isPhotoFav, isTagFavs } from '@/tag'; -import { convertPhotoToPhotoDbInsert, Photo } from '.'; +import { convertPhotoToPhotoDbInsert, Photo, PhotoDbInsert } from '.'; import { runAuthenticatedAdminServerAction } from '@/auth/server'; import { AiImageQuery, getAiImageQuery, getAiTextFieldsToGenerate } from './ai'; import { streamOpenAiImageQuery } from '@/platforms/openai'; @@ -66,7 +68,6 @@ import { storeOptimizedPhotosForUrl, } from './storage/server'; import { UrlAddStatus } from '@/admin/AdminUploadsClient'; -import { convertStringToArray } from '@/utility/string'; import { after } from 'next/server'; import { getColorFieldsForImageUrl, @@ -343,18 +344,6 @@ export const updatePhotoAction = async (formData: FormData) => redirect(PATH_ADMIN_PHOTOS); }); -export const tagMultiplePhotosAction = async ( - tags: string, - photoIds: string[], -) => - runAuthenticatedAdminServerAction(async () => { - await addTagsToPhotos( - convertStringToArray(tags, false) ?? [], - photoIds, - ); - revalidateAllKeysAndPaths(); - }); - export const toggleFavoritePhotoAction = async ( photoId: string, shouldRedirect?: boolean, @@ -388,17 +377,6 @@ export const togglePrivatePhotoAction = async ( if (redirectPath) { redirect(redirectPath); } }); -export const deletePhotosAction = async (photoIds: string[]) => - runAuthenticatedAdminServerAction(async () => { - for (const photoId of photoIds) { - const photo = await getPhoto(photoId, true); - if (photo) { - await deletePhotoAndFiles(photoId, photo.url); - } - } - revalidateAllKeysAndPaths(); - }); - export const deletePhotoAction = async ( photoId: string, photoUrl: string, @@ -525,19 +503,46 @@ export const replacePhotoStorageAction = async ( ) => runAuthenticatedAdminServerAction(async () => { const photo = await getPhoto(photoId, true); + if (photo) { const { fileExtension: extension, } = getFileNamePartsFromStorageUrl(updatedStorageUrl); - await updatePhoto(convertPhotoToPhotoDbInsert({ - ...photo, - url: updatedStorageUrl, - extension, - })); + + const { + formDataFromExif, + } = await extractImageDataFromBlobPath(updatedStorageUrl, { + generateBlurData: BLUR_ENABLED, + }); + + let imageFields: Partial = {}; + if (formDataFromExif) { + const photoDbInsert = convertFormDataToPhotoDbInsert(formDataFromExif); + imageFields = { + blurData: photoDbInsert.blurData, + width: photoDbInsert.width, + height: photoDbInsert.height, + aspectRatio: photoDbInsert.aspectRatio, + colorData: photoDbInsert.colorData, + colorSort: photoDbInsert.colorSort, + }; + } + + await updatePhoto({ + ...convertPhotoToPhotoDbInsert({ + ...photo, + url: updatedStorageUrl, + extension, + }), + ...imageFields, + }); + await storeOptimizedPhotosForUrl(updatedStorageUrl); + const existingStorageUrls = await getStorageUrlsForPhoto(photo) .then(urls => urls.map(({ url }) => url)); await Promise.all(existingStorageUrls.map(deleteFile)); + revalidatePhoto(photo.id); } }); @@ -695,6 +700,51 @@ export const streamAiImageQueryAction = async ( export const getImageBlurAction = async (url: string) => runAuthenticatedAdminServerAction(() => blurImageFromUrl(url)); +// Batch actions + +export const batchPhotoAction = async ({ + photoIds: _photoIds = [], + photoOptions, + tags = [], + albumTitles = [], + action, +}: { + photoIds?: string[] + photoOptions?: PhotoQueryOptions + tags?: string[] + albumTitles?: string[] + action?: 'favorite' | 'delete' +}) => runAuthenticatedAdminServerAction(async () => { + const photoIds = _photoIds.length > 0 + ? _photoIds + : photoOptions !== undefined + ? await getPhotoIds(photoOptions) + : []; + + if (tags.length > 0) { + await addTagsToPhotos(tags, photoIds); + } + if (albumTitles.length > 0) { + const albumIds = await createAlbumsAndGetIds(albumTitles); + await addPhotoAlbumIds(photoIds, albumIds); + } + switch (action) { + case 'favorite': + await addTagsToPhotos([TAG_FAVS], photoIds); + break; + case 'delete': + for (const photoId of photoIds) { + const photo = await getPhoto(photoId, true); + if (photo) { + await deletePhotoAndFiles(photoId, photo.url); + } + } + break; + } + + revalidateAllKeysAndPaths(); +}); + // Public/Private actions export const getPhotosAction = async ( diff --git a/src/photo/query.ts b/src/photo/query.ts index 2ef904be..3698f579 100644 --- a/src/photo/query.ts +++ b/src/photo/query.ts @@ -420,43 +420,93 @@ export const getUniqueFocalLengths = async () => }))) , 'getUniqueFocalLengths'); +const _getPhotos = async ( + options: PhotoQueryOptions = {}, + fields = ['*'], + shouldParse = true, +) => { + const sql = [ + `SELECT ${fields.map(field => `p.${field}`).join(', ')} FROM photos p`, + ]; + + const values = [] as (string | number)[]; + + const joins = getJoinsFromOptions(options); + + if (joins) { sql.push(joins); } + + const { + wheres, + wheresValues, + lastValuesIndex, + } = getWheresFromOptions(options); + + if (wheres) { + sql.push(wheres); + values.push(...wheresValues); + } + + sql.push(getOrderByFromOptions(options)); + + const { + limitAndOffset, + limitAndOffsetValues, + } = getLimitAndOffsetFromOptions(options, lastValuesIndex); + + // LIMIT + OFFSET + sql.push(limitAndOffset); + values.push(...limitAndOffsetValues); + + return query(sql.join(' '), values) + .then(({ rows, rowCount }) => ({ + // Only parse results if there's at least one photo + photos: shouldParse ? rows.map(parsePhotoFromDb) : rows, + // Prefer explicit count before falling back to row count + count: rows[0]?.count !== undefined + ? parseInt(rows[0]?.count ?? '0', 10) + : rowCount ?? 0, + })); +}; + export const getPhotos = async (options: PhotoQueryOptions = {}) => - safelyQuery(async () => { - const sql = ['SELECT p.* FROM photos p']; - const values = [] as (string | number)[]; + safelyQuery( + async () => _getPhotos(options).then(({ photos }) => photos), + 'getPhotos', + // Seemingly necessary to pass `options` for expected cache behavior + options, + ); - const joins = getJoinsFromOptions(options); +export const getPhotoIds = async (options: PhotoQueryOptions = {}) => + safelyQuery( + async () => _getPhotos(options, ['id'], false) + .then(({ photos }) => photos.map(photo => photo.id)), + 'getPhotoIds', + // Seemingly necessary to pass `options` for expected cache behavior + options, + ); - if (joins) { sql.push(joins); } +export const getPhotoUrls = async (options: PhotoQueryOptions = {}) => + safelyQuery( + async () => _getPhotos(options, ['id', 'title', 'url', 'hidden'], false) + .then(({ photos }) => + photos as { + id: string, + title: string, + url: string, + hidden?: boolean, + }[]), + 'getPhotoUrls', + // Seemingly necessary to pass `options` for expected cache behavior + options, + ); - const { - wheres, - wheresValues, - lastValuesIndex, - } = getWheresFromOptions(options); - - if (wheres) { - sql.push(wheres); - values.push(...wheresValues); - } - - sql.push(getOrderByFromOptions(options)); - - const { - limitAndOffset, - limitAndOffsetValues, - } = getLimitAndOffsetFromOptions(options, lastValuesIndex); - - // LIMIT + OFFSET - sql.push(limitAndOffset); - values.push(...limitAndOffsetValues); - - return query(sql.join(' '), values) - .then(({ rows }) => rows.map(parsePhotoFromDb)); - }, - 'getPhotos', - // Seemingly necessary to pass `options` for expected cache behavior - options, +export const getPhotoCount = async (options: PhotoQueryOptions = {}) => + safelyQuery( + async () => _getPhotos(options, ['COUNT(*)'], false) + .then(({ count }) => count), + 'getPhotoCount', + // Seemingly necessary to pass `options` for expected cache behavior + options, ); export const getPhotosNearId = async ( @@ -534,14 +584,14 @@ export const getPhotosMeta = (options: PhotoQueryOptions = {}) => })); }, 'getPhotosMeta'); -export const getPublicPhotoIds = async ({ limit }: { limit?: number }) => +export const getAllPublicPhotoIds = async ({ limit }: { limit?: number }) => safelyQuery(() => (limit ? sql`SELECT id FROM photos WHERE hidden IS NOT TRUE LIMIT ${limit}` : sql`SELECT id FROM photos WHERE hidden IS NOT TRUE`) .then(({ rows }) => rows.map(({ id }) => id as string)) , 'getPublicPhotoIds'); -export const getPhotoIdsAndUpdatedAt = async () => +export const getAllPhotoIdsWithUpdatedAt = async () => safelyQuery(() => sql`SELECT id, updated_at FROM photos WHERE hidden IS NOT TRUE` .then(({ rows }) => rows.map(({ id, updated_at }) =>