diff --git a/package.json b/package.json index f445c5f3..a6f83e1e 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,9 @@ "typescript-eslint": "^8.46.3" }, "dependencies": { + "@aws-sdk/client-s3": "^3.926.0", + "@aws-sdk/s3-presigned-post": "^3.926.0", + "@aws-sdk/s3-request-presigner": "^3.926.0", "@keyv/redis": "^5.1.3", "@nestjs-modules/mailer": "^2.0.2", "@nestjs/cache-manager": "^3.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9fc4fb6b..5368e8c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,15 @@ importers: .: dependencies: + '@aws-sdk/client-s3': + specifier: ^3.926.0 + version: 3.926.0 + '@aws-sdk/s3-presigned-post': + specifier: ^3.926.0 + version: 3.926.0 + '@aws-sdk/s3-request-presigner': + specifier: ^3.926.0 + version: 3.926.0 '@keyv/redis': specifier: ^5.1.3 version: 5.1.3(keyv@5.5.3) @@ -298,6 +307,16 @@ packages: resolution: {integrity: sha512-ADfbaBsrG8mBF6Mfs+crKA/2ykB8AJI50Cv9tKmZfwcUcyAdmTr+vVvhsBCfvUAEokigSsgqgpYxfkJVxhJYeg==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@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==} @@ -311,6 +330,10 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + '@aws-sdk/client-s3@3.926.0': + resolution: {integrity: sha512-+J2oiUFJMKnPhaM4iCcJtsFwCpSS7veEYd/urZZTGaJOMuioEo2fnE0A/oxEVjCS8zgUr4EBbxHyHoBmjOGgcg==} + engines: {node: '>=18.0.0'} + '@aws-sdk/client-ses@3.922.0': resolution: {integrity: sha512-zZTOeyMk2BmqRETlnw9C4DXKGHjwzS4Bd8SmsaP1vBcFK6iIQHByhL1+Z4GGDUrxY5CdUmZYgmSOGh6ROL9r5w==} engines: {node: '>=18.0.0'} @@ -319,42 +342,94 @@ packages: resolution: {integrity: sha512-jdHs7uy7cSpiMvrxhYmqHyJxgK7hyqw4plG8OQ4YTBpq0SbfAxdoOuOkwJ1IVUUQho4otR1xYYjiX/8e8J8qwQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/client-sso@3.926.0': + resolution: {integrity: sha512-pu23ewGIP+U7LqwMIQw80HblQRJyKAZJiwYwFN5GyL5hquOCBWboKC6J8xQ/I7bzDYwnLQ+en+WBhhdUmOAAWw==} + engines: {node: '>=18.0.0'} + '@aws-sdk/core@3.922.0': resolution: {integrity: sha512-EvfP4cqJfpO3L2v5vkIlTkMesPtRwWlMfsaW6Tpfm7iYfBOuTi6jx60pMDMTyJNVfh6cGmXwh/kj1jQdR+w99Q==} engines: {node: '>=18.0.0'} + '@aws-sdk/core@3.926.0': + resolution: {integrity: sha512-Ee2mdBZV6+2DqJdjLa/cD6WxNIPFDD80b/moqucdlzg0jra274ibJg9b5gg2c93XF8TN0Vl7Z12uzH+tIvm6Lw==} + 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-env@3.926.0': + resolution: {integrity: sha512-oq5PfKT/2H7YlpHEyhZgTbVz8fkqaM4jvlwIQ6C6+5AghyS3PPfuEYIAZo9e5Ljnz+5pl44JbldBUbbBcUXwFg==} + 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-http@3.926.0': + resolution: {integrity: sha512-OXp96NUc+kxQ55q6ANYDFu/RyWrVL1pV58zpo+/QJO2LEJkUCsiV+m/PVkpgH27FXocTB2ja4TVQVgKfSuV2+Q==} + 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-ini@3.926.0': + resolution: {integrity: sha512-V9BBJBKN7pOVDpfDc2UUSevi+WuMLSwUF78WxSYr0URe5RHIdK/GtHhSeEhmRaX9UHHl2VJ0L3H47lHdtKQE3w==} + 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-node@3.926.0': + resolution: {integrity: sha512-Tf9JpidOWq4LcB/j66gWaYhQD5CB57HrKlKWqjyiQN5HAGQWRvG50dMD53F0Ka9Akr/P4Zg7ce4kZugd/GPy5w==} + 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-process@3.926.0': + resolution: {integrity: sha512-teBOtoZqP5mHGXq6eyarma9RDvON196KFTt0+dy4JPPAdBen1LUovGad+HFDPn8akX1fnWnYxWmsQ2j2tbVseA==} + 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-sso@3.926.0': + resolution: {integrity: sha512-W+Ji7CmANmJN8KAu+2KO4nidHBkTHVFcR5DEQwXe+q2O9II0QCeuC/BplqaHC/qKiGNeJB/UcjAJUzIYBe5KXA==} + 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/credential-provider-web-identity@3.926.0': + resolution: {integrity: sha512-Nl5bK5QTb3RfAhEZfjPtXPa7NA/vz8SONG91QdZ0hVcA9EJX4cp2NeNOUCu39isvSKfefJhCWipdPl7SHLGWAA==} + 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.926.0': + resolution: {integrity: sha512-B2tKOHLKPQcce3+DLzZSQJkkmzdhoCM+tg9zvJmJQne8royS81goohXqxHLh1dIENZ03BN99qHRbRa+xPpFpTQ==} + 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.922.0': resolution: {integrity: sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg==} engines: {node: '>=18.0.0'} @@ -363,30 +438,74 @@ packages: resolution: {integrity: sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-sdk-s3@3.926.0': + resolution: {integrity: sha512-qDBKyaSYMMJWgGq7ktzdnGEIOADs16DEvdTLeA0ZWTzw0xM+jH9c38GoIaK5bPd80ALrV3hVKV3nsUwR2Kze9Q==} + 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.922.0': resolution: {integrity: sha512-N4Qx/9KP3oVQBJOrSghhz8iZFtUC2NNeSZt88hpPhbqAEAtuX8aD8OzVcpnAtrwWqy82Yd2YTxlkqMGkgqnBsQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-user-agent@3.926.0': + resolution: {integrity: sha512-BDcQ+UuxHXf2eRaEKrMDvuxpfTM2gbFWGP4RImgV37vdRmg3OpGDsS6CmcYpknlSM2fwcKPe08AlsU7tuQ8xQQ==} + 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/nested-clients@3.926.0': + resolution: {integrity: sha512-QdI61A9Jp0xZdD2GhFqc1UlER5QXrMWr9fo4Ig2inHng2AlNY/d2rextnRg6oCEF1PvVnnmwpre9X5Pr7eYV5g==} + 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/region-config-resolver@3.925.0': + resolution: {integrity: sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/s3-presigned-post@3.926.0': + resolution: {integrity: sha512-PEvJGhp0HpTCYIh4P+hbr7ticDrRCvjubinYexN3hbCn9jk8Xbu3xqjD08m6iR2Hd4RZu/y/2LdebIODj6kFug==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/s3-request-presigner@3.926.0': + resolution: {integrity: sha512-g+vzEr2Vhj8GUWobHedjeAQ4LmZkxvYShtOagno09Td1lanIFJLYWrOsppBH3edpj1z4pmBNPOAs730FstahdA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.926.0': + resolution: {integrity: sha512-CYpgaSeM1qWof3REoBC/iI+rgURWjsYmpbshRHUGkKPo+Cuo3ibiKxdScbxF8fMaEs+uc/Hqiuqe43hxRL2W0g==} + engines: {node: '>=18.0.0'} + '@aws-sdk/token-providers@3.922.0': resolution: {integrity: sha512-/inmPnjZE0ZBE16zaCowAvouSx05FJ7p6BQYuzlJ8vxEU0sS0Hf8fvhuiRnN9V9eDUPIBY+/5EjbMWygXL4wlQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/token-providers@3.926.0': + resolution: {integrity: sha512-Z6xdrX5XW4DWV25cVBZ8CqzlJMzXPF/tzjhU6uTA9upsN6tsJrALW0X+Bb+ry47HkIKSSsTT1Qhw2uSPhcSxiA==} + 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'} + '@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'} @@ -403,6 +522,15 @@ packages: aws-crt: optional: true + '@aws-sdk/util-user-agent-node@3.926.0': + resolution: {integrity: sha512-W3juPm5KK5gRo/7Nh99vcnWsWnCQlfz8BpOZ+GfvXKB3FDSeH71tDvVkB51fE+a54BobbotvUPtN35Ruf7Y0qg==} + engines: {node: '>=18.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + '@aws-sdk/xml-builder@3.921.0': resolution: {integrity: sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q==} engines: {node: '>=18.0.0'} @@ -1611,10 +1739,22 @@ packages: 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.4.1': resolution: {integrity: sha512-BciDJ5hkyYEGBBKMbjGB1A/Zq8bYZ41Zo9BMnGdKF6QD1fY4zIkYx6zui/0CHaVGnv6h0iy8y4rnPX9CPCAPyQ==} 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.17.2': resolution: {integrity: sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ==} engines: {node: '>=18.0.0'} @@ -1623,14 +1763,42 @@ packages: 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.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.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.4': resolution: {integrity: sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw==} engines: {node: '>=18.0.0'} @@ -1643,6 +1811,10 @@ 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.4': resolution: {integrity: sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow==} engines: {node: '>=18.0.0'} @@ -1743,6 +1915,10 @@ packages: resolution: {integrity: sha512-6hinjVqec0WYGsqN7h9hL/ywfULmJJNXGXnNZW7jrIn/cFuC/aVlVaiDfBIJEvKcOrmN8/EgsW69eY0gXABeHw==} 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.4': resolution: {integrity: sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg==} engines: {node: '>=18.0.0'} @@ -5969,6 +6145,27 @@ snapshots: transitivePeerDependencies: - chokidar + '@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 @@ -5995,6 +6192,68 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 + '@aws-sdk/client-s3@3.926.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.926.0 + '@aws-sdk/credential-provider-node': 3.926.0 + '@aws-sdk/middleware-bucket-endpoint': 3.922.0 + '@aws-sdk/middleware-expect-continue': 3.922.0 + '@aws-sdk/middleware-flexible-checksums': 3.926.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.926.0 + '@aws-sdk/middleware-ssec': 3.922.0 + '@aws-sdk/middleware-user-agent': 3.926.0 + '@aws-sdk/region-config-resolver': 3.925.0 + '@aws-sdk/signature-v4-multi-region': 3.926.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.926.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-ses@3.922.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -6083,6 +6342,49 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/client-sso@3.926.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.926.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.926.0 + '@aws-sdk/region-config-resolver': 3.925.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.926.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.922.0': dependencies: '@aws-sdk/types': 3.922.0 @@ -6099,6 +6401,22 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@aws-sdk/core@3.926.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.922.0': dependencies: '@aws-sdk/core': 3.922.0 @@ -6107,6 +6425,14 @@ snapshots: '@smithy/types': 4.8.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.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.922.0': dependencies: '@aws-sdk/core': 3.922.0 @@ -6120,6 +6446,19 @@ snapshots: '@smithy/util-stream': 4.5.5 tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.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.922.0': dependencies: '@aws-sdk/core': 3.922.0 @@ -6138,6 +6477,24 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.0 + '@aws-sdk/credential-provider-env': 3.926.0 + '@aws-sdk/credential-provider-http': 3.926.0 + '@aws-sdk/credential-provider-process': 3.926.0 + '@aws-sdk/credential-provider-sso': 3.926.0 + '@aws-sdk/credential-provider-web-identity': 3.926.0 + '@aws-sdk/nested-clients': 3.926.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.922.0': dependencies: '@aws-sdk/credential-provider-env': 3.922.0 @@ -6155,6 +6512,23 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.926.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.926.0 + '@aws-sdk/credential-provider-http': 3.926.0 + '@aws-sdk/credential-provider-ini': 3.926.0 + '@aws-sdk/credential-provider-process': 3.926.0 + '@aws-sdk/credential-provider-sso': 3.926.0 + '@aws-sdk/credential-provider-web-identity': 3.926.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.922.0': dependencies: '@aws-sdk/core': 3.922.0 @@ -6164,6 +6538,15 @@ snapshots: '@smithy/types': 4.8.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.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.922.0': dependencies: '@aws-sdk/client-sso': 3.922.0 @@ -6177,6 +6560,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-sso@3.926.0': + dependencies: + '@aws-sdk/client-sso': 3.926.0 + '@aws-sdk/core': 3.926.0 + '@aws-sdk/token-providers': 3.926.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.922.0': dependencies: '@aws-sdk/core': 3.922.0 @@ -6189,6 +6585,51 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-web-identity@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.0 + '@aws-sdk/nested-clients': 3.926.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.926.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/core': 3.926.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.922.0': dependencies: '@aws-sdk/types': 3.922.0 @@ -6196,6 +6637,12 @@ snapshots: '@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.922.0': dependencies: '@aws-sdk/types': 3.922.0 @@ -6210,6 +6657,29 @@ snapshots: '@smithy/types': 4.8.1 tslib: 2.8.1 + '@aws-sdk/middleware-sdk-s3@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.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.922.0': dependencies: '@aws-sdk/core': 3.922.0 @@ -6220,6 +6690,16 @@ snapshots: '@smithy/types': 4.8.1 tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.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.922.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -6263,6 +6743,49 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/nested-clients@3.926.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.926.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.926.0 + '@aws-sdk/region-config-resolver': 3.925.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.926.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.922.0': dependencies: '@aws-sdk/types': 3.922.0 @@ -6271,6 +6794,48 @@ snapshots: '@smithy/types': 4.8.1 tslib: 2.8.1 + '@aws-sdk/region-config-resolver@3.925.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-presigned-post@3.926.0': + dependencies: + '@aws-sdk/client-s3': 3.926.0 + '@aws-sdk/types': 3.922.0 + '@aws-sdk/util-format-url': 3.922.0 + '@smithy/middleware-endpoint': 4.3.6 + '@smithy/signature-v4': 5.3.4 + '@smithy/types': 4.8.1 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/s3-request-presigner@3.926.0': + dependencies: + '@aws-sdk/signature-v4-multi-region': 3.926.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.926.0': + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.926.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.922.0': dependencies: '@aws-sdk/core': 3.922.0 @@ -6283,11 +6848,27 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/token-providers@3.926.0': + dependencies: + '@aws-sdk/core': 3.926.0 + '@aws-sdk/nested-clients': 3.926.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.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 + '@aws-sdk/util-endpoints@3.922.0': dependencies: '@aws-sdk/types': 3.922.0 @@ -6296,6 +6877,13 @@ snapshots: '@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 @@ -6315,6 +6903,14 @@ snapshots: '@smithy/types': 4.8.1 tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.926.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.926.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.921.0': dependencies: '@smithy/types': 4.8.1 @@ -7720,6 +8316,15 @@ snapshots: '@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.4.1': dependencies: '@smithy/node-config-provider': 4.3.4 @@ -7729,6 +8334,15 @@ snapshots: '@smithy/util-middleware': 4.2.4 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.17.2': dependencies: '@smithy/middleware-serde': 4.2.4 @@ -7750,6 +8364,36 @@ snapshots: '@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.5': dependencies: '@smithy/protocol-http': 5.3.4 @@ -7758,6 +8402,13 @@ snapshots: '@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.4': dependencies: '@smithy/types': 4.8.1 @@ -7765,6 +8416,12 @@ snapshots: '@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.4': dependencies: '@smithy/types': 4.8.1 @@ -7778,6 +8435,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.4': dependencies: '@smithy/protocol-http': 5.3.4 @@ -7939,6 +8602,16 @@ snapshots: '@smithy/types': 4.8.1 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.4': dependencies: '@smithy/node-config-provider': 4.3.4 diff --git a/src/files/files.service.ts b/src/files/files.service.ts index dfb5f3d4..99ed8c43 100644 --- a/src/files/files.service.ts +++ b/src/files/files.service.ts @@ -1,17 +1,24 @@ import { HttpStatus, Injectable } from '@nestjs/common'; -import { AwsClient } from 'aws4fetch'; import { ConfigService } from '@nestjs/config'; import { Repository } from 'typeorm'; import { File } from './entities/file.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { AppException } from 'omniboxd/common/exceptions/app.exception'; import { I18nService } from 'nestjs-i18n'; +import { S3Client } from '@aws-sdk/client-s3'; +import { createPresignedPost, PresignedPost } from '@aws-sdk/s3-presigned-post'; +import { AwsClient } from 'aws4fetch'; +import { formatFileSize } from '../utils/format-file-size'; @Injectable() export class FilesService { private readonly awsClient: AwsClient; private readonly s3Url: URL; private readonly s3InternalUrl: URL; + private readonly s3Client: S3Client; + private readonly s3Bucket: string; + private readonly s3Prefix: string; + private readonly s3MaxFileSize: number; constructor( configService: ConfigService, @@ -43,9 +50,39 @@ export class FilesService { s3InternalUrl += '/'; } + const s3Endpoint = configService.get('OBB_S3_ENDPOINT'); + if (!s3Endpoint) { + throw new Error('S3 endpoint not set'); + } + + const s3Bucket = configService.get('OBB_S3_BUCKET'); + if (!s3Bucket) { + throw new Error('S3 bucket not set'); + } + + const s3Prefix = configService.get('OBB_S3_PREFIX'); + if (!s3Prefix) { + throw new Error('S3 prefix not set'); + } + this.awsClient = new AwsClient({ accessKeyId, secretAccessKey }); this.s3Url = new URL(s3Url); this.s3InternalUrl = new URL(s3InternalUrl); + this.s3MaxFileSize = configService.get( + 'OBB_S3_MAX_FILE_SIZE', + 20 * 1024 * 1024, + ); + const s3Region = configService.get('OBB_S3_REGION', 'us-east-1'); + this.s3Client = new S3Client({ + region: s3Region, + credentials: { + accessKeyId, + secretAccessKey, + }, + endpoint: s3Endpoint, + }); + this.s3Bucket = s3Bucket; + this.s3Prefix = s3Prefix; } async createFile( @@ -81,6 +118,38 @@ export class FilesService { return signedReq.url; } + async generatePostForm( + fileId: string, + fileSize: number | undefined, + filename: string, + mimetype: string, + ): Promise { + if (fileSize && fileSize > this.s3MaxFileSize) { + const message = this.i18n.t('resource.errors.fileTooLarge', { + args: { + userSize: formatFileSize(fileSize), + limitSize: formatFileSize(this.s3MaxFileSize), + }, + }); + throw new AppException(message, 'FILE_TOO_LARGE', HttpStatus.BAD_REQUEST); + } + const disposition = `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`; + return await createPresignedPost(this.s3Client, { + Bucket: this.s3Bucket, + Key: `${this.s3Prefix}/${fileId}`, + Conditions: [ + ['content-length-range', 0, this.s3MaxFileSize], + { 'content-type': mimetype }, + { 'content-disposition': disposition }, + ], + Fields: { + 'content-type': mimetype, + 'content-disposition': disposition, + }, + Expires: 900, // 900 seconds + }); + } + private async generateDownloadUrl( namespaceId: string, fileId: string, diff --git a/src/i18n/en/resource.json b/src/i18n/en/resource.json index 6c26f5f9..a9230035 100644 --- a/src/i18n/en/resource.json +++ b/src/i18n/en/resource.json @@ -4,6 +4,7 @@ "parentOrResourceIdRequired": "parent_id or resource_id is required", "resourceNotFound": "Resource not found", "fileNotFound": "File not found", + "fileTooLarge": "Your file ({userSize}) exceeds the maximum limit of {limitSize}", "cannotDeleteRoot": "Cannot delete root resource", "cannotDuplicateRoot": "Cannot duplicate root resource", "cannotRestoreRoot": "Cannot restore root resource", diff --git a/src/i18n/zh/resource.json b/src/i18n/zh/resource.json index 86a30d4d..591593a6 100644 --- a/src/i18n/zh/resource.json +++ b/src/i18n/zh/resource.json @@ -4,6 +4,7 @@ "parentOrResourceIdRequired": "需要 parent_id 或 resource_id", "resourceNotFound": "资源未找到", "fileNotFound": "文件未找到", + "fileTooLarge": "您的文件({userSize})超过最大限制 {limitSize}", "cannotDeleteRoot": "无法删除根资源", "cannotDuplicateRoot": "无法复制根资源", "cannotRestoreRoot": "无法恢复根资源", diff --git a/src/namespace-resources/dto/create-file-req.dto.ts b/src/namespace-resources/dto/create-file-req.dto.ts index e042880b..082ae3a6 100644 --- a/src/namespace-resources/dto/create-file-req.dto.ts +++ b/src/namespace-resources/dto/create-file-req.dto.ts @@ -1,5 +1,11 @@ import { Expose } from 'class-transformer'; -import { IsNotEmpty, IsString } from 'class-validator'; +import { + IsNotEmpty, + IsNumber, + IsOptional, + IsString, + Min, +} from 'class-validator'; export class CreateFileReqDto { @Expose() @@ -11,4 +17,10 @@ export class CreateFileReqDto { @IsString() @IsNotEmpty() mimetype: string; + + @Expose() + @IsNumber() + @Min(1) + @IsOptional() + size?: number; } diff --git a/src/namespace-resources/dto/file-info.dto.ts b/src/namespace-resources/dto/file-info.dto.ts index bce1fb62..0904301c 100644 --- a/src/namespace-resources/dto/file-info.dto.ts +++ b/src/namespace-resources/dto/file-info.dto.ts @@ -7,10 +7,25 @@ export class FileInfoDto { @Expose() url: string; - static new(id: string, url: string) { + @Expose({ name: 'post_url' }) + postUrl?: string; + + @Expose({ name: 'post_fields' }) + postFields?: [string, string][]; + + static new( + id: string, + url: string, + postUrl?: string, + postFields?: Record, + ) { const dto = new FileInfoDto(); dto.id = id; dto.url = url; + dto.postUrl = postUrl; + if (postFields) { + dto.postFields = Object.entries(postFields); + } return dto; } } diff --git a/src/namespace-resources/file-resources.e2e-spec.ts b/src/namespace-resources/file-resources.e2e-spec.ts index d6ff3c07..c7061ea7 100644 --- a/src/namespace-resources/file-resources.e2e-spec.ts +++ b/src/namespace-resources/file-resources.e2e-spec.ts @@ -26,12 +26,13 @@ describe('FileResourcesController (e2e)', () => { test.each(uploadLanguageDatasets)( 'upload and download file: $filename', - async ({ filename }) => { + async ({ filename, content }) => { const uploadRes = await client .post(`/api/v1/namespaces/${client.namespace.id}/resources/files`) .send({ name: filename, mimetype: 'text/plain', + size: content.length, }); expect(uploadRes.status).toBe(201); }, diff --git a/src/namespace-resources/namespace-resources.service.ts b/src/namespace-resources/namespace-resources.service.ts index c43566c6..7c0f8c89 100644 --- a/src/namespace-resources/namespace-resources.service.ts +++ b/src/namespace-resources/namespace-resources.service.ts @@ -715,7 +715,13 @@ export class NamespaceResourcesService { createReq.mimetype, ); const url = await this.filesService.generateUploadUrl(file.id); - return FileInfoDto.new(file.id, url); + const postReq = await this.filesService.generatePostForm( + file.id, + createReq.size, + file.name, + file.mimetype, + ); + return FileInfoDto.new(file.id, url, postReq.url, postReq.fields); } async update(userId: string, resourceId: string, data: UpdateResourceDto) { diff --git a/src/utils/format-file-size.spec.ts b/src/utils/format-file-size.spec.ts new file mode 100644 index 00000000..d31bd2ca --- /dev/null +++ b/src/utils/format-file-size.spec.ts @@ -0,0 +1,30 @@ +import { formatFileSize } from './format-file-size'; + +describe('formatFileSize', () => { + it('should format bytes correctly', () => { + expect(formatFileSize(0)).toBe('0 B'); + expect(formatFileSize(100)).toBe('100 B'); + expect(formatFileSize(1023)).toBe('1023 B'); + }); + + it('should format kilobytes correctly', () => { + expect(formatFileSize(1024)).toBe('1.0 KB'); + expect(formatFileSize(1536)).toBe('1.5 KB'); + expect(formatFileSize(10240)).toBe('10.0 KB'); + }); + + it('should format megabytes correctly', () => { + expect(formatFileSize(1024 * 1024)).toBe('1.0 MB'); + expect(formatFileSize(20 * 1024 * 1024)).toBe('20.0 MB'); + expect(formatFileSize(1.5 * 1024 * 1024)).toBe('1.5 MB'); + }); + + it('should format gigabytes correctly', () => { + expect(formatFileSize(1024 * 1024 * 1024)).toBe('1.0 GB'); + expect(formatFileSize(2.5 * 1024 * 1024 * 1024)).toBe('2.5 GB'); + }); + + it('should format terabytes correctly', () => { + expect(formatFileSize(1024 * 1024 * 1024 * 1024)).toBe('1.0 TB'); + }); +}); diff --git a/src/utils/format-file-size.ts b/src/utils/format-file-size.ts new file mode 100644 index 00000000..0741808c --- /dev/null +++ b/src/utils/format-file-size.ts @@ -0,0 +1,17 @@ +/** + * Format file size in bytes to human-readable format + * @param bytes - File size in bytes + * @returns Human-readable file size string (e.g., "20 MB", "1.5 GB") + */ +export function formatFileSize(bytes: number): string { + if (bytes === 0) return '0 B'; + + const units = ['B', 'KB', 'MB', 'GB', 'TB']; + const k = 1024; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + + const size = bytes / Math.pow(k, i); + const formattedSize = i === 0 ? size.toString() : size.toFixed(1); + + return `${formattedSize} ${units[i]}`; +} diff --git a/test/jest-e2e-setup.ts b/test/jest-e2e-setup.ts index 30bb6f39..ef35719a 100644 --- a/test/jest-e2e-setup.ts +++ b/test/jest-e2e-setup.ts @@ -64,6 +64,9 @@ export default async () => { process.env.OBB_S3_ACCESS_KEY_ID = 'minioadmin'; process.env.OBB_S3_SECRET_ACCESS_KEY = 'minioadmin'; process.env.OBB_S3_URL = `http://${minioContainer.getHost()}:${minioContainer.getMappedPort(9000)}`; + process.env.OBB_S3_ENDPOINT = `http://${minioContainer.getHost()}:${minioContainer.getMappedPort(9000)}`; + process.env.OBB_S3_BUCKET = 'omnibox-test'; + process.env.OBB_S3_PREFIX = 'uploaded-files'; process.env.OBB_MAIL_TRANSPORT = mailTransport; process.env.OBB_MAIL_FROM = '"Test "';