From 59ce3bafe339d90e9bd05733648ccc95b895959d Mon Sep 17 00:00:00 2001 From: Renan Decamps Date: Wed, 5 Nov 2025 17:01:17 +0100 Subject: [PATCH 1/8] feat: add file upload on book cover --- .env.example | 13 + docker-compose.yml | 46 +- package.json | 4 +- pnpm-lock.yaml | 1086 ++++++++++++++++- prisma/schema.prisma | 1 + src/env/client.ts | 1 + src/env/server.ts | 9 + src/features/book/book-cover.tsx | 20 +- src/features/book/manager/form-book-cover.tsx | 48 +- .../book/manager/page-book-update.tsx | 1 + src/features/book/schema.ts | 3 +- src/lib/s3/index.ts | 13 + src/locales/en/book.json | 6 +- src/routeTree.gen.ts | 21 + src/routes/api/upload.ts | 61 + src/server/routers/book.ts | 1 + 16 files changed, 1314 insertions(+), 20 deletions(-) create mode 100644 src/lib/s3/index.ts create mode 100644 src/routes/api/upload.ts diff --git a/.env.example b/.env.example index 6337b9aed..5737d9402 100644 --- a/.env.example +++ b/.env.example @@ -6,7 +6,20 @@ DOCKER_DATABASE_NAME="startui" DOCKER_DATABASE_USERNAME="startui" DOCKER_DATABASE_PASSWORD="startui" +DOCKER_MINIO_API_PORT="9000" +DOCKER_MINIO_UI_PORT="9001" +DOCKER_MINIO_USERNAME="minioadmin" +DOCKER_MINIO_PASSWORD="minioadmin" + +# S3 +S3_ENDPOINT="http://127.0.0.1:${DOCKER_MINIO_API_PORT}" +S3_BUCKET_NAME="start-ui-bucket" +S3_ACCESS_KEY_ID="startui-access-key" +S3_SECRET_ACCESS_KEY="startui-secret-key" +S3_REGION="default" + # PUBLIC CONFIG +VITE_S3_BUCKET_PUBLIC_URL="http://127.0.0.1:${DOCKER_MINIO_API_PORT}/${S3_BUCKET_NAME}" VITE_BASE_URL="http://localhost:${VITE_PORT}" # Use the following environment variables to show the environment name. VITE_ENV_NAME="LOCAL" diff --git a/docker-compose.yml b/docker-compose.yml index 2a5dad1b8..022137310 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,13 +4,55 @@ services: env_file: - .env ports: - - '${DOCKER_DATABASE_PORT:-5432}:5432' + - "${DOCKER_DATABASE_PORT:-5432}:5432" environment: POSTGRES_DB: $DOCKER_DATABASE_NAME POSTGRES_USER: $DOCKER_DATABASE_USERNAME POSTGRES_PASSWORD: $DOCKER_DATABASE_PASSWORD healthcheck: - test: ['CMD-SHELL', 'pg_isready -U $DOCKER_DATABASE_NAME'] + test: ["CMD-SHELL", "pg_isready -U $DOCKER_DATABASE_NAME"] interval: 10s timeout: 5s retries: 5 + + minio: + image: minio/minio:RELEASE.2025-07-23T15-54-02Z-cpuv1 + ports: + - "${DOCKER_MINIO_API_PORT}:9000" + - "${DOCKER_MINIO_UI_PORT}:9001" + environment: + - MINIO_ROOT_USER=${DOCKER_MINIO_USERNAME} + - MINIO_ROOT_PASSWORD=${DOCKER_MINIO_PASSWORD} + volumes: + - minio:/data/minio + command: minio server /data/minio --console-address :${DOCKER_MINIO_UI_PORT} + healthcheck: + test: ["CMD", "mc", "ready", "local"] + interval: 5s + timeout: 5s + retries: 5 + + createbucket: + image: minio/mc:RELEASE.2025-08-13T08-35-41Z-cpuv1 + profiles: + - init + depends_on: + minio: + condition: service_healthy + entrypoint: [""] + command: [ + "sh", + "-c", + ' + mc alias set default http://minio:9000 "${DOCKER_MINIO_USERNAME}" "${DOCKER_MINIO_PASSWORD}"; + mc admin user add default ${S3_ACCESS_KEY_ID} ${S3_SECRET_ACCESS_KEY}; + mc admin policy attach default readwrite --user ${S3_ACCESS_KEY_ID}; + mc mb --ignore-existing default/${S3_BUCKET_NAME} 2>/dev/null; + mc anonymous set download default/${S3_BUCKET_NAME}; + echo ''Bucket configuration completed successfully''; + ', + ] + restart: "no" + +volumes: + minio: diff --git a/package.json b/package.json index 886c8ce7a..82a742c5f 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "test:ui": "vitest", "e2e": "dotenv -- cross-env playwright test", "e2e:ui": "dotenv -- cross-env playwright test --ui", - "dk:init": "docker compose up -d", + "dk:init": "docker compose --profile init up -d", "dk:start": "docker compose start", "dk:stop": "docker compose stop", "dk:clear": "docker compose down --volumes", @@ -42,6 +42,7 @@ "db:seed": "dotenv -- cross-env node ./run-jiti ./prisma/seed/index.ts" }, "dependencies": { + "@aws-sdk/client-s3": "3.922.0", "@base-ui-components/react": "1.0.0-beta.1", "@bearstudio/ui-state": "1.0.2", "@better-auth/expo": "1.3.27", @@ -67,6 +68,7 @@ "@tanstack/zod-adapter": "1.132.47", "@uidotdev/usehooks": "2.4.1", "better-auth": "1.3.27", + "better-upload": "2.0.3", "boring-avatars": "2.0.4", "class-variance-authority": "0.7.1", "clsx": "2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75678fea9..3489edcbf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@aws-sdk/client-s3': + specifier: 3.922.0 + version: 3.922.0 '@base-ui-components/react': specifier: 1.0.0-beta.1 version: 1.0.0-beta.1(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -83,6 +86,9 @@ importers: better-auth: specifier: 1.3.27 version: 1.3.27(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(solid-js@1.9.9) + better-upload: + specifier: 2.0.3 + version: 2.0.3(@aws-sdk/client-s3@3.922.0)(react@19.2.0) boring-avatars: specifier: 2.0.4 version: 2.0.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -346,6 +352,16 @@ packages: '@asamuzakjp/css-color@2.8.3': resolution: {integrity: sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==} + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/crc32c@5.2.0': + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + + '@aws-crypto/sha1-browser@5.2.0': + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + '@aws-crypto/sha256-browser@5.2.0': resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} @@ -359,6 +375,10 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + '@aws-sdk/client-s3@3.922.0': + resolution: {integrity: sha512-SZRaZUUAHCWfEyBf4SRSPd29ko4uFoJpfd0E/w1meE68XhFB52FTtz/71UqYcwqZmN+s7oUNFFZT+DE/dnQSEA==} + engines: {node: '>=18.0.0'} + '@aws-sdk/client-sesv2@3.901.0': resolution: {integrity: sha512-xCS2qZlvgbXKZbJW8XgU8OEAL7BJyVqJ5yODOQxa1TJFZ/+wEhik9XZtULjNnQqa29sJDpPltuSDG1aDG2OUxQ==} engines: {node: '>=18.0.0'} @@ -367,78 +387,178 @@ packages: resolution: {integrity: sha512-sGyDjjkJ7ppaE+bAKL/Q5IvVCxtoyBIzN+7+hWTS/mUxWJ9EOq9238IqmVIIK6sYNIzEf9yhobfMARasPYVTNg==} engines: {node: '>=18.0.0'} + '@aws-sdk/client-sso@3.922.0': + resolution: {integrity: sha512-jdHs7uy7cSpiMvrxhYmqHyJxgK7hyqw4plG8OQ4YTBpq0SbfAxdoOuOkwJ1IVUUQho4otR1xYYjiX/8e8J8qwQ==} + engines: {node: '>=18.0.0'} + '@aws-sdk/core@3.901.0': resolution: {integrity: sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==} engines: {node: '>=18.0.0'} + '@aws-sdk/core@3.922.0': + resolution: {integrity: sha512-EvfP4cqJfpO3L2v5vkIlTkMesPtRwWlMfsaW6Tpfm7iYfBOuTi6jx60pMDMTyJNVfh6cGmXwh/kj1jQdR+w99Q==} + engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-env@3.901.0': resolution: {integrity: sha512-5hAdVl3tBuARh3zX5MLJ1P/d+Kr5kXtDU3xm1pxUEF4xt2XkEEpwiX5fbkNkz2rbh3BCt2gOHsAbh6b3M7n+DA==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-env@3.922.0': + resolution: {integrity: sha512-WikGQpKkROJSK3D3E7odPjZ8tU7WJp5/TgGdRuZw3izsHUeH48xMv6IznafpRTmvHcjAbDQj4U3CJZNAzOK/OQ==} + engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-http@3.901.0': resolution: {integrity: sha512-Ggr7+0M6QZEsrqRkK7iyJLf4LkIAacAxHz9c4dm9hnDdU7vqrlJm6g73IxMJXWN1bIV7IxfpzB11DsRrB/oNjQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-http@3.922.0': + resolution: {integrity: sha512-i72DgHMK7ydAEqdzU0Duqh60Q8W59EZmRJ73y0Y5oFmNOqnYsAI+UXyOoCsubp+Dkr6+yOwAn1gPt1XGE9Aowg==} + engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-ini@3.901.0': resolution: {integrity: sha512-zxadcDS0hNJgv8n4hFYJNOXyfjaNE1vvqIiF/JzZSQpSSYXzCd+WxXef5bQh+W3giDtRUmkvP5JLbamEFjZKyw==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-ini@3.922.0': + resolution: {integrity: sha512-bVF+pI5UCLNkvbiZr/t2fgTtv84s8FCdOGAPxQiQcw5qOZywNuuCCY3wIIchmQr6GJr8YFkEp5LgDCac5EC5aQ==} + engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-node@3.901.0': resolution: {integrity: sha512-dPuFzMF7L1s/lQyT3wDxqLe82PyTH+5o1jdfseTEln64LJMl0ZMWaKX/C1UFNDxaTd35Cgt1bDbjjAWHMiKSFQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-node@3.922.0': + resolution: {integrity: sha512-agCwaD6mBihToHkjycL8ObIS2XOnWypWZZWhJSoWyHwFrhEKz1zGvgylK9Dc711oUfU+zU6J8e0JPKNJMNb3BQ==} + engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-process@3.901.0': resolution: {integrity: sha512-/IWgmgM3Cl1wTdJA5HqKMAojxLkYchh5kDuphApxKhupLu6Pu0JBOHU8A5GGeFvOycyaVwosod6zDduINZxe+A==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-process@3.922.0': + resolution: {integrity: sha512-1DZOYezT6okslpvMW7oA2q+y17CJd4fxjNFH0jtThfswdh9CtG62+wxenqO+NExttq0UMaKisrkZiVrYQBTShw==} + engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-sso@3.901.0': resolution: {integrity: sha512-SjmqZQHmqFSET7+6xcZgtH7yEyh5q53LN87GqwYlJZ6KJ5oNw11acUNEhUOL1xTSJEvaWqwTIkS2zqrzLcM9bw==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-sso@3.922.0': + resolution: {integrity: sha512-nbD3G3hShTYxLCkKMqLkLPtKwAAfxdY/k9jHtZmVBFXek2T6tQrqZHKxlAu+fd23Ga4/Aik7DLQQx1RA1a5ipg==} + engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-web-identity@3.901.0': resolution: {integrity: sha512-NYjy/6NLxH9m01+pfpB4ql8QgAorJcu8tw69kzHwUd/ql6wUDTbC7HcXqtKlIwWjzjgj2BKL7j6SyFapgCuafA==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-web-identity@3.922.0': + resolution: {integrity: sha512-wjGIhgMHGGQfQTdFaJphNOKyAL8wZs6znJdHADPVURmgR+EWLyN/0fDO1u7wx8xaLMZpbHIFWBEvf9TritR/cQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-bucket-endpoint@3.922.0': + resolution: {integrity: sha512-Dpr2YeOaLFqt3q1hocwBesynE3x8/dXZqXZRuzSX/9/VQcwYBFChHAm4mTAl4zuvArtDbLrwzWSxmOWYZGtq5w==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-expect-continue@3.922.0': + resolution: {integrity: sha512-xmnLWMtmHJHJBupSWMUEW1gyxuRIeQ1Ov2xa8Tqq77fPr4Ft2AluEwiDMaZIMHoAvpxWKEEt9Si59Li7GIA+bQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-flexible-checksums@3.922.0': + resolution: {integrity: sha512-G363np7YcJhf+gBucskdv8cOTbs2TRwocEzRupuqDIooGDlLBlfJrvwehdgtWR8l53yjJR3zcHvGrVPTe2h8Nw==} + engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-host-header@3.901.0': resolution: {integrity: sha512-yWX7GvRmqBtbNnUW7qbre3GvZmyYwU0WHefpZzDTYDoNgatuYq6LgUIQ+z5C04/kCRoFkAFrHag8a3BXqFzq5A==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-host-header@3.922.0': + resolution: {integrity: sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-location-constraint@3.922.0': + resolution: {integrity: sha512-T4iqd7WQ2DDjCH/0s50mnhdoX+IJns83ZE+3zj9IDlpU0N2aq8R91IG890qTfYkUEdP9yRm0xir/CNed+v6Dew==} + engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-logger@3.901.0': resolution: {integrity: sha512-UoHebjE7el/tfRo8/CQTj91oNUm+5Heus5/a4ECdmWaSCHCS/hXTsU3PTTHAY67oAQR8wBLFPfp3mMvXjB+L2A==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-logger@3.922.0': + resolution: {integrity: sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg==} + engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-recursion-detection@3.901.0': resolution: {integrity: sha512-Wd2t8qa/4OL0v/oDpCHHYkgsXJr8/ttCxrvCKAt0H1zZe2LlRhY9gpDVKqdertfHrHDj786fOvEQA28G1L75Dg==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-recursion-detection@3.922.0': + resolution: {integrity: sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA==} + engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-sdk-s3@3.901.0': resolution: {integrity: sha512-prgjVC3fDT2VIlmQPiw/cLee8r4frTam9GILRUVQyDdNtshNwV3MiaSCLzzQJjKJlLgnBLNUHJCSmvUVtg+3iA==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-sdk-s3@3.922.0': + resolution: {integrity: sha512-ygg8lME1oFAbsH42ed2wtGqfHLoT5irgx6VC4X98j79fV1qXEwwwbqMsAiMQ/HJehpjqAFRVsHox3MHLN48Z5A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-ssec@3.922.0': + resolution: {integrity: sha512-eHvSJZTSRJO+/tjjGD6ocnPc8q9o3m26+qbwQTu/4V6yOJQ1q+xkDZNqwJQphL+CodYaQ7uljp8g1Ji/AN3D9w==} + engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-user-agent@3.901.0': resolution: {integrity: sha512-Zby4F03fvD9xAgXGPywyk4bC1jCbnyubMEYChLYohD+x20ULQCf+AimF/Btn7YL+hBpzh1+RmqmvZcx+RgwgNQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-user-agent@3.922.0': + resolution: {integrity: sha512-N4Qx/9KP3oVQBJOrSghhz8iZFtUC2NNeSZt88hpPhbqAEAtuX8aD8OzVcpnAtrwWqy82Yd2YTxlkqMGkgqnBsQ==} + engines: {node: '>=18.0.0'} + '@aws-sdk/nested-clients@3.901.0': resolution: {integrity: sha512-feAAAMsVwctk2Tms40ONybvpfJPLCmSdI+G+OTrNpizkGLNl6ik2Ng2RzxY6UqOfN8abqKP/DOUj1qYDRDG8ag==} engines: {node: '>=18.0.0'} + '@aws-sdk/nested-clients@3.922.0': + resolution: {integrity: sha512-uYvKCF1TGh/MuJ4TMqmUM0Csuao02HawcseG4LUDyxdUsd/EFuxalWq1Cx4fKZQ2K8F504efZBjctMAMNY+l7A==} + engines: {node: '>=18.0.0'} + '@aws-sdk/region-config-resolver@3.901.0': resolution: {integrity: sha512-7F0N888qVLHo4CSQOsnkZ4QAp8uHLKJ4v3u09Ly5k4AEStrSlFpckTPyUx6elwGL+fxGjNE2aakK8vEgzzCV0A==} engines: {node: '>=18.0.0'} + '@aws-sdk/region-config-resolver@3.922.0': + resolution: {integrity: sha512-44Y/rNNwhngR2KHp6gkx//TOr56/hx6s4l+XLjOqH7EBCHL7XhnrT1y92L+DLiroVr1tCSmO8eHQwBv0Y2+mvw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/s3-request-presigner@3.922.0': + resolution: {integrity: sha512-x/WZXOMAN10X/hbjHnaXjtU34RmV3/eJMiHoJsohquSgz8+pfRN1DeK65oa/XPoKCMPfV31RfHSzCduligHfsQ==} + engines: {node: '>=18.0.0'} + '@aws-sdk/signature-v4-multi-region@3.901.0': resolution: {integrity: sha512-2IWxbll/pRucp1WQkHi2W5E2SVPGBvk4Is923H7gpNksbVFws18ItjMM8ZpGm44cJEoy1zR5gjhLFklatpuoOw==} engines: {node: '>=18.0.0'} + '@aws-sdk/signature-v4-multi-region@3.922.0': + resolution: {integrity: sha512-mmsgEEL5pE+A7gFYiJMDBCLVciaXq4EFI5iAP7bPpnHvOplnNOYxVy2IreKMllGvrfjVyLnwxzZYlo5zZ65FWg==} + engines: {node: '>=18.0.0'} + '@aws-sdk/token-providers@3.901.0': resolution: {integrity: sha512-pJEr1Ggbc/uVTDqp9IbNu9hdr0eQf3yZix3s4Nnyvmg4xmJSGAlbPC9LrNr5u3CDZoc8Z9CuLrvbP4MwYquNpQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/token-providers@3.922.0': + resolution: {integrity: sha512-/inmPnjZE0ZBE16zaCowAvouSx05FJ7p6BQYuzlJ8vxEU0sS0Hf8fvhuiRnN9V9eDUPIBY+/5EjbMWygXL4wlQ==} + engines: {node: '>=18.0.0'} + '@aws-sdk/types@3.901.0': resolution: {integrity: sha512-FfEM25hLEs4LoXsLXQ/q6X6L4JmKkKkbVFpKD4mwfVHtRVQG6QxJiCPcrkcPISquiy6esbwK2eh64TWbiD60cg==} engines: {node: '>=18.0.0'} + '@aws-sdk/types@3.922.0': + resolution: {integrity: sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w==} + engines: {node: '>=18.0.0'} + '@aws-sdk/util-arn-parser@3.893.0': resolution: {integrity: sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==} engines: {node: '>=18.0.0'} @@ -447,6 +567,14 @@ packages: resolution: {integrity: sha512-5nZP3hGA8FHEtKvEQf4Aww5QZOkjLW1Z+NixSd+0XKfHvA39Ah5sZboScjLx0C9kti/K3OGW1RCx5K9Zc3bZqg==} engines: {node: '>=18.0.0'} + '@aws-sdk/util-endpoints@3.922.0': + resolution: {integrity: sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-format-url@3.922.0': + resolution: {integrity: sha512-UYLWPvZEd6TYilNkrQrIeXh2bXZsY3ighYErSEjD24f3JQhg0XdXoR/QHIE8licHu2qFrTRM6yi9LH1GY6X0cg==} + engines: {node: '>=18.0.0'} + '@aws-sdk/util-locate-window@3.893.0': resolution: {integrity: sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==} engines: {node: '>=18.0.0'} @@ -454,6 +582,9 @@ packages: '@aws-sdk/util-user-agent-browser@3.901.0': resolution: {integrity: sha512-Ntb6V/WFI21Ed4PDgL/8NSfoZQQf9xzrwNgiwvnxgAl/KvAvRBgQtqj5gHsDX8Nj2YmJuVoHfH9BGjL9VQ4WNg==} + '@aws-sdk/util-user-agent-browser@3.922.0': + resolution: {integrity: sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA==} + '@aws-sdk/util-user-agent-node@3.901.0': resolution: {integrity: sha512-l59KQP5TY7vPVUfEURc7P5BJKuNg1RSsAKBQW7LHLECXjLqDUbo2SMLrexLBEoArSt6E8QOrIN0C8z/0Xk0jYw==} engines: {node: '>=18.0.0'} @@ -463,14 +594,31 @@ packages: aws-crt: optional: true + '@aws-sdk/util-user-agent-node@3.922.0': + resolution: {integrity: sha512-NrPe/Rsr5kcGunkog0eBV+bY0inkRELsD2SacC4lQZvZiXf8VJ2Y7j+Yq1tB+h+FPLsdt3v9wItIvDf/laAm0Q==} + engines: {node: '>=18.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + '@aws-sdk/xml-builder@3.901.0': resolution: {integrity: sha512-pxFCkuAP7Q94wMTNPAwi6hEtNrp/BdFf+HOrIEeFQsk4EoOmpKY3I6S+u6A9Wg295J80Kh74LqDWM22ux3z6Aw==} engines: {node: '>=18.0.0'} + '@aws-sdk/xml-builder@3.921.0': + resolution: {integrity: sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q==} + engines: {node: '>=18.0.0'} + '@aws/lambda-invoke-store@0.0.1': resolution: {integrity: sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw==} engines: {node: '>=18.0.0'} + '@aws/lambda-invoke-store@0.1.1': + resolution: {integrity: sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} @@ -3206,30 +3354,94 @@ packages: resolution: {integrity: sha512-PLUYa+SUKOEZtXFURBu/CNxlsxfaFGxSBPcStL13KpVeVWIfdezWyDqkz7iDLmwnxojXD0s5KzuB5HGHvt4Aeg==} engines: {node: '>=18.0.0'} + '@smithy/abort-controller@4.2.4': + resolution: {integrity: sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader-native@4.2.1': + resolution: {integrity: sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader@5.2.0': + resolution: {integrity: sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==} + engines: {node: '>=18.0.0'} + '@smithy/config-resolver@4.3.0': resolution: {integrity: sha512-9oH+n8AVNiLPK/iK/agOsoWfrKZ3FGP3502tkksd6SRsKMYiu7AFX0YXo6YBADdsAj7C+G/aLKdsafIJHxuCkQ==} engines: {node: '>=18.0.0'} + '@smithy/config-resolver@4.4.2': + resolution: {integrity: sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw==} + engines: {node: '>=18.0.0'} + '@smithy/core@3.14.0': resolution: {integrity: sha512-XJ4z5FxvY/t0Dibms/+gLJrI5niRoY0BCmE02fwmPcRYFPI4KI876xaE79YGWIKnEslMbuQPsIEsoU/DXa0DoA==} engines: {node: '>=18.0.0'} + '@smithy/core@3.17.2': + resolution: {integrity: sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ==} + engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.2.0': resolution: {integrity: sha512-SOhFVvFH4D5HJZytb0bLKxCrSnwcqPiNlrw+S4ZXjMnsC+o9JcUQzbZOEQcA8yv9wJFNhfsUiIUKiEnYL68Big==} engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.2.4': + resolution: {integrity: sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.2.4': + resolution: {integrity: sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.2.4': + resolution: {integrity: sha512-d5T7ZS3J/r8P/PDjgmCcutmNxnSRvPH1U6iHeXjzI50sMr78GLmFcrczLw33Ap92oEKqa4CLrkAPeSSOqvGdUA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.3.4': + resolution: {integrity: sha512-lxfDT0UuSc1HqltOGsTEAlZ6H29gpfDSdEPTapD5G63RbnYToZ+ezjzdonCCH90j5tRRCw3aLXVbiZaBW3VRVg==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.2.4': + resolution: {integrity: sha512-TPhiGByWnYyzcpU/K3pO5V7QgtXYpE0NaJPEZBCa1Y5jlw5SjqzMSbFiLb+ZkJhqoQc0ImGyVINqnq1ze0ZRcQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.2.4': + resolution: {integrity: sha512-GNI/IXaY/XBB1SkGBFmbW033uWA0tj085eCxYih0eccUe/PFR7+UBQv9HNDk2fD9TJu7UVsCWsH99TkpEPSOzQ==} + engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.3.0': resolution: {integrity: sha512-BG3KSmsx9A//KyIfw+sqNmWFr1YBUr+TwpxFT7yPqAk0yyDh7oSNgzfNH7pS6OC099EGx2ltOULvumCFe8bcgw==} engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.3.5': + resolution: {integrity: sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-blob-browser@4.2.5': + resolution: {integrity: sha512-kCdgjD2J50qAqycYx0imbkA9tPtyQr1i5GwbK/EOUkpBmJGSkJe4mRJm+0F65TUSvvui1HZ5FFGFCND7l8/3WQ==} + engines: {node: '>=18.0.0'} + '@smithy/hash-node@4.2.0': resolution: {integrity: sha512-ugv93gOhZGysTctZh9qdgng8B+xO0cj+zN0qAZ+Sgh7qTQGPOJbMdIuyP89KNfUyfAqFSNh5tMvC+h2uCpmTtA==} engines: {node: '>=18.0.0'} + '@smithy/hash-node@4.2.4': + resolution: {integrity: sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-stream-node@4.2.4': + resolution: {integrity: sha512-amuh2IJiyRfO5MV0X/YFlZMD6banjvjAwKdeJiYGUbId608x+oSNwv3vlyW2Gt6AGAgl3EYAuyYLGRX/xU8npQ==} + engines: {node: '>=18.0.0'} + '@smithy/invalid-dependency@4.2.0': resolution: {integrity: sha512-ZmK5X5fUPAbtvRcUPtk28aqIClVhbfcmfoS4M7UQBTnDdrNxhsrxYVv0ZEl5NaPSyExsPWqL4GsPlRvtlwg+2A==} engines: {node: '>=18.0.0'} + '@smithy/invalid-dependency@4.2.4': + resolution: {integrity: sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw==} + engines: {node: '>=18.0.0'} + '@smithy/is-array-buffer@2.2.0': resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} engines: {node: '>=14.0.0'} @@ -3238,78 +3450,154 @@ packages: resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} engines: {node: '>=18.0.0'} + '@smithy/md5-js@4.2.4': + resolution: {integrity: sha512-h7kzNWZuMe5bPnZwKxhVbY1gan5+TZ2c9JcVTHCygB14buVGOZxLl+oGfpY2p2Xm48SFqEWdghpvbBdmaz3ncQ==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-content-length@4.2.0': resolution: {integrity: sha512-6ZAnwrXFecrA4kIDOcz6aLBhU5ih2is2NdcZtobBDSdSHtE9a+MThB5uqyK4XXesdOCvOcbCm2IGB95birTSOQ==} engines: {node: '>=18.0.0'} + '@smithy/middleware-content-length@4.2.4': + resolution: {integrity: sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-endpoint@4.3.0': resolution: {integrity: sha512-jFVjuQeV8TkxaRlcCNg0GFVgg98tscsmIrIwRFeC74TIUyLE3jmY9xgc1WXrPQYRjQNK3aRoaIk6fhFRGOIoGw==} engines: {node: '>=18.0.0'} + '@smithy/middleware-endpoint@4.3.6': + resolution: {integrity: sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.0': resolution: {integrity: sha512-yaVBR0vQnOnzex45zZ8ZrPzUnX73eUC8kVFaAAbn04+6V7lPtxn56vZEBBAhgS/eqD6Zm86o6sJs6FuQVoX5qg==} engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.6': + resolution: {integrity: sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-serde@4.2.0': resolution: {integrity: sha512-rpTQ7D65/EAbC6VydXlxjvbifTf4IH+sADKg6JmAvhkflJO2NvDeyU9qsWUNBelJiQFcXKejUHWRSdmpJmEmiw==} engines: {node: '>=18.0.0'} + '@smithy/middleware-serde@4.2.4': + resolution: {integrity: sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-stack@4.2.0': resolution: {integrity: sha512-G5CJ//eqRd9OARrQu9MK1H8fNm2sMtqFh6j8/rPozhEL+Dokpvi1Og+aCixTuwDAGZUkJPk6hJT5jchbk/WCyg==} engines: {node: '>=18.0.0'} + '@smithy/middleware-stack@4.2.4': + resolution: {integrity: sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA==} + engines: {node: '>=18.0.0'} + '@smithy/node-config-provider@4.3.0': resolution: {integrity: sha512-5QgHNuWdT9j9GwMPPJCKxy2KDxZ3E5l4M3/5TatSZrqYVoEiqQrDfAq8I6KWZw7RZOHtVtCzEPdYz7rHZixwcA==} engines: {node: '>=18.0.0'} + '@smithy/node-config-provider@4.3.4': + resolution: {integrity: sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw==} + engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.3.0': resolution: {integrity: sha512-RHZ/uWCmSNZ8cneoWEVsVwMZBKy/8123hEpm57vgGXA3Irf/Ja4v9TVshHK2ML5/IqzAZn0WhINHOP9xl+Qy6Q==} engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.4.4': + resolution: {integrity: sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA==} + engines: {node: '>=18.0.0'} + '@smithy/property-provider@4.2.0': resolution: {integrity: sha512-rV6wFre0BU6n/tx2Ztn5LdvEdNZ2FasQbPQmDOPfV9QQyDmsCkOAB0osQjotRCQg+nSKFmINhyda0D3AnjSBJw==} engines: {node: '>=18.0.0'} + '@smithy/property-provider@4.2.4': + resolution: {integrity: sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w==} + engines: {node: '>=18.0.0'} + '@smithy/protocol-http@5.3.0': resolution: {integrity: sha512-6POSYlmDnsLKb7r1D3SVm7RaYW6H1vcNcTWGWrF7s9+2noNYvUsm7E4tz5ZQ9HXPmKn6Hb67pBDRIjrT4w/d7Q==} engines: {node: '>=18.0.0'} + '@smithy/protocol-http@5.3.4': + resolution: {integrity: sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw==} + engines: {node: '>=18.0.0'} + '@smithy/querystring-builder@4.2.0': resolution: {integrity: sha512-Q4oFD0ZmI8yJkiPPeGUITZj++4HHYCW3pYBYfIobUCkYpI6mbkzmG1MAQQ3lJYYWj3iNqfzOenUZu+jqdPQ16A==} engines: {node: '>=18.0.0'} + '@smithy/querystring-builder@4.2.4': + resolution: {integrity: sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig==} + engines: {node: '>=18.0.0'} + '@smithy/querystring-parser@4.2.0': resolution: {integrity: sha512-BjATSNNyvVbQxOOlKse0b0pSezTWGMvA87SvoFoFlkRsKXVsN3bEtjCxvsNXJXfnAzlWFPaT9DmhWy1vn0sNEA==} engines: {node: '>=18.0.0'} + '@smithy/querystring-parser@4.2.4': + resolution: {integrity: sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ==} + engines: {node: '>=18.0.0'} + '@smithy/service-error-classification@4.2.0': resolution: {integrity: sha512-Ylv1ttUeKatpR0wEOMnHf1hXMktPUMObDClSWl2TpCVT4DwtJhCeighLzSLbgH3jr5pBNM0LDXT5yYxUvZ9WpA==} engines: {node: '>=18.0.0'} + '@smithy/service-error-classification@4.2.4': + resolution: {integrity: sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng==} + engines: {node: '>=18.0.0'} + '@smithy/shared-ini-file-loader@4.3.0': resolution: {integrity: sha512-VCUPPtNs+rKWlqqntX0CbVvWyjhmX30JCtzO+s5dlzzxrvSfRh5SY0yxnkirvc1c80vdKQttahL71a9EsdolSQ==} engines: {node: '>=18.0.0'} + '@smithy/shared-ini-file-loader@4.3.4': + resolution: {integrity: sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA==} + engines: {node: '>=18.0.0'} + '@smithy/signature-v4@5.3.0': resolution: {integrity: sha512-MKNyhXEs99xAZaFhm88h+3/V+tCRDQ+PrDzRqL0xdDpq4gjxcMmf5rBA3YXgqZqMZ/XwemZEurCBQMfxZOWq/g==} engines: {node: '>=18.0.0'} + '@smithy/signature-v4@5.3.4': + resolution: {integrity: sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A==} + engines: {node: '>=18.0.0'} + '@smithy/smithy-client@4.7.0': resolution: {integrity: sha512-3BDx/aCCPf+kkinYf5QQhdQ9UAGihgOVqI3QO5xQfSaIWvUE4KYLtiGRWsNe1SR7ijXC0QEPqofVp5Sb0zC8xQ==} engines: {node: '>=18.0.0'} + '@smithy/smithy-client@4.9.2': + resolution: {integrity: sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg==} + engines: {node: '>=18.0.0'} + '@smithy/types@4.6.0': resolution: {integrity: sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==} engines: {node: '>=18.0.0'} + '@smithy/types@4.8.1': + resolution: {integrity: sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA==} + engines: {node: '>=18.0.0'} + '@smithy/url-parser@4.2.0': resolution: {integrity: sha512-AlBmD6Idav2ugmoAL6UtR6ItS7jU5h5RNqLMZC7QrLCoITA9NzIN3nx9GWi8g4z1pfWh2r9r96SX/jHiNwPJ9A==} engines: {node: '>=18.0.0'} + '@smithy/url-parser@4.2.4': + resolution: {integrity: sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg==} + engines: {node: '>=18.0.0'} + '@smithy/util-base64@4.2.0': resolution: {integrity: sha512-+erInz8WDv5KPe7xCsJCp+1WCjSbah9gWcmUXc9NqmhyPx59tf7jqFz+za1tRG1Y5KM1Cy1rWCcGypylFp4mvA==} engines: {node: '>=18.0.0'} + '@smithy/util-base64@4.3.0': + resolution: {integrity: sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==} + engines: {node: '>=18.0.0'} + '@smithy/util-body-length-browser@4.2.0': resolution: {integrity: sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==} engines: {node: '>=18.0.0'} @@ -3318,6 +3606,10 @@ packages: resolution: {integrity: sha512-U8q1WsSZFjXijlD7a4wsDQOvOwV+72iHSfq1q7VD+V75xP/pdtm0WIGuaFJ3gcADDOKj2MIBn4+zisi140HEnQ==} engines: {node: '>=18.0.0'} + '@smithy/util-body-length-node@4.2.1': + resolution: {integrity: sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==} + engines: {node: '>=18.0.0'} + '@smithy/util-buffer-from@2.2.0': resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} engines: {node: '>=14.0.0'} @@ -3334,14 +3626,26 @@ packages: resolution: {integrity: sha512-qzHp7ZDk1Ba4LDwQVCNp90xPGqSu7kmL7y5toBpccuhi3AH7dcVBIT/pUxYcInK4jOy6FikrcTGq5wxcka8UaQ==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-browser@4.3.5': + resolution: {integrity: sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ==} + engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.0': resolution: {integrity: sha512-FxUHS3WXgx3bTWR6yQHNHHkQHZm/XKIi/CchTnKvBulN6obWpcbzJ6lDToXn+Wp0QlVKd7uYAz2/CTw1j7m+Kg==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.8': + resolution: {integrity: sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g==} + engines: {node: '>=18.0.0'} + '@smithy/util-endpoints@3.2.0': resolution: {integrity: sha512-TXeCn22D56vvWr/5xPqALc9oO+LN+QpFjrSM7peG/ckqEPoI3zaKZFp+bFwfmiHhn5MGWPaLCqDOJPPIixk9Wg==} engines: {node: '>=18.0.0'} + '@smithy/util-endpoints@3.2.4': + resolution: {integrity: sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg==} + engines: {node: '>=18.0.0'} + '@smithy/util-hex-encoding@4.2.0': resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} engines: {node: '>=18.0.0'} @@ -3350,14 +3654,26 @@ packages: resolution: {integrity: sha512-u9OOfDa43MjagtJZ8AapJcmimP+K2Z7szXn8xbty4aza+7P1wjFmy2ewjSbhEiYQoW1unTlOAIV165weYAaowA==} engines: {node: '>=18.0.0'} + '@smithy/util-middleware@4.2.4': + resolution: {integrity: sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg==} + engines: {node: '>=18.0.0'} + '@smithy/util-retry@4.2.0': resolution: {integrity: sha512-BWSiuGbwRnEE2SFfaAZEX0TqaxtvtSYPM/J73PFVm+A29Fg1HTPiYFb8TmX1DXp4hgcdyJcNQmprfd5foeORsg==} engines: {node: '>=18.0.0'} + '@smithy/util-retry@4.2.4': + resolution: {integrity: sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA==} + engines: {node: '>=18.0.0'} + '@smithy/util-stream@4.4.0': resolution: {integrity: sha512-vtO7ktbixEcrVzMRmpQDnw/Ehr9UWjBvSJ9fyAbadKkC4w5Cm/4lMO8cHz8Ysb8uflvQUNRcuux/oNHKPXkffg==} engines: {node: '>=18.0.0'} + '@smithy/util-stream@4.5.5': + resolution: {integrity: sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w==} + engines: {node: '>=18.0.0'} + '@smithy/util-uri-escape@4.2.0': resolution: {integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==} engines: {node: '>=18.0.0'} @@ -3370,6 +3686,10 @@ packages: resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} engines: {node: '>=18.0.0'} + '@smithy/util-waiter@4.2.4': + resolution: {integrity: sha512-roKXtXIC6fopFvVOju8VYHtguc/jAcMlK8IlDOHsrQn0ayMkHynjm/D2DCMRf7MJFXzjHhlzg2edr3QPEakchQ==} + engines: {node: '>=18.0.0'} + '@smithy/uuid@1.1.0': resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} engines: {node: '>=18.0.0'} @@ -4476,6 +4796,17 @@ packages: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} + better-upload@2.0.3: + resolution: {integrity: sha512-fXpymXzPLDSmDja18dDtuniY+t36NRXo8ftrzWjZJxWbEJxBDZ29sucf8+sd21AJZX1KM8W2nYLSK2ksggLYdA==} + peerDependencies: + '@aws-sdk/client-s3': '*' + react: '*' + peerDependenciesMeta: + '@aws-sdk/client-s3': + optional: true + react: + optional: true + big-integer@1.6.52: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} @@ -8956,12 +9287,33 @@ snapshots: '@csstools/css-tokenizer': 3.0.3 lru-cache: 10.4.3 + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.922.0 + tslib: 2.8.1 + + '@aws-crypto/crc32c@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.922.0 + tslib: 2.8.1 + + '@aws-crypto/sha1-browser@5.2.0': + dependencies: + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-locate-window': 3.893.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + '@aws-crypto/sha256-browser@5.2.0': dependencies: '@aws-crypto/sha256-js': 5.2.0 '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.901.0 + '@aws-sdk/types': 3.922.0 '@aws-sdk/util-locate-window': 3.893.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -8969,7 +9321,7 @@ snapshots: '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.901.0 + '@aws-sdk/types': 3.922.0 tslib: 2.8.1 '@aws-crypto/supports-web-crypto@5.2.0': @@ -8978,10 +9330,72 @@ snapshots: '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.901.0 + '@aws-sdk/types': 3.922.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 + '@aws-sdk/client-s3@3.922.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.922.0 + '@aws-sdk/credential-provider-node': 3.922.0 + '@aws-sdk/middleware-bucket-endpoint': 3.922.0 + '@aws-sdk/middleware-expect-continue': 3.922.0 + '@aws-sdk/middleware-flexible-checksums': 3.922.0 + '@aws-sdk/middleware-host-header': 3.922.0 + '@aws-sdk/middleware-location-constraint': 3.922.0 + '@aws-sdk/middleware-logger': 3.922.0 + '@aws-sdk/middleware-recursion-detection': 3.922.0 + '@aws-sdk/middleware-sdk-s3': 3.922.0 + '@aws-sdk/middleware-ssec': 3.922.0 + '@aws-sdk/middleware-user-agent': 3.922.0 + '@aws-sdk/region-config-resolver': 3.922.0 + '@aws-sdk/signature-v4-multi-region': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-endpoints': 3.922.0 + '@aws-sdk/util-user-agent-browser': 3.922.0 + '@aws-sdk/util-user-agent-node': 3.922.0 + '@aws-sdk/xml-builder': 3.921.0 + '@smithy/config-resolver': 4.4.2 + '@smithy/core': 3.17.2 + '@smithy/eventstream-serde-browser': 4.2.4 + '@smithy/eventstream-serde-config-resolver': 4.3.4 + '@smithy/eventstream-serde-node': 4.2.4 + '@smithy/fetch-http-handler': 5.3.5 + '@smithy/hash-blob-browser': 4.2.5 + '@smithy/hash-node': 4.2.4 + '@smithy/hash-stream-node': 4.2.4 + '@smithy/invalid-dependency': 4.2.4 + '@smithy/md5-js': 4.2.4 + '@smithy/middleware-content-length': 4.2.4 + '@smithy/middleware-endpoint': 4.3.6 + '@smithy/middleware-retry': 4.4.6 + '@smithy/middleware-serde': 4.2.4 + '@smithy/middleware-stack': 4.2.4 + '@smithy/node-config-provider': 4.3.4 + '@smithy/node-http-handler': 4.4.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + '@smithy/url-parser': 4.2.4 + '@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.5 + '@smithy/util-defaults-mode-node': 4.2.8 + '@smithy/util-endpoints': 3.2.4 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-retry': 4.2.4 + '@smithy/util-stream': 4.5.5 + '@smithy/util-utf8': 4.2.0 + '@smithy/util-waiter': 4.2.4 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/client-sesv2@3.901.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -9070,6 +9484,49 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/client-sso@3.922.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.922.0 + '@aws-sdk/middleware-host-header': 3.922.0 + '@aws-sdk/middleware-logger': 3.922.0 + '@aws-sdk/middleware-recursion-detection': 3.922.0 + '@aws-sdk/middleware-user-agent': 3.922.0 + '@aws-sdk/region-config-resolver': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-endpoints': 3.922.0 + '@aws-sdk/util-user-agent-browser': 3.922.0 + '@aws-sdk/util-user-agent-node': 3.922.0 + '@smithy/config-resolver': 4.4.2 + '@smithy/core': 3.17.2 + '@smithy/fetch-http-handler': 5.3.5 + '@smithy/hash-node': 4.2.4 + '@smithy/invalid-dependency': 4.2.4 + '@smithy/middleware-content-length': 4.2.4 + '@smithy/middleware-endpoint': 4.3.6 + '@smithy/middleware-retry': 4.4.6 + '@smithy/middleware-serde': 4.2.4 + '@smithy/middleware-stack': 4.2.4 + '@smithy/node-config-provider': 4.3.4 + '@smithy/node-http-handler': 4.4.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + '@smithy/url-parser': 4.2.4 + '@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.5 + '@smithy/util-defaults-mode-node': 4.2.8 + '@smithy/util-endpoints': 3.2.4 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-retry': 4.2.4 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/core@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 @@ -9086,6 +9543,22 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@aws-sdk/core@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@aws-sdk/xml-builder': 3.921.0 + '@smithy/core': 3.17.2 + '@smithy/node-config-provider': 4.3.4 + '@smithy/property-provider': 4.2.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/signature-v4': 5.3.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + '@smithy/util-base64': 4.3.0 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9094,6 +9567,14 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/property-provider': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9107,6 +9588,19 @@ snapshots: '@smithy/util-stream': 4.4.0 tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/fetch-http-handler': 5.3.5 + '@smithy/node-http-handler': 4.4.4 + '@smithy/property-provider': 4.2.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + '@smithy/util-stream': 4.5.5 + tslib: 2.8.1 + '@aws-sdk/credential-provider-ini@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9125,6 +9619,24 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/credential-provider-env': 3.922.0 + '@aws-sdk/credential-provider-http': 3.922.0 + '@aws-sdk/credential-provider-process': 3.922.0 + '@aws-sdk/credential-provider-sso': 3.922.0 + '@aws-sdk/credential-provider-web-identity': 3.922.0 + '@aws-sdk/nested-clients': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/credential-provider-imds': 4.2.4 + '@smithy/property-provider': 4.2.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-node@3.901.0': dependencies: '@aws-sdk/credential-provider-env': 3.901.0 @@ -9142,6 +9654,23 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.922.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.922.0 + '@aws-sdk/credential-provider-http': 3.922.0 + '@aws-sdk/credential-provider-ini': 3.922.0 + '@aws-sdk/credential-provider-process': 3.922.0 + '@aws-sdk/credential-provider-sso': 3.922.0 + '@aws-sdk/credential-provider-web-identity': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/credential-provider-imds': 4.2.4 + '@smithy/property-provider': 4.2.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-process@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9151,6 +9680,15 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/property-provider': 4.2.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/credential-provider-sso@3.901.0': dependencies: '@aws-sdk/client-sso': 3.901.0 @@ -9164,6 +9702,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-sso@3.922.0': + dependencies: + '@aws-sdk/client-sso': 3.922.0 + '@aws-sdk/core': 3.922.0 + '@aws-sdk/token-providers': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/property-provider': 4.2.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-web-identity@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9176,6 +9727,51 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-web-identity@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/nested-clients': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/property-provider': 4.2.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/middleware-bucket-endpoint@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-arn-parser': 3.893.0 + '@smithy/node-config-provider': 4.3.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + '@smithy/util-config-provider': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-expect-continue@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + + '@aws-sdk/middleware-flexible-checksums@3.922.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/core': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/is-array-buffer': 4.2.0 + '@smithy/node-config-provider': 4.3.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-stream': 4.5.5 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@aws-sdk/middleware-host-header@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 @@ -9183,12 +9779,31 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/middleware-host-header@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + + '@aws-sdk/middleware-location-constraint@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/middleware-logger@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/middleware-logger@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/middleware-recursion-detection@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 @@ -9197,6 +9812,14 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/middleware-recursion-detection@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@aws/lambda-invoke-store': 0.1.1 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/middleware-sdk-s3@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9214,6 +9837,29 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@aws-sdk/middleware-sdk-s3@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-arn-parser': 3.893.0 + '@smithy/core': 3.17.2 + '@smithy/node-config-provider': 4.3.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/signature-v4': 5.3.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + '@smithy/util-config-provider': 4.2.0 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-stream': 4.5.5 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-ssec@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9224,6 +9870,16 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-endpoints': 3.922.0 + '@smithy/core': 3.17.2 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/nested-clients@3.901.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -9267,6 +9923,49 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/nested-clients@3.922.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.922.0 + '@aws-sdk/middleware-host-header': 3.922.0 + '@aws-sdk/middleware-logger': 3.922.0 + '@aws-sdk/middleware-recursion-detection': 3.922.0 + '@aws-sdk/middleware-user-agent': 3.922.0 + '@aws-sdk/region-config-resolver': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-endpoints': 3.922.0 + '@aws-sdk/util-user-agent-browser': 3.922.0 + '@aws-sdk/util-user-agent-node': 3.922.0 + '@smithy/config-resolver': 4.4.2 + '@smithy/core': 3.17.2 + '@smithy/fetch-http-handler': 5.3.5 + '@smithy/hash-node': 4.2.4 + '@smithy/invalid-dependency': 4.2.4 + '@smithy/middleware-content-length': 4.2.4 + '@smithy/middleware-endpoint': 4.3.6 + '@smithy/middleware-retry': 4.4.6 + '@smithy/middleware-serde': 4.2.4 + '@smithy/middleware-stack': 4.2.4 + '@smithy/node-config-provider': 4.3.4 + '@smithy/node-http-handler': 4.4.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + '@smithy/url-parser': 4.2.4 + '@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.5 + '@smithy/util-defaults-mode-node': 4.2.8 + '@smithy/util-endpoints': 3.2.4 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-retry': 4.2.4 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/region-config-resolver@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 @@ -9276,6 +9975,25 @@ snapshots: '@smithy/util-middleware': 4.2.0 tslib: 2.8.1 + '@aws-sdk/region-config-resolver@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/config-resolver': 4.4.2 + '@smithy/node-config-provider': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + + '@aws-sdk/s3-request-presigner@3.922.0': + dependencies: + '@aws-sdk/signature-v4-multi-region': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-format-url': 3.922.0 + '@smithy/middleware-endpoint': 4.3.6 + '@smithy/protocol-http': 5.3.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/signature-v4-multi-region@3.901.0': dependencies: '@aws-sdk/middleware-sdk-s3': 3.901.0 @@ -9285,6 +10003,15 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/signature-v4-multi-region@3.922.0': + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/protocol-http': 5.3.4 + '@smithy/signature-v4': 5.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/token-providers@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9297,11 +10024,28 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/token-providers@3.922.0': + dependencies: + '@aws-sdk/core': 3.922.0 + '@aws-sdk/nested-clients': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/property-provider': 4.2.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/types@3.901.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/types@3.922.0': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/util-arn-parser@3.893.0': dependencies: tslib: 2.8.1 @@ -9314,6 +10058,21 @@ snapshots: '@smithy/util-endpoints': 3.2.0 tslib: 2.8.1 + '@aws-sdk/util-endpoints@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/types': 4.8.1 + '@smithy/url-parser': 4.2.4 + '@smithy/util-endpoints': 3.2.4 + tslib: 2.8.1 + + '@aws-sdk/util-format-url@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/querystring-builder': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/util-locate-window@3.893.0': dependencies: tslib: 2.8.1 @@ -9325,6 +10084,13 @@ snapshots: bowser: 2.12.1 tslib: 2.8.1 + '@aws-sdk/util-user-agent-browser@3.922.0': + dependencies: + '@aws-sdk/types': 3.922.0 + '@smithy/types': 4.8.1 + bowser: 2.12.1 + tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.901.0': dependencies: '@aws-sdk/middleware-user-agent': 3.901.0 @@ -9333,14 +10099,30 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.922.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.922.0 + '@aws-sdk/types': 3.922.0 + '@smithy/node-config-provider': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@aws-sdk/xml-builder@3.901.0': dependencies: '@smithy/types': 4.6.0 fast-xml-parser: 5.2.5 tslib: 2.8.1 + '@aws-sdk/xml-builder@3.921.0': + dependencies: + '@smithy/types': 4.8.1 + fast-xml-parser: 5.2.5 + tslib: 2.8.1 + '@aws/lambda-invoke-store@0.0.1': {} + '@aws/lambda-invoke-store@0.1.1': {} + '@babel/code-frame@7.10.4': dependencies: '@babel/highlight': 7.25.9 @@ -12555,6 +13337,20 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/abort-controller@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader-native@4.2.1': + dependencies: + '@smithy/util-base64': 4.3.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader@5.2.0': + dependencies: + tslib: 2.8.1 + '@smithy/config-resolver@4.3.0': dependencies: '@smithy/node-config-provider': 4.3.0 @@ -12563,6 +13359,15 @@ snapshots: '@smithy/util-middleware': 4.2.0 tslib: 2.8.1 + '@smithy/config-resolver@4.4.2': + dependencies: + '@smithy/node-config-provider': 4.3.4 + '@smithy/types': 4.8.1 + '@smithy/util-config-provider': 4.2.0 + '@smithy/util-endpoints': 3.2.4 + '@smithy/util-middleware': 4.2.4 + tslib: 2.8.1 + '@smithy/core@3.14.0': dependencies: '@smithy/middleware-serde': 4.2.0 @@ -12576,6 +13381,19 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/core@3.17.2': + dependencies: + '@smithy/middleware-serde': 4.2.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-stream': 4.5.5 + '@smithy/util-utf8': 4.2.0 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + '@smithy/credential-provider-imds@4.2.0': dependencies: '@smithy/node-config-provider': 4.3.0 @@ -12584,6 +13402,44 @@ snapshots: '@smithy/url-parser': 4.2.0 tslib: 2.8.1 + '@smithy/credential-provider-imds@4.2.4': + dependencies: + '@smithy/node-config-provider': 4.3.4 + '@smithy/property-provider': 4.2.4 + '@smithy/types': 4.8.1 + '@smithy/url-parser': 4.2.4 + tslib: 2.8.1 + + '@smithy/eventstream-codec@4.2.4': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.8.1 + '@smithy/util-hex-encoding': 4.2.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@4.2.4': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@4.3.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@4.2.4': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@4.2.4': + dependencies: + '@smithy/eventstream-codec': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/fetch-http-handler@5.3.0': dependencies: '@smithy/protocol-http': 5.3.0 @@ -12592,6 +13448,21 @@ snapshots: '@smithy/util-base64': 4.2.0 tslib: 2.8.1 + '@smithy/fetch-http-handler@5.3.5': + dependencies: + '@smithy/protocol-http': 5.3.4 + '@smithy/querystring-builder': 4.2.4 + '@smithy/types': 4.8.1 + '@smithy/util-base64': 4.3.0 + tslib: 2.8.1 + + '@smithy/hash-blob-browser@4.2.5': + dependencies: + '@smithy/chunked-blob-reader': 5.2.0 + '@smithy/chunked-blob-reader-native': 4.2.1 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/hash-node@4.2.0': dependencies: '@smithy/types': 4.6.0 @@ -12599,11 +13470,29 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/hash-node@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/hash-stream-node@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@smithy/invalid-dependency@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/invalid-dependency@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/is-array-buffer@2.2.0': dependencies: tslib: 2.8.1 @@ -12612,12 +13501,24 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/md5-js@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@smithy/middleware-content-length@4.2.0': dependencies: '@smithy/protocol-http': 5.3.0 '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/middleware-content-length@4.2.4': + dependencies: + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/middleware-endpoint@4.3.0': dependencies: '@smithy/core': 3.14.0 @@ -12629,6 +13530,17 @@ snapshots: '@smithy/util-middleware': 4.2.0 tslib: 2.8.1 + '@smithy/middleware-endpoint@4.3.6': + dependencies: + '@smithy/core': 3.17.2 + '@smithy/middleware-serde': 4.2.4 + '@smithy/node-config-provider': 4.3.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + '@smithy/url-parser': 4.2.4 + '@smithy/util-middleware': 4.2.4 + tslib: 2.8.1 + '@smithy/middleware-retry@4.4.0': dependencies: '@smithy/node-config-provider': 4.3.0 @@ -12641,17 +13553,40 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/middleware-retry@4.4.6': + dependencies: + '@smithy/node-config-provider': 4.3.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/service-error-classification': 4.2.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-retry': 4.2.4 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + '@smithy/middleware-serde@4.2.0': dependencies: '@smithy/protocol-http': 5.3.0 '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/middleware-serde@4.2.4': + dependencies: + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/middleware-stack@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/middleware-stack@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/node-config-provider@4.3.0': dependencies: '@smithy/property-provider': 4.2.0 @@ -12659,6 +13594,13 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/node-config-provider@4.3.4': + dependencies: + '@smithy/property-provider': 4.2.4 + '@smithy/shared-ini-file-loader': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/node-http-handler@4.3.0': dependencies: '@smithy/abort-controller': 4.2.0 @@ -12667,36 +13609,74 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/node-http-handler@4.4.4': + dependencies: + '@smithy/abort-controller': 4.2.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/querystring-builder': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/property-provider@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/property-provider@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/protocol-http@5.3.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/protocol-http@5.3.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/querystring-builder@4.2.0': dependencies: '@smithy/types': 4.6.0 '@smithy/util-uri-escape': 4.2.0 tslib: 2.8.1 + '@smithy/querystring-builder@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + '@smithy/util-uri-escape': 4.2.0 + tslib: 2.8.1 + '@smithy/querystring-parser@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/querystring-parser@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/service-error-classification@4.2.0': dependencies: '@smithy/types': 4.6.0 + '@smithy/service-error-classification@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + '@smithy/shared-ini-file-loader@4.3.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/shared-ini-file-loader@4.3.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/signature-v4@5.3.0': dependencies: '@smithy/is-array-buffer': 4.2.0 @@ -12708,6 +13688,17 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/signature-v4@5.3.4': + dependencies: + '@smithy/is-array-buffer': 4.2.0 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-middleware': 4.2.4 + '@smithy/util-uri-escape': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@smithy/smithy-client@4.7.0': dependencies: '@smithy/core': 3.14.0 @@ -12718,22 +13709,48 @@ snapshots: '@smithy/util-stream': 4.4.0 tslib: 2.8.1 + '@smithy/smithy-client@4.9.2': + dependencies: + '@smithy/core': 3.17.2 + '@smithy/middleware-endpoint': 4.3.6 + '@smithy/middleware-stack': 4.2.4 + '@smithy/protocol-http': 5.3.4 + '@smithy/types': 4.8.1 + '@smithy/util-stream': 4.5.5 + tslib: 2.8.1 + '@smithy/types@4.6.0': dependencies: tslib: 2.8.1 + '@smithy/types@4.8.1': + dependencies: + tslib: 2.8.1 + '@smithy/url-parser@4.2.0': dependencies: '@smithy/querystring-parser': 4.2.0 '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/url-parser@4.2.4': + dependencies: + '@smithy/querystring-parser': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/util-base64@4.2.0': dependencies: '@smithy/util-buffer-from': 4.2.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/util-base64@4.3.0': + dependencies: + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@smithy/util-body-length-browser@4.2.0': dependencies: tslib: 2.8.1 @@ -12742,6 +13759,10 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/util-body-length-node@4.2.1': + dependencies: + tslib: 2.8.1 + '@smithy/util-buffer-from@2.2.0': dependencies: '@smithy/is-array-buffer': 2.2.0 @@ -12764,6 +13785,13 @@ snapshots: bowser: 2.12.1 tslib: 2.8.1 + '@smithy/util-defaults-mode-browser@4.3.5': + dependencies: + '@smithy/property-provider': 4.2.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.0': dependencies: '@smithy/config-resolver': 4.3.0 @@ -12774,12 +13802,28 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.8': + dependencies: + '@smithy/config-resolver': 4.4.2 + '@smithy/credential-provider-imds': 4.2.4 + '@smithy/node-config-provider': 4.3.4 + '@smithy/property-provider': 4.2.4 + '@smithy/smithy-client': 4.9.2 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/util-endpoints@3.2.0': dependencies: '@smithy/node-config-provider': 4.3.0 '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/util-endpoints@3.2.4': + dependencies: + '@smithy/node-config-provider': 4.3.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/util-hex-encoding@4.2.0': dependencies: tslib: 2.8.1 @@ -12789,12 +13833,23 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/util-middleware@4.2.4': + dependencies: + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/util-retry@4.2.0': dependencies: '@smithy/service-error-classification': 4.2.0 '@smithy/types': 4.6.0 tslib: 2.8.1 + '@smithy/util-retry@4.2.4': + dependencies: + '@smithy/service-error-classification': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/util-stream@4.4.0': dependencies: '@smithy/fetch-http-handler': 5.3.0 @@ -12806,6 +13861,17 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/util-stream@4.5.5': + dependencies: + '@smithy/fetch-http-handler': 5.3.5 + '@smithy/node-http-handler': 4.4.4 + '@smithy/types': 4.8.1 + '@smithy/util-base64': 4.3.0 + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@smithy/util-uri-escape@4.2.0': dependencies: tslib: 2.8.1 @@ -12820,6 +13886,12 @@ snapshots: '@smithy/util-buffer-from': 4.2.0 tslib: 2.8.1 + '@smithy/util-waiter@4.2.4': + dependencies: + '@smithy/abort-controller': 4.2.4 + '@smithy/types': 4.8.1 + tslib: 2.8.1 + '@smithy/uuid@1.1.0': dependencies: tslib: 2.8.1 @@ -14271,6 +15343,14 @@ snapshots: dependencies: open: 8.4.2 + better-upload@2.0.3(@aws-sdk/client-s3@3.922.0)(react@19.2.0): + dependencies: + '@aws-sdk/s3-request-presigner': 3.922.0 + zod: 4.1.12 + optionalDependencies: + '@aws-sdk/client-s3': 3.922.0 + react: 19.2.0 + big-integer@1.6.52: {} binary-extensions@2.2.0: {} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 437b0e446..b16544e93 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -94,6 +94,7 @@ model Book { genre Genre? @relation(fields: [genreId], references: [id]) genreId String publisher String? + coverId String? @@unique([title, author]) @@map("book") diff --git a/src/env/client.ts b/src/env/client.ts index 1400af82f..66986fb38 100644 --- a/src/env/client.ts +++ b/src/env/client.ts @@ -42,6 +42,7 @@ export const envClient = createEnv({ .string() .optional() .transform((value) => value ?? (isDev ? 'gold' : 'plum')), + VITE_S3_BUCKET_PUBLIC_URL: z.string().url(), }, runtimeEnv: { ...envMetaOrProcess, diff --git a/src/env/server.ts b/src/env/server.ts index 9d8b0af68..c319230e5 100644 --- a/src/env/server.ts +++ b/src/env/server.ts @@ -33,6 +33,15 @@ export const envServer = createEnv({ .enum(['true', 'false']) .prefault(isProd ? 'false' : 'true') .transform((value) => value === 'true'), + DOCKER_MINIO_API_PORT: z.string().default('9000'), + DOCKER_MINIO_UI_PORT: z.string().default('9001'), + DOCKER_MINIO_USERNAME: z.string(), + DOCKER_MINIO_PASSWORD: z.string(), + S3_ACCESS_KEY_ID: z.string(), + S3_SECRET_ACCESS_KEY: z.string(), + S3_BUCKET_NAME: z.string().default('default'), + S3_REGION: z.string().default('default'), + S3_ENDPOINT: z.string(), }, runtimeEnv: process.env, emptyStringAsUndefined: true, diff --git a/src/features/book/book-cover.tsx b/src/features/book/book-cover.tsx index 30d20535a..90697100b 100644 --- a/src/features/book/book-cover.tsx +++ b/src/features/book/book-cover.tsx @@ -1,25 +1,35 @@ import { useTranslation } from 'react-i18next'; +import { match, P } from 'ts-pattern'; import { cn } from '@/lib/tailwind/utils'; +import { envClient } from '@/env/client'; import { Book } from '@/features/book/schema'; export const BookCover = (props: { - book: Partial>; + book: Partial>; variant?: 'default' | 'tiny'; className?: string; }) => { const { t } = useTranslation(['book']); + console.log(props.book); + const style = match(props.book.coverId || null) + .with(P.nullish, () => ({ + backgroundColor: props.book.genre?.color ?? '#333', + })) + .with(P._, (coverId) => ({ + backgroundImage: `url(${envClient.VITE_S3_BUCKET_PUBLIC_URL}/${coverId})`, + })) + .exhaustive(); + return (
diff --git a/src/features/book/manager/form-book-cover.tsx b/src/features/book/manager/form-book-cover.tsx index 8aaf3ce92..b551e4620 100644 --- a/src/features/book/manager/form-book-cover.tsx +++ b/src/features/book/manager/form-book-cover.tsx @@ -1,4 +1,5 @@ import { useQuery } from '@tanstack/react-query'; +import { useUploadFile } from 'better-upload/client'; import { useFormContext, useWatch } from 'react-hook-form'; import { orpc } from '@/lib/orpc/client'; @@ -22,13 +23,46 @@ export const FormBookCover = () => { control: form.control, }); const genre = genresQuery.data?.items.find((item) => item.id === genreId); + + const coverId = useWatch({ + name: 'coverId', + control: form.control, + }); + + const { upload, uploadedFile } = useUploadFile({ + route: 'bookCover', + onUploadComplete: ({ file }) => { + form.setValue('coverId', file.objectKey); + }, + }); + + // [TODO] Handle upload errors + return ( - +
+ +
); }; diff --git a/src/features/book/manager/page-book-update.tsx b/src/features/book/manager/page-book-update.tsx index 7fd2aaa18..e655cf33b 100644 --- a/src/features/book/manager/page-book-update.tsx +++ b/src/features/book/manager/page-book-update.tsx @@ -39,6 +39,7 @@ export const PageBookUpdate = (props: { params: { id: string } }) => { author: bookQuery.data?.author ?? '', genreId: bookQuery.data?.genre?.id ?? null!, publisher: bookQuery.data?.publisher ?? '', + coverId: bookQuery.data?.coverId ?? '', }, }); diff --git a/src/features/book/schema.ts b/src/features/book/schema.ts index 094a221ba..267bf434f 100644 --- a/src/features/book/schema.ts +++ b/src/features/book/schema.ts @@ -16,10 +16,11 @@ export const zBook = () => publisher: zu.fieldText.nullish(), createdAt: z.date(), updatedAt: z.date(), + coverId: z.string().nullish(), }); export type FormFieldsBook = z.infer>; export const zFormFieldsBook = () => zBook() - .pick({ title: true, author: true, publisher: true }) + .pick({ title: true, author: true, publisher: true, coverId: true }) .extend({ genreId: zu.fieldText.required() }); diff --git a/src/lib/s3/index.ts b/src/lib/s3/index.ts new file mode 100644 index 000000000..6f26f6ee9 --- /dev/null +++ b/src/lib/s3/index.ts @@ -0,0 +1,13 @@ +import { S3Client } from '@aws-sdk/client-s3'; + +import { envServer } from '@/env/server'; + +export const s3client = new S3Client({ + endpoint: envServer.S3_ENDPOINT, + forcePathStyle: true, + credentials: { + accessKeyId: envServer.S3_ACCESS_KEY_ID, + secretAccessKey: envServer.S3_SECRET_ACCESS_KEY, + }, + region: envServer.S3_REGION, +}); diff --git a/src/locales/en/book.json b/src/locales/en/book.json index eb3660064..92ec5e55e 100644 --- a/src/locales/en/book.json +++ b/src/locales/en/book.json @@ -57,7 +57,11 @@ "updateButton": { "label": "Save" }, - "updateError": "Failed to update a book" + "updateError": "Failed to update a book", + "uploadErrorCodes": { + "NOT_AUTHENTICATED": "You need to be authenticated to be able to upload a new cover", + "UNAUTHORIZED": "You are not allowed to change book cover" + } } } } diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 40ef49a78..e1babf500 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -16,6 +16,7 @@ import { Route as IndexRouteImport } from './routes/index' import { Route as ManagerIndexRouteImport } from './routes/manager/index' import { Route as LoginIndexRouteImport } from './routes/login/index' import { Route as AppIndexRouteImport } from './routes/app/index' +import { Route as ApiUploadRouteImport } from './routes/api/upload' import { Route as ManagerUsersIndexRouteImport } from './routes/manager/users/index' import { Route as ManagerDashboardIndexRouteImport } from './routes/manager/dashboard.index' import { Route as ManagerBooksIndexRouteImport } from './routes/manager/books/index' @@ -75,6 +76,11 @@ const AppIndexRoute = AppIndexRouteImport.update({ path: '/', getParentRoute: () => AppRouteRoute, } as any) +const ApiUploadRoute = ApiUploadRouteImport.update({ + id: '/api/upload', + path: '/api/upload', + getParentRoute: () => rootRouteImport, +} as any) const ManagerUsersIndexRoute = ManagerUsersIndexRouteImport.update({ id: '/users/', path: '/users/', @@ -198,6 +204,7 @@ export interface FileRoutesByFullPath { '/app': typeof AppRouteRouteWithChildren '/login': typeof LoginRouteRouteWithChildren '/manager': typeof ManagerRouteRouteWithChildren + '/api/upload': typeof ApiUploadRoute '/app/': typeof AppIndexRoute '/login/': typeof LoginIndexRoute '/manager/': typeof ManagerIndexRoute @@ -227,6 +234,7 @@ export interface FileRoutesByFullPath { } export interface FileRoutesByTo { '/': typeof IndexRoute + '/api/upload': typeof ApiUploadRoute '/app': typeof AppIndexRoute '/login': typeof LoginIndexRoute '/manager': typeof ManagerIndexRoute @@ -260,6 +268,7 @@ export interface FileRoutesById { '/app': typeof AppRouteRouteWithChildren '/login': typeof LoginRouteRouteWithChildren '/manager': typeof ManagerRouteRouteWithChildren + '/api/upload': typeof ApiUploadRoute '/app/': typeof AppIndexRoute '/login/': typeof LoginIndexRoute '/manager/': typeof ManagerIndexRoute @@ -294,6 +303,7 @@ export interface FileRouteTypes { | '/app' | '/login' | '/manager' + | '/api/upload' | '/app/' | '/login/' | '/manager/' @@ -323,6 +333,7 @@ export interface FileRouteTypes { fileRoutesByTo: FileRoutesByTo to: | '/' + | '/api/upload' | '/app' | '/login' | '/manager' @@ -355,6 +366,7 @@ export interface FileRouteTypes { | '/app' | '/login' | '/manager' + | '/api/upload' | '/app/' | '/login/' | '/manager/' @@ -388,6 +400,7 @@ export interface RootRouteChildren { AppRouteRoute: typeof AppRouteRouteWithChildren LoginRouteRoute: typeof LoginRouteRouteWithChildren ManagerRouteRoute: typeof ManagerRouteRouteWithChildren + ApiUploadRoute: typeof ApiUploadRoute ApiAuthSplatRoute: typeof ApiAuthSplatRoute ApiOpenapiAppRoute: typeof ApiOpenapiAppRouteWithChildren ApiOpenapiAuthRoute: typeof ApiOpenapiAuthRouteWithChildren @@ -447,6 +460,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AppIndexRouteImport parentRoute: typeof AppRouteRoute } + '/api/upload': { + id: '/api/upload' + path: '/api/upload' + fullPath: '/api/upload' + preLoaderRoute: typeof ApiUploadRouteImport + parentRoute: typeof rootRouteImport + } '/manager/users/': { id: '/manager/users/' path: '/users' @@ -706,6 +726,7 @@ const rootRouteChildren: RootRouteChildren = { AppRouteRoute: AppRouteRouteWithChildren, LoginRouteRoute: LoginRouteRouteWithChildren, ManagerRouteRoute: ManagerRouteRouteWithChildren, + ApiUploadRoute: ApiUploadRoute, ApiAuthSplatRoute: ApiAuthSplatRoute, ApiOpenapiAppRoute: ApiOpenapiAppRouteWithChildren, ApiOpenapiAuthRoute: ApiOpenapiAuthRouteWithChildren, diff --git a/src/routes/api/upload.ts b/src/routes/api/upload.ts new file mode 100644 index 000000000..0ec6bfbb9 --- /dev/null +++ b/src/routes/api/upload.ts @@ -0,0 +1,61 @@ +import { createFileRoute } from '@tanstack/react-router'; +import { + handleRequest, + RejectUpload, + route, + type Router, +} from 'better-upload/server'; + +import { s3client } from '@/lib/s3'; + +import { envServer } from '@/env/server'; +import { auth } from '@/server/auth'; + +const router: Router = { + client: s3client, + bucketName: envServer.S3_BUCKET_NAME, + routes: { + bookCover: route({ + fileTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'], + maxFileSize: 1024 * 1024 * 100, // 100Mb + onBeforeUpload: async ({ req, file }) => { + const session = await auth.api.getSession({ headers: req.headers }); + if (!session?.user) { + throw new RejectUpload('manager.uploadError.NOT_AUTHENTICATED'); + } + + // Only admins should be able to update book covers + const canUpdateBookCover = await auth.api.userHasPermission({ + body: { + userId: session.user.id, + permissions: { + book: ['create', 'update'], + }, + role: 'admin', + }, + }); + + if (!canUpdateBookCover.success) { + throw new RejectUpload('manager.uploadError.UNAUTHORIZED'); + } + + // normalize file extension from detected mimetype + const fileExtension = file.type.split('/').at(-1) as string; + return { + // I think it is a good idea to create a random file id as it impersonate the file name (which can contains sensitive data :/ ?) + objectInfo: { + key: `books/${crypto.randomUUID()}.${fileExtension}`, + }, + }; + }, + }), + }, +}; + +export const Route = createFileRoute('/api/upload')({ + server: { + handlers: { + POST: ({ request }) => handleRequest(request, router), + }, + }, +}); diff --git a/src/server/routers/book.ts b/src/server/routers/book.ts index a6bbd722f..03e6e6876 100644 --- a/src/server/routers/book.ts +++ b/src/server/routers/book.ts @@ -174,6 +174,7 @@ export default { author: input.author, genreId: input.genreId, publisher: input.publisher ?? null, + coverId: input.coverId ?? null, }, }); } catch (error: unknown) { From c33ee7977c6856f042f007bd5286098053b81607 Mon Sep 17 00:00:00 2001 From: Renan Decamps Date: Thu, 6 Nov 2025 12:02:34 +0100 Subject: [PATCH 2/8] feat: add missing error messages and translations --- .env.example | 2 +- src/features/book/manager/form-book-cover.tsx | 14 ++++++++++++-- src/locales/ar/book.json | 13 +++++++++++++ src/locales/en/book.json | 19 ++++++++++++++----- src/locales/fr/book.json | 13 +++++++++++++ src/locales/sw/book.json | 13 +++++++++++++ src/routes/api/upload.ts | 9 +++++++-- 7 files changed, 73 insertions(+), 10 deletions(-) diff --git a/.env.example b/.env.example index 5737d9402..4f4962275 100644 --- a/.env.example +++ b/.env.example @@ -19,7 +19,7 @@ S3_SECRET_ACCESS_KEY="startui-secret-key" S3_REGION="default" # PUBLIC CONFIG -VITE_S3_BUCKET_PUBLIC_URL="http://127.0.0.1:${DOCKER_MINIO_API_PORT}/${S3_BUCKET_NAME}" +VITE_S3_BUCKET_PUBLIC_URL="${S3_ENDPOINT}/${S3_BUCKET_NAME}" VITE_BASE_URL="http://localhost:${VITE_PORT}" # Use the following environment variables to show the environment name. VITE_ENV_NAME="LOCAL" diff --git a/src/features/book/manager/form-book-cover.tsx b/src/features/book/manager/form-book-cover.tsx index b551e4620..f19c1ddfc 100644 --- a/src/features/book/manager/form-book-cover.tsx +++ b/src/features/book/manager/form-book-cover.tsx @@ -1,6 +1,8 @@ import { useQuery } from '@tanstack/react-query'; import { useUploadFile } from 'better-upload/client'; import { useFormContext, useWatch } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'sonner'; import { orpc } from '@/lib/orpc/client'; @@ -8,6 +10,7 @@ import { BookCover } from '@/features/book/book-cover'; import { FormFieldsBook } from '@/features/book/schema'; export const FormBookCover = () => { + const { t } = useTranslation(['book']); const form = useFormContext(); const genresQuery = useQuery(orpc.genre.getAll.queryOptions()); const title = useWatch({ @@ -34,10 +37,17 @@ export const FormBookCover = () => { onUploadComplete: ({ file }) => { form.setValue('coverId', file.objectKey); }, + onError: (error) => { + if (error.type === 'rejected') { + // In this specific case, error should be a translated message + // because rejected are custom errors thrown by the developper + toast.error(error.message); + } else { + toast.error(t(`book:manager.uploadErrors.${error.type}`)); + } + }, }); - // [TODO] Handle upload errors - return (
); diff --git a/src/locales/ar/book.json b/src/locales/ar/book.json index cd904d7ae..d015ee232 100644 --- a/src/locales/ar/book.json +++ b/src/locales/ar/book.json @@ -59,6 +59,7 @@ }, "updateError": "فشل في تحديث الكتاب" }, + "uploadCover": "رفع الغلاف", "uploadErrors": { "NOT_AUTHENTICATED": "تحتاج إلى تسجيل الدخول لتتمكن من رفع غلاف جديد", "UNAUTHORIZED": "غير مسموح لك بتغيير غلاف الكتاب", diff --git a/src/locales/en/book.json b/src/locales/en/book.json index 6eeeeadf2..cb86885d3 100644 --- a/src/locales/en/book.json +++ b/src/locales/en/book.json @@ -59,6 +59,7 @@ }, "updateError": "Failed to update a book" }, + "uploadCover": "Upload Cover", "uploadErrors": { "NOT_AUTHENTICATED": "You need to be authenticated to be able to upload a new cover", "UNAUTHORIZED": "You are not allowed to change book cover", diff --git a/src/locales/fr/book.json b/src/locales/fr/book.json index 066509bd8..6c96c0106 100644 --- a/src/locales/fr/book.json +++ b/src/locales/fr/book.json @@ -59,6 +59,7 @@ }, "updateError": "Échec de la modification du livre" }, + "uploadCover": "Modifier", "uploadErrors": { "NOT_AUTHENTICATED": "Vous devez être authentifié pour pouvoir télécharger une nouvelle couverture", "UNAUTHORIZED": "Vous n'êtes pas autorisé à changer la couverture du livre", diff --git a/src/locales/sw/book.json b/src/locales/sw/book.json index 20950bfdc..edf82c013 100644 --- a/src/locales/sw/book.json +++ b/src/locales/sw/book.json @@ -59,6 +59,7 @@ }, "updateError": "Imeshindikana kusasisha kitabu" }, + "uploadCover": "Pakia Jalada", "uploadErrors": { "NOT_AUTHENTICATED": "Unahitaji kuwa umeingia ili uweze kupakia jalada jipya", "UNAUTHORIZED": "Hauruhusiwi kubadilisha jalada la kitabu", From 512fe7606db992e19180776a4041d9bc37abc37f Mon Sep 17 00:00:00 2001 From: Renan Decamps Date: Fri, 7 Nov 2025 09:03:28 +0100 Subject: [PATCH 4/8] fix: remove unused import --- src/features/book/manager/form-book-cover.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/features/book/manager/form-book-cover.tsx b/src/features/book/manager/form-book-cover.tsx index 49d605664..303f9e426 100644 --- a/src/features/book/manager/form-book-cover.tsx +++ b/src/features/book/manager/form-book-cover.tsx @@ -7,8 +7,6 @@ import { toast } from 'sonner'; import { orpc } from '@/lib/orpc/client'; -import { Button } from '@/components/ui/button'; - import { BookCover } from '@/features/book/book-cover'; import { FormFieldsBook } from '@/features/book/schema'; From 2de90ef8da53118be51a1bbd9d5c85058f151d99 Mon Sep 17 00:00:00 2001 From: Renan Decamps Date: Wed, 12 Nov 2025 18:08:03 +0100 Subject: [PATCH 5/8] fix: uplaod button and add missing examplee --- src/components/ui/upload-button.stories.tsx | 135 ++++++++++++++++++ src/components/ui/upload-button.tsx | 94 ++++++++++++ src/features/book/book-cover.tsx | 22 ++- src/features/book/manager/form-book-cover.tsx | 83 ++++++----- src/routes/api/upload.ts | 82 ++++++----- 5 files changed, 331 insertions(+), 85 deletions(-) create mode 100644 src/components/ui/upload-button.stories.tsx create mode 100644 src/components/ui/upload-button.tsx diff --git a/src/components/ui/upload-button.stories.tsx b/src/components/ui/upload-button.stories.tsx new file mode 100644 index 000000000..fc2a14df5 --- /dev/null +++ b/src/components/ui/upload-button.stories.tsx @@ -0,0 +1,135 @@ +import type { Meta } from '@storybook/react-vite'; +import { useUploadFile } from 'better-upload/client'; +import { UploadIcon } from 'lucide-react'; +import { useForm } from 'react-hook-form'; + +import { + Form, + FormField, + FormFieldController, + FormFieldError, +} from '@/components/form'; +import { UploadButton } from '@/components/ui/upload-button'; + +import { BookCover } from '@/features/book/book-cover'; + +export default { + title: 'Upload Button', +} satisfies Meta; + +export const Default = () => { + const { control } = useUploadFile({ route: 'bookCover' }); + + return ( + console.log('uploaded file', file)} + /> + ); +}; + +export const WithChildren = () => { + const { control } = useUploadFile({ route: 'bookCover' }); + + return ( +
+ console.log('uploaded file', file)} + > + + Upload a new file + + + console.log('uploaded file', file)} + > + Upload a new file + + + + console.log('uploaded file', file)} + > + Upload a new file + +
+ ); +}; + +export const Disabled = () => { + const { control } = useUploadFile({ route: 'bookCover' }); + + return ( +
+ console.log('uploaded file', file)} + > + + Upload a new file + + + console.log('uploaded file', file)} + > + Upload a new file + + +
+ ); +}; + +export const RealWorldUseCase = () => { + const form = useForm({ + defaultValues: { + coverId: '', + }, + }); + const { control, uploadedFile } = useUploadFile({ route: 'bookCover' }); + + return ( +
+ + { + return ( +
+
+ Upload cover + + + +
+ +
+ ); + }} + /> +
+
+ ); +}; diff --git a/src/components/ui/upload-button.tsx b/src/components/ui/upload-button.tsx new file mode 100644 index 000000000..571074285 --- /dev/null +++ b/src/components/ui/upload-button.tsx @@ -0,0 +1,94 @@ +import { + type FileUploadInfo, + type UploadHookControl, +} from 'better-upload/client'; +import { UploadIcon } from 'lucide-react'; +import { + type ChangeEvent, + type ComponentProps, + useEffect, + useId, + useRef, +} from 'react'; + +import { cn } from '@/lib/tailwind/utils'; + +import { Button } from '@/components/ui/button'; + +export type UploadButtonProps = { + control: UploadHookControl; + /** + * Called only if the file was uploaded successfully. + */ + onChange?: (file: FileUploadInfo<'complete'>) => void; + inputProps?: ComponentProps<'input'>; +} & Omit, 'onChange'>; + +/** + * Upload button that should be used with useUploadFile() better-upload hook. + */ +export const UploadButton = ({ + children, + inputProps, + control, + onChange, + disabled, + ...rest +}: UploadButtonProps) => { + const innerId = useId(); + + const handleFileChange = (event: ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + control.upload(file); + } + }; + + const inputRef = useRef(null); + + useEffect(() => { + if (!control.isSuccess || !control.uploadedFile) return; + // if success, it means the file was successfully uploaded + onChange?.(control.uploadedFile); + }, [control.isSuccess, control.uploadedFile, onChange]); + + return ( + <> + + { + handleFileChange(onChangeEvent); + inputProps?.onChange?.(onChangeEvent); + }} + /> + + ); +}; diff --git a/src/features/book/book-cover.tsx b/src/features/book/book-cover.tsx index 90697100b..490bb00c4 100644 --- a/src/features/book/book-cover.tsx +++ b/src/features/book/book-cover.tsx @@ -1,5 +1,4 @@ import { useTranslation } from 'react-i18next'; -import { match, P } from 'ts-pattern'; import { cn } from '@/lib/tailwind/utils'; @@ -12,25 +11,24 @@ export const BookCover = (props: { className?: string; }) => { const { t } = useTranslation(['book']); - console.log(props.book); - const style = match(props.book.coverId || null) - .with(P.nullish, () => ({ - backgroundColor: props.book.genre?.color ?? '#333', - })) - .with(P._, (coverId) => ({ - backgroundImage: `url(${envClient.VITE_S3_BUCKET_PUBLIC_URL}/${coverId})`, - })) - .exhaustive(); return (
+ {!!props.book.coverId && ( + + )}
diff --git a/src/features/book/manager/form-book-cover.tsx b/src/features/book/manager/form-book-cover.tsx index 303f9e426..a4a2d2ef1 100644 --- a/src/features/book/manager/form-book-cover.tsx +++ b/src/features/book/manager/form-book-cover.tsx @@ -1,12 +1,17 @@ import { useQuery } from '@tanstack/react-query'; import { useUploadFile } from 'better-upload/client'; -import { Upload } from 'lucide-react'; import { useFormContext, useWatch } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { toast } from 'sonner'; import { orpc } from '@/lib/orpc/client'; +import { + FormField, + FormFieldController, + FormFieldError, +} from '@/components/form'; +import { UploadButton } from '@/components/ui/upload-button'; + import { BookCover } from '@/features/book/book-cover'; import { FormFieldsBook } from '@/features/book/schema'; @@ -33,52 +38,62 @@ export const FormBookCover = () => { control: form.control, }); - const { upload, uploadedFile } = useUploadFile({ + const { uploadedFile, control } = useUploadFile({ route: 'bookCover', onUploadComplete: ({ file }) => { + form.clearErrors('coverId'); form.setValue('coverId', file.objectKey); }, onError: (error) => { if (error.type === 'rejected') { // In this specific case, error should be a translated message // because rejected are custom errors thrown by the developper - toast.error(error.message); + form.setError('coverId', { + type: 'custom', + message: error.message, + }); } else { - toast.error(t(`book:manager.uploadErrors.${error.type}`)); + form.setError('coverId', { + type: 'custom', + message: t(`book:manager.uploadErrors.${error.type}`), + }); } }, }); return ( -
-
+ + + ); + }} + /> + ); }; diff --git a/src/routes/api/upload.ts b/src/routes/api/upload.ts index 72b0d0f4c..55026e8d4 100644 --- a/src/routes/api/upload.ts +++ b/src/routes/api/upload.ts @@ -5,6 +5,7 @@ import { route, type Router, } from 'better-upload/server'; +import { mapValues } from 'remeda'; import i18n from '@/lib/i18n'; import { s3client } from '@/lib/s3'; @@ -12,49 +13,52 @@ import { s3client } from '@/lib/s3'; import { envServer } from '@/env/server'; import { auth } from '@/server/auth'; -const router: Router = { - client: s3client, - bucketName: envServer.S3_BUCKET_NAME, - routes: { - bookCover: route({ - fileTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'], - maxFileSize: 1024 * 1024 * 100, // 100Mb - onBeforeUpload: async ({ req, file }) => { - const session = await auth.api.getSession({ headers: req.headers }); - if (!session?.user) { - throw new RejectUpload( - i18n.t('book:manager.uploadErrors.NOT_AUTHENTICATED') - ); - } +export const uploadRoutes = { + bookCover: route({ + fileTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'], + maxFileSize: 1024 * 1024 * 100, // 100Mb + onBeforeUpload: async ({ req, file }) => { + const session = await auth.api.getSession({ headers: req.headers }); + if (!session?.user) { + throw new RejectUpload( + i18n.t('book:manager.uploadErrors.NOT_AUTHENTICATED') + ); + } - // Only admins should be able to update book covers - const canUpdateBookCover = await auth.api.userHasPermission({ - body: { - userId: session.user.id, - permissions: { - book: ['create', 'update'], - }, - role: 'admin', + // Only admins should be able to update book covers + const canUpdateBookCover = await auth.api.userHasPermission({ + body: { + userId: session.user.id, + permissions: { + book: ['create', 'update'], }, - }); + role: 'admin', + }, + }); - if (!canUpdateBookCover.success) { - throw new RejectUpload( - i18n.t('book:manager.uploadErrors.UNAUTHORIZED') - ); - } + if (!canUpdateBookCover.success) { + throw new RejectUpload( + i18n.t('book:manager.uploadErrors.UNAUTHORIZED') + ); + } - // normalize file extension from detected mimetype - const fileExtension = file.type.split('/').at(-1) as string; - return { - // I think it is a good idea to create a random file id as it impersonate the file name (which can contains sensitive data :/ ?) - objectInfo: { - key: `books/${crypto.randomUUID()}.${fileExtension}`, - }, - }; - }, - }), - }, + // normalize file extension from detected mimetype + const fileExtension = file.type.split('/').at(-1) as string; + return { + // I think it is a good idea to create a random file id as it impersonate the file name (which can contains sensitive data :/ ?) + objectInfo: { + key: `books/${crypto.randomUUID()}.${fileExtension}`, + }, + }; + }, + }), +} as const; +export const uploadRoutesName = mapValues(uploadRoutes, (_, key) => key); + +const router: Router = { + client: s3client, + bucketName: envServer.S3_BUCKET_NAME, + routes: uploadRoutes, }; export const Route = createFileRoute('/api/upload')({ From 07799489ae944ed54332e72dcc2206b06aa30830 Mon Sep 17 00:00:00 2001 From: Renan Decamps Date: Fri, 14 Nov 2025 15:27:24 +0100 Subject: [PATCH 6/8] feat: clean upload button component --- package.json | 4 +- pnpm-lock.yaml | 1111 +---------------- src/components/ui/upload-button.stories.tsx | 88 +- src/components/ui/upload-button.tsx | 95 +- src/env/client.ts | 2 +- src/features/book/book-cover.tsx | 1 + src/features/book/manager/form-book-cover.tsx | 39 +- src/features/book/manager/page-book-new.tsx | 5 + .../book/manager/page-book-update.tsx | 4 + src/lib/s3/index.ts | 13 +- src/routes/api/upload.ts | 95 +- src/server/routers/book.ts | 1 + 12 files changed, 194 insertions(+), 1264 deletions(-) diff --git a/package.json b/package.json index 82a742c5f..00e19abfc 100644 --- a/package.json +++ b/package.json @@ -42,10 +42,11 @@ "db:seed": "dotenv -- cross-env node ./run-jiti ./prisma/seed/index.ts" }, "dependencies": { - "@aws-sdk/client-s3": "3.922.0", "@base-ui-components/react": "1.0.0-beta.1", "@bearstudio/ui-state": "1.0.2", "@better-auth/expo": "1.3.27", + "@better-upload/client": "3.0.2", + "@better-upload/server": "3.0.2", "@fontsource-variable/inter": "5.2.8", "@headlessui/react": "2.2.9", "@hookform/resolvers": "5.2.2", @@ -68,7 +69,6 @@ "@tanstack/zod-adapter": "1.132.47", "@uidotdev/usehooks": "2.4.1", "better-auth": "1.3.27", - "better-upload": "2.0.3", "boring-avatars": "2.0.4", "class-variance-authority": "0.7.1", "clsx": "2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3489edcbf..7bbc1c5f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - '@aws-sdk/client-s3': - specifier: 3.922.0 - version: 3.922.0 '@base-ui-components/react': specifier: 1.0.0-beta.1 version: 1.0.0-beta.1(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -20,6 +17,12 @@ importers: '@better-auth/expo': specifier: 1.3.27 version: 1.3.27(45a7aa97bc666058466a19360edccb13) + '@better-upload/client': + specifier: 3.0.2 + version: 3.0.2(react@19.2.0) + '@better-upload/server': + specifier: 3.0.2 + version: 3.0.2 '@fontsource-variable/inter': specifier: 5.2.8 version: 5.2.8 @@ -86,9 +89,6 @@ importers: better-auth: specifier: 1.3.27 version: 1.3.27(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(solid-js@1.9.9) - better-upload: - specifier: 2.0.3 - version: 2.0.3(@aws-sdk/client-s3@3.922.0)(react@19.2.0) boring-avatars: specifier: 2.0.4 version: 2.0.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -124,7 +124,7 @@ importers: version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) nitro: specifier: npm:nitro-nightly@3.0.1-20251023-125324-a6f9b591 - version: nitro-nightly@3.0.1-20251023-125324-a6f9b591(chokidar@4.0.3)(ioredis@5.8.0)(vite@7.1.11(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.19.3)(yaml@2.8.1)) + version: nitro-nightly@3.0.1-20251023-125324-a6f9b591(aws4fetch@1.0.20)(chokidar@4.0.3)(ioredis@5.8.0)(vite@7.1.11(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.19.3)(yaml@2.8.1)) nodemailer: specifier: 7.0.9 version: 7.0.9 @@ -352,16 +352,6 @@ packages: '@asamuzakjp/css-color@2.8.3': resolution: {integrity: sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==} - '@aws-crypto/crc32@5.2.0': - resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} - engines: {node: '>=16.0.0'} - - '@aws-crypto/crc32c@5.2.0': - resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} - - '@aws-crypto/sha1-browser@5.2.0': - resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} - '@aws-crypto/sha256-browser@5.2.0': resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} @@ -375,10 +365,6 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.922.0': - resolution: {integrity: sha512-SZRaZUUAHCWfEyBf4SRSPd29ko4uFoJpfd0E/w1meE68XhFB52FTtz/71UqYcwqZmN+s7oUNFFZT+DE/dnQSEA==} - engines: {node: '>=18.0.0'} - '@aws-sdk/client-sesv2@3.901.0': resolution: {integrity: sha512-xCS2qZlvgbXKZbJW8XgU8OEAL7BJyVqJ5yODOQxa1TJFZ/+wEhik9XZtULjNnQqa29sJDpPltuSDG1aDG2OUxQ==} engines: {node: '>=18.0.0'} @@ -387,170 +373,74 @@ packages: resolution: {integrity: sha512-sGyDjjkJ7ppaE+bAKL/Q5IvVCxtoyBIzN+7+hWTS/mUxWJ9EOq9238IqmVIIK6sYNIzEf9yhobfMARasPYVTNg==} engines: {node: '>=18.0.0'} - '@aws-sdk/client-sso@3.922.0': - resolution: {integrity: sha512-jdHs7uy7cSpiMvrxhYmqHyJxgK7hyqw4plG8OQ4YTBpq0SbfAxdoOuOkwJ1IVUUQho4otR1xYYjiX/8e8J8qwQ==} - engines: {node: '>=18.0.0'} - '@aws-sdk/core@3.901.0': resolution: {integrity: sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==} engines: {node: '>=18.0.0'} - '@aws-sdk/core@3.922.0': - resolution: {integrity: sha512-EvfP4cqJfpO3L2v5vkIlTkMesPtRwWlMfsaW6Tpfm7iYfBOuTi6jx60pMDMTyJNVfh6cGmXwh/kj1jQdR+w99Q==} - engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-env@3.901.0': resolution: {integrity: sha512-5hAdVl3tBuARh3zX5MLJ1P/d+Kr5kXtDU3xm1pxUEF4xt2XkEEpwiX5fbkNkz2rbh3BCt2gOHsAbh6b3M7n+DA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-env@3.922.0': - resolution: {integrity: sha512-WikGQpKkROJSK3D3E7odPjZ8tU7WJp5/TgGdRuZw3izsHUeH48xMv6IznafpRTmvHcjAbDQj4U3CJZNAzOK/OQ==} - engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-http@3.901.0': resolution: {integrity: sha512-Ggr7+0M6QZEsrqRkK7iyJLf4LkIAacAxHz9c4dm9hnDdU7vqrlJm6g73IxMJXWN1bIV7IxfpzB11DsRrB/oNjQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-http@3.922.0': - resolution: {integrity: sha512-i72DgHMK7ydAEqdzU0Duqh60Q8W59EZmRJ73y0Y5oFmNOqnYsAI+UXyOoCsubp+Dkr6+yOwAn1gPt1XGE9Aowg==} - engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-ini@3.901.0': resolution: {integrity: sha512-zxadcDS0hNJgv8n4hFYJNOXyfjaNE1vvqIiF/JzZSQpSSYXzCd+WxXef5bQh+W3giDtRUmkvP5JLbamEFjZKyw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-ini@3.922.0': - resolution: {integrity: sha512-bVF+pI5UCLNkvbiZr/t2fgTtv84s8FCdOGAPxQiQcw5qOZywNuuCCY3wIIchmQr6GJr8YFkEp5LgDCac5EC5aQ==} - engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-node@3.901.0': resolution: {integrity: sha512-dPuFzMF7L1s/lQyT3wDxqLe82PyTH+5o1jdfseTEln64LJMl0ZMWaKX/C1UFNDxaTd35Cgt1bDbjjAWHMiKSFQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-node@3.922.0': - resolution: {integrity: sha512-agCwaD6mBihToHkjycL8ObIS2XOnWypWZZWhJSoWyHwFrhEKz1zGvgylK9Dc711oUfU+zU6J8e0JPKNJMNb3BQ==} - engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-process@3.901.0': resolution: {integrity: sha512-/IWgmgM3Cl1wTdJA5HqKMAojxLkYchh5kDuphApxKhupLu6Pu0JBOHU8A5GGeFvOycyaVwosod6zDduINZxe+A==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-process@3.922.0': - resolution: {integrity: sha512-1DZOYezT6okslpvMW7oA2q+y17CJd4fxjNFH0jtThfswdh9CtG62+wxenqO+NExttq0UMaKisrkZiVrYQBTShw==} - engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-sso@3.901.0': resolution: {integrity: sha512-SjmqZQHmqFSET7+6xcZgtH7yEyh5q53LN87GqwYlJZ6KJ5oNw11acUNEhUOL1xTSJEvaWqwTIkS2zqrzLcM9bw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-sso@3.922.0': - resolution: {integrity: sha512-nbD3G3hShTYxLCkKMqLkLPtKwAAfxdY/k9jHtZmVBFXek2T6tQrqZHKxlAu+fd23Ga4/Aik7DLQQx1RA1a5ipg==} - engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-web-identity@3.901.0': resolution: {integrity: sha512-NYjy/6NLxH9m01+pfpB4ql8QgAorJcu8tw69kzHwUd/ql6wUDTbC7HcXqtKlIwWjzjgj2BKL7j6SyFapgCuafA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-web-identity@3.922.0': - resolution: {integrity: sha512-wjGIhgMHGGQfQTdFaJphNOKyAL8wZs6znJdHADPVURmgR+EWLyN/0fDO1u7wx8xaLMZpbHIFWBEvf9TritR/cQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-bucket-endpoint@3.922.0': - resolution: {integrity: sha512-Dpr2YeOaLFqt3q1hocwBesynE3x8/dXZqXZRuzSX/9/VQcwYBFChHAm4mTAl4zuvArtDbLrwzWSxmOWYZGtq5w==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-expect-continue@3.922.0': - resolution: {integrity: sha512-xmnLWMtmHJHJBupSWMUEW1gyxuRIeQ1Ov2xa8Tqq77fPr4Ft2AluEwiDMaZIMHoAvpxWKEEt9Si59Li7GIA+bQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-flexible-checksums@3.922.0': - resolution: {integrity: sha512-G363np7YcJhf+gBucskdv8cOTbs2TRwocEzRupuqDIooGDlLBlfJrvwehdgtWR8l53yjJR3zcHvGrVPTe2h8Nw==} - engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-host-header@3.901.0': resolution: {integrity: sha512-yWX7GvRmqBtbNnUW7qbre3GvZmyYwU0WHefpZzDTYDoNgatuYq6LgUIQ+z5C04/kCRoFkAFrHag8a3BXqFzq5A==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-host-header@3.922.0': - resolution: {integrity: sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-location-constraint@3.922.0': - resolution: {integrity: sha512-T4iqd7WQ2DDjCH/0s50mnhdoX+IJns83ZE+3zj9IDlpU0N2aq8R91IG890qTfYkUEdP9yRm0xir/CNed+v6Dew==} - engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-logger@3.901.0': resolution: {integrity: sha512-UoHebjE7el/tfRo8/CQTj91oNUm+5Heus5/a4ECdmWaSCHCS/hXTsU3PTTHAY67oAQR8wBLFPfp3mMvXjB+L2A==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-logger@3.922.0': - resolution: {integrity: sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg==} - engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-recursion-detection@3.901.0': resolution: {integrity: sha512-Wd2t8qa/4OL0v/oDpCHHYkgsXJr8/ttCxrvCKAt0H1zZe2LlRhY9gpDVKqdertfHrHDj786fOvEQA28G1L75Dg==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-recursion-detection@3.922.0': - resolution: {integrity: sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA==} - engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-sdk-s3@3.901.0': resolution: {integrity: sha512-prgjVC3fDT2VIlmQPiw/cLee8r4frTam9GILRUVQyDdNtshNwV3MiaSCLzzQJjKJlLgnBLNUHJCSmvUVtg+3iA==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-sdk-s3@3.922.0': - resolution: {integrity: sha512-ygg8lME1oFAbsH42ed2wtGqfHLoT5irgx6VC4X98j79fV1qXEwwwbqMsAiMQ/HJehpjqAFRVsHox3MHLN48Z5A==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-ssec@3.922.0': - resolution: {integrity: sha512-eHvSJZTSRJO+/tjjGD6ocnPc8q9o3m26+qbwQTu/4V6yOJQ1q+xkDZNqwJQphL+CodYaQ7uljp8g1Ji/AN3D9w==} - engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-user-agent@3.901.0': resolution: {integrity: sha512-Zby4F03fvD9xAgXGPywyk4bC1jCbnyubMEYChLYohD+x20ULQCf+AimF/Btn7YL+hBpzh1+RmqmvZcx+RgwgNQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-user-agent@3.922.0': - resolution: {integrity: sha512-N4Qx/9KP3oVQBJOrSghhz8iZFtUC2NNeSZt88hpPhbqAEAtuX8aD8OzVcpnAtrwWqy82Yd2YTxlkqMGkgqnBsQ==} - engines: {node: '>=18.0.0'} - '@aws-sdk/nested-clients@3.901.0': resolution: {integrity: sha512-feAAAMsVwctk2Tms40ONybvpfJPLCmSdI+G+OTrNpizkGLNl6ik2Ng2RzxY6UqOfN8abqKP/DOUj1qYDRDG8ag==} engines: {node: '>=18.0.0'} - '@aws-sdk/nested-clients@3.922.0': - resolution: {integrity: sha512-uYvKCF1TGh/MuJ4TMqmUM0Csuao02HawcseG4LUDyxdUsd/EFuxalWq1Cx4fKZQ2K8F504efZBjctMAMNY+l7A==} - engines: {node: '>=18.0.0'} - '@aws-sdk/region-config-resolver@3.901.0': resolution: {integrity: sha512-7F0N888qVLHo4CSQOsnkZ4QAp8uHLKJ4v3u09Ly5k4AEStrSlFpckTPyUx6elwGL+fxGjNE2aakK8vEgzzCV0A==} engines: {node: '>=18.0.0'} - '@aws-sdk/region-config-resolver@3.922.0': - resolution: {integrity: sha512-44Y/rNNwhngR2KHp6gkx//TOr56/hx6s4l+XLjOqH7EBCHL7XhnrT1y92L+DLiroVr1tCSmO8eHQwBv0Y2+mvw==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/s3-request-presigner@3.922.0': - resolution: {integrity: sha512-x/WZXOMAN10X/hbjHnaXjtU34RmV3/eJMiHoJsohquSgz8+pfRN1DeK65oa/XPoKCMPfV31RfHSzCduligHfsQ==} - engines: {node: '>=18.0.0'} - '@aws-sdk/signature-v4-multi-region@3.901.0': resolution: {integrity: sha512-2IWxbll/pRucp1WQkHi2W5E2SVPGBvk4Is923H7gpNksbVFws18ItjMM8ZpGm44cJEoy1zR5gjhLFklatpuoOw==} engines: {node: '>=18.0.0'} - '@aws-sdk/signature-v4-multi-region@3.922.0': - resolution: {integrity: sha512-mmsgEEL5pE+A7gFYiJMDBCLVciaXq4EFI5iAP7bPpnHvOplnNOYxVy2IreKMllGvrfjVyLnwxzZYlo5zZ65FWg==} - engines: {node: '>=18.0.0'} - '@aws-sdk/token-providers@3.901.0': resolution: {integrity: sha512-pJEr1Ggbc/uVTDqp9IbNu9hdr0eQf3yZix3s4Nnyvmg4xmJSGAlbPC9LrNr5u3CDZoc8Z9CuLrvbP4MwYquNpQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/token-providers@3.922.0': - resolution: {integrity: sha512-/inmPnjZE0ZBE16zaCowAvouSx05FJ7p6BQYuzlJ8vxEU0sS0Hf8fvhuiRnN9V9eDUPIBY+/5EjbMWygXL4wlQ==} - engines: {node: '>=18.0.0'} - '@aws-sdk/types@3.901.0': resolution: {integrity: sha512-FfEM25hLEs4LoXsLXQ/q6X6L4JmKkKkbVFpKD4mwfVHtRVQG6QxJiCPcrkcPISquiy6esbwK2eh64TWbiD60cg==} engines: {node: '>=18.0.0'} @@ -567,14 +457,6 @@ packages: resolution: {integrity: sha512-5nZP3hGA8FHEtKvEQf4Aww5QZOkjLW1Z+NixSd+0XKfHvA39Ah5sZboScjLx0C9kti/K3OGW1RCx5K9Zc3bZqg==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-endpoints@3.922.0': - resolution: {integrity: sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/util-format-url@3.922.0': - resolution: {integrity: sha512-UYLWPvZEd6TYilNkrQrIeXh2bXZsY3ighYErSEjD24f3JQhg0XdXoR/QHIE8licHu2qFrTRM6yi9LH1GY6X0cg==} - engines: {node: '>=18.0.0'} - '@aws-sdk/util-locate-window@3.893.0': resolution: {integrity: sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==} engines: {node: '>=18.0.0'} @@ -582,9 +464,6 @@ packages: '@aws-sdk/util-user-agent-browser@3.901.0': resolution: {integrity: sha512-Ntb6V/WFI21Ed4PDgL/8NSfoZQQf9xzrwNgiwvnxgAl/KvAvRBgQtqj5gHsDX8Nj2YmJuVoHfH9BGjL9VQ4WNg==} - '@aws-sdk/util-user-agent-browser@3.922.0': - resolution: {integrity: sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA==} - '@aws-sdk/util-user-agent-node@3.901.0': resolution: {integrity: sha512-l59KQP5TY7vPVUfEURc7P5BJKuNg1RSsAKBQW7LHLECXjLqDUbo2SMLrexLBEoArSt6E8QOrIN0C8z/0Xk0jYw==} engines: {node: '>=18.0.0'} @@ -594,31 +473,14 @@ packages: aws-crt: optional: true - '@aws-sdk/util-user-agent-node@3.922.0': - resolution: {integrity: sha512-NrPe/Rsr5kcGunkog0eBV+bY0inkRELsD2SacC4lQZvZiXf8VJ2Y7j+Yq1tB+h+FPLsdt3v9wItIvDf/laAm0Q==} - engines: {node: '>=18.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - '@aws-sdk/xml-builder@3.901.0': resolution: {integrity: sha512-pxFCkuAP7Q94wMTNPAwi6hEtNrp/BdFf+HOrIEeFQsk4EoOmpKY3I6S+u6A9Wg295J80Kh74LqDWM22ux3z6Aw==} engines: {node: '>=18.0.0'} - '@aws-sdk/xml-builder@3.921.0': - resolution: {integrity: sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q==} - engines: {node: '>=18.0.0'} - '@aws/lambda-invoke-store@0.0.1': resolution: {integrity: sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw==} engines: {node: '>=18.0.0'} - '@aws/lambda-invoke-store@0.1.1': - resolution: {integrity: sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA==} - engines: {node: '>=18.0.0'} - '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} @@ -1221,6 +1083,14 @@ packages: '@better-fetch/fetch@1.1.18': resolution: {integrity: sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==} + '@better-upload/client@3.0.2': + resolution: {integrity: sha512-wNdRmee0/X55MK+TugZ6EvuSTN1IAowmNzRWm5aH7ymSZQmdWBCo0SS5mj7A0Fw65VYbr2EtLzwM1KoE5Mliyw==} + peerDependencies: + react: '*' + + '@better-upload/server@3.0.2': + resolution: {integrity: sha512-NNYAsVgjZvwXVtxRdrg6ARwGxAL6aNQof7UAdrxJrOJ9unNeZQplF1YyNt/BXYGLDDZ4I97E+cqfkaomF0RXwA==} + '@code-inspector/core@1.2.10': resolution: {integrity: sha512-xTkR4oBrTlRA/S2cXTuZLttCX6+wQgUpBpEK4Ad/e9KBIUIDRne5yoxuvrdy3xkTMkURS2V4SnCTzjFcu4OELQ==} @@ -3354,94 +3224,30 @@ packages: resolution: {integrity: sha512-PLUYa+SUKOEZtXFURBu/CNxlsxfaFGxSBPcStL13KpVeVWIfdezWyDqkz7iDLmwnxojXD0s5KzuB5HGHvt4Aeg==} engines: {node: '>=18.0.0'} - '@smithy/abort-controller@4.2.4': - resolution: {integrity: sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ==} - engines: {node: '>=18.0.0'} - - '@smithy/chunked-blob-reader-native@4.2.1': - resolution: {integrity: sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==} - engines: {node: '>=18.0.0'} - - '@smithy/chunked-blob-reader@5.2.0': - resolution: {integrity: sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==} - engines: {node: '>=18.0.0'} - '@smithy/config-resolver@4.3.0': resolution: {integrity: sha512-9oH+n8AVNiLPK/iK/agOsoWfrKZ3FGP3502tkksd6SRsKMYiu7AFX0YXo6YBADdsAj7C+G/aLKdsafIJHxuCkQ==} engines: {node: '>=18.0.0'} - '@smithy/config-resolver@4.4.2': - resolution: {integrity: sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw==} - engines: {node: '>=18.0.0'} - '@smithy/core@3.14.0': resolution: {integrity: sha512-XJ4z5FxvY/t0Dibms/+gLJrI5niRoY0BCmE02fwmPcRYFPI4KI876xaE79YGWIKnEslMbuQPsIEsoU/DXa0DoA==} engines: {node: '>=18.0.0'} - '@smithy/core@3.17.2': - resolution: {integrity: sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ==} - engines: {node: '>=18.0.0'} - '@smithy/credential-provider-imds@4.2.0': resolution: {integrity: sha512-SOhFVvFH4D5HJZytb0bLKxCrSnwcqPiNlrw+S4ZXjMnsC+o9JcUQzbZOEQcA8yv9wJFNhfsUiIUKiEnYL68Big==} engines: {node: '>=18.0.0'} - '@smithy/credential-provider-imds@4.2.4': - resolution: {integrity: sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-codec@4.2.4': - resolution: {integrity: sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-browser@4.2.4': - resolution: {integrity: sha512-d5T7ZS3J/r8P/PDjgmCcutmNxnSRvPH1U6iHeXjzI50sMr78GLmFcrczLw33Ap92oEKqa4CLrkAPeSSOqvGdUA==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-config-resolver@4.3.4': - resolution: {integrity: sha512-lxfDT0UuSc1HqltOGsTEAlZ6H29gpfDSdEPTapD5G63RbnYToZ+ezjzdonCCH90j5tRRCw3aLXVbiZaBW3VRVg==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-node@4.2.4': - resolution: {integrity: sha512-TPhiGByWnYyzcpU/K3pO5V7QgtXYpE0NaJPEZBCa1Y5jlw5SjqzMSbFiLb+ZkJhqoQc0ImGyVINqnq1ze0ZRcQ==} - engines: {node: '>=18.0.0'} - - '@smithy/eventstream-serde-universal@4.2.4': - resolution: {integrity: sha512-GNI/IXaY/XBB1SkGBFmbW033uWA0tj085eCxYih0eccUe/PFR7+UBQv9HNDk2fD9TJu7UVsCWsH99TkpEPSOzQ==} - engines: {node: '>=18.0.0'} - '@smithy/fetch-http-handler@5.3.0': resolution: {integrity: sha512-BG3KSmsx9A//KyIfw+sqNmWFr1YBUr+TwpxFT7yPqAk0yyDh7oSNgzfNH7pS6OC099EGx2ltOULvumCFe8bcgw==} engines: {node: '>=18.0.0'} - '@smithy/fetch-http-handler@5.3.5': - resolution: {integrity: sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ==} - engines: {node: '>=18.0.0'} - - '@smithy/hash-blob-browser@4.2.5': - resolution: {integrity: sha512-kCdgjD2J50qAqycYx0imbkA9tPtyQr1i5GwbK/EOUkpBmJGSkJe4mRJm+0F65TUSvvui1HZ5FFGFCND7l8/3WQ==} - engines: {node: '>=18.0.0'} - '@smithy/hash-node@4.2.0': resolution: {integrity: sha512-ugv93gOhZGysTctZh9qdgng8B+xO0cj+zN0qAZ+Sgh7qTQGPOJbMdIuyP89KNfUyfAqFSNh5tMvC+h2uCpmTtA==} engines: {node: '>=18.0.0'} - '@smithy/hash-node@4.2.4': - resolution: {integrity: sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw==} - engines: {node: '>=18.0.0'} - - '@smithy/hash-stream-node@4.2.4': - resolution: {integrity: sha512-amuh2IJiyRfO5MV0X/YFlZMD6banjvjAwKdeJiYGUbId608x+oSNwv3vlyW2Gt6AGAgl3EYAuyYLGRX/xU8npQ==} - engines: {node: '>=18.0.0'} - '@smithy/invalid-dependency@4.2.0': resolution: {integrity: sha512-ZmK5X5fUPAbtvRcUPtk28aqIClVhbfcmfoS4M7UQBTnDdrNxhsrxYVv0ZEl5NaPSyExsPWqL4GsPlRvtlwg+2A==} engines: {node: '>=18.0.0'} - '@smithy/invalid-dependency@4.2.4': - resolution: {integrity: sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw==} - engines: {node: '>=18.0.0'} - '@smithy/is-array-buffer@2.2.0': resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} engines: {node: '>=14.0.0'} @@ -3450,130 +3256,66 @@ packages: resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} engines: {node: '>=18.0.0'} - '@smithy/md5-js@4.2.4': - resolution: {integrity: sha512-h7kzNWZuMe5bPnZwKxhVbY1gan5+TZ2c9JcVTHCygB14buVGOZxLl+oGfpY2p2Xm48SFqEWdghpvbBdmaz3ncQ==} - engines: {node: '>=18.0.0'} - '@smithy/middleware-content-length@4.2.0': resolution: {integrity: sha512-6ZAnwrXFecrA4kIDOcz6aLBhU5ih2is2NdcZtobBDSdSHtE9a+MThB5uqyK4XXesdOCvOcbCm2IGB95birTSOQ==} engines: {node: '>=18.0.0'} - '@smithy/middleware-content-length@4.2.4': - resolution: {integrity: sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow==} - engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.3.0': resolution: {integrity: sha512-jFVjuQeV8TkxaRlcCNg0GFVgg98tscsmIrIwRFeC74TIUyLE3jmY9xgc1WXrPQYRjQNK3aRoaIk6fhFRGOIoGw==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.3.6': - resolution: {integrity: sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w==} - engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.4.0': resolution: {integrity: sha512-yaVBR0vQnOnzex45zZ8ZrPzUnX73eUC8kVFaAAbn04+6V7lPtxn56vZEBBAhgS/eqD6Zm86o6sJs6FuQVoX5qg==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.4.6': - resolution: {integrity: sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA==} - engines: {node: '>=18.0.0'} - '@smithy/middleware-serde@4.2.0': resolution: {integrity: sha512-rpTQ7D65/EAbC6VydXlxjvbifTf4IH+sADKg6JmAvhkflJO2NvDeyU9qsWUNBelJiQFcXKejUHWRSdmpJmEmiw==} engines: {node: '>=18.0.0'} - '@smithy/middleware-serde@4.2.4': - resolution: {integrity: sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg==} - engines: {node: '>=18.0.0'} - '@smithy/middleware-stack@4.2.0': resolution: {integrity: sha512-G5CJ//eqRd9OARrQu9MK1H8fNm2sMtqFh6j8/rPozhEL+Dokpvi1Og+aCixTuwDAGZUkJPk6hJT5jchbk/WCyg==} engines: {node: '>=18.0.0'} - '@smithy/middleware-stack@4.2.4': - resolution: {integrity: sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA==} - engines: {node: '>=18.0.0'} - '@smithy/node-config-provider@4.3.0': resolution: {integrity: sha512-5QgHNuWdT9j9GwMPPJCKxy2KDxZ3E5l4M3/5TatSZrqYVoEiqQrDfAq8I6KWZw7RZOHtVtCzEPdYz7rHZixwcA==} engines: {node: '>=18.0.0'} - '@smithy/node-config-provider@4.3.4': - resolution: {integrity: sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw==} - engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.3.0': resolution: {integrity: sha512-RHZ/uWCmSNZ8cneoWEVsVwMZBKy/8123hEpm57vgGXA3Irf/Ja4v9TVshHK2ML5/IqzAZn0WhINHOP9xl+Qy6Q==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.4.4': - resolution: {integrity: sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA==} - engines: {node: '>=18.0.0'} - '@smithy/property-provider@4.2.0': resolution: {integrity: sha512-rV6wFre0BU6n/tx2Ztn5LdvEdNZ2FasQbPQmDOPfV9QQyDmsCkOAB0osQjotRCQg+nSKFmINhyda0D3AnjSBJw==} engines: {node: '>=18.0.0'} - '@smithy/property-provider@4.2.4': - resolution: {integrity: sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w==} - engines: {node: '>=18.0.0'} - '@smithy/protocol-http@5.3.0': resolution: {integrity: sha512-6POSYlmDnsLKb7r1D3SVm7RaYW6H1vcNcTWGWrF7s9+2noNYvUsm7E4tz5ZQ9HXPmKn6Hb67pBDRIjrT4w/d7Q==} engines: {node: '>=18.0.0'} - '@smithy/protocol-http@5.3.4': - resolution: {integrity: sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw==} - engines: {node: '>=18.0.0'} - '@smithy/querystring-builder@4.2.0': resolution: {integrity: sha512-Q4oFD0ZmI8yJkiPPeGUITZj++4HHYCW3pYBYfIobUCkYpI6mbkzmG1MAQQ3lJYYWj3iNqfzOenUZu+jqdPQ16A==} engines: {node: '>=18.0.0'} - '@smithy/querystring-builder@4.2.4': - resolution: {integrity: sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig==} - engines: {node: '>=18.0.0'} - '@smithy/querystring-parser@4.2.0': resolution: {integrity: sha512-BjATSNNyvVbQxOOlKse0b0pSezTWGMvA87SvoFoFlkRsKXVsN3bEtjCxvsNXJXfnAzlWFPaT9DmhWy1vn0sNEA==} engines: {node: '>=18.0.0'} - '@smithy/querystring-parser@4.2.4': - resolution: {integrity: sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ==} - engines: {node: '>=18.0.0'} - '@smithy/service-error-classification@4.2.0': resolution: {integrity: sha512-Ylv1ttUeKatpR0wEOMnHf1hXMktPUMObDClSWl2TpCVT4DwtJhCeighLzSLbgH3jr5pBNM0LDXT5yYxUvZ9WpA==} engines: {node: '>=18.0.0'} - '@smithy/service-error-classification@4.2.4': - resolution: {integrity: sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng==} - engines: {node: '>=18.0.0'} - '@smithy/shared-ini-file-loader@4.3.0': resolution: {integrity: sha512-VCUPPtNs+rKWlqqntX0CbVvWyjhmX30JCtzO+s5dlzzxrvSfRh5SY0yxnkirvc1c80vdKQttahL71a9EsdolSQ==} engines: {node: '>=18.0.0'} - '@smithy/shared-ini-file-loader@4.3.4': - resolution: {integrity: sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA==} - engines: {node: '>=18.0.0'} - '@smithy/signature-v4@5.3.0': resolution: {integrity: sha512-MKNyhXEs99xAZaFhm88h+3/V+tCRDQ+PrDzRqL0xdDpq4gjxcMmf5rBA3YXgqZqMZ/XwemZEurCBQMfxZOWq/g==} engines: {node: '>=18.0.0'} - '@smithy/signature-v4@5.3.4': - resolution: {integrity: sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A==} - engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.7.0': resolution: {integrity: sha512-3BDx/aCCPf+kkinYf5QQhdQ9UAGihgOVqI3QO5xQfSaIWvUE4KYLtiGRWsNe1SR7ijXC0QEPqofVp5Sb0zC8xQ==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.9.2': - resolution: {integrity: sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg==} - engines: {node: '>=18.0.0'} - '@smithy/types@4.6.0': resolution: {integrity: sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==} engines: {node: '>=18.0.0'} @@ -3586,18 +3328,10 @@ packages: resolution: {integrity: sha512-AlBmD6Idav2ugmoAL6UtR6ItS7jU5h5RNqLMZC7QrLCoITA9NzIN3nx9GWi8g4z1pfWh2r9r96SX/jHiNwPJ9A==} engines: {node: '>=18.0.0'} - '@smithy/url-parser@4.2.4': - resolution: {integrity: sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg==} - engines: {node: '>=18.0.0'} - '@smithy/util-base64@4.2.0': resolution: {integrity: sha512-+erInz8WDv5KPe7xCsJCp+1WCjSbah9gWcmUXc9NqmhyPx59tf7jqFz+za1tRG1Y5KM1Cy1rWCcGypylFp4mvA==} engines: {node: '>=18.0.0'} - '@smithy/util-base64@4.3.0': - resolution: {integrity: sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==} - engines: {node: '>=18.0.0'} - '@smithy/util-body-length-browser@4.2.0': resolution: {integrity: sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==} engines: {node: '>=18.0.0'} @@ -3606,10 +3340,6 @@ packages: resolution: {integrity: sha512-U8q1WsSZFjXijlD7a4wsDQOvOwV+72iHSfq1q7VD+V75xP/pdtm0WIGuaFJ3gcADDOKj2MIBn4+zisi140HEnQ==} engines: {node: '>=18.0.0'} - '@smithy/util-body-length-node@4.2.1': - resolution: {integrity: sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==} - engines: {node: '>=18.0.0'} - '@smithy/util-buffer-from@2.2.0': resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} engines: {node: '>=14.0.0'} @@ -3626,26 +3356,14 @@ packages: resolution: {integrity: sha512-qzHp7ZDk1Ba4LDwQVCNp90xPGqSu7kmL7y5toBpccuhi3AH7dcVBIT/pUxYcInK4jOy6FikrcTGq5wxcka8UaQ==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.3.5': - resolution: {integrity: sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ==} - engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.2.0': resolution: {integrity: sha512-FxUHS3WXgx3bTWR6yQHNHHkQHZm/XKIi/CchTnKvBulN6obWpcbzJ6lDToXn+Wp0QlVKd7uYAz2/CTw1j7m+Kg==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.2.8': - resolution: {integrity: sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g==} - engines: {node: '>=18.0.0'} - '@smithy/util-endpoints@3.2.0': resolution: {integrity: sha512-TXeCn22D56vvWr/5xPqALc9oO+LN+QpFjrSM7peG/ckqEPoI3zaKZFp+bFwfmiHhn5MGWPaLCqDOJPPIixk9Wg==} engines: {node: '>=18.0.0'} - '@smithy/util-endpoints@3.2.4': - resolution: {integrity: sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg==} - engines: {node: '>=18.0.0'} - '@smithy/util-hex-encoding@4.2.0': resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} engines: {node: '>=18.0.0'} @@ -3654,26 +3372,14 @@ packages: resolution: {integrity: sha512-u9OOfDa43MjagtJZ8AapJcmimP+K2Z7szXn8xbty4aza+7P1wjFmy2ewjSbhEiYQoW1unTlOAIV165weYAaowA==} engines: {node: '>=18.0.0'} - '@smithy/util-middleware@4.2.4': - resolution: {integrity: sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg==} - engines: {node: '>=18.0.0'} - '@smithy/util-retry@4.2.0': resolution: {integrity: sha512-BWSiuGbwRnEE2SFfaAZEX0TqaxtvtSYPM/J73PFVm+A29Fg1HTPiYFb8TmX1DXp4hgcdyJcNQmprfd5foeORsg==} engines: {node: '>=18.0.0'} - '@smithy/util-retry@4.2.4': - resolution: {integrity: sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA==} - engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.4.0': resolution: {integrity: sha512-vtO7ktbixEcrVzMRmpQDnw/Ehr9UWjBvSJ9fyAbadKkC4w5Cm/4lMO8cHz8Ysb8uflvQUNRcuux/oNHKPXkffg==} engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.5.5': - resolution: {integrity: sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w==} - engines: {node: '>=18.0.0'} - '@smithy/util-uri-escape@4.2.0': resolution: {integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==} engines: {node: '>=18.0.0'} @@ -3686,10 +3392,6 @@ packages: resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} engines: {node: '>=18.0.0'} - '@smithy/util-waiter@4.2.4': - resolution: {integrity: sha512-roKXtXIC6fopFvVOju8VYHtguc/jAcMlK8IlDOHsrQn0ayMkHynjm/D2DCMRf7MJFXzjHhlzg2edr3QPEakchQ==} - engines: {node: '>=18.0.0'} - '@smithy/uuid@1.1.0': resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} engines: {node: '>=18.0.0'} @@ -4671,6 +4373,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + aws4fetch@1.0.20: + resolution: {integrity: sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==} + axe-core@4.10.3: resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} engines: {node: '>=4'} @@ -4796,17 +4501,6 @@ packages: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} - better-upload@2.0.3: - resolution: {integrity: sha512-fXpymXzPLDSmDja18dDtuniY+t36NRXo8ftrzWjZJxWbEJxBDZ29sucf8+sd21AJZX1KM8W2nYLSK2ksggLYdA==} - peerDependencies: - '@aws-sdk/client-s3': '*' - react: '*' - peerDependenciesMeta: - '@aws-sdk/client-s3': - optional: true - react: - optional: true - big-integer@1.6.52: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} @@ -5877,6 +5571,10 @@ packages: resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} hasBin: true + fast-xml-parser@5.3.2: + resolution: {integrity: sha512-n8v8b6p4Z1sMgqRmqLJm3awW4NX7NkaKPfb3uJIBTSH7Pdvufi3PQ3/lJLQrvxcMYl7JI2jnDO90siPEpD8JBA==} + hasBin: true + fastq@1.16.0: resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} @@ -9287,27 +8985,6 @@ snapshots: '@csstools/css-tokenizer': 3.0.3 lru-cache: 10.4.3 - '@aws-crypto/crc32@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.922.0 - tslib: 2.8.1 - - '@aws-crypto/crc32c@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.922.0 - tslib: 2.8.1 - - '@aws-crypto/sha1-browser@5.2.0': - dependencies: - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-locate-window': 3.893.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - '@aws-crypto/sha256-browser@5.2.0': dependencies: '@aws-crypto/sha256-js': 5.2.0 @@ -9334,68 +9011,6 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.922.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.922.0 - '@aws-sdk/credential-provider-node': 3.922.0 - '@aws-sdk/middleware-bucket-endpoint': 3.922.0 - '@aws-sdk/middleware-expect-continue': 3.922.0 - '@aws-sdk/middleware-flexible-checksums': 3.922.0 - '@aws-sdk/middleware-host-header': 3.922.0 - '@aws-sdk/middleware-location-constraint': 3.922.0 - '@aws-sdk/middleware-logger': 3.922.0 - '@aws-sdk/middleware-recursion-detection': 3.922.0 - '@aws-sdk/middleware-sdk-s3': 3.922.0 - '@aws-sdk/middleware-ssec': 3.922.0 - '@aws-sdk/middleware-user-agent': 3.922.0 - '@aws-sdk/region-config-resolver': 3.922.0 - '@aws-sdk/signature-v4-multi-region': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-endpoints': 3.922.0 - '@aws-sdk/util-user-agent-browser': 3.922.0 - '@aws-sdk/util-user-agent-node': 3.922.0 - '@aws-sdk/xml-builder': 3.921.0 - '@smithy/config-resolver': 4.4.2 - '@smithy/core': 3.17.2 - '@smithy/eventstream-serde-browser': 4.2.4 - '@smithy/eventstream-serde-config-resolver': 4.3.4 - '@smithy/eventstream-serde-node': 4.2.4 - '@smithy/fetch-http-handler': 5.3.5 - '@smithy/hash-blob-browser': 4.2.5 - '@smithy/hash-node': 4.2.4 - '@smithy/hash-stream-node': 4.2.4 - '@smithy/invalid-dependency': 4.2.4 - '@smithy/md5-js': 4.2.4 - '@smithy/middleware-content-length': 4.2.4 - '@smithy/middleware-endpoint': 4.3.6 - '@smithy/middleware-retry': 4.4.6 - '@smithy/middleware-serde': 4.2.4 - '@smithy/middleware-stack': 4.2.4 - '@smithy/node-config-provider': 4.3.4 - '@smithy/node-http-handler': 4.4.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - '@smithy/url-parser': 4.2.4 - '@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.5 - '@smithy/util-defaults-mode-node': 4.2.8 - '@smithy/util-endpoints': 3.2.4 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-retry': 4.2.4 - '@smithy/util-stream': 4.5.5 - '@smithy/util-utf8': 4.2.0 - '@smithy/util-waiter': 4.2.4 - '@smithy/uuid': 1.1.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sesv2@3.901.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -9484,49 +9099,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.922.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.922.0 - '@aws-sdk/middleware-host-header': 3.922.0 - '@aws-sdk/middleware-logger': 3.922.0 - '@aws-sdk/middleware-recursion-detection': 3.922.0 - '@aws-sdk/middleware-user-agent': 3.922.0 - '@aws-sdk/region-config-resolver': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-endpoints': 3.922.0 - '@aws-sdk/util-user-agent-browser': 3.922.0 - '@aws-sdk/util-user-agent-node': 3.922.0 - '@smithy/config-resolver': 4.4.2 - '@smithy/core': 3.17.2 - '@smithy/fetch-http-handler': 5.3.5 - '@smithy/hash-node': 4.2.4 - '@smithy/invalid-dependency': 4.2.4 - '@smithy/middleware-content-length': 4.2.4 - '@smithy/middleware-endpoint': 4.3.6 - '@smithy/middleware-retry': 4.4.6 - '@smithy/middleware-serde': 4.2.4 - '@smithy/middleware-stack': 4.2.4 - '@smithy/node-config-provider': 4.3.4 - '@smithy/node-http-handler': 4.4.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - '@smithy/url-parser': 4.2.4 - '@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.5 - '@smithy/util-defaults-mode-node': 4.2.8 - '@smithy/util-endpoints': 3.2.4 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-retry': 4.2.4 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/core@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 @@ -9543,22 +9115,6 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@aws-sdk/core@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@aws-sdk/xml-builder': 3.921.0 - '@smithy/core': 3.17.2 - '@smithy/node-config-provider': 4.3.4 - '@smithy/property-provider': 4.2.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/signature-v4': 5.3.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - '@smithy/util-base64': 4.3.0 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9567,14 +9123,6 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/property-provider': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9588,19 +9136,6 @@ snapshots: '@smithy/util-stream': 4.4.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/fetch-http-handler': 5.3.5 - '@smithy/node-http-handler': 4.4.4 - '@smithy/property-provider': 4.2.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - '@smithy/util-stream': 4.5.5 - tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9619,24 +9154,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/credential-provider-env': 3.922.0 - '@aws-sdk/credential-provider-http': 3.922.0 - '@aws-sdk/credential-provider-process': 3.922.0 - '@aws-sdk/credential-provider-sso': 3.922.0 - '@aws-sdk/credential-provider-web-identity': 3.922.0 - '@aws-sdk/nested-clients': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/credential-provider-imds': 4.2.4 - '@smithy/property-provider': 4.2.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/credential-provider-node@3.901.0': dependencies: '@aws-sdk/credential-provider-env': 3.901.0 @@ -9654,23 +9171,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.922.0': - dependencies: - '@aws-sdk/credential-provider-env': 3.922.0 - '@aws-sdk/credential-provider-http': 3.922.0 - '@aws-sdk/credential-provider-ini': 3.922.0 - '@aws-sdk/credential-provider-process': 3.922.0 - '@aws-sdk/credential-provider-sso': 3.922.0 - '@aws-sdk/credential-provider-web-identity': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/credential-provider-imds': 4.2.4 - '@smithy/property-provider': 4.2.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/credential-provider-process@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9680,15 +9180,6 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-process@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/property-provider': 4.2.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.901.0': dependencies: '@aws-sdk/client-sso': 3.901.0 @@ -9702,19 +9193,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-sso@3.922.0': - dependencies: - '@aws-sdk/client-sso': 3.922.0 - '@aws-sdk/core': 3.922.0 - '@aws-sdk/token-providers': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/property-provider': 4.2.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/credential-provider-web-identity@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9727,83 +9205,19 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/nested-clients': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/property-provider': 4.2.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/middleware-bucket-endpoint@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-arn-parser': 3.893.0 - '@smithy/node-config-provider': 4.3.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - '@smithy/util-config-provider': 4.2.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-expect-continue@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - - '@aws-sdk/middleware-flexible-checksums@3.922.0': - dependencies: - '@aws-crypto/crc32': 5.2.0 - '@aws-crypto/crc32c': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/is-array-buffer': 4.2.0 - '@smithy/node-config-provider': 4.3.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-stream': 4.5.5 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-host-header@3.901.0': + '@aws-sdk/middleware-host-header@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 '@smithy/protocol-http': 5.3.0 '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - - '@aws-sdk/middleware-location-constraint@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 @@ -9812,14 +9226,6 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@aws/lambda-invoke-store': 0.1.1 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9837,29 +9243,6 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-arn-parser': 3.893.0 - '@smithy/core': 3.17.2 - '@smithy/node-config-provider': 4.3.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/signature-v4': 5.3.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - '@smithy/util-config-provider': 4.2.0 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-stream': 4.5.5 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-ssec@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -9870,16 +9253,6 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-endpoints': 3.922.0 - '@smithy/core': 3.17.2 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/nested-clients@3.901.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -9923,49 +9296,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/nested-clients@3.922.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.922.0 - '@aws-sdk/middleware-host-header': 3.922.0 - '@aws-sdk/middleware-logger': 3.922.0 - '@aws-sdk/middleware-recursion-detection': 3.922.0 - '@aws-sdk/middleware-user-agent': 3.922.0 - '@aws-sdk/region-config-resolver': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-endpoints': 3.922.0 - '@aws-sdk/util-user-agent-browser': 3.922.0 - '@aws-sdk/util-user-agent-node': 3.922.0 - '@smithy/config-resolver': 4.4.2 - '@smithy/core': 3.17.2 - '@smithy/fetch-http-handler': 5.3.5 - '@smithy/hash-node': 4.2.4 - '@smithy/invalid-dependency': 4.2.4 - '@smithy/middleware-content-length': 4.2.4 - '@smithy/middleware-endpoint': 4.3.6 - '@smithy/middleware-retry': 4.4.6 - '@smithy/middleware-serde': 4.2.4 - '@smithy/middleware-stack': 4.2.4 - '@smithy/node-config-provider': 4.3.4 - '@smithy/node-http-handler': 4.4.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - '@smithy/url-parser': 4.2.4 - '@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.5 - '@smithy/util-defaults-mode-node': 4.2.8 - '@smithy/util-endpoints': 3.2.4 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-retry': 4.2.4 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/region-config-resolver@3.901.0': dependencies: '@aws-sdk/types': 3.901.0 @@ -9975,25 +9305,6 @@ snapshots: '@smithy/util-middleware': 4.2.0 tslib: 2.8.1 - '@aws-sdk/region-config-resolver@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/config-resolver': 4.4.2 - '@smithy/node-config-provider': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - - '@aws-sdk/s3-request-presigner@3.922.0': - dependencies: - '@aws-sdk/signature-v4-multi-region': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@aws-sdk/util-format-url': 3.922.0 - '@smithy/middleware-endpoint': 4.3.6 - '@smithy/protocol-http': 5.3.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.901.0': dependencies: '@aws-sdk/middleware-sdk-s3': 3.901.0 @@ -10003,15 +9314,6 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.922.0': - dependencies: - '@aws-sdk/middleware-sdk-s3': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/protocol-http': 5.3.4 - '@smithy/signature-v4': 5.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/token-providers@3.901.0': dependencies: '@aws-sdk/core': 3.901.0 @@ -10024,18 +9326,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/token-providers@3.922.0': - dependencies: - '@aws-sdk/core': 3.922.0 - '@aws-sdk/nested-clients': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/property-provider': 4.2.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/types@3.901.0': dependencies: '@smithy/types': 4.6.0 @@ -10058,21 +9348,6 @@ snapshots: '@smithy/util-endpoints': 3.2.0 tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/types': 4.8.1 - '@smithy/url-parser': 4.2.4 - '@smithy/util-endpoints': 3.2.4 - tslib: 2.8.1 - - '@aws-sdk/util-format-url@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/querystring-builder': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/util-locate-window@3.893.0': dependencies: tslib: 2.8.1 @@ -10084,13 +9359,6 @@ snapshots: bowser: 2.12.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.922.0': - dependencies: - '@aws-sdk/types': 3.922.0 - '@smithy/types': 4.8.1 - bowser: 2.12.1 - tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.901.0': dependencies: '@aws-sdk/middleware-user-agent': 3.901.0 @@ -10099,30 +9367,14 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.922.0': - dependencies: - '@aws-sdk/middleware-user-agent': 3.922.0 - '@aws-sdk/types': 3.922.0 - '@smithy/node-config-provider': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@aws-sdk/xml-builder@3.901.0': dependencies: '@smithy/types': 4.6.0 fast-xml-parser: 5.2.5 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.921.0': - dependencies: - '@smithy/types': 4.8.1 - fast-xml-parser: 5.2.5 - tslib: 2.8.1 - '@aws/lambda-invoke-store@0.0.1': {} - '@aws/lambda-invoke-store@0.1.1': {} - '@babel/code-frame@7.10.4': dependencies: '@babel/highlight': 7.25.9 @@ -10872,6 +10124,16 @@ snapshots: '@better-fetch/fetch@1.1.18': {} + '@better-upload/client@3.0.2(react@19.2.0)': + dependencies: + react: 19.2.0 + + '@better-upload/server@3.0.2': + dependencies: + aws4fetch: 1.0.20 + fast-xml-parser: 5.3.2 + zod: 4.1.12 + '@code-inspector/core@1.2.10': dependencies: '@vue/compiler-dom': 3.5.17 @@ -13337,20 +12599,6 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/abort-controller@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - - '@smithy/chunked-blob-reader-native@4.2.1': - dependencies: - '@smithy/util-base64': 4.3.0 - tslib: 2.8.1 - - '@smithy/chunked-blob-reader@5.2.0': - dependencies: - tslib: 2.8.1 - '@smithy/config-resolver@4.3.0': dependencies: '@smithy/node-config-provider': 4.3.0 @@ -13359,15 +12607,6 @@ snapshots: '@smithy/util-middleware': 4.2.0 tslib: 2.8.1 - '@smithy/config-resolver@4.4.2': - dependencies: - '@smithy/node-config-provider': 4.3.4 - '@smithy/types': 4.8.1 - '@smithy/util-config-provider': 4.2.0 - '@smithy/util-endpoints': 3.2.4 - '@smithy/util-middleware': 4.2.4 - tslib: 2.8.1 - '@smithy/core@3.14.0': dependencies: '@smithy/middleware-serde': 4.2.0 @@ -13381,19 +12620,6 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 - '@smithy/core@3.17.2': - dependencies: - '@smithy/middleware-serde': 4.2.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - '@smithy/util-base64': 4.3.0 - '@smithy/util-body-length-browser': 4.2.0 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-stream': 4.5.5 - '@smithy/util-utf8': 4.2.0 - '@smithy/uuid': 1.1.0 - tslib: 2.8.1 - '@smithy/credential-provider-imds@4.2.0': dependencies: '@smithy/node-config-provider': 4.3.0 @@ -13402,44 +12628,6 @@ snapshots: '@smithy/url-parser': 4.2.0 tslib: 2.8.1 - '@smithy/credential-provider-imds@4.2.4': - dependencies: - '@smithy/node-config-provider': 4.3.4 - '@smithy/property-provider': 4.2.4 - '@smithy/types': 4.8.1 - '@smithy/url-parser': 4.2.4 - tslib: 2.8.1 - - '@smithy/eventstream-codec@4.2.4': - dependencies: - '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.8.1 - '@smithy/util-hex-encoding': 4.2.0 - tslib: 2.8.1 - - '@smithy/eventstream-serde-browser@4.2.4': - dependencies: - '@smithy/eventstream-serde-universal': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - - '@smithy/eventstream-serde-config-resolver@4.3.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - - '@smithy/eventstream-serde-node@4.2.4': - dependencies: - '@smithy/eventstream-serde-universal': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - - '@smithy/eventstream-serde-universal@4.2.4': - dependencies: - '@smithy/eventstream-codec': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/fetch-http-handler@5.3.0': dependencies: '@smithy/protocol-http': 5.3.0 @@ -13448,21 +12636,6 @@ snapshots: '@smithy/util-base64': 4.2.0 tslib: 2.8.1 - '@smithy/fetch-http-handler@5.3.5': - dependencies: - '@smithy/protocol-http': 5.3.4 - '@smithy/querystring-builder': 4.2.4 - '@smithy/types': 4.8.1 - '@smithy/util-base64': 4.3.0 - tslib: 2.8.1 - - '@smithy/hash-blob-browser@4.2.5': - dependencies: - '@smithy/chunked-blob-reader': 5.2.0 - '@smithy/chunked-blob-reader-native': 4.2.1 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/hash-node@4.2.0': dependencies: '@smithy/types': 4.6.0 @@ -13470,29 +12643,11 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@smithy/hash-node@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - '@smithy/util-buffer-from': 4.2.0 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - - '@smithy/hash-stream-node@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - '@smithy/invalid-dependency@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/invalid-dependency@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/is-array-buffer@2.2.0': dependencies: tslib: 2.8.1 @@ -13501,24 +12656,12 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/md5-js@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - '@smithy/middleware-content-length@4.2.0': dependencies: '@smithy/protocol-http': 5.3.0 '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/middleware-content-length@4.2.4': - dependencies: - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/middleware-endpoint@4.3.0': dependencies: '@smithy/core': 3.14.0 @@ -13530,17 +12673,6 @@ snapshots: '@smithy/util-middleware': 4.2.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.3.6': - dependencies: - '@smithy/core': 3.17.2 - '@smithy/middleware-serde': 4.2.4 - '@smithy/node-config-provider': 4.3.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - '@smithy/url-parser': 4.2.4 - '@smithy/util-middleware': 4.2.4 - tslib: 2.8.1 - '@smithy/middleware-retry@4.4.0': dependencies: '@smithy/node-config-provider': 4.3.0 @@ -13553,40 +12685,17 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 - '@smithy/middleware-retry@4.4.6': - dependencies: - '@smithy/node-config-provider': 4.3.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/service-error-classification': 4.2.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-retry': 4.2.4 - '@smithy/uuid': 1.1.0 - tslib: 2.8.1 - '@smithy/middleware-serde@4.2.0': dependencies: '@smithy/protocol-http': 5.3.0 '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/middleware-serde@4.2.4': - dependencies: - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/middleware-stack@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/middleware-stack@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/node-config-provider@4.3.0': dependencies: '@smithy/property-provider': 4.2.0 @@ -13594,13 +12703,6 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/node-config-provider@4.3.4': - dependencies: - '@smithy/property-provider': 4.2.4 - '@smithy/shared-ini-file-loader': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/node-http-handler@4.3.0': dependencies: '@smithy/abort-controller': 4.2.0 @@ -13609,74 +12711,36 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/node-http-handler@4.4.4': - dependencies: - '@smithy/abort-controller': 4.2.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/querystring-builder': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/property-provider@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/property-provider@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/protocol-http@5.3.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/protocol-http@5.3.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/querystring-builder@4.2.0': dependencies: '@smithy/types': 4.6.0 '@smithy/util-uri-escape': 4.2.0 tslib: 2.8.1 - '@smithy/querystring-builder@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - '@smithy/util-uri-escape': 4.2.0 - tslib: 2.8.1 - '@smithy/querystring-parser@4.2.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/querystring-parser@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/service-error-classification@4.2.0': dependencies: '@smithy/types': 4.6.0 - '@smithy/service-error-classification@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - '@smithy/shared-ini-file-loader@4.3.0': dependencies: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/shared-ini-file-loader@4.3.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/signature-v4@5.3.0': dependencies: '@smithy/is-array-buffer': 4.2.0 @@ -13688,17 +12752,6 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@smithy/signature-v4@5.3.4': - dependencies: - '@smithy/is-array-buffer': 4.2.0 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - '@smithy/util-hex-encoding': 4.2.0 - '@smithy/util-middleware': 4.2.4 - '@smithy/util-uri-escape': 4.2.0 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - '@smithy/smithy-client@4.7.0': dependencies: '@smithy/core': 3.14.0 @@ -13709,16 +12762,6 @@ snapshots: '@smithy/util-stream': 4.4.0 tslib: 2.8.1 - '@smithy/smithy-client@4.9.2': - dependencies: - '@smithy/core': 3.17.2 - '@smithy/middleware-endpoint': 4.3.6 - '@smithy/middleware-stack': 4.2.4 - '@smithy/protocol-http': 5.3.4 - '@smithy/types': 4.8.1 - '@smithy/util-stream': 4.5.5 - tslib: 2.8.1 - '@smithy/types@4.6.0': dependencies: tslib: 2.8.1 @@ -13733,24 +12776,12 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/url-parser@4.2.4': - dependencies: - '@smithy/querystring-parser': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/util-base64@4.2.0': dependencies: '@smithy/util-buffer-from': 4.2.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@smithy/util-base64@4.3.0': - dependencies: - '@smithy/util-buffer-from': 4.2.0 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - '@smithy/util-body-length-browser@4.2.0': dependencies: tslib: 2.8.1 @@ -13759,10 +12790,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-body-length-node@4.2.1': - dependencies: - tslib: 2.8.1 - '@smithy/util-buffer-from@2.2.0': dependencies: '@smithy/is-array-buffer': 2.2.0 @@ -13785,13 +12812,6 @@ snapshots: bowser: 2.12.1 tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.3.5': - dependencies: - '@smithy/property-provider': 4.2.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.2.0': dependencies: '@smithy/config-resolver': 4.3.0 @@ -13802,28 +12822,12 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.2.8': - dependencies: - '@smithy/config-resolver': 4.4.2 - '@smithy/credential-provider-imds': 4.2.4 - '@smithy/node-config-provider': 4.3.4 - '@smithy/property-provider': 4.2.4 - '@smithy/smithy-client': 4.9.2 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/util-endpoints@3.2.0': dependencies: '@smithy/node-config-provider': 4.3.0 '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/util-endpoints@3.2.4': - dependencies: - '@smithy/node-config-provider': 4.3.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/util-hex-encoding@4.2.0': dependencies: tslib: 2.8.1 @@ -13833,23 +12837,12 @@ snapshots: '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/util-middleware@4.2.4': - dependencies: - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/util-retry@4.2.0': dependencies: '@smithy/service-error-classification': 4.2.0 '@smithy/types': 4.6.0 tslib: 2.8.1 - '@smithy/util-retry@4.2.4': - dependencies: - '@smithy/service-error-classification': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/util-stream@4.4.0': dependencies: '@smithy/fetch-http-handler': 5.3.0 @@ -13861,17 +12854,6 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@smithy/util-stream@4.5.5': - dependencies: - '@smithy/fetch-http-handler': 5.3.5 - '@smithy/node-http-handler': 4.4.4 - '@smithy/types': 4.8.1 - '@smithy/util-base64': 4.3.0 - '@smithy/util-buffer-from': 4.2.0 - '@smithy/util-hex-encoding': 4.2.0 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - '@smithy/util-uri-escape@4.2.0': dependencies: tslib: 2.8.1 @@ -13886,12 +12868,6 @@ snapshots: '@smithy/util-buffer-from': 4.2.0 tslib: 2.8.1 - '@smithy/util-waiter@4.2.4': - dependencies: - '@smithy/abort-controller': 4.2.4 - '@smithy/types': 4.8.1 - tslib: 2.8.1 - '@smithy/uuid@1.1.0': dependencies: tslib: 2.8.1 @@ -15163,6 +14139,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + aws4fetch@1.0.20: {} + axe-core@4.10.3: {} babel-dead-code-elimination@1.0.10: @@ -15343,14 +14321,6 @@ snapshots: dependencies: open: 8.4.2 - better-upload@2.0.3(@aws-sdk/client-s3@3.922.0)(react@19.2.0): - dependencies: - '@aws-sdk/s3-request-presigner': 3.922.0 - zod: 4.1.12 - optionalDependencies: - '@aws-sdk/client-s3': 3.922.0 - react: 19.2.0 - big-integer@1.6.52: {} binary-extensions@2.2.0: {} @@ -16682,6 +15652,10 @@ snapshots: dependencies: strnum: 2.1.1 + fast-xml-parser@5.3.2: + dependencies: + strnum: 2.1.1 + fastq@1.16.0: dependencies: reusify: 1.0.4 @@ -18182,7 +17156,7 @@ snapshots: nice-try@1.0.5: {} - nitro-nightly@3.0.1-20251023-125324-a6f9b591(chokidar@4.0.3)(ioredis@5.8.0)(vite@7.1.11(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.19.3)(yaml@2.8.1)): + nitro-nightly@3.0.1-20251023-125324-a6f9b591(aws4fetch@1.0.20)(chokidar@4.0.3)(ioredis@5.8.0)(vite@7.1.11(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.19.3)(yaml@2.8.1)): dependencies: consola: 3.4.2 cookie-es: 2.0.0 @@ -18200,7 +17174,7 @@ snapshots: srvx: 0.8.16 undici: 7.16.0 unenv: 2.0.0-rc.21 - unstorage: 2.0.0-alpha.3(chokidar@4.0.3)(db0@0.3.4)(ioredis@5.8.0)(ofetch@1.4.1) + unstorage: 2.0.0-alpha.3(aws4fetch@1.0.20)(chokidar@4.0.3)(db0@0.3.4)(ioredis@5.8.0)(ofetch@1.4.1) optionalDependencies: vite: 7.1.11(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.19.3)(yaml@2.8.1) transitivePeerDependencies: @@ -19878,8 +18852,9 @@ snapshots: picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - unstorage@2.0.0-alpha.3(chokidar@4.0.3)(db0@0.3.4)(ioredis@5.8.0)(ofetch@1.4.1): + unstorage@2.0.0-alpha.3(aws4fetch@1.0.20)(chokidar@4.0.3)(db0@0.3.4)(ioredis@5.8.0)(ofetch@1.4.1): optionalDependencies: + aws4fetch: 1.0.20 chokidar: 4.0.3 db0: 0.3.4 ioredis: 5.8.0 diff --git a/src/components/ui/upload-button.stories.tsx b/src/components/ui/upload-button.stories.tsx index fc2a14df5..e1d58b427 100644 --- a/src/components/ui/upload-button.stories.tsx +++ b/src/components/ui/upload-button.stories.tsx @@ -1,60 +1,46 @@ import type { Meta } from '@storybook/react-vite'; -import { useUploadFile } from 'better-upload/client'; import { UploadIcon } from 'lucide-react'; -import { useForm } from 'react-hook-form'; -import { - Form, - FormField, - FormFieldController, - FormFieldError, -} from '@/components/form'; import { UploadButton } from '@/components/ui/upload-button'; -import { BookCover } from '@/features/book/book-cover'; - export default { title: 'Upload Button', } satisfies Meta; export const Default = () => { - const { control } = useUploadFile({ route: 'bookCover' }); - return ( console.log('uploaded file', file)} + onUploadSuccess={(file) => console.log('uploaded file', file)} /> ); }; export const WithChildren = () => { - const { control } = useUploadFile({ route: 'bookCover' }); - return (
console.log('uploaded file', file)} + uploadRoute="bookCover" + onUploadSuccess={(file) => console.log('uploaded file', file)} > Upload a new file console.log('uploaded file', file)} + uploadRoute="bookCover" + onUploadSuccess={(file) => console.log('uploaded file', file)} > Upload a new file console.log('uploaded file', file)} + uploadRoute="bookCover" + onUploadSuccess={(file) => console.log('uploaded file', file)} > Upload a new file @@ -63,14 +49,12 @@ export const WithChildren = () => { }; export const Disabled = () => { - const { control } = useUploadFile({ route: 'bookCover' }); - return (
console.log('uploaded file', file)} + uploadRoute="bookCover" + onUploadSuccess={(file) => console.log('uploaded file', file)} > Upload a new file @@ -78,8 +62,8 @@ export const Disabled = () => { console.log('uploaded file', file)} + uploadRoute="bookCover" + onUploadSuccess={(file) => console.log('uploaded file', file)} > Upload a new file @@ -87,49 +71,3 @@ export const Disabled = () => {
); }; - -export const RealWorldUseCase = () => { - const form = useForm({ - defaultValues: { - coverId: '', - }, - }); - const { control, uploadedFile } = useUploadFile({ route: 'bookCover' }); - - return ( -
- - { - return ( -
-
- Upload cover - - - -
- -
- ); - }} - /> -
-
- ); -}; diff --git a/src/components/ui/upload-button.tsx b/src/components/ui/upload-button.tsx index 571074285..87fb11138 100644 --- a/src/components/ui/upload-button.tsx +++ b/src/components/ui/upload-button.tsx @@ -1,12 +1,15 @@ import { + type ClientUploadError, type FileUploadInfo, - type UploadHookControl, -} from 'better-upload/client'; + uploadFile, + type UploadStatus, +} from '@better-upload/client'; +import { useIsMutating, useMutation } from '@tanstack/react-query'; import { UploadIcon } from 'lucide-react'; import { type ChangeEvent, type ComponentProps, - useEffect, + type ReactElement, useId, useRef, } from 'react'; @@ -15,67 +18,87 @@ import { cn } from '@/lib/tailwind/utils'; import { Button } from '@/components/ui/button'; +import type { UploadRoutes } from '@/routes/api/upload'; + export type UploadButtonProps = { - control: UploadHookControl; + uploadRoute: UploadRoutes; /** * Called only if the file was uploaded successfully. */ - onChange?: (file: FileUploadInfo<'complete'>) => void; + onUploadSuccess?: (file: FileUploadInfo<'complete'>) => void; + onUploadStateChange?: ( + file: FileUploadInfo + ) => void; + onError?: (error: Error | ClientUploadError) => void; inputProps?: ComponentProps<'input'>; + icon?: ReactElement; } & Omit, 'onChange'>; -/** - * Upload button that should be used with useUploadFile() better-upload hook. - */ +export const useIsUploadingFiles = (uploadRoute: UploadRoutes) => + useIsMutating({ + mutationKey: ['fileUpload', uploadRoute], + }) > 0; + export const UploadButton = ({ children, inputProps, - control, - onChange, + onUploadStateChange, + onUploadSuccess, + onError, disabled, + icon, + uploadRoute, ...rest }: UploadButtonProps) => { const innerId = useId(); + const uploadMutation = useMutation({ + mutationKey: ['fileUpload', uploadRoute], + mutationFn: async (file: File) => { + return uploadFile({ + file, + route: uploadRoute, + onFileStateChange: ({ file }) => { + onUploadStateChange?.(file); + }, + }); + }, + onSuccess: ({ file }) => { + onUploadSuccess?.(file); + }, + onError: (error) => { + onError?.(error); + }, + }); + const handleFileChange = (event: ChangeEvent) => { const file = event.target.files?.[0]; if (file) { - control.upload(file); + uploadMutation.mutate(file); } }; const inputRef = useRef(null); - useEffect(() => { - if (!control.isSuccess || !control.uploadedFile) return; - // if success, it means the file was successfully uploaded - onChange?.(control.uploadedFile); - }, [control.isSuccess, control.uploadedFile, onChange]); - return ( <> { handleFileChange(onChangeEvent); inputProps?.onChange?.(onChangeEvent); diff --git a/src/env/client.ts b/src/env/client.ts index 66986fb38..753d6a519 100644 --- a/src/env/client.ts +++ b/src/env/client.ts @@ -42,7 +42,7 @@ export const envClient = createEnv({ .string() .optional() .transform((value) => value ?? (isDev ? 'gold' : 'plum')), - VITE_S3_BUCKET_PUBLIC_URL: z.string().url(), + VITE_S3_BUCKET_PUBLIC_URL: z.url(), }, runtimeEnv: { ...envMetaOrProcess, diff --git a/src/features/book/book-cover.tsx b/src/features/book/book-cover.tsx index 490bb00c4..8dbe4d052 100644 --- a/src/features/book/book-cover.tsx +++ b/src/features/book/book-cover.tsx @@ -25,6 +25,7 @@ export const BookCover = (props: { > {!!props.book.coverId && ( diff --git a/src/features/book/manager/form-book-cover.tsx b/src/features/book/manager/form-book-cover.tsx index a4a2d2ef1..c309139c1 100644 --- a/src/features/book/manager/form-book-cover.tsx +++ b/src/features/book/manager/form-book-cover.tsx @@ -1,5 +1,4 @@ import { useQuery } from '@tanstack/react-query'; -import { useUploadFile } from 'better-upload/client'; import { useFormContext, useWatch } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -31,35 +30,12 @@ export const FormBookCover = () => { name: 'author', control: form.control, }); - const genre = genresQuery.data?.items.find((item) => item.id === genreId); - const coverId = useWatch({ name: 'coverId', control: form.control, }); - const { uploadedFile, control } = useUploadFile({ - route: 'bookCover', - onUploadComplete: ({ file }) => { - form.clearErrors('coverId'); - form.setValue('coverId', file.objectKey); - }, - onError: (error) => { - if (error.type === 'rejected') { - // In this specific case, error should be a translated message - // because rejected are custom errors thrown by the developper - form.setError('coverId', { - type: 'custom', - message: error.message, - }); - } else { - form.setError('coverId', { - type: 'custom', - message: t(`book:manager.uploadErrors.${error.type}`), - }); - } - }, - }); + const genre = genresQuery.data?.items.find((item) => item.id === genreId); return ( @@ -67,7 +43,7 @@ export const FormBookCover = () => { control={form.control} type="custom" name="coverId" - render={() => { + render={({ field }) => { return ( <>
@@ -78,15 +54,20 @@ export const FormBookCover = () => { title, author, genre, - coverId: uploadedFile?.objectKey ?? coverId, + coverId, }} /> + field.onChange(file.objectInfo.key) + } />
diff --git a/src/features/book/manager/page-book-new.tsx b/src/features/book/manager/page-book-new.tsx index a80739e47..98b5856f7 100644 --- a/src/features/book/manager/page-book-new.tsx +++ b/src/features/book/manager/page-book-new.tsx @@ -13,6 +13,7 @@ import { Form } from '@/components/form'; import { PreventNavigation } from '@/components/prevent-navigation'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; +import { useIsUploadingFiles } from '@/components/ui/upload-button'; import { FormBook } from '@/features/book/manager/form-book'; import { FormBookCover } from '@/features/book/manager/form-book-cover'; @@ -36,9 +37,12 @@ export const PageBookNew = () => { author: '', genreId: '', publisher: '', + coverId: '', }, }); + const isUploadingFiles = useIsUploadingFiles('bookCover'); + const bookCreate = useMutation( orpc.book.create.mutationOptions({ onSuccess: async () => { @@ -90,6 +94,7 @@ export const PageBookNew = () => { type="submit" className="min-w-20" loading={bookCreate.isPending} + disabled={isUploadingFiles} > {t('book:manager.new.createButton.label')} diff --git a/src/features/book/manager/page-book-update.tsx b/src/features/book/manager/page-book-update.tsx index e655cf33b..4be931923 100644 --- a/src/features/book/manager/page-book-update.tsx +++ b/src/features/book/manager/page-book-update.tsx @@ -13,6 +13,7 @@ import { Form } from '@/components/form'; import { PreventNavigation } from '@/components/prevent-navigation'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; +import { useIsUploadingFiles } from '@/components/ui/upload-button'; import { FormBook } from '@/features/book/manager/form-book'; import { FormBookCover } from '@/features/book/manager/form-book-cover'; @@ -43,6 +44,8 @@ export const PageBookUpdate = (props: { params: { id: string } }) => { }, }); + const isUploadingFiles = useIsUploadingFiles('bookCover'); + const bookUpdate = useMutation( orpc.book.updateById.mutationOptions({ onSuccess: async () => { @@ -93,6 +96,7 @@ export const PageBookUpdate = (props: { params: { id: string } }) => { size="sm" type="submit" className="min-w-20" + disabled={isUploadingFiles} loading={bookUpdate.isPending} > {t('book:manager.update.updateButton.label')} diff --git a/src/lib/s3/index.ts b/src/lib/s3/index.ts index 6f26f6ee9..19367a774 100644 --- a/src/lib/s3/index.ts +++ b/src/lib/s3/index.ts @@ -1,13 +1,12 @@ -import { S3Client } from '@aws-sdk/client-s3'; +import { minio } from '@better-upload/server/clients'; import { envServer } from '@/env/server'; -export const s3client = new S3Client({ +// cf. https://better-upload.com/docs/helpers-server#s3-clients to +// see all available clients. +export const uploadClient = minio({ endpoint: envServer.S3_ENDPOINT, - forcePathStyle: true, - credentials: { - accessKeyId: envServer.S3_ACCESS_KEY_ID, - secretAccessKey: envServer.S3_SECRET_ACCESS_KEY, - }, + accessKeyId: envServer.S3_ACCESS_KEY_ID, + secretAccessKey: envServer.S3_SECRET_ACCESS_KEY, region: envServer.S3_REGION, }); diff --git a/src/routes/api/upload.ts b/src/routes/api/upload.ts index 55026e8d4..8371ae423 100644 --- a/src/routes/api/upload.ts +++ b/src/routes/api/upload.ts @@ -1,65 +1,68 @@ -import { createFileRoute } from '@tanstack/react-router'; import { handleRequest, RejectUpload, route, type Router, -} from 'better-upload/server'; -import { mapValues } from 'remeda'; +} from '@better-upload/server'; +import { createFileRoute } from '@tanstack/react-router'; import i18n from '@/lib/i18n'; -import { s3client } from '@/lib/s3'; +import { uploadClient } from '@/lib/s3'; import { envServer } from '@/env/server'; import { auth } from '@/server/auth'; -export const uploadRoutes = { - bookCover: route({ - fileTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'], - maxFileSize: 1024 * 1024 * 100, // 100Mb - onBeforeUpload: async ({ req, file }) => { - const session = await auth.api.getSession({ headers: req.headers }); - if (!session?.user) { - throw new RejectUpload( - i18n.t('book:manager.uploadErrors.NOT_AUTHENTICATED') - ); - } +const router = { + client: uploadClient, + bucketName: envServer.S3_BUCKET_NAME, + routes: { + bookCover: route({ + // [TODO] Check to find a way to extract these rules so they can be reused in the accept field of file inputs + fileTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'], + maxFileSize: 1024 * 1024 * 100, // 100Mb + onBeforeUpload: async ({ req, file }) => { + const session = await auth.api.getSession(req); + if (!session?.user) { + throw new RejectUpload( + i18n.t('book:manager.uploadErrors.NOT_AUTHENTICATED') + ); + } - // Only admins should be able to update book covers - const canUpdateBookCover = await auth.api.userHasPermission({ - body: { - userId: session.user.id, - permissions: { - book: ['create', 'update'], + // Only admins should be able to update book covers + const canUpdateBookCover = await auth.api.userHasPermission({ + body: { + userId: session.user.id, + permissions: { + book: ['create', 'update'], + }, + role: 'admin', }, - role: 'admin', - }, - }); + }); - if (!canUpdateBookCover.success) { - throw new RejectUpload( - i18n.t('book:manager.uploadErrors.UNAUTHORIZED') - ); - } + if (!canUpdateBookCover.success) { + throw new RejectUpload( + i18n.t('book:manager.uploadErrors.UNAUTHORIZED') + ); + } - // normalize file extension from detected mimetype - const fileExtension = file.type.split('/').at(-1) as string; - return { - // I think it is a good idea to create a random file id as it impersonate the file name (which can contains sensitive data :/ ?) - objectInfo: { - key: `books/${crypto.randomUUID()}.${fileExtension}`, - }, - }; - }, - }), -} as const; -export const uploadRoutesName = mapValues(uploadRoutes, (_, key) => key); + // normalize file extension from detected mimetype (file.type) + const fileExtension = file.type.split('/').at(-1) as string; + return { + // I think it is a good idea to create a random file id + // This allow us to invalidate cache (because the id will always be random) + // and it also prevent the user to upload a file with the same name (aka. objectKey), but different file content + objectInfo: { + key: `books/${crypto.randomUUID()}.${fileExtension}`, + }, + }; + }, + }), + }, +} as const satisfies Router; -const router: Router = { - client: s3client, - bucketName: envServer.S3_BUCKET_NAME, - routes: uploadRoutes, -}; +// Used to type route param on UploadButton component +// This is to prevent typo issues when specifying the uploadRoute prop +export type UploadRoutes = keyof typeof router.routes; export const Route = createFileRoute('/api/upload')({ server: { diff --git a/src/server/routers/book.ts b/src/server/routers/book.ts index 03e6e6876..b261ac259 100644 --- a/src/server/routers/book.ts +++ b/src/server/routers/book.ts @@ -135,6 +135,7 @@ export default { author: input.author, genreId: input.genreId ?? undefined, publisher: input.publisher, + coverId: input.coverId, }, }); } catch (error: unknown) { From ef3bdef9da269d21ea7d65c1deab5a8cd33e542e Mon Sep 17 00:00:00 2001 From: Renan Decamps Date: Fri, 14 Nov 2025 15:53:13 +0100 Subject: [PATCH 7/8] fix: extract mime type --- src/features/book/manager/form-book-cover.tsx | 8 ++- src/features/book/schema.ts | 7 +++ src/routes/api/upload.ts | 52 ++----------------- src/server/upload/book-cover.ts | 45 ++++++++++++++++ 4 files changed, 61 insertions(+), 51 deletions(-) create mode 100644 src/server/upload/book-cover.ts diff --git a/src/features/book/manager/form-book-cover.tsx b/src/features/book/manager/form-book-cover.tsx index c309139c1..2906a770d 100644 --- a/src/features/book/manager/form-book-cover.tsx +++ b/src/features/book/manager/form-book-cover.tsx @@ -1,6 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { useFormContext, useWatch } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; +import { join } from 'remeda'; import { orpc } from '@/lib/orpc/client'; @@ -12,7 +13,10 @@ import { import { UploadButton } from '@/components/ui/upload-button'; import { BookCover } from '@/features/book/book-cover'; -import { FormFieldsBook } from '@/features/book/schema'; +import { + bookCoverAcceptedFileTypes, + FormFieldsBook, +} from '@/features/book/schema'; export const FormBookCover = () => { const { t } = useTranslation(['book']); @@ -61,7 +65,7 @@ export const FormBookCover = () => { zBook() .pick({ title: true, author: true, publisher: true, coverId: true }) .extend({ genreId: zu.fieldText.required() }); + +export const bookCoverAcceptedFileTypes = [ + 'image/png', + 'image/jpeg', + 'image/webp', + 'image/gif', +]; diff --git a/src/routes/api/upload.ts b/src/routes/api/upload.ts index 8371ae423..322748485 100644 --- a/src/routes/api/upload.ts +++ b/src/routes/api/upload.ts @@ -1,62 +1,16 @@ -import { - handleRequest, - RejectUpload, - route, - type Router, -} from '@better-upload/server'; +import { handleRequest, type Router } from '@better-upload/server'; import { createFileRoute } from '@tanstack/react-router'; -import i18n from '@/lib/i18n'; import { uploadClient } from '@/lib/s3'; import { envServer } from '@/env/server'; -import { auth } from '@/server/auth'; +import { bookCover } from '@/server/upload/book-cover'; const router = { client: uploadClient, bucketName: envServer.S3_BUCKET_NAME, routes: { - bookCover: route({ - // [TODO] Check to find a way to extract these rules so they can be reused in the accept field of file inputs - fileTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'], - maxFileSize: 1024 * 1024 * 100, // 100Mb - onBeforeUpload: async ({ req, file }) => { - const session = await auth.api.getSession(req); - if (!session?.user) { - throw new RejectUpload( - i18n.t('book:manager.uploadErrors.NOT_AUTHENTICATED') - ); - } - - // Only admins should be able to update book covers - const canUpdateBookCover = await auth.api.userHasPermission({ - body: { - userId: session.user.id, - permissions: { - book: ['create', 'update'], - }, - role: 'admin', - }, - }); - - if (!canUpdateBookCover.success) { - throw new RejectUpload( - i18n.t('book:manager.uploadErrors.UNAUTHORIZED') - ); - } - - // normalize file extension from detected mimetype (file.type) - const fileExtension = file.type.split('/').at(-1) as string; - return { - // I think it is a good idea to create a random file id - // This allow us to invalidate cache (because the id will always be random) - // and it also prevent the user to upload a file with the same name (aka. objectKey), but different file content - objectInfo: { - key: `books/${crypto.randomUUID()}.${fileExtension}`, - }, - }; - }, - }), + bookCover, }, } as const satisfies Router; diff --git a/src/server/upload/book-cover.ts b/src/server/upload/book-cover.ts new file mode 100644 index 000000000..6f8a7e8fe --- /dev/null +++ b/src/server/upload/book-cover.ts @@ -0,0 +1,45 @@ +import { RejectUpload, route } from '@better-upload/server'; + +import i18n from '@/lib/i18n'; + +import { bookCoverAcceptedFileTypes } from '@/features/book/schema'; +import { auth } from '@/server/auth'; + +export const bookCover = route({ + fileTypes: bookCoverAcceptedFileTypes, + maxFileSize: 1024 * 1024 * 100, // 100Mb + onBeforeUpload: async ({ req, file }) => { + const session = await auth.api.getSession(req); + if (!session?.user) { + throw new RejectUpload( + i18n.t('book:manager.uploadErrors.NOT_AUTHENTICATED') + ); + } + + // Only admins should be able to update book covers + const canUpdateBookCover = await auth.api.userHasPermission({ + body: { + userId: session.user.id, + permissions: { + book: ['create', 'update'], + }, + role: 'admin', + }, + }); + + if (!canUpdateBookCover.success) { + throw new RejectUpload(i18n.t('book:manager.uploadErrors.UNAUTHORIZED')); + } + + // normalize file extension from detected mimetype (file.type) + const fileExtension = file.type.split('/').at(-1) as string; + return { + // I think it is a good idea to create a random file id + // This allow us to invalidate cache (because the id will always be random) + // and it also prevent the user to upload a file with the same name (aka. objectKey), but different file content + objectInfo: { + key: `books/${crypto.randomUUID()}.${fileExtension}`, + }, + }; + }, +}); From 87cc5ca723818f766ca6fb6b186b61362ad10dda Mon Sep 17 00:00:00 2001 From: Renan Decamps Date: Mon, 17 Nov 2025 09:57:44 +0100 Subject: [PATCH 8/8] fix: add default url for S3_BUCKET - fix env var check for tests - make sure defaults are the same between .env.example and client.ts env var validator --- .env.example | 2 +- src/env/client.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 4f4962275..dea3f489d 100644 --- a/.env.example +++ b/.env.example @@ -13,7 +13,7 @@ DOCKER_MINIO_PASSWORD="minioadmin" # S3 S3_ENDPOINT="http://127.0.0.1:${DOCKER_MINIO_API_PORT}" -S3_BUCKET_NAME="start-ui-bucket" +S3_BUCKET_NAME="default" S3_ACCESS_KEY_ID="startui-access-key" S3_SECRET_ACCESS_KEY="startui-secret-key" S3_REGION="default" diff --git a/src/env/client.ts b/src/env/client.ts index 753d6a519..ca6508ba7 100644 --- a/src/env/client.ts +++ b/src/env/client.ts @@ -42,7 +42,13 @@ export const envClient = createEnv({ .string() .optional() .transform((value) => value ?? (isDev ? 'gold' : 'plum')), - VITE_S3_BUCKET_PUBLIC_URL: z.url(), + VITE_S3_BUCKET_PUBLIC_URL: z + .url() + .optional() + .transform( + (value) => + value ?? (isDev ? 'http://127.0.0.1:9000/default' : undefined) + ), }, runtimeEnv: { ...envMetaOrProcess,