From 423f145c3644e3827bd1ba95ddfa49d73290061e Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Mon, 12 Feb 2024 14:25:04 -0800 Subject: [PATCH 1/4] chore(storage): enable eslint and remove tslint --- .eslintrc.js | 2 +- packages/storage/package.json | 3 +- packages/storage/tslint.json | 53 ----------------------------------- 3 files changed, 3 insertions(+), 55 deletions(-) delete mode 100644 packages/storage/tslint.json diff --git a/.eslintrc.js b/.eslintrc.js index 1b77b469b46..679e9c307d1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -56,7 +56,7 @@ module.exports = { 'packages/react-native', 'packages/rtn-push-notification', 'packages/rtn-web-browser', - 'packages/storage', + // 'packages/storage', ], rules: { camelcase: [ diff --git a/packages/storage/package.json b/packages/storage/package.json index e7d2633c848..0cd7ef0ecfd 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -31,7 +31,8 @@ "clean": "npm run clean:size && rimraf lib-esm lib dist", "clean:size": "rimraf dual-publish-tmp tmp*", "format": "echo \"Not implemented\"", - "lint": "tslint 'src/**/*.ts' && npm run ts-coverage", + "lint": "eslint '**/*.{ts,tsx}' && npm run ts-coverage", + "lint:fix": "eslint '**/*.{ts,tsx}' --fix", "ts-coverage": "typescript-coverage-report -p ./tsconfig.build.json -t 90.31" }, "typesVersions": { diff --git a/packages/storage/tslint.json b/packages/storage/tslint.json deleted file mode 100644 index 7fac7237f19..00000000000 --- a/packages/storage/tslint.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "linterOptions": { - "exclude": ["src/providers/s3/utils/client/types.ts"] - }, - "defaultSeverity": "error", - "plugins": ["prettier"], - "extends": [], - "jsRules": {}, - "rules": { - "prefer-const": true, - "max-line-length": [ - true, - { - "limit": 120, - "ignore-pattern": "//" - } - ], - "no-var-keyword": true, - "object-literal-shorthand": true, - "no-eval": true, - "space-before-function-paren": [ - true, - { - "anonymous": "ignore", - "named": "never" - } - ], - "no-parameter-reassignment": true, - "align": [true, "parameters"], - "no-duplicate-imports": true, - "one-variable-per-declaration": [false, "ignore-for-loop"], - "triple-equals": [true, "allow-null-check"], - "comment-format": [true, "check-space"], - "indent": [false], - "whitespace": [ - false, - "check-branch", - "check-decl", - "check-operator", - "check-preblock" - ], - "eofline": true, - "variable-name": [ - true, - "check-format", - "allow-pascal-case", - "allow-snake-case", - "allow-leading-underscore" - ], - "semicolon": [true, "always", "ignore-interfaces"] - }, - "rulesDirectory": [] -} From 59565d1b0d3a9d43d5799a8d365c258bdaea3040 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Mon, 12 Feb 2024 14:25:59 -0800 Subject: [PATCH 2/4] chore(storage): run yarn lint:fix --- packages/storage/src/errors/CanceledError.ts | 1 + .../storage/src/providers/s3/apis/copy.ts | 4 ++- .../src/providers/s3/apis/downloadData.ts | 2 ++ .../src/providers/s3/apis/getProperties.ts | 4 ++- .../storage/src/providers/s3/apis/getUrl.ts | 2 ++ .../src/providers/s3/apis/internal/copy.ts | 1 + .../s3/apis/internal/getProperties.ts | 2 ++ .../src/providers/s3/apis/internal/getUrl.ts | 6 +++-- .../src/providers/s3/apis/internal/list.ts | 13 ++++++---- .../src/providers/s3/apis/internal/remove.ts | 2 ++ .../storage/src/providers/s3/apis/list.ts | 8 +++--- .../storage/src/providers/s3/apis/remove.ts | 2 ++ .../src/providers/s3/apis/server/copy.ts | 1 + .../providers/s3/apis/server/getProperties.ts | 1 + .../src/providers/s3/apis/server/getUrl.ts | 1 + .../src/providers/s3/apis/server/list.ts | 7 ++--- .../src/providers/s3/apis/server/remove.ts | 1 + .../s3/apis/uploadData/byteLength.ts | 1 + .../src/providers/s3/apis/uploadData/index.ts | 5 +++- .../uploadData/multipart/calculatePartSize.ts | 1 + .../uploadData/multipart/getDataChunker.ts | 6 +++-- .../uploadData/multipart/initialUpload.ts | 19 ++++++++------ .../uploadData/multipart/progressTracker.ts | 7 ++--- .../apis/uploadData/multipart/uploadCache.ts | 17 +++++++----- .../uploadData/multipart/uploadHandlers.ts | 14 +++++----- .../multipart/uploadPartExecutor.ts | 11 ++++---- .../storage/src/providers/s3/types/inputs.ts | 8 +++--- .../storage/src/providers/s3/types/options.ts | 22 ++++++++-------- .../storage/src/providers/s3/types/outputs.ts | 2 +- .../s3/utils/client/abortMultipartUpload.ts | 3 ++- .../src/providers/s3/utils/client/base.ts | 8 +++--- .../utils/client/completeMultipartUpload.ts | 8 ++++++ .../providers/s3/utils/client/copyObject.ts | 5 +++- .../s3/utils/client/createMultipartUpload.ts | 6 +++-- .../providers/s3/utils/client/deleteObject.ts | 5 ++-- .../providers/s3/utils/client/getObject.ts | 12 +++++---- .../providers/s3/utils/client/headObject.ts | 5 ++-- .../s3/utils/client/listObjectsV2.ts | 3 +++ .../providers/s3/utils/client/listParts.ts | 7 +++-- .../providers/s3/utils/client/putObject.ts | 5 ++-- .../client/runtime/base64/index.browser.ts | 1 + .../client/runtime/contentSha256middleware.ts | 6 +++-- .../client/runtime/s3TransferHandler/fetch.ts | 4 ++- .../client/runtime/s3TransferHandler/xhr.ts | 10 +++---- .../client/runtime/xhrTransferHandler.ts | 18 ++++++++----- .../s3/utils/client/runtime/xmlParser/dom.ts | 2 ++ .../utils/client/runtime/xmlParser/pureJs.ts | 2 ++ .../src/providers/s3/utils/client/types.ts | 26 +++++++++---------- .../providers/s3/utils/client/uploadPart.ts | 5 ++-- .../utils/client/utils/deserializeHelpers.ts | 9 +++++-- .../s3/utils/client/utils/parsePayload.ts | 6 +++-- .../s3/utils/client/utils/serializeHelpers.ts | 5 +++- .../src/providers/s3/utils/md5.native.ts | 10 +++++-- .../storage/src/providers/s3/utils/md5.ts | 14 +++++++--- .../s3/utils/resolveS3ConfigAndInput.ts | 12 +++++---- .../src/providers/s3/utils/transferTask.ts | 26 +++++++++++-------- .../src/providers/s3/utils/userAgent.ts | 2 +- packages/storage/src/types/common.ts | 14 +++++----- packages/storage/src/types/inputs.ts | 22 ++++++++-------- packages/storage/src/types/options.ts | 4 +-- packages/storage/src/types/outputs.ts | 12 ++++----- packages/storage/src/utils/resolvePrefix.ts | 7 +++-- 62 files changed, 287 insertions(+), 168 deletions(-) diff --git a/packages/storage/src/errors/CanceledError.ts b/packages/storage/src/errors/CanceledError.ts index 8303aa86751..9388653432a 100644 --- a/packages/storage/src/errors/CanceledError.ts +++ b/packages/storage/src/errors/CanceledError.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { AmplifyErrorParams } from '@aws-amplify/core/internals/utils'; + import { StorageError } from './StorageError'; /** diff --git a/packages/storage/src/providers/s3/apis/copy.ts b/packages/storage/src/providers/s3/apis/copy.ts index 1eed73e3972..ca0ae3e8a39 100644 --- a/packages/storage/src/providers/s3/apis/copy.ts +++ b/packages/storage/src/providers/s3/apis/copy.ts @@ -2,10 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; + import { CopyInput, CopyOutput, S3Exception } from '../types'; -import { copy as copyInternal } from './internal/copy'; import { StorageValidationErrorCode } from '../../../errors/types/validation'; +import { copy as copyInternal } from './internal/copy'; + /** * Copy an object from a source object to a new object within the same bucket. Can optionally copy files across * different level or identityId (if source object's level is 'protected'). diff --git a/packages/storage/src/providers/s3/apis/downloadData.ts b/packages/storage/src/providers/s3/apis/downloadData.ts index 2af97220d24..b10fc35d8ea 100644 --- a/packages/storage/src/providers/s3/apis/downloadData.ts +++ b/packages/storage/src/providers/s3/apis/downloadData.ts @@ -51,6 +51,7 @@ export const downloadData = (input: DownloadDataInput): DownloadDataOutput => { abortController.abort(message); }, }); + return downloadTask; }; @@ -91,6 +92,7 @@ const downloadDataJob = }), }, ); + return { key, body, diff --git a/packages/storage/src/providers/s3/apis/getProperties.ts b/packages/storage/src/providers/s3/apis/getProperties.ts index 7d3f9765e37..5fe882e4808 100644 --- a/packages/storage/src/providers/s3/apis/getProperties.ts +++ b/packages/storage/src/providers/s3/apis/getProperties.ts @@ -2,7 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; -import { GetPropertiesOutput, GetPropertiesInput, S3Exception } from '../types'; + +import { GetPropertiesInput, GetPropertiesOutput, S3Exception } from '../types'; + import { getProperties as getPropertiesInternal } from './internal/getProperties'; /** diff --git a/packages/storage/src/providers/s3/apis/getUrl.ts b/packages/storage/src/providers/s3/apis/getUrl.ts index 0ceb612c06c..6cbd3ee5315 100644 --- a/packages/storage/src/providers/s3/apis/getUrl.ts +++ b/packages/storage/src/providers/s3/apis/getUrl.ts @@ -2,8 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; + import { StorageValidationErrorCode } from '../../../errors/types/validation'; import { GetUrlInput, GetUrlOutput, S3Exception } from '../types'; + import { getUrl as getUrlInternal } from './internal/getUrl'; /** diff --git a/packages/storage/src/providers/s3/apis/internal/copy.ts b/packages/storage/src/providers/s3/apis/internal/copy.ts index a5c0f3b159d..feefdd1b5c3 100644 --- a/packages/storage/src/providers/s3/apis/internal/copy.ts +++ b/packages/storage/src/providers/s3/apis/internal/copy.ts @@ -3,6 +3,7 @@ import { AmplifyClassV6 } from '@aws-amplify/core'; import { StorageAction } from '@aws-amplify/core/internals/utils'; + import { CopyInput, CopyOutput } from '../../types'; import { resolveS3ConfigAndInput } from '../../utils'; import { StorageValidationErrorCode } from '../../../../errors/types/validation'; diff --git a/packages/storage/src/providers/s3/apis/internal/getProperties.ts b/packages/storage/src/providers/s3/apis/internal/getProperties.ts index b0343e1ff64..adf79c50b8e 100644 --- a/packages/storage/src/providers/s3/apis/internal/getProperties.ts +++ b/packages/storage/src/providers/s3/apis/internal/getProperties.ts @@ -3,6 +3,7 @@ import { AmplifyClassV6 } from '@aws-amplify/core'; import { StorageAction } from '@aws-amplify/core/internals/utils'; + import { GetPropertiesInput, GetPropertiesOutput } from '../../types'; import { resolveS3ConfigAndInput } from '../../utils'; import { headObject } from '../../utils/client'; @@ -34,6 +35,7 @@ export const getProperties = async function ( Key: finalKey, }, ); + return { key, contentType: response.ContentType, diff --git a/packages/storage/src/providers/s3/apis/internal/getUrl.ts b/packages/storage/src/providers/s3/apis/internal/getUrl.ts index 24cd799983a..674c10ea717 100644 --- a/packages/storage/src/providers/s3/apis/internal/getUrl.ts +++ b/packages/storage/src/providers/s3/apis/internal/getUrl.ts @@ -2,17 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 import { AmplifyClassV6 } from '@aws-amplify/core'; +import { StorageAction } from '@aws-amplify/core/internals/utils'; + import { GetUrlInput, GetUrlOutput } from '../../types'; import { StorageValidationErrorCode } from '../../../../errors/types/validation'; import { getPresignedGetObjectUrl } from '../../utils/client'; -import { getProperties } from './getProperties'; import { resolveS3ConfigAndInput } from '../../utils'; import { assertValidationError } from '../../../../errors/utils/assertValidationError'; import { DEFAULT_PRESIGN_EXPIRATION, MAX_URL_EXPIRATION, } from '../../utils/constants'; -import { StorageAction } from '@aws-amplify/core/internals/utils'; + +import { getProperties } from './getProperties'; export const getUrl = async function ( amplify: AmplifyClassV6, diff --git a/packages/storage/src/providers/s3/apis/internal/list.ts b/packages/storage/src/providers/s3/apis/internal/list.ts index 15b6ed43cab..b31e67ec5d7 100644 --- a/packages/storage/src/providers/s3/apis/internal/list.ts +++ b/packages/storage/src/providers/s3/apis/internal/list.ts @@ -3,30 +3,31 @@ import { AmplifyClassV6 } from '@aws-amplify/core'; import { StorageAction } from '@aws-amplify/core/internals/utils'; + import { ListAllInput, - ListPaginateInput, ListAllOutput, - ListPaginateOutput, ListOutputItem, + ListPaginateInput, + ListPaginateOutput, } from '../../types'; import { resolveS3ConfigAndInput } from '../../utils'; import { ResolvedS3Config } from '../../types/options'; import { - listObjectsV2, ListObjectsV2Input, ListObjectsV2Output, + listObjectsV2, } from '../../utils/client'; import { getStorageUserAgentValue } from '../../utils/userAgent'; import { logger } from '../../../../utils'; const MAX_PAGE_SIZE = 1000; -type ListInputArgs = { +interface ListInputArgs { s3Config: ResolvedS3Config; listParams: ListObjectsV2Input; prefix: string; -}; +} export const list = async ( amplify: AmplifyClassV6, @@ -54,6 +55,7 @@ export const list = async ( ContinuationToken: options?.listAll ? undefined : options?.nextToken, }; logger.debug(`listing items from "${listParams.Prefix}"`); + return options.listAll ? await _listAll({ s3Config, listParams, prefix }) : await _list({ s3Config, listParams, prefix }); @@ -116,6 +118,7 @@ const _list = async ({ lastModified: item.LastModified, size: item.Size, })); + return { items: listResult, nextToken: response.NextContinuationToken, diff --git a/packages/storage/src/providers/s3/apis/internal/remove.ts b/packages/storage/src/providers/s3/apis/internal/remove.ts index f1283df9c29..7eae6bc5854 100644 --- a/packages/storage/src/providers/s3/apis/internal/remove.ts +++ b/packages/storage/src/providers/s3/apis/internal/remove.ts @@ -3,6 +3,7 @@ import { AmplifyClassV6 } from '@aws-amplify/core'; import { StorageAction } from '@aws-amplify/core/internals/utils'; + import { RemoveInput, RemoveOutput } from '../../types'; import { resolveS3ConfigAndInput } from '../../utils'; import { deleteObject } from '../../utils/client'; @@ -31,6 +32,7 @@ export const remove = async ( Key: finalKey, }, ); + return { key, }; diff --git a/packages/storage/src/providers/s3/apis/list.ts b/packages/storage/src/providers/s3/apis/list.ts index 24c0e751f05..f37b66ad381 100644 --- a/packages/storage/src/providers/s3/apis/list.ts +++ b/packages/storage/src/providers/s3/apis/list.ts @@ -2,15 +2,17 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; + import { ListAllInput, - ListPaginateInput, ListAllOutput, + ListPaginateInput, ListPaginateOutput, } from '../types'; + import { list as listInternal } from './internal/list'; -type ListApi = { +interface ListApi { /** * List files with given prefix in pages * pageSize defaulted to 1000. Additionally, the result will include a nextToken if there are more items to retrieve. @@ -28,7 +30,7 @@ type ListApi = { * @throws validation: {@link StorageValidationErrorCode } - thrown when there are issues with credentials */ (input?: ListAllInput): Promise; -}; +} export const list: ListApi = ( input?: ListAllInput | ListPaginateInput, diff --git a/packages/storage/src/providers/s3/apis/remove.ts b/packages/storage/src/providers/s3/apis/remove.ts index d26fb3058c5..0ed60256586 100644 --- a/packages/storage/src/providers/s3/apis/remove.ts +++ b/packages/storage/src/providers/s3/apis/remove.ts @@ -2,7 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; + import { RemoveInput, RemoveOutput } from '../types'; + import { remove as removeInternal } from './internal/remove'; /** diff --git a/packages/storage/src/providers/s3/apis/server/copy.ts b/packages/storage/src/providers/s3/apis/server/copy.ts index b17e5ab7a52..8a4f64d272d 100644 --- a/packages/storage/src/providers/s3/apis/server/copy.ts +++ b/packages/storage/src/providers/s3/apis/server/copy.ts @@ -5,6 +5,7 @@ import { AmplifyServer, getAmplifyServerContext, } from '@aws-amplify/core/internals/adapter-core'; + import { CopyInput, CopyOutput } from '../../types'; import { copy as copyInternal } from '../internal/copy'; diff --git a/packages/storage/src/providers/s3/apis/server/getProperties.ts b/packages/storage/src/providers/s3/apis/server/getProperties.ts index e54536b4e54..d56ee3d77f4 100644 --- a/packages/storage/src/providers/s3/apis/server/getProperties.ts +++ b/packages/storage/src/providers/s3/apis/server/getProperties.ts @@ -5,6 +5,7 @@ import { AmplifyServer, getAmplifyServerContext, } from '@aws-amplify/core/internals/adapter-core'; + import { GetPropertiesInput, GetPropertiesOutput } from '../../types'; import { getProperties as getPropertiesInternal } from '../internal/getProperties'; diff --git a/packages/storage/src/providers/s3/apis/server/getUrl.ts b/packages/storage/src/providers/s3/apis/server/getUrl.ts index b1913de0bdb..8cdfe2ffb4e 100644 --- a/packages/storage/src/providers/s3/apis/server/getUrl.ts +++ b/packages/storage/src/providers/s3/apis/server/getUrl.ts @@ -5,6 +5,7 @@ import { AmplifyServer, getAmplifyServerContext, } from '@aws-amplify/core/internals/adapter-core'; + import { GetUrlInput, GetUrlOutput } from '../../types'; import { getUrl as getUrlInternal } from '../internal/getUrl'; diff --git a/packages/storage/src/providers/s3/apis/server/list.ts b/packages/storage/src/providers/s3/apis/server/list.ts index 0bf46b11ca0..588275a7318 100644 --- a/packages/storage/src/providers/s3/apis/server/list.ts +++ b/packages/storage/src/providers/s3/apis/server/list.ts @@ -5,15 +5,16 @@ import { AmplifyServer, getAmplifyServerContext, } from '@aws-amplify/core/internals/adapter-core'; + import { ListAllInput, - ListPaginateInput, ListAllOutput, + ListPaginateInput, ListPaginateOutput, } from '../../types'; import { list as listInternal } from '../internal/list'; -type ListApi = { +interface ListApi { /** * Lists bucket objects with pagination. * @param {ListPaginateInput} The input object @@ -37,7 +38,7 @@ type ListApi = { contextSpec: AmplifyServer.ContextSpec, input?: ListAllInput, ): Promise; -}; +} export const list: ListApi = ( contextSpec: AmplifyServer.ContextSpec, diff --git a/packages/storage/src/providers/s3/apis/server/remove.ts b/packages/storage/src/providers/s3/apis/server/remove.ts index f6a1fcca364..8dbd45bfd19 100644 --- a/packages/storage/src/providers/s3/apis/server/remove.ts +++ b/packages/storage/src/providers/s3/apis/server/remove.ts @@ -5,6 +5,7 @@ import { AmplifyServer, getAmplifyServerContext, } from '@aws-amplify/core/internals/adapter-core'; + import { RemoveInput, RemoveOutput } from '../../types'; import { remove as removeInternal } from '../internal/remove'; diff --git a/packages/storage/src/providers/s3/apis/uploadData/byteLength.ts b/packages/storage/src/providers/s3/apis/uploadData/byteLength.ts index 96b97f42430..9b6ea87e42f 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/byteLength.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/byteLength.ts @@ -25,6 +25,7 @@ export const byteLength = (input?: any): number | undefined => { // handles browser File object return input.size; } + // TODO: support Node.js stream size when Node.js runtime is supported out-of-box. return undefined; }; diff --git a/packages/storage/src/providers/s3/apis/uploadData/index.ts b/packages/storage/src/providers/s3/apis/uploadData/index.ts index c2096366ea0..2c1926cb1e0 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/index.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/index.ts @@ -1,11 +1,12 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { UploadDataInput, UploadDataOutput, S3Exception } from '../../types'; +import { S3Exception, UploadDataInput, UploadDataOutput } from '../../types'; import { createUploadTask } from '../../utils'; import { assertValidationError } from '../../../../errors/utils/assertValidationError'; import { StorageValidationErrorCode } from '../../../../errors/types/validation'; import { DEFAULT_PART_SIZE, MAX_OBJECT_SIZE } from '../../utils/constants'; + import { byteLength } from './byteLength'; import { putObjectJob } from './putObjectJob'; import { getMultipartUploadHandlers } from './multipart'; @@ -69,6 +70,7 @@ export const uploadData = (input: UploadDataInput): UploadDataOutput => { if (dataByteLength && dataByteLength <= DEFAULT_PART_SIZE) { const abortController = new AbortController(); + return createUploadTask({ isMultipartUpload: false, job: putObjectJob(input, abortController.signal, dataByteLength), @@ -79,6 +81,7 @@ export const uploadData = (input: UploadDataInput): UploadDataOutput => { } else { const { multipartUploadJob, onPause, onResume, onCancel } = getMultipartUploadHandlers(input, dataByteLength); + return createUploadTask({ isMultipartUpload: true, job: multipartUploadJob, diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/calculatePartSize.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/calculatePartSize.ts index d12379a0075..8089038d6e1 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/calculatePartSize.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/calculatePartSize.ts @@ -13,5 +13,6 @@ export const calculatePartSize = (totalSize?: number): number => { partSize *= 2; partsCount = Math.ceil(totalSize / partSize); } + return partSize; }; diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/getDataChunker.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/getDataChunker.ts index 72fc9cf7e54..aab240be148 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/getDataChunker.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/getDataChunker.ts @@ -7,13 +7,14 @@ import { validationErrorMap, } from '../../../../../errors/types/validation'; import { StorageError } from '../../../../../errors/StorageError'; + import { calculatePartSize } from './calculatePartSize'; -export type PartToUpload = { +export interface PartToUpload { partNumber: number; data: Blob | ArrayBuffer | string; size: number; -}; +} export const getDataChunker = ( data: StorageUploadDataPayload, @@ -29,6 +30,7 @@ export const getDataChunker = ( return helper(data, 0, data.byteLength, partSize); } else if (typeof data === 'string') { const blob = new Blob([data]); + return getDataChunker(blob, blob.size); } else { throw new StorageError({ diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/initialUpload.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/initialUpload.ts index a0f432a87a0..f9b402c2e86 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/initialUpload.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/initialUpload.ts @@ -3,17 +3,18 @@ import { StorageAccessLevel } from '@aws-amplify/core'; +import { ResolvedS3Config } from '../../../types/options'; +import { StorageUploadDataPayload } from '../../../../../types'; +import { Part, createMultipartUpload } from '../../../utils/client'; +import { logger } from '../../../../../utils'; + import { cacheMultipartUpload, findCachedUploadParts, getUploadsCacheKey, } from './uploadCache'; -import { ResolvedS3Config } from '../../../types/options'; -import { StorageUploadDataPayload } from '../../../../../types'; -import { Part, createMultipartUpload } from '../../../utils/client'; -import { logger } from '../../../../../utils'; -type LoadOrCreateMultipartUploadOptions = { +interface LoadOrCreateMultipartUploadOptions { s3Config: ResolvedS3Config; data: StorageUploadDataPayload; bucket: string; @@ -26,12 +27,12 @@ type LoadOrCreateMultipartUploadOptions = { metadata?: Record; size?: number; abortSignal?: AbortSignal; -}; +} -type LoadOrCreateMultipartUploadResult = { +interface LoadOrCreateMultipartUploadResult { uploadId: string; cachedParts: Part[]; -}; +} /** * Load the in-progress multipart upload from local storage or async storage(RN) if it exists, or create a new multipart @@ -107,6 +108,7 @@ export const loadOrCreateMultipartUpload = async ({ ); if (size === undefined) { logger.debug('uploaded data size cannot be determined, skipping cache.'); + return { uploadId: UploadId!, cachedParts: [], @@ -126,6 +128,7 @@ export const loadOrCreateMultipartUpload = async ({ key, fileName: data instanceof File ? data.name : '', }); + return { uploadId: UploadId!, cachedParts: [], diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/progressTracker.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/progressTracker.ts index bf73adbec7b..0347d76dfcd 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/progressTracker.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/progressTracker.ts @@ -3,10 +3,10 @@ import { TransferProgressEvent } from '../../../../../types'; -type ConcurrentUploadsProgressTrackerOptions = { +interface ConcurrentUploadsProgressTrackerOptions { size?: number; - onProgress?: (event: TransferProgressEvent) => void; -}; + onProgress?(event: TransferProgressEvent): void; +} /** * Track the progress from multiple concurrent uploads, and invoke the onProgress callback. @@ -29,6 +29,7 @@ export const getConcurrentUploadsProgressTracker = ({ getOnProgressListener: () => { transferredBytesPerListener.push(0); const listenerIndex = transferredBytesPerListener.length - 1; + return (event: TransferProgressEvent) => { const { transferredBytes } = event; transferredBytesPerListener[listenerIndex] = transferredBytes; diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadCache.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadCache.ts index 6f6eb050e6e..1d8148223b1 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadCache.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadCache.ts @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { - defaultStorage, KeyValueStorageInterface, StorageAccessLevel, + defaultStorage, } from '@aws-amplify/core'; import { UPLOADS_STORAGE_KEY } from '../../../utils/constants'; @@ -14,12 +14,12 @@ import { logger } from '../../../../../utils'; const ONE_HOUR = 1000 * 60 * 60; -type FindCachedUploadPartsOptions = { +interface FindCachedUploadPartsOptions { cacheKey: string; s3Config: ResolvedS3Config; bucket: string; finalKey: string; -}; +} /** * Find the cached multipart upload id and get the parts that have been uploaded @@ -56,6 +56,7 @@ export const findCachedUploadParts = async ({ Key: finalKey, UploadId: cachedUpload.uploadId, }); + return { parts: Parts, uploadId: cachedUpload.uploadId, @@ -63,18 +64,19 @@ export const findCachedUploadParts = async ({ } catch (e) { logger.debug('failed to list cached parts, removing cached upload.'); await removeCachedUpload(cacheKey); + return null; } }; -type FileMetadata = { +interface FileMetadata { bucket: string; fileName: string; key: string; uploadId: string; // Unix timestamp in ms lastTouched: number; -}; +} const listCachedUploadTasks = async ( kvStorage: KeyValueStorageInterface, @@ -83,18 +85,19 @@ const listCachedUploadTasks = async ( return JSON.parse((await kvStorage.getItem(UPLOADS_STORAGE_KEY)) ?? '{}'); } catch (e) { logger.debug('failed to parse cached uploads record.'); + return {}; } }; -type UploadsCacheKeyOptions = { +interface UploadsCacheKeyOptions { size: number; contentType?: string; bucket: string; accessLevel: StorageAccessLevel; key: string; file?: File; -}; +} /** * Get the cache key of a multipart upload. Data source cached by different: size, content type, bucket, access level, diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts index 3d53ceadae1..0df1505a6eb 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts @@ -4,7 +4,6 @@ import { Amplify, StorageAccessLevel } from '@aws-amplify/core'; import { StorageAction } from '@aws-amplify/core/internals/utils'; -import { getDataChunker } from './getDataChunker'; import { UploadDataInput } from '../../../types'; import { resolveS3ConfigAndInput } from '../../../utils'; import { Item as S3Item } from '../../../types/outputs'; @@ -12,11 +11,7 @@ import { DEFAULT_ACCESS_LEVEL, DEFAULT_QUEUE_SIZE, } from '../../../utils/constants'; -import { loadOrCreateMultipartUpload } from './initialUpload'; import { ResolvedS3Config } from '../../../types/options'; -import { getConcurrentUploadsProgressTracker } from './progressTracker'; -import { getUploadsCacheKey, removeCachedUpload } from './uploadCache'; -import { uploadPartExecutor } from './uploadPartExecutor'; import { StorageError } from '../../../../../errors/StorageError'; import { CanceledError } from '../../../../../errors/CanceledError'; import { @@ -28,6 +23,12 @@ import { import { getStorageUserAgentValue } from '../../../utils/userAgent'; import { logger } from '../../../../../utils'; +import { uploadPartExecutor } from './uploadPartExecutor'; +import { getUploadsCacheKey, removeCachedUpload } from './uploadCache'; +import { getConcurrentUploadsProgressTracker } from './progressTracker'; +import { loadOrCreateMultipartUpload } from './initialUpload'; +import { getDataChunker } from './getDataChunker'; + /** * Create closure hiding the multipart upload implementation details and expose the upload job and control functions( * onPause, onResume, onCancel). @@ -54,7 +55,7 @@ export const getMultipartUploadHandlers = ( // Special flag that differentiates HTTP requests abort error caused by pause() from ones caused by cancel(). // The former one should NOT cause the upload job to throw, but cancels any pending HTTP requests. // This should be replaced by a special abort reason. However,the support of this API is lagged behind. - let isAbortSignalFromPause: boolean = false; + let isAbortSignalFromPause = false; const startUpload = async (): Promise => { const resolvedS3Options = await resolveS3ConfigAndInput( @@ -241,6 +242,7 @@ export const getMultipartUploadHandlers = ( new CanceledError(message ? { message } : undefined), ); }; + return { multipartUploadJob, onPause, diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadPartExecutor.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadPartExecutor.ts index 71801fe1a23..c93d791aad3 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadPartExecutor.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadPartExecutor.ts @@ -1,14 +1,15 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { PartToUpload } from './getDataChunker'; import { TransferProgressEvent } from '../../../../../types'; import { ResolvedS3Config } from '../../../types/options'; import { calculateContentMd5 } from '../../../utils'; import { uploadPart } from '../../../utils/client'; import { logger } from '../../../../../utils'; -type UploadPartExecutorOptions = { +import { PartToUpload } from './getDataChunker'; + +interface UploadPartExecutorOptions { dataChunkerGenerator: Generator; completedPartNumberSet: Set; s3Config: ResolvedS3Config; @@ -17,9 +18,9 @@ type UploadPartExecutorOptions = { finalKey: string; uploadId: string; isObjectLockEnabled?: boolean; - onPartUploadCompletion: (partNumber: number, eTag: string) => void; - onProgress?: (event: TransferProgressEvent) => void; -}; + onPartUploadCompletion(partNumber: number, eTag: string): void; + onProgress?(event: TransferProgressEvent): void; +} export const uploadPartExecutor = async ({ dataChunkerGenerator, diff --git a/packages/storage/src/providers/s3/types/inputs.ts b/packages/storage/src/providers/s3/types/inputs.ts index 51c25ab4b3f..9a360d0bfe3 100644 --- a/packages/storage/src/providers/s3/types/inputs.ts +++ b/packages/storage/src/providers/s3/types/inputs.ts @@ -3,23 +3,23 @@ import { StorageCopyInput, + StorageDownloadDataInput, StorageGetPropertiesInput, StorageGetUrlInput, StorageListInput, StorageRemoveInput, - StorageDownloadDataInput, StorageUploadDataInput, } from '../../../types'; import { + CopyDestinationOptions, + CopySourceOptions, + DownloadDataOptions, GetPropertiesOptions, GetUrlOptions, ListAllOptions, ListPaginateOptions, RemoveOptions, - DownloadDataOptions, UploadDataOptions, - CopyDestinationOptions, - CopySourceOptions, } from '../types'; // TODO: support use accelerate endpoint option diff --git a/packages/storage/src/providers/s3/types/options.ts b/packages/storage/src/providers/s3/types/options.ts index dace141e6b9..dad92d72f1b 100644 --- a/packages/storage/src/providers/s3/types/options.ts +++ b/packages/storage/src/providers/s3/types/options.ts @@ -10,38 +10,38 @@ import { StorageListPaginateOptions, } from '../../../types/options'; -type CommonOptions = { +interface CommonOptions { /** * Whether to use accelerate endpoint. * @default false */ useAccelerateEndpoint?: boolean; -}; +} type ReadOptions = | { accessLevel?: 'guest' | 'private' } | { accessLevel: 'protected'; targetIdentityId?: string }; -type WriteOptions = { +interface WriteOptions { accessLevel?: StorageAccessLevel; -}; +} -type BytesRangeOptions = { +interface BytesRangeOptions { bytesRange?: { start: number; end: number; }; -}; +} /** * Transfer-related options type for S3 downloadData, uploadData APIs. */ -type TransferOptions = { +interface TransferOptions { /** * Callback function tracking the upload/download progress. */ - onProgress?: (event: TransferProgressEvent) => void; -}; + onProgress?(event: TransferProgressEvent): void; +} /** * Input options type for S3 getProperties API. @@ -130,10 +130,10 @@ export type CopyDestinationOptions = WriteOptions & { * * @internal */ -export type ResolvedS3Config = { +export interface ResolvedS3Config { region: string; credentials: AWSCredentials; customEndpoint?: string; forcePathStyle?: boolean; useAccelerateEndpoint?: boolean; -}; +} diff --git a/packages/storage/src/providers/s3/types/outputs.ts b/packages/storage/src/providers/s3/types/outputs.ts index 532a4a455f1..bbcb9fc75b1 100644 --- a/packages/storage/src/providers/s3/types/outputs.ts +++ b/packages/storage/src/providers/s3/types/outputs.ts @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { + DownloadTask, StorageDownloadDataOutput, StorageGetUrlOutput, StorageItem, StorageListOutput, - DownloadTask, UploadTask, } from '../../../types'; diff --git a/packages/storage/src/providers/s3/utils/client/abortMultipartUpload.ts b/packages/storage/src/providers/s3/utils/client/abortMultipartUpload.ts index 72463961c96..bddaf570d0e 100644 --- a/packages/storage/src/providers/s3/utils/client/abortMultipartUpload.ts +++ b/packages/storage/src/providers/s3/utils/client/abortMultipartUpload.ts @@ -13,8 +13,8 @@ import { AmplifyUrlSearchParams, } from '@aws-amplify/core/internals/utils'; import { MetadataBearer } from '@aws-sdk/types'; -import type { AbortMultipartUploadCommandInput } from './types'; +import type { AbortMultipartUploadCommandInput } from './types'; import { defaultConfig } from './base'; import { buildStorageServiceError, @@ -42,6 +42,7 @@ const abortMultipartUploadSerializer = ( url.search = new AmplifyUrlSearchParams({ uploadId: input.UploadId, }).toString(); + return { method: 'DELETE', headers: {}, diff --git a/packages/storage/src/providers/s3/utils/client/base.ts b/packages/storage/src/providers/s3/utils/client/base.ts index f5697134f08..33eae5a8d05 100644 --- a/packages/storage/src/providers/s3/utils/client/base.ts +++ b/packages/storage/src/providers/s3/utils/client/base.ts @@ -2,15 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 import { - getAmplifyUserAgent, AmplifyUrl, + getAmplifyUserAgent, } from '@aws-amplify/core/internals/utils'; import { + EndpointResolverOptions, getDnsSuffix, - jitteredBackoff, getRetryDecider, - EndpointResolverOptions, + jitteredBackoff, } from '@aws-amplify/core/internals/aws-client-utils'; + import { parseXmlError } from './utils'; const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/; @@ -81,6 +82,7 @@ const endpointResolver = ( endpoint.host = `${apiInput.Bucket}.${endpoint.host}`; } } + return { url: endpoint }; }; diff --git a/packages/storage/src/providers/s3/utils/client/completeMultipartUpload.ts b/packages/storage/src/providers/s3/utils/client/completeMultipartUpload.ts index cc5ad37ebe0..36dd9f59a52 100644 --- a/packages/storage/src/providers/s3/utils/client/completeMultipartUpload.ts +++ b/packages/storage/src/providers/s3/utils/client/completeMultipartUpload.ts @@ -12,6 +12,7 @@ import { AmplifyUrlSearchParams, } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import type { CompleteMultipartUploadCommandInput, CompleteMultipartUploadCommandOutput, @@ -57,6 +58,7 @@ const completeMultipartUploadSerializer = async ( uploadId: input.UploadId, }).toString(); validateS3RequiredParameter(!!input.MultipartUpload, 'MultipartUpload'); + return { method: 'POST', headers, @@ -73,6 +75,7 @@ const serializeCompletedMultipartUpload = ( if (!input.Parts?.length) { throw new Error(`${INVALID_PARAMETER_ERROR_MSG}: ${input}`); } + return `${input.Parts.map( serializeCompletedPartList, ).join('')}`; @@ -82,6 +85,7 @@ const serializeCompletedPartList = (input: CompletedPart): string => { if (!input.ETag || input.PartNumber == null) { throw new Error(`${INVALID_PARAMETER_ERROR_MSG}: ${input}`); } + return `${input.ETag}${input.PartNumber}`; }; @@ -100,6 +104,7 @@ const parseXmlBodyOrThrow = async (response: HttpResponse): Promise => { })) as Error; throw buildStorageServiceError(error, response.statusCode); } + return parsed; }; @@ -116,6 +121,7 @@ const completeMultipartUploadDeserializer = async ( Key: 'Key', Location: 'Location', }); + return { $metadata: parseMetadata(response), ...contents, @@ -141,10 +147,12 @@ const retryWhenErrorWith200StatusCode = async ( if (parsed.Code !== undefined && parsed.Message !== undefined) { return true; } + return false; } const defaultRetryDecider = defaultConfig.retryDecider; + return defaultRetryDecider(response, error); }; diff --git a/packages/storage/src/providers/s3/utils/client/copyObject.ts b/packages/storage/src/providers/s3/utils/client/copyObject.ts index 1259fc3f8cf..a08301d9f7e 100644 --- a/packages/storage/src/providers/s3/utils/client/copyObject.ts +++ b/packages/storage/src/providers/s3/utils/client/copyObject.ts @@ -9,14 +9,15 @@ import { } from '@aws-amplify/core/internals/aws-client-utils'; import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import type { CopyObjectCommandInput, CopyObjectCommandOutput } from './types'; import { defaultConfig } from './base'; import { + assignStringVariables, buildStorageServiceError, parseXmlBody, parseXmlError, s3TransferHandler, - assignStringVariables, serializeObjectConfigsToHeaders, serializePathnameObjectKey, validateS3RequiredParameter, @@ -54,6 +55,7 @@ const copyObjectSerializer = async ( const url = new AmplifyUrl(endpoint.url.toString()); validateS3RequiredParameter(!!input.Key, 'Key'); url.pathname = serializePathnameObjectKey(url, input.Key); + return { method: 'PUT', headers, @@ -69,6 +71,7 @@ const copyObjectDeserializer = async ( throw buildStorageServiceError(error, response.statusCode); } else { await parseXmlBody(response); + return { $metadata: parseMetadata(response), }; diff --git a/packages/storage/src/providers/s3/utils/client/createMultipartUpload.ts b/packages/storage/src/providers/s3/utils/client/createMultipartUpload.ts index 0010721f464..5a2b79a9635 100644 --- a/packages/storage/src/providers/s3/utils/client/createMultipartUpload.ts +++ b/packages/storage/src/providers/s3/utils/client/createMultipartUpload.ts @@ -9,22 +9,22 @@ import { } from '@aws-amplify/core/internals/aws-client-utils'; import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import type { CreateMultipartUploadCommandInput, CreateMultipartUploadCommandOutput, } from './types'; import type { PutObjectInput } from './putObject'; - import { defaultConfig } from './base'; import { buildStorageServiceError, - validateS3RequiredParameter, map, parseXmlBody, parseXmlError, s3TransferHandler, serializeObjectConfigsToHeaders, serializePathnameObjectKey, + validateS3RequiredParameter, } from './utils'; export type CreateMultipartUploadInput = Extract< @@ -46,6 +46,7 @@ const createMultipartUploadSerializer = async ( validateS3RequiredParameter(!!input.Key, 'Key'); url.pathname = serializePathnameObjectKey(url, input.Key); url.search = 'uploads'; + return { method: 'POST', headers, @@ -64,6 +65,7 @@ const createMultipartUploadDeserializer = async ( const contents = map(parsed, { UploadId: 'UploadId', }); + return { $metadata: parseMetadata(response), ...contents, diff --git a/packages/storage/src/providers/s3/utils/client/deleteObject.ts b/packages/storage/src/providers/s3/utils/client/deleteObject.ts index 28cfc2ee797..290a3e5ebf0 100644 --- a/packages/storage/src/providers/s3/utils/client/deleteObject.ts +++ b/packages/storage/src/providers/s3/utils/client/deleteObject.ts @@ -9,11 +9,11 @@ import { } from '@aws-amplify/core/internals/aws-client-utils'; import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import type { DeleteObjectCommandInput, DeleteObjectCommandOutput, } from './types'; - import { defaultConfig } from './base'; import { buildStorageServiceError, @@ -24,7 +24,6 @@ import { serializePathnameObjectKey, validateS3RequiredParameter, } from './utils'; -import { StorageError } from '../../../../errors/StorageError'; export type DeleteObjectInput = Pick< DeleteObjectCommandInput, @@ -40,6 +39,7 @@ const deleteObjectSerializer = ( const url = new AmplifyUrl(endpoint.url.toString()); validateS3RequiredParameter(!!input.Key, 'Key'); url.pathname = serializePathnameObjectKey(url, input.Key); + return { method: 'DELETE', headers: {}, @@ -60,6 +60,7 @@ const deleteObjectDeserializer = async ( VersionId: 'x-amz-version-id', RequestCharged: 'x-amz-request-charged', }); + return { ...content, $metadata: parseMetadata(response), diff --git a/packages/storage/src/providers/s3/utils/client/getObject.ts b/packages/storage/src/providers/s3/utils/client/getObject.ts index a85c75bd248..4af6a32a39c 100644 --- a/packages/storage/src/providers/s3/utils/client/getObject.ts +++ b/packages/storage/src/providers/s3/utils/client/getObject.ts @@ -2,14 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import { + EMPTY_SHA256_HASH, Endpoint, HttpRequest, + HttpResponse, + PresignUrlOptions, + UserAgentOptions, parseMetadata, presignUrl, - UserAgentOptions, - PresignUrlOptions, - EMPTY_SHA256_HASH, - HttpResponse, } from '@aws-amplify/core/internals/aws-client-utils'; import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; @@ -21,6 +21,7 @@ import type { GetObjectCommandOutput, } from './types'; import { + CONTENT_SHA256_HEADER, buildStorageServiceError, deserializeBoolean, deserializeMetadata, @@ -30,7 +31,6 @@ import { parseXmlError, s3TransferHandler, serializePathnameObjectKey, - CONTENT_SHA256_HEADER, validateS3RequiredParameter, } from './utils'; @@ -50,6 +50,7 @@ const getObjectSerializer = async ( const url = new AmplifyUrl(endpoint.url.toString()); validateS3RequiredParameter(!!input.Key, 'Key'); url.pathname = serializePathnameObjectKey(url, input.Key); + return { method: 'GET', headers: { @@ -161,6 +162,7 @@ export const getPresignedGetObjectUrl = async ( )) { url.searchParams.append(headerName, value); } + return presignUrl( { method, url, body: undefined }, { diff --git a/packages/storage/src/providers/s3/utils/client/headObject.ts b/packages/storage/src/providers/s3/utils/client/headObject.ts index 65feae805bc..109263def26 100644 --- a/packages/storage/src/providers/s3/utils/client/headObject.ts +++ b/packages/storage/src/providers/s3/utils/client/headObject.ts @@ -9,9 +9,9 @@ import { } from '@aws-amplify/core/internals/aws-client-utils'; import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import { defaultConfig } from './base'; import type { HeadObjectCommandInput, HeadObjectCommandOutput } from './types'; - import { buildStorageServiceError, deserializeMetadata, @@ -23,7 +23,6 @@ import { serializePathnameObjectKey, validateS3RequiredParameter, } from './utils'; -import { StorageError } from '../../../../errors/StorageError'; export type HeadObjectInput = Pick; @@ -45,6 +44,7 @@ const headObjectSerializer = async ( const url = new AmplifyUrl(endpoint.url.toString()); validateS3RequiredParameter(!!input.Key, 'Key'); url.pathname = serializePathnameObjectKey(url, input.Key); + return { method: 'HEAD', headers: {}, @@ -70,6 +70,7 @@ const headObjectDeserializer = async ( }), Metadata: deserializeMetadata(response.headers), }; + return { $metadata: parseMetadata(response), ...contents, diff --git a/packages/storage/src/providers/s3/utils/client/listObjectsV2.ts b/packages/storage/src/providers/s3/utils/client/listObjectsV2.ts index 931977a5007..232499931c5 100644 --- a/packages/storage/src/providers/s3/utils/client/listObjectsV2.ts +++ b/packages/storage/src/providers/s3/utils/client/listObjectsV2.ts @@ -12,6 +12,7 @@ import { AmplifyUrlSearchParams, } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import type { ListObjectsV2CommandInput, ListObjectsV2CommandOutput, @@ -54,6 +55,7 @@ const listObjectsV2Serializer = ( }); const url = new AmplifyUrl(endpoint.url.toString()); url.search = new AmplifyUrlSearchParams(query).toString(); + return { method: 'GET', headers, @@ -90,6 +92,7 @@ const listObjectsV2Deserializer = async ( Prefix: 'Prefix', StartAfter: 'StartAfter', }); + return { $metadata: parseMetadata(response), ...contents, diff --git a/packages/storage/src/providers/s3/utils/client/listParts.ts b/packages/storage/src/providers/s3/utils/client/listParts.ts index ba12b4a97ff..86899ad4e9d 100644 --- a/packages/storage/src/providers/s3/utils/client/listParts.ts +++ b/packages/storage/src/providers/s3/utils/client/listParts.ts @@ -12,20 +12,21 @@ import { AmplifyUrlSearchParams, } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import type { + CompletedPart, ListPartsCommandInput, ListPartsCommandOutput, - CompletedPart, } from './types'; import { defaultConfig } from './base'; import { buildStorageServiceError, + deserializeNumber, emptyArrayGuard, map, parseXmlBody, parseXmlError, s3TransferHandler, - deserializeNumber, serializePathnameObjectKey, validateS3RequiredParameter, } from './utils'; @@ -52,6 +53,7 @@ const listPartsSerializer = async ( url.search = new AmplifyUrlSearchParams({ uploadId: input.UploadId, }).toString(); + return { method: 'GET', headers, @@ -74,6 +76,7 @@ const listPartsDeserializer = async ( value => emptyArrayGuard(value, deserializeCompletedPartList), ], }); + return { $metadata: parseMetadata(response), ...contents, diff --git a/packages/storage/src/providers/s3/utils/client/putObject.ts b/packages/storage/src/providers/s3/utils/client/putObject.ts index ac8509270a6..86755f1c703 100644 --- a/packages/storage/src/providers/s3/utils/client/putObject.ts +++ b/packages/storage/src/providers/s3/utils/client/putObject.ts @@ -13,14 +13,14 @@ import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/ import { defaultConfig } from './base'; import type { PutObjectCommandInput, PutObjectCommandOutput } from './types'; import { - buildStorageServiceError, - validateS3RequiredParameter, assignStringVariables, + buildStorageServiceError, map, parseXmlError, s3TransferHandler, serializeObjectConfigsToHeaders, serializePathnameObjectKey, + validateS3RequiredParameter, } from './utils'; export type PutObjectInput = Pick< @@ -60,6 +60,7 @@ const putObjectSerializer = async ( const url = new AmplifyUrl(endpoint.url.toString()); validateS3RequiredParameter(!!input.Key, 'Key'); url.pathname = serializePathnameObjectKey(url, input.Key); + return { method: 'PUT', headers, diff --git a/packages/storage/src/providers/s3/utils/client/runtime/base64/index.browser.ts b/packages/storage/src/providers/s3/utils/client/runtime/base64/index.browser.ts index 325b19a66f3..8ef5f37c850 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/base64/index.browser.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/base64/index.browser.ts @@ -3,6 +3,7 @@ function bytesToBase64(bytes: Uint8Array): string { const base64Str = Array.from(bytes, x => String.fromCodePoint(x)).join(''); + return btoa(base64Str); } diff --git a/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts b/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts index 93d82446080..a18083dca37 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts @@ -3,10 +3,11 @@ import { HttpRequest, - getHashedPayload, - MiddlewareHandler, HttpResponse, + MiddlewareHandler, + getHashedPayload, } from '@aws-amplify/core/internals/aws-client-utils'; + import { CONTENT_SHA256_HEADER } from './constants'; /** @@ -24,6 +25,7 @@ export const contentSha256Middleware = } else { const hash = await getHashedPayload(request.body); request.headers[CONTENT_SHA256_HEADER] = hash; + return next(request); } }; diff --git a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts index a805e6fbce1..cb024322589 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts @@ -6,10 +6,12 @@ import { HttpResponse, authenticatedHandler, } from '@aws-amplify/core/internals/aws-client-utils'; -import type { s3TransferHandler as s3BrowserTransferhandler } from './xhr'; import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; + import { contentSha256Middleware } from '../contentSha256middleware'; +import type { s3TransferHandler as s3BrowserTransferhandler } from './xhr'; + /** * S3 transfer handler for node based on Node-fetch. On top of basic transfer handler, it also supports * x-amz-content-sha256 header. However, it does not support request&response process tracking like browser. diff --git a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts index 8964ecc6c5c..b661988e2f0 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts @@ -2,14 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import { - retryMiddlewareFactory, + HttpRequest, + HttpResponse, RetryOptions, - signingMiddlewareFactory, SigningOptions, - userAgentMiddlewareFactory, UserAgentOptions, - HttpRequest, - HttpResponse, + retryMiddlewareFactory, + signingMiddlewareFactory, + userAgentMiddlewareFactory, } from '@aws-amplify/core/internals/aws-client-utils'; import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; diff --git a/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts b/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts index c323342fb1d..e0fc4ca5481 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts @@ -4,11 +4,15 @@ import { HttpRequest, HttpResponse, - TransferHandler, ResponseBodyMixin, + TransferHandler, withMemoization, } from '@aws-amplify/core/internals/aws-client-utils'; import { ConsoleLogger } from '@aws-amplify/core'; + +import { TransferProgressEvent } from '../../../../../types/common'; +import { CanceledError } from '../../../../../errors/CanceledError'; + import { ABORT_ERROR_CODE, ABORT_ERROR_MESSAGE, @@ -17,8 +21,6 @@ import { NETWORK_ERROR_CODE, NETWORK_ERROR_MESSAGE, } from './constants'; -import { TransferProgressEvent } from '../../../../../types/common'; -import { CanceledError } from '../../../../../errors/CanceledError'; const logger = new ConsoleLogger('xhr-http-handler'); @@ -30,8 +32,8 @@ export interface XhrTransferHandlerOptions { // download binary data. Otherwise, use `text` to return the response as a string. responseType: 'text' | 'blob'; abortSignal?: AbortSignal; - onDownloadProgress?: (event: TransferProgressEvent) => void; - onUploadProgress?: (event: TransferProgressEvent) => void; + onDownloadProgress?(event: TransferProgressEvent): void; + onUploadProgress?(event: TransferProgressEvent): void; } /** @@ -113,7 +115,7 @@ export const xhrTransferHandler: TransferHandler< const responseHeaders = convertResponseHeaders( xhr.getAllResponseHeaders(), ); - const responseType = xhr.responseType; + const { responseType } = xhr; const responseBlob = xhr.response as Blob; const responseText = responseType === 'text' ? xhr.responseText : ''; const bodyMixIn: ResponseBodyMixin = { @@ -193,6 +195,7 @@ const convertToTransferProgressEvent = ( const buildHandlerError = (message: string, name: string): Error => { const error = new Error(message); error.name = name; + return error; }; @@ -205,6 +208,7 @@ const convertResponseHeaders = (xhrHeaders: string): Record => { if (!xhrHeaders) { return {}; } + return xhrHeaders .split('\r\n') .reduce((headerMap: Record, line: string) => { @@ -212,12 +216,14 @@ const convertResponseHeaders = (xhrHeaders: string): Record => { const header = parts.shift()!; const value = parts.join(': '); headerMap[header.toLowerCase()] = value; + return headerMap; }, {}); }; const readBlobAsText = (blob: Blob) => { const reader = new FileReader(); + return new Promise((resolve, reject) => { reader.onloadend = () => { if (reader.readyState !== FileReader.DONE) { diff --git a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts index 89bf9da7304..34e9c3c1933 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts @@ -12,6 +12,7 @@ export const parser = { const xml = domParser.parseFromString(xmlStr, 'text/xml'); const parsedObj = parseXmlNode(xml); const rootKey = Object.keys(parsedObj)[0]; + return parsedObj[rootKey]; }, }; @@ -85,6 +86,7 @@ const hasOnlyNamespaceAttributes = (node: Element): boolean => { return false; } } + return true; }; diff --git a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts index 61f5ce74b2e..e55b99e71bb 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts @@ -33,6 +33,7 @@ export const parser = { parsedObjToReturn[key] = parsedObjToReturn[textNodeName]; delete parsedObjToReturn[textNodeName]; } + return getValueFromTextNode(parsedObjToReturn); }, }; @@ -51,5 +52,6 @@ const getValueFromTextNode = (obj: any) => { obj[key] = getValueFromTextNode(obj[key]); } } + return obj; }; diff --git a/packages/storage/src/providers/s3/utils/client/types.ts b/packages/storage/src/providers/s3/utils/client/types.ts index bada269fb21..d4ccf20c1cd 100644 --- a/packages/storage/src/providers/s3/utils/client/types.ts +++ b/packages/storage/src/providers/s3/utils/client/types.ts @@ -112,8 +112,7 @@ declare const TaggingDirective: { * * The input for {@link AbortMultipartUploadCommand}. */ -export interface AbortMultipartUploadCommandInput - extends AbortMultipartUploadRequest {} +export type AbortMultipartUploadCommandInput = AbortMultipartUploadRequest; /** * @public * @@ -183,8 +182,8 @@ export interface CommonPrefix { * * The input for {@link CompleteMultipartUploadCommand}. */ -export interface CompleteMultipartUploadCommandInput - extends CompleteMultipartUploadRequest {} +export type CompleteMultipartUploadCommandInput = + CompleteMultipartUploadRequest; /** * @public * @@ -429,7 +428,7 @@ export interface CompletedPart { * * The input for {@link CopyObjectCommand}. */ -export interface CopyObjectCommandInput extends CopyObjectRequest {} +export type CopyObjectCommandInput = CopyObjectRequest; /** * @public * @@ -787,8 +786,7 @@ export interface CopyObjectResult { * * The input for {@link CreateMultipartUploadCommand}. */ -export interface CreateMultipartUploadCommandInput - extends CreateMultipartUploadRequest {} +export type CreateMultipartUploadCommandInput = CreateMultipartUploadRequest; /** * @public * @@ -1045,7 +1043,7 @@ export interface CreateMultipartUploadRequest { * * The input for {@link DeleteObjectCommand}. */ -export interface DeleteObjectCommandInput extends DeleteObjectRequest {} +export type DeleteObjectCommandInput = DeleteObjectRequest; /** * @public * @@ -1124,7 +1122,7 @@ export interface DeleteObjectRequest { * * The input for {@link GetObjectCommand}. */ -export interface GetObjectCommandInput extends GetObjectRequest {} +export type GetObjectCommandInput = GetObjectRequest; /** * @public * @@ -1441,7 +1439,7 @@ export interface GetObjectRequest { * * The input for {@link HeadObjectCommand}. */ -export interface HeadObjectCommandInput extends HeadObjectRequest {} +export type HeadObjectCommandInput = HeadObjectRequest; /** * @public * @@ -1790,7 +1788,7 @@ export interface Initiator { * * The input for {@link ListObjectsV2Command}. */ -export interface ListObjectsV2CommandInput extends ListObjectsV2Request {} +export type ListObjectsV2CommandInput = ListObjectsV2Request; /** * @public * @@ -1948,7 +1946,7 @@ export interface ListObjectsV2Request { * * The input for {@link ListPartsCommand}. */ -export interface ListPartsCommandInput extends ListPartsRequest {} +export type ListPartsCommandInput = ListPartsRequest; /** * @public * @@ -2202,7 +2200,7 @@ export interface Part { /** * This interface extends from `PutObjectRequest` interface. There are more parameters than `Body` defined in {@link PutObjectRequest} */ -export interface PutObjectCommandInput extends PutObjectCommandInputType {} +export type PutObjectCommandInput = PutObjectCommandInputType; /** * @public * @@ -2540,7 +2538,7 @@ export interface PutObjectRequest { /** * This interface extends from `UploadPartRequest` interface. There are more parameters than `Body` defined in {@link UploadPartRequest} */ -export interface UploadPartCommandInput extends UploadPartCommandInputType {} +export type UploadPartCommandInput = UploadPartCommandInputType; /** * @public * diff --git a/packages/storage/src/providers/s3/utils/client/uploadPart.ts b/packages/storage/src/providers/s3/utils/client/uploadPart.ts index a5b9c22bb42..3bcacc6236f 100644 --- a/packages/storage/src/providers/s3/utils/client/uploadPart.ts +++ b/packages/storage/src/providers/s3/utils/client/uploadPart.ts @@ -16,13 +16,13 @@ import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/ import { defaultConfig } from './base'; import type { UploadPartCommandInput, UploadPartCommandOutput } from './types'; import { - buildStorageServiceError, - validateS3RequiredParameter, assignStringVariables, + buildStorageServiceError, map, parseXmlError, s3TransferHandler, serializePathnameObjectKey, + validateS3RequiredParameter, } from './utils'; // Content-length is ignored here because it's forbidden header @@ -54,6 +54,7 @@ const uploadPartSerializer = async ( partNumber: input.PartNumber + '', uploadId: input.UploadId, }).toString(); + return { method: 'PUT', headers, diff --git a/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts b/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts index 78d88a714b9..c7a48a2f564 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts @@ -48,7 +48,7 @@ type InferInstructionResultType> = * * @internal */ -export const map = }>( +export const map = >>( obj: Record, instructions: Instructions, ): { @@ -65,6 +65,7 @@ export const map = }>( : String(obj[accessor]); } } + return result; }; @@ -108,7 +109,7 @@ export const deserializeTimestamp = (value: string): Date | undefined => { * * @internal */ -export const emptyArrayGuard = >( +export const emptyArrayGuard = ( value: any, deserializer: (value: any[]) => T, ): T => { @@ -118,6 +119,7 @@ export const emptyArrayGuard = >( const valueArray = (Array.isArray(value) ? value : [value]).filter( e => e != null, ); + return deserializer(valueArray); }; @@ -132,8 +134,10 @@ export const deserializeMetadata = ( .filter(header => header.startsWith(objectMetadataHeaderPrefix)) .reduce((acc, header) => { acc[header.replace(objectMetadataHeaderPrefix, '')] = headers[header]; + return acc; }, {} as any); + return Object.keys(deserialized).length > 0 ? deserialized : undefined; }; @@ -154,5 +158,6 @@ export const buildStorageServiceError = ( storageError.recoverySuggestion = 'Please add the object with this key to the bucket as the key is not found.'; } + return storageError; }; diff --git a/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts b/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts index a905a864c86..242fa99aff4 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts @@ -15,13 +15,14 @@ export const parseXmlError: ErrorParser = async (response?: HttpResponse) => { } const { statusCode } = response; const body = await parseXmlBody(response); - const code = body?.['Code'] + const code = body?.Code ? (body.Code as string) : statusCode === 404 ? 'NotFound' : statusCode.toString(); - const message = body?.['message'] ?? body?.['Message'] ?? code; + const message = body?.message ?? body?.Message ?? code; const error = new Error(message); + return Object.assign(error, { name: code, $metadata: parseMetadata(response), @@ -41,5 +42,6 @@ export const parseXmlBody = async (response: HttpResponse): Promise => { throw new Error('Failed to parse XML response.'); } } + return {}; }; diff --git a/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts b/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts index b563f6070cf..c441376c8b3 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import { extendedEncodeURIComponent } from '@aws-amplify/core/internals/aws-client-utils'; import { AmplifyErrorCode } from '@aws-amplify/core/internals/utils'; + import { StorageError } from '../../../../../errors/StorageError'; /** * @internal */ export const assignStringVariables = ( - values: Record string } | undefined>, + values: Record, ): Record => { const queryParams: Record = {}; for (const [key, value] of Object.entries(values)) { @@ -16,6 +17,7 @@ export const assignStringVariables = ( queryParams[key] = value.toString(); } } + return queryParams; }; @@ -59,6 +61,7 @@ const serializeMetadata = ( ): Record => Object.keys(metadata).reduce((acc: any, suffix: string) => { acc[`x-amz-meta-${suffix.toLowerCase()}`] = metadata[suffix]; + return acc; }, {}); diff --git a/packages/storage/src/providers/s3/utils/md5.native.ts b/packages/storage/src/providers/s3/utils/md5.native.ts index 65479c67c84..6b86cde8d7b 100644 --- a/packages/storage/src/providers/s3/utils/md5.native.ts +++ b/packages/storage/src/providers/s3/utils/md5.native.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Md5 } from '@smithy/md5-js'; + import { toBase64 } from './client/utils'; export const calculateContentMd5 = async ( @@ -19,6 +20,7 @@ export const calculateContentMd5 = async ( hasher.update(buffer); } const digest = await hasher.digest(); + return toBase64(digest); }; @@ -29,8 +31,12 @@ const readFile = (file: Blob): Promise => { if (reader.result) { resolve(reader.result as ArrayBuffer); } - reader.onabort = () => reject(new Error('Read aborted')); - reader.onerror = () => reject(reader.error); + reader.onabort = () => { + reject(new Error('Read aborted')); + }; + reader.onerror = () => { + reject(reader.error); + }; }; if (file !== undefined) reader.readAsArrayBuffer(file); }); diff --git a/packages/storage/src/providers/s3/utils/md5.ts b/packages/storage/src/providers/s3/utils/md5.ts index cce01e71723..7dfa835264f 100644 --- a/packages/storage/src/providers/s3/utils/md5.ts +++ b/packages/storage/src/providers/s3/utils/md5.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Md5 } from '@smithy/md5-js'; + import { toBase64, utf8Encode } from './client/utils'; export const calculateContentMd5 = async ( @@ -19,6 +20,7 @@ export const calculateContentMd5 = async ( hasher.update(utf8Encode(buffer)); } const digest = await hasher.digest(); + return toBase64(digest); }; @@ -30,12 +32,18 @@ const readFileToBase64 = (blob: Blob): Promise => { // response from readAsDataURL is always prepended with "data:*/*;base64," // reference: https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readyState if (reader.readyState !== 2) { - return reject(new Error('Reader aborted too early')); + reject(new Error('Reader aborted too early')); + + return; } resolve((reader.result as string).split(',')[1]); }; - reader.onabort = () => reject(new Error('Read aborted')); - reader.onerror = () => reject(reader.error); + reader.onabort = () => { + reject(new Error('Read aborted')); + }; + reader.onerror = () => { + reject(reader.error); + }; // reader.readAsArrayBuffer is not available in RN reader.readAsDataURL(blob); }); diff --git a/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts b/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts index 04054e8474f..d99149f6c0a 100644 --- a/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts +++ b/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts @@ -2,25 +2,27 @@ // SPDX-License-Identifier: Apache-2.0 import { AmplifyClassV6, StorageAccessLevel } from '@aws-amplify/core'; + import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { StorageValidationErrorCode } from '../../../errors/types/validation'; import { StorageError } from '../../../errors/StorageError'; -import { DEFAULT_ACCESS_LEVEL, LOCAL_TESTING_S3_ENDPOINT } from './constants'; import { resolvePrefix as defaultPrefixResolver } from '../../../utils/resolvePrefix'; import { ResolvedS3Config } from '../types/options'; -type S3ApiOptions = { +import { DEFAULT_ACCESS_LEVEL, LOCAL_TESTING_S3_ENDPOINT } from './constants'; + +interface S3ApiOptions { accessLevel?: StorageAccessLevel; targetIdentityId?: string; useAccelerateEndpoint?: boolean; -}; +} -type ResolvedS3ConfigAndInput = { +interface ResolvedS3ConfigAndInput { s3Config: ResolvedS3Config; bucket: string; keyPrefix: string; isObjectLockEnabled?: boolean; -}; +} /** * resolve the common input options for S3 API handlers from Amplify configuration and library options. diff --git a/packages/storage/src/providers/s3/utils/transferTask.ts b/packages/storage/src/providers/s3/utils/transferTask.ts index ecbd3aa3b30..cc17f344a9b 100644 --- a/packages/storage/src/providers/s3/utils/transferTask.ts +++ b/packages/storage/src/providers/s3/utils/transferTask.ts @@ -9,10 +9,10 @@ import { } from '../../../types/common'; import { logger } from '../../../utils'; -type CreateCancellableTaskOptions = { - job: () => Promise; - onCancel: (message?: string) => void; -}; +interface CreateCancellableTaskOptions { + job(): Promise; + onCancel(message?: string): void; +} type CancellableTask = DownloadTask; @@ -21,12 +21,13 @@ const createCancellableTask = ({ onCancel, }: CreateCancellableTaskOptions): CancellableTask => { const state = 'IN_PROGRESS' as TransferTaskState; - let canceledErrorMessage: string | undefined = undefined; + let canceledErrorMessage: string | undefined; const cancelableTask = { cancel: (message?: string) => { const { state } = cancelableTask; if (state === 'CANCELED' || state === 'ERROR' || state === 'SUCCESS') { logger.debug(`This task cannot be canceled. State: ${state}`); + return; } cancelableTask.state = 'CANCELED'; @@ -40,6 +41,7 @@ const createCancellableTask = ({ try { const result = await job(); cancelableTask.state = 'SUCCESS'; + return result; } catch (e) { if (isCancelError(e)) { @@ -58,13 +60,13 @@ const createCancellableTask = ({ export const createDownloadTask = createCancellableTask; -type CreateUploadTaskOptions = { - job: () => Promise; - onCancel: (message?: string) => void; - onResume?: () => void; - onPause?: () => void; +interface CreateUploadTaskOptions { + job(): Promise; + onCancel(message?: string): void; + onResume?(): void; + onPause?(): void; isMultipartUpload?: boolean; -}; +} export const createUploadTask = ({ job, @@ -83,6 +85,7 @@ export const createUploadTask = ({ const { state } = uploadTask; if (!isMultipartUpload || state !== 'IN_PROGRESS') { logger.debug(`This task cannot be paused. State: ${state}`); + return; } // @ts-ignore @@ -93,6 +96,7 @@ export const createUploadTask = ({ const { state } = uploadTask; if (!isMultipartUpload || state !== 'PAUSED') { logger.debug(`This task cannot be resumed. State: ${state}`); + return; } // @ts-ignore diff --git a/packages/storage/src/providers/s3/utils/userAgent.ts b/packages/storage/src/providers/s3/utils/userAgent.ts index 1779ddfd0c5..ece480b88eb 100644 --- a/packages/storage/src/providers/s3/utils/userAgent.ts +++ b/packages/storage/src/providers/s3/utils/userAgent.ts @@ -1,8 +1,8 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { - StorageAction, Category, + StorageAction, getAmplifyUserAgent, } from '@aws-amplify/core/internals/utils'; diff --git a/packages/storage/src/types/common.ts b/packages/storage/src/types/common.ts index eaa4d546dfd..0f5b738c476 100644 --- a/packages/storage/src/types/common.ts +++ b/packages/storage/src/types/common.ts @@ -10,12 +10,12 @@ export type TransferTaskState = | 'SUCCESS' | 'ERROR'; -export type TransferProgressEvent = { +export interface TransferProgressEvent { transferredBytes: number; totalBytes?: number; -}; +} -export type TransferTask = { +export interface TransferTask { /** * Cancel an ongoing transfer(upload/download) task. This will reject the `result` promise with an `AbortError` by * default. You can use `isCancelError` to check if the error is caused by cancellation. @@ -24,19 +24,19 @@ export type TransferTask = { * canceled. If provided, the `result` promise will be rejected with a {@link CanceledError} with supplied error * message instead. */ - cancel: (message?: string) => void; + cancel(message?: string): void; /** * Pause an ongoing transfer(upload/download) task. This method does not support the following scenarios: * * Downloading data or file from given key. */ - pause: () => void; + pause(): void; /** * Resume a paused transfer(upload/download) task. This method does not support the following scenarios: * * Downloading data or file from given key. */ - resume: () => void; + resume(): void; /** * Current state of the transfer task. @@ -47,7 +47,7 @@ export type TransferTask = { * Promise that resolves when the transfer task is completed. The promise will be rejected if the task is canceled. */ result: Promise; -}; +} export type DownloadTask = Omit< TransferTask, diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index 0a8e709137d..861ebf53876 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -2,30 +2,30 @@ // SPDX-License-Identifier: Apache-2.0 import { - StorageOptions, StorageListAllOptions, StorageListPaginateOptions, + StorageOptions, } from './options'; -export type StorageOperationInput = { +export interface StorageOperationInput { key: string; options?: Options; -}; +} export type StorageGetPropertiesInput = StorageOperationInput; -export type StorageRemoveInput = { +export interface StorageRemoveInput { key: string; options?: Options; -}; +} -export type StorageListInput< +export interface StorageListInput< Options extends StorageListAllOptions | StorageListPaginateOptions, -> = { +> { prefix?: string; options?: Options; -}; +} export type StorageGetUrlInput = StorageOperationInput; @@ -38,13 +38,13 @@ export type StorageUploadDataInput = data: StorageUploadDataPayload; }; -export type StorageCopyInput< +export interface StorageCopyInput< SourceOptions extends StorageOptions, DestinationOptions extends StorageOptions, -> = { +> { source: SourceOptions; destination: DestinationOptions; -}; +} /** * The data payload type for upload operation. diff --git a/packages/storage/src/types/options.ts b/packages/storage/src/types/options.ts index 9962084dfde..df992df5838 100644 --- a/packages/storage/src/types/options.ts +++ b/packages/storage/src/types/options.ts @@ -3,9 +3,9 @@ import { StorageAccessLevel } from '@aws-amplify/core'; -export type StorageOptions = { +export interface StorageOptions { accessLevel?: StorageAccessLevel; -}; +} export type StorageListAllOptions = StorageOptions & { listAll: true; diff --git a/packages/storage/src/types/outputs.ts b/packages/storage/src/types/outputs.ts index 766acf95365..b5b3a9236c0 100644 --- a/packages/storage/src/types/outputs.ts +++ b/packages/storage/src/types/outputs.ts @@ -3,7 +3,7 @@ import { ResponseBodyMixin } from '@aws-amplify/core/internals/aws-client-utils'; -export type StorageItem = { +export interface StorageItem { /** * Key of the object */ @@ -26,13 +26,13 @@ export type StorageItem = { * @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html#UserMetadata */ metadata?: Record; -}; +} export type StorageDownloadDataOutput = T & { body: ResponseBodyMixin; }; -export type StorageGetUrlOutput = { +export interface StorageGetUrlOutput { /** * presigned URL of the given object. */ @@ -41,10 +41,10 @@ export type StorageGetUrlOutput = { * expiresAt is date in which generated URL expires. */ expiresAt: Date; -}; +} export type StorageUploadOutput = Item; -export type StorageListOutput = { +export interface StorageListOutput { items: Item[]; -}; +} diff --git a/packages/storage/src/utils/resolvePrefix.ts b/packages/storage/src/utils/resolvePrefix.ts index 8d33f59bd69..c2d1be25d40 100644 --- a/packages/storage/src/utils/resolvePrefix.ts +++ b/packages/storage/src/utils/resolvePrefix.ts @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import { StorageAccessLevel } from '@aws-amplify/core'; + import { assertValidationError } from '../errors/utils/assertValidationError'; import { StorageValidationErrorCode } from '../errors/types/validation'; -type ResolvePrefixOptions = { +interface ResolvePrefixOptions { accessLevel: StorageAccessLevel; targetIdentityId?: string; -}; +} export const resolvePrefix = ({ accessLevel, @@ -19,12 +20,14 @@ export const resolvePrefix = ({ !!targetIdentityId, StorageValidationErrorCode.NoIdentityId, ); + return `private/${targetIdentityId}/`; } else if (accessLevel === 'protected') { assertValidationError( !!targetIdentityId, StorageValidationErrorCode.NoIdentityId, ); + return `protected/${targetIdentityId}/`; } else { return 'public/'; From d24580a56d131870775f14bc4cbb6a256c136226 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Mon, 12 Feb 2024 14:43:36 -0800 Subject: [PATCH 3/4] chore(storage): manual fix of linter reported errors --- .../src/providers/s3/apis/getProperties.ts | 1 + .../storage/src/providers/s3/apis/getUrl.ts | 1 + .../s3/apis/internal/getProperties.ts | 4 +- .../src/providers/s3/apis/internal/getUrl.ts | 4 +- .../src/providers/s3/apis/internal/list.ts | 4 +- .../storage/src/providers/s3/apis/list.ts | 2 + .../storage/src/providers/s3/apis/remove.ts | 3 +- .../src/providers/s3/apis/server/list.ts | 2 + .../uploadData/multipart/uploadHandlers.ts | 48 ++++++++++--------- .../src/providers/s3/utils/client/base.ts | 2 +- .../client/runtime/base64/index.native.ts | 2 +- .../client/runtime/contentSha256middleware.ts | 4 +- .../client/runtime/s3TransferHandler/fetch.ts | 10 ++-- .../client/runtime/s3TransferHandler/xhr.ts | 6 +-- .../client/runtime/xhrTransferHandler.ts | 7 +-- .../s3/utils/client/runtime/xmlParser/dom.ts | 11 ++--- .../utils/client/runtime/xmlParser/pureJs.ts | 13 +++-- .../utils/client/utils/deserializeHelpers.ts | 2 +- .../src/providers/s3/utils/transferTask.ts | 14 ++++-- 19 files changed, 80 insertions(+), 60 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/getProperties.ts b/packages/storage/src/providers/s3/apis/getProperties.ts index 5fe882e4808..4b98d529f55 100644 --- a/packages/storage/src/providers/s3/apis/getProperties.ts +++ b/packages/storage/src/providers/s3/apis/getProperties.ts @@ -4,6 +4,7 @@ import { Amplify } from '@aws-amplify/core'; import { GetPropertiesInput, GetPropertiesOutput, S3Exception } from '../types'; +import { StorageValidationErrorCode } from '../../../errors/types/validation'; import { getProperties as getPropertiesInternal } from './internal/getProperties'; diff --git a/packages/storage/src/providers/s3/apis/getUrl.ts b/packages/storage/src/providers/s3/apis/getUrl.ts index 6cbd3ee5315..708e601cc87 100644 --- a/packages/storage/src/providers/s3/apis/getUrl.ts +++ b/packages/storage/src/providers/s3/apis/getUrl.ts @@ -5,6 +5,7 @@ import { Amplify } from '@aws-amplify/core'; import { StorageValidationErrorCode } from '../../../errors/types/validation'; import { GetUrlInput, GetUrlOutput, S3Exception } from '../types'; +import { StorageError } from '../../../errors/StorageError'; import { getUrl as getUrlInternal } from './internal/getUrl'; diff --git a/packages/storage/src/providers/s3/apis/internal/getProperties.ts b/packages/storage/src/providers/s3/apis/internal/getProperties.ts index adf79c50b8e..db854f8635b 100644 --- a/packages/storage/src/providers/s3/apis/internal/getProperties.ts +++ b/packages/storage/src/providers/s3/apis/internal/getProperties.ts @@ -10,11 +10,11 @@ import { headObject } from '../../utils/client'; import { getStorageUserAgentValue } from '../../utils/userAgent'; import { logger } from '../../../../utils'; -export const getProperties = async function ( +export const getProperties = async ( amplify: AmplifyClassV6, input: GetPropertiesInput, action?: StorageAction, -): Promise { +): Promise => { const { key, options } = input; const { s3Config, bucket, keyPrefix } = await resolveS3ConfigAndInput( amplify, diff --git a/packages/storage/src/providers/s3/apis/internal/getUrl.ts b/packages/storage/src/providers/s3/apis/internal/getUrl.ts index 674c10ea717..15110d535b7 100644 --- a/packages/storage/src/providers/s3/apis/internal/getUrl.ts +++ b/packages/storage/src/providers/s3/apis/internal/getUrl.ts @@ -16,10 +16,10 @@ import { import { getProperties } from './getProperties'; -export const getUrl = async function ( +export const getUrl = async ( amplify: AmplifyClassV6, input: GetUrlInput, -): Promise { +): Promise => { const { key, options } = input; if (options?.validateObjectExistence) { diff --git a/packages/storage/src/providers/s3/apis/internal/list.ts b/packages/storage/src/providers/s3/apis/internal/list.ts index b31e67ec5d7..1d49ed5942b 100644 --- a/packages/storage/src/providers/s3/apis/internal/list.ts +++ b/packages/storage/src/providers/s3/apis/internal/list.ts @@ -57,8 +57,8 @@ export const list = async ( logger.debug(`listing items from "${listParams.Prefix}"`); return options.listAll - ? await _listAll({ s3Config, listParams, prefix }) - : await _list({ s3Config, listParams, prefix }); + ? _listAll({ s3Config, listParams, prefix }) + : _list({ s3Config, listParams, prefix }); }; const _listAll = async ({ diff --git a/packages/storage/src/providers/s3/apis/list.ts b/packages/storage/src/providers/s3/apis/list.ts index f37b66ad381..0778252e34d 100644 --- a/packages/storage/src/providers/s3/apis/list.ts +++ b/packages/storage/src/providers/s3/apis/list.ts @@ -8,7 +8,9 @@ import { ListAllOutput, ListPaginateInput, ListPaginateOutput, + S3Exception, } from '../types'; +import { StorageValidationErrorCode } from '../../../errors/types/validation'; import { list as listInternal } from './internal/list'; diff --git a/packages/storage/src/providers/s3/apis/remove.ts b/packages/storage/src/providers/s3/apis/remove.ts index 0ed60256586..bda77060f5f 100644 --- a/packages/storage/src/providers/s3/apis/remove.ts +++ b/packages/storage/src/providers/s3/apis/remove.ts @@ -3,7 +3,8 @@ import { Amplify } from '@aws-amplify/core'; -import { RemoveInput, RemoveOutput } from '../types'; +import { RemoveInput, RemoveOutput, S3Exception } from '../types'; +import { StorageValidationErrorCode } from '../../../errors/types/validation'; import { remove as removeInternal } from './internal/remove'; diff --git a/packages/storage/src/providers/s3/apis/server/list.ts b/packages/storage/src/providers/s3/apis/server/list.ts index 588275a7318..50eb58ebfec 100644 --- a/packages/storage/src/providers/s3/apis/server/list.ts +++ b/packages/storage/src/providers/s3/apis/server/list.ts @@ -11,8 +11,10 @@ import { ListAllOutput, ListPaginateInput, ListPaginateOutput, + S3Exception, } from '../../types'; import { list as listInternal } from '../internal/list'; +import { StorageValidationErrorCode } from '../../../../errors/types/validation'; interface ListApi { /** diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts index 0df1505a6eb..587ee33c434 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts @@ -47,10 +47,10 @@ export const getMultipartUploadHandlers = ( completedParts: Part[]; } | undefined; - let s3Config: ResolvedS3Config | undefined; + let resolvedS3Config: ResolvedS3Config | undefined; let abortController: AbortController | undefined; - let bucket: string | undefined; - let keyPrefix: string | undefined; + let resolvedBucket: string | undefined; + let resolvedKeyPrefix: string | undefined; let uploadCacheKey: string | undefined; // Special flag that differentiates HTTP requests abort error caused by pause() from ones caused by cancel(). // The former one should NOT cause the upload job to throw, but cancels any pending HTTP requests. @@ -62,9 +62,10 @@ export const getMultipartUploadHandlers = ( Amplify, uploadDataOptions, ); - s3Config = resolvedS3Options.s3Config; - bucket = resolvedS3Options.bucket; - keyPrefix = resolvedS3Options.keyPrefix; + + resolvedS3Config = resolvedS3Options.s3Config; + resolvedBucket = resolvedS3Options.bucket; + resolvedKeyPrefix = resolvedS3Options.keyPrefix; abortController = new AbortController(); isAbortSignalFromPause = false; @@ -80,10 +81,10 @@ export const getMultipartUploadHandlers = ( if (!inProgressUpload) { const { uploadId, cachedParts } = await loadOrCreateMultipartUpload({ - s3Config, + s3Config: resolvedS3Config, accessLevel: resolveAccessLevel(accessLevel), - bucket, - keyPrefix, + bucket: resolvedBucket, + keyPrefix: resolvedKeyPrefix, key, contentType, contentDisposition, @@ -99,13 +100,13 @@ export const getMultipartUploadHandlers = ( }; } - const finalKey = keyPrefix + key; + const finalKey = resolvedKeyPrefix + key; uploadCacheKey = size ? getUploadsCacheKey({ file: data instanceof File ? data : undefined, accessLevel: resolveAccessLevel(uploadDataOptions?.accessLevel), contentType: uploadDataOptions?.contentType, - bucket: bucket!, + bucket: resolvedBucket!, size, key, }) @@ -133,9 +134,9 @@ export const getMultipartUploadHandlers = ( uploadPartExecutor({ dataChunkerGenerator: dataChunker, completedPartNumberSet, - s3Config, + s3Config: resolvedS3Config, abortSignal: abortController.signal, - bucket, + bucket: resolvedBucket, finalKey, uploadId: inProgressUpload.uploadId, onPartUploadCompletion, @@ -149,12 +150,12 @@ export const getMultipartUploadHandlers = ( const { ETag: eTag } = await completeMultipartUpload( { - ...s3Config, + ...resolvedS3Config, abortSignal: abortController.signal, userAgentValue: getStorageUserAgentValue(StorageAction.UploadData), }, { - Bucket: bucket, + Bucket: resolvedBucket, Key: finalKey, UploadId: inProgressUpload.uploadId, MultipartUpload: { @@ -166,10 +167,13 @@ export const getMultipartUploadHandlers = ( ); if (size) { - const { ContentLength: uploadedObjectSize } = await headObject(s3Config, { - Bucket: bucket, - Key: finalKey, - }); + const { ContentLength: uploadedObjectSize } = await headObject( + resolvedS3Config, + { + Bucket: resolvedBucket, + Key: finalKey, + }, + ); if (uploadedObjectSize && uploadedObjectSize !== size) { throw new StorageError({ name: 'Error', @@ -226,9 +230,9 @@ export const getMultipartUploadHandlers = ( await removeCachedUpload(uploadCacheKey); } // 3. clear multipart upload on server side. - await abortMultipartUpload(s3Config!, { - Bucket: bucket, - Key: keyPrefix! + key, + await abortMultipartUpload(resolvedS3Config!, { + Bucket: resolvedBucket, + Key: resolvedKeyPrefix! + key, UploadId: inProgressUpload?.uploadId, }); }; diff --git a/packages/storage/src/providers/s3/utils/client/base.ts b/packages/storage/src/providers/s3/utils/client/base.ts index 33eae5a8d05..96f0e5958ef 100644 --- a/packages/storage/src/providers/s3/utils/client/base.ts +++ b/packages/storage/src/providers/s3/utils/client/base.ts @@ -14,7 +14,7 @@ import { import { parseXmlError } from './utils'; -const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/; +const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/; const IP_ADDRESS_PATTERN = /(\d+\.){3}\d+/; const DOTS_PATTERN = /\.\./; diff --git a/packages/storage/src/providers/s3/utils/client/runtime/base64/index.native.ts b/packages/storage/src/providers/s3/utils/client/runtime/base64/index.native.ts index eb1d809c252..1135ea400bd 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/base64/index.native.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/base64/index.native.ts @@ -12,5 +12,5 @@ export function toBase64(input: string | ArrayBufferView): string { return Buffer.from(input, 'utf-8').toString('base64'); } - return new Buffer(input.buffer).toString('base64'); + return Buffer.from(input.buffer).toString('base64'); } diff --git a/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts b/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts index a18083dca37..eeb635dc656 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/contentSha256middleware.ts @@ -17,8 +17,8 @@ import { CONTENT_SHA256_HEADER } from './constants'; * * @internal */ -export const contentSha256Middleware = - (options: {}) => (next: MiddlewareHandler) => +export const contentSha256MiddlewareFactory = + () => (next: MiddlewareHandler) => async function contentSha256Middleware(request: HttpRequest) { if (request.headers[CONTENT_SHA256_HEADER]) { return next(request); diff --git a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts index cb024322589..865ee1a158e 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/fetch.ts @@ -8,9 +8,9 @@ import { } from '@aws-amplify/core/internals/aws-client-utils'; import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; -import { contentSha256Middleware } from '../contentSha256middleware'; +import { contentSha256MiddlewareFactory } from '../contentSha256middleware'; -import type { s3TransferHandler as s3BrowserTransferhandler } from './xhr'; +import type { s3TransferHandler as s3BrowserTransferHandler } from './xhr'; /** * S3 transfer handler for node based on Node-fetch. On top of basic transfer handler, it also supports @@ -18,10 +18,10 @@ import type { s3TransferHandler as s3BrowserTransferhandler } from './xhr'; * * @internal */ -export const s3TransferHandler: typeof s3BrowserTransferhandler = +export const s3TransferHandler: typeof s3BrowserTransferHandler = composeTransferHandler< - [{}], + [object], HttpRequest, HttpResponse, typeof authenticatedHandler - >(authenticatedHandler, [contentSha256Middleware]); + >(authenticatedHandler, [contentSha256MiddlewareFactory]); diff --git a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts index b661988e2f0..3ce1ec6e8c9 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/s3TransferHandler/xhr.ts @@ -13,7 +13,7 @@ import { } from '@aws-amplify/core/internals/aws-client-utils'; import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; -import { contentSha256Middleware } from '../contentSha256middleware'; +import { contentSha256MiddlewareFactory } from '../contentSha256middleware'; import { xhrTransferHandler } from '../xhrTransferHandler'; /** @@ -23,12 +23,12 @@ import { xhrTransferHandler } from '../xhrTransferHandler'; * @internal */ export const s3TransferHandler = composeTransferHandler< - [{}, UserAgentOptions, RetryOptions, SigningOptions], + [object, UserAgentOptions, RetryOptions, SigningOptions], HttpRequest, HttpResponse, typeof xhrTransferHandler >(xhrTransferHandler, [ - contentSha256Middleware, + contentSha256MiddlewareFactory, userAgentMiddlewareFactory, retryMiddlewareFactory, signingMiddlewareFactory, diff --git a/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts b/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts index e0fc4ca5481..371b4d8efa6 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts @@ -115,13 +115,14 @@ export const xhrTransferHandler: TransferHandler< const responseHeaders = convertResponseHeaders( xhr.getAllResponseHeaders(), ); - const { responseType } = xhr; + const { responseType: loadEndResponseType } = xhr; const responseBlob = xhr.response as Blob; - const responseText = responseType === 'text' ? xhr.responseText : ''; + const responseText = + loadEndResponseType === 'text' ? xhr.responseText : ''; const bodyMixIn: ResponseBodyMixin = { blob: () => Promise.resolve(responseBlob), text: withMemoization(() => - responseType === 'blob' + loadEndResponseType === 'blob' ? readBlobAsText(responseBlob) : Promise.resolve(responseText), ), diff --git a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts index 34e9c3c1933..f5b1d0a3a1c 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/dom.ts @@ -32,13 +32,12 @@ const parseXmlNode = (node: Node): any => { // Node like foo will be converted to { Location: 'foo' } // instead of { Location: { '#text': 'foo' } }. if (isTextOnlyElementNode(node)) { - return node.childNodes[0]?.nodeValue!; + return node.childNodes[0].nodeValue!; } const nodeValue: Record = {}; // convert attributes - for (let i = 0; i < node.attributes.length; i++) { - const attr = node.attributes[i]; + for (const attr of node.attributes) { if (!isNamespaceAttributeName(attr.nodeName)) { nodeValue[attr.nodeName] = attr.nodeValue!; } @@ -46,8 +45,7 @@ const parseXmlNode = (node: Node): any => { // convert child nodes if (node.children.length > 0) { - for (let i = 0; i < node.children.length; i++) { - const child = node.children[i]; + for (const child of node.children) { const childValue = parseXmlNode(child); if (childValue === undefined) { continue; @@ -80,8 +78,7 @@ const isTextOnlyElementNode = (node: Element): boolean => node.firstChild?.nodeType === Node.TEXT_NODE; const hasOnlyNamespaceAttributes = (node: Element): boolean => { - for (let i = 0; i < node.attributes.length; i++) { - const attr = node.attributes[i]; + for (const attr of node.attributes) { if (!isNamespaceAttributeName(attr.nodeName)) { return false; } diff --git a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts index e55b99e71bb..dcfc9950485 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/xmlParser/pureJs.ts @@ -12,7 +12,7 @@ import { XMLParser } from 'fast-xml-parser'; */ export const parser = { parse: (xmlStr: string): any => { - const parser = new XMLParser({ + const xmlParser = new XMLParser({ attributeNamePrefix: '', htmlEntities: true, ignoreAttributes: false, @@ -23,9 +23,9 @@ export const parser = { tagValueProcessor: (_, val) => val.trim() === '' && val.includes('\n') ? '' : undefined, }); - parser.addEntity('#xD', '\r'); - parser.addEntity('#10', '\n'); - const parsedObj: any = parser.parse(xmlStr); + xmlParser.addEntity('#xD', '\r'); + xmlParser.addEntity('#10', '\n'); + const parsedObj: any = xmlParser.parse(xmlStr); const textNodeName = '#text'; const key = Object.keys(parsedObj)[0]; const parsedObjToReturn = parsedObj[key]; @@ -46,7 +46,10 @@ export const parser = { const getValueFromTextNode = (obj: any) => { const textNodeName = '#text'; for (const key in obj) { - if (obj.hasOwnProperty(key) && obj[key][textNodeName] !== undefined) { + if ( + Object.prototype.hasOwnProperty.call(obj, key) && + obj[key][textNodeName] !== undefined + ) { obj[key] = obj[key][textNodeName]; } else if (typeof obj[key] === 'object' && obj[key] !== null) { obj[key] = getValueFromTextNode(obj[key]); diff --git a/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts b/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts index c7a48a2f564..0c06cbc60e7 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts @@ -59,7 +59,7 @@ export const map = >>( const [accessor, deserializer] = Array.isArray(instruction) ? instruction : [instruction]; - if (obj.hasOwnProperty(accessor)) { + if (Object.prototype.hasOwnProperty.call(obj, accessor)) { result[key as keyof Instructions] = deserializer ? deserializer(obj[accessor]) : String(obj[accessor]); diff --git a/packages/storage/src/providers/s3/utils/transferTask.ts b/packages/storage/src/providers/s3/utils/transferTask.ts index cc17f344a9b..47a1a0063a4 100644 --- a/packages/storage/src/providers/s3/utils/transferTask.ts +++ b/packages/storage/src/providers/s3/utils/transferTask.ts @@ -24,9 +24,13 @@ const createCancellableTask = ({ let canceledErrorMessage: string | undefined; const cancelableTask = { cancel: (message?: string) => { - const { state } = cancelableTask; - if (state === 'CANCELED' || state === 'ERROR' || state === 'SUCCESS') { - logger.debug(`This task cannot be canceled. State: ${state}`); + const { state: taskState } = cancelableTask; + if ( + taskState === 'CANCELED' || + taskState === 'ERROR' || + taskState === 'SUCCESS' + ) { + logger.debug(`This task cannot be canceled. State: ${taskState}`); return; } @@ -88,6 +92,8 @@ export const createUploadTask = ({ return; } + // TODO(eslint): remove this linter suppression. + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore uploadTask.state = 'PAUSED'; onPause?.(); @@ -99,6 +105,8 @@ export const createUploadTask = ({ return; } + // TODO(eslint): remove this linter suppression. + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore uploadTask.state = 'IN_PROGRESS'; onResume?.(); From 99bca3de1c92be4d8027427bca67fb2cf09c3444 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Mon, 12 Feb 2024 14:50:59 -0800 Subject: [PATCH 4/4] chore(storage): re-baseline jest statements coverage threshold --- packages/storage/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/storage/jest.config.js b/packages/storage/jest.config.js index 06b4ec635ed..e022cf95b7c 100644 --- a/packages/storage/jest.config.js +++ b/packages/storage/jest.config.js @@ -5,7 +5,7 @@ module.exports = { branches: 75, functions: 80, lines: 81, - statements: 91, + statements: 90, }, }, };