diff --git a/packages/predictions/package.json b/packages/predictions/package.json index 48e1871fa6e..e3942e86c97 100644 --- a/packages/predictions/package.json +++ b/packages/predictions/package.json @@ -75,7 +75,7 @@ "name": "Predictions (Identify provider)", "path": "./lib-esm/index.js", "import": "{ Amplify, Predictions, AmazonAIIdentifyPredictionsProvider }", - "limit": "105 kB" + "limit": "104.5 kB" }, { "name": "Predictions (Interpret provider)", diff --git a/packages/storage/__tests__/Storage-unit-test.ts b/packages/storage/__tests__/Storage-unit-test.ts index 1ece4ee6f1c..3ad93258fea 100644 --- a/packages/storage/__tests__/Storage-unit-test.ts +++ b/packages/storage/__tests__/Storage-unit-test.ts @@ -44,10 +44,6 @@ class TestCustomProvider implements StorageProvider { return Promise.resolve({ newKey: 'get' }); } - getProperties(key: string, options?: CustomProviderConfig) { - return Promise.resolve({ newKey: 'getProperties' }); - } - put(key: string, object: any, config: CustomProviderConfig) { return Promise.resolve({ newKey: 'put' }); } @@ -618,76 +614,6 @@ describe('Storage', () => { }); }); - describe('getProperties test', () => { - let storage: StorageClass; - let provider: StorageProvider; - let getPropertiesSpy: jest.SpyInstance; - - beforeEach(() => { - storage = new StorageClass(); - provider = new AWSStorageProvider(); - storage.addPluggable(provider); - storage.configure(options); - getPropertiesSpy = jest - .spyOn(AWSStorageProvider.prototype, 'getProperties') - .mockImplementation(() => - Promise.resolve({ - contentType: 'text/plain', - contentLength: 100, - eTag: 'etag', - lastModified: new Date('20 Oct 2023'), - metadata: { key: '' }, - }) - ); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('with default S3 provider', () => { - test('get properties of object successfully', async () => { - const result = await storage.getProperties('key'); - expect(getPropertiesSpy).toBeCalled(); - expect(result).toEqual({ - contentType: 'text/plain', - contentLength: 100, - eTag: 'etag', - lastModified: new Date('20 Oct 2023'), - metadata: { key: '' }, - }); - getPropertiesSpy.mockClear(); - }); - - test('get properties of object with available config', async () => { - await storage.getProperties('key', { - SSECustomerAlgorithm: 'aes256', - SSECustomerKey: 'key', - SSECustomerKeyMD5: 'md5', - }); - }); - }); - - test('get properties without provider', async () => { - const storage = new StorageClass(); - try { - await storage.getProperties('key'); - } catch (err) { - expect(err).toEqual(new Error('No plugin found with providerName')); - } - }); - - test('get properties with custom provider should work with no generic type provided', async () => { - const customProvider = new TestCustomProvider(); - const customProviderGetSpy = jest.spyOn(customProvider, 'getProperties'); - storage.addPluggable(customProvider); - await storage.getProperties('key', { - provider: 'customProvider', - }); - expect(customProviderGetSpy).toBeCalled(); - }); - }); - describe('put test', () => { let storage: StorageClass; let provider: StorageProvider; diff --git a/packages/storage/__tests__/providers/AWSS3Provider-unit-test.ts b/packages/storage/__tests__/providers/AWSS3Provider-unit-test.ts index 500be5212c3..342c8abdb08 100644 --- a/packages/storage/__tests__/providers/AWSS3Provider-unit-test.ts +++ b/packages/storage/__tests__/providers/AWSS3Provider-unit-test.ts @@ -8,7 +8,6 @@ import { ListObjectsV2Command, CreateMultipartUploadCommand, UploadPartCommand, - HeadObjectCommand, } from '@aws-sdk/client-s3'; import { S3RequestPresigner } from '@aws-sdk/s3-request-presigner'; @@ -53,14 +52,6 @@ S3Client.prototype.send = jest.fn(async command => { Contents: [resultObj], IsTruncated: false, }; - } else if (command instanceof HeadObjectCommand) { - return { - ContentLength: '100', - ContentType: 'text/plain', - ETag: 'etag', - LastModified: 'lastmodified', - Metadata: { key: 'value' }, - }; } return 'data'; }); @@ -528,7 +519,6 @@ describe('StorageProvider test', () => { return Promise.resolve(credentials); }); }); - test('get existing object with validateObjectExistence option', async () => { expect.assertions(5); const options_with_validateObjectExistence = Object.assign( @@ -566,6 +556,11 @@ describe('StorageProvider test', () => { test('get non-existing object with validateObjectExistence option', async () => { expect.assertions(2); + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({}); + }); + }); const dispatchSpy = jest.spyOn(StorageUtils, 'dispatchStorageEvent'); jest .spyOn(S3Client.prototype, 'send') @@ -591,63 +586,6 @@ describe('StorageProvider test', () => { }); }); - describe('getProperties test', () => { - beforeEach(() => { - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - }); - - test('getProperties successfully', async () => { - expect.assertions(4); - const spyon = jest.spyOn(S3Client.prototype, 'send'); - const dispatchSpy = jest.spyOn(StorageUtils, 'dispatchStorageEvent'); - const metadata = { key: 'value' }; - expect(await storage.getProperties('key')).toEqual({ - contentLength: '100', - contentType: 'text/plain', - eTag: 'etag', - lastModified: 'lastmodified', - metadata, - }); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toBeCalledWith( - false, - 'getProperties', - { method: 'getProperties', result: 'success' }, - null, - 'getProperties successful for key' - ); - expect(spyon.mock.calls[0][0].input).toEqual({ - Bucket: 'bucket', - Key: 'public/key', - }); - spyon.mockClear(); - }); - - test('get properties of non-existing object', async () => { - expect.assertions(2); - const dispatchSpy = jest.spyOn(StorageUtils, 'dispatchStorageEvent'); - jest - .spyOn(S3Client.prototype, 'send') - .mockImplementationOnce(async params => { - throw { $metadata: { httpStatusCode: 404 }, name: 'NotFound' }; - }); - try { - await storage.getProperties('invalid_key'); - } catch (error) { - expect(error.$metadata.httpStatusCode).toBe(404); - expect(dispatchSpy).toBeCalledWith( - false, - 'getProperties', - { method: 'getProperties', result: 'failed' }, - null, - 'invalid_key not found' - ); - } - }); - }); - describe('put test', () => { afterEach(() => { jest.clearAllMocks(); diff --git a/packages/storage/package.json b/packages/storage/package.json index 9d771a6b5ac..f19e981acfc 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -60,7 +60,7 @@ "name": "Storage (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Storage }", - "limit": "87.02 kB" + "limit": "87 kB" } ], "jest": { diff --git a/packages/storage/src/Storage.ts b/packages/storage/src/Storage.ts index e9c570ade9b..5653652e05a 100644 --- a/packages/storage/src/Storage.ts +++ b/packages/storage/src/Storage.ts @@ -23,8 +23,6 @@ import { StorageListOutput, StorageCopyOutput, UploadTask, - StorageGetPropertiesConfig, - StorageGetPropertiesOutput, } from './types'; import axios, { CancelTokenSource } from 'axios'; import { PutObjectCommandInput } from '@aws-sdk/client-s3'; @@ -248,22 +246,22 @@ export class Storage { config?: StorageCopyConfig ): StorageCopyOutput { const provider = config?.provider || DEFAULT_PROVIDER; - const plugin = this._pluggables.find( + const prov = this._pluggables.find( pluggable => pluggable.getProviderName() === provider ); - if (plugin === undefined) { + if (prov === undefined) { logger.debug('No plugin found with providerName', provider); return Promise.reject( 'No plugin found in Storage for the provider' ) as StorageCopyOutput; } const cancelTokenSource = this.getCancellableTokenSource(); - if (typeof plugin.copy !== 'function') { + if (typeof prov.copy !== 'function') { return Promise.reject( - `.copy is not implemented on provider ${plugin.getProviderName()}` + `.copy is not implemented on provider ${prov.getProviderName()}` ) as StorageCopyOutput; } - const responsePromise = plugin.copy(src, dest, { + const responsePromise = prov.copy(src, dest, { ...config, cancelTokenSource, }); @@ -287,17 +285,17 @@ export class Storage { T extends StorageProvider | { [key: string]: any; download?: boolean } >(key: string, config?: StorageGetConfig): StorageGetOutput { const provider = config?.provider || DEFAULT_PROVIDER; - const plugin = this._pluggables.find( + const prov = this._pluggables.find( pluggable => pluggable.getProviderName() === provider ); - if (plugin === undefined) { + if (prov === undefined) { logger.debug('No plugin found with providerName', provider); return Promise.reject( 'No plugin found in Storage for the provider' ) as StorageGetOutput; } const cancelTokenSource = this.getCancellableTokenSource(); - const responsePromise = plugin.get(key, { + const responsePromise = prov.get(key, { ...config, cancelTokenSource, }); @@ -309,31 +307,6 @@ export class Storage { return axios.isCancel(error); } - public getProperties( - key: string, - config?: StorageGetPropertiesConfig - ): StorageGetPropertiesOutput { - const provider = config?.provider || DEFAULT_PROVIDER; - const plugin = this._pluggables.find( - pluggable => pluggable.getProviderName() === provider - ); - if (plugin === undefined) { - logger.debug('No plugin found with providerName', provider); - throw new Error('No plugin found with providerName'); - } - const cancelTokenSource = this.getCancellableTokenSource(); - - if (typeof plugin.getProperties !== 'function') { - throw new Error( - `.getProperties is not implemented on provider ${plugin.getProviderName()}` - ); - } - const responsePromise = plugin.getProperties(key, { - ...config, - }); - this.updateRequestToBeCancellable(responsePromise, cancelTokenSource); - return responsePromise as StorageGetPropertiesOutput; - } /** * Put a file in storage bucket specified to configure method * @param key - key of the object @@ -353,17 +326,17 @@ export class Storage { config?: StoragePutConfig ): StoragePutOutput { const provider = config?.provider || DEFAULT_PROVIDER; - const plugin = this._pluggables.find( + const prov = this._pluggables.find( pluggable => pluggable.getProviderName() === provider ); - if (plugin === undefined) { + if (prov === undefined) { logger.debug('No plugin found with providerName', provider); return Promise.reject( 'No plugin found in Storage for the provider' ) as StoragePutOutput; } const cancelTokenSource = this.getCancellableTokenSource(); - const response = plugin.put(key, object, { + const response = prov.put(key, object, { ...config, cancelTokenSource, }); @@ -388,16 +361,16 @@ export class Storage { config?: StorageRemoveConfig ): StorageRemoveOutput { const provider = config?.provider || DEFAULT_PROVIDER; - const plugin = this._pluggables.find( + const prov = this._pluggables.find( pluggable => pluggable.getProviderName() === provider ); - if (plugin === undefined) { + if (prov === undefined) { logger.debug('No plugin found with providerName', provider); return Promise.reject( 'No plugin found in Storage for the provider' ) as StorageRemoveOutput; } - return plugin.remove(key, config) as StorageRemoveOutput; + return prov.remove(key, config) as StorageRemoveOutput; } /** @@ -415,16 +388,16 @@ export class Storage { config?: StorageListConfig ): StorageListOutput { const provider = config?.provider || DEFAULT_PROVIDER; - const plugin = this._pluggables.find( + const prov = this._pluggables.find( pluggable => pluggable.getProviderName() === provider ); - if (plugin === undefined) { + if (prov === undefined) { logger.debug('No plugin found with providerName', provider); return Promise.reject( 'No plugin found in Storage for the provider' ) as StorageListOutput; } - return plugin.list(path, config) as StorageListOutput; + return prov.list(path, config) as StorageListOutput; } } diff --git a/packages/storage/src/providers/AWSS3Provider.ts b/packages/storage/src/providers/AWSS3Provider.ts index be16d40f6a3..f92268cd29b 100644 --- a/packages/storage/src/providers/AWSS3Provider.ts +++ b/packages/storage/src/providers/AWSS3Provider.ts @@ -21,7 +21,6 @@ import { GetObjectCommandInput, ListObjectsV2Request, HeadObjectCommand, - HeadObjectCommandInput, } from '@aws-sdk/client-s3'; import { formatUrl } from '@aws-sdk/util-format-url'; import { createRequest } from '@aws-sdk/util-create-request'; @@ -50,8 +49,6 @@ import { UploadTask, S3ClientOptions, S3ProviderListOutput, - S3ProviderGetPropertiesOutput, - S3ProviderGetPropertiesConfig, } from '../types'; import { StorageErrorStrings } from '../common/StorageErrorStrings'; import { dispatchStorageEvent } from '../common/StorageUtils'; @@ -452,7 +449,7 @@ export class AWSS3Provider implements StorageProvider { } if (validateObjectExistence) { const headObjectCommand = new HeadObjectCommand(params); - + try { await s3.send(headObjectCommand); } catch (error) { @@ -501,87 +498,6 @@ export class AWSS3Provider implements StorageProvider { } } - /** - * Get Properties of the object - * - * @param {string} key - key of the object - * @param {S3ProviderGetPropertiesConfig} [config] - Optional configuration for the underlying S3 command - * @return {Promise} - A promise resolves to contentType, - * contentLength, eTag, lastModified, metadata - */ - public async getProperties( - key: string, - config?: S3ProviderGetPropertiesConfig - ): Promise { - const credentialsOK = await this._ensureCredentials(); - if (!credentialsOK || !this._isWithCredentials(this._config)) { - throw new Error(StorageErrorStrings.NO_CREDENTIALS); - } - const opt = Object.assign({}, this._config, config); - const { - bucket, - track = false, - SSECustomerAlgorithm, - SSECustomerKey, - SSECustomerKeyMD5, - } = opt; - const prefix = this._prefix(opt); - const final_key = prefix + key; - const emitter = new events.EventEmitter(); - const s3 = this._createNewS3Client(opt, emitter); - logger.debug(`getProperties ${key} from ${final_key}`); - - const params: HeadObjectCommandInput = { - Bucket: bucket, - Key: final_key, - }; - - if (SSECustomerAlgorithm) { - params.SSECustomerAlgorithm = SSECustomerAlgorithm; - } - if (SSECustomerKey) { - params.SSECustomerKey = SSECustomerKey; - } - if (SSECustomerKeyMD5) { - params.SSECustomerKeyMD5 = SSECustomerKeyMD5; - } - // See: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/classes/headobjectcommand.html - - const headObjectCommand = new HeadObjectCommand(params); - try { - const response = await s3.send(headObjectCommand); - const getPropertiesResponse: S3ProviderGetPropertiesOutput = { - contentLength: response.ContentLength, - contentType: response.ContentType, - eTag: response.ETag, - lastModified: response.LastModified, - metadata: response.Metadata, - }; - dispatchStorageEvent( - track, - 'getProperties', - { method: 'getProperties', result: 'success' }, - null, - `getProperties successful for ${key}` - ); - return getPropertiesResponse; - } catch (error) { - if (error.$metadata.httpStatusCode === 404) { - dispatchStorageEvent( - track, - 'getProperties', - { - method: 'getProperties', - result: 'failed', - }, - null, - `${key} not found` - ); - } - throw error; - } - } - /** * Put a file in S3 bucket specified to configure method * @param key - key of the object diff --git a/packages/storage/src/types/AWSS3Provider.ts b/packages/storage/src/types/AWSS3Provider.ts index 8663f9a7c64..046b128fa53 100644 --- a/packages/storage/src/types/AWSS3Provider.ts +++ b/packages/storage/src/types/AWSS3Provider.ts @@ -5,7 +5,6 @@ import { CopyObjectRequest, _Object, DeleteObjectCommandOutput, - HeadObjectRequest, } from '@aws-sdk/client-s3'; import { StorageOptions, StorageAccessLevel } from './Storage'; import { @@ -52,12 +51,6 @@ export type S3ProviderGetConfig = CommonStorageOptions & { validateObjectExistence?: boolean; }; -export type S3ProviderGetPropertiesConfig = CommonStorageOptions & { - SSECustomerAlgorithm?: HeadObjectRequest['SSECustomerAlgorithm']; - SSECustomerKey?: HeadObjectRequest['SSECustomerKey']; - SSECustomerKeyMD5?: HeadObjectRequest['SSECustomerKeyMD5']; -}; - export type S3ProviderGetOuput = T extends { download: true } ? GetObjectCommandOutput : string; @@ -180,14 +173,6 @@ export type S3ProviderCopyOutput = { key: string; }; -export type S3ProviderGetPropertiesOutput = { - contentType: string; - contentLength: number; - eTag: string; - lastModified: Date; - metadata: Record; -}; - export type PutResult = { key: string; }; diff --git a/packages/storage/src/types/Provider.ts b/packages/storage/src/types/Provider.ts index 74c8329092c..913548f8873 100644 --- a/packages/storage/src/types/Provider.ts +++ b/packages/storage/src/types/Provider.ts @@ -20,9 +20,6 @@ export interface StorageProvider { // get object/pre-signed url from storage get(key: string, options?): Promise; - // get properties of object - getProperties?(key: string, options?): Promise; - // upload storage object put(key: string, object, options?): Promise | UploadTask; @@ -55,10 +52,4 @@ export interface StorageProviderWithCopy extends StorageProvider { ): Promise; } -export type StorageProviderApi = - | 'copy' - | 'get' - | 'put' - | 'remove' - | 'list' - | 'getProperties'; +export type StorageProviderApi = 'copy' | 'get' | 'put' | 'remove' | 'list'; diff --git a/packages/storage/src/types/Storage.ts b/packages/storage/src/types/Storage.ts index 344871576ae..106739e9597 100644 --- a/packages/storage/src/types/Storage.ts +++ b/packages/storage/src/types/Storage.ts @@ -15,7 +15,6 @@ import { S3ProviderListOutput, S3ProviderCopyOutput, S3ProviderPutOutput, - S3ProviderGetPropertiesOutput, } from '../'; type Tail = ((...t: T) => void) extends ( @@ -88,14 +87,6 @@ export type StorageGetConfig> = T >; -export type StorageGetPropertiesConfig> = - T extends StorageProvider - ? StorageOperationConfig - : StorageOperationConfigMap< - StorageOperationConfig, - T - >; - export type StoragePutConfig> = T extends StorageProvider ? StorageOperationConfig @@ -177,12 +168,6 @@ export type StorageCopyOutput = PickProviderOutput< 'copy' >; -export type StorageGetPropertiesOutput = PickProviderOutput< - Promise, - T, - 'getProperties' ->; - /** * Utility type to allow custom provider to use any config keys, if provider is set to AWSS3 then it should use * AWSS3Provider's config.