From 1784abbccae1014bae7bab7b3fd895d447bce47d Mon Sep 17 00:00:00 2001
From: Maria Sauer <mcs22@inf.ufpr.br>
Date: Fri, 21 Feb 2025 13:21:38 -0300
Subject: [PATCH] colocado s3

---
 .env.example               |    8 +-
 2                          |  Bin 0 -> 8877 bytes
 alterContentsS3ACL.sh      |    9 +
 package.json               |    2 +
 pnpm-lock.yaml             | 1270 ++++++++++++++++++++++++++++++++++++
 src/env.ts                 |    4 +
 src/index.ts               |    2 +
 src/routes/s3.route.ts     |  363 +++++++++++
 src/services/config.ts     |    2 +
 src/services/s3.service.ts |  129 ++++
 10 files changed, 1788 insertions(+), 1 deletion(-)
 create mode 100644 2
 create mode 100755 alterContentsS3ACL.sh
 create mode 100644 src/routes/s3.route.ts
 create mode 100644 src/services/s3.service.ts

diff --git a/.env.example b/.env.example
index 354969e..83dc1cc 100644
--- a/.env.example
+++ b/.env.example
@@ -9,4 +9,10 @@ DB_PORT=5432
 DB_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
 
 # secret
-APP_SECRET=0crebI8PUWwj9E+GRzIGpBt64MwY9ufkBzBkYSH2v+Y=
\ No newline at end of file
+APP_SECRET=0crebI8PUWwj9E+GRzIGpBt64MwY9ufkBzBkYSH2v+Y=
+
+#s3
+AWS_ACCESS_KEY_ID=ACCESS_KEY
+AWS_SECRET_ACCESS_KEY=SECRET_KEY
+AWS_REGION=default
+S3_BUCKET=BUCKET_NAME
diff --git a/2 b/2
new file mode 100644
index 0000000000000000000000000000000000000000..34d7c925d56590fca89fde0b2523d7530bef0478
GIT binary patch
literal 8877
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
P_HTItPhE(W|9=wzf*=f;

literal 0
HcmV?d00001

diff --git a/alterContentsS3ACL.sh b/alterContentsS3ACL.sh
new file mode 100755
index 0000000..a35b830
--- /dev/null
+++ b/alterContentsS3ACL.sh
@@ -0,0 +1,9 @@
+bucket=mecred
+acl=public-read
+endpoint=https://s3.c3sl.ufpr.br
+objects=$(aws --endpoint-url=${endpoint} s3api list-objects --bucket ${bucket} |\
+        grep -i key | cut -d':' -f2 | sed 's/,//' | sed 's/"//g')
+
+for object in ${objects}; do
+    aws --endpoint-url=${endpoint} s3api put-object-acl --bucket ${bucket} --key ${object}  --acl ${acl};
+done;
diff --git a/package.json b/package.json
index 2da5428..09493e4 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
     "route:test": "bun db:seed && bun test"
   },
   "dependencies": {
+    "@aws-sdk/client-s3": "^3.750.0",
     "@hono/swagger-ui": "^0.5.0",
     "@hono/zod-openapi": "^0.18.3",
     "@hono/zod-validator": "^0.2.2",
@@ -16,6 +17,7 @@
     "dotenv-expand": "^11.0.6",
     "drizzle-orm": "^0.31.2",
     "drizzle-zod": "^0.5.1",
+    "file-type": "^20.1.0",
     "hono": "^4.4.8",
     "postgres": "^3.4.4",
     "reflect-metadata": "^0.2.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a404230..44b8d2b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,6 +8,9 @@ importers:
 
   .:
     dependencies:
+      '@aws-sdk/client-s3':
+        specifier: ^3.750.0
+        version: 3.750.0
       '@hono/swagger-ui':
         specifier: ^0.5.0
         version: 0.5.0(hono@4.6.1)
@@ -29,6 +32,9 @@ importers:
       drizzle-zod:
         specifier: ^0.5.1
         version: 0.5.1(drizzle-orm@0.31.4(bun-types@1.1.27)(postgres@3.4.4))(zod@3.23.8)
+      file-type:
+        specifier: ^20.1.0
+        version: 20.1.0
       hono:
         specifier: ^4.4.8
         version: 4.6.1
@@ -80,6 +86,157 @@ packages:
     peerDependencies:
       zod: ^3.20.2
 
+  '@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==}
+
+  '@aws-crypto/sha256-js@5.2.0':
+    resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==}
+    engines: {node: '>=16.0.0'}
+
+  '@aws-crypto/supports-web-crypto@5.2.0':
+    resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==}
+
+  '@aws-crypto/util@5.2.0':
+    resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==}
+
+  '@aws-sdk/client-s3@3.750.0':
+    resolution: {integrity: sha512-S9G9noCeBxchoMVkHYrRi1A1xW/VOTP2W7X34lP+Y7Wpl32yMA7IJo0fAGAuTc0q1Nu6/pXDm+oDG7rhTCA1tg==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/client-sso@3.750.0':
+    resolution: {integrity: sha512-y0Rx6pTQXw0E61CaptpZF65qNggjqOgymq/RYZU5vWba5DGQ+iqGt8Yq8s+jfBoBBNXshxq8l8Dl5Uq/JTY1wg==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/core@3.750.0':
+    resolution: {integrity: sha512-bZ5K7N5L4+Pa2epbVpUQqd1XLG2uU8BGs/Sd+2nbgTf+lNQJyIxAg/Qsrjz9MzmY8zzQIeRQEkNmR6yVAfCmmQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/credential-provider-env@3.750.0':
+    resolution: {integrity: sha512-In6bsG0p/P31HcH4DBRKBbcDS/3SHvEPjfXV8ODPWZO/l3/p7IRoYBdQ07C9R+VMZU2D0+/Sc/DWK/TUNDk1+Q==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/credential-provider-http@3.750.0':
+    resolution: {integrity: sha512-wFB9qqfa20AB0dElsQz5ZlZT5o+a+XzpEpmg0erylmGYqEOvh8NQWfDUVpRmQuGq9VbvW/8cIbxPoNqEbPtuWQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/credential-provider-ini@3.750.0':
+    resolution: {integrity: sha512-2YIZmyEr5RUd3uxXpxOLD9G67Bibm4I/65M6vKFP17jVMUT+R1nL7mKqmhEVO2p+BoeV+bwMyJ/jpTYG368PCg==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/credential-provider-node@3.750.0':
+    resolution: {integrity: sha512-THWHHAceLwsOiowPEmKyhWVDlEUxH07GHSw5AQFDvNQtGKOQl0HSIFO1mKObT2Q2Vqzji9Bq8H58SO5BFtNPRw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/credential-provider-process@3.750.0':
+    resolution: {integrity: sha512-Q78SCH1n0m7tpu36sJwfrUSxI8l611OyysjQeMiIOliVfZICEoHcLHLcLkiR+tnIpZ3rk7d2EQ6R1jwlXnalMQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/credential-provider-sso@3.750.0':
+    resolution: {integrity: sha512-FGYrDjXN/FOQVi/t8fHSv8zCk+NEvtFnuc4cZUj5OIbM4vrfFc5VaPyn41Uza3iv6Qq9rZg0QOwWnqK8lNrqUw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/credential-provider-web-identity@3.750.0':
+    resolution: {integrity: sha512-Nz8zs3YJ+GOTSrq+LyzbbC1Ffpt7pK38gcOyNZv76pP5MswKTUKNYBJehqwa+i7FcFQHsCk3TdhR8MT1ZR23uA==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-bucket-endpoint@3.734.0':
+    resolution: {integrity: sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-expect-continue@3.734.0':
+    resolution: {integrity: sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-flexible-checksums@3.750.0':
+    resolution: {integrity: sha512-ach0d2buDnX2TUausUbiXXFWFo3IegLnCrA+Rw8I9AYVpLN9lTaRwAYJwYC6zEuW9Golff8MwkYsp/OaC5tKMw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-host-header@3.734.0':
+    resolution: {integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-location-constraint@3.734.0':
+    resolution: {integrity: sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-logger@3.734.0':
+    resolution: {integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-recursion-detection@3.734.0':
+    resolution: {integrity: sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-sdk-s3@3.750.0':
+    resolution: {integrity: sha512-3H6Z46cmAQCHQ0z8mm7/cftY5ifiLfCjbObrbyyp2fhQs9zk6gCKzIX8Zjhw0RMd93FZi3ebRuKJWmMglf4Itw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-ssec@3.734.0':
+    resolution: {integrity: sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/middleware-user-agent@3.750.0':
+    resolution: {integrity: sha512-YYcslDsP5+2NZoN3UwuhZGkhAHPSli7HlJHBafBrvjGV/I9f8FuOO1d1ebxGdEP4HyRXUGyh+7Ur4q+Psk0ryw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/nested-clients@3.750.0':
+    resolution: {integrity: sha512-OH68BRF0rt9nDloq4zsfeHI0G21lj11a66qosaljtEP66PWm7tQ06feKbFkXHT5E1K3QhJW3nVyK8v2fEBY5fg==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/region-config-resolver@3.734.0':
+    resolution: {integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/signature-v4-multi-region@3.750.0':
+    resolution: {integrity: sha512-RA9hv1Irro/CrdPcOEXKwJ0DJYJwYCsauGEdRXihrRfy8MNSR9E+mD5/Fr5Rxjaq5AHM05DYnN3mg/DU6VwzSw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/token-providers@3.750.0':
+    resolution: {integrity: sha512-X/KzqZw41iWolwNdc8e3RMcNSMR364viHv78u6AefXOO5eRM40c4/LuST1jDzq35/LpnqRhL7/MuixOetw+sFw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/types@3.734.0':
+    resolution: {integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/util-arn-parser@3.723.0':
+    resolution: {integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/util-endpoints@3.743.0':
+    resolution: {integrity: sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/util-locate-window@3.723.0':
+    resolution: {integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==}
+    engines: {node: '>=18.0.0'}
+
+  '@aws-sdk/util-user-agent-browser@3.734.0':
+    resolution: {integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==}
+
+  '@aws-sdk/util-user-agent-node@3.750.0':
+    resolution: {integrity: sha512-84HJj9G9zbrHX2opLk9eHfDceB+UIHVrmflMzWHpsmo9fDuro/flIBqaVDlE021Osj6qIM0SJJcnL6s23j7JEw==}
+    engines: {node: '>=18.0.0'}
+    peerDependencies:
+      aws-crt: '>=1.0.0'
+    peerDependenciesMeta:
+      aws-crt:
+        optional: true
+
+  '@aws-sdk/xml-builder@3.734.0':
+    resolution: {integrity: sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==}
+    engines: {node: '>=18.0.0'}
+
   '@esbuild-kit/core-utils@3.3.2':
     resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==}
     deprecated: 'Merged into tsx: https://tsx.is'
@@ -432,6 +589,225 @@ packages:
     resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
     engines: {node: '>= 8'}
 
+  '@smithy/abort-controller@4.0.1':
+    resolution: {integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/chunked-blob-reader-native@4.0.0':
+    resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/chunked-blob-reader@5.0.0':
+    resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/config-resolver@4.0.1':
+    resolution: {integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/core@3.1.4':
+    resolution: {integrity: sha512-wFExFGK+7r2wYriOqe7RRIBNpvxwiS95ih09+GSLRBdoyK/O1uZA7K7pKesj5CBvwJuSBeXwLyR88WwIAY+DGA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/credential-provider-imds@4.0.1':
+    resolution: {integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/eventstream-codec@4.0.1':
+    resolution: {integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/eventstream-serde-browser@4.0.1':
+    resolution: {integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/eventstream-serde-config-resolver@4.0.1':
+    resolution: {integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/eventstream-serde-node@4.0.1':
+    resolution: {integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/eventstream-serde-universal@4.0.1':
+    resolution: {integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/fetch-http-handler@5.0.1':
+    resolution: {integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/hash-blob-browser@4.0.1':
+    resolution: {integrity: sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/hash-node@4.0.1':
+    resolution: {integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/hash-stream-node@4.0.1':
+    resolution: {integrity: sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/invalid-dependency@4.0.1':
+    resolution: {integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/is-array-buffer@2.2.0':
+    resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/is-array-buffer@4.0.0':
+    resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/md5-js@4.0.1':
+    resolution: {integrity: sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/middleware-content-length@4.0.1':
+    resolution: {integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/middleware-endpoint@4.0.5':
+    resolution: {integrity: sha512-cPzGZV7qStHwboFrm6GfrzQE+YDiCzWcTh4+7wKrP/ZQ4gkw+r7qDjV8GjM4N0UYsuUyLfpzLGg5hxsYTU11WA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/middleware-retry@4.0.6':
+    resolution: {integrity: sha512-s8QzuOQnbdvRymD9Gt9c9zMq10wUQAHQ3z72uirrBHCwZcLTrL5iCOuVTMdka2IXOYhQE890WD5t6G24+F+Qcg==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/middleware-serde@4.0.2':
+    resolution: {integrity: sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/middleware-stack@4.0.1':
+    resolution: {integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/node-config-provider@4.0.1':
+    resolution: {integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/node-http-handler@4.0.2':
+    resolution: {integrity: sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/property-provider@4.0.1':
+    resolution: {integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/protocol-http@5.0.1':
+    resolution: {integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/querystring-builder@4.0.1':
+    resolution: {integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/querystring-parser@4.0.1':
+    resolution: {integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/service-error-classification@4.0.1':
+    resolution: {integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/shared-ini-file-loader@4.0.1':
+    resolution: {integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/signature-v4@5.0.1':
+    resolution: {integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/smithy-client@4.1.5':
+    resolution: {integrity: sha512-DMXYoYeL4QkElr216n1yodTFeATbfb4jwYM9gKn71Rw/FNA1/Sm36tkTSCsZEs7mgpG3OINmkxL9vgVFzyGPaw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/types@4.1.0':
+    resolution: {integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/url-parser@4.0.1':
+    resolution: {integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-base64@4.0.0':
+    resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-body-length-browser@4.0.0':
+    resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-body-length-node@4.0.0':
+    resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==}
+    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'}
+
+  '@smithy/util-buffer-from@4.0.0':
+    resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-config-provider@4.0.0':
+    resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-defaults-mode-browser@4.0.6':
+    resolution: {integrity: sha512-N8+VCt+piupH1A7DgSVDNrVHqRLz8r6DvBkpS7EWHiIxsUk4jqGuQLjqC/gnCzmwGkVBdNruHoYAzzaSQ8e80w==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-defaults-mode-node@4.0.6':
+    resolution: {integrity: sha512-9zhx1shd1VwSSVvLZB8CM3qQ3RPD3le7A3h/UPuyh/PC7g4OaWDi2xUNzamsVoSmCGtmUBONl56lM2EU6LcH7A==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-endpoints@3.0.1':
+    resolution: {integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-hex-encoding@4.0.0':
+    resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-middleware@4.0.1':
+    resolution: {integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-retry@4.0.1':
+    resolution: {integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-stream@4.1.1':
+    resolution: {integrity: sha512-+Xvh8nhy0Wjv1y71rBVyV3eJU3356XsFQNI8dEZVNrQju7Eib8G31GWtO+zMa9kTCGd41Mflu+ZKfmQL/o2XzQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-uri-escape@4.0.0':
+    resolution: {integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-utf8@2.3.0':
+    resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==}
+    engines: {node: '>=14.0.0'}
+
+  '@smithy/util-utf8@4.0.0':
+    resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==}
+    engines: {node: '>=18.0.0'}
+
+  '@smithy/util-waiter@4.0.2':
+    resolution: {integrity: sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==}
+    engines: {node: '>=18.0.0'}
+
+  '@tokenizer/inflate@0.2.7':
+    resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==}
+    engines: {node: '>=18'}
+
+  '@tokenizer/token@0.3.0':
+    resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
+
   '@types/bun@1.1.9':
     resolution: {integrity: sha512-SXJRejXpmAc3qxyN/YS4/JGWEzLf4dDBa5fLtRDipQXHqNccuMU4EUYCooXNTsylG0DmwFQsGgEDHxZF+3DqRw==}
 
@@ -530,6 +906,9 @@ packages:
   balanced-match@1.0.2:
     resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
 
+  bowser@2.11.0:
+    resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
+
   brace-expansion@1.1.11:
     resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
 
@@ -582,6 +961,15 @@ packages:
       supports-color:
         optional: true
 
+  debug@4.4.0:
+    resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
   deep-is@0.1.4:
     resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
 
@@ -776,13 +1164,24 @@ packages:
   fast-levenshtein@2.0.6:
     resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
 
+  fast-xml-parser@4.4.1:
+    resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==}
+    hasBin: true
+
   fastq@1.17.1:
     resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
 
+  fflate@0.8.2:
+    resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
+
   file-entry-cache@8.0.0:
     resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
     engines: {node: '>=16.0.0'}
 
+  file-type@20.1.0:
+    resolution: {integrity: sha512-XoxU+lETfCf+bYK3SXkxFusAvmtYQl1u/ZC4zw1DBLEsHUvh339uwYucgQnnSMz1mRCWYJrCzsbJJ95hsQbZ8A==}
+    engines: {node: '>=18'}
+
   fill-range@7.1.1:
     resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
     engines: {node: '>=8'}
@@ -832,6 +1231,9 @@ packages:
     resolution: {integrity: sha512-6NGwvttY1+HAFii08VYiEKI6ETPAFbpLntpm2M/MogEsAFWdZV74UNT+2M4bmqX90cIQhjlpBSP+tO+CfB0uww==}
     engines: {node: '>=16.0.0'}
 
+  ieee754@1.2.1:
+    resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
   ignore@5.3.2:
     resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
     engines: {node: '>= 4'}
@@ -942,6 +1344,10 @@ packages:
     resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
     engines: {node: '>=8'}
 
+  peek-readable@6.1.1:
+    resolution: {integrity: sha512-7QmvgRKhxM0E2PGV4ocfROItVode+ELI27n4q+lpufZ+tRKBu/pBP8WOmw9HXn2ui/AUizqtvaVQhcJrOkRqYg==}
+    engines: {node: '>=18'}
+
   picomatch@2.3.1:
     resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
     engines: {node: '>=8.6'}
@@ -1015,6 +1421,13 @@ packages:
     resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
     engines: {node: '>=8'}
 
+  strnum@1.0.5:
+    resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
+
+  strtok3@10.2.1:
+    resolution: {integrity: sha512-Q2dTnW3UXokAvXmXvrvMoUj/me3LyJI76HNHeuGMh2o0As/vzd7eHV3ncLOyvu928vQIDbE7Vf9ldEnC7cwy1w==}
+    engines: {node: '>=18'}
+
   supports-color@7.2.0:
     resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
     engines: {node: '>=8'}
@@ -1026,12 +1439,19 @@ packages:
     resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
     engines: {node: '>=8.0'}
 
+  token-types@6.0.0:
+    resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==}
+    engines: {node: '>=14.16'}
+
   ts-api-utils@1.3.0:
     resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
     engines: {node: '>=16'}
     peerDependencies:
       typescript: '>=4.2.0'
 
+  tslib@2.8.1:
+    resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
   type-check@0.4.0:
     resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
     engines: {node: '>= 0.8.0'}
@@ -1054,12 +1474,20 @@ packages:
     engines: {node: '>=14.17'}
     hasBin: true
 
+  uint8array-extras@1.4.0:
+    resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
+    engines: {node: '>=18'}
+
   undici-types@5.26.5:
     resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
 
   uri-js@4.4.1:
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
 
+  uuid@9.0.1:
+    resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
+    hasBin: true
+
   which@2.0.2:
     resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
     engines: {node: '>= 8'}
@@ -1088,6 +1516,464 @@ snapshots:
       openapi3-ts: 4.4.0
       zod: 3.23.8
 
+  '@aws-crypto/crc32@5.2.0':
+    dependencies:
+      '@aws-crypto/util': 5.2.0
+      '@aws-sdk/types': 3.734.0
+      tslib: 2.8.1
+
+  '@aws-crypto/crc32c@5.2.0':
+    dependencies:
+      '@aws-crypto/util': 5.2.0
+      '@aws-sdk/types': 3.734.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.734.0
+      '@aws-sdk/util-locate-window': 3.723.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.734.0
+      '@aws-sdk/util-locate-window': 3.723.0
+      '@smithy/util-utf8': 2.3.0
+      tslib: 2.8.1
+
+  '@aws-crypto/sha256-js@5.2.0':
+    dependencies:
+      '@aws-crypto/util': 5.2.0
+      '@aws-sdk/types': 3.734.0
+      tslib: 2.8.1
+
+  '@aws-crypto/supports-web-crypto@5.2.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@aws-crypto/util@5.2.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/util-utf8': 2.3.0
+      tslib: 2.8.1
+
+  '@aws-sdk/client-s3@3.750.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.750.0
+      '@aws-sdk/credential-provider-node': 3.750.0
+      '@aws-sdk/middleware-bucket-endpoint': 3.734.0
+      '@aws-sdk/middleware-expect-continue': 3.734.0
+      '@aws-sdk/middleware-flexible-checksums': 3.750.0
+      '@aws-sdk/middleware-host-header': 3.734.0
+      '@aws-sdk/middleware-location-constraint': 3.734.0
+      '@aws-sdk/middleware-logger': 3.734.0
+      '@aws-sdk/middleware-recursion-detection': 3.734.0
+      '@aws-sdk/middleware-sdk-s3': 3.750.0
+      '@aws-sdk/middleware-ssec': 3.734.0
+      '@aws-sdk/middleware-user-agent': 3.750.0
+      '@aws-sdk/region-config-resolver': 3.734.0
+      '@aws-sdk/signature-v4-multi-region': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@aws-sdk/util-endpoints': 3.743.0
+      '@aws-sdk/util-user-agent-browser': 3.734.0
+      '@aws-sdk/util-user-agent-node': 3.750.0
+      '@aws-sdk/xml-builder': 3.734.0
+      '@smithy/config-resolver': 4.0.1
+      '@smithy/core': 3.1.4
+      '@smithy/eventstream-serde-browser': 4.0.1
+      '@smithy/eventstream-serde-config-resolver': 4.0.1
+      '@smithy/eventstream-serde-node': 4.0.1
+      '@smithy/fetch-http-handler': 5.0.1
+      '@smithy/hash-blob-browser': 4.0.1
+      '@smithy/hash-node': 4.0.1
+      '@smithy/hash-stream-node': 4.0.1
+      '@smithy/invalid-dependency': 4.0.1
+      '@smithy/md5-js': 4.0.1
+      '@smithy/middleware-content-length': 4.0.1
+      '@smithy/middleware-endpoint': 4.0.5
+      '@smithy/middleware-retry': 4.0.6
+      '@smithy/middleware-serde': 4.0.2
+      '@smithy/middleware-stack': 4.0.1
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/node-http-handler': 4.0.2
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      '@smithy/url-parser': 4.0.1
+      '@smithy/util-base64': 4.0.0
+      '@smithy/util-body-length-browser': 4.0.0
+      '@smithy/util-body-length-node': 4.0.0
+      '@smithy/util-defaults-mode-browser': 4.0.6
+      '@smithy/util-defaults-mode-node': 4.0.6
+      '@smithy/util-endpoints': 3.0.1
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-retry': 4.0.1
+      '@smithy/util-stream': 4.1.1
+      '@smithy/util-utf8': 4.0.0
+      '@smithy/util-waiter': 4.0.2
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/client-sso@3.750.0':
+    dependencies:
+      '@aws-crypto/sha256-browser': 5.2.0
+      '@aws-crypto/sha256-js': 5.2.0
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/middleware-host-header': 3.734.0
+      '@aws-sdk/middleware-logger': 3.734.0
+      '@aws-sdk/middleware-recursion-detection': 3.734.0
+      '@aws-sdk/middleware-user-agent': 3.750.0
+      '@aws-sdk/region-config-resolver': 3.734.0
+      '@aws-sdk/types': 3.734.0
+      '@aws-sdk/util-endpoints': 3.743.0
+      '@aws-sdk/util-user-agent-browser': 3.734.0
+      '@aws-sdk/util-user-agent-node': 3.750.0
+      '@smithy/config-resolver': 4.0.1
+      '@smithy/core': 3.1.4
+      '@smithy/fetch-http-handler': 5.0.1
+      '@smithy/hash-node': 4.0.1
+      '@smithy/invalid-dependency': 4.0.1
+      '@smithy/middleware-content-length': 4.0.1
+      '@smithy/middleware-endpoint': 4.0.5
+      '@smithy/middleware-retry': 4.0.6
+      '@smithy/middleware-serde': 4.0.2
+      '@smithy/middleware-stack': 4.0.1
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/node-http-handler': 4.0.2
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      '@smithy/url-parser': 4.0.1
+      '@smithy/util-base64': 4.0.0
+      '@smithy/util-body-length-browser': 4.0.0
+      '@smithy/util-body-length-node': 4.0.0
+      '@smithy/util-defaults-mode-browser': 4.0.6
+      '@smithy/util-defaults-mode-node': 4.0.6
+      '@smithy/util-endpoints': 3.0.1
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-retry': 4.0.1
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/core@3.750.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/core': 3.1.4
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/property-provider': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/signature-v4': 5.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      '@smithy/util-middleware': 4.0.1
+      fast-xml-parser: 4.4.1
+      tslib: 2.8.1
+
+  '@aws-sdk/credential-provider-env@3.750.0':
+    dependencies:
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/property-provider': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/credential-provider-http@3.750.0':
+    dependencies:
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/fetch-http-handler': 5.0.1
+      '@smithy/node-http-handler': 4.0.2
+      '@smithy/property-provider': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      '@smithy/util-stream': 4.1.1
+      tslib: 2.8.1
+
+  '@aws-sdk/credential-provider-ini@3.750.0':
+    dependencies:
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/credential-provider-env': 3.750.0
+      '@aws-sdk/credential-provider-http': 3.750.0
+      '@aws-sdk/credential-provider-process': 3.750.0
+      '@aws-sdk/credential-provider-sso': 3.750.0
+      '@aws-sdk/credential-provider-web-identity': 3.750.0
+      '@aws-sdk/nested-clients': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/credential-provider-imds': 4.0.1
+      '@smithy/property-provider': 4.0.1
+      '@smithy/shared-ini-file-loader': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/credential-provider-node@3.750.0':
+    dependencies:
+      '@aws-sdk/credential-provider-env': 3.750.0
+      '@aws-sdk/credential-provider-http': 3.750.0
+      '@aws-sdk/credential-provider-ini': 3.750.0
+      '@aws-sdk/credential-provider-process': 3.750.0
+      '@aws-sdk/credential-provider-sso': 3.750.0
+      '@aws-sdk/credential-provider-web-identity': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/credential-provider-imds': 4.0.1
+      '@smithy/property-provider': 4.0.1
+      '@smithy/shared-ini-file-loader': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/credential-provider-process@3.750.0':
+    dependencies:
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/property-provider': 4.0.1
+      '@smithy/shared-ini-file-loader': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/credential-provider-sso@3.750.0':
+    dependencies:
+      '@aws-sdk/client-sso': 3.750.0
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/token-providers': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/property-provider': 4.0.1
+      '@smithy/shared-ini-file-loader': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/credential-provider-web-identity@3.750.0':
+    dependencies:
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/nested-clients': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/property-provider': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/middleware-bucket-endpoint@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@aws-sdk/util-arn-parser': 3.723.0
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-config-provider': 4.0.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-expect-continue@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-flexible-checksums@3.750.0':
+    dependencies:
+      '@aws-crypto/crc32': 5.2.0
+      '@aws-crypto/crc32c': 5.2.0
+      '@aws-crypto/util': 5.2.0
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/is-array-buffer': 4.0.0
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-stream': 4.1.1
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-host-header@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-location-constraint@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-logger@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-recursion-detection@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-sdk-s3@3.750.0':
+    dependencies:
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@aws-sdk/util-arn-parser': 3.723.0
+      '@smithy/core': 3.1.4
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/signature-v4': 5.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      '@smithy/util-config-provider': 4.0.0
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-stream': 4.1.1
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-ssec@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/middleware-user-agent@3.750.0':
+    dependencies:
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@aws-sdk/util-endpoints': 3.743.0
+      '@smithy/core': 3.1.4
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/nested-clients@3.750.0':
+    dependencies:
+      '@aws-crypto/sha256-browser': 5.2.0
+      '@aws-crypto/sha256-js': 5.2.0
+      '@aws-sdk/core': 3.750.0
+      '@aws-sdk/middleware-host-header': 3.734.0
+      '@aws-sdk/middleware-logger': 3.734.0
+      '@aws-sdk/middleware-recursion-detection': 3.734.0
+      '@aws-sdk/middleware-user-agent': 3.750.0
+      '@aws-sdk/region-config-resolver': 3.734.0
+      '@aws-sdk/types': 3.734.0
+      '@aws-sdk/util-endpoints': 3.743.0
+      '@aws-sdk/util-user-agent-browser': 3.734.0
+      '@aws-sdk/util-user-agent-node': 3.750.0
+      '@smithy/config-resolver': 4.0.1
+      '@smithy/core': 3.1.4
+      '@smithy/fetch-http-handler': 5.0.1
+      '@smithy/hash-node': 4.0.1
+      '@smithy/invalid-dependency': 4.0.1
+      '@smithy/middleware-content-length': 4.0.1
+      '@smithy/middleware-endpoint': 4.0.5
+      '@smithy/middleware-retry': 4.0.6
+      '@smithy/middleware-serde': 4.0.2
+      '@smithy/middleware-stack': 4.0.1
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/node-http-handler': 4.0.2
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      '@smithy/url-parser': 4.0.1
+      '@smithy/util-base64': 4.0.0
+      '@smithy/util-body-length-browser': 4.0.0
+      '@smithy/util-body-length-node': 4.0.0
+      '@smithy/util-defaults-mode-browser': 4.0.6
+      '@smithy/util-defaults-mode-node': 4.0.6
+      '@smithy/util-endpoints': 3.0.1
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-retry': 4.0.1
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/region-config-resolver@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-config-provider': 4.0.0
+      '@smithy/util-middleware': 4.0.1
+      tslib: 2.8.1
+
+  '@aws-sdk/signature-v4-multi-region@3.750.0':
+    dependencies:
+      '@aws-sdk/middleware-sdk-s3': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/signature-v4': 5.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/token-providers@3.750.0':
+    dependencies:
+      '@aws-sdk/nested-clients': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/property-provider': 4.0.1
+      '@smithy/shared-ini-file-loader': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+    transitivePeerDependencies:
+      - aws-crt
+
+  '@aws-sdk/types@3.734.0':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/util-arn-parser@3.723.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@aws-sdk/util-endpoints@3.743.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/types': 4.1.0
+      '@smithy/util-endpoints': 3.0.1
+      tslib: 2.8.1
+
+  '@aws-sdk/util-locate-window@3.723.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@aws-sdk/util-user-agent-browser@3.734.0':
+    dependencies:
+      '@aws-sdk/types': 3.734.0
+      '@smithy/types': 4.1.0
+      bowser: 2.11.0
+      tslib: 2.8.1
+
+  '@aws-sdk/util-user-agent-node@3.750.0':
+    dependencies:
+      '@aws-sdk/middleware-user-agent': 3.750.0
+      '@aws-sdk/types': 3.734.0
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@aws-sdk/xml-builder@3.734.0':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
   '@esbuild-kit/core-utils@3.3.2':
     dependencies:
       esbuild: 0.18.20
@@ -1307,6 +2193,347 @@ snapshots:
       '@nodelib/fs.scandir': 2.1.5
       fastq: 1.17.1
 
+  '@smithy/abort-controller@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/chunked-blob-reader-native@4.0.0':
+    dependencies:
+      '@smithy/util-base64': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/chunked-blob-reader@5.0.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/config-resolver@4.0.1':
+    dependencies:
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-config-provider': 4.0.0
+      '@smithy/util-middleware': 4.0.1
+      tslib: 2.8.1
+
+  '@smithy/core@3.1.4':
+    dependencies:
+      '@smithy/middleware-serde': 4.0.2
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-body-length-browser': 4.0.0
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-stream': 4.1.1
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/credential-provider-imds@4.0.1':
+    dependencies:
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/property-provider': 4.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/url-parser': 4.0.1
+      tslib: 2.8.1
+
+  '@smithy/eventstream-codec@4.0.1':
+    dependencies:
+      '@aws-crypto/crc32': 5.2.0
+      '@smithy/types': 4.1.0
+      '@smithy/util-hex-encoding': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/eventstream-serde-browser@4.0.1':
+    dependencies:
+      '@smithy/eventstream-serde-universal': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/eventstream-serde-config-resolver@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/eventstream-serde-node@4.0.1':
+    dependencies:
+      '@smithy/eventstream-serde-universal': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/eventstream-serde-universal@4.0.1':
+    dependencies:
+      '@smithy/eventstream-codec': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/fetch-http-handler@5.0.1':
+    dependencies:
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/querystring-builder': 4.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-base64': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/hash-blob-browser@4.0.1':
+    dependencies:
+      '@smithy/chunked-blob-reader': 5.0.0
+      '@smithy/chunked-blob-reader-native': 4.0.0
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/hash-node@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      '@smithy/util-buffer-from': 4.0.0
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/hash-stream-node@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/invalid-dependency@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/is-array-buffer@2.2.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/is-array-buffer@4.0.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/md5-js@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/middleware-content-length@4.0.1':
+    dependencies:
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/middleware-endpoint@4.0.5':
+    dependencies:
+      '@smithy/core': 3.1.4
+      '@smithy/middleware-serde': 4.0.2
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/shared-ini-file-loader': 4.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/url-parser': 4.0.1
+      '@smithy/util-middleware': 4.0.1
+      tslib: 2.8.1
+
+  '@smithy/middleware-retry@4.0.6':
+    dependencies:
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/service-error-classification': 4.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-retry': 4.0.1
+      tslib: 2.8.1
+      uuid: 9.0.1
+
+  '@smithy/middleware-serde@4.0.2':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/middleware-stack@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/node-config-provider@4.0.1':
+    dependencies:
+      '@smithy/property-provider': 4.0.1
+      '@smithy/shared-ini-file-loader': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/node-http-handler@4.0.2':
+    dependencies:
+      '@smithy/abort-controller': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/querystring-builder': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/property-provider@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/protocol-http@5.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/querystring-builder@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      '@smithy/util-uri-escape': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/querystring-parser@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/service-error-classification@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+
+  '@smithy/shared-ini-file-loader@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/signature-v4@5.0.1':
+    dependencies:
+      '@smithy/is-array-buffer': 4.0.0
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-hex-encoding': 4.0.0
+      '@smithy/util-middleware': 4.0.1
+      '@smithy/util-uri-escape': 4.0.0
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/smithy-client@4.1.5':
+    dependencies:
+      '@smithy/core': 3.1.4
+      '@smithy/middleware-endpoint': 4.0.5
+      '@smithy/middleware-stack': 4.0.1
+      '@smithy/protocol-http': 5.0.1
+      '@smithy/types': 4.1.0
+      '@smithy/util-stream': 4.1.1
+      tslib: 2.8.1
+
+  '@smithy/types@4.1.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/url-parser@4.0.1':
+    dependencies:
+      '@smithy/querystring-parser': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/util-base64@4.0.0':
+    dependencies:
+      '@smithy/util-buffer-from': 4.0.0
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/util-body-length-browser@4.0.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/util-body-length-node@4.0.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/util-buffer-from@2.2.0':
+    dependencies:
+      '@smithy/is-array-buffer': 2.2.0
+      tslib: 2.8.1
+
+  '@smithy/util-buffer-from@4.0.0':
+    dependencies:
+      '@smithy/is-array-buffer': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/util-config-provider@4.0.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/util-defaults-mode-browser@4.0.6':
+    dependencies:
+      '@smithy/property-provider': 4.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      bowser: 2.11.0
+      tslib: 2.8.1
+
+  '@smithy/util-defaults-mode-node@4.0.6':
+    dependencies:
+      '@smithy/config-resolver': 4.0.1
+      '@smithy/credential-provider-imds': 4.0.1
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/property-provider': 4.0.1
+      '@smithy/smithy-client': 4.1.5
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/util-endpoints@3.0.1':
+    dependencies:
+      '@smithy/node-config-provider': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/util-hex-encoding@4.0.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/util-middleware@4.0.1':
+    dependencies:
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/util-retry@4.0.1':
+    dependencies:
+      '@smithy/service-error-classification': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@smithy/util-stream@4.1.1':
+    dependencies:
+      '@smithy/fetch-http-handler': 5.0.1
+      '@smithy/node-http-handler': 4.0.2
+      '@smithy/types': 4.1.0
+      '@smithy/util-base64': 4.0.0
+      '@smithy/util-buffer-from': 4.0.0
+      '@smithy/util-hex-encoding': 4.0.0
+      '@smithy/util-utf8': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/util-uri-escape@4.0.0':
+    dependencies:
+      tslib: 2.8.1
+
+  '@smithy/util-utf8@2.3.0':
+    dependencies:
+      '@smithy/util-buffer-from': 2.2.0
+      tslib: 2.8.1
+
+  '@smithy/util-utf8@4.0.0':
+    dependencies:
+      '@smithy/util-buffer-from': 4.0.0
+      tslib: 2.8.1
+
+  '@smithy/util-waiter@4.0.2':
+    dependencies:
+      '@smithy/abort-controller': 4.0.1
+      '@smithy/types': 4.1.0
+      tslib: 2.8.1
+
+  '@tokenizer/inflate@0.2.7':
+    dependencies:
+      debug: 4.4.0
+      fflate: 0.8.2
+      token-types: 6.0.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@tokenizer/token@0.3.0': {}
+
   '@types/bun@1.1.9':
     dependencies:
       bun-types: 1.1.27
@@ -1425,6 +2652,8 @@ snapshots:
 
   balanced-match@1.0.2: {}
 
+  bowser@2.11.0: {}
+
   brace-expansion@1.1.11:
     dependencies:
       balanced-match: 1.0.2
@@ -1474,6 +2703,10 @@ snapshots:
     dependencies:
       ms: 2.1.3
 
+  debug@4.4.0:
+    dependencies:
+      ms: 2.1.3
+
   deep-is@0.1.4: {}
 
   dir-glob@3.0.1:
@@ -1648,14 +2881,29 @@ snapshots:
 
   fast-levenshtein@2.0.6: {}
 
+  fast-xml-parser@4.4.1:
+    dependencies:
+      strnum: 1.0.5
+
   fastq@1.17.1:
     dependencies:
       reusify: 1.0.4
 
+  fflate@0.8.2: {}
+
   file-entry-cache@8.0.0:
     dependencies:
       flat-cache: 4.0.1
 
+  file-type@20.1.0:
+    dependencies:
+      '@tokenizer/inflate': 0.2.7
+      strtok3: 10.2.1
+      token-types: 6.0.0
+      uint8array-extras: 1.4.0
+    transitivePeerDependencies:
+      - supports-color
+
   fill-range@7.1.1:
     dependencies:
       to-regex-range: 5.0.1
@@ -1703,6 +2951,8 @@ snapshots:
 
   hono@4.6.1: {}
 
+  ieee754@1.2.1: {}
+
   ignore@5.3.2: {}
 
   import-fresh@3.3.0:
@@ -1799,6 +3049,8 @@ snapshots:
 
   path-type@4.0.0: {}
 
+  peek-readable@6.1.1: {}
+
   picomatch@2.3.1: {}
 
   postgres@3.4.4: {}
@@ -1846,6 +3098,13 @@ snapshots:
 
   strip-json-comments@3.1.1: {}
 
+  strnum@1.0.5: {}
+
+  strtok3@10.2.1:
+    dependencies:
+      '@tokenizer/token': 0.3.0
+      peek-readable: 6.1.1
+
   supports-color@7.2.0:
     dependencies:
       has-flag: 4.0.0
@@ -1856,10 +3115,17 @@ snapshots:
     dependencies:
       is-number: 7.0.0
 
+  token-types@6.0.0:
+    dependencies:
+      '@tokenizer/token': 0.3.0
+      ieee754: 1.2.1
+
   ts-api-utils@1.3.0(typescript@5.6.2):
     dependencies:
       typescript: 5.6.2
 
+  tslib@2.8.1: {}
+
   type-check@0.4.0:
     dependencies:
       prelude-ls: 1.2.1
@@ -1879,12 +3145,16 @@ snapshots:
 
   typescript@5.6.2: {}
 
+  uint8array-extras@1.4.0: {}
+
   undici-types@5.26.5: {}
 
   uri-js@4.4.1:
     dependencies:
       punycode: 2.3.1
 
+  uuid@9.0.1: {}
+
   which@2.0.2:
     dependencies:
       isexe: 2.0.0
diff --git a/src/env.ts b/src/env.ts
index 01b957d..9f31ea2 100644
--- a/src/env.ts
+++ b/src/env.ts
@@ -21,6 +21,10 @@ const EnvSchema = z.object({
   DB_MIGRATING: stringBoolean,
   DB_SEEDING: stringBoolean,
   APP_SECRET: z.string(),
+  AWS_ACCESS_KEY_ID: z.string(),
+  AWS_SECRET_ACCESS_KEY: z.string(),
+  AWS_REGION: z.string(),
+  S3_BUCKET: z.string(),
 })
 
 export type EnvSchema = z.infer<typeof EnvSchema>
diff --git a/src/index.ts b/src/index.ts
index 509f3df..aa4fb29 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -43,6 +43,7 @@ import { OpenAPIHono } from "@hono/zod-openapi";
 import { commentsRouter, publicCommentsRoute } from './routes/comments.route'
 import { publicCommentsReplyRoute, commentReplyRouter } from './routes/comment-reply.route'
 import { publicUserCollectionsRoutes, userCollectionsRoute } from './routes/user-collection.route'
+import { s3Routes } from './routes/s3.route'
 
 
 
@@ -155,6 +156,7 @@ app
   .route('/comments', commentsRouter)
   .route('/replyComment', commentReplyRouter)
   .route('/userCollections', userCollectionsRoute)
+  .route('/s3', s3Routes)
 
 export default app
 export type AppType = typeof app
diff --git a/src/routes/s3.route.ts b/src/routes/s3.route.ts
new file mode 100644
index 0000000..102489c
--- /dev/null
+++ b/src/routes/s3.route.ts
@@ -0,0 +1,363 @@
+import { deleteObject, getFile, putFile } from "@/services/s3.service";
+import { Hono } from "hono";
+
+
+export const s3Routes = new Hono()
+
+    //rota de enviar blob para o s3
+    //id_ resource é o id do recurso
+    //faz o upload do conteudo do recurso
+    .post('/upload/resource/:id_resource',
+        async (ctx) => {
+            const id = ctx.req.param('id_resource');
+
+            const formData = await ctx.req.formData();
+            const fileBlob = formData.get('file');
+
+
+
+            if (!fileBlob || !(fileBlob instanceof Blob)) {
+                return ctx.json({ message: 'No files sent or invalid format' }, 400)
+            }
+
+            // Obtém o tamanho do arquivo em bytes
+            const fileSize = fileBlob.size;
+            const maxSize = 5 * 1024 * 1024 * 1024; // 5GB em bytes
+
+            if (fileSize > maxSize) {
+                return ctx.json({
+                    message: `O arquivo excede o limite de 5GB (${(fileSize / (1024 * 1024 * 1024)).toFixed(2)} GB).`,
+                    status: 'error'
+                }, 400);
+            }
+
+            try {
+                const result = await putFile(fileBlob, id, "resource")
+                return ctx.json({
+                    message: 'Arquivo enviado com sucesso!',
+                    fileId: id,
+                    status: 'success',
+                    details: result
+                }, 200);
+            } catch (error) {
+                console.error('Erro ao fazer upload do arquivo:', error);
+                return ctx.json({
+                    message: 'Erro interno ao enviar o arquivo. Tente novamente mais tarde.',
+                    status: 'error'
+                }, 500);
+            }
+        }
+    )
+
+    // envio de fotos de thumbnail do recurso
+    .post('/upload/thumbnail/resource/:id_resource',
+        async (ctx) => {
+            const id = ctx.req.param('id_resource');
+
+            const formData = await ctx.req.formData();
+            const fileBlob = formData.get('file');
+
+
+            if (!fileBlob || !(fileBlob instanceof Blob)) {
+                return ctx.json({ message: 'No files sent or invalid format' }, 400)
+            }
+
+            // Obtém o tamanho do arquivo em bytes
+            const fileSize = fileBlob.size;
+            const maxSize = 1 * 1024 * 1024; // 1MB em bytes
+
+            if (fileSize > maxSize) {
+                return ctx.json({
+                    message: `A thumbnail do recurso excede o limite de 1MB (${(fileSize / (1024)).toFixed(2)} KB).`,
+                    status: 'error'
+                }, 400);
+            }
+
+
+            try {
+                const result = await putFile(fileBlob, id, "thumbnail/resource")
+                return ctx.json({
+                    message: 'Arquivo enviado com sucesso!',
+                    fileId: id,
+                    status: 'success',
+                    details: result
+                }, 200);
+            } catch (error) {
+                console.error('Erro ao fazer upload do arquivo:', error);
+                return ctx.json({
+                    message: 'Erro interno ao enviar o arquivo. Tente novamente mais tarde.',
+                    status: 'error'
+                }, 500);
+            }
+        }
+    )
+
+
+    // envio de fotos de thumbnail da coleção
+    .post('/upload/thumbnail/collection/:id_collection',
+        async (ctx) => {
+            const id = ctx.req.param('id_collection');
+
+            const formData = await ctx.req.formData();
+            const fileBlob = formData.get('file');
+
+
+            if (!fileBlob || !(fileBlob instanceof Blob)) {
+                return ctx.json({ message: 'No files sent or invalid format' }, 400)
+            }
+
+            // Obtém o tamanho do arquivo em bytes
+            const fileSize = fileBlob.size;
+            const maxSize = 1 * 1024 * 1024; // 1MB em bytes
+
+            if (fileSize > maxSize) {
+                return ctx.json({
+                    message: `A thumbnail da collection excede o limite de 1MB (${(fileSize / (1024)).toFixed(2)} KB).`,
+                    status: 'error'
+                }, 400);
+            }
+
+
+            try {
+                const result = await putFile(fileBlob, id, "thumbnail/collection")
+                return ctx.json({
+                    message: 'Arquivo enviado com sucesso!',
+                    fileId: id,
+                    status: 'success',
+                    details: result
+                }, 200);
+            } catch (error) {
+                console.error('Erro ao fazer upload do arquivo:', error);
+                return ctx.json({
+                    message: 'Erro interno ao enviar o arquivo. Tente novamente mais tarde.',
+                    status: 'error'
+                }, 500);
+            }
+        }
+    )
+
+
+    // envio de fotos de thumbnail da coleção
+    .post('/upload/avatar/:id_avatar',
+        async (ctx) => {
+            const id = ctx.req.param('id_avatar');
+
+            const formData = await ctx.req.formData();
+            const fileBlob = formData.get('file');
+
+
+            if (!fileBlob || !(fileBlob instanceof Blob)) {
+                return ctx.json({ message: 'No files sent or invalid format' }, 400)
+            }
+
+            // Obtém o tamanho do arquivo em bytes
+            const fileSize = fileBlob.size;
+            const maxSize = 5 * 1024 * 1024; // 5MB em bytes
+
+            if (fileSize > maxSize) {
+                return ctx.json({
+                    message: `O avatar excede o limite de 5MB (${(fileSize / (1024)).toFixed(2)} KB).`,
+                    status: 'error'
+                }, 400);
+            }
+
+
+            try {
+                const result = await putFile(fileBlob, id, "avatar")
+                return ctx.json({
+                    message: 'Arquivo enviado com sucesso!',
+                    fileId: id,
+                    status: 'success',
+                    details: result
+                }, 200);
+            } catch (error) {
+                console.error('Erro ao fazer upload do arquivo:', error);
+                return ctx.json({
+                    message: 'Erro interno ao enviar o arquivo. Tente novamente mais tarde.',
+                    status: 'error'
+                }, 500);
+            }
+        }
+    )
+
+    .post("/delete/resource/:id", async (c) => {
+        const id = c.req.param("id");
+
+        try {
+            const response = await deleteObject(`resource/${id}`);
+            return c.json(response); 
+        } catch (error) {
+            return c.json({ error: "Erro ao deletar objeto do S3." }, 500);
+        }
+    })
+
+    .post("/delete/avatar/:id", async (c) => {
+        const id = c.req.param("id");
+
+        try {
+            const response = await deleteObject(`avatar/${id}`);
+            return c.json(response); 
+        } catch (error) {
+            return c.json({ error: "Erro ao deletar objeto do S3." }, 500);
+        }
+    })
+
+    .post("/delete/thumbnail/resource/:id", async (c) => {
+        const id = c.req.param("id");
+
+        try {
+            const response = await deleteObject(`thumbnail/resource/${id}`);
+            return c.json(response); 
+        } catch (error) {
+            return c.json({ error: "Erro ao deletar objeto do S3." }, 500);
+        }
+    })
+
+    .post("/delete/thumbnail/collection/:id", async (c) => {
+        const id = c.req.param("id");
+
+        try {
+            const response = await deleteObject(`thumbnail/collection/${id}`);
+            return c.json(response); 
+        } catch (error) {
+            return c.json({ error: "Erro ao deletar objeto do S3." }, 500);
+        }
+    })
+
+
+
+    .get("get/resource/:id",
+        async (ctx) => {
+
+            const id = ctx.req.param("id");
+
+            try {
+                // Busca o arquivo no S3 com a chave "resource/id"
+                const response = await getFile(`resource/${id}`);
+
+                if (!response || !response.Body) {
+                    return ctx.json({ message: "Arquivo não encontrado" }, 404);
+                }
+
+                // O corpo da resposta é o arquivo, e seu tipo de conteúdo pode ser acessado diretamente
+                const fileData = await response.Body.transformToByteArray()// Converte o conteúdo do corpo para ArrayBuffer ou outro formato adequado
+
+                return new Response(fileData, {
+                    status: 200,
+                    headers: {
+                        "Content-Type": response.ContentType || "application/octet-stream", // Obtém o tipo de conteúdo diretamente da resposta
+                    }
+                });
+
+            } catch (error) {
+                console.error("Erro ao buscar arquivo do S3:", error);
+                return ctx.json(
+                    { message: "Erro interno ao buscar o arquivo" },
+                    500
+                );
+            }
+        }
+    )
+
+    .get("get/thumbnail/resource/:id",
+        async (ctx) => {
+
+            const id = ctx.req.param("id");
+
+            try {
+                // Busca o arquivo no S3 com a chave "resource/id"
+                const response = await getFile(`thumbnail/resource/${id}`);
+
+                if (!response || !response.Body) {
+                    return ctx.json({ message: "Arquivo não encontrado" }, 404);
+                }
+
+                // O corpo da resposta é o arquivo, e seu tipo de conteúdo pode ser acessado diretamente
+                const fileData = await response.Body.transformToByteArray()// Converte o conteúdo do corpo para ArrayBuffer ou outro formato adequado
+
+                return new Response(fileData, {
+                    status: 200,
+                    headers: {
+                        "Content-Type": response.ContentType || "application/octet-stream", // Obtém o tipo de conteúdo diretamente da resposta
+                    }
+                });
+
+            } catch (error) {
+                console.error("Erro ao buscar arquivo do S3:", error);
+                return ctx.json(
+                    { message: "Erro interno ao buscar o arquivo" },
+                    500
+                );
+            }
+        }
+    )
+
+
+
+    .get("get/thumbnail/collection/:id",
+        async (ctx) => {
+
+            const id = ctx.req.param("id");
+
+            try {
+                // Busca o arquivo no S3 com a chave "resource/id"
+                const response = await getFile(`thumbnail/collection/${id}`);
+
+                if (!response || !response.Body) {
+                    return ctx.json({ message: "Arquivo não encontrado" }, 404);
+                }
+
+                // O corpo da resposta é o arquivo, e seu tipo de conteúdo pode ser acessado diretamente
+                const fileData = await response.Body.transformToByteArray()// Converte o conteúdo do corpo para ArrayBuffer ou outro formato adequado
+
+                return new Response(fileData, {
+                    status: 200,
+                    headers: {
+                        "Content-Type": response.ContentType || "application/octet-stream", // Obtém o tipo de conteúdo diretamente da resposta
+                    }
+                });
+
+            } catch (error) {
+                console.error("Erro ao buscar arquivo do S3:", error);
+                return ctx.json(
+                    { message: "Erro interno ao buscar o arquivo" },
+                    500
+                );
+            }
+        }
+    )
+
+    .get("get/avatar/:id",
+        async (ctx) => {
+
+            const id = ctx.req.param("id");
+
+            try {
+                // Busca o arquivo no S3 com a chave "resource/id"
+                const response = await getFile(`avatar/${id}`);
+
+                if (!response || !response.Body) {
+                    return ctx.json({ message: "Arquivo não encontrado" }, 404);
+                }
+
+                // O corpo da resposta é o arquivo, e seu tipo de conteúdo pode ser acessado diretamente
+                const fileData = await response.Body.transformToByteArray()// Converte o conteúdo do corpo para ArrayBuffer ou outro formato adequado
+
+                return new Response(fileData, {
+                    status: 200,
+                    headers: {
+                        "Content-Type": response.ContentType || "application/octet-stream", // Obtém o tipo de conteúdo diretamente da resposta
+                    }
+                });
+
+            } catch (error) {
+                console.error("Erro ao buscar arquivo do S3:", error);
+                return ctx.json(
+                    { message: "Erro interno ao buscar o arquivo" },
+                    500
+                );
+            }
+        }
+    )
+
+
diff --git a/src/services/config.ts b/src/services/config.ts
index c6dd476..36f86fa 100644
--- a/src/services/config.ts
+++ b/src/services/config.ts
@@ -1,3 +1,5 @@
+
+
 var mailConfig: any;
 
 mailConfig = {
diff --git a/src/services/s3.service.ts b/src/services/s3.service.ts
new file mode 100644
index 0000000..0e4237e
--- /dev/null
+++ b/src/services/s3.service.ts
@@ -0,0 +1,129 @@
+import env from '../env.ts';
+import { S3Client, PutObjectCommand, S3ServiceException, GetObjectCommand, DeleteObjectCommand, HeadObjectCommand } from '@aws-sdk/client-s3';
+import { Buffer } from 'buffer';
+import { fileTypeFromBuffer } from "file-type";
+
+
+// cria um cliente s3
+const s3Client = new S3Client({
+    endpoint: 'https://s3.c3sl.ufpr.br',
+    region: env.AWS_REGION,
+    credentials: {
+        accessKeyId: env.AWS_ACCESS_KEY_ID,
+        secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
+    },
+});
+
+//função de upload de arquivos para o s3, id é o id do objeto
+// file is Blob-like, é tipo um Blob mas não é
+// usamos pick para construir um tipo
+export async function putFile(file: { arrayBuffer(): Promise<ArrayBuffer> }, id: string, path: string) {
+    const buffer = (await file.arrayBuffer());
+    const fileType = await fileTypeFromBuffer(buffer); // Detecta o tipo MIME real
+
+    const command = new PutObjectCommand({
+        Bucket: env.S3_BUCKET,
+        Key: `${path}/${id}`, // Key é uma string, criando as "subpastas"
+        Body: Buffer.from(buffer),
+        ContentType: fileType?.mime || "application/octet-stream", //manda o MIME, para que ele consiga fazer tudo certo
+        ACL: "public-read" //permissao de leitura no objeto
+    })
+
+    try {
+        const response = await s3Client.send(command);
+        console.log(response)
+        return response
+
+    } catch (caught) {
+        if (
+            caught instanceof S3ServiceException &&
+            caught.name === "EntityTooLarge"
+        ) {
+            console.error(
+                `Error from S3 while uploading object to ${env.S3_BUCKET}. \
+      The object was too large .`,
+            );
+        } else if (caught instanceof S3ServiceException) {
+            console.error(
+                `Error from S3 while uploading object to ${env.S3_BUCKET}.  ${caught.name}: ${caught.message}`,
+            );
+        } else {
+            console.error(
+                `Error is not from S3..`, caught
+            );
+        }
+
+
+    }
+}
+
+const checkObjectExists = async ( key: string) => {
+    try {
+        await s3Client.send(new HeadObjectCommand({ Bucket: env.S3_BUCKET, Key: key }));
+        return true; // O objeto existe
+    } catch (error) {
+        if (error instanceof S3ServiceException && error.name === "NotFound") {
+            return false; // O objeto não existe
+        }
+        throw error; // Outro erro inesperado
+    }
+};
+
+export async function deleteObject(id: string) {
+
+    const command = new DeleteObjectCommand({
+        Bucket: env.S3_BUCKET,
+        Key: id
+    })
+
+    const exists = await checkObjectExists(id);
+    if (!exists) {
+        return { error: `Objeto ${id} não encontrado.`, status: 404 }; // Retorna um JSON se não existir
+    }
+
+    try {
+        await s3Client.send(command);
+
+
+        console.log(`The object "${id}" from bucket "${env.S3_BUCKET}" was deleted, or it didn't exist.`);
+        return { message: `The object "${id}" was deleted successfully.` };
+    } catch (caught) {
+        if (caught instanceof S3ServiceException && caught.name === "NoSuchBucket") {
+            console.error(`Error from S3 while deleting object from ${env.S3_BUCKET}. The bucket doesn't exist.`);
+            throw new Error("Bucket does not exist.");
+        } else if (caught instanceof S3ServiceException) {
+            console.error(`Error from S3 while deleting object from ${env.S3_BUCKET}. ${caught.name}: ${caught.message}`);
+            throw new Error(`S3 Error: ${caught.name}: ${caught.message}`);
+        } else {
+            throw caught;
+        }
+    }
+}
+
+
+
+export async function getFile(id: string) {
+
+    const command = new GetObjectCommand({
+        Bucket: env.S3_BUCKET,
+        Key: id
+    })
+    try {
+        const response = await s3Client.send(command);
+        if (!response.Body) {
+            throw new Error("File not found in S3");
+        }
+
+        return response;
+
+    } catch (error) {
+        console.error("Error to get file in S3:", error);
+        if (error instanceof Error) {
+            console.error("Nome do erro:", error.name);
+            console.error("Mensagem:", error.message);
+            console.error("Stack trace:", error.stack);
+        }
+
+        throw error;
+    }
+}
\ No newline at end of file
-- 
GitLab