From f721dc95f4e1b9051e180ad9f2cd1088ce6853f8 Mon Sep 17 00:00:00 2001 From: ashika112 Date: Wed, 14 Feb 2024 22:16:51 -0800 Subject: [PATCH 01/11] basic change --- .../uploadData/multipart/uploadHandlers.ts | 6 ++--- .../s3/apis/uploadData/putObjectJob.ts | 6 ++--- .../storage/src/providers/s3/types/inputs.ts | 3 ++- .../storage/src/providers/s3/types/options.ts | 24 +++++++++++++++++++ packages/storage/src/types/inputs.ts | 13 ++++++++-- 5 files changed, 43 insertions(+), 9 deletions(-) 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 587ee33c434..68354ea2543 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts @@ -36,7 +36,7 @@ import { getDataChunker } from './getDataChunker'; * @internal */ export const getMultipartUploadHandlers = ( - { options: uploadDataOptions, key, data }: UploadDataInput, + { options: uploadDataOptions, path: key, data }: UploadDataInput, size?: number, ) => { let resolveCallback: ((value: S3Item) => void) | undefined; @@ -70,12 +70,12 @@ export const getMultipartUploadHandlers = ( abortController = new AbortController(); isAbortSignalFromPause = false; + const accessLevel = "guest" const { contentDisposition, contentEncoding, contentType = 'application/octet-stream', metadata, - accessLevel, onProgress, } = uploadDataOptions ?? {}; @@ -104,7 +104,7 @@ export const getMultipartUploadHandlers = ( uploadCacheKey = size ? getUploadsCacheKey({ file: data instanceof File ? data : undefined, - accessLevel: resolveAccessLevel(uploadDataOptions?.accessLevel), + accessLevel: resolveAccessLevel(accessLevel), contentType: uploadDataOptions?.contentType, bucket: resolvedBucket!, size, diff --git a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts index 5d1a40786ad..0717e51a46e 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts @@ -17,7 +17,7 @@ import { getStorageUserAgentValue } from '../../utils/userAgent'; */ export const putObjectJob = ( - { options: uploadDataOptions, key, data }: UploadDataInput, + { options: uploadDataOptions, path: key, data }: UploadDataInput, abortSignal: AbortSignal, totalLength?: number, ) => @@ -25,7 +25,7 @@ export const putObjectJob = const { bucket, keyPrefix, s3Config, isObjectLockEnabled } = await resolveS3ConfigAndInput(Amplify, uploadDataOptions); - const finalKey = keyPrefix + key; + // const finalKey = keyPrefix + key; const { contentDisposition, contentEncoding, @@ -43,7 +43,7 @@ export const putObjectJob = }, { Bucket: bucket, - Key: finalKey, + Key: key, Body: data, ContentType: contentType, ContentDisposition: contentDisposition, diff --git a/packages/storage/src/providers/s3/types/inputs.ts b/packages/storage/src/providers/s3/types/inputs.ts index 9a360d0bfe3..75e26ae830b 100644 --- a/packages/storage/src/providers/s3/types/inputs.ts +++ b/packages/storage/src/providers/s3/types/inputs.ts @@ -21,6 +21,7 @@ import { RemoveOptions, UploadDataOptions, } from '../types'; +import { UploadDataOptionsNew } from './options'; // TODO: support use accelerate endpoint option /** @@ -65,4 +66,4 @@ export type DownloadDataInput = StorageDownloadDataInput; /** * Input type for S3 uploadData API. */ -export type UploadDataInput = StorageUploadDataInput; +export type UploadDataInput = StorageUploadDataInput; diff --git a/packages/storage/src/providers/s3/types/options.ts b/packages/storage/src/providers/s3/types/options.ts index dad92d72f1b..25c59eea1ff 100644 --- a/packages/storage/src/providers/s3/types/options.ts +++ b/packages/storage/src/providers/s3/types/options.ts @@ -117,6 +117,30 @@ export type UploadDataOptions = WriteOptions & metadata?: Record; }; +export type UploadDataOptionsNew = CommonOptions & + TransferOptions & { + /** + * The default content-disposition header value of the file when downloading it. + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + */ + contentDisposition?: string; + /** + * The default content-encoding header value of the file when downloading it. + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding + */ + contentEncoding?: string; + /** + * The default content-type header value of the file when downloading it. + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + */ + contentType?: string; + /** + * The user-defined metadata for the object uploaded to S3. + * @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html#UserMetadata + */ + metadata?: Record; + }; + export type CopySourceOptions = ReadOptions & { key: string; }; diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index 861ebf53876..90a7fd3422f 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -12,6 +12,15 @@ export interface StorageOperationInput { options?: Options; } +export type StorageOperationInputPath = { + path: string; + options?: Options; +}; + +// export type StorageOperationInputNew = +// | StorageOperationInput +// | StorageOperationInputPath; + export type StorageGetPropertiesInput = StorageOperationInput; @@ -33,8 +42,8 @@ export type StorageGetUrlInput = export type StorageDownloadDataInput = StorageOperationInput; -export type StorageUploadDataInput = - StorageOperationInput & { +export type StorageUploadDataInput = + StorageOperationInputPath & { data: StorageUploadDataPayload; }; From 55f753902b3cba99becb3633835c47035f8e342c Mon Sep 17 00:00:00 2001 From: ashika112 Date: Fri, 16 Feb 2024 13:17:38 -0800 Subject: [PATCH 02/11] update types with never --- .../src/providers/s3/apis/uploadData/index.ts | 7 +++++-- .../uploadData/multipart/uploadHandlers.ts | 6 +++--- .../s3/apis/uploadData/putObjectJob.ts | 18 ++++++++++++++---- .../storage/src/providers/s3/types/inputs.ts | 10 +++++++++- .../storage/src/providers/s3/types/options.ts | 2 +- packages/storage/src/types/index.ts | 1 + packages/storage/src/types/inputs.ts | 19 ++++++++++++------- 7 files changed, 45 insertions(+), 18 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/uploadData/index.ts b/packages/storage/src/providers/s3/apis/uploadData/index.ts index 2c1926cb1e0..c34c84c820c 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/index.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/index.ts @@ -10,6 +10,7 @@ import { DEFAULT_PART_SIZE, MAX_OBJECT_SIZE } from '../../utils/constants'; import { byteLength } from './byteLength'; import { putObjectJob } from './putObjectJob'; import { getMultipartUploadHandlers } from './multipart'; +import { UploadDataInputPath } from '../../types/inputs'; /** * Upload data to specified S3 object. By default, it uses single PUT operation to upload if the data is less than 5MB. @@ -59,7 +60,9 @@ import { getMultipartUploadHandlers } from './multipart'; * await uploadTask.result; * ``` */ -export const uploadData = (input: UploadDataInput): UploadDataOutput => { +export const uploadData = ( + input: UploadDataInput | UploadDataInputPath, +): UploadDataOutput => { const { data } = input; const dataByteLength = byteLength(data); @@ -80,7 +83,7 @@ export const uploadData = (input: UploadDataInput): UploadDataOutput => { }); } else { const { multipartUploadJob, onPause, onResume, onCancel } = - getMultipartUploadHandlers(input, dataByteLength); + getMultipartUploadHandlers(input as UploadDataInput, dataByteLength); return createUploadTask({ isMultipartUpload: true, 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 68354ea2543..6fdd523329c 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts @@ -36,7 +36,7 @@ import { getDataChunker } from './getDataChunker'; * @internal */ export const getMultipartUploadHandlers = ( - { options: uploadDataOptions, path: key, data }: UploadDataInput, + { options: uploadDataOptions, key, data }: UploadDataInput, size?: number, ) => { let resolveCallback: ((value: S3Item) => void) | undefined; @@ -70,7 +70,7 @@ export const getMultipartUploadHandlers = ( abortController = new AbortController(); isAbortSignalFromPause = false; - const accessLevel = "guest" + const accessLevel = 'guest'; const { contentDisposition, contentEncoding, @@ -109,7 +109,7 @@ export const getMultipartUploadHandlers = ( bucket: resolvedBucket!, size, key, - }) + }) : undefined; const dataChunker = getDataChunker(data, size); diff --git a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts index 0717e51a46e..78c814ec620 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts @@ -9,6 +9,7 @@ import { calculateContentMd5, resolveS3ConfigAndInput } from '../../utils'; import { Item as S3Item } from '../../types/outputs'; import { putObject } from '../../utils/client'; import { getStorageUserAgentValue } from '../../utils/userAgent'; +import { UploadDataInputPath } from '../../types/inputs'; /** * Get a function the returns a promise to call putObject API to S3. @@ -17,14 +18,23 @@ import { getStorageUserAgentValue } from '../../utils/userAgent'; */ export const putObjectJob = ( - { options: uploadDataOptions, path: key, data }: UploadDataInput, + uploadInput: UploadDataInput | UploadDataInputPath, abortSignal: AbortSignal, totalLength?: number, ) => async (): Promise => { + const { options: uploadDataOptions, data } = uploadInput; + + // eslint-disable-next-line unused-imports/no-unused-vars const { bucket, keyPrefix, s3Config, isObjectLockEnabled } = await resolveS3ConfigAndInput(Amplify, uploadDataOptions); - + let finalKey: string; + if ('path' in uploadInput) { + const { path } = uploadInput as UploadDataInputPath; + finalKey = typeof path === 'string' ? path : path(''); + } else { + finalKey = keyPrefix + uploadInput.key; + } // const finalKey = keyPrefix + key; const { contentDisposition, @@ -43,7 +53,7 @@ export const putObjectJob = }, { Bucket: bucket, - Key: key, + Key: finalKey, Body: data, ContentType: contentType, ContentDisposition: contentDisposition, @@ -56,7 +66,7 @@ export const putObjectJob = ); return { - key, + key: finalKey, eTag, versionId, contentType, diff --git a/packages/storage/src/providers/s3/types/inputs.ts b/packages/storage/src/providers/s3/types/inputs.ts index 75e26ae830b..9353f6864a0 100644 --- a/packages/storage/src/providers/s3/types/inputs.ts +++ b/packages/storage/src/providers/s3/types/inputs.ts @@ -9,6 +9,7 @@ import { StorageListInput, StorageRemoveInput, StorageUploadDataInput, + StorageUploadDataInputPath, } from '../../../types'; import { CopyDestinationOptions, @@ -21,6 +22,7 @@ import { RemoveOptions, UploadDataOptions, } from '../types'; + import { UploadDataOptionsNew } from './options'; // TODO: support use accelerate endpoint option @@ -66,4 +68,10 @@ export type DownloadDataInput = StorageDownloadDataInput; /** * Input type for S3 uploadData API. */ -export type UploadDataInput = StorageUploadDataInput; +export type UploadDataInputPath = + StorageUploadDataInputPath; + +/** + * Input type for S3 uploadData API. + */ +export type UploadDataInput = StorageUploadDataInput; diff --git a/packages/storage/src/providers/s3/types/options.ts b/packages/storage/src/providers/s3/types/options.ts index 25c59eea1ff..74163de8512 100644 --- a/packages/storage/src/providers/s3/types/options.ts +++ b/packages/storage/src/providers/s3/types/options.ts @@ -117,7 +117,7 @@ export type UploadDataOptions = WriteOptions & metadata?: Record; }; -export type UploadDataOptionsNew = CommonOptions & +export type UploadDataOptionsNew = {accessLevel?: never} & CommonOptions & TransferOptions & { /** * The default content-disposition header value of the file when downloading it. diff --git a/packages/storage/src/types/index.ts b/packages/storage/src/types/index.ts index 39bb1c049a3..975a8cb43a7 100644 --- a/packages/storage/src/types/index.ts +++ b/packages/storage/src/types/index.ts @@ -17,6 +17,7 @@ export { StorageCopyInput, StorageGetUrlInput, StorageUploadDataPayload, + StorageUploadDataInputPath } from './inputs'; export { StorageOptions, diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index 90a7fd3422f..2b9114d7677 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -9,18 +9,18 @@ import { export interface StorageOperationInput { key: string; + path?: never; options?: Options; } -export type StorageOperationInputPath = { - path: string; +type PathOptions = { accessLevel?: never } + +export type StorageOperationInputPath = { + key?: never; + path: string | ((id: string) => string); options?: Options; }; -// export type StorageOperationInputNew = -// | StorageOperationInput -// | StorageOperationInputPath; - export type StorageGetPropertiesInput = StorageOperationInput; @@ -42,7 +42,12 @@ export type StorageGetUrlInput = export type StorageDownloadDataInput = StorageOperationInput; -export type StorageUploadDataInput = +export type StorageUploadDataInput = + StorageOperationInput & { + data: StorageUploadDataPayload; + }; + +export type StorageUploadDataInputPath = StorageOperationInputPath & { data: StorageUploadDataPayload; }; From 03a5ab1a912c68916f3f431b5f91238938ec4ec7 Mon Sep 17 00:00:00 2001 From: ashika112 Date: Mon, 19 Feb 2024 17:14:28 -0800 Subject: [PATCH 03/11] update output type based on input --- .../src/providers/s3/apis/uploadData/index.ts | 2 +- .../s3/apis/uploadData/putObjectJob.ts | 15 +++++++++-- .../storage/src/providers/s3/types/outputs.ts | 13 +++++++++- packages/storage/src/types/outputs.ts | 25 +++++++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/uploadData/index.ts b/packages/storage/src/providers/s3/apis/uploadData/index.ts index c34c84c820c..288a71400b3 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/index.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/index.ts @@ -6,11 +6,11 @@ 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 { UploadDataInputPath } from '../../types/inputs'; import { byteLength } from './byteLength'; import { putObjectJob } from './putObjectJob'; import { getMultipartUploadHandlers } from './multipart'; -import { UploadDataInputPath } from '../../types/inputs'; /** * Upload data to specified S3 object. By default, it uses single PUT operation to upload if the data is less than 5MB. diff --git a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts index 78c814ec620..263a5b0a2b0 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts @@ -6,7 +6,7 @@ import { StorageAction } from '@aws-amplify/core/internals/utils'; import { UploadDataInput } from '../../types'; import { calculateContentMd5, resolveS3ConfigAndInput } from '../../utils'; -import { Item as S3Item } from '../../types/outputs'; +import { Item as S3Item, ItemPath as S3ItemPath } from '../../types/outputs'; import { putObject } from '../../utils/client'; import { getStorageUserAgentValue } from '../../utils/userAgent'; import { UploadDataInputPath } from '../../types/inputs'; @@ -22,7 +22,7 @@ export const putObjectJob = abortSignal: AbortSignal, totalLength?: number, ) => - async (): Promise => { + async (): Promise => { const { options: uploadDataOptions, data } = uploadInput; // eslint-disable-next-line unused-imports/no-unused-vars @@ -65,6 +65,17 @@ export const putObjectJob = }, ); + if ('path' in uploadInput) { + return { + path: finalKey, + eTag, + versionId, + contentType, + metadata, + size: totalLength, + }; + } + return { key: finalKey, eTag, diff --git a/packages/storage/src/providers/s3/types/outputs.ts b/packages/storage/src/providers/s3/types/outputs.ts index bbcb9fc75b1..a465bbfa442 100644 --- a/packages/storage/src/providers/s3/types/outputs.ts +++ b/packages/storage/src/providers/s3/types/outputs.ts @@ -9,6 +9,7 @@ import { StorageListOutput, UploadTask, } from '../../../types'; +import { StorageItemPath } from '../../../types/outputs'; /** * type for S3 item. @@ -23,6 +24,16 @@ export interface Item extends StorageItem { */ contentType?: string; } +export interface ItemPath extends StorageItemPath { + /** + * VersionId used to reference a specific version of the object. + */ + versionId?: string; + /** + * A standard MIME type describing the format of the object data. + */ + contentType?: string; +} /** * type for S3 list item. @@ -42,7 +53,7 @@ export type GetUrlOutput = StorageGetUrlOutput; /** * Output type for S3 uploadData API. */ -export type UploadDataOutput = UploadTask; +export type UploadDataOutput = UploadTask; /** * Output type for S3 getProperties API. diff --git a/packages/storage/src/types/outputs.ts b/packages/storage/src/types/outputs.ts index b5b3a9236c0..d5e7b2991d9 100644 --- a/packages/storage/src/types/outputs.ts +++ b/packages/storage/src/types/outputs.ts @@ -28,6 +28,31 @@ export interface StorageItem { metadata?: Record; } +export interface StorageItemPath { + /** + * Key of the object + */ + path: string; + /** + * Creation date of the object. + */ + lastModified?: Date; + /** + * Size of the body in bytes. + */ + size?: number; + /** + * An entity tag (ETag) is an opaque identifier assigned by a web server to a specific version of a resource found at + * a URL. + */ + eTag?: string; + /** + * The user-defined metadata for the object uploaded to S3. + * @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html#UserMetadata + */ + metadata?: Record; +} + export type StorageDownloadDataOutput = T & { body: ResponseBodyMixin; }; From 832b73739106d34b3b95081d66c1c73d6df0c9e5 Mon Sep 17 00:00:00 2001 From: ashika112 Date: Wed, 21 Feb 2024 16:00:39 -0800 Subject: [PATCH 04/11] use StrictUnion util type --- .../s3/apis/uploadData/multipart/uploadHandlers.ts | 4 ++-- .../src/providers/s3/apis/uploadData/putObjectJob.ts | 5 ++--- packages/storage/src/providers/s3/types/inputs.ts | 6 +++++- packages/storage/src/providers/s3/types/options.ts | 2 +- packages/storage/src/types/index.ts | 2 +- packages/storage/src/types/inputs.ts | 12 ++++++------ packages/storage/src/types/outputs.ts | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) 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 6fdd523329c..5d585203953 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts @@ -36,7 +36,7 @@ import { getDataChunker } from './getDataChunker'; * @internal */ export const getMultipartUploadHandlers = ( - { options: uploadDataOptions, key, data }: UploadDataInput, + { options: uploadDataOptions, key = '', data }: UploadDataInput, size?: number, ) => { let resolveCallback: ((value: S3Item) => void) | undefined; @@ -109,7 +109,7 @@ export const getMultipartUploadHandlers = ( bucket: resolvedBucket!, size, key, - }) + }) : undefined; const dataChunker = getDataChunker(data, size); diff --git a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts index 263a5b0a2b0..2b74cde406c 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts @@ -18,14 +18,13 @@ import { UploadDataInputPath } from '../../types/inputs'; */ export const putObjectJob = ( - uploadInput: UploadDataInput | UploadDataInputPath, + uploadInput: UploadDataInput, abortSignal: AbortSignal, totalLength?: number, ) => async (): Promise => { const { options: uploadDataOptions, data } = uploadInput; - // eslint-disable-next-line unused-imports/no-unused-vars const { bucket, keyPrefix, s3Config, isObjectLockEnabled } = await resolveS3ConfigAndInput(Amplify, uploadDataOptions); let finalKey: string; @@ -35,7 +34,7 @@ export const putObjectJob = } else { finalKey = keyPrefix + uploadInput.key; } - // const finalKey = keyPrefix + key; + const { contentDisposition, contentEncoding, diff --git a/packages/storage/src/providers/s3/types/inputs.ts b/packages/storage/src/providers/s3/types/inputs.ts index 9353f6864a0..e49db4d0c20 100644 --- a/packages/storage/src/providers/s3/types/inputs.ts +++ b/packages/storage/src/providers/s3/types/inputs.ts @@ -1,6 +1,8 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { StrictUnion } from '@aws-amplify/core/internals/utils'; + import { StorageCopyInput, StorageDownloadDataInput, @@ -74,4 +76,6 @@ export type UploadDataInputPath = /** * Input type for S3 uploadData API. */ -export type UploadDataInput = StorageUploadDataInput; +export type UploadDataInput = StrictUnion< + StorageUploadDataInput | UploadDataInputPath +>; diff --git a/packages/storage/src/providers/s3/types/options.ts b/packages/storage/src/providers/s3/types/options.ts index 74163de8512..25c59eea1ff 100644 --- a/packages/storage/src/providers/s3/types/options.ts +++ b/packages/storage/src/providers/s3/types/options.ts @@ -117,7 +117,7 @@ export type UploadDataOptions = WriteOptions & metadata?: Record; }; -export type UploadDataOptionsNew = {accessLevel?: never} & CommonOptions & +export type UploadDataOptionsNew = CommonOptions & TransferOptions & { /** * The default content-disposition header value of the file when downloading it. diff --git a/packages/storage/src/types/index.ts b/packages/storage/src/types/index.ts index 975a8cb43a7..68c238eaa19 100644 --- a/packages/storage/src/types/index.ts +++ b/packages/storage/src/types/index.ts @@ -17,7 +17,7 @@ export { StorageCopyInput, StorageGetUrlInput, StorageUploadDataPayload, - StorageUploadDataInputPath + StorageUploadDataInputPath, } from './inputs'; export { StorageOptions, diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index 2b9114d7677..042f404c0ba 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -9,17 +9,17 @@ import { export interface StorageOperationInput { key: string; - path?: never; options?: Options; } -type PathOptions = { accessLevel?: never } +// interface PathOptions { +// accessLevel?: never; +// } -export type StorageOperationInputPath = { - key?: never; +export interface StorageOperationInputPath { path: string | ((id: string) => string); options?: Options; -}; +} export type StorageGetPropertiesInput = StorageOperationInput; @@ -47,7 +47,7 @@ export type StorageUploadDataInput = data: StorageUploadDataPayload; }; -export type StorageUploadDataInputPath = +export type StorageUploadDataInputPath = StorageOperationInputPath & { data: StorageUploadDataPayload; }; diff --git a/packages/storage/src/types/outputs.ts b/packages/storage/src/types/outputs.ts index d5e7b2991d9..ebb645715d3 100644 --- a/packages/storage/src/types/outputs.ts +++ b/packages/storage/src/types/outputs.ts @@ -30,7 +30,7 @@ export interface StorageItem { export interface StorageItemPath { /** - * Key of the object + * Path of the object */ path: string; /** From e713523e27ec0919815652b2de833080dc833c9f Mon Sep 17 00:00:00 2001 From: ashika112 Date: Wed, 21 Feb 2024 16:14:34 -0800 Subject: [PATCH 05/11] minor cleanup --- .../storage/src/providers/s3/apis/uploadData/index.ts | 7 ++----- packages/storage/src/providers/s3/types/inputs.ts | 11 ++++++++--- packages/storage/src/types/index.ts | 2 +- packages/storage/src/types/inputs.ts | 7 +------ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/uploadData/index.ts b/packages/storage/src/providers/s3/apis/uploadData/index.ts index 288a71400b3..2c1926cb1e0 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/index.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/index.ts @@ -6,7 +6,6 @@ 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 { UploadDataInputPath } from '../../types/inputs'; import { byteLength } from './byteLength'; import { putObjectJob } from './putObjectJob'; @@ -60,9 +59,7 @@ import { getMultipartUploadHandlers } from './multipart'; * await uploadTask.result; * ``` */ -export const uploadData = ( - input: UploadDataInput | UploadDataInputPath, -): UploadDataOutput => { +export const uploadData = (input: UploadDataInput): UploadDataOutput => { const { data } = input; const dataByteLength = byteLength(data); @@ -83,7 +80,7 @@ export const uploadData = ( }); } else { const { multipartUploadJob, onPause, onResume, onCancel } = - getMultipartUploadHandlers(input as UploadDataInput, dataByteLength); + getMultipartUploadHandlers(input, dataByteLength); return createUploadTask({ isMultipartUpload: true, diff --git a/packages/storage/src/providers/s3/types/inputs.ts b/packages/storage/src/providers/s3/types/inputs.ts index e49db4d0c20..03211528779 100644 --- a/packages/storage/src/providers/s3/types/inputs.ts +++ b/packages/storage/src/providers/s3/types/inputs.ts @@ -10,7 +10,7 @@ import { StorageGetUrlInput, StorageListInput, StorageRemoveInput, - StorageUploadDataInput, + StorageUploadDataInputKey, StorageUploadDataInputPath, } from '../../../types'; import { @@ -68,7 +68,12 @@ export type RemoveInput = StorageRemoveInput; export type DownloadDataInput = StorageDownloadDataInput; /** - * Input type for S3 uploadData API. + * Input type for S3 uploadData API with key. + */ +export type UploadDataInputKey = StorageUploadDataInputKey; + +/** + * Input type for S3 uploadData API with path. */ export type UploadDataInputPath = StorageUploadDataInputPath; @@ -77,5 +82,5 @@ export type UploadDataInputPath = * Input type for S3 uploadData API. */ export type UploadDataInput = StrictUnion< - StorageUploadDataInput | UploadDataInputPath + UploadDataInputKey | UploadDataInputPath >; diff --git a/packages/storage/src/types/index.ts b/packages/storage/src/types/index.ts index 68c238eaa19..036f6f36062 100644 --- a/packages/storage/src/types/index.ts +++ b/packages/storage/src/types/index.ts @@ -13,10 +13,10 @@ export { StorageGetPropertiesInput, StorageRemoveInput, StorageDownloadDataInput, - StorageUploadDataInput, StorageCopyInput, StorageGetUrlInput, StorageUploadDataPayload, + StorageUploadDataInputKey, StorageUploadDataInputPath, } from './inputs'; export { diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index 042f404c0ba..2ea1c26cd5d 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -11,11 +11,6 @@ export interface StorageOperationInput { key: string; options?: Options; } - -// interface PathOptions { -// accessLevel?: never; -// } - export interface StorageOperationInputPath { path: string | ((id: string) => string); options?: Options; @@ -42,7 +37,7 @@ export type StorageGetUrlInput = export type StorageDownloadDataInput = StorageOperationInput; -export type StorageUploadDataInput = +export type StorageUploadDataInputKey = StorageOperationInput & { data: StorageUploadDataPayload; }; From 8aedee1b4e4a5593bcdd8c96e2c9565a0b21e4f3 Mon Sep 17 00:00:00 2001 From: ashika112 Date: Sun, 25 Feb 2024 18:02:24 -0800 Subject: [PATCH 06/11] overlaod typing --- .../src/providers/s3/apis/uploadData/index.ts | 9 ++++- .../s3/apis/uploadData/putObjectJob.ts | 32 ++++++------------ .../src/providers/s3/apis/uploadData/utils.ts | 33 +++++++++++++++++++ .../storage/src/providers/s3/types/outputs.ts | 3 +- 4 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 packages/storage/src/providers/s3/apis/uploadData/utils.ts diff --git a/packages/storage/src/providers/s3/apis/uploadData/index.ts b/packages/storage/src/providers/s3/apis/uploadData/index.ts index 2c1926cb1e0..d02d9898b41 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/index.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/index.ts @@ -6,6 +6,8 @@ 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 { UploadDataInputKey, UploadDataInputPath } from '../../types/inputs'; +import { UploadDataOutputPath } from '../../types/outputs'; import { byteLength } from './byteLength'; import { putObjectJob } from './putObjectJob'; @@ -59,7 +61,12 @@ import { getMultipartUploadHandlers } from './multipart'; * await uploadTask.result; * ``` */ -export const uploadData = (input: UploadDataInput): UploadDataOutput => { +interface UploadData { + (input: UploadDataInputKey): UploadDataOutput; + (input: UploadDataInputPath): UploadDataOutputPath; +} + +export const uploadData: UploadData = (input: UploadDataInput): any => { const { data } = input; const dataByteLength = byteLength(data); diff --git a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts index 2b74cde406c..be5b1294d0d 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts @@ -4,12 +4,13 @@ import { Amplify } from '@aws-amplify/core'; import { StorageAction } from '@aws-amplify/core/internals/utils'; -import { UploadDataInput } from '../../types'; import { calculateContentMd5, resolveS3ConfigAndInput } from '../../utils'; import { Item as S3Item, ItemPath as S3ItemPath } from '../../types/outputs'; import { putObject } from '../../utils/client'; import { getStorageUserAgentValue } from '../../utils/userAgent'; -import { UploadDataInputPath } from '../../types/inputs'; +import { UploadDataInput } from '../../types/inputs'; + +import { validateUploadInput } from './utils'; /** * Get a function the returns a promise to call putObject API to S3. @@ -27,13 +28,8 @@ export const putObjectJob = const { bucket, keyPrefix, s3Config, isObjectLockEnabled } = await resolveS3ConfigAndInput(Amplify, uploadDataOptions); - let finalKey: string; - if ('path' in uploadInput) { - const { path } = uploadInput as UploadDataInputPath; - finalKey = typeof path === 'string' ? path : path(''); - } else { - finalKey = keyPrefix + uploadInput.key; - } + + const { inputType, finalKey } = validateUploadInput(uploadInput, keyPrefix); const { contentDisposition, @@ -64,23 +60,15 @@ export const putObjectJob = }, ); - if ('path' in uploadInput) { - return { - path: finalKey, - eTag, - versionId, - contentType, - metadata, - size: totalLength, - }; - } - - return { - key: finalKey, + const result = { eTag, versionId, contentType, metadata, size: totalLength, }; + + return inputType === 'path' + ? { ...result, path: finalKey } + : { ...result, key: finalKey }; }; diff --git a/packages/storage/src/providers/s3/apis/uploadData/utils.ts b/packages/storage/src/providers/s3/apis/uploadData/utils.ts new file mode 100644 index 00000000000..0c25ac1fcfd --- /dev/null +++ b/packages/storage/src/providers/s3/apis/uploadData/utils.ts @@ -0,0 +1,33 @@ +import { UploadDataInput } from '../../types'; +import { UploadDataInputKey, UploadDataInputPath } from '../../types/inputs'; + +const isInputWithKey = ( + input: UploadDataInput, +): input is UploadDataInputKey => { + return input.key !== undefined; +}; + +const isInputWithPath = ( + input: UploadDataInput, +): input is UploadDataInputPath => { + return input.path !== undefined; +}; + +export const validateUploadInput = ( + uploadInput: UploadDataInput, + keyPrefix: string, +) => { + let finalKey; + if (isInputWithPath(uploadInput)) { + const { path } = uploadInput; + finalKey = typeof path === 'string' ? path : path(''); + + return { inputType: 'path', finalKey }; + } else if (isInputWithKey(uploadInput)) { + finalKey = keyPrefix + uploadInput.key; + + return { inputType: 'key', finalKey }; + } else { + throw new Error('invalid input'); + } +}; diff --git a/packages/storage/src/providers/s3/types/outputs.ts b/packages/storage/src/providers/s3/types/outputs.ts index a465bbfa442..7c5c94e9493 100644 --- a/packages/storage/src/providers/s3/types/outputs.ts +++ b/packages/storage/src/providers/s3/types/outputs.ts @@ -53,7 +53,8 @@ export type GetUrlOutput = StorageGetUrlOutput; /** * Output type for S3 uploadData API. */ -export type UploadDataOutput = UploadTask; +export type UploadDataOutput = UploadTask; +export type UploadDataOutputPath = UploadTask; /** * Output type for S3 getProperties API. From dde5049250c3735fb4b1363057258d82dc01ea6d Mon Sep 17 00:00:00 2001 From: ashika112 Date: Mon, 26 Feb 2024 23:13:03 -0800 Subject: [PATCH 07/11] updating type info --- .../src/providers/s3/apis/downloadData.ts | 11 +++++--- .../storage/src/providers/s3/types/inputs.ts | 11 +++++++- .../storage/src/providers/s3/types/options.ts | 4 +++ packages/storage/src/types/index.ts | 1 + packages/storage/src/types/inputs.ts | 8 ++++++ packages/storage/src/types/outputs.ts | 27 ++++++++++++++++++- 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/downloadData.ts b/packages/storage/src/providers/s3/apis/downloadData.ts index 281f73a7456..5da4ba19c6d 100644 --- a/packages/storage/src/providers/s3/apis/downloadData.ts +++ b/packages/storage/src/providers/s3/apis/downloadData.ts @@ -11,6 +11,9 @@ import { createDownloadTask } from '../utils'; import { getObject } from '../utils/client'; import { getStorageUserAgentValue } from '../utils/userAgent'; import { logger } from '../../../utils'; +import { Item } from '../types/outputs'; +import { StorageDownloadDataOutput } from '../../../types'; +import { DownloadDataInputKey, DownloadDataInputPath } from '../types/inputs'; /** * Download S3 object data to memory @@ -42,6 +45,7 @@ import { logger } from '../../../utils'; * } *``` */ + export const downloadData = (input: DownloadDataInput): DownloadDataOutput => { const abortController = new AbortController(); @@ -55,11 +59,12 @@ export const downloadData = (input: DownloadDataInput): DownloadDataOutput => { }; const downloadDataJob = - ( + ( { options: downloadDataOptions, key }: DownloadDataInput, abortSignal: AbortSignal ) => - async () => { + async (): Promise> => { + const { bucket, keyPrefix, s3Config } = await resolveS3ConfigAndInput( Amplify, downloadDataOptions @@ -92,7 +97,7 @@ const downloadDataJob = } ); return { - key, + key: key ?? '', body, lastModified, size, diff --git a/packages/storage/src/providers/s3/types/inputs.ts b/packages/storage/src/providers/s3/types/inputs.ts index 51c25ab4b3f..4d71d537fc3 100644 --- a/packages/storage/src/providers/s3/types/inputs.ts +++ b/packages/storage/src/providers/s3/types/inputs.ts @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { StrictUnion } from '@aws-amplify/core/internals/utils'; import { StorageCopyInput, StorageGetPropertiesInput, @@ -9,6 +10,7 @@ import { StorageRemoveInput, StorageDownloadDataInput, StorageUploadDataInput, + StorageDownloadDataInputPath, } from '../../../types'; import { GetPropertiesOptions, @@ -21,6 +23,7 @@ import { CopyDestinationOptions, CopySourceOptions, } from '../types'; +import { DownloadDataOptionsPath } from './options'; // TODO: support use accelerate endpoint option /** @@ -60,7 +63,13 @@ export type RemoveInput = StorageRemoveInput; /** * Input type for S3 downloadData API. */ -export type DownloadDataInput = StorageDownloadDataInput; +export type DownloadDataInputKey = + StorageDownloadDataInput; +export type DownloadDataInputPath = + StorageDownloadDataInputPath; +export type DownloadDataInput = StrictUnion< + DownloadDataInputKey | DownloadDataInputPath +>; /** * Input type for S3 uploadData API. diff --git a/packages/storage/src/providers/s3/types/options.ts b/packages/storage/src/providers/s3/types/options.ts index dace141e6b9..17cf8b04a22 100644 --- a/packages/storage/src/providers/s3/types/options.ts +++ b/packages/storage/src/providers/s3/types/options.ts @@ -92,6 +92,10 @@ export type DownloadDataOptions = ReadOptions & TransferOptions & BytesRangeOptions; +export type DownloadDataOptionsPath = CommonOptions & + TransferOptions & + BytesRangeOptions; + export type UploadDataOptions = WriteOptions & CommonOptions & TransferOptions & { diff --git a/packages/storage/src/types/index.ts b/packages/storage/src/types/index.ts index 39bb1c049a3..20132e5cbda 100644 --- a/packages/storage/src/types/index.ts +++ b/packages/storage/src/types/index.ts @@ -13,6 +13,7 @@ export { StorageGetPropertiesInput, StorageRemoveInput, StorageDownloadDataInput, + StorageDownloadDataInputPath, StorageUploadDataInput, StorageCopyInput, StorageGetUrlInput, diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index 0a8e709137d..ecdf1ea2624 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -12,6 +12,11 @@ export type StorageOperationInput = { options?: Options; }; +export type StorageOperationInputPath = { + path: string | ((id: string) => string); + options?: Options; +}; + export type StorageGetPropertiesInput = StorageOperationInput; @@ -33,6 +38,9 @@ export type StorageGetUrlInput = export type StorageDownloadDataInput = StorageOperationInput; +export type StorageDownloadDataInputPath = + StorageOperationInputPath; + export type StorageUploadDataInput = StorageOperationInput & { data: StorageUploadDataPayload; diff --git a/packages/storage/src/types/outputs.ts b/packages/storage/src/types/outputs.ts index 766acf95365..375cbd5a213 100644 --- a/packages/storage/src/types/outputs.ts +++ b/packages/storage/src/types/outputs.ts @@ -27,8 +27,33 @@ export type StorageItem = { */ metadata?: Record; }; +export type StorageItemPath = { + /** + * Path of the object + */ + path: string; + /** + * Creation date of the object. + */ + lastModified?: Date; + /** + * Size of the body in bytes. + */ + size?: number; + /** + * An entity tag (ETag) is an opaque identifier assigned by a web server to a specific version of a resource found at + * a URL. + */ + eTag?: string; + /** + * The user-defined metadata for the object uploaded to S3. + * @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html#UserMetadata + */ + metadata?: Record; +}; + -export type StorageDownloadDataOutput = T & { +export type StorageDownloadDataOutput = T & { body: ResponseBodyMixin; }; From 0b2b2c8b3309637f4331b03aff0ca4cec4016138 Mon Sep 17 00:00:00 2001 From: ashika112 Date: Tue, 27 Feb 2024 13:48:13 -0800 Subject: [PATCH 08/11] update downloadData implementation --- .../src/providers/s3/apis/downloadData.ts | 29 ++++++++++++------- .../storage/src/providers/s3/types/outputs.ts | 14 ++++++++- .../src/providers/s3/utils/constants.ts | 5 ++++ .../storage/src/providers/s3/utils/utils.ts | 29 +++++++++++++++++++ packages/storage/src/types/inputs.ts | 13 +++++---- packages/storage/src/types/outputs.ts | 2 +- 6 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 packages/storage/src/providers/s3/utils/utils.ts diff --git a/packages/storage/src/providers/s3/apis/downloadData.ts b/packages/storage/src/providers/s3/apis/downloadData.ts index 5da4ba19c6d..37318db50ea 100644 --- a/packages/storage/src/providers/s3/apis/downloadData.ts +++ b/packages/storage/src/providers/s3/apis/downloadData.ts @@ -14,6 +14,9 @@ import { logger } from '../../../utils'; import { Item } from '../types/outputs'; import { StorageDownloadDataOutput } from '../../../types'; import { DownloadDataInputKey, DownloadDataInputPath } from '../types/inputs'; +import { validateStorageOperationInput } from '../utils/utils'; +import { STORAGE_INPUT_TYPES } from '../utils/constants'; +import { StorageItem, StorageItemPath } from '../../../types/outputs'; /** * Download S3 object data to memory @@ -60,18 +63,21 @@ export const downloadData = (input: DownloadDataInput): DownloadDataOutput => { const downloadDataJob = ( - { options: downloadDataOptions, key }: DownloadDataInput, - abortSignal: AbortSignal + downloadDataInput: DownloadDataInput, + abortSignal: AbortSignal, ) => - async (): Promise> => { - + async (): Promise> => { + const { options: downloadDataOptions } = downloadDataInput; + const { inputType, objectKey } = + validateStorageOperationInput(downloadDataInput); const { bucket, keyPrefix, s3Config } = await resolveS3ConfigAndInput( Amplify, - downloadDataOptions + downloadDataOptions, ); - const finalKey = keyPrefix + key; + const finalKey = + inputType === STORAGE_INPUT_TYPES.KEY ? keyPrefix + objectKey : objectKey; - logger.debug(`download ${key} from ${finalKey}.`); + logger.debug(`download ${objectKey} from ${finalKey}.`); const { Body: body, @@ -94,10 +100,10 @@ const downloadDataJob = ...(downloadDataOptions?.bytesRange && { Range: `bytes=${downloadDataOptions.bytesRange.start}-${downloadDataOptions.bytesRange.end}`, }), - } + }, ); - return { - key: key ?? '', + + const result = { body, lastModified, size, @@ -106,4 +112,7 @@ const downloadDataJob = metadata, versionId, }; + return inputType === STORAGE_INPUT_TYPES.KEY + ? { key: finalKey, ...result } + : { path: finalKey, ...result }; }; diff --git a/packages/storage/src/providers/s3/types/outputs.ts b/packages/storage/src/providers/s3/types/outputs.ts index 532a4a455f1..4018e486cd0 100644 --- a/packages/storage/src/providers/s3/types/outputs.ts +++ b/packages/storage/src/providers/s3/types/outputs.ts @@ -9,6 +9,7 @@ import { DownloadTask, UploadTask, } from '../../../types'; +import { StorageItemPath } from '../../../types/outputs'; /** * type for S3 item. @@ -24,6 +25,17 @@ export interface Item extends StorageItem { contentType?: string; } +export interface ItemPath extends StorageItemPath { + /** + * VersionId used to reference a specific version of the object. + */ + versionId?: string; + /** + * A standard MIME type describing the format of the object data. + */ + contentType?: string; +} + /** * type for S3 list item. */ @@ -32,7 +44,7 @@ export type ListOutputItem = Omit; /** * Output type for S3 downloadData API. */ -export type DownloadDataOutput = DownloadTask>; +export type DownloadDataOutput = DownloadTask>; /** * Output type for S3 getUrl API. diff --git a/packages/storage/src/providers/s3/utils/constants.ts b/packages/storage/src/providers/s3/utils/constants.ts index 9e48b80047f..0827e19be7e 100644 --- a/packages/storage/src/providers/s3/utils/constants.ts +++ b/packages/storage/src/providers/s3/utils/constants.ts @@ -19,3 +19,8 @@ export const MAX_PARTS_COUNT = 10000; export const DEFAULT_QUEUE_SIZE = 4; export const UPLOADS_STORAGE_KEY = '__uploadInProgress'; + +export enum STORAGE_INPUT_TYPES { + PATH = 'path', + KEY = 'key' +} diff --git a/packages/storage/src/providers/s3/utils/utils.ts b/packages/storage/src/providers/s3/utils/utils.ts new file mode 100644 index 00000000000..095ab43c849 --- /dev/null +++ b/packages/storage/src/providers/s3/utils/utils.ts @@ -0,0 +1,29 @@ +import { StrictUnion } from '@aws-amplify/core/internals/utils'; +import { + StorageOperationInputKey, + StorageOperationInputPath, +} from '../../../types/inputs'; +import { STORAGE_INPUT_TYPES } from './constants'; + +type Input = StrictUnion; + +const isInputWithKey = (input: Input): input is StorageOperationInputKey => { + return input.key !== undefined; +}; + +const isInputWithPath = ( + input: Input, +): input is StorageOperationInputPath => { + return input.path !== undefined; +}; + +export const validateStorageOperationInput = (input: Input) => { + if (isInputWithPath(input)) { + const { path } = input; + return { inputType: STORAGE_INPUT_TYPES.PATH, objectKey: typeof path === 'string' ? path : path('') }; + } else if (isInputWithKey(input)) { + return { inputType: STORAGE_INPUT_TYPES.KEY, objectKey: input.key }; + } else { + throw new Error('invalid input'); + } +} diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index ecdf1ea2624..4edc8be0511 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -7,15 +7,18 @@ import { StorageListPaginateOptions, } from './options'; +export type StorageOperationInputKey = {key: string} +export type StorageOperationInputPath = {path: string | ((id: string) => string);} + export type StorageOperationInput = { key: string; options?: Options; }; -export type StorageOperationInputPath = { - path: string | ((id: string) => string); - options?: Options; -}; +// export type StorageOperationInputPath = { +// path: string | ((id: string) => string); +// options?: Options; +// }; export type StorageGetPropertiesInput = StorageOperationInput; @@ -39,7 +42,7 @@ export type StorageDownloadDataInput = StorageOperationInput; export type StorageDownloadDataInputPath = - StorageOperationInputPath; + StorageOperationInputPath & {options: Options}; export type StorageUploadDataInput = StorageOperationInput & { diff --git a/packages/storage/src/types/outputs.ts b/packages/storage/src/types/outputs.ts index 375cbd5a213..fee002151a7 100644 --- a/packages/storage/src/types/outputs.ts +++ b/packages/storage/src/types/outputs.ts @@ -53,7 +53,7 @@ export type StorageItemPath = { }; -export type StorageDownloadDataOutput = T & { +export type StorageDownloadDataOutput = Item & { body: ResponseBodyMixin; }; From e33051ce4ca8e5811ccdc2ee5d2a6a0ebf35d034 Mon Sep 17 00:00:00 2001 From: ashika112 Date: Tue, 27 Feb 2024 14:39:26 -0800 Subject: [PATCH 09/11] fix output type --- .../src/providers/s3/apis/downloadData.ts | 21 ++++++++++++++----- .../storage/src/providers/s3/types/outputs.ts | 4 +++- packages/storage/src/types/inputs.ts | 2 +- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/downloadData.ts b/packages/storage/src/providers/s3/apis/downloadData.ts index 37318db50ea..a1b06dd39e1 100644 --- a/packages/storage/src/providers/s3/apis/downloadData.ts +++ b/packages/storage/src/providers/s3/apis/downloadData.ts @@ -11,7 +11,7 @@ import { createDownloadTask } from '../utils'; import { getObject } from '../utils/client'; import { getStorageUserAgentValue } from '../utils/userAgent'; import { logger } from '../../../utils'; -import { Item } from '../types/outputs'; +import { DownloadDataOutputPath } from '../types/outputs'; import { StorageDownloadDataOutput } from '../../../types'; import { DownloadDataInputKey, DownloadDataInputPath } from '../types/inputs'; import { validateStorageOperationInput } from '../utils/utils'; @@ -49,16 +49,25 @@ import { StorageItem, StorageItemPath } from '../../../types/outputs'; *``` */ -export const downloadData = (input: DownloadDataInput): DownloadDataOutput => { +interface DownloadData { + (input: DownloadDataInputPath): DownloadDataOutputPath; + (input: DownloadDataInputKey): DownloadDataOutput; +} + +export const downloadData: DownloadData = < + Output extends DownloadDataOutput | DownloadDataOutputPath, +>( + input: DownloadDataInput, +): Output => { const abortController = new AbortController(); const downloadTask = createDownloadTask({ - job: downloadDataJob(input, abortController.signal), + job: downloadDataJob(input as DownloadDataInputKey, abortController.signal), onCancel: (message?: string) => { abortController.abort(message); }, }); - return downloadTask; + return downloadTask as Output; }; const downloadDataJob = @@ -66,7 +75,9 @@ const downloadDataJob = downloadDataInput: DownloadDataInput, abortSignal: AbortSignal, ) => - async (): Promise> => { + async (): Promise< + StorageDownloadDataOutput + > => { const { options: downloadDataOptions } = downloadDataInput; const { inputType, objectKey } = validateStorageOperationInput(downloadDataInput); diff --git a/packages/storage/src/providers/s3/types/outputs.ts b/packages/storage/src/providers/s3/types/outputs.ts index 4018e486cd0..9b6f7bf18aa 100644 --- a/packages/storage/src/providers/s3/types/outputs.ts +++ b/packages/storage/src/providers/s3/types/outputs.ts @@ -44,7 +44,9 @@ export type ListOutputItem = Omit; /** * Output type for S3 downloadData API. */ -export type DownloadDataOutput = DownloadTask>; +export type DownloadDataOutput = DownloadTask>; +export type DownloadDataOutputPath = DownloadTask>; + /** * Output type for S3 getUrl API. diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index 4edc8be0511..a7f6df8b0bb 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -42,7 +42,7 @@ export type StorageDownloadDataInput = StorageOperationInput; export type StorageDownloadDataInputPath = - StorageOperationInputPath & {options: Options}; + StorageOperationInputPath & {options?: Options}; export type StorageUploadDataInput = StorageOperationInput & { From b5856054928676208890b84e4a32e3aca78fba1b Mon Sep 17 00:00:00 2001 From: ashika112 Date: Wed, 28 Feb 2024 17:00:23 -0800 Subject: [PATCH 10/11] path dynamic construction --- packages/storage/src/providers/s3/apis/downloadData.ts | 8 +++----- .../src/providers/s3/utils/resolveS3ConfigAndInput.ts | 6 +++++- packages/storage/src/providers/s3/utils/utils.ts | 4 ++-- packages/storage/src/types/inputs.ts | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/downloadData.ts b/packages/storage/src/providers/s3/apis/downloadData.ts index a1b06dd39e1..a874207d60c 100644 --- a/packages/storage/src/providers/s3/apis/downloadData.ts +++ b/packages/storage/src/providers/s3/apis/downloadData.ts @@ -79,12 +79,10 @@ const downloadDataJob = StorageDownloadDataOutput > => { const { options: downloadDataOptions } = downloadDataInput; + const { bucket, keyPrefix, s3Config, identityId, userSub } = + await resolveS3ConfigAndInput(Amplify, downloadDataOptions); const { inputType, objectKey } = - validateStorageOperationInput(downloadDataInput); - const { bucket, keyPrefix, s3Config } = await resolveS3ConfigAndInput( - Amplify, - downloadDataOptions, - ); + validateStorageOperationInput(downloadDataInput, identityId, userSub); const finalKey = inputType === STORAGE_INPUT_TYPES.KEY ? keyPrefix + objectKey : objectKey; diff --git a/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts b/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts index cf32138b86e..ac8073b03ce 100644 --- a/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts +++ b/packages/storage/src/providers/s3/utils/resolveS3ConfigAndInput.ts @@ -20,6 +20,8 @@ type ResolvedS3ConfigAndInput = { bucket: string; keyPrefix: string; isObjectLockEnabled?: boolean; + identityId?: string; + userSub?: string; }; /** @@ -38,7 +40,7 @@ export const resolveS3ConfigAndInput = async ( apiOptions?: S3ApiOptions ): Promise => { // identityId is always cached in memory if forceRefresh is not set. So we can safely make calls here. - const { credentials, identityId } = await amplify.Auth.fetchAuthSession({ + const { credentials, identityId, userSub } = await amplify.Auth.fetchAuthSession({ forceRefresh: false, }); assertValidationError( @@ -82,6 +84,8 @@ export const resolveS3ConfigAndInput = async ( }, bucket, keyPrefix, + identityId, + userSub, isObjectLockEnabled, }; }; diff --git a/packages/storage/src/providers/s3/utils/utils.ts b/packages/storage/src/providers/s3/utils/utils.ts index 095ab43c849..bdc5686d9f3 100644 --- a/packages/storage/src/providers/s3/utils/utils.ts +++ b/packages/storage/src/providers/s3/utils/utils.ts @@ -17,10 +17,10 @@ const isInputWithPath = ( return input.path !== undefined; }; -export const validateStorageOperationInput = (input: Input) => { +export const validateStorageOperationInput = (input: Input, identityId: string = '', userSub: string= '') => { if (isInputWithPath(input)) { const { path } = input; - return { inputType: STORAGE_INPUT_TYPES.PATH, objectKey: typeof path === 'string' ? path : path('') }; + return { inputType: STORAGE_INPUT_TYPES.PATH, objectKey: typeof path === 'string' ? path : path({identityId, userSub}) }; } else if (isInputWithKey(input)) { return { inputType: STORAGE_INPUT_TYPES.KEY, objectKey: input.key }; } else { diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index a7f6df8b0bb..f8ae0de3eda 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -8,7 +8,7 @@ import { } from './options'; export type StorageOperationInputKey = {key: string} -export type StorageOperationInputPath = {path: string | ((id: string) => string);} +export type StorageOperationInputPath = {path: string | (({identityId, userSub}: {identityId?: string, userSub?: string}) => string);} export type StorageOperationInput = { key: string; From c4934ddfd47fb57b9a51de4fe72aed3dbf443e9d Mon Sep 17 00:00:00 2001 From: ashika112 Date: Thu, 29 Feb 2024 00:52:57 -0800 Subject: [PATCH 11/11] refine upload and download --- .../src/providers/s3/apis/downloadData.ts | 2 +- .../src/providers/s3/apis/uploadData/index.ts | 10 +++++-- .../s3/apis/uploadData/putObjectJob.ts | 29 ++++++++++++++----- .../src/providers/s3/apis/uploadData/utils.ts | 2 +- .../storage/src/providers/s3/types/outputs.ts | 17 ++--------- .../storage/src/providers/s3/utils/utils.ts | 21 ++++++++++---- 6 files changed, 48 insertions(+), 33 deletions(-) diff --git a/packages/storage/src/providers/s3/apis/downloadData.ts b/packages/storage/src/providers/s3/apis/downloadData.ts index bc78211666b..423a8e5834d 100644 --- a/packages/storage/src/providers/s3/apis/downloadData.ts +++ b/packages/storage/src/providers/s3/apis/downloadData.ts @@ -126,6 +126,6 @@ const downloadDataJob = }; return inputType === STORAGE_INPUT_TYPES.KEY - ? { key: finalKey, ...result } + ? { key: objectKey, ...result } : { path: finalKey, ...result }; }; diff --git a/packages/storage/src/providers/s3/apis/uploadData/index.ts b/packages/storage/src/providers/s3/apis/uploadData/index.ts index d02d9898b41..6358eefb848 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/index.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/index.ts @@ -66,7 +66,11 @@ interface UploadData { (input: UploadDataInputPath): UploadDataOutputPath; } -export const uploadData: UploadData = (input: UploadDataInput): any => { +export const uploadData: UploadData = < + Output extends UploadDataOutput | UploadDataOutputPath, +>( + input: UploadDataInput, +): Output => { const { data } = input; const dataByteLength = byteLength(data); @@ -84,7 +88,7 @@ export const uploadData: UploadData = (input: UploadDataInput): any => { onCancel: (message?: string) => { abortController.abort(message); }, - }); + }) as Output; } else { const { multipartUploadJob, onPause, onResume, onCancel } = getMultipartUploadHandlers(input, dataByteLength); @@ -97,6 +101,6 @@ export const uploadData: UploadData = (input: UploadDataInput): any => { }, onPause, onResume, - }); + }) as Output; } }; diff --git a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts index be5b1294d0d..1531ca61f83 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/putObjectJob.ts @@ -9,8 +9,8 @@ import { Item as S3Item, ItemPath as S3ItemPath } from '../../types/outputs'; import { putObject } from '../../utils/client'; import { getStorageUserAgentValue } from '../../utils/userAgent'; import { UploadDataInput } from '../../types/inputs'; - -import { validateUploadInput } from './utils'; +import { validateStorageOperationInput } from '../../utils/utils'; +import { STORAGE_INPUT_TYPES } from '../../utils/constants'; /** * Get a function the returns a promise to call putObject API to S3. @@ -26,10 +26,23 @@ export const putObjectJob = async (): Promise => { const { options: uploadDataOptions, data } = uploadInput; - const { bucket, keyPrefix, s3Config, isObjectLockEnabled } = - await resolveS3ConfigAndInput(Amplify, uploadDataOptions); + const { + bucket, + keyPrefix, + s3Config, + isObjectLockEnabled, + identityId, + userSub, + } = await resolveS3ConfigAndInput(Amplify, uploadDataOptions); + + const { inputType, objectKey } = validateStorageOperationInput( + uploadInput, + identityId, + userSub, + ); - const { inputType, finalKey } = validateUploadInput(uploadInput, keyPrefix); + const finalKey = + inputType === STORAGE_INPUT_TYPES.KEY ? keyPrefix + objectKey : objectKey; const { contentDisposition, @@ -68,7 +81,7 @@ export const putObjectJob = size: totalLength, }; - return inputType === 'path' - ? { ...result, path: finalKey } - : { ...result, key: finalKey }; + return inputType === STORAGE_INPUT_TYPES.KEY + ? { key: objectKey, ...result } + : { path: finalKey, ...result }; }; diff --git a/packages/storage/src/providers/s3/apis/uploadData/utils.ts b/packages/storage/src/providers/s3/apis/uploadData/utils.ts index 0c25ac1fcfd..278d6a0ef09 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/utils.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/utils.ts @@ -20,7 +20,7 @@ export const validateUploadInput = ( let finalKey; if (isInputWithPath(uploadInput)) { const { path } = uploadInput; - finalKey = typeof path === 'string' ? path : path(''); + finalKey = typeof path === 'string' ? path : path({}); return { inputType: 'path', finalKey }; } else if (isInputWithKey(uploadInput)) { diff --git a/packages/storage/src/providers/s3/types/outputs.ts b/packages/storage/src/providers/s3/types/outputs.ts index 01b6b571be5..7215245af42 100644 --- a/packages/storage/src/providers/s3/types/outputs.ts +++ b/packages/storage/src/providers/s3/types/outputs.ts @@ -34,18 +34,6 @@ export interface ItemPath extends StorageItemPath { */ contentType?: string; } - -export interface ItemPath extends StorageItemPath { - /** - * VersionId used to reference a specific version of the object. - */ - versionId?: string; - /** - * A standard MIME type describing the format of the object data. - */ - contentType?: string; -} - /** * type for S3 list item. */ @@ -55,8 +43,9 @@ export type ListOutputItem = Omit; * Output type for S3 downloadData API. */ export type DownloadDataOutput = DownloadTask>; -export type DownloadDataOutputPath = DownloadTask>; - +export type DownloadDataOutputPath = DownloadTask< + StorageDownloadDataOutput +>; /** * Output type for S3 getUrl API. diff --git a/packages/storage/src/providers/s3/utils/utils.ts b/packages/storage/src/providers/s3/utils/utils.ts index bdc5686d9f3..dda9c9144c3 100644 --- a/packages/storage/src/providers/s3/utils/utils.ts +++ b/packages/storage/src/providers/s3/utils/utils.ts @@ -1,8 +1,10 @@ import { StrictUnion } from '@aws-amplify/core/internals/utils'; + import { StorageOperationInputKey, StorageOperationInputPath, } from '../../../types/inputs'; + import { STORAGE_INPUT_TYPES } from './constants'; type Input = StrictUnion; @@ -11,19 +13,26 @@ const isInputWithKey = (input: Input): input is StorageOperationInputKey => { return input.key !== undefined; }; -const isInputWithPath = ( - input: Input, -): input is StorageOperationInputPath => { +const isInputWithPath = (input: Input): input is StorageOperationInputPath => { return input.path !== undefined; }; -export const validateStorageOperationInput = (input: Input, identityId: string = '', userSub: string= '') => { +export const validateStorageOperationInput = ( + input: Input, + identityId = '', + userSub = '', +) => { if (isInputWithPath(input)) { const { path } = input; - return { inputType: STORAGE_INPUT_TYPES.PATH, objectKey: typeof path === 'string' ? path : path({identityId, userSub}) }; + + return { + inputType: STORAGE_INPUT_TYPES.PATH, + objectKey: + typeof path === 'string' ? path : path({ identityId, userSub }), + }; } else if (isInputWithKey(input)) { return { inputType: STORAGE_INPUT_TYPES.KEY, objectKey: input.key }; } else { throw new Error('invalid input'); } -} +};