feat(s3): implement non-ephemeral storage through S3/DO Spaces

This commit is contained in:
Amruth Pillai 2022-04-09 09:28:08 +02:00
parent d0863d68c6
commit feb911aea0
No known key found for this signature in database
GPG Key ID: E3C57DF9B80855AD
13 changed files with 973 additions and 38 deletions

View File

@ -23,6 +23,12 @@ SENDGRID_API_KEY=
SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID=
SENDGRID_FROM_NAME=
SENDGRID_FROM_EMAIL=
STORAGE_BUCKET=
STORAGE_REGION=
STORAGE_ENDPOINT=
STORAGE_URL_PREFIX=
STORAGE_ACCESS_KEY=
STORAGE_SECRET_KEY=
# Flags
PUBLIC_FLAG_DISABLE_SIGNUPS=false

View File

@ -2,8 +2,6 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [3.3.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.2...v3.3.3) (2022-04-09)
### [3.3.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.1...v3.3.2) (2022-04-08)

View File

@ -12,7 +12,7 @@ const nextConfig = {
},
images: {
domains: ['www.gravatar.com'],
domains: ['cdn.rxresu.me', 'www.gravatar.com'],
},
async rewrites() {

View File

@ -28,6 +28,12 @@ x-env-server: &env-server
- SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID=
- SENDGRID_FROM_NAME=
- SENDGRID_FROM_EMAIL=
- STORAGE_BUCKET=
- STORAGE_REGION=
- STORAGE_ENDPOINT=
- STORAGE_URL_PREFIX=
- STORAGE_ACCESS_KEY=
- STORAGE_SECRET_KEY=
x-env-flags: &env-flags
environment:

View File

@ -161,3 +161,31 @@ You can get your own key here: https://docs.sendgrid.com/ui/account-and-settings
**Required**: `no`
**Description:** Sender's Email Address
## Storage
You can either use S3 or any S3-compliant service such as DigitalOcean Spaces to store profile pictures uploaded by users of the platform.
### `STORAGE_BUCKET`
**Required**: `yes`
### `STORAGE_REGION`
**Required**: `yes`
### `STORAGE_ENDPOINT`
**Required**: `yes`
### `STORAGE_URL_PREFIX`
**Required**: `yes`
### `STORAGE_ACCESS_KEY`
**Required**: `yes`
### `STORAGE_SECRET_KEY`
**Required**: `yes`

View File

@ -1,6 +1,6 @@
{
"name": "reactive-resume",
"version": "3.3.3",
"version": "3.3.2",
"private": true,
"workspaces": [
"schema",

View File

@ -205,6 +205,7 @@ importers:
server:
specifiers:
'@aws-sdk/client-s3': ^3.67.0
'@nestjs/axios': ^0.0.7
'@nestjs/cli': ^8.2.5
'@nestjs/common': ^8.4.4
@ -260,6 +261,7 @@ importers:
uuid: ^8.3.2
webpack: ^5.72.0
dependencies:
'@aws-sdk/client-s3': 3.67.0
'@nestjs/axios': 0.0.7_7670df531e7a1503cdbe395599f41db7
'@nestjs/common': 8.4.4_ea528571bae7e3437ac6e354bb00c0f4
'@nestjs/config': 2.0.0_7670df531e7a1503cdbe395599f41db7
@ -515,6 +517,859 @@ packages:
- chokidar
dev: true
/@aws-crypto/crc32/2.0.0:
resolution: {integrity: sha512-TvE1r2CUueyXOuHdEigYjIZVesInd9KN+K/TFFNfkkxRThiNxO6i4ZqqAVMoEjAamZZ1AA8WXJkjCz7YShHPQA==}
dependencies:
'@aws-crypto/util': 2.0.1
'@aws-sdk/types': 3.55.0
tslib: 1.14.1
dev: false
/@aws-crypto/crc32c/2.0.0:
resolution: {integrity: sha512-vF0eMdMHx3O3MoOXUfBZry8Y4ZDtcuskjjKgJz8YfIDjLStxTZrYXk+kZqtl6A0uCmmiN/Eb/JbC/CndTV1MHg==}
dependencies:
'@aws-crypto/util': 2.0.1
'@aws-sdk/types': 3.55.0
tslib: 1.14.1
dev: false
/@aws-crypto/ie11-detection/2.0.0:
resolution: {integrity: sha512-pkVXf/dq6PITJ0jzYZ69VhL8VFOFoPZLZqtU/12SGnzYuJOOGNfF41q9GxdI1yqC8R13Rq3jOLKDFpUJFT5eTA==}
dependencies:
tslib: 1.14.1
dev: false
/@aws-crypto/sha1-browser/2.0.0:
resolution: {integrity: sha512-3fIVRjPFY8EG5HWXR+ZJZMdWNRpwbxGzJ9IH9q93FpbgCH8u8GHRi46mZXp3cYD7gealmyqpm3ThZwLKJjWJhA==}
dependencies:
'@aws-crypto/ie11-detection': 2.0.0
'@aws-crypto/supports-web-crypto': 2.0.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-locate-window': 3.55.0
'@aws-sdk/util-utf8-browser': 3.55.0
tslib: 1.14.1
dev: false
/@aws-crypto/sha256-browser/2.0.0:
resolution: {integrity: sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==}
dependencies:
'@aws-crypto/ie11-detection': 2.0.0
'@aws-crypto/sha256-js': 2.0.0
'@aws-crypto/supports-web-crypto': 2.0.0
'@aws-crypto/util': 2.0.1
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-locate-window': 3.55.0
'@aws-sdk/util-utf8-browser': 3.55.0
tslib: 1.14.1
dev: false
/@aws-crypto/sha256-js/2.0.0:
resolution: {integrity: sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==}
dependencies:
'@aws-crypto/util': 2.0.1
'@aws-sdk/types': 3.55.0
tslib: 1.14.1
dev: false
/@aws-crypto/supports-web-crypto/2.0.0:
resolution: {integrity: sha512-Ge7WQ3E0OC7FHYprsZV3h0QIcpdyJLvIeg+uTuHqRYm8D6qCFJoiC+edSzSyFiHtZf+NOQDJ1q46qxjtzIY2nA==}
dependencies:
tslib: 1.14.1
dev: false
/@aws-crypto/util/2.0.1:
resolution: {integrity: sha512-JJmFFwvbm08lULw4Nm5QOLg8+lAQeC8aCXK5xrtxntYzYXCGfHwUJ4Is3770Q7HmICsXthGQ+ZsDL7C2uH3yBQ==}
dependencies:
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-utf8-browser': 3.55.0
tslib: 1.14.1
dev: false
/@aws-sdk/abort-controller/3.55.0:
resolution: {integrity: sha512-rCcTxJDEFnmvo/PgbhCRv24/Uv03lEGfRslKZq7SjaMcOubflS/ZXYaMEgsjYHgAT0zlpSsyCIkJXmhFaM7H7w==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/chunked-blob-reader-native/3.58.0:
resolution: {integrity: sha512-+D3xnPD5985iphgAqgUerBDs371a2WzzoEVi7eHJUMMsP/gEnSTdSH0HNxsqhYv6CW4EdKtvDAQdAwA1VtCf2A==}
dependencies:
'@aws-sdk/util-base64-browser': 3.58.0
tslib: 2.3.1
dev: false
/@aws-sdk/chunked-blob-reader/3.55.0:
resolution: {integrity: sha512-o/xjMCq81opAjSBjt7YdHJwIJcGVG5XIV9+C2KXcY5QwVimkOKPybWTv0mXPvSwSilSx+EhpLNhkcJuXdzhw4w==}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/client-s3/3.67.0:
resolution: {integrity: sha512-+wSWhkxXG8mY5rlsTXdDaYULpzq8AZ3B2TZKVGEXb6zs1txedyWSYeZr6ENpBoxtJepmlwXDC7oRm39eVoRixw==}
engines: {node: '>=12.0.0'}
dependencies:
'@aws-crypto/sha1-browser': 2.0.0
'@aws-crypto/sha256-browser': 2.0.0
'@aws-crypto/sha256-js': 2.0.0
'@aws-sdk/client-sts': 3.67.0
'@aws-sdk/config-resolver': 3.58.0
'@aws-sdk/credential-provider-node': 3.67.0
'@aws-sdk/eventstream-serde-browser': 3.58.0
'@aws-sdk/eventstream-serde-config-resolver': 3.55.0
'@aws-sdk/eventstream-serde-node': 3.58.0
'@aws-sdk/fetch-http-handler': 3.58.0
'@aws-sdk/hash-blob-browser': 3.58.0
'@aws-sdk/hash-node': 3.55.0
'@aws-sdk/hash-stream-node': 3.58.0
'@aws-sdk/invalid-dependency': 3.55.0
'@aws-sdk/md5-js': 3.58.0
'@aws-sdk/middleware-bucket-endpoint': 3.58.0
'@aws-sdk/middleware-content-length': 3.58.0
'@aws-sdk/middleware-expect-continue': 3.58.0
'@aws-sdk/middleware-flexible-checksums': 3.58.0
'@aws-sdk/middleware-host-header': 3.58.0
'@aws-sdk/middleware-location-constraint': 3.55.0
'@aws-sdk/middleware-logger': 3.55.0
'@aws-sdk/middleware-retry': 3.58.0
'@aws-sdk/middleware-sdk-s3': 3.66.0
'@aws-sdk/middleware-serde': 3.55.0
'@aws-sdk/middleware-signing': 3.58.0
'@aws-sdk/middleware-ssec': 3.55.0
'@aws-sdk/middleware-stack': 3.55.0
'@aws-sdk/middleware-user-agent': 3.58.0
'@aws-sdk/node-config-provider': 3.58.0
'@aws-sdk/node-http-handler': 3.58.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/signature-v4-multi-region': 3.66.0
'@aws-sdk/smithy-client': 3.55.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/url-parser': 3.55.0
'@aws-sdk/util-base64-browser': 3.58.0
'@aws-sdk/util-base64-node': 3.55.0
'@aws-sdk/util-body-length-browser': 3.55.0
'@aws-sdk/util-body-length-node': 3.55.0
'@aws-sdk/util-defaults-mode-browser': 3.55.0
'@aws-sdk/util-defaults-mode-node': 3.58.0
'@aws-sdk/util-stream-browser': 3.55.0
'@aws-sdk/util-stream-node': 3.55.0
'@aws-sdk/util-user-agent-browser': 3.58.0
'@aws-sdk/util-user-agent-node': 3.58.0
'@aws-sdk/util-utf8-browser': 3.55.0
'@aws-sdk/util-utf8-node': 3.55.0
'@aws-sdk/util-waiter': 3.55.0
'@aws-sdk/xml-builder': 3.55.0
entities: 2.2.0
fast-xml-parser: 3.19.0
tslib: 2.3.1
transitivePeerDependencies:
- '@aws-sdk/signature-v4-crt'
dev: false
/@aws-sdk/client-sso/3.67.0:
resolution: {integrity: sha512-njBLSqX2+4eTjeptODxdYgBC8cYwwNE3VwrIFgf+nosIo8Ll07evZgHhfZsyURou0cUUpxFInDf1KaAotH9lBQ==}
engines: {node: '>=12.0.0'}
dependencies:
'@aws-crypto/sha256-browser': 2.0.0
'@aws-crypto/sha256-js': 2.0.0
'@aws-sdk/config-resolver': 3.58.0
'@aws-sdk/fetch-http-handler': 3.58.0
'@aws-sdk/hash-node': 3.55.0
'@aws-sdk/invalid-dependency': 3.55.0
'@aws-sdk/middleware-content-length': 3.58.0
'@aws-sdk/middleware-host-header': 3.58.0
'@aws-sdk/middleware-logger': 3.55.0
'@aws-sdk/middleware-retry': 3.58.0
'@aws-sdk/middleware-serde': 3.55.0
'@aws-sdk/middleware-stack': 3.55.0
'@aws-sdk/middleware-user-agent': 3.58.0
'@aws-sdk/node-config-provider': 3.58.0
'@aws-sdk/node-http-handler': 3.58.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/smithy-client': 3.55.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/url-parser': 3.55.0
'@aws-sdk/util-base64-browser': 3.58.0
'@aws-sdk/util-base64-node': 3.55.0
'@aws-sdk/util-body-length-browser': 3.55.0
'@aws-sdk/util-body-length-node': 3.55.0
'@aws-sdk/util-defaults-mode-browser': 3.55.0
'@aws-sdk/util-defaults-mode-node': 3.58.0
'@aws-sdk/util-user-agent-browser': 3.58.0
'@aws-sdk/util-user-agent-node': 3.58.0
'@aws-sdk/util-utf8-browser': 3.55.0
'@aws-sdk/util-utf8-node': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/client-sts/3.67.0:
resolution: {integrity: sha512-gTWQU/4tPQLMJpLXgSbUss5s5dsyxpXJW2gWosvLLtX5QlchGBzWEawoA3QIxFRkNJrXqLyaVDBdFFqB+l0mVQ==}
engines: {node: '>=12.0.0'}
dependencies:
'@aws-crypto/sha256-browser': 2.0.0
'@aws-crypto/sha256-js': 2.0.0
'@aws-sdk/config-resolver': 3.58.0
'@aws-sdk/credential-provider-node': 3.67.0
'@aws-sdk/fetch-http-handler': 3.58.0
'@aws-sdk/hash-node': 3.55.0
'@aws-sdk/invalid-dependency': 3.55.0
'@aws-sdk/middleware-content-length': 3.58.0
'@aws-sdk/middleware-host-header': 3.58.0
'@aws-sdk/middleware-logger': 3.55.0
'@aws-sdk/middleware-retry': 3.58.0
'@aws-sdk/middleware-sdk-sts': 3.58.0
'@aws-sdk/middleware-serde': 3.55.0
'@aws-sdk/middleware-signing': 3.58.0
'@aws-sdk/middleware-stack': 3.55.0
'@aws-sdk/middleware-user-agent': 3.58.0
'@aws-sdk/node-config-provider': 3.58.0
'@aws-sdk/node-http-handler': 3.58.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/smithy-client': 3.55.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/url-parser': 3.55.0
'@aws-sdk/util-base64-browser': 3.58.0
'@aws-sdk/util-base64-node': 3.55.0
'@aws-sdk/util-body-length-browser': 3.55.0
'@aws-sdk/util-body-length-node': 3.55.0
'@aws-sdk/util-defaults-mode-browser': 3.55.0
'@aws-sdk/util-defaults-mode-node': 3.58.0
'@aws-sdk/util-user-agent-browser': 3.58.0
'@aws-sdk/util-user-agent-node': 3.58.0
'@aws-sdk/util-utf8-browser': 3.55.0
'@aws-sdk/util-utf8-node': 3.55.0
entities: 2.2.0
fast-xml-parser: 3.19.0
tslib: 2.3.1
dev: false
/@aws-sdk/config-resolver/3.58.0:
resolution: {integrity: sha512-NXEwYw0JrXcvenu42QpNMQXK+6pgZ+6bDGfCgOfCC0FmyI+w/CuF36lApwm7InHvHazOaDlwArXm2pfntErKoA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/signature-v4': 3.58.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-config-provider': 3.55.0
'@aws-sdk/util-middleware': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/credential-provider-env/3.55.0:
resolution: {integrity: sha512-4AIIXEdvinLlWNFtrUbUgoB7dkuV04RTcTruVWI4Ub4WSsuSCa72ZU1vqyvcEAOgGGLBmcSaGTWByjiD2sGcGA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/credential-provider-imds/3.58.0:
resolution: {integrity: sha512-CdtnTQ9zqLx1FbXdbgjijLbMcIWOyQM03TFaLSCjI3FNbUwyt3T7StBU9tj/LtbypHhSdXyQBpzUtXTOMWCEhg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/node-config-provider': 3.58.0
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/url-parser': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/credential-provider-ini/3.67.0:
resolution: {integrity: sha512-47uNhLsd2eKWOa+alsyoT48TbtIfYtIJmC85APunHczqfpUC1YHOyHZ3pCzByGrgx4khjnJ323gfq9kreEHCvA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/credential-provider-env': 3.55.0
'@aws-sdk/credential-provider-imds': 3.58.0
'@aws-sdk/credential-provider-sso': 3.67.0
'@aws-sdk/credential-provider-web-identity': 3.55.0
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/shared-ini-file-loader': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/credential-provider-node/3.67.0:
resolution: {integrity: sha512-nxBUJ4rANue9MWQyhrmkZwuKVVpwbUXEqyMwJD1uxEZnYXksmAoVxKW/m4vxy1nh/65wAFCCipeLmqYzwJ8m0A==}
engines: {node: '>=12.0.0'}
dependencies:
'@aws-sdk/credential-provider-env': 3.55.0
'@aws-sdk/credential-provider-imds': 3.58.0
'@aws-sdk/credential-provider-ini': 3.67.0
'@aws-sdk/credential-provider-process': 3.58.0
'@aws-sdk/credential-provider-sso': 3.67.0
'@aws-sdk/credential-provider-web-identity': 3.55.0
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/shared-ini-file-loader': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/credential-provider-process/3.58.0:
resolution: {integrity: sha512-npgFqPUjMhUamf1FvJjBYUdpbWx8XWkKCwJsX73I7IYQAvAi2atCOkdtKq+4rds0VWAYu6vzlaI1tXgFxjOPNQ==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/shared-ini-file-loader': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/credential-provider-sso/3.67.0:
resolution: {integrity: sha512-AwS7tvA++2li0+yZkiCL1zk56EC3N6fDXWDqPEG/lKuviwyv1B+up6r/6ks7ADWbXuOKzrmslS7rn3DT2ZUkig==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/client-sso': 3.67.0
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/shared-ini-file-loader': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/credential-provider-web-identity/3.55.0:
resolution: {integrity: sha512-aKnXfZNGohTuF9rCGYLg4JEIOvWIZ/sb66XMq7bOUrx13KRPDwL/eUQL8quS5jGRLpjXVNvrS17AFf65GbdUBg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/eventstream-marshaller/3.58.0:
resolution: {integrity: sha512-vTdVFLIHGZTx/Anp9GpkTXVuvwSCNOecTutU5Py4i6fATgefWiSutc5Xc/FLujBSc0EhAXDGZIcTMpZC7jUpeg==}
dependencies:
'@aws-crypto/crc32': 2.0.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-hex-encoding': 3.58.0
tslib: 2.3.1
dev: false
/@aws-sdk/eventstream-serde-browser/3.58.0:
resolution: {integrity: sha512-oR5yoOoJrTSUKwbxZSt37bZgMXUUSsOub96E6SOb8wh8TMq2f0wvqeO8A+aaxY487gKpzuVUClp7jSQ9LgiVcw==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/eventstream-marshaller': 3.58.0
'@aws-sdk/eventstream-serde-universal': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/eventstream-serde-config-resolver/3.55.0:
resolution: {integrity: sha512-NTJHLq1sbXyXAaJucKvcdN3Svr/fM2TjHEC3l8P/torFjIsX1+Ykpi8tZt8KsX8RjoUTTfKylh41AjJq0K9X4Q==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/eventstream-serde-node/3.58.0:
resolution: {integrity: sha512-U1DnRVfvKOXty+Bei6oqhRWFzGWzxl0OFHtev9GzC7BE/E6s4Gn695o+NO+9IwQgjOlc/JsGyAcWevq3MDxymg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/eventstream-marshaller': 3.58.0
'@aws-sdk/eventstream-serde-universal': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/eventstream-serde-universal/3.58.0:
resolution: {integrity: sha512-w7czmMNvCCspJi8Ij0lTByCiuYBhyNzYTM1wv33vtF7dL+FJgi4W4c5WFAOtvpsPulobY013TWCjPJG+V0IPGQ==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/eventstream-marshaller': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/fetch-http-handler/3.58.0:
resolution: {integrity: sha512-timF3FjPV5Bd+Kgph83LIKVlPCFObVYzious1a6doeLAT6YFwZpRrWbfP/HzS+DCoYiwUsH69oVJ91BoV66oyA==}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/querystring-builder': 3.55.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-base64-browser': 3.58.0
tslib: 2.3.1
dev: false
/@aws-sdk/hash-blob-browser/3.58.0:
resolution: {integrity: sha512-fdp12BqypRxwvevbJSl/sUhXJRi4Ghv6JKEXAHI1klkR6xY1GRORO5SHWltVY/xl373ERMol5o/n+ra/7jcx/g==}
dependencies:
'@aws-sdk/chunked-blob-reader': 3.55.0
'@aws-sdk/chunked-blob-reader-native': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/hash-node/3.55.0:
resolution: {integrity: sha512-2UdYwY/++AlzWEAFaK9wOed2QSxbzV527vmqKjReLHpPKPrSIlooUxlTH3LU6Y6WVDAzDRtLK43KUVXTLgGK1A==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-buffer-from': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/hash-stream-node/3.58.0:
resolution: {integrity: sha512-y7HEeC3OiuXCRqsHnKDn5yef8UAbnegD9r+OM9bdD+3e6FLAL8Rq7hQTOpwIAiPXuD7HKx8h98s9JLvkwTOBkg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/invalid-dependency/3.55.0:
resolution: {integrity: sha512-delH0lV+78fdD/8MXIt9kTLS6IwHvdhqq9dw/ow5VjTUw+xBwUlfPfZplaai+3hKTKWh6a2WZCeDasNItBv9aA==}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/is-array-buffer/3.55.0:
resolution: {integrity: sha512-NbiPHVYuPxdqdFd6FxzzN3H1BQn/iWA3ri3Ry7AyLeP/tGs1yzEWMwf8BN8TSMALI0GXT6Sh0GDWy3Ok5xB6DA==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/md5-js/3.58.0:
resolution: {integrity: sha512-V5f4Re+CLn3aDF1nrmDqdUtcqBHCyxxD2s2Ot+hZ2JFit+OtJggo1cI03ldTrQpG79rwHG+bHqL2VvNQP7Aj9A==}
dependencies:
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-utf8-browser': 3.55.0
'@aws-sdk/util-utf8-node': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-bucket-endpoint/3.58.0:
resolution: {integrity: sha512-zocLfFzj+NQjXLGZKPJBAYWWldAKBJkGzGVpTfrYx9bxxHTA70Gu+3sx+Xe+iOu8dtQT0OAnIX0wGudOPnTGNg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-arn-parser': 3.55.0
'@aws-sdk/util-config-provider': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-content-length/3.58.0:
resolution: {integrity: sha512-h/BypPkhjv2CpCUbXA8Fa2s7V2GPiz9l11XhYK+sKSuQvQ7Lbq6VhaKaLqfeD3gLVZHgJZSLGl2btdHV1qHNNA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-expect-continue/3.58.0:
resolution: {integrity: sha512-nx6X6qLPwvbJrGoPxXSu4tsOek2eRnnjk78hhRUDfxFewpHJQLSPlyNKkXAo+C3syVALe6RJRmUYu5bShY6FfA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/middleware-header-default': 3.58.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-flexible-checksums/3.58.0:
resolution: {integrity: sha512-R8S3U1boaIb7+kYhLJBks7rv/eaGj7I5T/2CgmcGY1BJBUU0h0arjPC7eeA/5wV29EHapoxVYQvJda//706rCw==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-crypto/crc32': 2.0.0
'@aws-crypto/crc32c': 2.0.0
'@aws-sdk/is-array-buffer': 3.55.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-header-default/3.58.0:
resolution: {integrity: sha512-7F+CdLLauMmNbwFGYrE2pKsgTKY8G2PgazHmaE9s3FySEFcGPWmiEAG8sVImfZooj8gxGFQMLr97nanWjhSq2Q==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-host-header/3.58.0:
resolution: {integrity: sha512-q/UKGcanm9e6DBRNN6UKhVqLvpRRdZWbmmPCeDNr4HqhCmgT6i1OvWdhAMOnT++hvCX8DpTsIXzNSlY6zWAxBg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-location-constraint/3.55.0:
resolution: {integrity: sha512-OvCKwBFbl8Gbfk0HGX00pkdORJN8BPuH/O5l3+mOBWuwILPuckRP5WGnL+1HT/gu4hHS6h1lpxUrPxUOoeKIAg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-logger/3.55.0:
resolution: {integrity: sha512-PtRbVrxEzDmeV9prBIP4/9or7R5Dj66mjbFSvNRGZ0n+UBfBFfVRfNrhQPNzQpfV9A3KVl9YyWCVXDSW+/rk9Q==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-retry/3.58.0:
resolution: {integrity: sha512-sfSq+t0Yy47DQwrWGpA8iOx9sd26l4l1JDVTwHNi7+OKD4ClRPVCEdw3bTbbyYz/PV4f9AEfAZ6jwtSff4wkGw==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/service-error-classification': 3.55.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-middleware': 3.55.0
tslib: 2.3.1
uuid: 8.3.2
dev: false
/@aws-sdk/middleware-sdk-s3/3.66.0:
resolution: {integrity: sha512-4ACAdKAZkIjEK99UwoaKTrTGhS7qGqyLmjiGHlzR0ggMUUVmlep7EtcluImFtT6pi+ANVLDzuZGa+95MwGY/Qg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-arn-parser': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-sdk-sts/3.58.0:
resolution: {integrity: sha512-HUz7MhcsSDDTGygOwL61l4voc0pZco06J3z06JjTX19D5XxcQ7hSCtkHHHz0oMb9M1himVSiEon2tjhjsnB99g==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/middleware-signing': 3.58.0
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/signature-v4': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-serde/3.55.0:
resolution: {integrity: sha512-NkEbTDrSZcC2NhuvfjXHKJEl0xgI2B5tMAwi/rMOq/TEnARwVUL9qAy+5lgeiPCqebiNllWatARrFgAaYf0VeA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-signing/3.58.0:
resolution: {integrity: sha512-4FXubHB66GbhyZUlo6YPQoWpYfED15GNbEmHbJLSONzrVzZR3IkViSPLasDngVm1a050JqKuqNkFYGJBP4No/Q==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/signature-v4': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-ssec/3.55.0:
resolution: {integrity: sha512-HTdA23hksOphQe0TmYORsa/kMNnKRGbdh0VJcsDGHQScJXzJ+C//THwfcoklff0XZfC+vGh93PECBWqixMELZw==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-stack/3.55.0:
resolution: {integrity: sha512-ouD+wFz8W2R0ZQ8HrbhgN8tg1jyINEg9lPEEXY79w1Q5sf94LJ90XKAMVk02rw3dJalUWjLHf0OQe1/qxZfHyA==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/middleware-user-agent/3.58.0:
resolution: {integrity: sha512-1c69bIWM63JwXijXvb9IWwcwQ/gViKMZ1lhxv52NvdG5VSxWXXsFJ2jETEXZoAypwT97Hmf3xo9SYuaHcKoq+g==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/node-config-provider/3.58.0:
resolution: {integrity: sha512-AMcPqPhKxo/3/yOMS9PsKlI0GWp2/8eD6gSlhzdBpznPCKplyqXOSnSX7wS814Cyh373hFSjCaOrCOA9/EYtDg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/shared-ini-file-loader': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/node-http-handler/3.58.0:
resolution: {integrity: sha512-D9xVZG2nfo4GbPsby3JuBiAhpqXTFk1+CfuQU0AZv0gQvE3fFTCnB3za83jo7JV/pyRPU+s+/LHIpxCWUHzStg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/abort-controller': 3.55.0
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/querystring-builder': 3.55.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/property-provider/3.55.0:
resolution: {integrity: sha512-o7cKFJSHq5WOhwPsspYrzNto35oKKZvESZuWDtLxaZKSI6l7zpA366BI4kDG6Tc9i2+teV553MbxyZ9eya5A8g==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/protocol-http/3.58.0:
resolution: {integrity: sha512-0yFFRPbR+CCa9eOQBBQ2qtrIDLYqSMN0y7G4iqVM8wQdIw7n3QK1PsTI3RNPGJ3Oi2krFTw5uUKqQQZPZEBuVQ==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/querystring-builder/3.55.0:
resolution: {integrity: sha512-/ZAXNipt9nRR8k+eowwukE/YjXnQ49p5w/MkaQxsBk3IuIf7MAcgVg8glHr0igH84GfUQ7ZVP8v+G2S3tKUG+Q==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-uri-escape': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/querystring-parser/3.55.0:
resolution: {integrity: sha512-e+2FLgo+eDx7oh7ap5HngN9XSVMxredAVztLHxCcSN0lFHHHzMa8b2SpXbaowUxQHh7ziymSqvOrPYFQ71Filg==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/service-error-classification/3.55.0:
resolution: {integrity: sha512-HdjnDyarsa1Avq1MJurkLyEe9c3eRa76dPmK4TmRGgwJ+tInEzGHL0rBW7V8xBK+PDF+fJQ71hvm8jPYmzvBwQ==}
engines: {node: '>= 12.0.0'}
dev: false
/@aws-sdk/shared-ini-file-loader/3.58.0:
resolution: {integrity: sha512-ARDKQerIzgNs/MFNdCEuK2lgRJ1lneAaJw0p9O1LkJUvcSibvkSATwny7vwJMueOf+ae1Pf+8+54OMNIt0nTkQ==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/signature-v4-multi-region/3.66.0:
resolution: {integrity: sha512-Akvc8G9Del2+umg0R/5Gc/PWgQwbxxTXdnm6YTHtDzvyPPiYWBs6au6WqJQqcqk07gcQV67MLVqFFhnFuLlcVg==}
engines: {node: '>= 12.0.0'}
peerDependencies:
'@aws-sdk/signature-v4-crt': ^3.66.0
peerDependenciesMeta:
'@aws-sdk/signature-v4-crt':
optional: true
dependencies:
'@aws-sdk/protocol-http': 3.58.0
'@aws-sdk/signature-v4': 3.58.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-arn-parser': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/signature-v4/3.58.0:
resolution: {integrity: sha512-flEo8p3XkzWoBDqnIUQre4jLuT5aLnmfQNI8c2uSjyJ3OBxpJ0iS1cDu3E++d1/pN6Q8o0KOmr2ypHeiyBOujw==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/is-array-buffer': 3.55.0
'@aws-sdk/types': 3.55.0
'@aws-sdk/util-hex-encoding': 3.58.0
'@aws-sdk/util-middleware': 3.55.0
'@aws-sdk/util-uri-escape': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/smithy-client/3.55.0:
resolution: {integrity: sha512-YgBpqg6R3Qg8CH9biOP1N1lYTvh8VLGD6AoDGgy/R1dQSqRQuxgKANLl3DOVcZnIZLsw4TdB0m7U+ZPtirPR1Q==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/middleware-stack': 3.55.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/types/3.55.0:
resolution: {integrity: sha512-wrDZjuy1CVAYxDCbm3bWQIKMGfNs7XXmG0eG4858Ixgqmq2avsIn5TORy8ynBxcXn9aekV/+tGEQ7BBSYzIVNQ==}
engines: {node: '>= 12.0.0'}
dev: false
/@aws-sdk/url-parser/3.55.0:
resolution: {integrity: sha512-qrTwN5xIgTLreqLnZ+x3cAudjNKfxi6srW1H/px2mk4lb2U9B4fpGjZ6VU+XV8U2kR+YlT8J6Jo5iwuVGfC91A==}
dependencies:
'@aws-sdk/querystring-parser': 3.55.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-arn-parser/3.55.0:
resolution: {integrity: sha512-76KJxp4MRWufHYWys7DFl64znr5yeJ3AIQNAPCKKw1sP0hzO7p6Kx0PaJnw9x+CPSzOrT4NbuApL6/srYhKDGg==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-base64-browser/3.58.0:
resolution: {integrity: sha512-0ebsXIZNpu/fup9OgsFPnRKfCFbuuI9PPRzvP6twzLxUB0c/aix6Co7LGHFKcRKHZdaykoJMXArf8eHj2Nzv1Q==}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-base64-node/3.55.0:
resolution: {integrity: sha512-UQ/ZuNoAc8CFMpSiRYmevaTsuRKzLwulZTnM8LNlIt9Wx1tpNvqp80cfvVj7yySKROtEi20wq29h31dZf1eYNQ==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/util-buffer-from': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-body-length-browser/3.55.0:
resolution: {integrity: sha512-Ei2OCzXQw5N6ZkTMZbamUzc1z+z1R1Ja5tMEagz5BxuX4vWdBObT+uGlSzL8yvTbjoPjnxWA2aXyEqaUP3JS8Q==}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-body-length-node/3.55.0:
resolution: {integrity: sha512-lU1d4I+9wJwydduXs0SxSfd+mHKjxeyd39VwOv6i2KSwWkPbji9UQqpflKLKw+r45jL7+xU/zfeTUg5Tt/3Gew==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-buffer-from/3.55.0:
resolution: {integrity: sha512-uVzKG1UgvnV7XX2FPTylBujYMKBPBaq/qFBxfl0LVNfrty7YjpfieQxAe6yRLD+T0Kir/WDQwGvYC+tOYG3IGA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/is-array-buffer': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-config-provider/3.55.0:
resolution: {integrity: sha512-30dzofQQfx6tp1jVZkZ0DGRsT0wwC15nEysKRiAcjncM64A0Cm6sra77d0os3vbKiKoPCI/lMsFr4o3533+qvQ==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-defaults-mode-browser/3.55.0:
resolution: {integrity: sha512-OS3gAwR84bHz7ObhjsSJM+grfeaBq3leGrj7xiX4BH3C8J+c10GMo3fqx1pV8Fq5F+9lMmhHpfOocD63SN5Q8A==}
engines: {node: '>= 10.0.0'}
dependencies:
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/types': 3.55.0
bowser: 2.11.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-defaults-mode-node/3.58.0:
resolution: {integrity: sha512-KNUCp0MXI+z3Z3pQCKDkx3Stdy1TXDjcUB+ZJFxRTJGIuBYwX4fV6G8s/zeFJi5Qv1ztR3CJ9fWJGsrx9mQ5EA==}
engines: {node: '>= 10.0.0'}
dependencies:
'@aws-sdk/config-resolver': 3.58.0
'@aws-sdk/credential-provider-imds': 3.58.0
'@aws-sdk/node-config-provider': 3.58.0
'@aws-sdk/property-provider': 3.55.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-hex-encoding/3.58.0:
resolution: {integrity: sha512-Rl+jXUzk/FJkOLYfUVYPhKa2aUmTpeobRP31l8IatQltSzDgLyRHO35f6UEs7Ztn5s1jbu/POatLAZ2WjbgVyg==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-locate-window/3.55.0:
resolution: {integrity: sha512-0sPmK2JaJE2BbTcnvybzob/VrFKCXKfN4CUKcvn0yGg/me7Bz+vtzQRB3Xp+YSx+7OtWxzv63wsvHoAnXvgxgg==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-middleware/3.55.0:
resolution: {integrity: sha512-82fW2XV+rUalv8lkd4VlhpPp6xnXO5n9sckMp1N+TrQ+p8eqxqT0+o8n1/6s9Qsnkw64Y3m6+EfCdc8/uFOY2g==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-stream-browser/3.55.0:
resolution: {integrity: sha512-3f/zQsAqexJpKssCL0adTjG8WO+NPQ63E3TingyKpnCnHQPEnqPdya5I5OLGzZ0WR0iUWRtpuW0MtuDabyLDWw==}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-stream-node/3.55.0:
resolution: {integrity: sha512-brCK3iENvXEL7BK5eDAdkZ2VuBSvXj7DH9EQezxl4Ntrj1lvb+McOk9WoU/o7yzE7A/bzEJEoNQAPi+VPNbb/w==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-uri-escape/3.55.0:
resolution: {integrity: sha512-mmdDLUpFCN2nkfwlLdOM54lTD528GiGSPN1qb8XtGLgZsJUmg3uJSFIN2lPeSbEwJB3NFjVas/rnQC48i7mV8w==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-user-agent-browser/3.58.0:
resolution: {integrity: sha512-aJpqCvT09giJRg5xFTBDBRAVF0k0yq3OEf6UTuiOVf5azlL2MGp6PJ/xkJp9Z06PuQQkwBJ/2nIQZemo02a5Sw==}
dependencies:
'@aws-sdk/types': 3.55.0
bowser: 2.11.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-user-agent-node/3.58.0:
resolution: {integrity: sha512-VlbY/nzWdN2pfLUHqKvnlGBQ6tEeV4jyK9ggAD2Szjj0bkYvaaKwpBKswQmuJpi5/J2v7Bo4ayBLnqDL7PgzLA==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/node-config-provider': 3.58.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-utf8-browser/3.55.0:
resolution: {integrity: sha512-ljzqJcyjfJpEVSIAxwtIS8xMRUly84BdjlBXyp6cu4G8TUufgjNS31LWdhyGhgmW5vYBNr+LTz0Kwf6J+ou7Ug==}
dependencies:
tslib: 2.3.1
dev: false
/@aws-sdk/util-utf8-node/3.55.0:
resolution: {integrity: sha512-FsFm7GFaC7j0tlPEm/ri8bU2QCwFW5WKjxUg8lm1oWaxplCpKGUsmcfPJ4sw58GIoyoGu4QXBK60oCWosZYYdQ==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/util-buffer-from': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/util-waiter/3.55.0:
resolution: {integrity: sha512-Do34MKPFSC/+zVN6vY+FZ+0WN61hzga4nPoAC590AOjs8rW6/H6sDN6Gz1KAZbPnuQUZfvsIJjMxN7lblXHJkQ==}
engines: {node: '>= 12.0.0'}
dependencies:
'@aws-sdk/abort-controller': 3.55.0
'@aws-sdk/types': 3.55.0
tslib: 2.3.1
dev: false
/@aws-sdk/xml-builder/3.55.0:
resolution: {integrity: sha512-BH+i5S2FLprmfSeIuGy3UbNtEoJPVjh8arl5+LV3i2KY/+TmrS4yT8JtztDlDxHF0cMtNLZNO0KEPtsACS6SOg==}
engines: {node: '>= 12.0.0'}
dependencies:
tslib: 2.3.1
dev: false
/@babel/code-frame/7.16.7:
resolution: {integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==}
engines: {node: '>=6.9.0'}
@ -5151,6 +6006,10 @@ packages:
resolution: {integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24=}
dev: false
/bowser/2.11.0:
resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
dev: false
/boxen/5.1.2:
resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
engines: {node: '>=10'}
@ -7459,6 +8318,11 @@ packages:
punycode: 1.4.1
dev: false
/fast-xml-parser/3.19.0:
resolution: {integrity: sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==}
hasBin: true
dev: false
/fastq/1.13.0:
resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==}
dependencies:

View File

@ -10,6 +10,7 @@
"lint": "eslint --fix --ext .ts ./src"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.67.0",
"@nestjs/axios": "^0.0.7",
"@nestjs/common": "^8.4.4",
"@nestjs/config": "^2.0.0",

View File

@ -7,6 +7,7 @@ import authConfig from './auth.config';
import databaseConfig from './database.config';
import googleConfig from './google.config';
import sendgridConfig from './sendgrid.config';
import storageConfig from './storage.config';
const validationSchema = Joi.object({
// App
@ -40,12 +41,20 @@ const validationSchema = Joi.object({
SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID: Joi.string().allow(''),
SENDGRID_FROM_NAME: Joi.string().allow(''),
SENDGRID_FROM_EMAIL: Joi.string().allow(''),
// Storage
STORAGE_BUCKET: Joi.string().allow(''),
STORAGE_REGION: Joi.string().allow(''),
STORAGE_ENDPOINT: Joi.string().allow(''),
STORAGE_URL_PREFIX: Joi.string().allow(''),
STORAGE_ACCESS_KEY: Joi.string().allow(''),
STORAGE_SECRET_KEY: Joi.string().allow(''),
});
@Module({
imports: [
NestConfigModule.forRoot({
load: [appConfig, authConfig, databaseConfig, googleConfig, sendgridConfig],
load: [appConfig, authConfig, databaseConfig, googleConfig, sendgridConfig, storageConfig],
validationSchema: validationSchema,
}),
],

View File

@ -0,0 +1,10 @@
import { registerAs } from '@nestjs/config';
export default registerAs('storage', () => ({
bucket: process.env.STORAGE_BUCKET,
region: process.env.STORAGE_REGION,
endpoint: process.env.STORAGE_ENDPOINT,
urlPrefix: process.env.STORAGE_URL_PREFIX,
accessKey: process.env.STORAGE_ACCESS_KEY,
secretKey: process.env.STORAGE_SECRET_KEY,
}));

View File

@ -99,7 +99,7 @@ export class ResumeController {
@Put(':id/photo')
@UseInterceptors(FileInterceptor('file'))
async uploadPhoto(@Param('id') id: string, @User('id') userId: number, @UploadedFile() file: Express.Multer.File) {
return this.resumeService.uploadPhoto(+id, userId, file.filename);
return this.resumeService.uploadPhoto(+id, userId, file);
}
@UseGuards(JwtAuthGuard)

View File

@ -2,12 +2,9 @@ import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MulterModule } from '@nestjs/platform-express';
import { TypeOrmModule } from '@nestjs/typeorm';
import { mkdir } from 'fs/promises';
import { diskStorage } from 'multer';
import { extname, join } from 'path';
import { memoryStorage } from 'multer';
import { AuthModule } from '@/auth/auth.module';
import { User } from '@/users/entities/user.entity';
import { UsersModule } from '@/users/users.module';
import { Resume } from './entities/resume.entity';
@ -18,24 +15,7 @@ import { ResumeService } from './resume.service';
imports: [
ConfigModule,
TypeOrmModule.forFeature([Resume]),
MulterModule.register({
storage: diskStorage({
destination: async (req, _, cb) => {
const userId = (req.user as User).id;
const resumeId = +req.params.id;
const destination = join(__dirname, '..', `assets/uploads/${userId}/${resumeId}`);
await mkdir(destination, { recursive: true });
cb(null, destination);
},
filename: (_, file, cb) => {
const filename = new Date().getTime() + extname(file.originalname);
cb(null, filename);
},
}),
}),
MulterModule.register({ storage: memoryStorage() }),
AuthModule,
UsersModule,
],

View File

@ -1,11 +1,11 @@
import { DeleteObjectCommand, PutObjectCommand, S3, S3Client } from '@aws-sdk/client-s3';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { Resume as ResumeSchema } from '@reactive-resume/schema';
import { unlink } from 'fs/promises';
import { pick, sample, set } from 'lodash';
import { nanoid } from 'nanoid';
import { join } from 'path';
import { extname } from 'path';
import { Repository } from 'typeorm';
import { PostgresErrorCode } from '@/database/errorCodes.enum';
@ -22,11 +22,22 @@ export const SHORT_ID_LENGTH = 8;
@Injectable()
export class ResumeService {
private s3Client: S3Client;
constructor(
@InjectRepository(Resume) private resumeRepository: Repository<Resume>,
private configService: ConfigService,
private usersService: UsersService
) {}
) {
this.s3Client = new S3({
endpoint: configService.get<string>('storage.endpoint'),
region: configService.get<string>('storage.region'),
credentials: {
accessKeyId: configService.get<string>('storage.accessKey'),
secretAccessKey: configService.get<string>('storage.secretKey'),
},
});
}
async create(createResumeDto: CreateResumeDto, userId: number) {
try {
@ -216,22 +227,44 @@ export class ResumeService {
return this.resumeRepository.update(id, nextResume);
}
async uploadPhoto(id: number, userId: number, filename: string) {
async uploadPhoto(id: number, userId: number, file: Express.Multer.File) {
const resume = await this.findOne(id, userId);
const url = `/api/assets/uploads/${userId}/${id}/${filename}`;
const updatedResume = set(resume, 'basics.photo.url', url);
const urlPrefix = this.configService.get<string>('storage.urlPrefix');
const filename = new Date().getTime() + extname(file.originalname);
const key = `uploads/${userId}/${id}/${filename}`;
await this.s3Client.send(
new PutObjectCommand({
Bucket: this.configService.get<string>('storage.bucket'),
Key: key,
Body: file.buffer,
ACL: 'public-read',
})
);
const publicUrl = urlPrefix + key;
const updatedResume = set(resume, 'basics.photo.url', publicUrl);
return this.resumeRepository.save<Resume>(updatedResume);
}
async deletePhoto(id: number, userId: number) {
const resume = await this.findOne(id, userId);
const filepath = new URL(resume.basics.photo.url).pathname;
const photoPath = join(__dirname, '..', `assets/${filepath}`);
const updatedResume = set(resume, 'basics.photo.url', '');
await unlink(photoPath);
const urlPrefix = this.configService.get<string>('storage.urlPrefix');
const publicUrl = resume.basics.photo.url;
const key = publicUrl.replace(urlPrefix, '');
await this.s3Client.send(
new DeleteObjectCommand({
Bucket: this.configService.get<string>('storage.bucket'),
Key: key,
})
);
const updatedResume = set(resume, 'basics.photo.url', '');
return this.resumeRepository.save<Resume>(updatedResume);
}