diff --git a/packages/amplify-e2e-core/package.json b/packages/amplify-e2e-core/package.json index e3921f86e42..a38dff35cbe 100644 --- a/packages/amplify-e2e-core/package.json +++ b/packages/amplify-e2e-core/package.json @@ -23,12 +23,31 @@ }, "dependencies": { "@aws-amplify/amplify-cli-core": "4.4.2", + "@aws-sdk/client-amplifybackend": "3.624.0", + "@aws-sdk/client-amplifyuibuilder": "3.624.0", + "@aws-sdk/client-appsync": "3.624.0", + "@aws-sdk/client-cloudformation": "3.624.0", + "@aws-sdk/client-cloudwatch-events": "3.624.0", + "@aws-sdk/client-cloudwatch-logs": "3.624.0", + "@aws-sdk/client-cognito-identity": "3.624.0", + "@aws-sdk/client-cognito-identity-provider": "3.624.0", + "@aws-sdk/client-dynamodb": "3.624.0", + "@aws-sdk/client-iam": "3.624.0", + "@aws-sdk/client-kinesis": "3.624.0", + "@aws-sdk/client-lambda": "3.624.0", + "@aws-sdk/client-lex-model-building-service": "3.624.0", + "@aws-sdk/client-location": "3.624.0", + "@aws-sdk/client-pinpoint": "3.624.0", + "@aws-sdk/client-rekognition": "3.624.0", + "@aws-sdk/client-s3": "3.624.0", + "@aws-sdk/client-ssm": "3.624.0", "@aws-sdk/client-sts": "3.624.0", "@aws-sdk/credential-providers": "3.624.0", + "@aws-sdk/lib-dynamodb": "3.624.0", "amplify-headless-interface": "1.17.8", "aws-amplify": "^5.3.16", "aws-appsync": "^4.1.1", - "aws-sdk": "^2.1464.0", + "aws-sdk": "^2.1692.0", "chalk": "^4.1.1", "dotenv": "^8.2.0", "execa": "^5.1.1", diff --git a/packages/amplify-e2e-core/src/categories/lambda-function.ts b/packages/amplify-e2e-core/src/categories/lambda-function.ts index 7dca51bcf5c..a8cf697e3e5 100644 --- a/packages/amplify-e2e-core/src/categories/lambda-function.ts +++ b/packages/amplify-e2e-core/src/categories/lambda-function.ts @@ -1,5 +1,5 @@ import { nspawn as spawn, ExecutionContext, KEY_DOWN_ARROW, getCLIPath, getProjectMeta, getBackendAmplifyMeta, invokeFunction } from '..'; -import { Lambda } from 'aws-sdk'; +import { InvokeCommandOutput } from '@aws-sdk/client-lambda'; import { singleSelect, multiSelect, moveUp, moveDown } from '../utils/selectors'; import { globSync } from 'glob'; import * as path from 'path'; @@ -636,10 +636,7 @@ export const functionMockAssert = ( }); }; -export const functionCloudInvoke = async ( - cwd: string, - settings: { funcName: string; payload: string }, -): Promise => { +export const functionCloudInvoke = async (cwd: string, settings: { funcName: string; payload: string }): Promise => { const meta = getProjectMeta(cwd); const lookupName = settings.funcName; expect(meta.function[lookupName]).toBeDefined(); @@ -647,10 +644,10 @@ export const functionCloudInvoke = async ( expect(functionName).toBeDefined(); expect(region).toBeDefined(); const result = await invokeFunction(functionName, settings.payload, region); - if (!result.$response.data) { - throw new Error('No data in lambda response'); + if (!result.Payload) { + throw new Error('No payload in lambda response'); } - return result.$response.data as Lambda.InvocationResponse; + return result; }; const getTemplateChoices = (runtime: FunctionRuntimes) => { diff --git a/packages/amplify-e2e-core/src/categories/uibuilder/myFormCheckout.component.ts b/packages/amplify-e2e-core/src/categories/uibuilder/myFormCheckout.component.ts index de159e6a93a..ff296306757 100644 --- a/packages/amplify-e2e-core/src/categories/uibuilder/myFormCheckout.component.ts +++ b/packages/amplify-e2e-core/src/categories/uibuilder/myFormCheckout.component.ts @@ -1,9 +1,9 @@ -import { AmplifyUIBuilder } from 'aws-sdk'; +import { CreateComponentData } from '@aws-sdk/client-amplifyuibuilder'; // FormCheckout used from AmplifyUIKit // Source: https://www.figma.com/community/file/1047600760128127424 -export const formCheckoutComponent: AmplifyUIBuilder.CreateComponentData = { +export const formCheckoutComponent: CreateComponentData = { name: 'FormCheckout', componentType: 'Flex', schemaVersion: '1.0', diff --git a/packages/amplify-e2e-core/src/categories/uibuilder/myIcon.component.ts b/packages/amplify-e2e-core/src/categories/uibuilder/myIcon.component.ts index 1b9f0feaa74..cf7bf9eb542 100644 --- a/packages/amplify-e2e-core/src/categories/uibuilder/myIcon.component.ts +++ b/packages/amplify-e2e-core/src/categories/uibuilder/myIcon.component.ts @@ -1,9 +1,9 @@ -import { AmplifyUIBuilder } from 'aws-sdk'; +import { CreateComponentData } from '@aws-sdk/client-amplifyuibuilder'; // MyIcon used from AmplifyUIKit // Source: https://www.figma.com/community/file/1047600760128127424 -export const myIconComponent: AmplifyUIBuilder.CreateComponentData = { +export const myIconComponent: CreateComponentData = { name: 'MyIcon', componentType: 'Icon', schemaVersion: '1.0', diff --git a/packages/amplify-e2e-core/src/utils/auth-utils.ts b/packages/amplify-e2e-core/src/utils/auth-utils.ts index 194efe18861..6ce30adc43d 100644 --- a/packages/amplify-e2e-core/src/utils/auth-utils.ts +++ b/packages/amplify-e2e-core/src/utils/auth-utils.ts @@ -1,6 +1,10 @@ import { Amplify, Auth } from 'aws-amplify'; import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import { CognitoIdentityServiceProvider } from 'aws-sdk'; +import { + CognitoIdentityProviderClient, + AdminCreateUserCommand, + AdminAddUserToGroupCommand, +} from '@aws-sdk/client-cognito-identity-provider'; import fs from 'fs-extra'; import path from 'path'; import { getAwsAndroidConfig, getAwsIOSConfig, getBackendAmplifyMeta, getCLIInputs, getProjectMeta, setCLIInputs } from './projectMeta'; @@ -19,53 +23,48 @@ export async function setupUser( region?: string, ): Promise { const cognitoClient = getConfiguredCognitoClient(region); - await cognitoClient - .adminCreateUser({ - UserPoolId: userPoolId, - UserAttributes: [{ Name: 'email', Value: 'username@amazon.com' }], - Username: username, - MessageAction: 'SUPPRESS', - TemporaryPassword: tempPassword, - }) - .promise(); + const createUserCommand = new AdminCreateUserCommand({ + UserPoolId: userPoolId, + UserAttributes: [{ Name: 'email', Value: 'username@amazon.com' }], + Username: username, + MessageAction: 'SUPPRESS', + TemporaryPassword: tempPassword, + }); + await cognitoClient.send(createUserCommand); await authenticateUser(username, tempPassword, password); if (groupName) { - await cognitoClient - .adminAddUserToGroup({ - UserPoolId: userPoolId, - Username: username, - GroupName: groupName, - }) - .promise(); + const addToGroupCommand = new AdminAddUserToGroupCommand({ + UserPoolId: userPoolId, + Username: username, + GroupName: groupName, + }); + await cognitoClient.send(addToGroupCommand); } } export async function addUserToGroup(userPoolId: string, username: string, groupName: string, region?: string): Promise { const cognitoClient = getConfiguredCognitoClient(region); - await cognitoClient - .adminAddUserToGroup({ - UserPoolId: userPoolId, - Username: username, - GroupName: groupName, - }) - .promise(); + const command = new AdminAddUserToGroupCommand({ + UserPoolId: userPoolId, + Username: username, + GroupName: groupName, + }); + await cognitoClient.send(command); } -export function getConfiguredCognitoClient(region = process.env.CLI_REGION): CognitoIdentityServiceProvider { - const cognitoClient = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-19', region }); - +export function getConfiguredCognitoClient(region = process.env.CLI_REGION): CognitoIdentityProviderClient { const awsconfig = { - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, - sessionToken: process.env.AWS_SESSION_TOKEN, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + sessionToken: process.env.AWS_SESSION_TOKEN, + }, region, }; - cognitoClient.config.update(awsconfig); - - return cognitoClient; + return new CognitoIdentityProviderClient(awsconfig); } export function getConfiguredAppsyncClientCognitoAuth(url: string, region: string, user: any) { diff --git a/packages/amplify-e2e-core/src/utils/pinpoint.ts b/packages/amplify-e2e-core/src/utils/pinpoint.ts index eb40a64d1e9..742ad2959c1 100644 --- a/packages/amplify-e2e-core/src/utils/pinpoint.ts +++ b/packages/amplify-e2e-core/src/utils/pinpoint.ts @@ -1,4 +1,4 @@ -import { Pinpoint } from 'aws-sdk'; +import { PinpointClient, GetAppCommand } from '@aws-sdk/client-pinpoint'; import { EOL } from 'os'; import { getCLIPath, nspawn as spawn, singleSelect, amplifyRegions, addCircleCITags, KEY_DOWN_ARROW } from '..'; @@ -25,24 +25,25 @@ const settings = { export async function pinpointAppExist(pinpointProjectId: string, region: string): Promise { let result = false; - const pinpointClient = new Pinpoint({ - accessKeyId: settings.accessKeyId, - secretAccessKey: settings.secretAccessKey, - sessionToken: settings.sessionToken, + const pinpointClient = new PinpointClient({ + credentials: { + accessKeyId: settings.accessKeyId, + secretAccessKey: settings.secretAccessKey, + sessionToken: settings.sessionToken, + }, region, }); try { - const response = await pinpointClient - .getApp({ - ApplicationId: pinpointProjectId, - }) - .promise(); - if (response.ApplicationResponse.Id === pinpointProjectId) { + const command = new GetAppCommand({ + ApplicationId: pinpointProjectId, + }); + const response = await pinpointClient.send(command); + if (response.ApplicationResponse?.Id === pinpointProjectId) { result = true; } } catch (err) { - if (err.code === 'NotFoundException') { + if (err.name === 'NotFoundException') { result = false; } else { throw err; diff --git a/packages/amplify-e2e-core/src/utils/sdk-calls.ts b/packages/amplify-e2e-core/src/utils/sdk-calls.ts index 5e0f5f0acf4..8b481506b78 100644 --- a/packages/amplify-e2e-core/src/utils/sdk-calls.ts +++ b/packages/amplify-e2e-core/src/utils/sdk-calls.ts @@ -1,49 +1,85 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable no-return-await */ +import { DynamoDBClient, DescribeTableCommand, DeleteTableCommand } from '@aws-sdk/client-dynamodb'; +import { DynamoDBDocumentClient, PutCommand, ScanCommand } from '@aws-sdk/lib-dynamodb'; import { - DynamoDB, - S3, - CognitoIdentity, - CognitoIdentityServiceProvider, - Lambda, - LexModelBuildingService, - Rekognition, - AppSync, - CloudWatchLogs, - CloudWatchEvents, - Kinesis, - CloudFormation, - AmplifyBackend, - IAM, - SSM, - Location, -} from 'aws-sdk'; + S3Client, + HeadBucketCommand, + GetBucketEncryptionCommand, + ListObjectsCommand, + GetObjectCommand, + ListObjectVersionsCommand, + DeleteObjectsCommand, + DeleteBucketCommand, + waitUntilBucketNotExists, + ObjectIdentifier, +} from '@aws-sdk/client-s3'; +import { CognitoIdentityClient, GetIdentityPoolRolesCommand } from '@aws-sdk/client-cognito-identity'; +import { + CognitoIdentityProviderClient, + DescribeUserPoolCommand, + DeleteUserPoolDomainCommand, + DeleteIdentityProviderCommand, + ListIdentityProvidersCommand, + DescribeIdentityProviderCommand, + DescribeUserPoolDomainCommand, + ListUserPoolsCommand, + GetUserPoolMfaConfigCommand, + DescribeUserPoolClientCommand, + AdminCreateUserCommand, + ListUsersCommand, + AdminListGroupsForUserCommand, +} from '@aws-sdk/client-cognito-identity-provider'; +import { + LambdaClient, + GetFunctionCommand, + GetLayerVersionByArnCommand, + ListLayerVersionsCommand, + InvokeCommand, + ListEventSourceMappingsCommand, +} from '@aws-sdk/client-lambda'; +import { LexModelBuildingServiceClient, GetBotCommand } from '@aws-sdk/client-lex-model-building-service'; +import { RekognitionClient, DescribeCollectionCommand } from '@aws-sdk/client-rekognition'; +import { AppSyncClient, GetGraphqlApiCommand } from '@aws-sdk/client-appsync'; +import { CloudWatchLogsClient, DescribeLogStreamsCommand, GetLogEventsCommand } from '@aws-sdk/client-cloudwatch-logs'; +import { CloudWatchEventsClient, ListRuleNamesByTargetCommand } from '@aws-sdk/client-cloudwatch-events'; +import { KinesisClient, PutRecordsCommand } from '@aws-sdk/client-kinesis'; +import { CloudFormationClient, DescribeStacksCommand, DescribeStackResourcesCommand } from '@aws-sdk/client-cloudformation'; +import { AmplifyBackendClient, CreateBackendConfigCommand, GetBackendJobCommand } from '@aws-sdk/client-amplifybackend'; +import { IAMClient, ListRolePoliciesCommand, ListAttachedRolePoliciesCommand, GetRoleCommand } from '@aws-sdk/client-iam'; +import { SSMClient, GetParametersCommand, DeleteParameterCommand, GetParametersByPathCommand } from '@aws-sdk/client-ssm'; +import { + LocationClient, + DescribeMapCommand, + DescribePlaceIndexCommand, + DescribeGeofenceCollectionCommand, + GetGeofenceCommand, + ListGeofencesCommand, +} from '@aws-sdk/client-location'; import * as path from 'path'; import _ from 'lodash'; import { $TSAny } from '@aws-amplify/amplify-cli-core'; import { getProjectMeta } from './projectMeta'; export const getDDBTable = async (tableName: string, region: string) => { - const service = new DynamoDB({ region }); + const service = new DynamoDBClient({ region }); if (tableName) { - return await service.describeTable({ TableName: tableName }).promise(); + const command = new DescribeTableCommand({ TableName: tableName }); + return await service.send(command); } return undefined; }; export const checkIfBucketExists = async (bucketName: string, region: string) => { - const service = new S3({ region }); - return await service.headBucket({ Bucket: bucketName }).promise(); + const service = new S3Client({ region }); + const command = new HeadBucketCommand({ Bucket: bucketName }); + return await service.send(command); }; export const bucketNotExists = async (bucket: string) => { - const s3 = new S3(); - const params = { - Bucket: bucket, - $waiter: { maxAttempts: 10, delay: 30 }, - }; + const s3 = new S3Client({}); try { - await s3.waitFor('bucketNotExists', params).promise(); + await waitUntilBucketNotExists({ client: s3, maxWaitTime: 300 }, { Bucket: bucket }); return true; } catch (error) { if (error.statusCode === 200) { @@ -54,24 +90,23 @@ export const bucketNotExists = async (bucket: string) => { }; export const getBucketEncryption = async (bucket: string) => { - const s3 = new S3(); - const params = { - Bucket: bucket, - }; + const s3 = new S3Client({}); + const command = new GetBucketEncryptionCommand({ Bucket: bucket }); try { - const result = await s3.getBucketEncryption(params).promise(); + const result = await s3.send(command); return result.ServerSideEncryptionConfiguration; } catch (err) { throw new Error(`Error fetching SSE info for bucket ${bucket}. Underlying error was [${err.message}]`); } }; -export const getBucketKeys = async (params: S3.ListObjectsRequest) => { - const s3 = new S3(); +export const getBucketKeys = async (params: { Bucket: string; Prefix?: string; Marker?: string; MaxKeys?: number }) => { + const s3 = new S3Client({}); + const command = new ListObjectsCommand(params); try { - const result = await s3.listObjects(params).promise(); - return result.Contents.map((contentObj) => contentObj.Key); + const result = await s3.send(command); + return result.Contents?.map((contentObj) => contentObj.Key); } catch (err) { throw new Error(`Error fetching keys for bucket ${params.Bucket}. Underlying error was [${err.message}]`); } @@ -80,28 +115,27 @@ export const getBucketKeys = async (params: S3.ListObjectsRequest) => { export const getDeploymentBucketObject = async (projectRoot: string, objectKey: string) => { const meta = getProjectMeta(projectRoot); const deploymentBucket = meta.providers.awscloudformation.DeploymentBucketName; - const s3 = new S3(); - const result = await s3 - .getObject({ - Bucket: deploymentBucket, - Key: objectKey, - }) - .promise(); - return result.Body.toLocaleString(); -}; - -export const deleteS3Bucket = async (bucket: string, providedS3Client: S3 | undefined = undefined) => { - const s3 = providedS3Client || new S3(); - let continuationToken: Required>; - const objectKeyAndVersion = []; + const s3 = new S3Client({}); + const command = new GetObjectCommand({ + Bucket: deploymentBucket, + Key: objectKey, + }); + const result = await s3.send(command); + return result.Body?.transformToString(); +}; + +export const deleteS3Bucket = async (bucket: string, providedS3Client: S3Client | undefined = undefined) => { + const s3 = providedS3Client || new S3Client({}); + let continuationToken: { KeyMarker?: string; VersionIdMarker?: string } = {}; + const objectKeyAndVersion: { Key?: string; VersionId?: string }[] = []; let truncated = false; + do { - const results = await s3 - .listObjectVersions({ - Bucket: bucket, - ...continuationToken, - }) - .promise(); + const command = new ListObjectVersionsCommand({ + Bucket: bucket, + ...continuationToken, + }); + const results = await s3.send(command); results.Versions?.forEach(({ Key, VersionId }) => { objectKeyAndVersion.push({ Key, VersionId }); @@ -111,32 +145,40 @@ export const deleteS3Bucket = async (bucket: string, providedS3Client: S3 | unde objectKeyAndVersion.push({ Key, VersionId }); }); - continuationToken = { KeyMarker: results.NextKeyMarker, VersionIdMarker: results.NextVersionIdMarker }; + continuationToken = { + KeyMarker: results.NextKeyMarker, + VersionIdMarker: results.NextVersionIdMarker, + }; truncated = results.IsTruncated; } while (truncated); + const chunkedResult = _.chunk(objectKeyAndVersion, 1000); const deleteReq = chunkedResult - .map((r) => ({ - Bucket: bucket, - Delete: { - Objects: r, - Quiet: true, - }, - })) - .map((delParams) => s3.deleteObjects(delParams).promise()); + .map( + (r) => + new DeleteObjectsCommand({ + Bucket: bucket, + Delete: { + Objects: r as ObjectIdentifier[], + Quiet: true, + }, + }), + ) + .map((delCommand) => s3.send(delCommand)); + await Promise.all(deleteReq); - await s3 - .deleteBucket({ - Bucket: bucket, - }) - .promise(); + + const deleteBucketCommand = new DeleteBucketCommand({ Bucket: bucket }); + await s3.send(deleteBucketCommand); await bucketNotExists(bucket); }; export const getUserPool = async (userpoolId, region) => { let res; try { - res = await new CognitoIdentityServiceProvider({ region }).describeUserPool({ UserPoolId: userpoolId }).promise(); + const client = new CognitoIdentityProviderClient({ region }); + const command = new DescribeUserPoolCommand({ UserPoolId: userpoolId }); + res = await client.send(command); } catch (e) { console.log(e); } @@ -146,7 +188,9 @@ export const getUserPool = async (userpoolId, region) => { export const deleteUserPoolDomain = async (domain: string, userpoolId: string, region: string) => { let res; try { - res = await new CognitoIdentityServiceProvider({ region }).deleteUserPoolDomain({ Domain: domain, UserPoolId: userpoolId }).promise(); + const client = new CognitoIdentityProviderClient({ region }); + const command = new DeleteUserPoolDomainCommand({ Domain: domain, UserPoolId: userpoolId }); + res = await client.send(command); } catch (e) { console.log(e); } @@ -154,11 +198,14 @@ export const deleteUserPoolDomain = async (domain: string, userpoolId: string, r }; export const deleteSocialIdpProviders = async (providers: string[], userpoolId: string, region: string) => { + const client = new CognitoIdentityProviderClient({ region }); for (const provider of providers) { try { - await new CognitoIdentityServiceProvider({ region }) - .deleteIdentityProvider({ ProviderName: provider, UserPoolId: userpoolId }) - .promise(); + const command = new DeleteIdentityProviderCommand({ + ProviderName: provider, + UserPoolId: userpoolId, + }); + await client.send(command); } catch (err) { console.log(err); } @@ -168,7 +215,9 @@ export const deleteSocialIdpProviders = async (providers: string[], userpoolId: export const listSocialIdpProviders = async (userpoolId: string, region: string) => { let res; try { - res = await new CognitoIdentityServiceProvider({ region }).listIdentityProviders({ UserPoolId: userpoolId }).promise(); + const client = new CognitoIdentityProviderClient({ region }); + const command = new ListIdentityProvidersCommand({ UserPoolId: userpoolId }); + res = await client.send(command); } catch (err) { console.log(err); } @@ -182,12 +231,12 @@ export const getSocialIdpProvider = async ( ) => { let res; try { - res = await new CognitoIdentityServiceProvider({ region }) - .describeIdentityProvider({ - UserPoolId: userpoolId, - ProviderName: providerName, - }) - .promise(); + const client = new CognitoIdentityProviderClient({ region }); + const command = new DescribeIdentityProviderCommand({ + UserPoolId: userpoolId, + ProviderName: providerName, + }); + res = await client.send(command); } catch (err) { console.log(err); } @@ -197,11 +246,9 @@ export const getSocialIdpProvider = async ( export const getUserPoolDomain = async (domain: string, region: string) => { let res; try { - res = await new CognitoIdentityServiceProvider({ region }) - .describeUserPoolDomain({ - Domain: domain, - }) - .promise(); + const client = new CognitoIdentityProviderClient({ region }); + const command = new DescribeUserPoolDomainCommand({ Domain: domain }); + res = await client.send(command); } catch (err) { console.log(err); } @@ -212,7 +259,9 @@ export const getIdentityPoolRoles = async (identityPoolId: string, region: strin let res; try { - res = await new CognitoIdentity({ region }).getIdentityPoolRoles({ IdentityPoolId: identityPoolId }).promise(); + const client = new CognitoIdentityClient({ region }); + const command = new GetIdentityPoolRolesCommand({ IdentityPoolId: identityPoolId }); + res = await client.send(command); } catch (e) { console.log(e); } @@ -223,24 +272,26 @@ export const getIdentityPoolRoles = async (identityPoolId: string, region: strin export const listUserPools = async (region, maxResults = 5) => { let res; try { - res = await new CognitoIdentityServiceProvider({ region }).listUserPools({ MaxResults: maxResults }).promise(); + const client = new CognitoIdentityProviderClient({ region }); + const command = new ListUserPoolsCommand({ MaxResults: maxResults }); + res = await client.send(command); } catch (e) { console.log(e); } return res?.UserPools ?? []; }; -export const getMFAConfiguration = async ( - userPoolId: string, - region: string, -): Promise => { - return await new CognitoIdentityServiceProvider({ region }).getUserPoolMfaConfig({ UserPoolId: userPoolId }).promise(); +export const getMFAConfiguration = async (userPoolId: string, region: string) => { + const client = new CognitoIdentityProviderClient({ region }); + const command = new GetUserPoolMfaConfigCommand({ UserPoolId: userPoolId }); + return await client.send(command); }; export const getLambdaFunction = async (functionName: string, region: string) => { - const lambda = new Lambda({ region }); + const client = new LambdaClient({ region }); try { - return await lambda.getFunction({ FunctionName: functionName }).promise(); + const command = new GetFunctionCommand({ FunctionName: functionName }); + return await client.send(command); } catch (e) { console.log(e); } @@ -248,16 +299,15 @@ export const getLambdaFunction = async (functionName: string, region: string) => }; export const getUserPoolClients = async (userPoolId: string, clientIds: string[], region: string) => { - const provider = new CognitoIdentityServiceProvider({ region }); + const provider = new CognitoIdentityProviderClient({ region }); const res = []; try { for (let i = 0; i < clientIds.length; i++) { - const clientData = await provider - .describeUserPoolClient({ - UserPoolId: userPoolId, - ClientId: clientIds[i], - }) - .promise(); + const command = new DescribeUserPoolClientCommand({ + UserPoolId: userPoolId, + ClientId: clientIds[i], + }); + const clientData = await provider.send(command); res.push(clientData); } } catch (e) { @@ -267,111 +317,127 @@ export const getUserPoolClients = async (userPoolId: string, clientIds: string[] }; export const addUserToUserPool = async (userPoolId: string, region: string) => { - const provider = new CognitoIdentityServiceProvider({ region }); - const params = { + const provider = new CognitoIdentityProviderClient({ region }); + const command = new AdminCreateUserCommand({ UserPoolId: userPoolId, UserAttributes: [{ Name: 'email', Value: 'username@amazon.com' }], Username: 'testUser', MessageAction: 'SUPPRESS', TemporaryPassword: 'password', - }; - await provider.adminCreateUser(params).promise(); + }); + await provider.send(command); }; /** * list all users in a Cognito user pool */ export const listUsersInUserPool = async (userPoolId: string, region: string): Promise => { - const provider = new CognitoIdentityServiceProvider({ region }); - const params = { - UserPoolId: userPoolId /* required */, - }; - const { Users } = await provider.listUsers(params).promise(); - return Users.map((u) => u.Username); + const provider = new CognitoIdentityProviderClient({ region }); + const command = new ListUsersCommand({ UserPoolId: userPoolId }); + const result = await provider.send(command); + return result.Users?.map((u) => u.Username) || []; }; /** * list all userPool groups to which a user belongs to */ export const listUserPoolGroupsForUser = async (userPoolId: string, userName: string, region: string): Promise => { - const provider = new CognitoIdentityServiceProvider({ region }); - const params = { - UserPoolId: userPoolId /* required */, - Username: userName /* required */, - }; - const res = await provider.adminListGroupsForUser(params).promise(); - const groups = res.Groups.map((group) => group.GroupName); + const provider = new CognitoIdentityProviderClient({ region }); + const command = new AdminListGroupsForUserCommand({ + UserPoolId: userPoolId, + Username: userName, + }); + const res = await provider.send(command); + const groups = res.Groups?.map((group) => group.GroupName) || []; return groups; }; export const getBot = async (botName: string, region: string) => { - const service = new LexModelBuildingService({ region }); - return await service.getBot({ name: botName, versionOrAlias: '$LATEST' }).promise(); + const service = new LexModelBuildingServiceClient({ region }); + const command = new GetBotCommand({ name: botName, versionOrAlias: '$LATEST' }); + return await service.send(command); }; export const getFunction = async (functionName: string, region: string) => { - const service = new Lambda({ region }); - return await service.getFunction({ FunctionName: functionName }).promise(); + const service = new LambdaClient({ region }); + const command = new GetFunctionCommand({ FunctionName: functionName }); + return await service.send(command); }; export const getLayerVersion = async (functionArn: string, region: string) => { - const service = new Lambda({ region }); - return await service.getLayerVersionByArn({ Arn: functionArn }).promise(); + const service = new LambdaClient({ region }); + const command = new GetLayerVersionByArnCommand({ Arn: functionArn }); + return await service.send(command); }; export const listVersions = async (layerName: string, region: string) => { - const service = new Lambda({ region }); - return await service.listLayerVersions({ LayerName: layerName }).promise(); + const service = new LambdaClient({ region }); + const command = new ListLayerVersionsCommand({ LayerName: layerName }); + return await service.send(command); }; export const invokeFunction = async (functionName: string, payload: string, region: string) => { - const service = new Lambda({ region }); - return await service.invoke({ FunctionName: functionName, Payload: payload }).promise(); + const service = new LambdaClient({ region }); + const command = new InvokeCommand({ FunctionName: functionName, Payload: payload }); + return await service.send(command); }; export const getCollection = async (collectionId: string, region: string) => { - const service = new Rekognition({ region }); - return await service.describeCollection({ CollectionId: collectionId }).promise(); + const service = new RekognitionClient({ region }); + const command = new DescribeCollectionCommand({ CollectionId: collectionId }); + return await service.send(command); }; export const getTable = async (tableName: string, region: string) => { - const service = new DynamoDB({ region }); - return await service.describeTable({ TableName: tableName }).promise(); + const service = new DynamoDBClient({ region }); + const command = new DescribeTableCommand({ TableName: tableName }); + return await service.send(command); }; export const getEventSourceMappings = async (functionName: string, region: string) => { - const service = new Lambda({ region }); - return (await service.listEventSourceMappings({ FunctionName: functionName }).promise()).EventSourceMappings; + const service = new LambdaClient({ region }); + const command = new ListEventSourceMappingsCommand({ FunctionName: functionName }); + const result = await service.send(command); + return result.EventSourceMappings || []; }; export const deleteTable = async (tableName: string, region: string) => { - const service = new DynamoDB({ region }); - return await service.deleteTable({ TableName: tableName }).promise(); + const service = new DynamoDBClient({ region }); + const command = new DeleteTableCommand({ TableName: tableName }); + return await service.send(command); }; export const putItemInTable = async (tableName: string, region: string, item: unknown) => { - const ddb = new DynamoDB.DocumentClient({ region }); - return await ddb.put({ TableName: tableName, Item: item }).promise(); + const ddb = new DynamoDBClient({ region }); + const docClient = DynamoDBDocumentClient.from(ddb); + const command = new PutCommand({ TableName: tableName, Item: item }); + return await docClient.send(command); }; export const scanTable = async (tableName: string, region: string) => { - const ddb = new DynamoDB.DocumentClient({ region }); - return await ddb.scan({ TableName: tableName }).promise(); + const ddb = new DynamoDBClient({ region }); + const docClient = DynamoDBDocumentClient.from(ddb); + const command = new ScanCommand({ TableName: tableName }); + return await docClient.send(command); }; export const getAppSyncApi = async (appSyncApiId: string, region: string) => { - const service = new AppSync({ region }); - return await service.getGraphqlApi({ apiId: appSyncApiId }).promise(); + const service = new AppSyncClient({ region }); + const command = new GetGraphqlApiCommand({ apiId: appSyncApiId }); + return await service.send(command); }; export const getCloudWatchLogs = async (region: string, logGroupName: string, logStreamName: string | undefined = undefined) => { - const cloudWatchLogsClient = new CloudWatchLogs({ region, retryDelayOptions: { base: 500 } }); + const cloudWatchLogsClient = new CloudWatchLogsClient({ region, retryMode: 'standard' }); let targetStreamName = logStreamName; if (targetStreamName === undefined) { - const describeStreamsResp = await cloudWatchLogsClient - .describeLogStreams({ logGroupName, descending: true, orderBy: 'LastEventTime' }) - .promise(); + const describeCommand = new DescribeLogStreamsCommand({ + logGroupName, + descending: true, + orderBy: 'LastEventTime', + }); + const describeStreamsResp = await cloudWatchLogsClient.send(describeCommand); if (describeStreamsResp.logStreams === undefined || describeStreamsResp.logStreams.length === 0) { return []; } @@ -379,20 +445,29 @@ export const getCloudWatchLogs = async (region: string, logGroupName: string, lo targetStreamName = describeStreamsResp.logStreams[0].logStreamName; } - const logsResp = await cloudWatchLogsClient.getLogEvents({ logGroupName, logStreamName: targetStreamName }).promise(); + const getLogsCommand = new GetLogEventsCommand({ + logGroupName, + logStreamName: targetStreamName, + }); + const logsResp = await cloudWatchLogsClient.send(getLogsCommand); return logsResp.events || []; }; export const describeCloudFormationStack = async (stackName: string, region: string, profileConfig?: $TSAny) => { - const service = profileConfig ? new CloudFormation(profileConfig) : new CloudFormation({ region }); - return (await service.describeStacks({ StackName: stackName }).promise()).Stacks.find( - (stack) => stack.StackName === stackName || stack.StackId === stackName, - ); + const clientConfig = profileConfig ? profileConfig : { region }; + const client = new CloudFormationClient(clientConfig); + const command = new DescribeStacksCommand({ StackName: stackName }); + const result = await client.send(command); + return result.Stacks?.find((stack) => stack.StackName === stackName || stack.StackId === stackName); }; export const getNestedStackID = async (stackName: string, region: string, logicalId: string): Promise => { - const cfnClient = new CloudFormation({ region }); - const resource = await cfnClient.describeStackResources({ StackName: stackName, LogicalResourceId: logicalId }).promise(); + const cfnClient = new CloudFormationClient({ region }); + const command = new DescribeStackResourcesCommand({ + StackName: stackName, + LogicalResourceId: logicalId, + }); + const resource = await cfnClient.send(command); return resource?.StackResources?.[0].PhysicalResourceId ?? null; }; @@ -405,47 +480,43 @@ export const getNestedStackID = async (stackName: string, region: string, logica */ export const getTableResourceId = async (region: string, table: string, StackId: string): Promise => { - const cfnClient = new CloudFormation({ region }); - const apiResources = await cfnClient - .describeStackResources({ - StackName: StackId, - }) - .promise(); - const resource = apiResources.StackResources.find((stackResource) => table === stackResource.LogicalResourceId); + const cfnClient = new CloudFormationClient({ region }); + const resourcesCommand = new DescribeStackResourcesCommand({ StackName: StackId }); + const apiResources = await cfnClient.send(resourcesCommand); + + const resource = apiResources.StackResources?.find((stackResource) => table === stackResource.LogicalResourceId); if (resource) { - const tableStack = await cfnClient.describeStacks({ StackName: resource.PhysicalResourceId }).promise(); + const stackCommand = new DescribeStacksCommand({ StackName: resource.PhysicalResourceId }); + const tableStack = await cfnClient.send(stackCommand); if (tableStack?.Stacks?.length > 0) { - const tableName = tableStack.Stacks[0].Outputs.find((out) => out.OutputKey === `GetAtt${resource.LogicalResourceId}TableName`); - return tableName.OutputValue; + const tableName = tableStack.Stacks[0].Outputs?.find((out) => out.OutputKey === `GetAtt${resource.LogicalResourceId}TableName`); + return tableName?.OutputValue || null; } } return null; }; export const putKinesisRecords = async (data: string, partitionKey: string, streamName: string, region: string) => { - const kinesis = new Kinesis({ region }); + const kinesis = new KinesisClient({ region }); + const command = new PutRecordsCommand({ + Records: [ + { + Data: new TextEncoder().encode(data), + PartitionKey: partitionKey, + }, + ], + StreamName: streamName, + }); - return await kinesis - .putRecords({ - Records: [ - { - Data: data, - PartitionKey: partitionKey, - }, - ], - StreamName: streamName, - }) - .promise(); + return await kinesis.send(command); }; export const getCloudWatchEventRule = async (targetName: string, region: string) => { - const service = new CloudWatchEvents({ region }); - const params = { - TargetArn: targetName /* required */, - }; + const service = new CloudWatchEventsClient({ region }); + const command = new ListRuleNamesByTargetCommand({ TargetArn: targetName }); let ruleName; try { - ruleName = await service.listRuleNamesByTarget(params).promise(); + ruleName = await service.send(command); } catch (e) { console.log(e); } @@ -453,49 +524,52 @@ export const getCloudWatchEventRule = async (targetName: string, region: string) }; export const setupAmplifyAdminUI = async (appId: string, region: string) => { - const amplifyBackend = new AmplifyBackend({ region }); - - return await amplifyBackend.createBackendConfig({ AppId: appId }).promise(); + const amplifyBackend = new AmplifyBackendClient({ region }); + const command = new CreateBackendConfigCommand({ AppId: appId }); + return await amplifyBackend.send(command); }; export const getAmplifyBackendJobStatus = async (jobId: string, appId: string, envName: string, region: string) => { - const amplifyBackend = new AmplifyBackend({ region }); - - return await amplifyBackend - .getBackendJob({ - JobId: jobId, - AppId: appId, - BackendEnvironmentName: envName, - }) - .promise(); + const amplifyBackend = new AmplifyBackendClient({ region }); + const command = new GetBackendJobCommand({ + JobId: jobId, + AppId: appId, + BackendEnvironmentName: envName, + }); + return await amplifyBackend.send(command); }; export const listRolePolicies = async (roleName: string, region: string) => { - const service = new IAM({ region }); - return (await service.listRolePolicies({ RoleName: roleName }).promise()).PolicyNames; + const service = new IAMClient({ region }); + const command = new ListRolePoliciesCommand({ RoleName: roleName }); + const result = await service.send(command); + return result.PolicyNames || []; }; export const listAttachedRolePolicies = async (roleName: string, region: string) => { - const service = new IAM({ region }); - return (await service.listAttachedRolePolicies({ RoleName: roleName }).promise()).AttachedPolicies; + const service = new IAMClient({ region }); + const command = new ListAttachedRolePoliciesCommand({ RoleName: roleName }); + const result = await service.send(command); + return result.AttachedPolicies || []; }; export const getPermissionsBoundary = async (roleName: string, region) => { - const iamClient = new IAM({ region }); - return (await iamClient.getRole({ RoleName: roleName }).promise())?.Role?.PermissionsBoundary?.PermissionsBoundaryArn; + const iamClient = new IAMClient({ region }); + const command = new GetRoleCommand({ RoleName: roleName }); + const result = await iamClient.send(command); + return result?.Role?.PermissionsBoundary?.PermissionsBoundaryArn; }; export const getSSMParameters = async (region: string, appId: string, envName: string, funcName: string, parameterNames: string[]) => { - const ssmClient = new SSM({ region }); + const ssmClient = new SSMClient({ region }); if (!parameterNames || parameterNames.length === 0) { throw new Error('no parameterNames specified'); } - return await ssmClient - .getParameters({ - Names: parameterNames.map((name) => path.posix.join('/amplify', appId, envName, `AMPLIFY_${funcName}_${name}`)), - WithDecryption: true, - }) - .promise(); + const command = new GetParametersCommand({ + Names: parameterNames.map((name) => path.posix.join('/amplify', appId, envName, `AMPLIFY_${funcName}_${name}`)), + WithDecryption: true, + }); + return await ssmClient.send(command); }; export const deleteSSMParameter = async ( @@ -506,12 +580,11 @@ export const deleteSSMParameter = async ( funcName: string, parameterName: string, ) => { - const ssmClient = new SSM({ region }); - return await ssmClient - .deleteParameter({ - Name: path.posix.join('/amplify', appId, envName, `AMPLIFY_${category}_${funcName}_${parameterName}`), - }) - .promise(); + const ssmClient = new SSMClient({ region }); + const command = new DeleteParameterCommand({ + Name: path.posix.join('/amplify', appId, envName, `AMPLIFY_${category}_${funcName}_${parameterName}`), + }); + return await ssmClient.send(command); }; export const getSSMParametersCategoryPrefix = async ( @@ -522,25 +595,25 @@ export const getSSMParametersCategoryPrefix = async ( resourceName: string, parameterNames: string[], ) => { - const ssmClient = new SSM({ region }); + const ssmClient = new SSMClient({ region }); if (!parameterNames || parameterNames.length === 0) { throw new Error('no parameterNames specified'); } - return ssmClient - .getParameters({ - Names: parameterNames.map((name) => `/amplify/${appId}/${envName}/AMPLIFY_${category}_${resourceName}_${name}`), - }) - .promise(); + const command = new GetParametersCommand({ + Names: parameterNames.map((name) => `/amplify/${appId}/${envName}/AMPLIFY_${category}_${resourceName}_${name}`), + }); + return ssmClient.send(command); }; export const getAllSSMParamatersForAppId = async (appId: string, region: string): Promise> => { - const ssmClient = new SSM({ region }); + const ssmClient = new SSMClient({ region }); const retrievedParameters: Array = []; let receivedNextToken = ''; do { const ssmArgument = getSsmSdkParametersByPath(appId, receivedNextToken); - const data = await ssmClient.getParametersByPath(ssmArgument).promise(); - retrievedParameters.push(...data.Parameters.map((returnedParameter) => returnedParameter.Name)); + const command = new GetParametersByPathCommand(ssmArgument); + const data = await ssmClient.send(command); + retrievedParameters.push(...(data.Parameters?.map((returnedParameter) => returnedParameter.Name) || [])); receivedNextToken = data.NextToken; } while (receivedNextToken); return retrievedParameters; @@ -558,9 +631,9 @@ export const expectParametersOptionalValue = async ( const parametersToRequest = expectToExist.map((exist) => exist.name).concat(expectNotExist); const result = await getSSMParametersCategoryPrefix(region, appId, envName, category, resourceName, parametersToRequest); const mapName = (name: string) => `/amplify/${appId}/${envName}/AMPLIFY_${category}_${resourceName}_${name}`; - expect(result.InvalidParameters.length).toBe(expectNotExist.length); + expect(result.InvalidParameters?.length || 0).toBe(expectNotExist.length); expect(result.InvalidParameters.sort()).toEqual(expectNotExist.map(mapName).sort()); - expect(result.Parameters.length).toBe(expectToExist.length); + expect(result.Parameters?.length || 0).toBe(expectToExist.length); const mappedResult = result.Parameters.map((param) => ({ name: param.Name, value: JSON.parse(param.Value) })).sort(sortByName); const mappedExpect = expectToExist .map((exist) => ({ name: mapName(exist.name), value: exist.value ? exist.value : '' })) @@ -594,50 +667,38 @@ type SsmGetParametersByPathArgument = { // Amazon location service calls export const getMap = async (mapName: string, region: string) => { - const service = new Location({ region }); - return await service - .describeMap({ - MapName: mapName, - }) - .promise(); + const service = new LocationClient({ region }); + const command = new DescribeMapCommand({ MapName: mapName }); + return await service.send(command); }; export const getPlaceIndex = async (placeIndexName: string, region: string) => { - const service = new Location({ region }); - return await service - .describePlaceIndex({ - IndexName: placeIndexName, - }) - .promise(); + const service = new LocationClient({ region }); + const command = new DescribePlaceIndexCommand({ IndexName: placeIndexName }); + return await service.send(command); }; export const getGeofenceCollection = async (geofenceCollectionName: string, region: string) => { - const service = new Location({ region }); - return await service - .describeGeofenceCollection({ - CollectionName: geofenceCollectionName, - }) - .promise(); + const service = new LocationClient({ region }); + const command = new DescribeGeofenceCollectionCommand({ CollectionName: geofenceCollectionName }); + return await service.send(command); }; export const getGeofence = async (geofenceCollectionName: string, geofenceId: string, region: string) => { - const service = new Location({ region }); - return ( - await service.getGeofence({ - CollectionName: geofenceCollectionName, - GeofenceId: geofenceId, - }) - ).promise(); + const service = new LocationClient({ region }); + const command = new GetGeofenceCommand({ + CollectionName: geofenceCollectionName, + GeofenceId: geofenceId, + }); + return await service.send(command); }; // eslint-disable-next-line spellcheck/spell-checker export const listGeofences = async (geofenceCollectionName: string, region: string, nextToken: string = null) => { - const service = new Location({ region }); - // eslint-disable-next-line spellcheck/spell-checker - return ( - await service.listGeofences({ - CollectionName: geofenceCollectionName, - NextToken: nextToken, - }) - ).promise(); + const client = new LocationClient({ region }); + const command = new ListGeofencesCommand({ + CollectionName: geofenceCollectionName, + NextToken: nextToken, + }); + return await client.send(command); }; diff --git a/packages/amplify-e2e-tests/functions/mutation-appsync.js b/packages/amplify-e2e-tests/functions/mutation-appsync.js index 8ef68db28f2..fe76682dbb1 100644 --- a/packages/amplify-e2e-tests/functions/mutation-appsync.js +++ b/packages/amplify-e2e-tests/functions/mutation-appsync.js @@ -1,6 +1,6 @@ /* eslint-disable no-console */ require('isomorphic-fetch'); -const AWS = require('aws-sdk'); +const { fromNodeProviderChain } = require('@aws-sdk/credential-providers'); const AWSAppSyncClient = require('aws-appsync').default; const { AUTH_TYPE } = require('aws-appsync'); const gql = require('graphql-tag'); @@ -11,7 +11,8 @@ const runGQLMutation = async (gql_url, mutation, variables) => { region: process.env.REGION, auth: { type: AUTH_TYPE.AWS_IAM, - credentials: AWS.config.credentials, + // See documentation here: https://www.npmjs.com/package/@aws-sdk/credential-providers + credentials: fromNodeProviderChain(), }, disableOffline: true, }); diff --git a/packages/amplify-e2e-tests/functions/s3-list-objects.js b/packages/amplify-e2e-tests/functions/s3-list-objects.js index 849e88491ce..621829d4e8f 100644 --- a/packages/amplify-e2e-tests/functions/s3-list-objects.js +++ b/packages/amplify-e2e-tests/functions/s3-list-objects.js @@ -1,13 +1,13 @@ -const AWS = require('aws-sdk'); -const awsS3Client = new AWS.S3(); +const { S3Client, ListObjectsV2Command } = require('@aws-sdk/client-s3'); +const awsS3Client = new S3Client(); const bucketEnvVar = '{{bucketEnvVar}}'; // This value is replaced from test exports.handler = async () => { - const listObjects = await awsS3Client - .listObjectsV2({ - Bucket: process.env[bucketEnvVar], - }) - .promise(); + const command = new ListObjectsV2Command({ + Bucket: process.env[bucketEnvVar], + }); + + const listObjects = await awsS3Client.send(command); return listObjects; }; diff --git a/packages/amplify-e2e-tests/package.json b/packages/amplify-e2e-tests/package.json index 11379544b60..12fd6de9fdc 100644 --- a/packages/amplify-e2e-tests/package.json +++ b/packages/amplify-e2e-tests/package.json @@ -30,10 +30,22 @@ "@aws-amplify/amplify-e2e-core": "5.7.5", "@aws-amplify/amplify-opensearch-simulator": "1.7.20", "@aws-amplify/graphql-transformer-core": "^2.11.1", + "@aws-sdk/client-amplify": "3.624.0", + "@aws-sdk/client-amplifyuibuilder": "3.624.0", "@aws-sdk/client-appsync": "3.624.0", + "@aws-sdk/client-cloudformation": "3.624.0", + "@aws-sdk/client-cloudfront": "3.624.0", + "@aws-sdk/client-codebuild": "3.624.0", + "@aws-sdk/client-cognito-identity-provider": "3.624.0", "@aws-sdk/client-dynamodb": "3.624.0", + "@aws-sdk/client-iam": "3.624.0", + "@aws-sdk/client-organizations": "3.624.0", + "@aws-sdk/client-pinpoint": "3.624.0", "@aws-sdk/client-s3": "3.624.0", "@aws-sdk/client-ssm": "3.624.0", + "@aws-sdk/client-sts": "3.624.0", + "@aws-sdk/credential-providers": "3.624.0", + "@aws-sdk/lib-storage": "3.624.0", "@babel/core": "^7.23.2", "@babel/plugin-transform-modules-commonjs": "7.10.4", "amplify-dynamodb-simulator": "2.9.24", diff --git a/packages/amplify-e2e-tests/src/__tests__/api_1.test.ts b/packages/amplify-e2e-tests/src/__tests__/api_1.test.ts index 72256158db6..9ab144387d8 100644 --- a/packages/amplify-e2e-tests/src/__tests__/api_1.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/api_1.test.ts @@ -58,12 +58,12 @@ describe('amplify add api (GraphQL)', () => { expect(graphqlApi).toBeDefined(); expect(graphqlApi.apiId).toEqual(GraphQLAPIIdOutput); const tableName = `AmplifyDataStore-${graphqlApi.apiId}-${envName}`; - const error = { message: null }; + let error: Error; try { const table = await getDDBTable(tableName, region); - expect(table).toBeUndefined(); + expect(table.Table).toBeUndefined(); } catch (ex) { - Object.assign(error, ex); + error = ex; } expect(error).toBeDefined(); expect(error.message).toContain(`${tableName} not found`); @@ -117,12 +117,12 @@ describe('amplify add api (GraphQL)', () => { expect(graphqlApi).toBeDefined(); expect(graphqlApi.apiId).toEqual(GraphQLAPIIdOutput); const tableName = `AmplifyDataStore-${graphqlApi.apiId}-${envName}`; - const error = { message: null }; + let error: Error; try { const table = await getDDBTable(tableName, region); - expect(table).toBeUndefined(); + expect(table.Table).toBeUndefined(); } catch (ex) { - Object.assign(error, ex); + error = ex; } expect(error).toBeDefined(); expect(error.message).toContain(`${tableName} not found`); diff --git a/packages/amplify-e2e-tests/src/__tests__/api_3.test.ts b/packages/amplify-e2e-tests/src/__tests__/api_3.test.ts index fb7db3d58b0..24ad008f18b 100644 --- a/packages/amplify-e2e-tests/src/__tests__/api_3.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/api_3.test.ts @@ -185,7 +185,7 @@ describe('amplify add api (GraphQL)', () => { await getAppSyncApi(GraphQLAPIIdOutput, meta.providers.awscloudformation.Region); expect(true).toBe(false); // expecting failure } catch (err) { - expect(err.message).toBe(`GraphQL API ${GraphQLAPIIdOutput} not found.`); + expect(err.message).toBe(`API not found.`); } }); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/api_7.test.ts b/packages/amplify-e2e-tests/src/__tests__/api_7.test.ts index a062cec5544..93871f4a899 100644 --- a/packages/amplify-e2e-tests/src/__tests__/api_7.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/api_7.test.ts @@ -59,12 +59,12 @@ describe('amplify add api (GraphQL)', () => { expect(graphqlApi).toBeDefined(); expect(graphqlApi.apiId).toEqual(GraphQLAPIIdOutput); const tableName = `AmplifyDataStore-${graphqlApi.apiId}-${envName}`; - const error = { message: null }; + let error: Error; try { const table = await getDDBTable(tableName, region); - expect(table).toBeUndefined(); + expect(table.Table).toBeUndefined(); } catch (ex) { - Object.assign(error, ex); + error = ex; } expect(error).toBeDefined(); expect(error.message).toContain(`${tableName} not found`); diff --git a/packages/amplify-e2e-tests/src/__tests__/api_9b.test.ts b/packages/amplify-e2e-tests/src/__tests__/api_9b.test.ts index 6eb1af05aa2..0581f3e0289 100644 --- a/packages/amplify-e2e-tests/src/__tests__/api_9b.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/api_9b.test.ts @@ -74,12 +74,12 @@ describe('amplify add api (GraphQL)', () => { expect(graphqlApi).toBeDefined(); expect(graphqlApi.apiId).toEqual(GraphQLAPIIdOutput); const tableName = `Comment-${GraphQLAPIIdOutput}-integtest`; - const error = { message: null }; + let error: Error; try { const table = await getDDBTable(tableName, region); - expect(table).toBeUndefined(); + expect(table.Table).toBeUndefined(); } catch (ex) { - Object.assign(error, ex); + error = ex; } expect(error).toBeDefined(); expect(error.message).toContain(`${tableName} not found`); diff --git a/packages/amplify-e2e-tests/src/__tests__/auth/admin-api.test.ts b/packages/amplify-e2e-tests/src/__tests__/auth/admin-api.test.ts index 45e16415a30..4f474735104 100644 --- a/packages/amplify-e2e-tests/src/__tests__/auth/admin-api.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/auth/admin-api.test.ts @@ -31,7 +31,7 @@ describe('auth admin api tests', () => { }; } const lambdaResponse = await invokeFunction(adminLambdaName, JSON.stringify(request), adminLambdaRegion); - return JSON.parse(lambdaResponse.Payload.toString()); + return JSON.parse(lambdaResponse.Payload.transformToString()); }; beforeAll(async () => { diff --git a/packages/amplify-e2e-tests/src/__tests__/auth/hosted-ui.test.ts b/packages/amplify-e2e-tests/src/__tests__/auth/hosted-ui.test.ts index b998be45e83..b57592f9fb2 100644 --- a/packages/amplify-e2e-tests/src/__tests__/auth/hosted-ui.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/auth/hosted-ui.test.ts @@ -135,7 +135,9 @@ describe('hosted ui tests', () => { const updatedDomainRes = await getUserPoolDomain(hostedUIDomain, region); expect(updatedDomainRes).toBeDefined(); const originalDomainRes = await getUserPoolDomain(originalHostedUIDomain, region); - expect(originalDomainRes).toEqual({ DomainDescription: {} }); + // originalDomainRes has 2 properties $metadata and DomainDescription, we expect DomainDescription to be an empty object + // $metadata property is common in SDK V3 objects + expect(originalDomainRes.DomainDescription).toEqual({}); const deleteOriginalDomainRes = await deleteUserPoolDomain(originalHostedUIDomain, userPoolId, region); // undefined response as it throws InvalidParameterException: No such domain or user pool exists. diff --git a/packages/amplify-e2e-tests/src/__tests__/auth_9.test.ts b/packages/amplify-e2e-tests/src/__tests__/auth_9.test.ts index f12047d033b..5ecced7c6ad 100644 --- a/packages/amplify-e2e-tests/src/__tests__/auth_9.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/auth_9.test.ts @@ -10,7 +10,7 @@ import { initJSProjectWithProfile, nspawn as spawn, } from '@aws-amplify/amplify-e2e-core'; -import { CognitoIdentityServiceProvider } from 'aws-sdk'; +import { DescribeUserPoolCommandOutput } from '@aws-sdk/client-cognito-identity-provider'; const defaultsSettings = { name: 'authTest', @@ -35,10 +35,7 @@ describe('amplify auth with trigger', () => { const meta = getProjectMeta(projRoot); const userPoolId = Object.keys(meta.auth).map((key) => meta.auth[key])[0].output.UserPoolId; - let userPool = (await getUserPool( - userPoolId, - meta.providers.awscloudformation.Region, - )) as CognitoIdentityServiceProvider.DescribeUserPoolResponse; + let userPool = (await getUserPool(userPoolId, meta.providers.awscloudformation.Region)) as DescribeUserPoolCommandOutput; expect(userPool.UserPool).toBeDefined(); expect(userPool.UserPool.LambdaConfig).toBeDefined(); @@ -50,10 +47,7 @@ describe('amplify auth with trigger', () => { await amplifyPushAuth(projRoot); - userPool = (await getUserPool( - userPoolId, - meta.providers.awscloudformation.Region, - )) as CognitoIdentityServiceProvider.DescribeUserPoolResponse; + userPool = (await getUserPool(userPoolId, meta.providers.awscloudformation.Region)) as DescribeUserPoolCommandOutput; expect(userPool.UserPool).toBeDefined(); expect(userPool.UserPool.EmailVerificationSubject).toBe('New code'); diff --git a/packages/amplify-e2e-tests/src/__tests__/custom_policies_container.test.ts b/packages/amplify-e2e-tests/src/__tests__/custom_policies_container.test.ts index 39c7bc53d93..98a2e0b4379 100644 --- a/packages/amplify-e2e-tests/src/__tests__/custom_policies_container.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/custom_policies_container.test.ts @@ -11,7 +11,7 @@ import { deleteProjectDir, } from '@aws-amplify/amplify-e2e-core'; import { JSONUtilities } from '@aws-amplify/amplify-cli-core'; -import AWS from 'aws-sdk'; +import { SSMClient, GetParameterCommand, PutParameterCommand } from '@aws-sdk/client-ssm'; import path from 'path'; const customIAMPolicy: CustomIAMPolicy = { @@ -50,21 +50,21 @@ it(`should init and deploy a api container, attach custom policies to the Fargat const region = meta?.providers?.awscloudformation.Region ?? undefined; // Put SSM parameter - const ssmClient = new AWS.SSM({ region }); - await ssmClient - .putParameter({ + const ssmClient = new SSMClient({ region }); + await ssmClient.send( + new PutParameterCommand({ Name: '/amplify/testCustomPolicies', Value: 'testCustomPoliciesValue', Type: 'String', Overwrite: true, - }) - .promise(); + }), + ); - const getParaResponse = await ssmClient - .getParameter({ + const getParaResponse = await ssmClient.send( + new GetParameterCommand({ Name: '/amplify/testCustomPolicies', - }) - .promise(); + }), + ); const ssmParameterArn = getParaResponse.Parameter.ARN; customIAMPolicy.Resource.push(ssmParameterArn); diff --git a/packages/amplify-e2e-tests/src/__tests__/custom_policies_function.test.ts b/packages/amplify-e2e-tests/src/__tests__/custom_policies_function.test.ts index e7a0952be1c..1aac8f8acac 100644 --- a/packages/amplify-e2e-tests/src/__tests__/custom_policies_function.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/custom_policies_function.test.ts @@ -88,7 +88,7 @@ it('should init and deploy storage DynamoDB + Lambda trigger, attach custom poli // check that the lambda response includes the secret value const response = await invokeFunction(`${funcName}-integtest`, JSON.stringify(lambdaEvent), region); - expect(JSON.parse(response.Payload.toString())?.Value).toEqual('testCustomPoliciesValue'); + expect(JSON.parse(response.Payload.transformToString())?.Value).toEqual('testCustomPoliciesValue'); }); type CustomIAMPolicy = { diff --git a/packages/amplify-e2e-tests/src/__tests__/delete.test.ts b/packages/amplify-e2e-tests/src/__tests__/delete.test.ts index 24f19f12e37..cf472608d04 100644 --- a/packages/amplify-e2e-tests/src/__tests__/delete.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/delete.test.ts @@ -1,4 +1,5 @@ -import { S3, Amplify } from 'aws-sdk'; +import { S3Client, HeadBucketCommand, PutObjectCommand } from '@aws-sdk/client-s3'; +import { AmplifyClient, GetAppCommand } from '@aws-sdk/client-amplify'; import { addPinpointAnalytics, addApiWithoutSchema, @@ -137,22 +138,22 @@ async function testDeletion(projRoot: string, settings: { ios?: boolean; android } async function putFiles(bucket: string, count = 1001) { - const s3 = new S3(); + const s3 = new S3Client(); const s3Params = [...Array(count)].map((_, num) => ({ Bucket: bucket, Body: 'dummy body', Key: `${num}.txt`, })); - await Promise.all(s3Params.map((p) => s3.putObject(p).promise())); + await Promise.all(s3Params.map((p) => s3.send(new PutObjectCommand(p)))); } async function bucketExists(bucket: string) { - const s3 = new S3(); + const s3 = new S3Client(); const params = { Bucket: bucket, }; try { - await s3.headBucket(params).promise(); + await s3.send(new HeadBucketCommand(params)); return true; } catch (error) { if (error.statusCode === 404) { @@ -163,9 +164,9 @@ async function bucketExists(bucket: string) { } async function appExists(appId: string, region: string) { - const amplify = new Amplify({ region }); + const amplify = new AmplifyClient({ region }); try { - await amplify.getApp({ appId }).promise(); + await amplify.send(new GetAppCommand({ appId })); return true; } catch (ex) { return false; diff --git a/packages/amplify-e2e-tests/src/__tests__/function_1.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_1.test.ts index 4140bb6c41c..bc1c53b0bc4 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_1.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_1.test.ts @@ -50,7 +50,7 @@ describe('nodejs', () => { expect(region).toBeDefined(); const cloudFunction = await getFunction(Name, region); const response = await invokeFunction(Name, JSON.stringify({}), region); - const payload = JSON.parse(response.Payload.toString()); + const payload = JSON.parse(response.Payload.transformToString()); expect(payload.headers['Access-Control-Allow-Origin']).toEqual('*'); expect(payload.headers['Access-Control-Allow-Headers']).toEqual('*'); expect(cloudFunction.Configuration.FunctionArn).toEqual(functionArn); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_11.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_11.test.ts index 359035d59d6..de3035bdbd2 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_11.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_11.test.ts @@ -116,7 +116,7 @@ describe('Lambda AppSync nodejs:', () => { expect(fnResponse.StatusCode).toBe(200); expect(fnResponse.Payload).toBeDefined(); - const gqlResponse = JSON.parse(fnResponse.Payload as string); + const gqlResponse = JSON.parse(fnResponse.Payload.transformToString()); expect(gqlResponse.body).toBeDefined(); }); @@ -167,7 +167,7 @@ describe('Lambda AppSync nodejs:', () => { expect(fnResponse.StatusCode).toBe(200); expect(fnResponse.Payload).toBeDefined(); - const gqlResponse = JSON.parse(fnResponse.Payload as string); + const gqlResponse = JSON.parse(fnResponse.Payload.transformToString()); expect(gqlResponse.body).toBeDefined(); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_2b.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_2b.test.ts index 99e14b1a10e..15197670c65 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_2b.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_2b.test.ts @@ -77,7 +77,7 @@ describe('nodejs', () => { expect(result1.StatusCode).toBe(200); expect(result1.Payload).toBeDefined(); - const payload1 = JSON.parse(result1.Payload.toString()); + const payload1 = JSON.parse(result1.Payload.transformToString()); expect(payload1.errorType).toBeUndefined(); expect(payload1.errorMessage).toBeUndefined(); expect(payload1.Items).toBeDefined(); @@ -90,7 +90,7 @@ describe('nodejs', () => { expect(result2.StatusCode).toBe(200); expect(result2.Payload).toBeDefined(); - const payload2 = JSON.parse(result2.Payload.toString()); + const payload2 = JSON.parse(result2.Payload.transformToString()); expect(payload2.errorType).toBeUndefined(); expect(payload2.errorMessage).toBeUndefined(); expect(payload2.Items).toBeDefined(); @@ -153,7 +153,7 @@ describe('nodejs', () => { expect(result.StatusCode).toBe(200); expect(result.Payload).toBeDefined(); - const payload = JSON.parse(result.Payload.toString()); + const payload = JSON.parse(result.Payload.transformToString()); expect(payload.errorType).toBeUndefined(); expect(payload.errorMessage).toBeUndefined(); expect(payload.Items).toBeDefined(); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_2d.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_2d.test.ts index 2f881d3a036..ae99c912232 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_2d.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_2d.test.ts @@ -59,8 +59,8 @@ describe('nodejs', () => { }, }), }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); - expect(JSON.parse(response.Payload.toString()).body).toContain('post call succeed!'); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); + expect(JSON.parse(response.Payload.transformToString()).body).toContain('post call succeed!'); response = await functionCloudInvoke(projRoot, { funcName, @@ -73,8 +73,8 @@ describe('nodejs', () => { }, }), }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); - expect(JSON.parse(response.Payload.toString()).body).toContain('post call succeed!'); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); + expect(JSON.parse(response.Payload.transformToString()).body).toContain('post call succeed!'); response = await functionCloudInvoke(projRoot, { funcName, @@ -87,8 +87,8 @@ describe('nodejs', () => { }, }), }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); - expect(JSON.parse(response.Payload.toString()).body).toContain('put call succeed!'); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); + expect(JSON.parse(response.Payload.transformToString()).body).toContain('put call succeed!'); response = await functionCloudInvoke(projRoot, { funcName, @@ -97,8 +97,8 @@ describe('nodejs', () => { httpMethod: 'GET', }), }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toEqual([item1]); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toEqual([item1]); response = await functionCloudInvoke(projRoot, { funcName, @@ -107,8 +107,8 @@ describe('nodejs', () => { httpMethod: 'GET', }), }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toEqual(item2); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toEqual(item2); response = await functionCloudInvoke(projRoot, { funcName, @@ -117,9 +117,9 @@ describe('nodejs', () => { httpMethod: 'GET', }), }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toContainEqual(item1); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toContainEqual(item2); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toContainEqual(item1); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toContainEqual(item2); response = await functionCloudInvoke(projRoot, { funcName, @@ -128,7 +128,7 @@ describe('nodejs', () => { httpMethod: 'DELETE', }), }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); }); }); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_dotnet.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_dotnet.test.ts index f34c4a22958..6c4566803f4 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_3a_dotnet.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_dotnet.test.ts @@ -53,6 +53,6 @@ describe('dotnet function tests', () => { const payload = '{"key1":"value1","key2":"value2","key3":"value3"}'; await amplifyPushAuth(projRoot); const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); + expect(JSON.parse(response.Payload.transformToString())).toEqual(helloWorldSuccessObj); }); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_go.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_go.test.ts index db523a78abe..99dde69aa85 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_3a_go.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_go.test.ts @@ -39,6 +39,6 @@ describe('go function tests', () => { const payload = '{"name":"Amplify"}'; await amplifyPushAuth(projRoot); const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessOutput); + expect(JSON.parse(response.Payload.transformToString())).toEqual(helloWorldSuccessOutput); }); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_nodejs.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_nodejs.test.ts index 39764fc6b29..a980ce1fe34 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_3a_nodejs.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_nodejs.test.ts @@ -58,7 +58,7 @@ describe('nodejs function tests', () => { const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); + expect(JSON.parse(response.Payload.transformToString())).toEqual(helloWorldSuccessObj); }); it('add nodejs hello world function and mock locally, check buildType, push, check buildType', async () => { diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_python.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_python.test.ts index 4f622dd0483..ee7d6c10587 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_3a_python.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_python.test.ts @@ -65,6 +65,6 @@ describe('python function tests', () => { ...helloWorldSuccessOutput, body: JSON.stringify(helloWorldSuccessOutput.body), }; - expect(JSON.parse(response.Payload.toString())).toEqual(JSON.parse(JSON.stringify(helloWorldSuccessOutputCloud))); + expect(JSON.parse(response.Payload.transformToString())).toEqual(JSON.parse(JSON.stringify(helloWorldSuccessOutputCloud))); }); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3b.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3b.test.ts index 9af13f0d2a3..e1516fe542c 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_3b.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_3b.test.ts @@ -79,7 +79,7 @@ describe('dotnet function tests', () => { const payload = '{"key1":"value1","key2":"value2","key3":"value3"}'; await amplifyPushAuth(projRoot); const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); + expect(JSON.parse(response.Payload.transformToString())).toEqual(helloWorldSuccessObj); assertDotNetVersion(); }); @@ -120,7 +120,7 @@ describe('dotnet function tests', () => { }); await amplifyPushAuth(projRoot); const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString()).statusCode).toEqual(200); + expect(JSON.parse(response.Payload.transformToString()).statusCode).toEqual(200); assertDotNetVersion(); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_4.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_4.test.ts index bada470a22b..3a8bc46a8f6 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_4.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_4.test.ts @@ -77,7 +77,7 @@ describe('add function with layers for runtime nodeJS', () => { const payload = '{}'; const response = await functionCloudInvoke(projRoot, { funcName: functionName, payload }); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toEqual(helloWorldSuccessOutput); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toEqual(helloWorldSuccessOutput); }); it('can add multiple project layers for nodejs', async () => { @@ -128,7 +128,7 @@ describe('add function with layers for runtime nodeJS', () => { const payload = '{}'; const response = await functionCloudInvoke(projRoot, { funcName: functionName, payload }); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toEqual(helloWorldSuccessOutput); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toEqual(helloWorldSuccessOutput); }); }); @@ -191,6 +191,6 @@ describe('add function with layers for runtime python', () => { const payload = '{}'; const response = await functionCloudInvoke(projRoot, { funcName: functionName, payload }); - expect(JSON.parse(response.Payload.toString()).body).toMatch(helloWorldSuccessOutput); + expect(JSON.parse(response.Payload.transformToString()).body).toMatch(helloWorldSuccessOutput); }); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_7.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_7.test.ts index 52b9154eeab..0421c9dc134 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_7.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_7.test.ts @@ -62,7 +62,7 @@ describe('function secret value', () => { // check that the lambda response includes the secret value const response = await invokeFunction(`${funcName}-integtest`, JSON.stringify(lambdaEvent), region); - expect(JSON.parse(response.Payload.toString())[0]?.Value).toEqual('testsecretvalue'); + expect(JSON.parse(response.Payload.transformToString())[0]?.Value).toEqual('testsecretvalue'); }); it('removes secrets immediately when func not pushed', async () => { diff --git a/packages/amplify-e2e-tests/src/__tests__/function_8.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_8.test.ts index 976e1813bbb..030e80492e2 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_8.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_8.test.ts @@ -57,7 +57,7 @@ describe('java function tests', () => { const payload = '{"firstName":"John","lastName" : "Doe"}'; await amplifyPushAuth(projRoot); const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); + expect(JSON.parse(response.Payload.transformToString())).toEqual(helloWorldSuccessObj); }); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_9b.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_9b.test.ts index 65a19100a96..b136dad9c8d 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_9b.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_9b.test.ts @@ -143,7 +143,7 @@ describe('nodejs', () => { expect(fnResponse.StatusCode).toBe(200); expect(fnResponse.Payload).toBeDefined(); - const gqlResponse = JSON.parse(fnResponse.Payload as string); + const gqlResponse = JSON.parse(fnResponse.Payload.transformToString()); expect(gqlResponse.data).toBeDefined(); expect(gqlResponse.data.createTodo.name).toEqual('todo'); @@ -203,7 +203,7 @@ describe('nodejs', () => { expect(fnResponse.StatusCode).toBe(200); expect(fnResponse.Payload).toBeDefined(); - const gqlResponse = JSON.parse(fnResponse.Payload as string); + const gqlResponse = JSON.parse(fnResponse.Payload.transformToString()); expect(gqlResponse.data).toBeDefined(); expect(gqlResponse.data.createTodo.name).toEqual('todo'); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_9c.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_9c.test.ts index 6608d476ee1..579af2095d2 100644 --- a/packages/amplify-e2e-tests/src/__tests__/function_9c.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/function_9c.test.ts @@ -70,7 +70,7 @@ describe('nodejs', () => { expect(fnResponse.StatusCode).toBe(200); expect(fnResponse.Payload).toBeDefined(); - const apiResponse = JSON.parse(fnResponse.Payload as string); + const apiResponse = JSON.parse(fnResponse.Payload.transformToString()); expect(apiResponse.graphqlApi).toBeDefined(); expect(apiResponse.graphqlApi.name).toContain(apiName); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/git-clone-attach.test.ts b/packages/amplify-e2e-tests/src/__tests__/git-clone-attach.test.ts index ad7939eb021..94df019f0d5 100644 --- a/packages/amplify-e2e-tests/src/__tests__/git-clone-attach.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/git-clone-attach.test.ts @@ -25,16 +25,16 @@ import { nonInteractiveInitAttach, nonInteractivePullAttach, } from '@aws-amplify/amplify-e2e-core'; -import { S3 } from 'aws-sdk'; +import { S3Client, CreateBucketCommand, DeleteBucketCommand } from '@aws-sdk/client-s3'; import { getShortId, importS3 } from '../import-helpers'; describe('attach amplify to git-cloned project', () => { const envName = 'test'; let projRoot: string; - const s3Client = new S3(); + const s3Client = new S3Client(); const importBucketName = `git-clone-test-bucket-${getShortId()}`; beforeAll(async () => { - await s3Client.createBucket({ Bucket: importBucketName }).promise(); + await s3Client.send(new CreateBucketCommand({ Bucket: importBucketName })); projRoot = await createNewProjectDir('clone-test'); await initJSProjectWithProfile(projRoot, { envName, disableAmplifyAppCreation: false }); await addFunction( @@ -60,7 +60,7 @@ describe('attach amplify to git-cloned project', () => { await deleteProject(projRoot); deleteProjectDir(projRoot); } finally { - await s3Client.deleteBucket({ Bucket: importBucketName }).promise(); + await s3Client.send(new DeleteBucketCommand({ Bucket: importBucketName })); } }); diff --git a/packages/amplify-e2e-tests/src/__tests__/hostingPROD.test.ts b/packages/amplify-e2e-tests/src/__tests__/hostingPROD.test.ts index 826de4355ec..a55a73f2fed 100644 --- a/packages/amplify-e2e-tests/src/__tests__/hostingPROD.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/hostingPROD.test.ts @@ -1,4 +1,4 @@ -import { CloudFront } from 'aws-sdk'; +import { CloudFrontClient, GetDistributionCommand } from '@aws-sdk/client-cloudfront'; import { amplifyPublishWithoutUpdate, createReactTestProject, @@ -77,11 +77,11 @@ describe('amplify add hosting', () => { }); async function getCloudFrontDistribution(cloudFrontDistributionID: string) { - const cloudFrontClient = new CloudFront(); - const getDistributionResult = await cloudFrontClient - .getDistribution({ + const cloudFrontClient = new CloudFrontClient(); + const getDistributionResult = await cloudFrontClient.send( + new GetDistributionCommand({ Id: cloudFrontDistributionID, - }) - .promise(); + }), + ); return getDistributionResult.Distribution; } diff --git a/packages/amplify-e2e-tests/src/__tests__/import_s3_3.test.ts b/packages/amplify-e2e-tests/src/__tests__/import_s3_3.test.ts index 0e8ed5e3883..15d8f8dfe9f 100644 --- a/packages/amplify-e2e-tests/src/__tests__/import_s3_3.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/import_s3_3.test.ts @@ -1,4 +1,4 @@ -import * as aws from 'aws-sdk'; +import { S3Client, CreateBucketCommand, GetBucketLocationCommand, DeleteBucketCommand } from '@aws-sdk/client-s3'; import { addAuthWithDefault, amplifyPushAuth, @@ -36,26 +36,27 @@ describe('headless s3 import', () => { const shortId = getShortId(); bucketNameToImport = `${bucketPrefix}${shortId}`; - const s3 = new aws.S3(); + // setting default region for S3 Client + const s3 = new S3Client({ region: 'us-east-1' }); - await s3 - .createBucket({ + await s3.send( + new CreateBucketCommand({ Bucket: bucketNameToImport, - }) - .promise(); + }), + ); - const locationResponse = await s3 - .getBucketLocation({ + const locationResponse = await s3.send( + new GetBucketLocationCommand({ Bucket: bucketNameToImport, - }) - .promise(); + }), + ); // For us-east-1 buckets the LocationConstraint is always emtpy, we have to return a // region in every case. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html if ( locationResponse.LocationConstraint === undefined || - locationResponse.LocationConstraint === '' || + locationResponse.LocationConstraint.toString() === '' || locationResponse.LocationConstraint === null ) { bucketLocation = 'us-east-1'; @@ -65,14 +66,14 @@ describe('headless s3 import', () => { }); afterAll(async () => { - // Delete bucket - const s3 = new aws.S3(); + // Delete bucket- in SDK V3, buckets are very picky about the region their client is in + const s3 = new S3Client({ region: bucketLocation || 'us-east-1' }); - await s3 - .deleteBucket({ + await s3.send( + new DeleteBucketCommand({ Bucket: bucketNameToImport, - }) - .promise(); + }), + ); }); beforeEach(async () => { diff --git a/packages/amplify-e2e-tests/src/__tests__/layer-2.test.ts b/packages/amplify-e2e-tests/src/__tests__/layer-2.test.ts index a6007b19ebb..ed4d0d2d2e8 100644 --- a/packages/amplify-e2e-tests/src/__tests__/layer-2.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/layer-2.test.ts @@ -233,7 +233,7 @@ describe('amplify add lambda layer with changes', () => { const payload = '{}'; let response = await functionCloudInvoke(projRoot, { funcName: functionName, payload }); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toEqual(helloWorldUpperCaseOutput); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toEqual(helloWorldUpperCaseOutput); // 2. Step // - Update casing.js in layer @@ -266,7 +266,7 @@ describe('amplify add lambda layer with changes', () => { response = await functionCloudInvoke(projRoot, { funcName: functionName, payload }); - expect(JSON.parse(JSON.parse(response.Payload.toString()).body)).toEqual(helloWorldUpperCaseOutput); + expect(JSON.parse(JSON.parse(response.Payload.transformToString()).body)).toEqual(helloWorldUpperCaseOutput); // 3. Step // - Update function to use latest version of the layer diff --git a/packages/amplify-e2e-tests/src/__tests__/push.test.ts b/packages/amplify-e2e-tests/src/__tests__/push.test.ts index 5b6257ff2ab..d8196a0b105 100644 --- a/packages/amplify-e2e-tests/src/__tests__/push.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/push.test.ts @@ -9,7 +9,7 @@ import { initJSProjectWithProfile, amplifyPushAuth, } from '@aws-amplify/amplify-e2e-core'; -import * as AWS from 'aws-sdk'; +import { S3Client, DeleteObjectCommand } from '@aws-sdk/client-s3'; describe('amplify push ', () => { let pushProjRoot: string; @@ -33,13 +33,13 @@ describe('amplify push ', () => { const meta = amplifyMeta.providers.awscloudformation; const bucketName = meta.DeploymentBucketName; - const s3 = new AWS.S3(); - await s3 - .deleteObject({ + const s3 = new S3Client(); + await s3.send( + new DeleteObjectCommand({ Bucket: bucketName, Key: '#current-cloud-backend.zip', - }) - .promise(); + }), + ); await expect(amplifyPushAuth(pushProjRoot)).rejects.toThrow(); await amplifyPushForce(pushProjRoot); diff --git a/packages/amplify-e2e-tests/src/__tests__/schema-iterative-update-locking.test.ts b/packages/amplify-e2e-tests/src/__tests__/schema-iterative-update-locking.test.ts index bbfa4996da4..03cc5c166e0 100644 --- a/packages/amplify-e2e-tests/src/__tests__/schema-iterative-update-locking.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/schema-iterative-update-locking.test.ts @@ -14,7 +14,7 @@ import { getProjectMeta, sleep, } from '@aws-amplify/amplify-e2e-core'; -import S3 from 'aws-sdk/clients/s3'; +import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; import { DeploymentState, DeploymentStatus, JSONUtilities } from '@aws-amplify/amplify-cli-core'; describe('Schema iterative update - locking', () => { @@ -67,7 +67,7 @@ describe('Schema iterative update - locking', () => { const projectRegion = meta.providers.awscloudformation.Region; const deploymentBucketName = meta.providers.awscloudformation.DeploymentBucketName; - const s3 = new S3({ + const s3 = new S3Client({ region: projectRegion, }); @@ -79,14 +79,15 @@ describe('Schema iterative update - locking', () => { while (retry < maxRetries || !lockFileExists) { try { - const deploymentStateObject = await s3 - .getObject({ + const deploymentStateObject = await s3.send( + new GetObjectCommand({ Bucket: deploymentBucketName, Key: stateFileName, - }) - .promise(); + }), + ); - const deploymentState = JSONUtilities.parse(deploymentStateObject.Body.toString()); + const bodyString = await deploymentStateObject.Body?.transformToString(); + const deploymentState = JSONUtilities.parse(bodyString); if (deploymentState.status === DeploymentStatus.DEPLOYING) { lockFileExists = true; diff --git a/packages/amplify-e2e-tests/src/__tests__/storage-simulator/S3server.test.ts b/packages/amplify-e2e-tests/src/__tests__/storage-simulator/S3server.test.ts index 63e3305a61f..5e4e8ac9cd3 100644 --- a/packages/amplify-e2e-tests/src/__tests__/storage-simulator/S3server.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/storage-simulator/S3server.test.ts @@ -1,5 +1,6 @@ import { AmplifyStorageSimulator } from 'amplify-storage-simulator'; -import * as AWS from 'aws-sdk'; +import { S3Client, ListObjectsV2Command, GetObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3'; +import { Upload } from '@aws-sdk/lib-storage'; import * as fs from 'fs-extra'; const port = 20005; // for testing @@ -17,16 +18,17 @@ let simulator; jest.setTimeout(2000000); beforeAll(async () => { - const ep = new AWS.Endpoint('http://localhost:20005'); - s3client = new AWS.S3({ - accessKeyId: fakeAccessId, - secretAccessKey: fakeSecretKey, + s3client = new S3Client({ + credentials: { + accessKeyId: fakeAccessId, + secretAccessKey: fakeSecretKey, + }, region: fakeRegion, apiVersion: '2006-03-01', - endpoint: ep.href, - s3BucketEndpoint: true, - sslEnabled: false, - s3ForcePathStyle: true, + endpoint: 'http://localhost:20005', + forcePathStyle: true, + bucketEndpoint: true, + tls: false, }); simulator = new AmplifyStorageSimulator({ port, route, localDirS3 }); @@ -57,59 +59,58 @@ describe('test server running', () => { describe('Test get api', () => { test('get image work ', async () => { - const data = await s3client.getObject({ Bucket: bucket, Key: '2.png' }).promise(); + const data = await s3client.send(new GetObjectCommand({ Bucket: bucket, Key: '2.png' })); expect(data).toBeDefined(); expect(data.Body).toBeDefined(); }); test('get text file', async () => { - const data = await s3client.getObject({ Bucket: bucket, Key: 'abc.txt' }).promise(); + const data = await s3client.send(new GetObjectCommand({ Bucket: bucket, Key: 'abc.txt' })); expect(data).toBeDefined(); expect(data.Body).toBeDefined(); - expect(data.Body.toString()).toEqual('Helloworld1234'); + const bodyString = await data.Body.transformToString(); + expect(bodyString).toEqual('Helloworld1234'); }); }); describe('Test list api', () => { test('get list', async () => { - const response = await s3client.listObjects({ Bucket: bucket, Prefix: 'normal' }).promise(); + const response = await s3client.send(new ListObjectsV2Command({ Bucket: bucket, Prefix: 'normal' })); expect(response).toBeDefined(); expect(response.Contents[0].Key).toEqual('normal/2.png'); expect(response.Contents.length).toEqual(1); }); test('get list', async () => { - const response = await s3client.listObjects({ Bucket: bucket }).promise(); + const response = await s3client.send(new ListObjectsV2Command({ Bucket: bucket, Prefix: '' })); expect(response).toBeDefined(); //expect(response.Contents.length).toEqual(1); }); test('empty bucket', async () => { - const response = await s3client.listObjects({ Bucket: bucket, Prefix: 'public' }).promise(); + const response = await s3client.send(new ListObjectsV2Command({ Bucket: bucket, Prefix: 'public' })); expect(response).toBeDefined(); - expect(response.Contents.length).toEqual(0); + expect(response.Contents).toBeUndefined(); }); test('list object pagination', async () => { const maxKeys = 2; let total = 7; - let response = await s3client - .listObjects({ + let response = await s3client.send( + new ListObjectsV2Command({ Bucket: bucket, Prefix: 'pagination', - Marker: '', MaxKeys: maxKeys, - }) - .promise(); + }), + ); while (response.IsTruncated === true) { expect(response).toBeDefined(); expect(response.Contents.length).toEqual(maxKeys); - response = await s3client - .listObjects({ + response = await s3client.send( + new ListObjectsV2Command({ Bucket: bucket, Prefix: 'pagination', - Marker: response.NextMarker, MaxKeys: maxKeys, - }) - .promise(); + }), + ); total = total - maxKeys; } expect(response.Contents.length).toEqual(total); @@ -123,7 +124,7 @@ describe('Test delete api', () => { fs.copySync(__dirname + '/test-data/normal/', dirPathOne + '/'); }); test('test one delete ', async () => { - await s3client.deleteObject({ Bucket: bucket, Key: 'deleteOne/2.png' }).promise(); + await s3client.send(new DeleteObjectCommand({ Bucket: bucket, Key: 'deleteOne/2.png' })); expect(fs.rmdirSync(dirPathOne)).toBeUndefined; }); }); @@ -138,7 +139,11 @@ describe('Test put api', () => { Prefix: 'upload', Body: buffer, }; - const data = await s3client.upload(params).promise(); + const upload = new Upload({ + client: s3client, + params, + }); + const data = await upload.done(); expect(data).toBeDefined(); }); @@ -181,7 +186,10 @@ describe('Test put api', () => { Key: 'upload/abc.txt', Body: buf1, }; - const data = await s3client.upload(params).promise(); + const data = await new Upload({ + client: s3client, + params, + }).done(); expect(data).toBeDefined(); }); @@ -192,7 +200,10 @@ describe('Test put api', () => { Body: JSON.stringify(Jsonobj), ContentType: 'application/json', }; - const data = await s3client.upload(params).promise(); + const data = await new Upload({ + client: s3client, + params, + }).done(); const jsonFile = __dirname + '/test-data/upload/abc.json'; const contents = fs.readFileSync(jsonFile); const obj = JSON.parse(contents.toString()); @@ -209,7 +220,10 @@ describe('Test put api', () => { Key: 'upload/long_image.jpg', Body: buf2, }; - const data = await s3client.upload(params).promise(); + const data = await new Upload({ + client: s3client, + params, + }).done(); expect(data.Key).toBe('upload/long_image.jpg'); }); @@ -219,21 +233,30 @@ describe('Test put api', () => { Key: 'upload/long_image1.jpg', Body: buf2, }; - const data = await s3client.upload(params1).promise(); + const data = await new Upload({ + client: s3client, + params: params1, + }).done(); const params2 = { Bucket: bucket, // pass your bucket name Key: 'upload/long_image2.jpg', Body: buf2, }; - const data2 = await s3client.upload(params2).promise(); + const data2 = await new Upload({ + client: s3client, + params: params2, + }).done(); const params3 = { Bucket: bucket, // pass your bucket name Key: 'upload/long_image3.jpg', Body: buf2, }; - const data3 = await s3client.upload(params3).promise(); + const data3 = await new Upload({ + client: s3client, + params: params3, + }).done(); expect(data.Key).toBe('upload/long_image1.jpg'); expect(data2.Key).toBe('upload/long_image2.jpg'); @@ -258,9 +281,9 @@ describe('Test put api', () => { }; const uploadPromises = []; - uploadPromises.push(s3client.upload(params1).promise()); - uploadPromises.push(s3client.upload(params2).promise()); - uploadPromises.push(s3client.upload(params3).promise()); + uploadPromises.push(new Upload({ client: s3client, params: params1 }).done()); + uploadPromises.push(new Upload({ client: s3client, params: params2 }).done()); + uploadPromises.push(new Upload({ client: s3client, params: params3 }).done()); const uploadResults = await Promise.all(uploadPromises); expect(uploadResults[0].Key).toBe('upload/long_image1.jpg'); diff --git a/packages/amplify-e2e-tests/src/__tests__/uibuilder.test.ts b/packages/amplify-e2e-tests/src/__tests__/uibuilder.test.ts index 21b477bd289..703e8665a88 100644 --- a/packages/amplify-e2e-tests/src/__tests__/uibuilder.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/uibuilder.test.ts @@ -14,7 +14,7 @@ import { amplifyStudioHeadlessPull, } from '@aws-amplify/amplify-e2e-core'; import { spawnSync, spawn } from 'child_process'; -import { AmplifyUIBuilder } from 'aws-sdk'; +import { AmplifyUIBuilderClient, CreateComponentCommand } from '@aws-sdk/client-amplifyuibuilder'; import fs from 'fs-extra'; import path from 'path'; import * as execa from 'execa'; @@ -51,23 +51,23 @@ describe('amplify pull with uibuilder', () => { appId = getAppId(projRoot); const meta = getBackendAmplifyMeta(projRoot); const region = meta.providers.awscloudformation.Region; - const amplifyUIBuilder = new AmplifyUIBuilder({ region }); + const amplifyUIBuilder = new AmplifyUIBuilderClient({ region }); - await amplifyUIBuilder - .createComponent({ + await amplifyUIBuilder.send( + new CreateComponentCommand({ appId, environmentName: envName, componentToCreate: myIconComponent, - }) - .promise(); + }), + ); - await amplifyUIBuilder - .createComponent({ + await amplifyUIBuilder.send( + new CreateComponentCommand({ appId, environmentName: envName, componentToCreate: formCheckoutComponent, - }) - .promise(); + }), + ); // needs to enable studio for resources to be pull down await enableAdminUI(appId, envName, region); diff --git a/packages/amplify-e2e-tests/src/aws-matchers/iamMatcher.ts b/packages/amplify-e2e-tests/src/aws-matchers/iamMatcher.ts index b06e6e6874f..164a639b1f6 100644 --- a/packages/amplify-e2e-tests/src/aws-matchers/iamMatcher.ts +++ b/packages/amplify-e2e-tests/src/aws-matchers/iamMatcher.ts @@ -1,11 +1,11 @@ -import { IAM } from 'aws-sdk'; +import { IAMClient, GetRoleCommand } from '@aws-sdk/client-iam'; export const toBeIAMRoleWithArn = async (roleName: string, arn?: string) => { - const iam = new IAM(); + const iam = new IAMClient(); let pass: boolean; let message: string; try { - const { Role: role } = await iam.getRole({ RoleName: roleName }).promise(); + const { Role: role } = await iam.send(new GetRoleCommand({ RoleName: roleName })); if (arn) { pass = role.Arn === arn ? true : false; if (pass) { @@ -33,13 +33,15 @@ export const toHaveValidPolicyConditionMatchingIdpId = async (roleName: string, let message = ''; try { - const iam = new IAM({ - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, - sessionToken: process.env.AWS_SESSION_TOKEN, + const iam = new IAMClient({ + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + sessionToken: process.env.AWS_SESSION_TOKEN, + }, }); - const { Role: role } = await iam.getRole({ RoleName: roleName }).promise(); + const { Role: role } = await iam.send(new GetRoleCommand({ RoleName: roleName })); const assumeRolePolicyDocument = JSON.parse(decodeURIComponent(role.AssumeRolePolicyDocument)); pass = assumeRolePolicyDocument.Statement.some((statement) => { @@ -73,13 +75,15 @@ export const toHaveDenyAssumeRolePolicy = async (roleName: string) => { let message = ''; try { - const iam = new IAM({ - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, - sessionToken: process.env.AWS_SESSION_TOKEN, + const iam = new IAMClient({ + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + sessionToken: process.env.AWS_SESSION_TOKEN, + }, }); - const { Role: role } = await iam.getRole({ RoleName: roleName }).promise(); + const { Role: role } = await iam.send(new GetRoleCommand({ RoleName: roleName })); const assumeRolePolicyDocument = JSON.parse(decodeURIComponent(role.AssumeRolePolicyDocument)); pass = assumeRolePolicyDocument?.Statement?.length === 1 && assumeRolePolicyDocument?.Statement?.[0]?.Effect === 'Deny'; diff --git a/packages/amplify-e2e-tests/src/aws-matchers/s3matcher.ts b/packages/amplify-e2e-tests/src/aws-matchers/s3matcher.ts index b007f43c47f..f5a9723b68a 100644 --- a/packages/amplify-e2e-tests/src/aws-matchers/s3matcher.ts +++ b/packages/amplify-e2e-tests/src/aws-matchers/s3matcher.ts @@ -1,10 +1,10 @@ -import { S3 } from 'aws-sdk'; +import { S3Client, HeadBucketCommand } from '@aws-sdk/client-s3'; export const toBeAS3Bucket = async (bucketName: string) => { - const s3 = new S3(); + const s3 = new S3Client(); let pass: boolean; try { - await s3.headBucket({ Bucket: bucketName }).promise(); + await s3.send(new HeadBucketCommand({ Bucket: bucketName })); pass = true; } catch (e) { pass = false; diff --git a/packages/amplify-e2e-tests/src/cleanup-codebuild-resources.ts b/packages/amplify-e2e-tests/src/cleanup-codebuild-resources.ts index 61c492499c4..e2501c259e7 100644 --- a/packages/amplify-e2e-tests/src/cleanup-codebuild-resources.ts +++ b/packages/amplify-e2e-tests/src/cleanup-codebuild-resources.ts @@ -1,15 +1,55 @@ +import { AmplifyClient, ListAppsCommand, DeleteAppCommand, ListBackendEnvironmentsCommand } from '@aws-sdk/client-amplify'; +import { AppSyncClient, ListGraphqlApisCommand, DeleteGraphqlApiCommand } from '@aws-sdk/client-appsync'; import { - Amplify, - AppSync, - CloudFormation, - CodeBuild, - CognitoIdentityServiceProvider, - IAM, - Organizations, - Pinpoint, - S3, - STS, -} from 'aws-sdk'; + CloudFormationClient, + ListStacksCommand, + DeleteStackCommand, + DescribeStacksCommand, + ListStackResourcesCommand, + StackStatus, + Tag, +} from '@aws-sdk/client-cloudformation'; +import { CodeBuildClient, BatchGetBuildsCommand, Build, StatusType } from '@aws-sdk/client-codebuild'; +import { + CognitoIdentityProviderClient, + ListUserPoolsCommand, + DeleteUserPoolCommand, + DescribeUserPoolCommand, + DeleteUserPoolDomainCommand, + UserPoolDescriptionType, +} from '@aws-sdk/client-cognito-identity-provider'; +import { + IAMClient, + ListRolesCommand, + DeleteRoleCommand, + ListRolePoliciesCommand, + DeleteRolePolicyCommand, + ListAttachedRolePoliciesCommand, + DetachRolePolicyCommand, + ListOpenIDConnectProvidersCommand, + DeleteOpenIDConnectProviderCommand, + Role, + AttachedPolicy, +} from '@aws-sdk/client-iam'; +import { OrganizationsClient, ListAccountsCommand } from '@aws-sdk/client-organizations'; +import { + PinpointClient, + GetAppsCommand, + DeleteAppCommand as DeletePinpointAppCommand, + ApplicationResponse, +} from '@aws-sdk/client-pinpoint'; +import { + S3Client, + ListBucketsCommand, + DeleteBucketCommand, + ListObjectsV2Command, + DeleteObjectsCommand, + GetBucketTaggingCommand, + ListObjectVersionsCommand, + Bucket, + GetBucketLocationCommand, +} from '@aws-sdk/client-s3'; +import { STSClient, GetCallerIdentityCommand, AssumeRoleCommand } from '@aws-sdk/client-sts'; import fs from 'fs-extra'; import _ from 'lodash'; import path from 'path'; @@ -54,7 +94,7 @@ type StackInfo = { resourcesFailedToDelete?: string[]; tags: Record; region: string; - cbInfo?: CodeBuild.Build; + cbInfo?: Build; }; type AmplifyAppInfo = { @@ -66,7 +106,7 @@ type AmplifyAppInfo = { type S3BucketInfo = { name?: string; - cbInfo?: CodeBuild.Build; + cbInfo?: Build; createTime?: Date; }; @@ -81,13 +121,13 @@ type PinpointAppInfo = { name?: string; arn: string; region: string; - cbInfo?: CodeBuild.Build; + cbInfo?: Build; createTime: Date; }; type IamRoleInfo = { name: string; - cbInfo?: CodeBuild.Build; + cbInfo?: Build; createTime: Date; }; @@ -95,13 +135,13 @@ type AppSyncApiInfo = { apiId?: string; name?: string; region: string; - cbInfo?: CodeBuild.Build; + cbInfo?: Build; }; type ReportEntry = { jobId?: string; workflowId?: string; - cbInfo?: CodeBuild.Build; + cbInfo?: Build; amplifyApps: AmplifyAppInfo[]; stacks: StackInfo[]; buckets: Record; @@ -162,22 +202,22 @@ const isStale = (created: string | Date | undefined): boolean => { /** * We define a resource as viable for deletion if it matches TEST_REGEX in the name, and if it is > STALE_DURATION_MS old. */ -const testBucketStalenessFilter = (resource: S3.Bucket): boolean => { +const testBucketStalenessFilter = (resource: Bucket): boolean => { const isTestResource = !!resource?.Name?.match(BUCKET_TEST_REGEX); return isTestResource && isStale(resource.CreationDate); }; -const testRoleStalenessFilter = (resource: IAM.Role): boolean => { +const testRoleStalenessFilter = (resource: Role): boolean => { const isTestResource = !!resource?.RoleName?.match(IAM_TEST_REGEX); return isTestResource && isStale(resource.CreateDate); }; -const testUserPoolStalenessFilter = (resource: CognitoIdentityServiceProvider.UserPoolDescriptionType): boolean => { +const testUserPoolStalenessFilter = (resource: UserPoolDescriptionType): boolean => { const isTestResource = !!resource?.Name?.match(USER_POOL_TEST_REGEX); return isTestResource && isStale(resource.CreationDate); }; -const testAppSyncApiStalenessFilter = (resource: AppSync.GraphqlApi): boolean => { +const testAppSyncApiStalenessFilter = (resource: any): boolean => { const isTestResource = !!resource?.name?.match(APPSYNC_TEST_REGEX); const createTimeTagValue = resource?.tags?.['codebuild:create_time']; let isStaleResource = true; @@ -188,8 +228,8 @@ const testAppSyncApiStalenessFilter = (resource: AppSync.GraphqlApi): boolean => return isTestResource && isStaleResource; }; -const testPinpointAppStalenessFilter = (resource: Pinpoint.ApplicationResponse): boolean => { - const isTestResource = !!(resource.Name.match(PINPOINT_TEST_REGEX) && resource.CreationDate); +const testPinpointAppStalenessFilter = (resource: ApplicationResponse): boolean => { + const isTestResource = !!(resource.Name?.match(PINPOINT_TEST_REGEX) && resource.CreationDate); return isTestResource && isStale(resource.CreationDate); }; @@ -197,8 +237,8 @@ const testPinpointAppStalenessFilter = (resource: Pinpoint.ApplicationResponse): * Get all S3 buckets in the account, and filter down to the ones we consider stale. */ const getOrphanS3TestBuckets = async (account: AWSAccountInfo): Promise => { - const s3Client = new S3(getAWSConfig(account)); - const listBucketResponse = await s3Client.listBuckets().promise(); + const s3Client = new S3Client(getAWSConfig(account)); + const listBucketResponse = await s3Client.send(new ListBucketsCommand({})); const staleBuckets = listBucketResponse?.Buckets?.filter(testBucketStalenessFilter); return staleBuckets?.map((it) => ({ name: it.Name, createTime: it.CreationDate })) ?? []; }; @@ -207,38 +247,38 @@ const getOrphanS3TestBuckets = async (account: AWSAccountInfo): Promise => { - const iamClient = new IAM(getAWSConfig(account)); - const listRoleResponse = await iamClient.listRoles({ MaxItems: 1000 }).promise(); - const staleRoles = listRoleResponse.Roles.filter(testRoleStalenessFilter); - return staleRoles.map((it) => ({ name: it.RoleName, createTime: it.CreateDate })); + const iamClient = new IAMClient(getAWSConfig(account)); + const listRoleResponse = await iamClient.send(new ListRolesCommand({ MaxItems: 1000 })); + const staleRoles = listRoleResponse.Roles?.filter(testRoleStalenessFilter) ?? []; + return staleRoles.map((it) => ({ name: it.RoleName!, createTime: it.CreateDate! })); }; const getOrphanPinpointApplications = async (account: AWSAccountInfo, region: string): Promise => { - const pinpoint = new Pinpoint(getAWSConfig(account, region)); + const pinpoint = new PinpointClient(getAWSConfig(account, region)); const apps: PinpointAppInfo[] = []; let nextToken = undefined; do { - const result: Pinpoint.GetAppsResponse = await pinpoint.getApps({ Token: nextToken }).promise(); + const result = await pinpoint.send(new GetAppsCommand({ Token: nextToken })); apps.push( ...(result.ApplicationsResponse?.Item || []).filter(testPinpointAppStalenessFilter).map((it) => ({ - id: it.Id, + id: it.Id!, name: it.Name, - arn: it.Arn, + arn: it.Arn!, region, createTime: new Date(it?.CreationDate ?? 'Invalid Date'), })), ); - nextToken = result.ApplicationsResponse.NextToken; + nextToken = result.ApplicationsResponse?.NextToken; } while (nextToken); return apps; }; const getOrphanUserPools = async (account: AWSAccountInfo, region: string): Promise => { - const cognitoClient = new CognitoIdentityServiceProvider(getAWSConfig(account, region)); - const userPools = await cognitoClient.listUserPools({ MaxResults: 60 }).promise(); + const cognitoClient = new CognitoIdentityProviderClient(getAWSConfig(account, region)); + const userPools = await cognitoClient.send(new ListUserPoolsCommand({ MaxResults: 60 })); const staleUserPools = userPools?.UserPools?.filter(testUserPoolStalenessFilter); return staleUserPools?.map((it) => ({ name: it.Name, userPoolId: it.Id, region })) ?? []; }; @@ -247,8 +287,8 @@ const getOrphanUserPools = async (account: AWSAccountInfo, region: string): Prom * Get all AppSync Apis in the account, and filter down to the ones we consider stale. */ const getOrphanAppSyncApis = async (account: AWSAccountInfo, region: string): Promise => { - const appSyncClient = new AppSync(getAWSConfig(account, region)); - const listApisResponse = await appSyncClient.listGraphqlApis({ maxResults: 25 }).promise(); + const appSyncClient = new AppSyncClient(getAWSConfig(account, region)); + const listApisResponse = await appSyncClient.send(new ListGraphqlApisCommand({ maxResults: 25 })); const staleApis = listApisResponse?.graphqlApis?.filter(testAppSyncApiStalenessFilter); return staleApis?.map((it) => ({ apiId: it.apiId, name: it.name, region })) ?? []; }; @@ -257,14 +297,14 @@ const getOrphanAppSyncApis = async (account: AWSAccountInfo, region: string): Pr * Get all OIDC providers in the account that match */ const deleteOrphanedOidcProviders = async (account: AWSAccountInfo): Promise => { - const iamClient = new IAM(getAWSConfig(account)); - const response = await iamClient.listOpenIDConnectProviders().promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + const response = await iamClient.send(new ListOpenIDConnectProvidersCommand({})); if (response.OpenIDConnectProviderList) { for (const provider of response.OpenIDConnectProviderList) { // these seem to be the only offending resources at this time, but we can add more later - if (provider.Arn.endsWith('oidc-provider/accounts.google.com')) { + if (provider.Arn?.endsWith('oidc-provider/accounts.google.com')) { console.log('OIDC PROVIDER:', provider.Arn); - await iamClient.deleteOpenIDConnectProvider({ OpenIDConnectProviderArn: provider.Arn }).promise(); + await iamClient.send(new DeleteOpenIDConnectProviderCommand({ OpenIDConnectProviderArn: provider.Arn })); } } } @@ -286,18 +326,18 @@ const getAWSConfig = ({ accessKeyId, secretAccessKey, sessionToken }: AWSAccount /** * delete an S3 bucket, copied from amplify-e2e-core */ -const deleteS3Bucket = async (bucket: string, providedS3Client: S3 | undefined = undefined) => { - const s3 = providedS3Client || new S3(); - let continuationToken: Pick | undefined = undefined; - const objectKeyAndVersion = []; +const deleteS3Bucket = async (bucket: string, providedS3Client: S3Client | undefined = undefined) => { + const s3 = providedS3Client || new S3Client({}); + let continuationToken: string | undefined = undefined; + const objectKeyAndVersion: { Key: string; VersionId?: string }[] = []; let truncated = true; while (truncated) { - const results: S3.ListObjectVersionsOutput = await s3 - .listObjectVersions({ + const results = await s3.send( + new ListObjectVersionsCommand({ Bucket: bucket, - ...(continuationToken ? continuationToken : {}), - }) - .promise(); + ...(continuationToken ? { KeyMarker: continuationToken } : {}), + }), + ); results.Versions?.forEach(({ Key, VersionId }) => { if (Key) { @@ -311,25 +351,25 @@ const deleteS3Bucket = async (bucket: string, providedS3Client: S3 | undefined = } }); - continuationToken = { KeyMarker: results.NextKeyMarker, VersionIdMarker: results.NextVersionIdMarker }; + continuationToken = results.NextKeyMarker; truncated = !!results.IsTruncated; } const chunkedResult = _.chunk(objectKeyAndVersion, 1000); const deleteReq = chunkedResult - .map((r: S3.ObjectIdentifier[]) => ({ + .map((r) => ({ Bucket: bucket, Delete: { Objects: r, Quiet: true, }, })) - .map((delParams: S3.DeleteObjectsRequest) => s3.deleteObjects(delParams).promise()); + .map((delParams) => s3.send(new DeleteObjectsCommand(delParams))); await Promise.all(deleteReq); - await s3 - .deleteBucket({ + await s3.send( + new DeleteBucketCommand({ Bucket: bucket, - }) - .promise(); + }), + ); await bucketNotExists(bucket); }; @@ -337,20 +377,34 @@ const deleteS3Bucket = async (bucket: string, providedS3Client: S3 | undefined = * Copied from amplify-e2e-core */ const bucketNotExists = async (bucket: string) => { - const s3 = new S3(); - const params = { - Bucket: bucket, - $waiter: { maxAttempts: 10, delay: 30 }, - }; - try { - await s3.waitFor('bucketNotExists', params).promise(); - return true; - } catch (error) { - if (error.statusCode === 200) { + const s3 = new S3Client({}); + const maxAttempts = 10; + const delay = 30000; // 30 seconds + + for (let attempt = 0; attempt < maxAttempts; attempt++) { + try { + await s3.send(new ListObjectsV2Command({ Bucket: bucket, MaxKeys: 1 })); + // If we get here, bucket still exists + if (attempt < maxAttempts - 1) { + await sleep(delay); + continue; + } return false; + } catch (error: any) { + if (error.name === 'NoSuchBucket') { + return true; + } + if (error.$metadata?.httpStatusCode === 404) { + return true; + } + if (attempt < maxAttempts - 1) { + await sleep(delay); + continue; + } + throw error; } - throw error; } + return false; }; /** @@ -365,13 +419,13 @@ const sleep = async (milliseconds: number): Promise => new Promise((resolv * @param region aws region to query for amplify Apps * @returns Promise a list of Amplify Apps in the region with build info */ -const getAmplifyApps = async (account: AWSAccountInfo, region: string, cbClient: CodeBuild): Promise => { +const getAmplifyApps = async (account: AWSAccountInfo, region: string, cbClient: CodeBuildClient): Promise => { if (region === 'us-east-1' && account.parent) { return []; // temporarily disabled until us-east-1 is re-enabled for this account } - const amplifyClient = new Amplify(getAWSConfig(account, region)); + const amplifyClient = new AmplifyClient(getAWSConfig(account, region)); try { - const amplifyApps = await amplifyClient.listApps({ maxResults: 25 }).promise(); // keeping it to 25 as max supported is 25 + const amplifyApps = await amplifyClient.send(new ListAppsCommand({ maxResults: 25 })); // keeping it to 25 as max supported is 25 const result: AmplifyAppInfo[] = []; for (const app of amplifyApps.apps) { if (!isStale(app.createTime)) { @@ -379,12 +433,12 @@ const getAmplifyApps = async (account: AWSAccountInfo, region: string, cbClient: } const backends: Record = {}; try { - const backendEnvironments = await amplifyClient.listBackendEnvironments({ appId: app.appId, maxResults: 5 }).promise(); + const backendEnvironments = await amplifyClient.send(new ListBackendEnvironmentsCommand({ appId: app.appId, maxResults: 5 })); for (const backendEnv of backendEnvironments.backendEnvironments) { if (backendEnv.stackName) { const buildInfo = await getStackDetails(backendEnv.stackName, account, region, cbClient); if (buildInfo) { - backends[backendEnv.environmentName] = buildInfo; + backends[backendEnv.environmentName!] = buildInfo; } } } @@ -392,8 +446,8 @@ const getAmplifyApps = async (account: AWSAccountInfo, region: string, cbClient: // console.log(e); } result.push({ - appId: app.appId, - name: app.name, + appId: app.appId!, + name: app.name!, region, backends, }); @@ -410,7 +464,7 @@ const getAmplifyApps = async (account: AWSAccountInfo, region: string, cbClient: * @param tags Tags associated with the resource * @returns build number or undefined */ -const getJobId = (tags: CloudFormation.Tags = []): string | undefined => { +const getJobId = (tags: Tag[] = []): string | undefined => { const jobId = tags.find((tag) => tag.Key === 'codebuild:build_id')?.Value; return jobId; }; @@ -425,17 +479,22 @@ const getJobId = (tags: CloudFormation.Tags = []): string | undefined => { * @param region region * @returns stack details */ -const getStackDetails = async (stackName: string, account: AWSAccountInfo, region: string, cbClient: CodeBuild): Promise => { - const cfnClient = new CloudFormation(getAWSConfig(account, region)); - const stack = await cfnClient.describeStacks({ StackName: stackName }).promise(); +const getStackDetails = async ( + stackName: string, + account: AWSAccountInfo, + region: string, + cbClient: CodeBuildClient, +): Promise => { + const cfnClient = new CloudFormationClient(getAWSConfig(account, region)); + const stack = await cfnClient.send(new DescribeStacksCommand({ StackName: stackName })); const tags = stack?.Stacks?.[0].Tags ?? []; const stackStatus = stack?.Stacks?.[0]?.StackStatus ?? 'UNDEFINED'; let resourcesFailedToDelete: string[] = []; if (stackStatus === 'DELETE_FAILED') { // Todo: We need to investigate if we should go ahead and remove the resources to prevent account getting cluttered - const resources = await cfnClient.listStackResources({ StackName: stackName }).promise(); + const resources = await cfnClient.send(new ListStackResourcesCommand({ StackName: stackName })); resourcesFailedToDelete = - resources?.StackResourceSummaries?.filter((r) => r.ResourceStatus === 'DELETE_FAILED').map((r) => r.LogicalResourceId) ?? []; + resources?.StackResourceSummaries?.filter((r) => r.ResourceStatus === 'DELETE_FAILED').map((r) => r.LogicalResourceId!) ?? []; } const jobId = getJobId(tags); return { @@ -443,39 +502,39 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio stackStatus, resourcesFailedToDelete, region, - tags: tags.reduce((acc, tag) => ({ ...acc, [tag.Key]: tag.Value }), {}), + tags: tags.reduce((acc, tag) => ({ ...acc, [tag.Key!]: tag.Value }), {}), cbInfo: jobId ? await getCIJobDetails(jobId, cbClient) : undefined, }; }; -const getStacks = async (account: AWSAccountInfo, region: string, cbClient: CodeBuild): Promise => { - const cfnClient = new CloudFormation(getAWSConfig(account, region)); +const getStacks = async (account: AWSAccountInfo, region: string, cbClient: CodeBuildClient): Promise => { + const cfnClient = new CloudFormationClient(getAWSConfig(account, region)); const stackStatusFilter = [ - 'CREATE_COMPLETE', - 'ROLLBACK_FAILED', - 'ROLLBACK_COMPLETE', - 'DELETE_FAILED', - 'UPDATE_COMPLETE', - 'UPDATE_ROLLBACK_FAILED', - 'UPDATE_ROLLBACK_COMPLETE', - 'IMPORT_COMPLETE', - 'IMPORT_ROLLBACK_FAILED', - 'IMPORT_ROLLBACK_COMPLETE', + StackStatus.CREATE_COMPLETE, + StackStatus.ROLLBACK_FAILED, + StackStatus.ROLLBACK_COMPLETE, + StackStatus.DELETE_FAILED, + StackStatus.UPDATE_COMPLETE, + StackStatus.UPDATE_ROLLBACK_FAILED, + StackStatus.UPDATE_ROLLBACK_COMPLETE, + StackStatus.IMPORT_COMPLETE, + StackStatus.IMPORT_ROLLBACK_FAILED, + StackStatus.IMPORT_ROLLBACK_COMPLETE, ]; - const stacks = await cfnClient - .listStacks({ + const stacks = await cfnClient.send( + new ListStacksCommand({ StackStatusFilter: stackStatusFilter, - }) - .promise(); + }), + ); // loop let nextToken = stacks.NextToken; while (nextToken && stacks?.StackSummaries?.length && stacks.StackSummaries.length < DELETE_LIMITS.PER_REGION.CFN_STACK) { - const nextPage = await cfnClient - .listStacks({ + const nextPage = await cfnClient.send( + new ListStacksCommand({ StackStatusFilter: stackStatusFilter, NextToken: nextToken, - }) - .promise(); + }), + ); if (nextPage?.StackSummaries?.length) { stacks.StackSummaries.push(...nextPage.StackSummaries); nextToken = nextPage.NextToken; @@ -505,7 +564,7 @@ const getStacks = async (account: AWSAccountInfo, region: string, cbClient: Code const results: StackInfo[] = []; for (const stack of rootStacks) { try { - const details = await getStackDetails(stack.StackName, account, region, cbClient); + const details = await getStackDetails(stack.StackName!, account, region, cbClient); if (details) { results.push(details); } @@ -516,16 +575,16 @@ const getStacks = async (account: AWSAccountInfo, region: string, cbClient: Code return results; }; -const getCIJobDetails = async (build_id: string, cbClient: CodeBuild): Promise => { - const batchBuilds = await cbClient.batchGetBuilds({ ids: [build_id] }).promise(); +const getCIJobDetails = async (build_id: string, cbClient: CodeBuildClient): Promise => { + const batchBuilds = await cbClient.send(new BatchGetBuildsCommand({ ids: [build_id] })); const buildInfo = batchBuilds?.builds?.[0]; return buildInfo; }; -const getS3Buckets = async (account: AWSAccountInfo, cbClient: CodeBuild): Promise => { - const s3Client = new S3(getAWSConfig(account)); - const buckets = await s3Client.listBuckets().promise(); +const getS3Buckets = async (account: AWSAccountInfo, cbClient: CodeBuildClient): Promise => { + const s3Client = new S3Client(getAWSConfig(account)); + const buckets = await s3Client.send(new ListBucketsCommand({})); if (buckets.Buckets === undefined) { return []; } @@ -535,7 +594,10 @@ const getS3Buckets = async (account: AWSAccountInfo, cbClient: CodeBuild): Promi continue; } try { - const bucketDetails = await s3Client.getBucketTagging({ Bucket: bucket.Name }).promise(); + const locationResponse = await s3Client.send(new GetBucketLocationCommand({ Bucket: bucket.Name })); + const bucketRegion = locationResponse.LocationConstraint || 'us-east-1'; + const bucketS3Client = new S3Client(getAWSConfig(account, bucketRegion)); + const bucketDetails = await bucketS3Client.send(new GetBucketTaggingCommand({ Bucket: bucket.Name })); const jobId = getJobId(bucketDetails.TagSet); if (jobId) { result.push({ @@ -545,7 +607,7 @@ const getS3Buckets = async (account: AWSAccountInfo, cbClient: CodeBuild): Promi }); } } catch (e) { - if (e.code !== 'NoSuchTagSet' && e.code !== 'NoSuchBucket') { + if (e.name !== 'NoSuchTagSet' && e.name !== 'NoSuchBucket') { throw e; } result.push({ @@ -695,12 +757,12 @@ const deleteAmplifyApps = async (account: AWSAccountInfo, accountIndex: number, const deleteAmplifyApp = async (account: AWSAccountInfo, accountIndex: number, app: AmplifyAppInfo): Promise => { const { name, appId, region } = app; console.log(`[ACCOUNT ${accountIndex}] Deleting App ${name}(${appId})`); - const amplifyClient = new Amplify(getAWSConfig(account, region)); + const amplifyClient = new AmplifyClient(getAWSConfig(account, region)); try { - await amplifyClient.deleteApp({ appId }).promise(); + await amplifyClient.send(new DeleteAppCommand({ appId })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting Amplify App ${appId} failed with the following error`, e); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -715,21 +777,21 @@ const deleteIamRole = async (account: AWSAccountInfo, accountIndex: number, role try { console.log(`[ACCOUNT ${accountIndex}] Deleting Iam Role ${roleName}`); console.log(`Role creation time (PST): ${role.createTime.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })}`); - const iamClient = new IAM(getAWSConfig(account)); + const iamClient = new IAMClient(getAWSConfig(account)); await deleteAttachedRolePolicies(account, accountIndex, roleName); await deleteRolePolicies(account, accountIndex, roleName); - await iamClient.deleteRole({ RoleName: roleName }).promise(); + await iamClient.send(new DeleteRoleCommand({ RoleName: roleName })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting iam role ${roleName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } }; const deleteAttachedRolePolicies = async (account: AWSAccountInfo, accountIndex: number, roleName: string): Promise => { - const iamClient = new IAM(getAWSConfig(account)); - const rolePolicies = await iamClient.listAttachedRolePolicies({ RoleName: roleName }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + const rolePolicies = await iamClient.send(new ListAttachedRolePoliciesCommand({ RoleName: roleName })); if (rolePolicies?.AttachedPolicies) { await Promise.all(rolePolicies.AttachedPolicies.map((policy) => detachIamAttachedRolePolicy(account, accountIndex, roleName, policy))); } @@ -739,16 +801,16 @@ const detachIamAttachedRolePolicy = async ( account: AWSAccountInfo, accountIndex: number, roleName: string, - policy: IAM.AttachedPolicy, + policy: AttachedPolicy, ): Promise => { if (policy?.PolicyArn) { try { console.log(`[ACCOUNT ${accountIndex}] Detach Iam Attached Role Policy ${policy.PolicyName}`); - const iamClient = new IAM(getAWSConfig(account)); - await iamClient.detachRolePolicy({ RoleName: roleName, PolicyArn: policy.PolicyArn }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + await iamClient.send(new DetachRolePolicyCommand({ RoleName: roleName, PolicyArn: policy.PolicyArn })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Detach iam role policy ${policy.PolicyName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -756,19 +818,19 @@ const detachIamAttachedRolePolicy = async ( }; const deleteRolePolicies = async (account: AWSAccountInfo, accountIndex: number, roleName: string): Promise => { - const iamClient = new IAM(getAWSConfig(account)); - const rolePolicies = await iamClient.listRolePolicies({ RoleName: roleName }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + const rolePolicies = await iamClient.send(new ListRolePoliciesCommand({ RoleName: roleName })); await Promise.all(rolePolicies.PolicyNames.map((policy) => deleteIamRolePolicy(account, accountIndex, roleName, policy))); }; const deleteIamRolePolicy = async (account: AWSAccountInfo, accountIndex: number, roleName: string, policyName: string): Promise => { try { console.log(`[ACCOUNT ${accountIndex}] Deleting Iam Role Policy ${policyName}`); - const iamClient = new IAM(getAWSConfig(account)); - await iamClient.deleteRolePolicy({ RoleName: roleName, PolicyName: policyName }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + await iamClient.send(new DeleteRolePolicyCommand({ RoleName: roleName, PolicyName: policyName })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting iam role policy ${policyName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -784,11 +846,14 @@ const deleteBucket = async (account: AWSAccountInfo, accountIndex: number, bucke try { console.log(`[ACCOUNT ${accountIndex}] Deleting S3 Bucket ${name}`); console.log(`Bucket creation time (PST): ${createTime?.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })}`); - const s3 = new S3(getAWSConfig(account)); - await deleteS3Bucket(name, s3); + const s3 = new S3Client(getAWSConfig(account)); + const locationResponse = await s3.send(new GetBucketLocationCommand({ Bucket: name })); + const bucketRegion = locationResponse.LocationConstraint || 'us-east-1'; + const regionalS3Client = new S3Client(getAWSConfig(account, bucketRegion)); + await deleteS3Bucket(name, regionalS3Client); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting bucket ${name} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -804,8 +869,8 @@ const deletePinpointApp = async (account: AWSAccountInfo, accountIndex: number, try { console.log(`[ACCOUNT ${accountIndex}] Deleting Pinpoint App ${name}`); console.log(`Pinpoint creation time (PST): ${app.createTime.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })}`); - const pinpoint = new Pinpoint(getAWSConfig(account, region)); - await pinpoint.deleteApp({ ApplicationId: id }).promise(); + const pinpoint = new PinpointClient(getAWSConfig(account, region)); + await pinpoint.send(new DeletePinpointAppCommand({ ApplicationId: id })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting pinpoint app ${name} failed with error ${e.message}`); } @@ -820,8 +885,8 @@ const deleteAppSyncApi = async (account: AWSAccountInfo, accountIndex: number, a if (apiId) { try { console.log(`[ACCOUNT ${accountIndex}] Deleting AppSync Api ${name}`); - const appSync = new AppSync(getAWSConfig(account, region)); - await appSync.deleteGraphqlApi({ apiId }).promise(); + const appSync = new AppSyncClient(getAWSConfig(account, region)); + await appSync.send(new DeleteGraphqlApiCommand({ apiId })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting AppSync Api ${name} failed with error ${e.message}`); } @@ -839,17 +904,17 @@ const deleteUserPool = async (account: AWSAccountInfo, accountIndex: number, use } try { console.log(`[ACCOUNT ${accountIndex}] Deleting UserPool ${name}`); - const cognitoClient = new CognitoIdentityServiceProvider(getAWSConfig(account, region)); - const userPoolDetails = await cognitoClient.describeUserPool({ UserPoolId: userPoolId }).promise(); + const cognitoClient = new CognitoIdentityProviderClient(getAWSConfig(account, region)); + const userPoolDetails = await cognitoClient.send(new DescribeUserPoolCommand({ UserPoolId: userPoolId })); if (userPoolDetails?.UserPool?.Domain) { - await cognitoClient - .deleteUserPoolDomain({ + await cognitoClient.send( + new DeleteUserPoolDomainCommand({ UserPoolId: userPoolId, Domain: userPoolDetails.UserPool.Domain, - }) - .promise(); + }), + ); } - await cognitoClient.deleteUserPool({ UserPoolId: userPoolId }).promise(); + await cognitoClient.send(new DeleteUserPoolCommand({ UserPoolId: userPoolId })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting UserPool ${name} failed with error ${e.message}`); } @@ -864,13 +929,35 @@ const deleteCfnStack = async (account: AWSAccountInfo, accountIndex: number, sta const resourceToRetain = resourcesFailedToDelete?.length ? resourcesFailedToDelete : undefined; console.log(`[ACCOUNT ${accountIndex}] Deleting CloudFormation stack ${stackName}`); try { - const cfnClient = new CloudFormation(getAWSConfig(account, region)); - await cfnClient.deleteStack({ StackName: stackName, RetainResources: resourceToRetain }).promise(); + const cfnClient = new CloudFormationClient(getAWSConfig(account, region)); + await cfnClient.send(new DeleteStackCommand({ StackName: stackName, RetainResources: resourceToRetain })); // we'll only wait up to a minute before moving on - await cfnClient.waitFor('stackDeleteComplete', { StackName: stackName, $waiter: { maxAttempts: 2 } }).promise(); + const maxAttempts = 2; + for (let attempt = 0; attempt < maxAttempts; attempt++) { + try { + const result = await cfnClient.send(new DescribeStacksCommand({ StackName: stackName })); + const stackStatus = result.Stacks?.[0]?.StackStatus; + if (stackStatus === 'DELETE_COMPLETE') { + break; + } + if (stackStatus === 'DELETE_FAILED') { + console.log(`Stack ${stackName} deletion failed`); + break; + } + if (attempt < maxAttempts - 1) { + await sleep(30000); // wait 30 seconds + } + } catch (e: any) { + if (e.name === 'ValidationError' && e.message?.includes('does not exist')) { + // Stack was deleted successfully + break; + } + throw e; + } + } } catch (e) { console.log(`Deleting CloudFormation stack ${stackName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -938,24 +1025,26 @@ const deleteResources = async ( * to get all accounts within the root account organization. */ const getAccountsToCleanup = async (): Promise => { - const stsRes = new STS({ + const stsRes = new STSClient({ apiVersion: '2011-06-15', - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, - sessionToken: process.env.AWS_SESSION_TOKEN, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID!, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!, + sessionToken: process.env.AWS_SESSION_TOKEN!, + }, }); - const parentAccountIdentity = await stsRes.getCallerIdentity().promise(); - const orgApi = new Organizations({ + const parentAccountIdentity = await stsRes.send(new GetCallerIdentityCommand({})); + const orgApi = new OrganizationsClient({ apiVersion: '2016-11-28', // the region where the organization exists region: 'us-east-1', }); try { - const orgAccounts = await orgApi.listAccounts().promise(); + const orgAccounts = await orgApi.send(new ListAccountsCommand({})); const allAccounts = orgAccounts.Accounts ?? []; let nextToken = orgAccounts.NextToken; while (nextToken) { - const nextPage = await orgApi.listAccounts({ NextToken: nextToken }).promise(); + const nextPage = await orgApi.send(new ListAccountsCommand({ NextToken: nextToken })); if (!nextPage?.Accounts?.length) { break; } @@ -967,14 +1056,14 @@ const getAccountsToCleanup = async (): Promise => { return getEnvVarCredentials(); } const randomNumber = Math.floor(Math.random() * 100000); - const assumeRoleRes = await stsRes - .assumeRole({ + const assumeRoleRes = await stsRes.send( + new AssumeRoleCommand({ RoleArn: `arn:aws:iam::${account.Id}:role/OrganizationAccountAccessRole`, RoleSessionName: `testSession${randomNumber}`, // One hour DurationSeconds: 1 * 60 * 60, - }) - .promise(); + }), + ); const accessKeyId = assumeRoleRes?.Credentials?.AccessKeyId ?? ''; const secretAccessKey = assumeRoleRes?.Credentials?.SecretAccessKey ?? ''; @@ -1012,7 +1101,7 @@ const getEnvVarCredentials = (): AWSAccountInfo => { }; const cleanupAccount = async (account: AWSAccountInfo, accountIndex: number, filterPredicate: JobFilterPredicate): Promise => { - const cbClient = new CodeBuild(getAWSConfig(account)); + const cbClient = new CodeBuildClient(getAWSConfig(account)); const appPromises = AWS_REGIONS_TO_RUN_TESTS.map((region) => getAmplifyApps(account, region, cbClient)); const stackPromises = AWS_REGIONS_TO_RUN_TESTS.map((region) => getStacks(account, region, cbClient)); const bucketPromise = getS3Buckets(account, cbClient); @@ -1070,7 +1159,7 @@ const cleanupAccount = async (account: AWSAccountInfo, accountIndex: number, fil * of account ids since the logs these are written to will be effectively public. */ const cleanup = async (): Promise => { - const filterPredicateStaleResources = (job: ReportEntry) => job?.cbInfo?.buildStatus === 'finished' || job.jobId === ORPHAN; + const filterPredicateStaleResources = (job: ReportEntry) => job?.cbInfo?.buildStatus !== StatusType.IN_PROGRESS || job.jobId === ORPHAN; const accounts = await getAccountsToCleanup(); for (let i = 0; i < 3; ++i) { console.log('CLEANUP ROUND: ', i + 1); diff --git a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts index 83da29fa3b5..68d6eba3445 100644 --- a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts @@ -2,7 +2,48 @@ /* eslint-disable spellcheck/spell-checker */ import { config } from 'dotenv'; import yargs from 'yargs'; -import * as aws from 'aws-sdk'; +import { S3Client, ListBucketsCommand, GetBucketTaggingCommand, GetBucketLocationCommand, Bucket } from '@aws-sdk/client-s3'; +import { + IAMClient, + ListRolesCommand, + ListOpenIDConnectProvidersCommand, + DeleteOpenIDConnectProviderCommand, + DeleteRoleCommand, + ListAttachedRolePoliciesCommand, + DetachRolePolicyCommand, + ListRolePoliciesCommand, + DeleteRolePolicyCommand, + Role, + AttachedPolicy, +} from '@aws-sdk/client-iam'; +import { PinpointClient, GetAppsCommand, DeleteAppCommand, ApplicationResponse } from '@aws-sdk/client-pinpoint'; +import { + CognitoIdentityProviderClient, + ListUserPoolsCommand, + DescribeUserPoolCommand, + DeleteUserPoolDomainCommand, + DeleteUserPoolCommand, + UserPoolDescriptionType, +} from '@aws-sdk/client-cognito-identity-provider'; +import { AppSyncClient, ListGraphqlApisCommand, DeleteGraphqlApiCommand } from '@aws-sdk/client-appsync'; +import { + AmplifyClient, + ListAppsCommand, + ListBackendEnvironmentsCommand, + DeleteAppCommand as AmplifyDeleteAppCommand, +} from '@aws-sdk/client-amplify'; +import { + CloudFormationClient, + DescribeStacksCommand, + ListStackResourcesCommand, + ListStacksCommand, + DeleteStackCommand, + waitUntilStackDeleteComplete, + StackStatus, + Tag, +} from '@aws-sdk/client-cloudformation'; +import { STSClient, GetCallerIdentityCommand, AssumeRoleCommand } from '@aws-sdk/client-sts'; +import { OrganizationsClient, ListAccountsCommand } from '@aws-sdk/client-organizations'; import _ from 'lodash'; import fs from 'fs-extra'; import path from 'path'; @@ -147,22 +188,22 @@ const isStale = (created: Date): boolean => { /** * We define a resource as viable for deletion if it matches TEST_REGEX in the name, and if it is > STALE_DURATION_MS old. */ -const testBucketStalenessFilter = (resource: aws.S3.Bucket): boolean => { +const testBucketStalenessFilter = (resource: Bucket): boolean => { const isTestResource = resource.Name.match(BUCKET_TEST_REGEX); return isTestResource && isStale(resource.CreationDate); }; -const testRoleStalenessFilter = (resource: aws.IAM.Role): boolean => { +const testRoleStalenessFilter = (resource: Role): boolean => { const isTestResource = resource.RoleName.match(IAM_TEST_REGEX); return isTestResource && isStale(resource.CreateDate); }; -const testUserPoolStalenessFilter = (resource: aws.CognitoIdentityServiceProvider.UserPoolDescriptionType): boolean => { +const testUserPoolStalenessFilter = (resource: UserPoolDescriptionType): boolean => { const isTestResource = resource.Name.match(USER_POOL_TEST_REGEX); return isTestResource && isStale(resource.CreationDate); }; -const testAppSyncApiStalenessFilter = (resource: aws.AppSync.GraphqlApi): boolean => { +const testAppSyncApiStalenessFilter = (resource: any): boolean => { const isTestResource = resource.name.match(APPSYNC_TEST_REGEX); const createTimeTagValue = resource.tags['circleci:create_time']; let isStaleResource = true; @@ -173,7 +214,7 @@ const testAppSyncApiStalenessFilter = (resource: aws.AppSync.GraphqlApi): boolea return isTestResource && isStaleResource; }; -const testPinpointAppStalenessFilter = (resource: aws.Pinpoint.ApplicationResponse): boolean => { +const testPinpointAppStalenessFilter = (resource: ApplicationResponse): boolean => { const isTestResource = resource.Name.match(PINPOINT_TEST_REGEX); return isTestResource && isStale(new Date(resource.CreationDate)); }; @@ -182,8 +223,8 @@ const testPinpointAppStalenessFilter = (resource: aws.Pinpoint.ApplicationRespon * Get all S3 buckets in the account, and filter down to the ones we consider stale. */ const getOrphanS3TestBuckets = async (account: AWSAccountInfo): Promise => { - const s3Client = new aws.S3(getAWSConfig(account)); - const listBucketResponse = await s3Client.listBuckets().promise(); + const s3Client = new S3Client(getAWSConfig(account)); + const listBucketResponse = await s3Client.send(new ListBucketsCommand({})); const staleBuckets = listBucketResponse.Buckets.filter(testBucketStalenessFilter); return staleBuckets.map((it) => ({ name: it.Name, createTime: it.CreationDate })); }; @@ -192,23 +233,23 @@ const getOrphanS3TestBuckets = async (account: AWSAccountInfo): Promise => { - const iamClient = new aws.IAM(getAWSConfig(account)); - const listRoleResponse = await iamClient.listRoles({ MaxItems: 1000 }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + const listRoleResponse = await iamClient.send(new ListRolesCommand({ MaxItems: 1000 })); const staleRoles = listRoleResponse.Roles.filter(testRoleStalenessFilter); return staleRoles.map((it) => ({ name: it.RoleName, createTime: it.CreateDate })); }; const getOrphanPinpointApplications = async (account: AWSAccountInfo, region: string): Promise => { - const pinpoint = new aws.Pinpoint(getAWSConfig(account, region)); + const pinpoint = new PinpointClient(getAWSConfig(account, region)); const apps: PinpointAppInfo[] = []; let nextToken = null; do { - const result = await pinpoint - .getApps({ + const result = await pinpoint.send( + new GetAppsCommand({ Token: nextToken, - }) - .promise(); + }), + ); apps.push( ...result.ApplicationsResponse.Item.filter(testPinpointAppStalenessFilter).map((it) => ({ id: it.Id, @@ -226,8 +267,8 @@ const getOrphanPinpointApplications = async (account: AWSAccountInfo, region: st }; const getOrphanUserPools = async (account: AWSAccountInfo, region: string): Promise => { - const cognitoClient = new aws.CognitoIdentityServiceProvider(getAWSConfig(account, region)); - const userPools = await cognitoClient.listUserPools({ MaxResults: 60 }).promise(); + const cognitoClient = new CognitoIdentityProviderClient(getAWSConfig(account, region)); + const userPools = await cognitoClient.send(new ListUserPoolsCommand({ MaxResults: 60 })); const staleUserPools = userPools.UserPools.filter(testUserPoolStalenessFilter); return staleUserPools.map((it) => ({ name: it.Name, userPoolId: it.Id, region })); }; @@ -236,8 +277,8 @@ const getOrphanUserPools = async (account: AWSAccountInfo, region: string): Prom * Get all AppSync Apis in the account, and filter down to the ones we consider stale. */ const getOrphanAppSyncApis = async (account: AWSAccountInfo, region: string): Promise => { - const appSyncClient = new aws.AppSync(getAWSConfig(account, region)); - const listApisResponse = await appSyncClient.listGraphqlApis({ maxResults: 25 }).promise(); + const appSyncClient = new AppSyncClient(getAWSConfig(account, region)); + const listApisResponse = await appSyncClient.send(new ListGraphqlApisCommand({ maxResults: 25 })); const staleApis = listApisResponse.graphqlApis.filter(testAppSyncApiStalenessFilter); return staleApis.map((it) => ({ apiId: it.apiId, name: it.name, region })); }; @@ -246,14 +287,14 @@ const getOrphanAppSyncApis = async (account: AWSAccountInfo, region: string): Pr * Get all OIDC providers in the account that match */ const deleteOrphanedOidcProviders = async (account: AWSAccountInfo): Promise => { - const iamClient = new aws.IAM(getAWSConfig(account)); - const response = await iamClient.listOpenIDConnectProviders().promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + const response = await iamClient.send(new ListOpenIDConnectProvidersCommand({})); if (response.OpenIDConnectProviderList) { for (const provider of response.OpenIDConnectProviderList) { // these seem to be the only offending resources at this time, but we can add more later if (provider.Arn.endsWith('oidc-provider/accounts.google.com')) { console.log('OIDC PROVIDER:', provider.Arn); - await iamClient.deleteOpenIDConnectProvider({ OpenIDConnectProviderArn: provider.Arn }).promise(); + await iamClient.send(new DeleteOpenIDConnectProviderCommand({ OpenIDConnectProviderArn: provider.Arn })); } } } @@ -262,14 +303,14 @@ const deleteOrphanedOidcProviders = async (account: AWSAccountInfo): Promise ({ +const getAWSConfig = ({ accessKeyId, secretAccessKey, sessionToken }: AWSAccountInfo, region?: string): any => ({ credentials: { accessKeyId, secretAccessKey, sessionToken, }, ...(region ? { region } : {}), - maxRetries: 10, + maxAttempts: 10, }); /** @@ -280,9 +321,9 @@ const getAWSConfig = ({ accessKeyId, secretAccessKey, sessionToken }: AWSAccount * @returns Promise a list of Amplify Apps in the region with build info */ const getAmplifyApps = async (account: AWSAccountInfo, region: string): Promise => { - const amplifyClient = new aws.Amplify(getAWSConfig(account, region)); + const amplifyClient = new AmplifyClient(getAWSConfig(account, region)); try { - const amplifyApps = await amplifyClient.listApps({ maxResults: 25 }).promise(); // keeping it to 25 as max supported is 25 + const amplifyApps = await amplifyClient.send(new ListAppsCommand({ maxResults: 25 })); // keeping it to 25 as max supported is 25 const result: AmplifyAppInfo[] = []; for (const app of amplifyApps.apps) { if (!isStale(app.createTime)) { @@ -290,7 +331,7 @@ const getAmplifyApps = async (account: AWSAccountInfo, region: string): Promise< } const backends: Record = {}; try { - const backendEnvironments = await amplifyClient.listBackendEnvironments({ appId: app.appId, maxResults: 5 }).promise(); + const backendEnvironments = await amplifyClient.send(new ListBackendEnvironmentsCommand({ appId: app.appId, maxResults: 5 })); for (const backendEnv of backendEnvironments.backendEnvironments) { const buildInfo = await getStackDetails(backendEnv.stackName, account, region); if (buildInfo) { @@ -319,7 +360,7 @@ const getAmplifyApps = async (account: AWSAccountInfo, region: string): Promise< * @param tags Tags associated with the resource * @returns build number or undefined */ -const getJobId = (tags: aws.CloudFormation.Tags = []): number | undefined => { +const getJobId = (tags: Tag[] = []): number | undefined => { const jobId = tags.find((tag) => tag.Key === 'circleci:build_id')?.Value; return jobId && Number.parseInt(jobId, 10); }; @@ -335,14 +376,14 @@ const getJobId = (tags: aws.CloudFormation.Tags = []): number | undefined => { * @returns stack details */ const getStackDetails = async (stackName: string, account: AWSAccountInfo, region: string): Promise => { - const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); - const stack = await cfnClient.describeStacks({ StackName: stackName }).promise(); + const cfnClient = new CloudFormationClient(getAWSConfig(account, region)); + const stack = await cfnClient.send(new DescribeStacksCommand({ StackName: stackName })); const tags = stack.Stacks.length && stack.Stacks[0].Tags; const stackStatus = stack.Stacks[0].StackStatus; let resourcesFailedToDelete: string[] = []; if (stackStatus === 'DELETE_FAILED') { // Todo: We need to investigate if we should go ahead and remove the resources to prevent account getting cluttered - const resources = await cfnClient.listStackResources({ StackName: stackName }).promise(); + const resources = await cfnClient.send(new ListStackResourcesCommand({ StackName: stackName })); resourcesFailedToDelete = resources.StackResourceSummaries.filter((r) => r.ResourceStatus === 'DELETE_FAILED').map( (r) => r.LogicalResourceId, ); @@ -357,33 +398,33 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio }; const getStacks = async (account: AWSAccountInfo, region: string): Promise => { - const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); + const cfnClient = new CloudFormationClient(getAWSConfig(account, region)); const stackStatusFilter = [ - 'CREATE_COMPLETE', - 'ROLLBACK_FAILED', - 'ROLLBACK_COMPLETE', - 'DELETE_FAILED', - 'UPDATE_COMPLETE', - 'UPDATE_ROLLBACK_FAILED', - 'UPDATE_ROLLBACK_COMPLETE', - 'IMPORT_COMPLETE', - 'IMPORT_ROLLBACK_FAILED', - 'IMPORT_ROLLBACK_COMPLETE', + StackStatus.CREATE_COMPLETE, + StackStatus.ROLLBACK_FAILED, + StackStatus.ROLLBACK_COMPLETE, + StackStatus.DELETE_FAILED, + StackStatus.UPDATE_COMPLETE, + StackStatus.UPDATE_ROLLBACK_FAILED, + StackStatus.UPDATE_ROLLBACK_COMPLETE, + StackStatus.IMPORT_COMPLETE, + StackStatus.IMPORT_ROLLBACK_FAILED, + StackStatus.IMPORT_ROLLBACK_COMPLETE, ]; - const stacks = await cfnClient - .listStacks({ + const stacks = await cfnClient.send( + new ListStacksCommand({ StackStatusFilter: stackStatusFilter, - }) - .promise(); + }), + ); // loop let nextToken = stacks.NextToken; while (nextToken && stacks.StackSummaries.length < DELETE_LIMITS.PER_REGION.CFN_STACK) { - const nextPage = await cfnClient - .listStacks({ + const nextPage = await cfnClient.send( + new ListStacksCommand({ StackStatusFilter: stackStatusFilter, NextToken: nextToken, - }) - .promise(); + }), + ); stacks.StackSummaries.push(...nextPage.StackSummaries); nextToken = nextPage.NextToken; } @@ -421,12 +462,15 @@ const getStacks = async (account: AWSAccountInfo, region: string): Promise => { - const s3Client = new aws.S3(getAWSConfig(account)); - const buckets = await s3Client.listBuckets().promise(); + const s3Client = new S3Client(getAWSConfig(account)); + const buckets = await s3Client.send(new ListBucketsCommand({})); const result: S3BucketInfo[] = []; for (const bucket of buckets.Buckets) { try { - const bucketDetails = await s3Client.getBucketTagging({ Bucket: bucket.Name }).promise(); + const locationResponse = await s3Client.send(new GetBucketLocationCommand({ Bucket: bucket.Name })); + const bucketRegion = locationResponse.LocationConstraint || 'us-east-1'; + const bucketS3Client = new S3Client(getAWSConfig(account, bucketRegion)); + const bucketDetails = await bucketS3Client.send(new GetBucketTaggingCommand({ Bucket: bucket.Name })); const jobId = getJobId(bucketDetails.TagSet); if (jobId) { result.push({ @@ -435,7 +479,7 @@ const getS3Buckets = async (account: AWSAccountInfo): Promise => }); } } catch (e) { - if (e.code !== 'NoSuchTagSet' && e.code !== 'NoSuchBucket') { + if (e.name !== 'NoSuchTagSet' && e.name !== 'NoSuchBucket') { throw e; } result.push({ @@ -586,12 +630,12 @@ const deleteAmplifyApps = async (account: AWSAccountInfo, accountIndex: number, const deleteAmplifyApp = async (account: AWSAccountInfo, accountIndex: number, app: AmplifyAppInfo): Promise => { const { name, appId, region } = app; console.log(`[ACCOUNT ${accountIndex}] Deleting App ${name}(${appId})`); - const amplifyClient = new aws.Amplify(getAWSConfig(account, region)); + const amplifyClient = new AmplifyClient(getAWSConfig(account, region)); try { - await amplifyClient.deleteApp({ appId }).promise(); + await amplifyClient.send(new AmplifyDeleteAppCommand({ appId })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting Amplify App ${appId} failed with the following error`, e); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -606,21 +650,21 @@ const deleteIamRole = async (account: AWSAccountInfo, accountIndex: number, role try { console.log(`[ACCOUNT ${accountIndex}] Deleting Iam Role ${roleName}`); console.log(`Role creation time (PST): ${role.createTime.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })}`); - const iamClient = new aws.IAM(getAWSConfig(account)); + const iamClient = new IAMClient(getAWSConfig(account)); await deleteAttachedRolePolicies(account, accountIndex, roleName); await deleteRolePolicies(account, accountIndex, roleName); - await iamClient.deleteRole({ RoleName: roleName }).promise(); + await iamClient.send(new DeleteRoleCommand({ RoleName: roleName })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting iam role ${roleName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } }; const deleteAttachedRolePolicies = async (account: AWSAccountInfo, accountIndex: number, roleName: string): Promise => { - const iamClient = new aws.IAM(getAWSConfig(account)); - const rolePolicies = await iamClient.listAttachedRolePolicies({ RoleName: roleName }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + const rolePolicies = await iamClient.send(new ListAttachedRolePoliciesCommand({ RoleName: roleName })); await Promise.all(rolePolicies.AttachedPolicies.map((policy) => detachIamAttachedRolePolicy(account, accountIndex, roleName, policy))); }; @@ -628,34 +672,34 @@ const detachIamAttachedRolePolicy = async ( account: AWSAccountInfo, accountIndex: number, roleName: string, - policy: aws.IAM.AttachedPolicy, + policy: AttachedPolicy, ): Promise => { try { console.log(`[ACCOUNT ${accountIndex}] Detach Iam Attached Role Policy ${policy.PolicyName}`); - const iamClient = new aws.IAM(getAWSConfig(account)); - await iamClient.detachRolePolicy({ RoleName: roleName, PolicyArn: policy.PolicyArn }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + await iamClient.send(new DetachRolePolicyCommand({ RoleName: roleName, PolicyArn: policy.PolicyArn })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Detach iam role policy ${policy.PolicyName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } }; const deleteRolePolicies = async (account: AWSAccountInfo, accountIndex: number, roleName: string): Promise => { - const iamClient = new aws.IAM(getAWSConfig(account)); - const rolePolicies = await iamClient.listRolePolicies({ RoleName: roleName }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + const rolePolicies = await iamClient.send(new ListRolePoliciesCommand({ RoleName: roleName })); await Promise.all(rolePolicies.PolicyNames.map((policy) => deleteIamRolePolicy(account, accountIndex, roleName, policy))); }; const deleteIamRolePolicy = async (account: AWSAccountInfo, accountIndex: number, roleName: string, policyName: string): Promise => { try { console.log(`[ACCOUNT ${accountIndex}] Deleting Iam Role Policy ${policyName}`); - const iamClient = new aws.IAM(getAWSConfig(account)); - await iamClient.deleteRolePolicy({ RoleName: roleName, PolicyName: policyName }).promise(); + const iamClient = new IAMClient(getAWSConfig(account)); + await iamClient.send(new DeleteRolePolicyCommand({ RoleName: roleName, PolicyName: policyName })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting iam role policy ${policyName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -670,11 +714,14 @@ const deleteBucket = async (account: AWSAccountInfo, accountIndex: number, bucke try { console.log(`[ACCOUNT ${accountIndex}] Deleting S3 Bucket ${name}`); console.log(`Bucket creation time (PST): ${bucket.createTime.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })}`); - const s3 = new aws.S3(getAWSConfig(account)); - await deleteS3Bucket(name, s3); + const s3 = new S3Client(getAWSConfig(account)); + const locationReponse = await s3.send(new GetBucketLocationCommand({ Bucket: name })); + const bucketRegion = locationReponse.LocationConstraint || 'us-east-1'; + const regionalS3Client = new S3Client(getAWSConfig(account, bucketRegion)); + await deleteS3Bucket(name, regionalS3Client); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting bucket ${name} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -689,8 +736,8 @@ const deletePinpointApp = async (account: AWSAccountInfo, accountIndex: number, try { console.log(`[ACCOUNT ${accountIndex}] Deleting Pinpoint App ${name}`); console.log(`Pinpoint creation time (PST): ${app.createTime.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })}`); - const pinpoint = new aws.Pinpoint(getAWSConfig(account, region)); - await pinpoint.deleteApp({ ApplicationId: id }).promise(); + const pinpoint = new PinpointClient(getAWSConfig(account, region)); + await pinpoint.send(new DeleteAppCommand({ ApplicationId: id })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting pinpoint app ${name} failed with error ${e.message}`); } @@ -704,8 +751,8 @@ const deleteAppSyncApi = async (account: AWSAccountInfo, accountIndex: number, a const { apiId, name, region } = api; try { console.log(`[ACCOUNT ${accountIndex}] Deleting AppSync Api ${name}`); - const appSync = new aws.AppSync(getAWSConfig(account, region)); - await appSync.deleteGraphqlApi({ apiId }).promise(); + const appSync = new AppSyncClient(getAWSConfig(account, region)); + await appSync.send(new DeleteGraphqlApiCommand({ apiId })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting AppSync Api ${name} failed with error ${e.message}`); } @@ -719,17 +766,17 @@ const deleteUserPool = async (account: AWSAccountInfo, accountIndex: number, use const { name, region, userPoolId } = userPool; try { console.log(`[ACCOUNT ${accountIndex}] Deleting UserPool ${name}`); - const cognitoClient = new aws.CognitoIdentityServiceProvider(getAWSConfig(account, region)); - const userPoolDetails = await cognitoClient.describeUserPool({ UserPoolId: userPoolId }).promise(); + const cognitoClient = new CognitoIdentityProviderClient(getAWSConfig(account, region)); + const userPoolDetails = await cognitoClient.send(new DescribeUserPoolCommand({ UserPoolId: userPoolId })); if (userPoolDetails.UserPool.Domain) { - await cognitoClient - .deleteUserPoolDomain({ + await cognitoClient.send( + new DeleteUserPoolDomainCommand({ UserPoolId: userPoolId, Domain: userPoolDetails.UserPool.Domain, - }) - .promise(); + }), + ); } - await cognitoClient.deleteUserPool({ UserPoolId: userPoolId }).promise(); + await cognitoClient.send(new DeleteUserPoolCommand({ UserPoolId: userPoolId })); } catch (e) { console.log(`[ACCOUNT ${accountIndex}] Deleting UserPool ${name} failed with error ${e.message}`); } @@ -744,13 +791,13 @@ const deleteCfnStack = async (account: AWSAccountInfo, accountIndex: number, sta const resourceToRetain = resourcesFailedToDelete.length ? resourcesFailedToDelete : undefined; console.log(`[ACCOUNT ${accountIndex}] Deleting CloudFormation stack ${stackName}`); try { - const cfnClient = new aws.CloudFormation(getAWSConfig(account, region)); - await cfnClient.deleteStack({ StackName: stackName, RetainResources: resourceToRetain }).promise(); + const cfnClient = new CloudFormationClient(getAWSConfig(account, region)); + await cfnClient.send(new DeleteStackCommand({ StackName: stackName, RetainResources: resourceToRetain })); // we'll only wait up to a minute before moving on - await cfnClient.waitFor('stackDeleteComplete', { StackName: stackName, $waiter: { maxAttempts: 2 } }).promise(); + await waitUntilStackDeleteComplete({ client: cfnClient, maxWaitTime: 120 }, { StackName: stackName }); } catch (e) { console.log(`Deleting CloudFormation stack ${stackName} failed with error ${e.message}`); - if (e.code === 'ExpiredTokenException') { + if (e.name === 'ExpiredTokenException') { handleExpiredTokenException(); } } @@ -842,24 +889,25 @@ const getFilterPredicate = (args: any): JobFilterPredicate => { * to get all accounts within the root account organization. */ const getAccountsToCleanup = async (): Promise => { - const stsRes = new aws.STS({ - apiVersion: '2011-06-15', - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, - sessionToken: process.env.AWS_SESSION_TOKEN, + const stsRes = new STSClient({ + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + sessionToken: process.env.AWS_SESSION_TOKEN, + }, + endpoint: 'https://sts.amazonaws.com', }); - const parentAccountIdentity = await stsRes.getCallerIdentity().promise(); - const orgApi = new aws.Organizations({ - apiVersion: '2016-11-28', + const parentAccountIdentity = await stsRes.send(new GetCallerIdentityCommand({})); + const orgApi = new OrganizationsClient({ // the region where the organization exists region: 'us-east-1', }); try { - const orgAccounts = await orgApi.listAccounts().promise(); + const orgAccounts = await orgApi.send(new ListAccountsCommand({})); const allAccounts = orgAccounts.Accounts; let nextToken = orgAccounts.NextToken; while (nextToken) { - const nextPage = await orgApi.listAccounts({ NextToken: nextToken }).promise(); + const nextPage = await orgApi.send(new ListAccountsCommand({ NextToken: nextToken })); allAccounts.push(...nextPage.Accounts); nextToken = nextPage.NextToken; } @@ -873,14 +921,14 @@ const getAccountsToCleanup = async (): Promise => { }; } const randomNumber = Math.floor(Math.random() * 100000); - const assumeRoleRes = await stsRes - .assumeRole({ + const assumeRoleRes = await stsRes.send( + new AssumeRoleCommand({ RoleArn: `arn:aws:iam::${account.Id}:role/OrganizationAccountAccessRole`, RoleSessionName: `testSession${randomNumber}`, // One hour DurationSeconds: 1 * 60 * 60, - }) - .promise(); + }), + ); return { accessKeyId: assumeRoleRes.Credentials.AccessKeyId, secretAccessKey: assumeRoleRes.Credentials.SecretAccessKey, diff --git a/packages/amplify-e2e-tests/src/import-helpers/types.ts b/packages/amplify-e2e-tests/src/import-helpers/types.ts index 548763ec902..fc44773bd60 100644 --- a/packages/amplify-e2e-tests/src/import-helpers/types.ts +++ b/packages/amplify-e2e-tests/src/import-helpers/types.ts @@ -1,11 +1,4 @@ -import { - BooleanType, - CallbackURLsListType, - OAuthFlowsType, - ScopeListType, - SupportedIdentityProvidersListType, -} from 'aws-sdk/clients/cognitoidentityserviceprovider'; - +import { CreateUserPoolClientCommandInput } from '@aws-sdk/client-cognito-identity-provider'; import { $TSObject } from '@aws-amplify/amplify-cli-core'; export type AuthProjectDetails = { @@ -92,10 +85,10 @@ export type DynamoDBProjectDetails = { }; export type AppClientSettings = { - allowedOAuthFlows?: OAuthFlowsType; - callbackURLs?: CallbackURLsListType; - logoutURLs?: CallbackURLsListType; - allowedScopes?: ScopeListType; - supportedIdentityProviders?: SupportedIdentityProvidersListType; - allowedOAuthFlowsUserPoolClient?: BooleanType; + allowedOAuthFlows?: CreateUserPoolClientCommandInput['AllowedOAuthFlows']; + callbackURLs?: CreateUserPoolClientCommandInput['CallbackURLs']; + logoutURLs?: CreateUserPoolClientCommandInput['LogoutURLs']; + allowedScopes?: CreateUserPoolClientCommandInput['AllowedOAuthScopes']; + supportedIdentityProviders?: CreateUserPoolClientCommandInput['SupportedIdentityProviders']; + allowedOAuthFlowsUserPoolClient?: CreateUserPoolClientCommandInput['AllowedOAuthFlowsUserPoolClient']; }; diff --git a/packages/amplify-e2e-tests/src/import-helpers/utilities.ts b/packages/amplify-e2e-tests/src/import-helpers/utilities.ts index ba18f8e869e..9b575cd4cd8 100644 --- a/packages/amplify-e2e-tests/src/import-helpers/utilities.ts +++ b/packages/amplify-e2e-tests/src/import-helpers/utilities.ts @@ -8,7 +8,12 @@ import { getProjectMeta, getTeamProviderInfo, } from '@aws-amplify/amplify-e2e-core'; -import * as aws from 'aws-sdk'; +import { + CognitoIdentityProviderClient, + CreateUserPoolClientCommand, + DeleteUserPoolClientCommand, +} from '@aws-sdk/client-cognito-identity-provider'; +import { fromIni } from '@aws-sdk/credential-providers'; import * as fs from 'fs-extra'; import _ from 'lodash'; import * as path from 'path'; @@ -295,14 +300,14 @@ const addAppClient = async ( ) => { const projectDetails = getProjectMeta(projectRoot); const authDetails = getAuthProjectDetails(projectRoot); - const creds = new aws.SharedIniFileCredentials({ profile: profileName }); + const creds = fromIni({ profile: profileName }); - const cognitoClient = new aws.CognitoIdentityServiceProvider({ + const cognitoClient = new CognitoIdentityProviderClient({ credentials: creds, region: projectDetails.providers.awscloudformation.Region, }); - const response = await cognitoClient - .createUserPoolClient({ + const response = await cognitoClient.send( + new CreateUserPoolClientCommand({ ClientName: clientName, UserPoolId: authDetails.meta.UserPoolId, GenerateSecret: generateSecret, @@ -312,8 +317,8 @@ const addAppClient = async ( AllowedOAuthScopes: settings.allowedScopes, SupportedIdentityProviders: settings.supportedIdentityProviders, AllowedOAuthFlowsUserPoolClient: settings.allowedOAuthFlowsUserPoolClient, - }) - .promise(); + }), + ); // eslint-disable-next-line spellcheck/spell-checker return { appClientId: response.UserPoolClient.ClientId, appclientSecret: response.UserPoolClient.ClientSecret }; }; @@ -333,13 +338,13 @@ export const addAppClientWithoutSecret = async ( export const deleteAppClient = async (profileName: string, projectRoot: string, clientId: string): Promise => { const authDetails = getAuthProjectDetails(projectRoot); const projectDetails = getProjectMeta(projectRoot); - const creds = new aws.SharedIniFileCredentials({ profile: profileName }); + const creds = fromIni({ profile: profileName }); - const cognitoClient = new aws.CognitoIdentityServiceProvider({ + const cognitoClient = new CognitoIdentityProviderClient({ credentials: creds, region: projectDetails.providers.awscloudformation.Region, }); - await cognitoClient.deleteUserPoolClient({ ClientId: clientId, UserPoolId: authDetails.meta.UserPoolId }).promise(); + await cognitoClient.send(new DeleteUserPoolClientCommand({ ClientId: clientId, UserPoolId: authDetails.meta.UserPoolId })); }; /** diff --git a/yarn.lock b/yarn.lock index c1a9b706a82..812138da36c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -535,12 +535,31 @@ __metadata: resolution: "@aws-amplify/amplify-e2e-core@workspace:packages/amplify-e2e-core" dependencies: "@aws-amplify/amplify-cli-core": 4.4.2 + "@aws-sdk/client-amplifybackend": 3.624.0 + "@aws-sdk/client-amplifyuibuilder": 3.624.0 + "@aws-sdk/client-appsync": 3.624.0 + "@aws-sdk/client-cloudformation": 3.624.0 + "@aws-sdk/client-cloudwatch-events": 3.624.0 + "@aws-sdk/client-cloudwatch-logs": 3.624.0 + "@aws-sdk/client-cognito-identity": 3.624.0 + "@aws-sdk/client-cognito-identity-provider": 3.624.0 + "@aws-sdk/client-dynamodb": 3.624.0 + "@aws-sdk/client-iam": 3.624.0 + "@aws-sdk/client-kinesis": 3.624.0 + "@aws-sdk/client-lambda": 3.624.0 + "@aws-sdk/client-lex-model-building-service": 3.624.0 + "@aws-sdk/client-location": 3.624.0 + "@aws-sdk/client-pinpoint": 3.624.0 + "@aws-sdk/client-rekognition": 3.624.0 + "@aws-sdk/client-s3": 3.624.0 + "@aws-sdk/client-ssm": 3.624.0 "@aws-sdk/client-sts": 3.624.0 "@aws-sdk/credential-providers": 3.624.0 + "@aws-sdk/lib-dynamodb": 3.624.0 amplify-headless-interface: 1.17.8 aws-amplify: ^5.3.16 aws-appsync: ^4.1.1 - aws-sdk: ^2.1464.0 + aws-sdk: ^2.1692.0 chalk: ^4.1.1 dotenv: ^8.2.0 execa: ^5.1.1 @@ -2076,6 +2095,154 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/client-amplify@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-amplify@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + checksum: 9af25d555ffd1ea4f19b2406d2d84bfcc1cab0c92714ca92cacb3e5f2ec2a078b2ccfd156d6775459083d8c13d122426f865b2a7c725827f0619cb5ab6a60b6b + languageName: node + linkType: hard + +"@aws-sdk/client-amplifybackend@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-amplifybackend@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + checksum: f7bcfcd8ca7e5338355e6fc0df543453811c466f480c7302734201731d6f0f6a98ed45dc69b0ae0fff56a3a7e96418965935a186024d8c432fb768ddf619846a + languageName: node + linkType: hard + +"@aws-sdk/client-amplifyuibuilder@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-amplifyuibuilder@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + uuid: ^9.0.1 + checksum: 09e1b5043e11c7576b721e14c85ac4d7b687f99e731bf6a51a68bbfa2bb5091617aae77809b76e34806da30b49f7e45ddd7bc3b9de43629dd6f8575663da5d21 + languageName: node + linkType: hard + "@aws-sdk/client-appsync@npm:3.624.0": version: 3.624.0 resolution: "@aws-sdk/client-appsync@npm:3.624.0" @@ -2126,6 +2293,158 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/client-cloudformation@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-cloudformation@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + "@smithy/util-waiter": ^3.1.2 + tslib: ^2.6.2 + uuid: ^9.0.1 + checksum: 6e53724db011a863fbc3cad7390640bdeb017bc350a4775f6fe5aa4f186ded57a0609e1419e6f86efe8a9d9aebb58f7e647dc2042be5e2d68b740db63289ab37 + languageName: node + linkType: hard + +"@aws-sdk/client-cloudfront@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-cloudfront@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@aws-sdk/xml-builder": 3.609.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-stream": ^3.1.3 + "@smithy/util-utf8": ^3.0.0 + "@smithy/util-waiter": ^3.1.2 + tslib: ^2.6.2 + checksum: 8aa885868fe14c0592c1b8cea51c3eb02881725ecf0b3d80c2854f4e95b84fcbb999fe3c6ce9e7574cfc349161c6b067ead194760b820f5ea2c09532513ec63f + languageName: node + linkType: hard + +"@aws-sdk/client-cloudwatch-events@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-cloudwatch-events@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + checksum: d56f58125c95c739f75b0f80b52c39398a2de90fbd0a8dab11064dc72b9ce1f0bfa7297a6a59edd277c86835a685908ed8a4435d1c1a472cc196e9429503dff4 + languageName: node + linkType: hard + "@aws-sdk/client-cloudwatch-logs@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/client-cloudwatch-logs@npm:3.6.1" @@ -2165,6 +2484,108 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/client-cloudwatch-logs@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-cloudwatch-logs@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/eventstream-serde-browser": ^3.0.5 + "@smithy/eventstream-serde-config-resolver": ^3.0.3 + "@smithy/eventstream-serde-node": ^3.0.4 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + uuid: ^9.0.1 + checksum: afc7b8b8605acf73dae50d9377c7c624420c4c81d6caaa3505f20673ec072f162d8b56ef33ab3f0b6ad160f3443565934c99813e978e97420b0a3cecfb46073e + languageName: node + linkType: hard + +"@aws-sdk/client-codebuild@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-codebuild@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + checksum: a8d567896a19705af46455249a9fb50dc96b8a354ae1dbe257423d600cec9faf725765ac8b00b6217aaf27c132ea289405e9941cc526729f500ddd90f16b304f + languageName: node + linkType: hard + "@aws-sdk/client-cognito-identity-provider@npm:3.624.0": version: 3.624.0 resolution: "@aws-sdk/client-cognito-identity-provider@npm:3.624.0" @@ -2539,6 +2960,59 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/client-kinesis@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-kinesis@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/eventstream-serde-browser": ^3.0.5 + "@smithy/eventstream-serde-config-resolver": ^3.0.3 + "@smithy/eventstream-serde-node": ^3.0.4 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + "@smithy/util-waiter": ^3.1.2 + tslib: ^2.6.2 + checksum: 363c7861ee859f796911f68bf7ee15255eb60657e0f4410fba614d9f32c35a1e81b1f795504f5389f497e3bd1dfa2f26745137ffe8589c7c201d7556ea0305e1 + languageName: node + linkType: hard + "@aws-sdk/client-lambda@npm:3.624.0": version: 3.624.0 resolution: "@aws-sdk/client-lambda@npm:3.624.0" @@ -2593,6 +3067,55 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/client-lex-model-building-service@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-lex-model-building-service@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + checksum: ec2d43cf3f9a2c7f19bed4f6a14a85196a1a90995db4b99656b22adf7b452a0269454816b10adf5570410e187113162524aa6876d4c726db5ce5febd1c63baea + languageName: node + linkType: hard + "@aws-sdk/client-lex-runtime-service@npm:3.186.3": version: 3.186.3 resolution: "@aws-sdk/client-lex-runtime-service@npm:3.186.3" @@ -2774,6 +3297,55 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/client-organizations@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-organizations@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + checksum: 3165cdabe5631226c14662855fdb60c6a0f9a6484cd416ab4e0859be3919455c29f63a0480004e7bdc5c87986f88412fc531f52ed8acf504463646846f4a602b + languageName: node + linkType: hard + "@aws-sdk/client-personalize-events@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/client-personalize-events@npm:3.6.1" @@ -2813,6 +3385,55 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/client-pinpoint@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/client-pinpoint@npm:3.624.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/core": 3.624.0 + "@aws-sdk/credential-provider-node": 3.624.0 + "@aws-sdk/middleware-host-header": 3.620.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.620.0 + "@aws-sdk/middleware-user-agent": 3.620.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.3.2 + "@smithy/fetch-http-handler": ^3.2.4 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.5 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/middleware-retry": ^3.0.14 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.4 + "@smithy/protocol-http": ^4.1.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-base64": ^3.0.0 + "@smithy/util-body-length-browser": ^3.0.0 + "@smithy/util-body-length-node": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.14 + "@smithy/util-defaults-mode-node": ^3.0.14 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 + "@smithy/util-utf8": ^3.0.0 + tslib: ^2.6.2 + checksum: ea448fd8188332b85b6c987e733512f95f8326bd04d90205014c35ea26e3263a322856b985ae0773c0ed6cb67190c5744d8c39f32661782a435ce79349c3b6a0 + languageName: node + linkType: hard + "@aws-sdk/client-polly@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/client-polly@npm:3.6.1" @@ -4003,18 +4624,34 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/lib-storage@npm:^3.25.0": - version: 3.44.0 - resolution: "@aws-sdk/lib-storage@npm:3.44.0" +"@aws-sdk/lib-dynamodb@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/lib-dynamodb@npm:3.624.0" + dependencies: + "@aws-sdk/util-dynamodb": 3.624.0 + "@smithy/smithy-client": ^3.1.12 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + peerDependencies: + "@aws-sdk/client-dynamodb": ^3.624.0 + checksum: b4c8bd08b446997c298acec7705477f5ed2da06d83dbd952f1bfb6661822b32a063bf0a81f79ca5828105a0d525247c412ded01ebbcb607e9f5901503e9ef106 + languageName: node + linkType: hard + +"@aws-sdk/lib-storage@npm:3.624.0, @aws-sdk/lib-storage@npm:^3.25.0": + version: 3.624.0 + resolution: "@aws-sdk/lib-storage@npm:3.624.0" dependencies: + "@smithy/abort-controller": ^3.1.1 + "@smithy/middleware-endpoint": ^3.1.0 + "@smithy/smithy-client": ^3.1.12 buffer: 5.6.0 events: 3.3.0 stream-browserify: 3.0.0 - tslib: ^2.3.0 + tslib: ^2.6.2 peerDependencies: - "@aws-sdk/abort-controller": ^3.0.0 - "@aws-sdk/client-s3": ^3.0.0 - checksum: bb62cd63593f59317ce45c886cf14b23c496758694217ad6f200effdae5291554dc166ba9af175b07f1696c0fd8b7d7954c36e89d46e6122d37a5959997c116c + "@aws-sdk/client-s3": ^3.624.0 + checksum: 85d0b5d75b1f64a1bbe4a47e7b8afaad547373c31a6869de4e80795909baaaaea724cfc3d4b5ebf7c8e1d3db8e61bb3c4d39c23a1a19a0cb2797616fcf4816ec languageName: node linkType: hard @@ -4895,6 +5532,17 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/util-dynamodb@npm:3.624.0": + version: 3.624.0 + resolution: "@aws-sdk/util-dynamodb@npm:3.624.0" + dependencies: + tslib: ^2.6.2 + peerDependencies: + "@aws-sdk/client-dynamodb": ^3.624.0 + checksum: 75f6f16ec0964b3c100c783f68bea4568b33aa559951204a58b069b3dc5acd54f8dd168cf676633549121d82e1cb13860bb3dd2eadf137bd1f4f6598078fab3b + languageName: node + linkType: hard + "@aws-sdk/util-endpoints@npm:3.614.0": version: 3.614.0 resolution: "@aws-sdk/util-endpoints@npm:3.614.0" @@ -9125,13 +9773,13 @@ __metadata: languageName: node linkType: hard -"@smithy/abort-controller@npm:^3.1.6": - version: 3.1.6 - resolution: "@smithy/abort-controller@npm:3.1.6" +"@smithy/abort-controller@npm:^3.1.1, @smithy/abort-controller@npm:^3.1.6": + version: 3.1.9 + resolution: "@smithy/abort-controller@npm:3.1.9" dependencies: - "@smithy/types": ^3.6.0 + "@smithy/types": ^3.7.2 tslib: ^2.6.2 - checksum: 9933c69a81223e9a6a864c9d1f7cc00b0788ac6637b57eea8390d2b6cb39a0b87a406d32a5052441b3e9fdef9812870676464349abb5b19d3ee0ea348e2f7b1d + checksum: d8e27940a087a16922d3c292049b50847fe8a84e632701e5aa33c175ddd84c1ef2566ac3f6550bcc06689da64bf79bdbabaf4e442ba92b18c252e62ca6a8880e languageName: node linkType: hard @@ -9531,12 +10179,12 @@ __metadata: languageName: node linkType: hard -"@smithy/types@npm:^3.3.0, @smithy/types@npm:^3.5.0, @smithy/types@npm:^3.6.0": - version: 3.6.0 - resolution: "@smithy/types@npm:3.6.0" +"@smithy/types@npm:^3.3.0, @smithy/types@npm:^3.5.0, @smithy/types@npm:^3.6.0, @smithy/types@npm:^3.7.2": + version: 3.7.2 + resolution: "@smithy/types@npm:3.7.2" dependencies: tslib: ^2.6.2 - checksum: de16293da6cf6f1aa4b2ee604df245ef33688d985f27b5dae3aa69e18ed5b17baa1bc1a42412f1454c50d09a1817c8a54e7d6261c90fee230e103ff91e55174a + checksum: 4bf4674c922c092f9c92b482b074163ceea199e82466ccd4414c4cd9651f67757456414f969e9997371250e112778b636115727b5af53324334300f328069293 languageName: node linkType: hard @@ -11825,10 +12473,22 @@ __metadata: "@aws-amplify/amplify-e2e-core": 5.7.5 "@aws-amplify/amplify-opensearch-simulator": 1.7.20 "@aws-amplify/graphql-transformer-core": ^2.11.1 + "@aws-sdk/client-amplify": 3.624.0 + "@aws-sdk/client-amplifyuibuilder": 3.624.0 "@aws-sdk/client-appsync": 3.624.0 + "@aws-sdk/client-cloudformation": 3.624.0 + "@aws-sdk/client-cloudfront": 3.624.0 + "@aws-sdk/client-codebuild": 3.624.0 + "@aws-sdk/client-cognito-identity-provider": 3.624.0 "@aws-sdk/client-dynamodb": 3.624.0 + "@aws-sdk/client-iam": 3.624.0 + "@aws-sdk/client-organizations": 3.624.0 + "@aws-sdk/client-pinpoint": 3.624.0 "@aws-sdk/client-s3": 3.624.0 "@aws-sdk/client-ssm": 3.624.0 + "@aws-sdk/client-sts": 3.624.0 + "@aws-sdk/credential-providers": 3.624.0 + "@aws-sdk/lib-storage": 3.624.0 "@babel/core": ^7.23.2 "@babel/plugin-transform-modules-commonjs": 7.10.4 "@types/body-parser": ^1.19.2